scene-capability-engine 3.6.2 → 3.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -102,7 +102,32 @@ function registerSessionCommands(program) {
102
102
  try {
103
103
  const store = new SessionStore(process.cwd());
104
104
  const current = await store.getSession(sessionRef || 'latest');
105
- _printSessionResult('session_show', current, options.json);
105
+ const sceneIndex = await store.getSceneIndexDiagnostics();
106
+ _printSessionResult('session_show', current, options.json, {
107
+ session_source: 'file',
108
+ scene_index: sceneIndex
109
+ });
110
+ } catch (error) {
111
+ _exitWithError(error, options.json);
112
+ }
113
+ });
114
+
115
+ session
116
+ .command('list')
117
+ .description('List recent sessions')
118
+ .option('--limit <n>', 'Maximum sessions to return', '20')
119
+ .option('--json', 'Output as JSON')
120
+ .action(async (options) => {
121
+ try {
122
+ const store = new SessionStore(process.cwd());
123
+ const limitRaw = Number.parseInt(`${options.limit || '20'}`, 10);
124
+ const limit = Number.isFinite(limitRaw) && limitRaw > 0 ? Math.min(limitRaw, 5000) : 20;
125
+ const sessions = await store.listSessions();
126
+ const sceneIndex = await store.getSceneIndexDiagnostics();
127
+ _printSessionListResult('session_list', sessions.slice(0, limit), options.json, {
128
+ session_source: 'file',
129
+ scene_index: sceneIndex
130
+ });
106
131
  } catch (error) {
107
132
  _exitWithError(error, options.json);
108
133
  }
@@ -120,12 +145,13 @@ function _parsePayload(raw) {
120
145
  }
121
146
  }
122
147
 
123
- function _printSessionResult(action, session, asJson = false) {
148
+ function _printSessionResult(action, session, asJson = false, metadata = {}) {
124
149
  if (asJson) {
125
150
  console.log(JSON.stringify({
126
151
  success: true,
127
152
  action,
128
153
  session,
154
+ ...metadata
129
155
  }, null, 2));
130
156
  return;
131
157
  }
@@ -147,6 +173,38 @@ function _printSessionResult(action, session, asJson = false) {
147
173
  if (session.objective) {
148
174
  console.log(chalk.gray(`Objective: ${session.objective}`));
149
175
  }
176
+ if (metadata.session_source) {
177
+ console.log(chalk.gray(`Session source: ${metadata.session_source}`));
178
+ }
179
+ if (metadata.scene_index && metadata.scene_index.status) {
180
+ console.log(chalk.gray(`Scene index consistency: ${metadata.scene_index.status}`));
181
+ }
182
+ }
183
+
184
+ function _printSessionListResult(action, sessions, asJson = false, metadata = {}) {
185
+ if (asJson) {
186
+ console.log(JSON.stringify({
187
+ success: true,
188
+ action,
189
+ total: Array.isArray(sessions) ? sessions.length : 0,
190
+ sessions: Array.isArray(sessions) ? sessions : [],
191
+ ...metadata
192
+ }, null, 2));
193
+ return;
194
+ }
195
+
196
+ console.log(chalk.green('✓ Sessions listed'));
197
+ const list = Array.isArray(sessions) ? sessions : [];
198
+ console.log(chalk.gray(`Total: ${list.length}`));
199
+ if (metadata.session_source) {
200
+ console.log(chalk.gray(`Session source: ${metadata.session_source}`));
201
+ }
202
+ if (metadata.scene_index && metadata.scene_index.status) {
203
+ console.log(chalk.gray(`Scene index consistency: ${metadata.scene_index.status}`));
204
+ }
205
+ for (const session of list) {
206
+ console.log(`- ${session.session_id} | ${session.status} | ${session.updated_at || session.started_at || 'n/a'}`);
207
+ }
150
208
  }
151
209
 
152
210
  function _exitWithError(error, asJson = false) {
@@ -0,0 +1,210 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const fs = require('fs-extra');
4
+ const {
5
+ COMPONENT_DEFINITIONS,
6
+ buildStateMigrationPlan,
7
+ runStateMigration,
8
+ runStateDoctor,
9
+ runStateExport
10
+ } = require('../state/state-migration-manager');
11
+
12
+ function normalizeString(value) {
13
+ if (typeof value !== 'string') {
14
+ return '';
15
+ }
16
+ return value.trim();
17
+ }
18
+
19
+ function collectOptionValue(value, previous = []) {
20
+ const normalized = normalizeString(value);
21
+ if (!normalized) {
22
+ return previous;
23
+ }
24
+ return [...previous, normalized];
25
+ }
26
+
27
+ function normalizeComponentInput(value = []) {
28
+ if (!Array.isArray(value)) {
29
+ return [];
30
+ }
31
+ const items = [];
32
+ for (const entry of value) {
33
+ const normalized = normalizeString(entry);
34
+ if (!normalized) {
35
+ continue;
36
+ }
37
+ for (const token of normalized.split(/[,\s]+/g)) {
38
+ const cleaned = normalizeString(token);
39
+ if (cleaned) {
40
+ items.push(cleaned);
41
+ }
42
+ }
43
+ }
44
+ return Array.from(new Set(items));
45
+ }
46
+
47
+ function printPayload(payload, options = {}, title = 'State') {
48
+ if (options.json) {
49
+ console.log(JSON.stringify(payload, null, 2));
50
+ return;
51
+ }
52
+
53
+ console.log(chalk.blue(title));
54
+ if (payload.mode) {
55
+ console.log(` Mode: ${payload.mode}`);
56
+ }
57
+ if (payload.store_path) {
58
+ console.log(` Store: ${payload.store_path}`);
59
+ }
60
+ if (payload.sqlite) {
61
+ console.log(` SQLite: configured=${payload.sqlite.configured ? 'yes' : 'no'} available=${payload.sqlite.available ? 'yes' : 'no'}`);
62
+ }
63
+ if (payload.summary && typeof payload.summary === 'object') {
64
+ for (const [key, value] of Object.entries(payload.summary)) {
65
+ console.log(` ${key}: ${value}`);
66
+ }
67
+ }
68
+ if (Array.isArray(payload.components)) {
69
+ for (const item of payload.components) {
70
+ console.log(` - ${item.id} | source=${item.source_record_count} | status=${item.status}`);
71
+ }
72
+ }
73
+ if (Array.isArray(payload.operations)) {
74
+ for (const item of payload.operations) {
75
+ console.log(` - ${item.component_id} | ${item.status} | source=${item.source_record_count}`);
76
+ }
77
+ }
78
+ if (payload.out_file) {
79
+ console.log(` Export: ${payload.out_file}`);
80
+ }
81
+ }
82
+
83
+ async function runStatePlanCommand(options = {}, dependencies = {}) {
84
+ const projectPath = dependencies.projectPath || process.cwd();
85
+ const fileSystem = dependencies.fileSystem || fs;
86
+ const env = dependencies.env || process.env;
87
+ const components = normalizeComponentInput(options.component);
88
+
89
+ const payload = await buildStateMigrationPlan({
90
+ componentIds: components
91
+ }, {
92
+ projectPath,
93
+ fileSystem,
94
+ env
95
+ });
96
+ printPayload(payload, options, 'State Plan');
97
+ return payload;
98
+ }
99
+
100
+ async function runStateDoctorCommand(options = {}, dependencies = {}) {
101
+ const projectPath = dependencies.projectPath || process.cwd();
102
+ const fileSystem = dependencies.fileSystem || fs;
103
+ const env = dependencies.env || process.env;
104
+
105
+ const payload = await runStateDoctor({}, {
106
+ projectPath,
107
+ fileSystem,
108
+ env
109
+ });
110
+ printPayload(payload, options, 'State Doctor');
111
+ return payload;
112
+ }
113
+
114
+ async function runStateMigrateCommand(options = {}, dependencies = {}) {
115
+ const projectPath = dependencies.projectPath || process.cwd();
116
+ const fileSystem = dependencies.fileSystem || fs;
117
+ const env = dependencies.env || process.env;
118
+ const components = normalizeComponentInput(options.component);
119
+ const componentIds = options.all === true ? [] : components;
120
+
121
+ const payload = await runStateMigration({
122
+ apply: options.apply === true,
123
+ all: options.all === true,
124
+ componentIds
125
+ }, {
126
+ projectPath,
127
+ fileSystem,
128
+ env
129
+ });
130
+ printPayload(payload, options, 'State Migrate');
131
+ return payload;
132
+ }
133
+
134
+ async function runStateExportCommand(options = {}, dependencies = {}) {
135
+ const projectPath = dependencies.projectPath || process.cwd();
136
+ const fileSystem = dependencies.fileSystem || fs;
137
+ const env = dependencies.env || process.env;
138
+
139
+ const payload = await runStateExport({
140
+ out: normalizeString(options.out)
141
+ }, {
142
+ projectPath,
143
+ fileSystem,
144
+ env
145
+ });
146
+ printPayload(payload, options, 'State Export');
147
+ return payload;
148
+ }
149
+
150
+ async function safeRun(handler, options = {}, dependencies = {}, title = 'state command') {
151
+ try {
152
+ await handler(options, dependencies);
153
+ } catch (error) {
154
+ if (options && options.json) {
155
+ console.log(JSON.stringify({
156
+ success: false,
157
+ mode: title.replace(/\s+/g, '-'),
158
+ error: error.message
159
+ }, null, 2));
160
+ } else {
161
+ console.error(chalk.red(`${title} failed:`), error.message);
162
+ }
163
+ process.exitCode = 1;
164
+ }
165
+ }
166
+
167
+ function registerStateCommands(program) {
168
+ const state = program
169
+ .command('state')
170
+ .description('Manage gradual migration from file registries to sqlite indexes');
171
+
172
+ const knownIds = COMPONENT_DEFINITIONS.map((item) => item.id).join(', ');
173
+
174
+ state
175
+ .command('plan')
176
+ .description('Inspect migratable file-based registries and produce migration plan')
177
+ .option('--component <id>', `Component id (repeatable): ${knownIds}`, collectOptionValue, [])
178
+ .option('--json', 'Print machine-readable JSON output')
179
+ .action(async (options) => safeRun(runStatePlanCommand, options, {}, 'state plan'));
180
+
181
+ state
182
+ .command('doctor')
183
+ .description('Check sqlite readiness and file/sqlite index consistency')
184
+ .option('--json', 'Print machine-readable JSON output')
185
+ .action(async (options) => safeRun(runStateDoctorCommand, options, {}, 'state doctor'));
186
+
187
+ state
188
+ .command('migrate')
189
+ .description('Migrate selected components to sqlite indexes (dry-run by default)')
190
+ .option('--component <id>', `Component id (repeatable): ${knownIds}`, collectOptionValue, [])
191
+ .option('--all', 'Migrate all known components')
192
+ .option('--apply', 'Apply migration writes (default is dry-run)')
193
+ .option('--json', 'Print machine-readable JSON output')
194
+ .action(async (options) => safeRun(runStateMigrateCommand, options, {}, 'state migrate'));
195
+
196
+ state
197
+ .command('export')
198
+ .description('Export sqlite state migration tables as JSON snapshot')
199
+ .option('--out <path>', 'Output file path', '.sce/reports/state-migration/state-export.latest.json')
200
+ .option('--json', 'Print machine-readable JSON output')
201
+ .action(async (options) => safeRun(runStateExportCommand, options, {}, 'state export'));
202
+ }
203
+
204
+ module.exports = {
205
+ runStatePlanCommand,
206
+ runStateDoctorCommand,
207
+ runStateMigrateCommand,
208
+ runStateExportCommand,
209
+ registerStateCommands
210
+ };
@@ -13,6 +13,7 @@ const { captureTimelineCheckpoint } = require('../runtime/project-timeline');
13
13
  const { runProblemEvaluation } = require('../problem/problem-evaluator');
14
14
  const { TaskRefRegistry } = require('../task/task-ref-registry');
15
15
  const { getSceStateStore } = require('../state/sce-state-store');
16
+ const { ensureWriteAuthorization } = require('../security/write-authorization');
16
17
  const {
17
18
  loadStudioIntakePolicy,
18
19
  runStudioAutoIntake,
@@ -2661,6 +2662,12 @@ async function runStudioApplyCommand(options = {}, dependencies = {}) {
2661
2662
  const job = await loadJob(paths, jobId, fileSystem);
2662
2663
  ensureNotRolledBack(job, 'apply');
2663
2664
  ensureStagePrerequisite(job, 'apply', 'generate');
2665
+ const leaseAuthResult = await ensureWriteAuthorization('studio:apply', options, {
2666
+ projectPath,
2667
+ fileSystem,
2668
+ env: dependencies.env,
2669
+ authSecret: dependencies.authSecret
2670
+ });
2664
2671
  const authResult = await ensureStudioAuthorization('apply', options, {
2665
2672
  projectPath,
2666
2673
  fileSystem,
@@ -2696,14 +2703,22 @@ async function runStudioApplyCommand(options = {}, dependencies = {}) {
2696
2703
 
2697
2704
  ensureStageCompleted(job, 'apply', {
2698
2705
  patch_bundle_id: patchBundleId,
2699
- auth_required: authResult.required,
2706
+ auth_required: authResult.required || leaseAuthResult.required,
2707
+ auth_password_required: authResult.required,
2708
+ auth_lease_required: leaseAuthResult.required,
2709
+ auth_lease_id: leaseAuthResult.lease_id || null,
2710
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null,
2700
2711
  problem_evaluation: summarizeProblemEvaluation(applyProblemEvaluation)
2701
2712
  });
2702
2713
 
2703
2714
  await saveJob(paths, job, fileSystem);
2704
2715
  const applyEvent = await appendStudioEvent(paths, job, 'stage.apply.completed', {
2705
2716
  patch_bundle_id: patchBundleId,
2706
- auth_required: authResult.required,
2717
+ auth_required: authResult.required || leaseAuthResult.required,
2718
+ auth_password_required: authResult.required,
2719
+ auth_lease_required: leaseAuthResult.required,
2720
+ auth_lease_id: leaseAuthResult.lease_id || null,
2721
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null,
2707
2722
  problem_evaluation: summarizeProblemEvaluation(applyProblemEvaluation)
2708
2723
  }, fileSystem);
2709
2724
  await writeLatestJob(paths, jobId, fileSystem);
@@ -2890,6 +2905,12 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
2890
2905
  const job = await loadJob(paths, jobId, fileSystem);
2891
2906
  ensureNotRolledBack(job, 'release');
2892
2907
  ensureStagePrerequisite(job, 'release', 'verify');
2908
+ const leaseAuthResult = await ensureWriteAuthorization('studio:release', options, {
2909
+ projectPath,
2910
+ fileSystem,
2911
+ env: dependencies.env,
2912
+ authSecret: dependencies.authSecret
2913
+ });
2893
2914
  const authResult = await ensureStudioAuthorization('release', options, {
2894
2915
  projectPath,
2895
2916
  fileSystem,
@@ -3006,7 +3027,11 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
3006
3027
  passed: false,
3007
3028
  report: releaseReportPath,
3008
3029
  gate_steps: gateResult.steps,
3009
- auth_required: authResult.required,
3030
+ auth_required: authResult.required || leaseAuthResult.required,
3031
+ auth_password_required: authResult.required,
3032
+ auth_lease_required: leaseAuthResult.required,
3033
+ auth_lease_id: leaseAuthResult.lease_id || null,
3034
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null,
3010
3035
  problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
3011
3036
  domain_chain: domainChainMetadata,
3012
3037
  auto_errorbook_records: autoErrorbookRecords
@@ -3017,7 +3042,11 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
3017
3042
  channel,
3018
3043
  release_ref: releaseRef,
3019
3044
  report: releaseReportPath,
3020
- auth_required: authResult.required,
3045
+ auth_required: authResult.required || leaseAuthResult.required,
3046
+ auth_password_required: authResult.required,
3047
+ auth_lease_required: leaseAuthResult.required,
3048
+ auth_lease_id: leaseAuthResult.lease_id || null,
3049
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null,
3021
3050
  problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
3022
3051
  domain_chain: domainChainMetadata,
3023
3052
  auto_errorbook_records: autoErrorbookRecords
@@ -3032,7 +3061,11 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
3032
3061
  release_ref: releaseRef,
3033
3062
  report: releaseReportPath,
3034
3063
  gate_steps: gateResult.steps,
3035
- auth_required: authResult.required,
3064
+ auth_required: authResult.required || leaseAuthResult.required,
3065
+ auth_password_required: authResult.required,
3066
+ auth_lease_required: leaseAuthResult.required,
3067
+ auth_lease_id: leaseAuthResult.lease_id || null,
3068
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null,
3036
3069
  problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
3037
3070
  domain_chain: domainChainMetadata,
3038
3071
  auto_errorbook_records: autoErrorbookRecords
@@ -3064,7 +3097,11 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
3064
3097
  channel,
3065
3098
  release_ref: releaseRef,
3066
3099
  report: releaseReportPath,
3067
- auth_required: authResult.required,
3100
+ auth_required: authResult.required || leaseAuthResult.required,
3101
+ auth_password_required: authResult.required,
3102
+ auth_lease_required: leaseAuthResult.required,
3103
+ auth_lease_id: leaseAuthResult.lease_id || null,
3104
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null,
3068
3105
  problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
3069
3106
  domain_chain: domainChainMetadata,
3070
3107
  auto_errorbook_records: autoErrorbookRecords
@@ -3119,6 +3156,12 @@ async function runStudioRollbackCommand(options = {}, dependencies = {}) {
3119
3156
 
3120
3157
  const reason = normalizeString(options.reason) || 'manual-rollback';
3121
3158
  const job = await loadJob(paths, jobId, fileSystem);
3159
+ const leaseAuthResult = await ensureWriteAuthorization('studio:rollback', options, {
3160
+ projectPath,
3161
+ fileSystem,
3162
+ env: dependencies.env,
3163
+ authSecret: dependencies.authSecret
3164
+ });
3122
3165
  const authResult = await ensureStudioAuthorization('rollback', options, {
3123
3166
  projectPath,
3124
3167
  fileSystem,
@@ -3134,7 +3177,11 @@ async function runStudioRollbackCommand(options = {}, dependencies = {}) {
3134
3177
  job.rollback = {
3135
3178
  reason,
3136
3179
  rolled_back_at: job.updated_at,
3137
- auth_required: authResult.required
3180
+ auth_required: authResult.required || leaseAuthResult.required,
3181
+ auth_password_required: authResult.required,
3182
+ auth_lease_required: leaseAuthResult.required,
3183
+ auth_lease_id: leaseAuthResult.lease_id || null,
3184
+ auth_lease_expires_at: leaseAuthResult.lease_expires_at || null
3138
3185
  };
3139
3186
 
3140
3187
  const sceneSessionId = normalizeString(job && job.session && job.session.scene_session_id);
@@ -3508,6 +3555,7 @@ function registerStudioCommands(program) {
3508
3555
  .command('apply')
3509
3556
  .description('Apply generated patch bundle metadata to studio job')
3510
3557
  .option('--patch-bundle <id>', 'Patch bundle identifier (defaults to generated artifact)')
3558
+ .option('--auth-lease <lease-id>', 'Write authorization lease id (sce auth grant)')
3511
3559
  .option('--auth-password <password>', 'Authorization password for protected apply action')
3512
3560
  .option('--require-auth', 'Require authorization even when policy is advisory')
3513
3561
  .option('--job <job-id>', 'Studio job id (defaults to latest)')
@@ -3527,6 +3575,7 @@ function registerStudioCommands(program) {
3527
3575
  .description('Record release stage for studio job')
3528
3576
  .option('--channel <channel>', 'Release channel (dev|prod)', 'dev')
3529
3577
  .option('--profile <profile>', 'Release gate profile', 'standard')
3578
+ .option('--auth-lease <lease-id>', 'Write authorization lease id (sce auth grant)')
3530
3579
  .option('--auth-password <password>', 'Authorization password for protected release action')
3531
3580
  .option('--require-auth', 'Require authorization even when policy is advisory')
3532
3581
  .option('--release-ref <ref>', 'Explicit release reference/tag')
@@ -3555,6 +3604,7 @@ function registerStudioCommands(program) {
3555
3604
  .description('Rollback a studio job after apply/release')
3556
3605
  .option('--job <job-id>', 'Studio job id (defaults to latest)')
3557
3606
  .option('--reason <reason>', 'Rollback reason')
3607
+ .option('--auth-lease <lease-id>', 'Write authorization lease id (sce auth grant)')
3558
3608
  .option('--auth-password <password>', 'Authorization password for protected rollback action')
3559
3609
  .option('--require-auth', 'Require authorization even when policy is advisory')
3560
3610
  .option('--json', 'Print machine-readable JSON output')
@@ -11,6 +11,7 @@ const chalk = require('chalk');
11
11
  const TaskClaimer = require('../task/task-claimer');
12
12
  const WorkspaceManager = require('../workspace/workspace-manager');
13
13
  const { TaskRefRegistry } = require('../task/task-ref-registry');
14
+ const { ensureWriteAuthorization } = require('../security/write-authorization');
14
15
 
15
16
  function normalizeString(value) {
16
17
  if (typeof value !== 'string') {
@@ -436,6 +437,17 @@ async function runTaskRerunCommand(options = {}, dependencies = {}) {
436
437
  if (!lookup) {
437
438
  throw new Error(`Task ref not found: ${taskRef}`);
438
439
  }
440
+ const writeAuthResult = dryRun
441
+ ? {
442
+ required: false,
443
+ passed: true
444
+ }
445
+ : await ensureWriteAuthorization('task:rerun', options, {
446
+ projectPath,
447
+ fileSystem,
448
+ env: dependencies.env,
449
+ authSecret: dependencies.authSecret
450
+ });
439
451
 
440
452
  if (isStudioTaskRef(lookup)) {
441
453
  const stage = resolveStudioStageFromTaskKey(lookup.task_key);
@@ -453,7 +465,12 @@ async function runTaskRerunCommand(options = {}, dependencies = {}) {
453
465
  stage,
454
466
  job_id: normalizeString(job?.job_id) || null,
455
467
  dry_run: dryRun,
456
- command: stringifySceArgs(rerunPlan.args)
468
+ command: stringifySceArgs(rerunPlan.args),
469
+ authorization: {
470
+ required: writeAuthResult.required === true,
471
+ lease_id: writeAuthResult.lease_id || null,
472
+ lease_expires_at: writeAuthResult.lease_expires_at || null
473
+ }
457
474
  };
458
475
 
459
476
  if (!dryRun) {
@@ -486,7 +503,12 @@ async function runTaskRerunCommand(options = {}, dependencies = {}) {
486
503
  task_ref: lookup.task_ref,
487
504
  rerun_type: 'spec-task',
488
505
  dry_run: dryRun,
489
- command: `sce task claim ${lookup.spec_id} ${lookup.task_key}`
506
+ command: `sce task claim ${lookup.spec_id} ${lookup.task_key}`,
507
+ authorization: {
508
+ required: writeAuthResult.required === true,
509
+ lease_id: writeAuthResult.lease_id || null,
510
+ lease_expires_at: writeAuthResult.lease_expires_at || null
511
+ }
490
512
  };
491
513
 
492
514
  if (!dryRun) {
@@ -734,6 +756,7 @@ function registerTaskCommands(program) {
734
756
  .description('Rerun task by hierarchical reference')
735
757
  .requiredOption('--ref <task-ref>', 'Task reference (SS.PP.TT)')
736
758
  .option('--dry-run', 'Preview rerun command without executing')
759
+ .option('--auth-lease <lease-id>', 'Write authorization lease id (sce auth grant)')
737
760
  .option('--from-chat <session>', 'Override session for studio plan rerun')
738
761
  .option('--job <job-id>', 'Override studio job id')
739
762
  .option('--profile <profile>', 'Override profile for studio verify/release rerun')