oasis_test 0.1.108 → 0.1.109

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 +291 -53
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4092,7 +4092,23 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
4092
4092
  `- \`--unresolved\` **\u4F60\u77E5\u9053\u4F46\u6CA1\u89E3\u51B3\u7684** \u2014\u2014 \u514D\u5F97\u4E0B\u6E38\u91CD\u590D\u8E29\u4F60\u5DF2\u7ECF\u8E29\u8FC7\u7684\u5751\u3002\u4F8B\uFF1A\`--unresolved "\u7EBF\u4E0A\u914D\u989D\u6CA1\u786E\u8BA4"\``,
4093
4093
  `- \`--risks\` **\u4EA4\u4ED8\u7269\u672C\u8EAB\u6CA1\u9519\u3001\u4F46\u7528\u7684\u65F6\u5019\u8981\u5F53\u5FC3\u7684** \u2014\u2014 \u4F8B\uFF1A\`--risks "\u5E76\u53D1\u8C03\u7528\u53EF\u80FD\u89E6\u53D1\u9650\u6D41"\``,
4094
4094
  `- \`--next\` **\u5EFA\u8BAE\u4E0B\u6E38\u5148\u505A\u54EA\u4E00\u6B65**\uFF08\u53EF\u9009\uFF09\u2014\u2014 \u4F8B\uFF1A\`--next "\u5148\u8DD1\u4E00\u6B21\u5C0F\u6D41\u91CF\u7070\u5EA6"\``,
4095
- `\u5199 \`none\` = \u300C\u6211\u786E\u8BA4\u6CA1\u6709\u300D\uFF1B\u4E0D\u5199 = \u300C\u6CA1\u4EBA\u5199\u8FC7\u300D\u3002**\u8FD9\u4E24\u4EF6\u4E8B\u5BF9\u4E0B\u6E38\u5B8C\u5168\u4E0D\u540C\uFF0C\u522B\u6DF7\u3002**`
4095
+ `\u5199 \`none\` = \u300C\u6211\u786E\u8BA4\u6CA1\u6709\u300D\uFF1B\u4E0D\u5199 = \u300C\u6CA1\u4EBA\u5199\u8FC7\u300D\u3002**\u8FD9\u4E24\u4EF6\u4E8B\u5BF9\u4E0B\u6E38\u5B8C\u5168\u4E0D\u540C\uFF0C\u522B\u6DF7\u3002**`,
4096
+ ``,
4097
+ `### \u4F1A\u8BDD\u53EF\u80FD\u88AB\u780D\uFF1A\u4E2D\u9014\u7559\u4E2A\u65AD\u70B9`,
4098
+ // ★ 2026-08-18:`continuity-checkpoint` 此前在任务书里出现 **0 次**——说明书只在
4099
+ // `execution/CONTINUITY.md`(没人读)和 `oasis help` 里。线上 160 条 checkpoint 只有 6 条带
4100
+ // pendingSteps,且全部来自同一个自己跑 `oasis help continuity-checkpoint` 摸出来的 agent。
4101
+ // 「知道的会用、且用得很好」已被实证,缺的只是这段话。
4102
+ // 刻意不写「过去 24 小时发生 N 次」这类统计:任务书是长期提示词,写死的数字会过期变成假话。
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
+ `\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
+ `\`\`\``,
4106
+ `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`,
4110
+ `\`\`\``,
4111
+ `**\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`
4096
4112
  ],
4097
4113
  // 兜底(§10):上次失败了 → 明确告诉它发生了什么 + 怎么破(首选 add-revision 拆出去)
4098
4114
  ...args.lastFailure ? args.lastFailure.resumed ? [
@@ -158863,6 +158879,8 @@ async function listModels(runtime, executablePath) {
158863
158879
  return cachedDiscovery(runtime, async () => await discoverACPModels(executablePath ?? "kimi", "kimi", ["acp"]) ?? []);
158864
158880
  case "kiro":
158865
158881
  return cachedDiscovery(runtime, async () => await discoverACPModels(executablePath ?? "kiro-cli", "kiro", ["acp"]) ?? []);
158882
+ case "reasonix":
158883
+ return cachedDiscovery(runtime, async () => await discoverACPModels(executablePath ?? "reasonix", "reasonix", ["acp"]) ?? []);
158866
158884
  case "openclaw":
158867
158885
  return cachedDiscovery(runtime, () => discoverOpenclawModels(executablePath));
158868
158886
  default:
@@ -160122,6 +160140,20 @@ function joinOutputParts(parts) {
160122
160140
  if (parts.every((p2) => typeof p2 === "string")) return parts.join("");
160123
160141
  return parts;
160124
160142
  }
160143
+ function pickApprovalOptionId(params) {
160144
+ const raw = params?.options;
160145
+ if (!Array.isArray(raw)) return LEGACY_APPROVE_OPTION_ID;
160146
+ const options = raw.filter(
160147
+ (o) => typeof o?.optionId === "string"
160148
+ );
160149
+ if (options.length === 0) return LEGACY_APPROVE_OPTION_ID;
160150
+ const byId = options.find((o) => o.optionId === LEGACY_APPROVE_OPTION_ID)?.optionId;
160151
+ const byKind = (kind) => options.find((o) => o.kind === kind)?.optionId;
160152
+ const nonReject = options.find(
160153
+ (o) => !String(o.kind ?? o.optionId).startsWith("reject")
160154
+ )?.optionId;
160155
+ return byId ?? byKind("allow_always") ?? byKind("allow_once") ?? nonReject ?? LEGACY_APPROVE_OPTION_ID;
160156
+ }
160125
160157
  function normalizeACPUpdate(data) {
160126
160158
  const d = data;
160127
160159
  if (!d) return ["", data];
@@ -160370,7 +160402,8 @@ async function runACPSession(job, cfg) {
160370
160402
  if (reason === "cancelled") finish({ code: null, reason: "cancelled", transcriptRef });
160371
160403
  },
160372
160404
  () => streamingCurrentTurn,
160373
- cfg.finalUsageIsAuthoritative === true
160405
+ cfg.finalUsageIsAuthoritative === true,
160406
+ cfg.vendorUsageNotification
160374
160407
  );
160375
160408
  usageClient = client;
160376
160409
  const rl = readline3.createInterface({ input: child.stdout });
@@ -160540,7 +160573,7 @@ ${task}` : task;
160540
160573
  }
160541
160574
  };
160542
160575
  }
160543
- var import_node_child_process10, import_node_crypto16, fs11, path11, readline3, ACPClient;
160576
+ var import_node_child_process10, import_node_crypto16, fs11, path11, readline3, ACPClient, LEGACY_APPROVE_OPTION_ID;
160544
160577
  var init_acp = __esm({
160545
160578
  "../adapters/src/_core/acp.ts"() {
160546
160579
  "use strict";
@@ -160559,13 +160592,14 @@ var init_acp = __esm({
160559
160592
  init_transcript();
160560
160593
  init_filter_extra_args();
160561
160594
  ACPClient = class {
160562
- constructor(write, onOutput, onTelemetry, onStop, acceptNotification = () => true, finalUsageIsAuthoritative = false) {
160595
+ constructor(write, onOutput, onTelemetry, onStop, acceptNotification = () => true, finalUsageIsAuthoritative = false, vendorUsage) {
160563
160596
  this.write = write;
160564
160597
  this.onOutput = onOutput;
160565
160598
  this.onTelemetry = onTelemetry;
160566
160599
  this.onStop = onStop;
160567
160600
  this.acceptNotification = acceptNotification;
160568
160601
  this.finalUsageIsAuthoritative = finalUsageIsAuthoritative;
160602
+ this.vendorUsage = vendorUsage;
160569
160603
  }
160570
160604
  nextId = 0;
160571
160605
  pending = /* @__PURE__ */ new Map();
@@ -160579,7 +160613,37 @@ var init_acp = __esm({
160579
160613
  * 是否还在流。每收到一条 session/update / session/notification 就 +1,主循环轮询该值。
160580
160614
  */
160581
160615
  notificationCount = 0;
160616
+ /** 厂商私有用量:已完成轮次的累计 + 当前轮的最新快照,两者相加即 this.usage。 */
160617
+ vendorTurnBase = newUsageAcc();
160618
+ vendorTurnSnapshot = newUsageAcc();
160619
+ applyVendorUsage(params) {
160620
+ const picked = this.vendorUsage?.pick(params);
160621
+ if (!picked) return;
160622
+ this.vendorTurnSnapshot = {
160623
+ inputTokens: picked.inputTokens ?? 0,
160624
+ outputTokens: picked.outputTokens ?? 0,
160625
+ cacheReadTokens: picked.cacheReadTokens ?? 0,
160626
+ cacheCreationTokens: picked.cacheCreationTokens ?? 0
160627
+ };
160628
+ this.usage = {
160629
+ inputTokens: this.vendorTurnBase.inputTokens + this.vendorTurnSnapshot.inputTokens,
160630
+ outputTokens: this.vendorTurnBase.outputTokens + this.vendorTurnSnapshot.outputTokens,
160631
+ cacheReadTokens: this.vendorTurnBase.cacheReadTokens + this.vendorTurnSnapshot.cacheReadTokens,
160632
+ cacheCreationTokens: this.vendorTurnBase.cacheCreationTokens + this.vendorTurnSnapshot.cacheCreationTokens
160633
+ };
160634
+ }
160635
+ /** 新一轮 prompt 发出前,把上一轮的快照折进基数(快照是「当前轮」口径,会归零重来)。 */
160636
+ foldVendorTurn() {
160637
+ this.vendorTurnBase = {
160638
+ inputTokens: this.vendorTurnBase.inputTokens + this.vendorTurnSnapshot.inputTokens,
160639
+ outputTokens: this.vendorTurnBase.outputTokens + this.vendorTurnSnapshot.outputTokens,
160640
+ cacheReadTokens: this.vendorTurnBase.cacheReadTokens + this.vendorTurnSnapshot.cacheReadTokens,
160641
+ cacheCreationTokens: this.vendorTurnBase.cacheCreationTokens + this.vendorTurnSnapshot.cacheCreationTokens
160642
+ };
160643
+ this.vendorTurnSnapshot = newUsageAcc();
160644
+ }
160582
160645
  request(method, params) {
160646
+ if (this.vendorUsage && method === "session/prompt") this.foldVendorTurn();
160583
160647
  const id = this.nextId++;
160584
160648
  return new Promise((resolve10, reject) => {
160585
160649
  this.pending.set(id, { resolve: resolve10, reject, method });
@@ -160631,11 +160695,15 @@ var init_acp = __esm({
160631
160695
  handleAgentRequest(raw) {
160632
160696
  const method = raw["method"];
160633
160697
  const id = raw["id"];
160634
- const resp = method === "session/request_permission" ? { jsonrpc: "2.0", id, result: { outcome: { outcome: "selected", optionId: "approve_for_session" } } } : { jsonrpc: "2.0", id, error: { code: -32601, message: `method not found: ${method}` } };
160698
+ const resp = method === "session/request_permission" ? { jsonrpc: "2.0", id, result: { outcome: { outcome: "selected", optionId: pickApprovalOptionId(raw["params"]) } } } : { jsonrpc: "2.0", id, error: { code: -32601, message: `method not found: ${method}` } };
160635
160699
  this.write(JSON.stringify(resp) + "\n");
160636
160700
  }
160637
160701
  handleNotification(raw) {
160638
160702
  const method = raw["method"];
160703
+ if (this.vendorUsage && method === this.vendorUsage.method) {
160704
+ this.applyVendorUsage(raw["params"]);
160705
+ return;
160706
+ }
160639
160707
  if (method !== "session/update" && method !== "session/notification") return;
160640
160708
  const params = raw["params"];
160641
160709
  if (!params?.update) return;
@@ -160794,6 +160862,7 @@ var init_acp = __esm({
160794
160862
  });
160795
160863
  }
160796
160864
  };
160865
+ LEGACY_APPROVE_OPTION_ID = "approve_for_session";
160797
160866
  }
160798
160867
  });
160799
160868
 
@@ -160895,6 +160964,72 @@ var init_kiro = __esm({
160895
160964
  }
160896
160965
  });
160897
160966
 
160967
+ // ../adapters/src/reasonix/index.ts
160968
+ var REASONIX_BLOCKED_FLAGS, REASONIX_USAGE_NOTIFICATION, ReasonixAdapter;
160969
+ var init_reasonix = __esm({
160970
+ "../adapters/src/reasonix/index.ts"() {
160971
+ "use strict";
160972
+ init_acp();
160973
+ REASONIX_BLOCKED_FLAGS = /* @__PURE__ */ new Map([
160974
+ ["--model", "value"],
160975
+ ["--planner", "value"],
160976
+ ["--sandbox-network", "value"],
160977
+ ["--sandbox-bash", "value"],
160978
+ ["--workspace-only", "boolean"]
160979
+ ]);
160980
+ REASONIX_USAGE_NOTIFICATION = {
160981
+ method: "_reasonix.io/session/status_update",
160982
+ pick(params) {
160983
+ const rec = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
160984
+ const num2 = (v2) => typeof v2 === "number" && Number.isFinite(v2) && v2 >= 0 ? v2 : void 0;
160985
+ const turn = rec(rec(rec(rec(params)?.["status"])?.["usage"])?.["turn"]);
160986
+ if (!turn) return void 0;
160987
+ const promptTokens = num2(turn["promptTokens"]);
160988
+ const cacheHit = num2(turn["cacheHitTokens"]);
160989
+ const cacheMiss = num2(turn["cacheMissTokens"]);
160990
+ const inputTokens = cacheMiss ?? (promptTokens === void 0 ? void 0 : Math.max(0, promptTokens - (cacheHit ?? 0)));
160991
+ const outputTokens = num2(turn["completionTokens"]);
160992
+ if (inputTokens === void 0 && outputTokens === void 0 && cacheHit === void 0) return void 0;
160993
+ return {
160994
+ ...inputTokens !== void 0 ? { inputTokens } : {},
160995
+ ...outputTokens !== void 0 ? { outputTokens } : {},
160996
+ ...cacheHit !== void 0 ? { cacheReadTokens: cacheHit } : {}
160997
+ };
160998
+ }
160999
+ };
161000
+ ReasonixAdapter = class {
161001
+ constructor(opts = {}) {
161002
+ this.opts = opts;
161003
+ }
161004
+ /** ADR-0093:ACP 引擎原生支持对话追加(同 session 二次 session/prompt)。 */
161005
+ capabilities = { appendInput: true };
161006
+ spawn(job) {
161007
+ return runACPSession(job, {
161008
+ bin: this.opts.reasonixBin ?? "reasonix",
161009
+ args: [
161010
+ "acp",
161011
+ "--planner",
161012
+ "auto",
161013
+ "--sandbox-network",
161014
+ "auto",
161015
+ "--sandbox-bash",
161016
+ "auto",
161017
+ "--workspace-only"
161018
+ ],
161019
+ model: this.opts.model,
161020
+ resumeMethod: "session/resume",
161021
+ vendorUsageNotification: REASONIX_USAGE_NOTIFICATION,
161022
+ blockedFlags: REASONIX_BLOCKED_FLAGS,
161023
+ workRoot: this.opts.workRoot,
161024
+ cleanupWorkdir: this.opts.cleanupWorkdir,
161025
+ env: this.opts.env,
161026
+ extraArgs: this.opts.extraArgs
161027
+ });
161028
+ }
161029
+ };
161030
+ }
161031
+ });
161032
+
160898
161033
  // ../adapters/src/_core/subprocess.ts
160899
161034
  async function materialize(job, cfg) {
160900
161035
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
@@ -161975,6 +162110,7 @@ var init_src6 = __esm({
161975
162110
  init_hermes();
161976
162111
  init_kimi();
161977
162112
  init_kiro();
162113
+ init_reasonix();
161978
162114
  init_cursor();
161979
162115
  init_codebuddy();
161980
162116
  init_gemini();
@@ -163962,6 +164098,7 @@ async function startOasisServer(opts) {
163962
164098
  ...tokenClaims.artifactId !== void 0 ? { artifactId: tokenClaims.artifactId } : {},
163963
164099
  durableRefs: tokenClaims.artifactId !== void 0 ? [{ kind: "artifact", id: tokenClaims.artifactId, label: body.command }] : [],
163964
164100
  at: (/* @__PURE__ */ new Date()).toISOString(),
164101
+ ...listArg("pendingSteps") ? { pendingSteps: listArg("pendingSteps") } : {},
163965
164102
  ...delivered ? { delivered } : {}
163966
164103
  });
163967
164104
  } catch (error2) {
@@ -166323,7 +166460,14 @@ var init_memory_registry_store = __esm({
166323
166460
  this.skillFiles.delete(skillId);
166324
166461
  }
166325
166462
  async putVariable(v2) {
166326
- this.variables.set(this._varKey(v2.key, v2.actorId, v2.projectId), { ...v2 });
166463
+ const mk = this._varKey(v2.key, v2.actorId, v2.projectId);
166464
+ const ex = this.variables.get(mk);
166465
+ this.variables.set(mk, { ...v2, ...ex?.lastUsedAt !== void 0 ? { lastUsedAt: ex.lastUsedAt } : {} });
166466
+ }
166467
+ async touchVariableUsage(key, actorId, projectId, when) {
166468
+ const mk = this._varKey(key, actorId, projectId);
166469
+ const ex = this.variables.get(mk);
166470
+ if (ex) this.variables.set(mk, { ...ex, lastUsedAt: when });
166327
166471
  }
166328
166472
  async patchVariableValue(key, actorId, valueEncrypted, updatedAt) {
166329
166473
  const mk = this._varKey(key, actorId);
@@ -174471,9 +174615,37 @@ ${input.description}
174471
174615
  // 非连接器写入到此 deliveryMode 必非空(上面已拦);连接器写入沿用 env(其值经 sensitiveVars 剔除,不进 env)。
174472
174616
  deliveryMode: v2.deliveryMode ?? "env",
174473
174617
  valueEncrypted: v2.encrypted === false ? `plain:${v2.value}` : this.encrypt(v2.value),
174474
- updatedAt: this.now()
174618
+ updatedAt: this.now(),
174619
+ // ADR 凭据保险库补章 §D2.2:expiresAt 写侧穿透——**显式带 key**(含 undefined),使清空(传空→undefined)
174620
+ // 也落到底(store 两实现都按此覆盖)。lastUsedAt 从不由写侧传,取用时另刷(§D2.3)。
174621
+ expiresAt: v2.expiresAt
174475
174622
  });
174476
174623
  }
174624
+ /** ADR 凭据保险库补章 §D2.3:某一行变量「明文真被取用」→ 刷 lastUsedAt。行按 (key, actorId?, projectId?)
174625
+ * 唯一键定位(与 put/delete 同址)。store 未实现该方法时静默跳过(不影响主功能)。 */
174626
+ async touchVariableUsage(key, origin, when) {
174627
+ await this.opts.store.touchVariableUsage?.(key, origin?.actorId, origin?.projectId, when ?? this.now());
174628
+ }
174629
+ /**
174630
+ * ADR 凭据保险库补章 §D1.2:**人类控制台** reveal 的取值——不走 agent 的 `resolveActorProvisionEntries`
174631
+ * 解析链(人类既无 personal 变量也无派单 artifactId,那条链恒空)。直接按存储唯一键取该行、解出明文。
174632
+ * - `selector` 由控制台列表行给出(personal 带 actorId、project 带 projectId、global 两者皆空)——
174633
+ * 与 `GET /api/variables`「对所有人类返回全量」的可见口径一致(补章 §D1.3),列得到即 reveal 得到。
174634
+ * - 命中返回明文 + 该行的 origin(供刷 lastUsedAt);未命中(无此行)返回 null(路由映射 403,与 agent 同壳)。
174635
+ */
174636
+ async revealHumanValue(key, selector) {
174637
+ const wantActor = selector?.actorId;
174638
+ const wantProject = selector?.projectId;
174639
+ const rows = await this.opts.store.listVariables();
174640
+ const row = rows.find(
174641
+ (r) => r.key === key && (r.actorId ?? void 0) === (wantActor ?? void 0) && (r.projectId ?? void 0) === (wantProject ?? void 0)
174642
+ );
174643
+ if (!row) return null;
174644
+ return {
174645
+ value: this.decodeCiphertext(row.valueEncrypted),
174646
+ origin: { ...row.actorId !== void 0 ? { actorId: row.actorId } : {}, ...row.projectId !== void 0 ? { projectId: row.projectId } : {} }
174647
+ };
174648
+ }
174477
174649
  /** 更新已有变量的 encrypted 属性(重新加密或解密),不改其他字段 */
174478
174650
  async patchVariableEncryption(key, actorId, encrypted) {
174479
174651
  const ct = await this.opts.store.getVariableCiphertext(key, actorId);
@@ -174512,7 +174684,10 @@ ${input.description}
174512
174684
  // 缺省视为 env(ADR §4.4;存量行读侧统一回填)
174513
174685
  encrypted: !isPlain,
174514
174686
  maskedValue: isPlain ? r.valueEncrypted.slice(6) : mask(this.decrypt(r.valueEncrypted)),
174515
- updatedAt: r.updatedAt
174687
+ updatedAt: r.updatedAt,
174688
+ // ADR 凭据保险库补章 §D2.1:到期/取用时间戳透传(展示层据此染色;补章 §D2.4)。
174689
+ ...r.expiresAt !== void 0 ? { expiresAt: r.expiresAt } : {},
174690
+ ...r.lastUsedAt !== void 0 ? { lastUsedAt: r.lastUsedAt } : {}
174516
174691
  };
174517
174692
  });
174518
174693
  }
@@ -174605,7 +174780,12 @@ ${input.description}
174605
174780
  const gated = (row) => !row.connectorId || enabledConnectors.has(row.connectorId);
174606
174781
  const put = (row) => {
174607
174782
  if (!gated(row)) return;
174608
- merged.set(row.key, { key: row.key, value: this.decodeCiphertext(row.valueEncrypted), deliveryMode: row.deliveryMode ?? "env" });
174783
+ merged.set(row.key, {
174784
+ key: row.key,
174785
+ value: this.decodeCiphertext(row.valueEncrypted),
174786
+ deliveryMode: row.deliveryMode ?? "env",
174787
+ origin: { ...row.actorId !== void 0 ? { actorId: row.actorId } : {}, ...row.projectId !== void 0 ? { projectId: row.projectId } : {} }
174788
+ });
174609
174789
  };
174610
174790
  for (const row of rows) {
174611
174791
  if (row.scope === "global" && !row.actorId) put(row);
@@ -174625,7 +174805,7 @@ ${input.description}
174625
174805
  async resolveRevealValue(actorId, key, opts) {
174626
174806
  const entries = await this.resolveActorProvisionEntries(actorId, { ...opts, refreshConnectors: false });
174627
174807
  const hit = entries.find((e) => e.key === key);
174628
- return hit ? { value: hit.value } : null;
174808
+ return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
174629
174809
  }
174630
174810
  encrypt(plain) {
174631
174811
  const iv = (0, import_node_crypto26.randomBytes)(12);
@@ -175854,6 +176034,21 @@ var init_connector_skills = __esm({
175854
176034
  function isKnownRevealSource(source) {
175855
176035
  return CREDENTIAL_REVEAL_SOURCES.has(source) || source.startsWith("agent-skill:");
175856
176036
  }
176037
+ function clientMetaFromReq(req) {
176038
+ const fwd = req.raw?.headers?.["x-forwarded-for"];
176039
+ const fwdFirst = (Array.isArray(fwd) ? fwd[0] : fwd)?.split(",")[0]?.trim();
176040
+ const clientIp = fwdFirst || req.raw?.socket?.remoteAddress || void 0;
176041
+ const ua = req.raw?.headers?.["user-agent"];
176042
+ const userAgent = (Array.isArray(ua) ? ua[0] : ua) || void 0;
176043
+ return { ...clientIp ? { clientIp } : {}, ...userAgent ? { userAgent } : {} };
176044
+ }
176045
+ function normalizeExpiresAt(raw) {
176046
+ if (raw === void 0 || raw === null || raw === "") return void 0;
176047
+ if (typeof raw !== "string") throw new ApiError(400, "BAD_REQUEST", "expiresAt \u987B\u4E3A ISO-8601 \u5B57\u7B26\u4E32");
176048
+ const t = Date.parse(raw);
176049
+ if (Number.isNaN(t)) throw new ApiError(400, "BAD_REQUEST", `expiresAt \u4E0D\u662F\u5408\u6CD5\u65E5\u671F\uFF1A${raw}`);
176050
+ return new Date(t).toISOString();
176051
+ }
175857
176052
  function positionsFromPayload(body) {
175858
176053
  if (!body) return void 0;
175859
176054
  if (Object.prototype.hasOwnProperty.call(body, "roles")) {
@@ -175888,6 +176083,8 @@ function actorsDomain(opts) {
175888
176083
  const { resolveCtx } = opts;
175889
176084
  const revealLimits = opts.credentialRevealLimits ?? { perSession: 200, perSessionPerKey: 20 };
175890
176085
  const revealLimiter = new RevealRateLimiter(revealLimits.perSession, revealLimits.perSessionPerKey);
176086
+ const consoleRevealLimits = opts.credentialRevealLimits?.console ?? { perSession: 60, perSessionPerKey: 10 };
176087
+ const consoleRevealLimiter = new RevealRateLimiter(consoleRevealLimits.perSession, consoleRevealLimits.perSessionPerKey);
175891
176088
  return (router) => {
175892
176089
  router.get("/api/actors", async (req) => {
175893
176090
  const { service } = await resolveCtx(req.auth.companyId);
@@ -176174,11 +176371,6 @@ function actorsDomain(opts) {
176174
176371
  }
176175
176372
  };
176176
176373
  const auditVariableChange = async (req, kind, variableKey, targetScope) => {
176177
- const fwd = req.raw?.headers?.["x-forwarded-for"];
176178
- const fwdFirst = (Array.isArray(fwd) ? fwd[0] : fwd)?.split(",")[0]?.trim();
176179
- const clientIp = fwdFirst || req.raw?.socket?.remoteAddress || void 0;
176180
- const ua = req.raw?.headers?.["user-agent"];
176181
- const userAgent = (Array.isArray(ua) ? ua[0] : ua) || void 0;
176182
176374
  await opts.credentialAudit?.({
176183
176375
  kind,
176184
176376
  actor: req.auth.actor,
@@ -176186,8 +176378,7 @@ function actorsDomain(opts) {
176186
176378
  targetScope,
176187
176379
  source: "console",
176188
176380
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
176189
- ...clientIp ? { clientIp } : {},
176190
- ...userAgent ? { userAgent } : {}
176381
+ ...clientMetaFromReq(req)
176191
176382
  });
176192
176383
  };
176193
176384
  router.get("/api/variables", async (req) => {
@@ -176200,6 +176391,7 @@ function actorsDomain(opts) {
176200
176391
  const { service } = await resolveCtx(req.auth.companyId);
176201
176392
  const b2 = req.body;
176202
176393
  if (!b2?.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
176394
+ const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
176203
176395
  if (b2.scope !== "global" && b2.scope !== "personal" && b2.scope !== "project") {
176204
176396
  throw new ApiError(
176205
176397
  400,
@@ -176240,7 +176432,8 @@ function actorsDomain(opts) {
176240
176432
  ...b2.deliveryMode !== void 0 ? { deliveryMode: b2.deliveryMode } : {},
176241
176433
  ...b2.connectorId !== void 0 ? { connectorId: b2.connectorId } : {},
176242
176434
  ...b2.overrides !== void 0 ? { overrides: b2.overrides } : {},
176243
- ...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {}
176435
+ ...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {},
176436
+ expiresAt: expiresAt2
176244
176437
  });
176245
176438
  await auditVariableChange(
176246
176439
  req,
@@ -176278,6 +176471,7 @@ function actorsDomain(opts) {
176278
176471
  const actorId = req.params.id;
176279
176472
  const b2 = req.body;
176280
176473
  if (!b2?.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
176474
+ const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
176281
176475
  if (b2.deliveryMode !== void 0 && b2.deliveryMode !== "env" && b2.deliveryMode !== "ref" && b2.deliveryMode !== "broker") {
176282
176476
  throw new ApiError(400, "BAD_REQUEST", "deliveryMode \u53EA\u80FD\u662F env\u3001ref \u6216 broker");
176283
176477
  }
@@ -176308,7 +176502,8 @@ function actorsDomain(opts) {
176308
176502
  ...b2.deliveryMode !== void 0 ? { deliveryMode: b2.deliveryMode } : {},
176309
176503
  ...b2.connectorId !== void 0 ? { connectorId: b2.connectorId } : {},
176310
176504
  ...b2.overrides !== void 0 ? { overrides: b2.overrides } : {},
176311
- ...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {}
176505
+ ...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {},
176506
+ expiresAt: expiresAt2
176312
176507
  });
176313
176508
  await auditVariableChange(req, "credential_write", b2.key, `personal:${actorId}`);
176314
176509
  return { status: 201, body: { ok: true } };
@@ -176329,25 +176524,33 @@ function actorsDomain(opts) {
176329
176524
  const source = typeof b2?.source === "string" && b2.source.trim() || "agent-cli";
176330
176525
  if (!isKnownRevealSource(source)) throw new ApiError(400, "BAD_REQUEST", `\u672A\u8BC6\u522B\u7684 source\u300C${source}\u300D\uFF08\xA74.5.4\uFF1A\u53EA\u63A5\u53D7\u8BC6\u522B\u503C\uFF09`);
176331
176526
  const actor = req.auth.actor;
176527
+ const isHuman2 = isHumanActor(actor);
176528
+ const isConsole = source === "console";
176529
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
176332
176530
  const artifactId = req.auth.dispatch?.artifactId;
176333
176531
  const sessionId = req.auth.dispatch?.sessionId;
176334
- const now = Date.now();
176335
- const timestamp = new Date(now).toISOString();
176336
- const sessionKey = sessionId ?? `${actor}::${artifactId ?? "no-artifact"}`;
176337
176532
  const dispatchFields = { ...sessionId ? { sessionId } : {}, ...artifactId ? { artifactId } : {} };
176338
- const throttled = revealLimiter.check(sessionKey, key, now);
176533
+ const consoleMeta = isConsole ? clientMetaFromReq(req) : {};
176534
+ if (isConsole && !isHuman2) {
176535
+ await opts.credentialAudit?.({ kind: "credential_reveal_denied", actor, variableKey: key, source, timestamp, reason: "no_permission", ...dispatchFields, ...consoleMeta });
176536
+ return { status: 403, body: { code: "denied", key } };
176537
+ }
176538
+ const now = Date.now();
176539
+ const sessionKey = isConsole ? actor : sessionId ?? `${actor}::${artifactId ?? "no-artifact"}`;
176540
+ const limiter = isConsole ? consoleRevealLimiter : revealLimiter;
176541
+ const throttled = limiter.check(sessionKey, key, now);
176339
176542
  if (throttled) {
176340
- await opts.credentialAudit?.({ kind: "credential_reveal_throttled", actor, variableKey: key, source, timestamp, scope: throttled, ...dispatchFields });
176543
+ await opts.credentialAudit?.({ kind: "credential_reveal_throttled", actor, variableKey: key, source, timestamp, scope: throttled, ...dispatchFields, ...consoleMeta });
176341
176544
  return { status: 429, body: { code: "throttled", key, scope: throttled } };
176342
176545
  }
176343
- const scope = artifactId && opts.resolveDispatchScope ? await opts.resolveDispatchScope(artifactId) : {};
176344
- const resolved = await service.resolveRevealValue(actor, key, scope);
176546
+ const resolved = isHuman2 ? await service.revealHumanValue(key, { ...b2?.actorId ? { actorId: b2.actorId } : {}, ...b2?.projectId ? { projectId: b2.projectId } : {} }) : await service.resolveRevealValue(actor, key, artifactId && opts.resolveDispatchScope ? await opts.resolveDispatchScope(artifactId) : {});
176345
176547
  if (!resolved) {
176346
176548
  const reason = await service.hasVariableKey(key) ? "no_permission" : "not_found";
176347
- await opts.credentialAudit?.({ kind: "credential_reveal_denied", actor, variableKey: key, source, timestamp, reason, ...dispatchFields });
176549
+ await opts.credentialAudit?.({ kind: "credential_reveal_denied", actor, variableKey: key, source, timestamp, reason, ...dispatchFields, ...consoleMeta });
176348
176550
  return { status: 403, body: { code: "denied", key } };
176349
176551
  }
176350
- await opts.credentialAudit?.({ kind: "credential_reveal", actor, variableKey: key, source, timestamp, ...dispatchFields });
176552
+ await opts.credentialAudit?.({ kind: "credential_reveal", actor, variableKey: key, source, timestamp, ...dispatchFields, ...consoleMeta });
176553
+ await service.touchVariableUsage(key, resolved.origin, timestamp);
176351
176554
  return { status: 200, body: { value: resolved.value } };
176352
176555
  });
176353
176556
  router.get("/api/variables/reveal-audit", async (req) => {
@@ -176850,7 +177053,7 @@ var init_routes2 = __esm({
176850
177053
  init_image_upload();
176851
177054
  init_skill_materializer();
176852
177055
  init_connector_skills();
176853
- CREDENTIAL_REVEAL_SOURCES = /* @__PURE__ */ new Set(["agent-cli", "agent-exec", "smoke-test", "oasis-internal"]);
177056
+ CREDENTIAL_REVEAL_SOURCES = /* @__PURE__ */ new Set(["agent-cli", "agent-exec", "smoke-test", "oasis-internal", "console"]);
176854
177057
  RevealRateLimiter = class {
176855
177058
  constructor(perSession, perSessionPerKey, ttlMs = 2 * 60 * 6e4) {
176856
177059
  this.perSession = perSession;
@@ -183066,8 +183269,8 @@ function executionContinuityDomain(service) {
183066
183269
  if (b2.changedOutputs !== void 0 && !isRefArray(b2.changedOutputs) || b2.unresolvedIssues !== void 0 && !isStringArray(b2.unresolvedIssues) || b2.risks !== void 0 && !isStringArray(b2.risks) || b2.nextActions !== void 0 && !isStringArray(b2.nextActions) || b2.verificationGaps !== void 0 && !isStringArray(b2.verificationGaps)) {
183067
183270
  throw new ApiError(400, "BAD_REQUEST", "handoff arrays contain invalid values");
183068
183271
  }
183069
- if (!isUserHandoff(b2.userHandoff)) {
183070
- throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11\u5408\u6CD5\u7684 userHandoff\uFF1BAgent \u5FC5\u987B\u63D0\u4EA4\u672C\u6B21\u5DE5\u4F5C\u7684\u4E1A\u52A1\u4EA4\u63A5\u6458\u8981");
183272
+ if (b2.userHandoff !== void 0 && b2.userHandoff !== null && !isUserHandoff(b2.userHandoff)) {
183273
+ throw new ApiError(400, "BAD_REQUEST", "userHandoff \u5F62\u72B6\u975E\u6CD5\uFF08\u53EF\u4EE5\u4E0D\u7ED9\uFF1B\u7ED9\u4E86\u5C31\u8981\u5408\u6CD5\uFF09");
183071
183274
  }
183072
183275
  const handoff = await service.handoff({
183073
183276
  attemptId,
@@ -183118,10 +183321,20 @@ function renderResumePack(pack) {
183118
183321
  if (!pack.previousAttempt) lines.push("- This is the first attempt.");
183119
183322
  else {
183120
183323
  lines.push(`- Attempt ${pack.previousAttempt.attemptNo ?? "?"}: ${pack.previousHandoff?.summary || pack.previousAttempt.status}`);
183121
- if (pack.latestCheckpoint) {
183122
- lines.push(`- Recoverability: ${pack.latestCheckpoint.recoverability}`);
183123
- for (const step of pack.latestCheckpoint.pendingSteps) lines.push(` - pending: ${step}`);
183124
- for (const ref2 of pack.latestCheckpoint.durableRefs) lines.push(` - durable: ${ref2.kind}:${ref2.id}${ref2.version ? `@${ref2.version}` : ""}`);
183324
+ const cp = pack.latestCheckpoint;
183325
+ const done = cp?.completedStepIds ?? [];
183326
+ const durable = (cp?.durableRefs.length ? cp.durableRefs : pack.previousHandoff?.changedOutputs) ?? [];
183327
+ if (cp) lines.push(`- Recoverability: ${cp.recoverability}`);
183328
+ if (done.length > 0) lines.push(`- \u4E0A\u4E00\u8D9F\u5DF2\u5B8C\u6210\u7684\u6B65\u9AA4\uFF1A${done.join("\u3001")}`);
183329
+ for (const ref2 of durable) {
183330
+ lines.push(` - durable: ${ref2.kind}:${ref2.id}${ref2.version ? `@${ref2.version}` : ""}${ref2.label ? ` \u2014 ${ref2.label}` : ""}`);
183331
+ }
183332
+ if (cp && cp.pendingSteps.length > 0) {
183333
+ for (const step of cp.pendingSteps) lines.push(` - pending: ${step}`);
183334
+ } else {
183335
+ lines.push(
183336
+ durable.length > 0 || done.length > 0 ? "- \u672A\u5B8C\u6210\u7684\u6B65\u9AA4\uFF1A**\u672A\u77E5**\uFF08\u4E0A\u4E00\u8D9F\u6CA1\u7559 checkpoint\uFF09\u2014\u2014\u4EE5\u4E0A\u9762\u8FD9\u4E9B\u5DF2\u843D\u5730\u7684\u4EA7\u51FA\u4E3A\u51C6\uFF0C\u81EA\u5DF1\u6838\u5BF9\u8FD8\u7F3A\u4EC0\u4E48\uFF0C\u522B\u4ECE\u5934\u91CD\u505A\u3002" : "- \u4E0A\u4E00\u8D9F\u6CA1\u7559\u4E0B\u4EFB\u4F55\u53EF\u6062\u590D\u7684\u75D5\u8FF9\uFF08\u6CA1\u8DD1\u5230\u4EFB\u4F55\u6301\u4E45\u5316\u547D\u4EE4\uFF09\u2014\u2014\u6309\u9996\u6B21\u6267\u884C\u5904\u7406\u3002"
183337
+ );
183125
183338
  }
183126
183339
  }
183127
183340
  lines.push("", "## External effects");
@@ -183230,6 +183443,7 @@ function renderCoordinatorView(view) {
183230
183443
  function shouldInjectResumePack(pack) {
183231
183444
  const status = pack?.previousAttempt?.status;
183232
183445
  if (!status) return false;
183446
+ if (status === "running" || status === "queued") return false;
183233
183447
  return status !== "succeeded" && status !== "no-output";
183234
183448
  }
183235
183449
  function renderContinuityProtocol() {
@@ -183462,9 +183676,6 @@ var init_service7 = __esm({
183462
183676
  async handoff(input) {
183463
183677
  if (!HANDOFF_OUTCOMES2.has(input.outcome)) throw new Error(`invalid handoff outcome: ${input.outcome}`);
183464
183678
  if (!input.summary.trim()) throw new Error("handoff summary is required");
183465
- if (input.producedBy === "agent" && !input.userHandoff) {
183466
- throw new Error("agent-authored handoff requires userHandoff");
183467
- }
183468
183679
  const userHandoff = input.userHandoff ? normalizeUserHandoff(input.outcome, input.changedOutputs ?? [], input.userHandoff) : void 0;
183469
183680
  const attempt = await this.awaitAttempt(input.attemptId);
183470
183681
  const handoff = await this.afterAttemptVisible(() => this.store.putHandoff({
@@ -183668,8 +183879,7 @@ var init_service7 = __esm({
183668
183879
  "failed"
183669
183880
  ].map((state) => [state, nodes.filter((node) => node.nodeState === state).length]));
183670
183881
  const collaborationStatus = nodes.length > 0 && nodes.every((node) => DONE_STATES.has(node.nodeState)) ? "completed" : nodes.some((node) => BLOCKING_STATES.has(node.nodeState)) ? "needs_coordination" : "in_progress";
183671
- const handoffSummary = [...nodes].sort((a, b2) => Number(BLOCKING_STATES.has(b2.nodeState)) - Number(BLOCKING_STATES.has(a.nodeState))).map((node) => node.summary.trim()).find(Boolean) ?? "";
183672
- return { workOrderId, mode: this.mode, collaborationStatus, handoffSummary, progress, nodes, dependencyBlocks, todo: todos };
183882
+ return { workOrderId, mode: this.mode, collaborationStatus, progress, nodes, dependencyBlocks, todo: todos };
183673
183883
  }
183674
183884
  };
183675
183885
  }
@@ -183804,8 +184014,7 @@ function createUpstreamHandoffInputResolver(opts) {
183804
184014
  const edge = snapshot.edges.find(
183805
184015
  (candidate) => candidate.fromNodeId === input.upstreamNodeId && candidate.toNodeId === input.downstreamNodeId
183806
184016
  );
183807
- const downstream = snapshot.nodes.find((node) => node.id === input.downstreamNodeId);
183808
- const businessEdge = edge?.kind === "data" && edge.required && downstream?.fields?.[BUSINESS_HANDOFF_POLICY_FIELD] !== BUSINESS_HANDOFF_POLICY_EXEMPT;
184017
+ const businessEdge = edge?.kind === "data" && edge.required;
183809
184018
  if (!businessEdge) return null;
183810
184019
  if (edge.pinnedWorkId !== input.pinnedWorkId) {
183811
184020
  warn(
@@ -183871,7 +184080,6 @@ var INJECTED_TEXT_LIMIT, NONE_TOKENS;
183871
184080
  var init_upstream_handoff_input = __esm({
183872
184081
  "../server/src/domains/execution-continuity/upstream-handoff-input.ts"() {
183873
184082
  "use strict";
183874
- init_src3();
183875
184083
  INJECTED_TEXT_LIMIT = 4e3;
183876
184084
  NONE_TOKENS = /* @__PURE__ */ new Set(["none", "n/a", "na", "nil", "\u65E0", "\u6CA1\u6709", "\u6682\u65E0"]);
183877
184085
  }
@@ -188084,7 +188292,10 @@ function rowToVariable(row) {
188084
188292
  // **不塌成 env**,否则未知档位读回来变明文;仅 null/空回填 "env"(存量行)。派单侧按未知档保守处理。
188085
188293
  deliveryMode: typeof row.delivery_mode === "string" && row.delivery_mode ? row.delivery_mode : "env",
188086
188294
  valueEncrypted: row.value_encrypted,
188087
- updatedAt: new Date(row.updated_at).toISOString()
188295
+ updatedAt: new Date(row.updated_at).toISOString(),
188296
+ // ADR 凭据保险库补章 §D2.1:到期/取用时间戳(text 列存 ISO 字符串,原样带出;null/空 = undefined)。
188297
+ ...row.expires_at ? { expiresAt: row.expires_at } : {},
188298
+ ...row.last_used_at ? { lastUsedAt: row.last_used_at } : {}
188088
188299
  };
188089
188300
  }
188090
188301
  var ident4, PostgresRegistryStore, rowToActor, rowToConfig, rowToAgentPrefs;
@@ -188247,6 +188458,8 @@ var init_postgres_registry = __esm({
188247
188458
  await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS project_id text`);
188248
188459
  await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS environment text`);
188249
188460
  await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS delivery_mode text`);
188461
+ await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS expires_at text`);
188462
+ await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS last_used_at text`);
188250
188463
  await pool.query(`DROP INDEX IF EXISTS "${s2}"."${s2}_variables_key_actor_uq"`);
188251
188464
  await pool.query(`DROP INDEX IF EXISTS "${s2}"."${s2}_variables_scope_uq"`);
188252
188465
  await pool.query(`
@@ -188723,10 +188936,10 @@ var init_postgres_registry = __esm({
188723
188936
  /* ---------- 变量 ---------- */
188724
188937
  async putVariable(v2) {
188725
188938
  await this.pool.query(
188726
- `INSERT INTO ${this.s}.variables (key, scope, actor_id, project_id, connector_id, overrides, delivery_mode, value_encrypted, updated_at)
188727
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)
188939
+ `INSERT INTO ${this.s}.variables (key, scope, actor_id, project_id, connector_id, overrides, delivery_mode, value_encrypted, updated_at, expires_at)
188940
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
188728
188941
  ON CONFLICT (key, COALESCE(actor_id, ''), COALESCE(project_id, '')) DO UPDATE
188729
- SET scope=$2, actor_id=$3, project_id=$4, connector_id=$5, overrides=$6, delivery_mode=$7, value_encrypted=$8, updated_at=$9`,
188942
+ SET scope=$2, actor_id=$3, project_id=$4, connector_id=$5, overrides=$6, delivery_mode=$7, value_encrypted=$8, updated_at=$9, expires_at=$10`,
188730
188943
  [
188731
188944
  v2.key,
188732
188945
  v2.scope,
@@ -188736,10 +188949,18 @@ var init_postgres_registry = __esm({
188736
188949
  v2.overrides ?? null,
188737
188950
  v2.deliveryMode ?? null,
188738
188951
  v2.valueEncrypted,
188739
- v2.updatedAt
188952
+ v2.updatedAt,
188953
+ v2.expiresAt ?? null
188740
188954
  ]
188741
188955
  );
188742
188956
  }
188957
+ async touchVariableUsage(key, actorId, projectId, when) {
188958
+ await this.pool.query(
188959
+ `UPDATE ${this.s}.variables SET last_used_at=$4
188960
+ WHERE key=$1 AND COALESCE(actor_id,'')=COALESCE($2::text,'') AND COALESCE(project_id,'')=COALESCE($3::text,'')`,
188961
+ [key, actorId ?? null, projectId ?? null, when]
188962
+ );
188963
+ }
188743
188964
  async patchVariableValue(key, actorId, valueEncrypted, updatedAt) {
188744
188965
  const aid = actorId ?? null;
188745
188966
  await this.pool.query(
@@ -194470,6 +194691,15 @@ async function buildActorProvision(service, actorId, scope, onBrokerRefused) {
194470
194691
  const brokerRefused = [];
194471
194692
  applyRefDelivery(env, entries, void 0, (k2) => brokerRefused.push(k2));
194472
194693
  if (onBrokerRefused) for (const k2 of brokerRefused) await onBrokerRefused(k2);
194694
+ const brokerSet = new Set(brokerRefused);
194695
+ for (const e of entries) {
194696
+ if (brokerSet.has(e.key)) continue;
194697
+ try {
194698
+ await service.touchVariableUsage(e.key, e.origin);
194699
+ } catch (err) {
194700
+ console.warn(`[credential] touchVariableUsage(${e.key}) \u5931\u8D25\uFF08\u4E0D\u963B\u65AD\u6D3E\u5355\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}`);
194701
+ }
194702
+ }
194473
194703
  return {
194474
194704
  env,
194475
194705
  wrapperPaths: [oasisWrapperScript(), ...provision.wrapperPaths],
@@ -195781,7 +196011,10 @@ async function startServe(opts) {
195781
196011
  ...await materializeSkillFiles({ service: actors.service, actorId, runtimeKind })
195782
196012
  }),
195783
196013
  uploadChatAttachment: async ({ contentBase64 }) => ({ blobRef: await assets.put(new Uint8Array(Buffer.from(contentBase64, "base64"))) }),
195784
- onDispatchCommandCompleted: async ({ dispatchId, command, durableRefs, at, delivered }) => {
196014
+ onDispatchCommandCompleted: async ({ dispatchId, command, durableRefs, at, delivered, pendingSteps }) => {
196015
+ if (pendingSteps && pendingSteps.length > 0) {
196016
+ traceStoreSink.checkpointState(dispatchId, { pendingSteps: [...pendingSteps] });
196017
+ }
195785
196018
  traceStoreSink.checkpoint(dispatchId, {
195786
196019
  trigger: "important_output",
195787
196020
  // 交作业的那条命令带着版本号(`wk:<节点>:<n>`),比笼统的「动过这个产物」有用得多——
@@ -197751,12 +197984,13 @@ var KNOWN2 = [
197751
197984
  { adapter: "copilot", binary: "copilot" },
197752
197985
  { adapter: "kimi", binary: "kimi" },
197753
197986
  { adapter: "kiro", binary: "kiro-cli" },
197987
+ { adapter: "reasonix", binary: "reasonix" },
197754
197988
  { adapter: "pi", binary: "pi" },
197755
197989
  { adapter: "openclaw", binary: "openclaw" },
197756
197990
  { adapter: "codebuddy", binary: "codebuddy" },
197757
197991
  { adapter: "antigravity", binary: "agy" }
197758
197992
  ];
197759
- var NATIVE_APPEND_RUNTIMES = /* @__PURE__ */ new Set(["hermes", "gemini", "kimi", "kiro"]);
197993
+ var NATIVE_APPEND_RUNTIMES = /* @__PURE__ */ new Set(["hermes", "gemini", "kimi", "kiro", "reasonix"]);
197760
197994
  function onPath(binary) {
197761
197995
  try {
197762
197996
  const cmd = process.platform === "win32" ? "where" : "which";
@@ -198560,6 +198794,7 @@ async function startNode(opts) {
198560
198794
  copilot: new CopilotAdapter(),
198561
198795
  kimi: new KimiAdapter(),
198562
198796
  kiro: new KiroAdapter(),
198797
+ reasonix: new ReasonixAdapter(),
198563
198798
  pi: new PiAdapter(),
198564
198799
  openclaw: new OpenClawAdapter(),
198565
198800
  codebuddy: new CodebuddyAdapter(),
@@ -199044,7 +199279,8 @@ var COMMAND_DECLS = {
199044
199279
  { name: "unresolved", desc: "\u7559\u7ED9\u4E0B\u6E38\u7684\u672A\u51B3\u4E8B\u9879\uFF08\u5206\u53F7\u5206\u9694\uFF09\u3002\u5199\u8FDB\u672C\u8282\u70B9\u7684\u6280\u672F\u4EA4\u63A5\uFF0C\u4E0B\u6E38\u5F00\u5DE5\u524D\u4F1A\u8BFB\u5230" },
199045
199280
  { name: "risks", desc: "\u4E0B\u6E38\u8BE5\u77E5\u9053\u7684\u98CE\u9669\uFF08\u5206\u53F7\u5206\u9694\uFF09" },
199046
199281
  { name: "next", desc: "\u5EFA\u8BAE\u4E0B\u6E38\u63A5\u7740\u505A\u4EC0\u4E48\uFF08\u5206\u53F7\u5206\u9694\uFF09" },
199047
- { name: "gaps", desc: "\u4F60\u6CA1\u80FD\u6838\u9A8C\u7684\u90E8\u5206\uFF08\u5206\u53F7\u5206\u9694\uFF09\u2014\u2014\u522B\u8BA9\u4E0B\u6E38\u4EE5\u4E3A\u5DF2\u9A8C\u8FC7" }
199282
+ { name: "gaps", desc: "\u4F60\u6CA1\u80FD\u6838\u9A8C\u7684\u90E8\u5206\uFF08\u5206\u53F7\u5206\u9694\uFF09\u2014\u2014\u522B\u8BA9\u4E0B\u6E38\u4EE5\u4E3A\u5DF2\u9A8C\u8FC7" },
199283
+ { name: "pending", desc: "\u8FD8\u5269\u4EC0\u4E48\u6CA1\u505A\uFF08\u5206\u53F7\u5206\u9694\uFF09\u3002\u5B58\u8FDB\u672C\u8F6E checkpoint\uFF1A\u8FD9\u4E00\u8D9F\u82E5\u88AB\u780D\uFF08\u8D85\u65F6/\u989D\u5EA6/\u6389\u7EBF\uFF09\uFF0C\u4E0B\u4E00\u8D9F\u63A5\u624B\u7684\u4EBA\u636E\u5B83\u63A5\u7740\u505A" }
199048
199284
  ],
199049
199285
  examples: [
199050
199286
  'oasis propose artifact:dev:abc-123 --from-dir deliverable/ --reason "\u4FEE\u590D\u767B\u5F55\u9875\u767D\u5C4F"',
@@ -201730,7 +201966,9 @@ ${res.warning}`);
201730
201966
  ...semicolonList(flags.get("unresolved"), "unresolvedIssues"),
201731
201967
  ...semicolonList(flags.get("risks"), "risks"),
201732
201968
  ...semicolonList(flags.get("next"), "nextActions"),
201733
- ...semicolonList(flags.get("gaps"), "verificationGaps")
201969
+ ...semicolonList(flags.get("gaps"), "verificationGaps"),
201970
+ // 「还剩什么没做」:唯一系统推不出来的字段,挂在本来就要跑的命令上(见 server 的 pendingSteps 注释)
201971
+ ...semicolonList(flags.get("pending"), "pendingSteps")
201734
201972
  });
201735
201973
  println(message);
201736
201974
  break;
@@ -203004,7 +203242,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
203004
203242
  }
203005
203243
 
203006
203244
  // src/index.ts
203007
- var PKG_VERSION = true ? "0.1.108" : "dev";
203245
+ var PKG_VERSION = true ? "0.1.109" : "dev";
203008
203246
  var OASIS_DIR = path28.join(os11.homedir(), ".oasis");
203009
203247
  var CONFIG_FILE = path28.join(OASIS_DIR, "node-config.json");
203010
203248
  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.108",
3
+ "version": "0.1.109",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"