Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ Control-plane operation: `governance.proposals.withdraw`.

- `--server <value>`: Control-plane server profile or URL.
- `--project <value>`: Project id or slug.
- `--yes`: Confirm authorized automation.
- `--json`: Emit the stable JSON envelope.
- `--if-match <value>`: Exact current resource version, or new when unconfigured.
- `--idempotency-key <value>`: Reuse the same request identity when retrying this mutation.
Expand Down Expand Up @@ -2139,6 +2140,9 @@ Control-plane operation: `capacity.usage`.
- `--server <value>`: Control-plane server profile or URL.
- `--team <value>`: Team id or slug.
- `--project <value>`: Project id or slug.
- `--status <value>`: Status filter.
- `--limit <value>`: Page size.
- `--cursor <value>`: Opaque page cursor.
- `--json`: Emit the stable JSON envelope.
- `--workday <value>`: Restrict evidence to one workday.

Expand Down
36 changes: 35 additions & 1 deletion schemas/command-tree.json
Original file line number Diff line number Diff line change
Expand Up @@ -1262,7 +1262,7 @@
],
"authorization": {
"capability": "command.withdraw",
"confirmation": "never"
"confirmation": "destructive"
},
"resultSchemaId": "treeseed.command.withdraw/v1",
"execution": {
Expand Down Expand Up @@ -5583,6 +5583,16 @@
"name": "--workday",
"description": "Restrict evidence to one workday.",
"type": "string"
},
{
"name": "--limit",
"description": "Page size.",
"type": "number"
},
{
"name": "--cursor",
"description": "Opaque page cursor.",
"type": "string"
}
],
"resultSchemaId": "treeseed.command.usage/v1",
Expand Down Expand Up @@ -5613,6 +5623,30 @@
"name": "workday",
"required": false,
"transform": "identity"
},
{
"target": "query",
"field": "status",
"source": "option",
"name": "status",
"required": false,
"transform": "identity"
},
{
"target": "query",
"field": "limit",
"source": "option",
"name": "limit",
"required": false,
"transform": "integer"
},
{
"target": "query",
"field": "cursor",
"source": "option",
"name": "cursor",
"required": false,
"transform": "identity"
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/development.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,20 +290,20 @@ async function rebuildPackage(input: { state: LocalSessionState; record: { sessi
}
async function restartConsumer(input: { state: LocalSessionState; runtime: DevelopmentRuntime; target: DevelopmentTarget; worktree: string; mode: 'candidate' | 'live'; context: CommandContext; recordGeneration?: boolean }) {
const { state, runtime, target, worktree, mode, context } = input, key = `${runtime.project.id}.${target.id}`;
const resolved = await invoke(context, 'local.dev.environment', { sessionId: state.sessionId, projectId: runtime.project.id, targetId: target.id }) as { environment?: NodeJS.ProcessEnv };
if (usesManagedContainer(target) && !usesManagerBuild(target) && target.kind === 'rebuild-restart' && target.operations.build) runOneShotOperation(state, target.operations.build, worktree, mode, context.env, resolved.environment ?? {});
await stopProcess(state, key);
if (usesManagedContainer(target)) {
// Preserve the live selection if manager custody refuses an active claim.
await containerOperation(context, state.sessionId, runtime, target, 'stop');
await invoke(context, 'local.dev.use', {sessionId:state.sessionId,projectId:runtime.project.id,targetId:target.id,mode:'released'});
}
else if (target.operations.cleanup) runOneShotOperation(state, target.operations.cleanup, worktree, mode, context.env, { TREESEED_DEVELOPMENT_CLEANUP_SCOPE: 'runtime' });
const resolved = await invoke(context, 'local.dev.environment', { sessionId: state.sessionId, projectId: runtime.project.id, targetId: target.id }) as { environment?: NodeJS.ProcessEnv };
if (target.operations.setup) runOneShotOperation(state, target.operations.setup, worktree, mode, context.env, resolved.environment ?? {});
if (!target.operations.start && target.kind === 'rebuild-restart' && target.operations.build) {
runOneShotOperation(state, target.operations.build, worktree, mode, context.env, resolved.environment ?? {});
await waitForDirectReadiness(target, target.ready.kind === 'process' ? target.ready.graceSeconds : target.ready.timeoutSeconds);
} else if (usesManagedContainer(target)) {
if (!usesManagerBuild(target) && target.kind === 'rebuild-restart' && target.operations.build) runOneShotOperation(state, target.operations.build, worktree, mode, context.env, resolved.environment ?? {});
await containerOperation(context, state.sessionId, runtime, target, 'start');
} else {
startOperation(state, runtime, target, worktree, mode, context.env, resolved.environment ?? {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ test('container startup and cleanup only invoke the protected manager, including
assert.equal(await runCommandLine(['dev','restart','api.service','--session',selected,'--plan','--json'],{...context,write:(value:string)=>planned.push(value)}),0);
assert.deepEqual(actions,beforePlan,'Plan must not stop or start a container');
assert.equal(record.session.targets[0].mode,'live','Plan must not switch routes');
Object.assign(target, { kind: 'rebuild-restart' });
Object.assign(target.operations, { build: { command: process.execPath, args: ['-e', 'process.exit(7)'], environment: {}, timeoutSeconds: 10 } });
writeFileSync(file,JSON.stringify({development:runtime}));
const beforeFailedBuild = [...actions];
assert.equal(await runCommandLine(['dev','restart','api.service','--session',selected,'--json'],context),1);
assert.deepEqual(actions,beforeFailedBuild,'A failed candidate build must not stop the healthy managed runtime');
assert.equal(record.session.targets[0].mode,'live','A failed candidate build must retain the live route');
delete (target.operations as { build?: unknown }).build;
Object.assign(target, { kind: 'live-api' });
writeFileSync(file,JSON.stringify({development:runtime}));
assert.equal(JSON.parse(planned[0]!).result.mutation,false);
rejectStop=true;
for(const command of ['restart','rebuild']) {
Expand Down
Loading