oasis_test 0.1.109 → 0.1.110

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.
Files changed (2) hide show
  1. package/dist/index.js +184 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4102,12 +4102,15 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
4102
4102
  // 刻意不写「过去 24 小时发生 N 次」这类统计:任务书是长期提示词,写死的数字会过期变成假话。
4103
4103
  `\u4F60\u8FD9\u4E00\u8F6E\u968F\u65F6\u53EF\u80FD\u88AB\u780D\u2014\u2014\u8D85\u65F6\u3001\u989D\u5EA6\u6253\u6EE1\u3001\u8282\u70B9\u6389\u7EBF\u90FD\u4F1A\uFF0C\u800C\u4E14**\u662F\u5E38\u4E8B**\u3002\u771F\u88AB\u780D\u65F6\uFF0C\u4E0B\u4E00\u8D9F\u63A5\u624B\u7684\u4EBA\u53EA\u770B\u5F97\u5230\u300C\u4F60\u4E3A\u4EC0\u4E48\u65AD\u300D\uFF0C\u770B\u4E0D\u5230\u300C\u4F60\u5E72\u5230\u54EA\u300D\u2014\u2014\u9664\u975E\u4F60\u7559\u4E86\u65AD\u70B9\u3002`,
4104
4104
  `\u505A\u5B8C\u4E00\u4E2A\u9636\u6BB5\u3001\u6216\u8981\u5F00\u59CB\u4E00\u4EF6\u53EF\u80FD\u5F88\u4E45\u7684\u4E8B\u4E4B\u524D\uFF0C\u987A\u624B\u8BB0\u4E00\u6761\uFF08\u51E0\u79D2\u8FD4\u56DE\uFF0C\u4E0D\u6253\u65AD\u4F60\uFF09\uFF1A`,
4105
+ // ★ 参数必须是 **JSON string array**(CLI 侧 `JSON.parse` 后校验,见 cli.ts parseStringArrayFlag)。
4106
+ // 这里给的是能逐字复制的真例子——写成自然语言一句话会当场抛 `--pending 必须是 JSON string array`。
4105
4107
  `\`\`\``,
4106
4108
  `oasis continuity-checkpoint --trigger stage_completed \\`,
4107
- ` --completed "\u5DF2\u5B8C\u6210\u7684\u6B65\u9AA4,\u9017\u53F7\u5206\u9694\uFF08\u7528\u7A33\u5B9A\u7684\u540D\u5B57\uFF0C\u91CD\u8DD1\u65F6\u540C\u4E00\u6B65\u540C\u4E00\u4E2A\u540D\uFF09" \\`,
4108
- ` --pending "\u8FD8\u5269\u4EC0\u4E48\u6CA1\u505A" \\`,
4109
- ` --recoverability full|partial|none`,
4109
+ ` --completed '["\u8BFB\u9700\u6C42","\u6539 auth \u4E2D\u95F4\u4EF6","\u8DD1\u5355\u6D4B"]' \\`,
4110
+ ` --pending '["\u8865\u96C6\u6210\u6D4B\u8BD5","\u5199\u7ED3\u6848\u62A5\u544A"]' \\`,
4111
+ ` --recoverability partial`,
4110
4112
  `\`\`\``,
4113
+ `\u4E24\u4E2A\u6570\u7EC4\u90FD\u662F JSON\uFF08\u5355\u5F15\u53F7\u5305\u4F4F\u3001\u91CC\u9762\u7528\u53CC\u5F15\u53F7\uFF09\u3002\u6B65\u9AA4\u540D\u7528\u7A33\u5B9A\u7684\u8BF4\u6CD5\u2014\u2014\u91CD\u8DD1\u65F6\u540C\u4E00\u6B65\u7528\u540C\u4E00\u4E2A\u540D\uFF0C\u4E0B\u4E00\u8D9F\u624D\u8BA4\u5F97\u51FA\u54EA\u4E9B\u5DF2\u7ECF\u505A\u5B8C\u3002\`--recoverability\` \u4E09\u9009\u4E00\uFF1A\`full\`=\u63A5\u624B\u7684\u4EBA\u7167\u7740\u5C31\u80FD\u7EED\u4E0A\u3001\`partial\`=\u80FD\u7EED\u4F46\u8981\u91CD\u505A\u4E00\u90E8\u5206\u3001\`none\`=\u7B49\u4E8E\u4ECE\u5934\u518D\u6765\u3002`,
4111
4114
  `**\u53EA\u6709\u4F60\u77E5\u9053\u300C\u8FD8\u5269\u4EC0\u4E48\u300D**\u2014\u2014\u7CFB\u7EDF\u80FD\u81EA\u52A8\u8BB0\u4E0B\u4F60\u8DD1\u8FC7\u54EA\u4E9B\u547D\u4EE4\u3001\u4EA4\u5230\u4E86\u54EA\u4E00\u7248\uFF0C\u4F46\u63A8\u4E0D\u51FA\u4F60\u6253\u7B97\u5E72\u4EC0\u4E48\u3002\u522B\u5199\u7A7A\u8BDD\uFF1B\u6CA1\u4EC0\u4E48\u53EF\u5199\u5C31\u4E0D\u5199\uFF0C\u522B\u4E3A\u4E86\u586B\u800C\u586B\u3002`
4112
4115
  ],
4113
4116
  // 兜底(§10):上次失败了 → 明确告诉它发生了什么 + 怎么破(首选 add-revision 拆出去)
@@ -158906,7 +158909,12 @@ async function cachedDiscovery(key, fn) {
158906
158909
  if (entry && now < entry.expiresAt) {
158907
158910
  return entry.models;
158908
158911
  }
158909
- const models = await fn();
158912
+ let models;
158913
+ try {
158914
+ models = await fn();
158915
+ } catch {
158916
+ return [];
158917
+ }
158910
158918
  modelCache.set(key, { models, expiresAt: now + CACHE_TTL_MS });
158911
158919
  return models;
158912
158920
  }
@@ -158976,12 +158984,77 @@ async function discoverCursorModels(bin) {
158976
158984
  async function discoverOpenCodeModels(bin) {
158977
158985
  throw new Error("discoverOpenCodeModels: TODO");
158978
158986
  }
158987
+ function isPiDiscoveryNoise(line) {
158988
+ const lower = line.toLowerCase();
158989
+ if (lower.includes("no models match pattern")) return true;
158990
+ if (lower.startsWith("warning:") || lower.startsWith("error:") || lower.startsWith("info:")) return true;
158991
+ return line.includes("`") || lower.includes("--help") || lower.includes("usage:") || lower.includes("unknown flag") || lower.includes("unknown command");
158992
+ }
158993
+ function parsePiModels(output) {
158994
+ const models = [];
158995
+ const seen = /* @__PURE__ */ new Set();
158996
+ for (const raw of output.split("\n")) {
158997
+ const line = raw.trim();
158998
+ if (!line || isPiDiscoveryNoise(line)) continue;
158999
+ const fields = line.split(/\s+/).filter(Boolean);
159000
+ if (fields.length === 0) continue;
159001
+ const first = fields[0];
159002
+ if (first.toLowerCase() === "provider") continue;
159003
+ let id;
159004
+ if (/[:/]/.test(first)) {
159005
+ id = first.replace(":", "/");
159006
+ } else if (fields.length >= 2) {
159007
+ id = `${first}/${fields[1]}`;
159008
+ } else {
159009
+ continue;
159010
+ }
159011
+ const slash = id.indexOf("/");
159012
+ if (slash <= 0 || slash === id.length - 1) continue;
159013
+ if (seen.has(id)) continue;
159014
+ seen.add(id);
159015
+ models.push({ id, label: id, provider: id.slice(0, slash) });
159016
+ }
159017
+ return models;
159018
+ }
158979
159019
  async function discoverPiModels(bin) {
158980
- throw new Error("discoverPiModels: TODO");
159020
+ const out = await runCapture(bin ?? "pi", ["--list-models"]);
159021
+ return out === void 0 ? [] : parsePiModels(out);
158981
159022
  }
158982
159023
  async function discoverAntigravityModels(bin) {
158983
159024
  throw new Error("discoverAntigravityModels: TODO");
158984
159025
  }
159026
+ async function runCapture(bin, args, timeoutMs = 15e3) {
159027
+ return await new Promise((resolve10) => {
159028
+ let child;
159029
+ try {
159030
+ child = (0, import_node_child_process8.spawn)(bin, args, { stdio: ["ignore", "pipe", "ignore"], env: { ...process.env } });
159031
+ } catch {
159032
+ resolve10(void 0);
159033
+ return;
159034
+ }
159035
+ let out = "";
159036
+ let settled = false;
159037
+ const done = (v2) => {
159038
+ if (!settled) {
159039
+ settled = true;
159040
+ clearTimeout(timer);
159041
+ resolve10(v2);
159042
+ }
159043
+ };
159044
+ const timer = setTimeout(() => {
159045
+ try {
159046
+ child.kill("SIGKILL");
159047
+ } catch {
159048
+ }
159049
+ done(void 0);
159050
+ }, timeoutMs);
159051
+ child.stdout?.on("data", (d) => {
159052
+ out += d.toString();
159053
+ });
159054
+ child.on("error", () => done(void 0));
159055
+ child.on("close", (code) => done(code === 0 ? out : void 0));
159056
+ });
159057
+ }
158985
159058
  async function discoverACPModels(bin, provider, args = ["acp"]) {
158986
159059
  const child = (() => {
158987
159060
  try {
@@ -166721,12 +166794,11 @@ function systemHandoffFor(run, checkpoint = null, effects = []) {
166721
166794
  summary: `[system_reconstructed] attempt=${run.id} outcome=${outcome} reason=${terminalReason}; ${progress}`.slice(0, 400),
166722
166795
  changedOutputs: structuredClone(run.outputRefs),
166723
166796
  unresolvedIssues: [],
166724
- risks: [
166725
- ...run.errorMessage ? [run.errorMessage.slice(0, 400)] : [],
166726
- ...pendingEffects || failedEffects ? [`external effects: pending=${pendingEffects}, failed=${failedEffects}`] : []
166727
- ],
166797
+ // 与 PG 触发器同口径(2026-08-18):risks / verificationGaps 只装业务语义的东西。会话怎么死的
166798
+ // 已在 summary reason= 段里,不再冒充成「交付物的风险」;「没有断点」也不是「验证缺口」。
166799
+ risks: pendingEffects || failedEffects ? [`external effects: pending=${pendingEffects}, failed=${failedEffects}`] : [],
166728
166800
  nextActions: structuredClone(checkpoint?.pendingSteps ?? []),
166729
- verificationGaps: checkpoint ? [] : ["No valid pre-terminal checkpoint was available."],
166801
+ verificationGaps: [],
166730
166802
  userHandoff: null,
166731
166803
  createdAt: run.endedAt ?? run.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
166732
166804
  };
@@ -167116,6 +167188,13 @@ var init_memory_trace_store = __esm({
167116
167188
  const handoff = this.handoffs.get(attemptId);
167117
167189
  return handoff ? structuredClone(handoff) : null;
167118
167190
  }
167191
+ async getHandoffByOutputVersion(version2) {
167192
+ const hits = [...this.handoffs.values()].filter((h) => h.changedOutputs.some((ref2) => ref2.version === version2));
167193
+ if (hits.length === 0) return null;
167194
+ let best = hits[0];
167195
+ for (const h of hits.slice(1)) if (h.createdAt >= best.createdAt) best = h;
167196
+ return structuredClone(best);
167197
+ }
167119
167198
  async listAttempts(workOrderId) {
167120
167199
  return [...this.runs.values()].filter((run) => run.workOrderId === workOrderId && run.nodeId !== null).sort((a, b2) => (a.nodeId ?? "").localeCompare(b2.nodeId ?? "") || (a.attemptNo ?? 0) - (b2.attemptNo ?? 0)).map((run) => this.decorate(structuredClone(run)));
167121
167200
  }
@@ -184040,7 +184119,7 @@ function createUpstreamHandoffInputResolver(opts) {
184040
184119
  version: input.pinnedWorkId,
184041
184120
  ...upstreamNode?.title ? { label: upstreamNode.title } : {}
184042
184121
  }];
184043
- const deliveredRow = typeof work.sessionRef === "string" && work.sessionRef ? await opts.getHandoff(work.sessionRef).catch(() => null) : null;
184122
+ const deliveredRow = await opts.getHandoffByOutputVersion(input.pinnedWorkId).catch(() => null);
184044
184123
  const systemHandoff = () => renderDeliveredWorkHandoff({
184045
184124
  upstreamNodeId: input.upstreamNodeId,
184046
184125
  upstreamTitle: upstreamNode?.title,
@@ -187722,8 +187801,30 @@ ${ctx.nodeFault}
187722
187801
  ...prov?.connectorCreds && prov.connectorCreds.length > 0 ? { connectorCreds: prov.connectorCreds } : {}
187723
187802
  };
187724
187803
  this.deps.log?.(`[coordinator] ${logMsg}`);
187804
+ const coordinatorRunId = `coordinate:${runtimeSessionId}`;
187805
+ if (this.deps.recordCoordinatorRun) {
187806
+ await this.deps.recordCoordinatorRun({
187807
+ runId: coordinatorRunId,
187808
+ actorId,
187809
+ artifactId,
187810
+ workOrderId: workspace ?? null,
187811
+ runtimeSessionId,
187812
+ bundleFiles: Object.keys(job.bundle.files)
187813
+ }).catch((error2) => {
187814
+ this.deps.log?.(`[coordinator] \u8D26\u672C\u767B\u8BB0\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u4F1A\u8BDD\uFF09\uFF1A${String(error2)}`);
187815
+ });
187816
+ }
187725
187817
  const handle = await this.deps.adapter.spawn(job);
187726
187818
  const exit = await new Promise((resolve10) => handle.onExit(resolve10));
187819
+ if (this.deps.finishCoordinatorRun) {
187820
+ await this.deps.finishCoordinatorRun(coordinatorRunId, {
187821
+ status: exit.code === 0 ? "succeeded" : "failed",
187822
+ exitCode: exit.code,
187823
+ ...exit.reason ? { exitReason: String(exit.reason) } : {}
187824
+ }).catch((error2) => {
187825
+ this.deps.log?.(`[coordinator] \u8D26\u672C\u6536\u5C3E\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u4F1A\u8BDD\uFF09\uFF1A${String(error2)}`);
187826
+ });
187827
+ }
187727
187828
  await this.finalizeStage(token);
187728
187829
  this.registerRetained(artifactId, actorId, runtimeSessionId);
187729
187830
  return { sessionId: runtimeSessionId, managerActorId: actorId, exit };
@@ -190889,6 +190990,9 @@ var init_postgres_trace = __esm({
190889
190990
  await pool.query(`ALTER TABLE "${s2}".node_handoffs ADD COLUMN IF NOT EXISTS part text`);
190890
190991
  await pool.query(`ALTER TABLE "${s2}".node_handoffs ADD COLUMN IF NOT EXISTS user_handoff jsonb`);
190891
190992
  await pool.query(`ALTER TABLE "${s2}".node_handoffs DROP CONSTRAINT IF EXISTS node_handoffs_summary_check`);
190993
+ await pool.query(
190994
+ `CREATE INDEX IF NOT EXISTS node_handoffs_changed_outputs_idx ON "${s2}".node_handoffs USING GIN (changed_outputs)`
190995
+ );
190892
190996
  await pool.query(`
190893
190997
  UPDATE "${s2}".node_handoffs h
190894
190998
  SET job_key=COALESCE(NULLIF(h.job_key, ''), r.job_key, 'attempt:' || h.attempt_id), part=r.part
@@ -190998,15 +191102,26 @@ var init_postgres_trace = __esm({
190998
191102
  END,
190999
191103
  400
191000
191104
  );
191105
+ -- 2026-08-18\uFF1Arisks / verification_gaps \u53EA\u88C5 **\u4E1A\u52A1\u8BED\u4E49** \u7684\u4E1C\u897F\u3002
191106
+ --
191107
+ -- \u75C5\u6839\uFF1A\u8FD9\u91CC\u539F\u672C\u628A NEW.error_message \u585E\u8FDB risks\u3001\u628A\u300C\u6CA1\u6709\u53EF\u7528\u65AD\u70B9\u300D\u585E\u8FDB verification_gaps\u3002
191108
+ -- \u4E24\u8005\u90FD\u4E0D\u662F\u5B83\u4EEC\u5B57\u9762\u7684\u610F\u601D\u2014\u2014\u7EBF\u4E0A\u771F\u5B9E\u503C\u662F
191109
+ -- risks = ["[success] You've hit your session limit - resets 4:40pm (UTC)"]
191110
+ -- verification_gaps = ["No valid pre-terminal checkpoint was available."]
191111
+ -- \u524D\u8005\u662F\u300C\u8FD9\u6B21\u4F1A\u8BDD\u600E\u4E48\u6B7B\u7684\u300D\uFF0C\u540E\u8005\u662F\u300C\u7CFB\u7EDF\u81EA\u5DF1\u6CA1\u6599\u300D\uFF0C\u90FD\u4E0D\u662F\u300C\u4EA4\u4ED8\u7269\u6709\u4EC0\u4E48\u98CE\u9669 / \u54EA\u91CC\u6CA1\u6838\u9A8C\u300D\u3002
191112
+ -- \u5371\u5BB3\u6709\u4E8C\uFF1A(1) \u4EA4\u4ED8\u6210\u529F\u4E4B\u540E\u4F1A\u8BDD\u624D\u8D85\u65F6\u7684\u60C5\u5F62\uFF0C\u8FD9\u4E9B\u4F1A\u88AB\u586B\u8FDB\u7A7A\u5B57\u6BB5\u5E76 **\u771F\u7684\u88AB\u4E0B\u6E38\u8BFB\u5230**\uFF1B
191113
+ -- (2) \u7EDF\u8BA1\u586B\u5145\u7387\u65F6\u5168\u662F\u566A\u97F3\uFF0C\u770B\u8D77\u6765 80% \u6709\u503C\uFF0C\u5176\u5B9E\u6CA1\u4E00\u6761\u662F\u6267\u884C\u4EBA\u5199\u7684\u3002
191114
+ --
191115
+ -- \u4E24\u6761\u4FE1\u606F\u90FD\u4E0D\u4E22\uFF1A\u7EC8\u6001\u539F\u56E0\u5DF2\u5728 summary \u7684 reason= \u6BB5\u91CC\uFF08terminal_reason \u5C31\u53D6\u81EA
191116
+ -- error_message\uFF09\uFF0C\u300C\u6CA1\u6709\u65AD\u70B9\u300D\u4E5F\u5DF2\u5728 summary \u7684 no valid pre-terminal checkpoint \u91CC\u3002
191117
+ -- \u8FD9\u91CC\u53EA\u662F\u4E0D\u518D\u628A\u5B83\u4EEC\u5192\u5145\u6210\u4E1A\u52A1\u5B57\u6BB5\u3002
191118
+ --
191119
+ -- \u5916\u90E8\u6548\u5E94\u7559\u5728 risks\uFF1A\u534A\u6210\u54C1\u526F\u4F5C\u7528\uFF08\u5DF2\u53D1\u51FA\u7684\u8BF7\u6C42 / \u5EFA\u4E86\u4E00\u534A\u7684\u8D44\u6E90\uFF09\u786E\u5B9E\u662F\u4E0B\u6E38\u8BE5\u77E5\u9053\u7684\u98CE\u9669\u3002
191001
191120
  reconstructed_risks :=
191002
- CASE WHEN NEW.error_message IS NULL THEN '[]'::jsonb
191003
- ELSE jsonb_build_array(left(NEW.error_message, 400)) END ||
191004
191121
  CASE WHEN COALESCE(pending_effects, 0) = 0 AND COALESCE(failed_effects, 0) = 0 THEN '[]'::jsonb
191005
191122
  ELSE jsonb_build_array('external effects: pending=' || COALESCE(pending_effects, 0) ||
191006
191123
  ', failed=' || COALESCE(failed_effects, 0)) END;
191007
- reconstructed_gaps := CASE WHEN latest_checkpoint_id IS NULL
191008
- THEN jsonb_build_array('No valid pre-terminal checkpoint was available.')
191009
- ELSE '[]'::jsonb END;
191124
+ reconstructed_gaps := '[]'::jsonb;
191010
191125
  INSERT INTO "${s2}".node_handoffs AS current_handoff
191011
191126
  (handoff_id, attempt_id, job_key, part, produced_by, outcome, summary, changed_outputs,
191012
191127
  unresolved_issues, risks, next_actions, verification_gaps, user_handoff, created_at)
@@ -191954,6 +192069,15 @@ var init_postgres_trace = __esm({
191954
192069
  const r = await this.pool.query(`SELECT * FROM ${this.s}.node_handoffs WHERE attempt_id=$1`, [attemptId]);
191955
192070
  return r.rows[0] ? rowToHandoff(r.rows[0]) : null;
191956
192071
  }
192072
+ async getHandoffByOutputVersion(version2) {
192073
+ const r = await this.pool.query(
192074
+ `SELECT * FROM ${this.s}.node_handoffs
192075
+ WHERE changed_outputs @> $1::jsonb
192076
+ ORDER BY created_at DESC LIMIT 1`,
192077
+ [JSON.stringify([{ version: version2 }])]
192078
+ );
192079
+ return r.rows[0] ? rowToHandoff(r.rows[0]) : null;
192080
+ }
191957
192081
  async listAttempts(workOrderId) {
191958
192082
  const r = await this.pool.query(
191959
192083
  `SELECT r.*, (SELECT count(*) FROM ${this.s}.agent_tool_calls tc WHERE tc.run_id=r.id)::int AS tool_call_count
@@ -197142,7 +197266,8 @@ async function startServe(opts) {
197142
197266
  if (!store) throw new Error(`engine store unavailable for ${companyId}`);
197143
197267
  return store.transaction((tx) => tx.loadWorkorder(workOrderId));
197144
197268
  },
197145
- getHandoff: (attemptId) => traceStore.getHandoff(attemptId)
197269
+ getHandoff: (attemptId) => traceStore.getHandoff(attemptId),
197270
+ getHandoffByOutputVersion: (version2) => traceStore.getHandoffByOutputVersion(version2)
197146
197271
  }),
197147
197272
  executionContinuityInstructions: continuityMode === "off" ? renderBusinessHandoffProtocol() : renderContinuityProtocol(),
197148
197273
  // ★ 恢复包注入(2026-08-17):从「只有 resume 实验组才给」改成「只要账本开着就给」——
@@ -197762,6 +197887,31 @@ ${st.detail}
197762
197887
  const view = await executionContinuity.service.coordinatorView(workOrderId, defaultCompanyId);
197763
197888
  return view ? renderCoordinatorView(view) : null;
197764
197889
  },
197890
+ // D2(2026-08-18):协调者会话进执行账本。inputRefs 记下 bundle 里实际发出的文件——
197891
+ // 这是唯一能证明「COORDINATOR_VIEW.md 到底有没有随会话发出去」的痕迹。两处都 fail-open。
197892
+ recordCoordinatorRun: async (input) => {
197893
+ await traceStore.createRun({
197894
+ id: input.runId,
197895
+ actorId: input.actorId,
197896
+ runtimeKind: "claude-code",
197897
+ triggerKind: "intervention",
197898
+ artifactId: input.artifactId,
197899
+ nodeId: input.artifactId,
197900
+ workOrderId: input.workOrderId,
197901
+ runtimeSessionId: input.runtimeSessionId,
197902
+ jobKey: `coordinate::${input.artifactId}`,
197903
+ action: "coordinate",
197904
+ inputRefs: input.bundleFiles.map((name) => ({ kind: "bundle", id: name }))
197905
+ });
197906
+ },
197907
+ finishCoordinatorRun: async (runId, outcome) => {
197908
+ await traceStore.updateRun(runId, {
197909
+ status: outcome.status,
197910
+ exitCode: outcome.exitCode,
197911
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
197912
+ ...outcome.exitReason ? { exitReason: outcome.exitReason } : {}
197913
+ });
197914
+ },
197765
197915
  // 阻塞诊断(proposal D1/D3):派发器运行时信号(queued/fused/backoff/hasInFlight)注入诊断,
197766
197916
  // 让协调者把"资源 / 运行时"病因和"图病"分开——资源排队的节点不会被误唤去砍流程。
197767
197917
  runtimeSignals: (id) => {
@@ -199453,13 +199603,13 @@ var COMMAND_DECLS = {
199453
199603
  },
199454
199604
  "continuity-checkpoint": {
199455
199605
  group: "\u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09",
199456
- usage: "oasis continuity-checkpoint --pending <json-string-array> --recoverability full|partial|none [--trigger plan_completed|stage_completed] [--refs <json-array>] [--completed <json-string-array>]",
199606
+ usage: "oasis continuity-checkpoint --pending <list> --recoverability full|partial|none [--trigger plan_completed|stage_completed] [--refs <json-array>] [--completed <list>]",
199457
199607
  description: "\u4E3A\u5F53\u524D\u6D3E\u53D1 attempt \u8FFD\u52A0\u53EF\u6062\u590D\u68C0\u67E5\u70B9\uFF08\u81EA\u52A8\u4FDD\u7559\u6700\u65B0\u4E94\u4E2A\uFF09\u3002",
199458
199608
  flags: [
199459
- { name: "pending", desc: "\u5F85\u5B8C\u6210\u6B65\u9AA4 JSON string array", required: true },
199609
+ { name: "pending", desc: `\u5F85\u5B8C\u6210\u6B65\u9AA4\u3002JSON \u6570\u7EC4 '["a","b"]' \u6216\u5206\u53F7\u5206\u9694 "a; b" \u90FD\u6536`, required: true },
199460
199610
  { name: "recoverability", desc: "\u6062\u590D\u7A0B\u5EA6\uFF08full | partial | none\uFF09", required: true },
199461
199611
  { name: "refs", desc: "\u5DF2\u6301\u4E45\u5316\u4EA7\u51FA\u5F15\u7528 JSON array" },
199462
- { name: "completed", desc: "\u5DF2\u5B8C\u6210\u7A33\u5B9A\u6B65\u9AA4 id JSON string array" },
199612
+ { name: "completed", desc: "\u5DF2\u5B8C\u6210\u7684\u7A33\u5B9A\u6B65\u9AA4 id\u3002JSON \u6570\u7EC4\u6216\u5206\u53F7\u5206\u9694\u90FD\u6536" },
199463
199613
  { name: "trigger", desc: "\u7ED3\u6784\u5316\u8FB9\u754C\uFF08plan_completed | stage_completed\uFF1B\u7701\u7565\u4E3A\u666E\u901A agent checkpoint\uFF09" }
199464
199614
  ],
199465
199615
  examples: [`oasis continuity-checkpoint --pending '["run tests"]' --recoverability full --refs '[{"kind":"file","id":"src/x.ts"}]'`]
@@ -200572,6 +200722,19 @@ function semicolonList(raw, field) {
200572
200722
  const items = raw.split(";").map((x2) => x2.trim()).filter(Boolean);
200573
200723
  return items.length > 0 ? { [field]: items } : {};
200574
200724
  }
200725
+ function parseStringArrayFlag(value, name) {
200726
+ const trimmed = value.trim();
200727
+ if (trimmed.startsWith("[")) {
200728
+ const parsed = JSON.parse(trimmed);
200729
+ if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== "string")) {
200730
+ throw new Error(`--${name} \u5FC5\u987B\u662F JSON string array`);
200731
+ }
200732
+ return parsed;
200733
+ }
200734
+ const items = trimmed.split(";").map((x2) => x2.trim()).filter(Boolean);
200735
+ if (items.length === 0) throw new Error(`--${name} \u4E0D\u80FD\u4E3A\u7A7A\uFF08JSON string array\uFF0C\u6216\u5206\u53F7\u5206\u9694\uFF09`);
200736
+ return items;
200737
+ }
200575
200738
  async function readStdin() {
200576
200739
  if (process.stdin.isTTY) return "";
200577
200740
  const chunks = [];
@@ -201132,13 +201295,6 @@ async function runCli(argv, println = console.log, progressln = console.error) {
201132
201295
  }
201133
201296
  return parsed;
201134
201297
  };
201135
- const parseStringArrayFlag = (value, name) => {
201136
- const parsed = JSON.parse(value);
201137
- if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== "string")) {
201138
- throw new Error(`--${name} \u5FC5\u987B\u662F JSON string array`);
201139
- }
201140
- return parsed;
201141
- };
201142
201298
  const parseArrayFlag = (value, name) => {
201143
201299
  const parsed = JSON.parse(value);
201144
201300
  if (!Array.isArray(parsed)) throw new Error(`--${name} \u5FC5\u987B\u662F JSON array`);
@@ -203242,7 +203398,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
203242
203398
  }
203243
203399
 
203244
203400
  // src/index.ts
203245
- var PKG_VERSION = true ? "0.1.109" : "dev";
203401
+ var PKG_VERSION = true ? "0.1.110" : "dev";
203246
203402
  var OASIS_DIR = path28.join(os11.homedir(), ".oasis");
203247
203403
  var CONFIG_FILE = path28.join(OASIS_DIR, "node-config.json");
203248
203404
  var PID_FILE = path28.join(OASIS_DIR, "node.pid");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.109",
3
+ "version": "0.1.110",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"