superlab 0.1.45 → 0.1.47

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.
package/bin/superlab.cjs CHANGED
@@ -39,7 +39,7 @@ Usage:
39
39
  superlab init [--target <dir>] [--platform codex|claude|both|all] [--lang en|zh] [--force]
40
40
  superlab install [--target <dir>] [--platform codex|claude|both|all] [--lang en|zh] [--force]
41
41
  superlab paper attach-template --path <dir> [--target <dir>]
42
- superlab auto start [--target <dir>]
42
+ superlab auto start [--target <dir>] [--objective <text>] [--campaign-kind <kind>] [--allowed-stages <csv>] [--autonomy-level <L1|L2|L3>]
43
43
  superlab auto status [--target <dir>]
44
44
  superlab auto stop [--target <dir>]
45
45
  superlab update [--target <dir>]
@@ -222,10 +222,38 @@ function parseAutoArgs(argv) {
222
222
  if (!["start", "status", "stop"].includes(action || "")) {
223
223
  throw new Error(`Unknown auto action: ${action || "(missing)"}`);
224
224
  }
225
- return {
225
+ const options = {
226
226
  action,
227
- ...parseTargetOnlyArgs(rest),
227
+ targetDir: process.cwd(),
228
+ requestedObjective: "",
229
+ requestedCampaignKind: "",
230
+ requestedAllowedStages: "",
231
+ requestedAutonomyLevel: "",
228
232
  };
233
+
234
+ for (let index = 0; index < rest.length; index += 1) {
235
+ const value = rest[index];
236
+ if (value === "--target") {
237
+ options.targetDir = path.resolve(rest[index + 1]);
238
+ index += 1;
239
+ } else if (action === "start" && value === "--objective") {
240
+ options.requestedObjective = rest[index + 1] || "";
241
+ index += 1;
242
+ } else if (action === "start" && value === "--campaign-kind") {
243
+ options.requestedCampaignKind = rest[index + 1] || "";
244
+ index += 1;
245
+ } else if (action === "start" && value === "--allowed-stages") {
246
+ options.requestedAllowedStages = rest[index + 1] || "";
247
+ index += 1;
248
+ } else if (action === "start" && value === "--autonomy-level") {
249
+ options.requestedAutonomyLevel = (rest[index + 1] || "").trim();
250
+ index += 1;
251
+ } else {
252
+ throw new Error(`Unknown option: ${value}`);
253
+ }
254
+ }
255
+
256
+ return options;
229
257
  }
230
258
 
231
259
  function printVersion(options) {
@@ -963,7 +991,15 @@ async function main() {
963
991
  return;
964
992
  }
965
993
  if (options.action === "start") {
966
- const result = await startAutoMode({ targetDir: options.targetDir });
994
+ const result = await startAutoMode({
995
+ targetDir: options.targetDir,
996
+ requestedContract: {
997
+ objective: options.requestedObjective,
998
+ campaignKind: options.requestedCampaignKind,
999
+ allowedStages: options.requestedAllowedStages,
1000
+ autonomyLevel: options.requestedAutonomyLevel,
1001
+ },
1002
+ });
967
1003
  const verb = result.status.status === "stopped" ? "stopped" : "completed";
968
1004
  console.log(`auto mode ${verb} in ${options.targetDir}`);
969
1005
  console.log(`objective: ${result.mode.objective}`);
@@ -6,6 +6,7 @@ const {
6
6
  extractValue,
7
7
  isMeaningful,
8
8
  normalizeList,
9
+ normalizeScalar,
9
10
  parseInteger,
10
11
  readFileIfExists,
11
12
  readWorkflowConfig,
@@ -43,6 +44,147 @@ const PROMOTION_CANONICAL_FILES = [
43
44
  path.join(".lab", "context", "workflow-state.md"),
44
45
  ];
45
46
 
47
+ function isLocalProcessAlive(ownerId) {
48
+ const pid = parseInteger(ownerId, null);
49
+ if (!Number.isInteger(pid) || pid <= 0) {
50
+ return false;
51
+ }
52
+ try {
53
+ process.kill(pid, 0);
54
+ return true;
55
+ } catch (error) {
56
+ if (error && error.code === "EPERM") {
57
+ return true;
58
+ }
59
+ return false;
60
+ }
61
+ }
62
+
63
+ function inferCampaignKind({ campaignKind = "", allowedStages = [] }) {
64
+ if (isMeaningful(campaignKind)) {
65
+ return campaignKind.trim().toLowerCase();
66
+ }
67
+ const stageSet = new Set((allowedStages || []).map((stage) => stage.trim().toLowerCase()).filter(Boolean));
68
+ const hasPlanning = ["idea", "data", "framing", "spec"].some((stage) => stageSet.has(stage));
69
+ const hasExecution = ["run", "iterate"].some((stage) => stageSet.has(stage));
70
+ const hasWriteOnly = stageSet.has("write") && !hasExecution;
71
+
72
+ if (hasPlanning && !hasExecution) {
73
+ return "spec";
74
+ }
75
+ if (hasExecution) {
76
+ return "experiment-loop";
77
+ }
78
+ if (hasWriteOnly || stageSet.has("report")) {
79
+ return "report-polish";
80
+ }
81
+ return "generic";
82
+ }
83
+
84
+ function normalizeRequestedAutoContract(requested = {}) {
85
+ const allowedStages = Array.isArray(requested.allowedStages)
86
+ ? requested.allowedStages.map((stage) => String(stage).trim().toLowerCase()).filter(Boolean)
87
+ : normalizeList(requested.allowedStages || "").map((stage) => stage.toLowerCase());
88
+ return {
89
+ objective: (requested.objective || "").trim(),
90
+ autonomyLevel: normalizeScalar(requested.autonomyLevel || ""),
91
+ campaignKind:
92
+ isMeaningful(requested.campaignKind || "") || allowedStages.length > 0
93
+ ? inferCampaignKind({
94
+ campaignKind: requested.campaignKind || "",
95
+ allowedStages,
96
+ })
97
+ : "",
98
+ allowedStages,
99
+ };
100
+ }
101
+
102
+ function sameStageSet(left, right) {
103
+ if (left.length !== right.length) {
104
+ return false;
105
+ }
106
+ const leftSet = new Set(left);
107
+ return right.every((value) => leftSet.has(value));
108
+ }
109
+
110
+ function hasLiveOwner(status, ledger) {
111
+ const normalizedStatus = (status.status || "").trim().toLowerCase();
112
+ const observedState = (ledger.observedState || "").trim().toLowerCase();
113
+ if ((ledger.ownerType || "").trim().toLowerCase() === "local-process" && isLocalProcessAlive(ledger.ownerId)) {
114
+ return true;
115
+ }
116
+ if (["local-runner", "remote-runner"].includes((ledger.ownerType || "").trim().toLowerCase())) {
117
+ return ["running", "retrying", "resuming", "checkpointed"].includes(observedState);
118
+ }
119
+ return normalizedStatus === "running" || ["running", "retrying", "resuming"].includes(observedState);
120
+ }
121
+
122
+ function classifyAutoContractFit({ mode, status, ledger, requested }) {
123
+ const normalizedRequest = normalizeRequestedAutoContract(requested);
124
+ const requestIsEmpty =
125
+ !isMeaningful(normalizedRequest.objective) &&
126
+ !isMeaningful(normalizedRequest.campaignKind) &&
127
+ normalizedRequest.allowedStages.length === 0;
128
+ const currentCampaignKind = inferCampaignKind(mode);
129
+ if (requestIsEmpty) {
130
+ return {
131
+ classification: "fit",
132
+ reason: "no requested contract override",
133
+ currentCampaignKind,
134
+ requestedCampaignKind: "",
135
+ };
136
+ }
137
+
138
+ const requestedCampaignKind = normalizedRequest.campaignKind || currentCampaignKind;
139
+ const requestedStages = normalizedRequest.allowedStages.length > 0
140
+ ? normalizedRequest.allowedStages
141
+ : mode.allowedStages;
142
+ const stageOutsideCurrentEnvelope = requestedStages.some((stage) => !mode.allowedStages.includes(stage));
143
+ const objectiveDiffers =
144
+ isMeaningful(normalizedRequest.objective) &&
145
+ isMeaningful(mode.objective) &&
146
+ normalizedRequest.objective.trim() !== mode.objective.trim();
147
+ const kindDiffers = requestedCampaignKind !== currentCampaignKind;
148
+
149
+ if (hasLiveOwner(status, ledger) && (kindDiffers || stageOutsideCurrentEnvelope || objectiveDiffers)) {
150
+ return {
151
+ classification: "live-conflict",
152
+ reason: "requested campaign conflicts with a live auto campaign",
153
+ currentCampaignKind,
154
+ requestedCampaignKind,
155
+ };
156
+ }
157
+
158
+ if (kindDiffers || stageOutsideCurrentEnvelope) {
159
+ return {
160
+ classification: "hard-mismatch",
161
+ reason: stageOutsideCurrentEnvelope
162
+ ? "requested stages fall outside the current auto-stage envelope"
163
+ : "requested campaign kind differs from the current auto campaign",
164
+ currentCampaignKind,
165
+ requestedCampaignKind,
166
+ };
167
+ }
168
+
169
+ if (!sameStageSet(requestedStages, mode.allowedStages) || objectiveDiffers) {
170
+ return {
171
+ classification: "soft-mismatch",
172
+ reason: !sameStageSet(requestedStages, mode.allowedStages)
173
+ ? "requested stages differ but stay inside the current envelope"
174
+ : "requested objective differs inside the same campaign family",
175
+ currentCampaignKind,
176
+ requestedCampaignKind,
177
+ };
178
+ }
179
+
180
+ return {
181
+ classification: "fit",
182
+ reason: "requested campaign matches current auto contract",
183
+ currentCampaignKind,
184
+ requestedCampaignKind,
185
+ };
186
+ }
187
+
46
188
  function resolveFrozenCoreEntries(rawValue) {
47
189
  const normalized = normalizeList(rawValue);
48
190
  const paths = new Set();
@@ -380,9 +522,14 @@ module.exports = {
380
522
  REVIEW_CONTEXT_FILES,
381
523
  VALID_APPROVAL_STATUSES,
382
524
  VALID_TERMINAL_GOAL_TYPES,
525
+ classifyAutoContractFit,
383
526
  changedSnapshotPaths,
384
527
  detectFrozenCoreChanges,
528
+ hasLiveOwner,
385
529
  hashPathState,
530
+ inferCampaignKind,
531
+ isLocalProcessAlive,
532
+ normalizeRequestedAutoContract,
386
533
  resolveFrozenCoreEntries,
387
534
  resolveStageCommand,
388
535
  snapshotFrozenCore,
@@ -1,4 +1,5 @@
1
1
  const fs = require("node:fs");
2
+ const path = require("node:path");
2
3
  const { spawn } = require("node:child_process");
3
4
  const { refreshContext } = require("./context.cjs");
4
5
  const { parseEvalProtocol, validateEvalProtocol } = require("./eval_protocol.cjs");
@@ -9,7 +10,11 @@ const {
9
10
  sleep,
10
11
  } = require("./auto_common.cjs");
11
12
  const {
13
+ classifyAutoContractFit,
12
14
  detectFrozenCoreChanges,
15
+ inferCampaignKind,
16
+ isLocalProcessAlive,
17
+ normalizeRequestedAutoContract,
13
18
  resolveStageCommand,
14
19
  snapshotFrozenCore,
15
20
  snapshotPaths,
@@ -28,6 +33,7 @@ const {
28
33
  readWorkflowLanguage,
29
34
  resolveRequiredArtifact,
30
35
  writeAutoLedger,
36
+ writeAutoMode,
31
37
  writeAutoOutcome,
32
38
  writeAutoStatus,
33
39
  } = require("./auto_state.cjs");
@@ -48,22 +54,6 @@ function isStopTransition(value) {
48
54
  return ["stop", "campaign-stop", "terminal-stop"].includes((value || "").trim().toLowerCase());
49
55
  }
50
56
 
51
- function isLocalProcessAlive(ownerId) {
52
- const pid = parseInteger(ownerId, null);
53
- if (!Number.isInteger(pid) || pid <= 0) {
54
- return false;
55
- }
56
- try {
57
- process.kill(pid, 0);
58
- return true;
59
- } catch (error) {
60
- if (error && error.code === "EPERM") {
61
- return true;
62
- }
63
- return false;
64
- }
65
- }
66
-
67
57
  function resolveResumePlan({ mode, evalProtocol, status, ledger, now }) {
68
58
  const hasLedgerState = [
69
59
  ledger.campaignId,
@@ -143,6 +133,146 @@ function resolveResumePlan({ mode, evalProtocol, status, ledger, now }) {
143
133
  return { blockingIssue: "", resumePlan: null };
144
134
  }
145
135
 
136
+ function makeCampaignId({ requested, now }) {
137
+ const raw = isMeaningful(requested.campaignKind)
138
+ ? `${requested.campaignKind}-${now.toISOString()}`
139
+ : `auto-${now.toISOString()}`;
140
+ return raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
141
+ }
142
+
143
+ function archiveAutoArtifact(targetDir, relativePath, campaignId, now) {
144
+ const absolutePath = path.join(targetDir, relativePath);
145
+ if (!fs.existsSync(absolutePath)) {
146
+ return "";
147
+ }
148
+ const archiveDir = path.join(targetDir, ".lab", "context", "archive");
149
+ fs.mkdirSync(archiveDir, { recursive: true });
150
+ const baseName = path.basename(relativePath);
151
+ const archivePath = path.join(
152
+ archiveDir,
153
+ `${now.toISOString().slice(0, 10)}-${campaignId}-${baseName}`
154
+ );
155
+ fs.copyFileSync(absolutePath, archivePath);
156
+ return archivePath;
157
+ }
158
+
159
+ function buildRolledOverAutoMode(mode, requested, now) {
160
+ const allowedStages = requested.allowedStages.length > 0 ? requested.allowedStages : mode.allowedStages;
161
+ const campaignKind = requested.campaignKind || inferCampaignKind({ allowedStages });
162
+ return {
163
+ campaignId: makeCampaignId({ requested: { ...requested, campaignKind }, now }),
164
+ campaignKind,
165
+ campaignStartedAt: now.toISOString(),
166
+ objective: requested.objective || mode.objective,
167
+ autonomyLevel: requested.autonomyLevel || mode.autonomyLevel || "l2",
168
+ approvalStatus: "draft",
169
+ allowedStages,
170
+ successCriteria: "",
171
+ terminalGoalType: "",
172
+ terminalGoalTarget: "",
173
+ requiredTerminalArtifact: "",
174
+ primaryGate: "",
175
+ secondaryGuard: "",
176
+ promotionCondition: "",
177
+ stopReason: "",
178
+ escalationReason: "",
179
+ maxIterations: mode.maxIterations,
180
+ maxWallClockTime: mode.maxWallClockTime,
181
+ maxFailures: mode.maxFailures,
182
+ pollInterval: mode.pollInterval,
183
+ stageCommands: {
184
+ run: "",
185
+ iterate: "",
186
+ review: "",
187
+ report: "",
188
+ write: "",
189
+ },
190
+ successCheckCommand: "",
191
+ stopCheckCommand: mode.stopCheckCommand,
192
+ promotionCheckCommand: "",
193
+ promotionCommand: "",
194
+ promotionPolicy: "",
195
+ frozenCore: mode.frozenCore,
196
+ explorationEnvelope: "",
197
+ stopConditions: "",
198
+ escalationConditions: "",
199
+ };
200
+ }
201
+
202
+ function rolloverAutoCampaign({ targetDir, mode, status, ledger, requested, lang, now }) {
203
+ const newMode = buildRolledOverAutoMode(mode, requested, now);
204
+ const archivedPaths = [
205
+ archiveAutoArtifact(targetDir, path.join(".lab", "context", "auto-mode.md"), mode.campaignId || "auto-campaign", now),
206
+ archiveAutoArtifact(targetDir, path.join(".lab", "context", "auto-status.md"), mode.campaignId || "auto-campaign", now),
207
+ ].filter(Boolean);
208
+
209
+ const hasMeaningfulLedger = [
210
+ ledger.campaignId,
211
+ ledger.ownerType,
212
+ ledger.ownerId,
213
+ ledger.observedState,
214
+ ledger.activeRung,
215
+ ].some((value) => isMeaningful(value));
216
+ if (hasMeaningfulLedger) {
217
+ const archivedLedger = archiveAutoArtifact(
218
+ targetDir,
219
+ path.join(".lab", "context", "auto-ledger.md"),
220
+ mode.campaignId || "auto-campaign",
221
+ now
222
+ );
223
+ if (archivedLedger) {
224
+ archivedPaths.push(archivedLedger);
225
+ }
226
+ }
227
+
228
+ writeAutoMode(targetDir, newMode, { lang });
229
+ writeAutoStatus(
230
+ targetDir,
231
+ {
232
+ status: "idle",
233
+ currentStage: "",
234
+ currentCommand: "",
235
+ activeRunId: "",
236
+ iterationCount: "0",
237
+ currentRung: "",
238
+ watchTarget: "",
239
+ nextRung: "",
240
+ startedAt: "",
241
+ lastHeartbeat: now.toISOString(),
242
+ lastCheckpoint: "",
243
+ lastSummary: `rolled over from previous auto campaign${archivedPaths.length > 0 ? `; archived: ${archivedPaths.join(", ")}` : ""}`,
244
+ decision: "fill the new auto-mode contract and approve it before starting the next campaign",
245
+ },
246
+ { lang }
247
+ );
248
+ writeAutoLedger(
249
+ targetDir,
250
+ {
251
+ campaignId: newMode.campaignId,
252
+ objective: newMode.objective,
253
+ activeStage: "",
254
+ activeRung: "",
255
+ ownerType: "",
256
+ ownerId: "",
257
+ command: "",
258
+ watchTarget: "",
259
+ startedAt: "",
260
+ lastObservedAt: now.toISOString(),
261
+ observedState: "draft",
262
+ lastCheckpoint: "",
263
+ checkpointSummary: "new campaign draft created by controlled rollover",
264
+ nextTransition: "",
265
+ continueBoundary: "Fill and approve the new contract before starting the campaign.",
266
+ stopBoundary: "",
267
+ escalationBoundary: "",
268
+ requiredReadSet: ".lab/context/eval-protocol.md, .lab/context/auto-mode.md, .lab/context/auto-status.md, .lab/context/auto-ledger.md, .lab/context/auto-outcome.md",
269
+ resumeCommand: "",
270
+ },
271
+ { lang }
272
+ );
273
+ return { newMode, archivedPaths };
274
+ }
275
+
146
276
  async function runCommandWithPolling({
147
277
  targetDir,
148
278
  stage,
@@ -333,17 +463,51 @@ async function evaluateTerminalGoal({ mode, iteration, targetDir, deadlineMs })
333
463
  };
334
464
  }
335
465
 
336
- async function startAutoMode({ targetDir, now = new Date() }) {
466
+ async function startAutoMode({ targetDir, now = new Date(), requestedContract = null }) {
337
467
  const mode = parseAutoMode(targetDir);
338
468
  const existingStatus = parseAutoStatus(targetDir);
339
469
  const existingLedger = parseAutoLedger(targetDir);
340
470
  const evalProtocol = parseEvalProtocol(targetDir);
471
+ const lang = readWorkflowLanguage(targetDir);
341
472
  const missingSchemaFields = listMissingCurrentAutoModeFields(mode);
342
473
  if (missingSchemaFields.length > 0) {
343
474
  throw new Error(
344
475
  `auto-mode.md is missing current contract fields: ${missingSchemaFields.join(", ")}; run \`superlab update --target ${targetDir}\` to apply the managed schema migration, then fill the new fields before starting auto mode`
345
476
  );
346
477
  }
478
+ if (requestedContract) {
479
+ const fit = classifyAutoContractFit({
480
+ mode,
481
+ status: existingStatus,
482
+ ledger: existingLedger,
483
+ requested: requestedContract,
484
+ });
485
+ if (fit.classification === "live-conflict") {
486
+ throw new Error(
487
+ `requested auto campaign conflicts with the current live campaign; stop the live campaign before rolling over (current: ${fit.currentCampaignKind}, requested: ${fit.requestedCampaignKind})`
488
+ );
489
+ }
490
+ if (fit.classification === "hard-mismatch") {
491
+ const normalizedRequest = normalizeRequestedAutoContract(requestedContract);
492
+ const { newMode, archivedPaths } = rolloverAutoCampaign({
493
+ targetDir,
494
+ mode,
495
+ status: existingStatus,
496
+ ledger: existingLedger,
497
+ requested: normalizedRequest,
498
+ lang,
499
+ now,
500
+ });
501
+ throw new Error(
502
+ `current auto contract does not fit the requested campaign and was rolled over to a new draft (${newMode.campaignId}); archived old campaign files: ${archivedPaths.join(", ")}; fill the new contract fields and approve it before starting auto mode`
503
+ );
504
+ }
505
+ if (fit.classification === "soft-mismatch") {
506
+ throw new Error(
507
+ `current auto contract only partially fits the requested campaign: ${fit.reason}; update auto-mode.md or narrow the request before starting auto mode`
508
+ );
509
+ }
510
+ }
347
511
  const issues = validateAutoMode(mode, null, evalProtocol);
348
512
  if (issues.length > 0) {
349
513
  throw new Error(issues.join(" | "));
@@ -366,7 +530,6 @@ async function startAutoMode({ targetDir, now = new Date() }) {
366
530
  throw new Error(blockingIssue);
367
531
  }
368
532
 
369
- const lang = readWorkflowLanguage(targetDir);
370
533
  const timestamp = now.toISOString();
371
534
  const status = {
372
535
  status: "running",
@@ -16,6 +16,9 @@ function parseAutoMode(targetDir) {
16
16
  return {
17
17
  path: contextFile(targetDir, "auto-mode.md"),
18
18
  text,
19
+ campaignId: extractValue(text, ["Campaign id", "Campaign ID", "活动 id"]),
20
+ campaignKind: normalizeScalar(extractValue(text, ["Campaign kind", "活动类型"])),
21
+ campaignStartedAt: extractValue(text, ["Campaign started at", "活动开始时间"]),
19
22
  objective: extractValue(text, ["Objective", "目标"]),
20
23
  autonomyLevel: normalizeScalar(extractValue(text, ["Autonomy level", "自治级别"])),
21
24
  approvalStatus: normalizeScalar(extractValue(text, ["Approval status", "批准状态"])),
@@ -52,7 +55,10 @@ function parseAutoMode(targetDir) {
52
55
  };
53
56
  }
54
57
 
55
- const CURRENT_AUTO_MODE_SCHEMA_FIELDS = [
58
+ const CURRENT_AUTO_MODE_MIGRATION_FIELDS = [
59
+ ["Campaign id", "campaignId"],
60
+ ["Campaign kind", "campaignKind"],
61
+ ["Campaign started at", "campaignStartedAt"],
56
62
  ["Autonomy level", "autonomyLevel"],
57
63
  ["Approval status", "approvalStatus"],
58
64
  ["Terminal goal type", "terminalGoalType"],
@@ -65,12 +71,22 @@ const CURRENT_AUTO_MODE_SCHEMA_FIELDS = [
65
71
  ["Escalation reason", "escalationReason"],
66
72
  ];
67
73
 
74
+ const CURRENT_AUTO_MODE_SCHEMA_FIELDS = CURRENT_AUTO_MODE_MIGRATION_FIELDS.filter(
75
+ ([label]) => !["Campaign id", "Campaign kind", "Campaign started at"].includes(label)
76
+ );
77
+
68
78
  function listMissingCurrentAutoModeFields(mode) {
69
79
  return CURRENT_AUTO_MODE_SCHEMA_FIELDS
70
80
  .filter(([, key]) => !isMeaningful(mode[key]))
71
81
  .map(([label]) => label);
72
82
  }
73
83
 
84
+ function listMissingMigratedAutoModeFields(mode) {
85
+ return CURRENT_AUTO_MODE_MIGRATION_FIELDS
86
+ .filter(([, key]) => !isMeaningful(mode[key]))
87
+ .map(([label]) => label);
88
+ }
89
+
74
90
  function parseAutoStatus(targetDir) {
75
91
  const text = readFileIfExists(contextFile(targetDir, "auto-status.md"));
76
92
  return {
@@ -392,18 +408,147 @@ function resolveRequiredArtifact(targetDir, configuredPath) {
392
408
  };
393
409
  }
394
410
 
411
+ function renderAutoModeContract(mode, { lang = "en" } = {}) {
412
+ const allowedStages = Array.isArray(mode.allowedStages) ? mode.allowedStages.join(", ") : (mode.allowedStages || "");
413
+ if (lang === "zh") {
414
+ return `# 自动模式契约
415
+
416
+ 用这个文件定义 \`/lab:auto\` 的有边界自治执行范围。
417
+
418
+ ## 目标
419
+
420
+ - Campaign id: ${mode.campaignId || ""}
421
+ - 活动类型: ${mode.campaignKind || ""}
422
+ - 活动开始时间: ${mode.campaignStartedAt || ""}
423
+ - Objective: ${mode.objective || ""}
424
+ - 自治级别: ${mode.autonomyLevel || "L2"}
425
+ - 批准状态: ${mode.approvalStatus || "draft"}
426
+ - 允许阶段: ${allowedStages}
427
+ - 成功标准: ${mode.successCriteria || ""}
428
+ - 终止目标类型: ${mode.terminalGoalType || ""}
429
+ - 终止目标目标值: ${mode.terminalGoalTarget || ""}
430
+ - 终止目标工件: ${mode.requiredTerminalArtifact || ""}
431
+ - 主 gate: ${mode.primaryGate || ""}
432
+ - 次级 guard: ${mode.secondaryGuard || ""}
433
+ - 升格条件: ${mode.promotionCondition || ""}
434
+ - 停止原因: ${mode.stopReason || ""}
435
+ - 升级原因: ${mode.escalationReason || ""}
436
+
437
+ ## 循环预算
438
+
439
+ - Max iterations: ${mode.maxIterations || ""}
440
+ - Max wall-clock time: ${mode.maxWallClockTime || ""}
441
+ - Max failures: ${mode.maxFailures || ""}
442
+ - Poll interval: ${mode.pollInterval || ""}
443
+
444
+ ## 阶段命令
445
+
446
+ - Run command: ${mode.stageCommands?.run || ""}
447
+ - Iterate command: ${mode.stageCommands?.iterate || ""}
448
+ - Review command: ${mode.stageCommands?.review || ""}
449
+ - Report command: ${mode.stageCommands?.report || ""}
450
+ - Write command: ${mode.stageCommands?.write || ""}
451
+ - Success check command: ${mode.successCheckCommand || ""}
452
+ - Stop check command: ${mode.stopCheckCommand || ""}
453
+ - Promotion check command: ${mode.promotionCheckCommand || ""}
454
+ - Promotion command: ${mode.promotionCommand || ""}
455
+
456
+ ## 升格策略
457
+
458
+ - Promotion policy: ${mode.promotionPolicy || ""}
459
+
460
+ ## 边界
461
+
462
+ - Frozen core: ${mode.frozenCore || ""}
463
+ - Exploration envelope: ${mode.explorationEnvelope || ""}
464
+
465
+ ## 停止条件
466
+
467
+ - Stop conditions: ${mode.stopConditions || ""}
468
+ - Escalation conditions: ${mode.escalationConditions || ""}
469
+ `;
470
+ }
471
+
472
+ return `# Auto Mode Contract
473
+
474
+ Use this file to define the bounded autonomous execution envelope for \`/lab:auto\`.
475
+
476
+ ## Objective
477
+
478
+ - Campaign id: ${mode.campaignId || ""}
479
+ - Campaign kind: ${mode.campaignKind || ""}
480
+ - Campaign started at: ${mode.campaignStartedAt || ""}
481
+ - Objective: ${mode.objective || ""}
482
+ - Autonomy level: ${mode.autonomyLevel || "L2"}
483
+ - Approval status: ${mode.approvalStatus || "draft"}
484
+ - Allowed stages: ${allowedStages}
485
+ - Success criteria: ${mode.successCriteria || ""}
486
+ - Terminal goal type: ${mode.terminalGoalType || ""}
487
+ - Terminal goal target: ${mode.terminalGoalTarget || ""}
488
+ - Required terminal artifact: ${mode.requiredTerminalArtifact || ""}
489
+ - Primary gate: ${mode.primaryGate || ""}
490
+ - Secondary guard: ${mode.secondaryGuard || ""}
491
+ - Promotion condition: ${mode.promotionCondition || ""}
492
+ - Stop reason: ${mode.stopReason || ""}
493
+ - Escalation reason: ${mode.escalationReason || ""}
494
+
495
+ ## Loop Budget
496
+
497
+ - Max iterations: ${mode.maxIterations || ""}
498
+ - Max wall-clock time: ${mode.maxWallClockTime || ""}
499
+ - Max failures: ${mode.maxFailures || ""}
500
+ - Poll interval: ${mode.pollInterval || ""}
501
+
502
+ ## Stage Commands
503
+
504
+ - Run command: ${mode.stageCommands?.run || ""}
505
+ - Iterate command: ${mode.stageCommands?.iterate || ""}
506
+ - Review command: ${mode.stageCommands?.review || ""}
507
+ - Report command: ${mode.stageCommands?.report || ""}
508
+ - Write command: ${mode.stageCommands?.write || ""}
509
+ - Success check command: ${mode.successCheckCommand || ""}
510
+ - Stop check command: ${mode.stopCheckCommand || ""}
511
+ - Promotion check command: ${mode.promotionCheckCommand || ""}
512
+ - Promotion command: ${mode.promotionCommand || ""}
513
+
514
+ ## Promotion Policy
515
+
516
+ - Promotion policy: ${mode.promotionPolicy || ""}
517
+
518
+ ## Boundaries
519
+
520
+ - Frozen core: ${mode.frozenCore || ""}
521
+ - Exploration envelope: ${mode.explorationEnvelope || ""}
522
+
523
+ ## Stop Conditions
524
+
525
+ - Stop conditions: ${mode.stopConditions || ""}
526
+ - Escalation conditions: ${mode.escalationConditions || ""}
527
+ `;
528
+ }
529
+
530
+ function writeAutoMode(targetDir, mode, { lang = "en" } = {}) {
531
+ const filePath = contextFile(targetDir, "auto-mode.md");
532
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
533
+ fs.writeFileSync(filePath, renderAutoModeContract(mode, { lang }).trimEnd() + "\n");
534
+ }
535
+
395
536
  module.exports = {
537
+ CURRENT_AUTO_MODE_MIGRATION_FIELDS,
396
538
  CURRENT_AUTO_MODE_SCHEMA_FIELDS,
397
539
  listMissingCurrentAutoModeFields,
540
+ listMissingMigratedAutoModeFields,
398
541
  parseAutoLedger,
399
542
  parseAutoMode,
400
543
  parseAutoStatus,
401
544
  readWorkflowLanguage,
402
545
  renderAutoLedger,
546
+ renderAutoModeContract,
403
547
  renderAutoOutcome,
404
548
  renderAutoStatus,
405
549
  resolveRequiredArtifact,
406
550
  writeAutoLedger,
551
+ writeAutoMode,
407
552
  writeAutoOutcome,
408
553
  writeAutoStatus,
409
554
  };
package/lib/i18n.cjs CHANGED
@@ -2180,7 +2180,7 @@ ZH_CONTENT[path.join(".codex", "prompts", "lab-data.md")] = codexPrompt(
2180
2180
  ZH_CONTENT[path.join(".codex", "prompts", "lab-auto.md")] = codexPrompt(
2181
2181
  "在已批准边界内编排自动实验循环",
2182
2182
  "auto mode objective",
2183
- "使用已安装的 `lab` 技能:`.codex/skills/lab/SKILL.md`。\n\n立刻针对用户当前给出的参数执行 `/lab:auto`,不要只推荐别的 `/lab` 阶段。只有在缺少阻塞性前提时,才明确指出缺什么,并且一次最多追问一个问题。\n\n本命令运行 `/lab:auto` 阶段。它必须读取 `.lab/context/eval-protocol.md`、`.lab/context/auto-mode.md`、`.lab/context/auto-status.md`、`.lab/context/auto-ledger.md` 与 `.lab/context/auto-outcome.md`,先确认 autonomy level、approval status、terminal goal schema,以及 primary gate、secondary guard、promotion condition、stop reason、escalation reason,再把 eval-protocol 里的指标释义、主表计划、来源约束与结构化实验阶梯当作执行依据,在不修改 mission、framing 和核心 claims 的前提下编排已批准的 `run`、`iterate`、`review`、`report`,轮询长任务完成情况;如果声明了 rung,就保持会话活着并按 rung 转移继续推进。\n首个可见输出块必须是 `Auto preflight`。这个块必须列出已读取文件,并回显 `Autonomy level`、`Approval status`、`Allowed stages`、`Terminal goal`、`Primary gate` 和 `Secondary guard`,然后才能进入执行摘要或动作计划。\n如果 preflight 所需字段缺失、过期或彼此冲突,就必须在执行前停下,并明确指出到底是哪一个字段阻止了 loop 启动。\n当 loop 活着时,必须把当前 owner、观察状态、checkpoint 摘要、继续边界、停止边界和恢复读取集合写进 `.lab/context/auto-ledger.md`。\n如果仓库的 workflow language 是中文,摘要、清单条目、任务标签和进度更新都必须使用中文,除非某个文件路径、代码标识符或字面指标名必须保持原样。\n把 `Layer 3`、`Phase 1`、`Table 2` 这类表达视为论文范围目标;只有显式写成 `Autonomy level L3` 或 `自治级别 L3` 时,才把它当成执行权限级别。\n不要用 `sleep 30`、单次 `pgrep` 或一次性的 `metrics.json` 探针来代替真实长任务命令;当真实实验进程还活着时,只允许发进度更新并继续等待。"
2183
+ "使用已安装的 `lab` 技能:`.codex/skills/lab/SKILL.md`。\n\n立刻针对用户当前给出的参数执行 `/lab:auto`,不要只推荐别的 `/lab` 阶段。只有在缺少阻塞性前提时,才明确指出缺什么,并且一次最多追问一个问题。\n\n先把用户请求规范化成可交给 CLI 的 auto contract 字段:objective、autonomy level、campaign kind、allowed stages,以及任何不改变范围就能明确的 terminal-goal 提示。\n你的第一步执行动作必须是对当前项目运行 `superlab auto start`,而不是自己直接改写 `.lab/context/auto-mode.md`、`.lab/context/auto-status.md`、`.lab/context/auto-ledger.md` 或 `.lab/context/auto-outcome.md`。\n把规范化后的字段通过 CLI 参数传下去,包括 `--objective`、`--campaign-kind`、`--allowed-stages`,以及在用户已明确或已隐含时传 `--autonomy-level`。\nCLI 返回后的 runtime 结果才是事实来源。如果 CLI 报 rollover、conflict、缺字段,或已经成功启动 campaign,就如实回报,不要绕过 CLI 自己做 prompt 侧写回。\n\n本命令运行 `/lab:auto` 阶段。它必须读取 `.lab/context/eval-protocol.md`、`.lab/context/auto-mode.md`、`.lab/context/auto-status.md`、`.lab/context/auto-ledger.md` 与 `.lab/context/auto-outcome.md`,先确认 autonomy level、approval status、terminal goal schema,以及 primary gate、secondary guard、promotion condition、stop reason、escalation reason,再把 eval-protocol 里的指标释义、主表计划、来源约束与结构化实验阶梯当作执行依据,在不修改 mission、framing 和核心 claims 的前提下编排已批准的 `run`、`iterate`、`review`、`report`,轮询长任务完成情况;如果声明了 rung,就保持会话活着并按 rung 转移继续推进。\n首个可见输出块必须是 `Auto preflight`。这个块必须列出已读取文件,并回显 `Autonomy level`、`Approval status`、`Allowed stages`、`Terminal goal`、`Primary gate` 和 `Secondary guard`,然后才能进入执行摘要或动作计划。\n如果 preflight 所需字段缺失、过期或彼此冲突,就必须在执行前停下,并明确指出到底是哪一个字段阻止了 loop 启动。\n当 loop 活着时,必须把当前 owner、观察状态、checkpoint 摘要、继续边界、停止边界和恢复读取集合写进 `.lab/context/auto-ledger.md`。\n如果仓库的 workflow language 是中文,摘要、清单条目、任务标签和进度更新都必须使用中文,除非某个文件路径、代码标识符或字面指标名必须保持原样。\n把 `Layer 3`、`Phase 1`、`Table 2` 这类表达视为论文范围目标;只有显式写成 `Autonomy level L3` 或 `自治级别 L3` 时,才把它当成执行权限级别。\n不要用 `sleep 30`、单次 `pgrep` 或一次性的 `metrics.json` 探针来代替真实长任务命令;当真实实验进程还活着时,只允许发进度更新并继续等待。"
2184
2184
  );
2185
2185
 
2186
2186
  ZH_CONTENT[path.join(".claude", "commands", "lab.md")] = claudeCommand(
@@ -2201,7 +2201,7 @@ ZH_CONTENT[path.join(".claude", "commands", "lab-auto.md")] = claudeCommand(
2201
2201
  "lab-auto",
2202
2202
  "在已批准边界内编排自动实验循环",
2203
2203
  "auto mode objective",
2204
- "使用已安装的 `lab` 技能:`.claude/skills/lab/SKILL.md`。\n\n立刻针对用户当前给出的参数执行 `auto` 阶段,不要只推荐别的 lab 阶段。只有在缺少阻塞性前提时,才明确指出缺什么,并且一次最多追问一个问题。\n\n本命令运行 lab workflow 的 `auto` 阶段。它必须读取 `.lab/context/eval-protocol.md`、`.lab/context/auto-mode.md`、`.lab/context/auto-status.md`、`.lab/context/auto-ledger.md` 与 `.lab/context/auto-outcome.md`,先确认 autonomy level、approval status、terminal goal schema,以及 primary gate、secondary guard、promotion condition、stop reason、escalation reason,再把 eval-protocol 里的指标释义、主表计划、来源约束与结构化实验阶梯当作执行依据,在不修改 mission、framing 和核心 claims 的前提下编排已批准的 `run`、`iterate`、`review`、`report`,轮询长任务完成情况;如果声明了 rung,就保持会话活着并按 rung 转移继续推进。\n首个可见输出块必须是 `Auto preflight`。这个块必须列出已读取文件,并回显 `Autonomy level`、`Approval status`、`Allowed stages`、`Terminal goal`、`Primary gate` 和 `Secondary guard`,然后才能进入执行摘要或动作计划。\n如果 preflight 所需字段缺失、过期或彼此冲突,就必须在执行前停下,并明确指出到底是哪一个字段阻止了 loop 启动。\n当 loop 活着时,必须把当前 owner、观察状态、checkpoint 摘要、继续边界、停止边界和恢复读取集合写进 `.lab/context/auto-ledger.md`。\n如果仓库的 workflow language 是中文,摘要、清单条目、任务标签和进度更新都必须使用中文,除非某个文件路径、代码标识符或字面指标名必须保持原样。\n把 `Layer 3`、`Phase 1`、`Table 2` 这类表达视为论文范围目标;只有显式写成 `Autonomy level L3` 或 `自治级别 L3` 时,才把它当成执行权限级别。\n不要用 `sleep 30`、单次 `pgrep` 或一次性的 `metrics.json` 探针来代替真实长任务命令;当真实实验进程还活着时,只允许发进度更新并继续等待。"
2204
+ "使用已安装的 `lab` 技能:`.claude/skills/lab/SKILL.md`。\n\n立刻针对用户当前给出的参数执行 `auto` 阶段,不要只推荐别的 lab 阶段。只有在缺少阻塞性前提时,才明确指出缺什么,并且一次最多追问一个问题。\n\n先把用户请求规范化成可交给 CLI 的 auto contract 字段:objective、autonomy level、campaign kind、allowed stages,以及任何不改变范围就能明确的 terminal-goal 提示。\n你的第一步执行动作必须是对当前项目运行 `superlab auto start`,而不是自己直接改写 `.lab/context/auto-mode.md`、`.lab/context/auto-status.md`、`.lab/context/auto-ledger.md` 或 `.lab/context/auto-outcome.md`。\n把规范化后的字段通过 CLI 参数传下去,包括 `--objective`、`--campaign-kind`、`--allowed-stages`,以及在用户已明确或已隐含时传 `--autonomy-level`。\nCLI 返回后的 runtime 结果才是事实来源。如果 CLI 报 rollover、conflict、缺字段,或已经成功启动 campaign,就如实回报,不要绕过 CLI 自己做 prompt 侧写回。\n\n本命令运行 lab workflow 的 `auto` 阶段。它必须读取 `.lab/context/eval-protocol.md`、`.lab/context/auto-mode.md`、`.lab/context/auto-status.md`、`.lab/context/auto-ledger.md` 与 `.lab/context/auto-outcome.md`,先确认 autonomy level、approval status、terminal goal schema,以及 primary gate、secondary guard、promotion condition、stop reason、escalation reason,再把 eval-protocol 里的指标释义、主表计划、来源约束与结构化实验阶梯当作执行依据,在不修改 mission、framing 和核心 claims 的前提下编排已批准的 `run`、`iterate`、`review`、`report`,轮询长任务完成情况;如果声明了 rung,就保持会话活着并按 rung 转移继续推进。\n首个可见输出块必须是 `Auto preflight`。这个块必须列出已读取文件,并回显 `Autonomy level`、`Approval status`、`Allowed stages`、`Terminal goal`、`Primary gate` 和 `Secondary guard`,然后才能进入执行摘要或动作计划。\n如果 preflight 所需字段缺失、过期或彼此冲突,就必须在执行前停下,并明确指出到底是哪一个字段阻止了 loop 启动。\n当 loop 活着时,必须把当前 owner、观察状态、checkpoint 摘要、继续边界、停止边界和恢复读取集合写进 `.lab/context/auto-ledger.md`。\n如果仓库的 workflow language 是中文,摘要、清单条目、任务标签和进度更新都必须使用中文,除非某个文件路径、代码标识符或字面指标名必须保持原样。\n把 `Layer 3`、`Phase 1`、`Table 2` 这类表达视为论文范围目标;只有显式写成 `Autonomy level L3` 或 `自治级别 L3` 时,才把它当成执行权限级别。\n不要用 `sleep 30`、单次 `pgrep` 或一次性的 `metrics.json` 探针来代替真实长任务命令;当真实实验进程还活着时,只允许发进度更新并继续等待。"
2205
2205
  );
2206
2206
 
2207
2207
  const zhRecipeQuickPathLine =
package/lib/install.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const fs = require("node:fs");
2
2
  const os = require("node:os");
3
3
  const path = require("node:path");
4
- const { CURRENT_AUTO_MODE_SCHEMA_FIELDS } = require("./auto_state.cjs");
4
+ const { CURRENT_AUTO_MODE_MIGRATION_FIELDS } = require("./auto_state.cjs");
5
5
  const { getLocalizedContent } = require("./i18n.cjs");
6
6
 
7
7
  const REPO_ROOT = path.resolve(__dirname, "..");
@@ -156,6 +156,9 @@ function installLabAssets(targetDir, force) {
156
156
  function autoModeSchemaFieldLine(label, lang) {
157
157
  if (lang === "zh") {
158
158
  const zhDefaults = {
159
+ "Campaign id": "- Campaign id: ",
160
+ "Campaign kind": "- 活动类型: ",
161
+ "Campaign started at": "- 活动开始时间: ",
159
162
  "Autonomy level": "- 自治级别: L2",
160
163
  "Approval status": "- 批准状态: draft",
161
164
  "Terminal goal type": "- 终止目标类型: ",
@@ -171,6 +174,9 @@ function autoModeSchemaFieldLine(label, lang) {
171
174
  }
172
175
 
173
176
  const defaults = {
177
+ "Campaign id": "- Campaign id: ",
178
+ "Campaign kind": "- Campaign kind: ",
179
+ "Campaign started at": "- Campaign started at: ",
174
180
  "Autonomy level": "- Autonomy level: L2",
175
181
  "Approval status": "- Approval status: draft",
176
182
  "Terminal goal type": "- Terminal goal type: ",
@@ -192,7 +198,7 @@ function migrateAutoModeContext(targetDir, lang) {
192
198
  }
193
199
 
194
200
  const existing = fs.readFileSync(filePath, "utf8");
195
- const missing = CURRENT_AUTO_MODE_SCHEMA_FIELDS
201
+ const missing = CURRENT_AUTO_MODE_MIGRATION_FIELDS
196
202
  .map(([label]) => label)
197
203
  .filter((label) => {
198
204
  const localizedLabel = autoModeSchemaFieldLine(label, lang).replace(/^- /, "").split(":")[0];
@@ -7,6 +7,10 @@ argument-hint: autonomous campaign target
7
7
  Use the installed `lab` skill at `.claude/skills/lab/SKILL.md`.
8
8
 
9
9
  Execute the requested `/lab-auto` command against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
10
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
11
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
12
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
13
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
10
14
  This command runs the `auto` stage of the lab workflow. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
11
15
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
12
16
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -7,6 +7,10 @@ argument-hint: autonomous campaign target
7
7
  Use the installed `lab` skill at `.claude/skills/lab/SKILL.md`.
8
8
 
9
9
  Execute the requested `/lab-auto` command against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
10
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
11
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
12
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
13
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
10
14
  This command runs the `auto` stage of the lab workflow. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
11
15
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
12
16
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -7,6 +7,10 @@ argument-hint: autonomous campaign target
7
7
  Use the installed `lab` skill at `.claude/skills/lab/SKILL.md`.
8
8
 
9
9
  Execute the requested `/lab-auto` command against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
10
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
11
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
12
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
13
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
10
14
  This command runs the `auto` stage of the lab workflow. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
11
15
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
12
16
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -7,6 +7,10 @@ argument-hint: autonomous campaign target
7
7
  Use the installed `lab` skill at `.claude/skills/lab/SKILL.md`.
8
8
 
9
9
  Execute the requested `/lab-auto` command against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
10
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
11
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
12
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
13
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
10
14
  This command runs the `auto` stage of the lab workflow. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
11
15
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
12
16
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -6,6 +6,10 @@ argument-hint: autonomous campaign target
6
6
  Use the installed `lab` skill at `.codex/skills/lab/SKILL.md`.
7
7
 
8
8
  Execute the requested `/lab:auto` stage against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
9
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
10
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
11
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
12
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
9
13
  This command runs the `/lab:auto` stage. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
10
14
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
11
15
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -6,6 +6,10 @@ argument-hint: autonomous campaign target
6
6
  Use the installed `lab` skill at `.codex/skills/lab/SKILL.md`.
7
7
 
8
8
  Execute the requested `/lab:auto` stage against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
9
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
10
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
11
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
12
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
9
13
  This command runs the `/lab:auto` stage. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
10
14
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
11
15
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -6,6 +6,10 @@ argument-hint: autonomous campaign target
6
6
  Use the installed `lab` skill at `.codex/skills/lab/SKILL.md`.
7
7
 
8
8
  Execute the requested `/lab:auto` stage against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
9
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
10
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
11
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
12
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
9
13
  This command runs the `/lab:auto` stage. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
10
14
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
11
15
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -6,6 +6,10 @@ argument-hint: autonomous campaign target
6
6
  Use the installed `lab` skill at `.codex/skills/lab/SKILL.md`.
7
7
 
8
8
  Execute the requested `/lab:auto` stage against the user's argument now. Do not only recommend another lab stage. If a blocking prerequisite is missing, say exactly what is missing and ask at most one clarifying question.
9
+ First normalize the user's request into CLI-ready auto contract fields: objective, autonomy level, campaign kind, allowed stages, and any explicit terminal-goal hints that can be inferred without changing scope.
10
+ Your first execution action must be to run `superlab auto start` against the current project instead of directly rewriting `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, or `.lab/context/auto-outcome.md` yourself.
11
+ Pass the normalized fields through CLI flags, including `--objective`, `--campaign-kind`, `--allowed-stages`, and `--autonomy-level` when the user specified or implied them.
12
+ After that CLI handoff, treat the CLI/runtime result as the source of truth. If it reports rollover, conflict, missing contract fields, or a started campaign, reflect that result back to the user instead of bypassing it with prompt-side edits.
9
13
  This command runs the `/lab:auto` stage. It must read `.lab/context/eval-protocol.md`, `.lab/context/auto-mode.md`, `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`, enforce the declared terminal goal schema, make the primary gate, secondary guard, promotion condition, stop reason, and escalation reason explicit, orchestrate approved run, iterate, review, and report stages inside that contract, poll long-running work until completion or stop conditions, and write live owner state plus progress and the final outcome back into `.lab/context/auto-status.md`, `.lab/context/auto-ledger.md`, and `.lab/context/auto-outcome.md`.
10
14
  The first visible block must be `Auto preflight`. That first visible block must list the files read and echo `Autonomy level`, `Approval status`, `Allowed stages`, `Terminal goal`, `Primary gate`, and `Secondary guard` before any execution summary or action plan.
11
15
  If the preflight block cannot be completed because any required field is missing, stale, or inconsistent, stop before execution and say exactly which field blocked arming the loop.
@@ -7,6 +7,9 @@ Use `.lab/context/auto-ledger.md` as the live runtime ledger for ownership, chec
7
7
 
8
8
  ## Objective
9
9
 
10
+ - Campaign id:
11
+ - Campaign kind:
12
+ - Campaign started at:
10
13
  - Objective:
11
14
  - Autonomy level: L2
12
15
  - Autonomy level controls execution privilege, not paper layer or table number.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superlab",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
4
4
  "description": "Strict /lab research workflow installer for Codex and Claude",
5
5
  "keywords": [
6
6
  "codex",