oasis_test 0.1.108 → 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.
- package/dist/index.js +471 -77
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4092,7 +4092,26 @@ ${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
|
+
// ★ 参数必须是 **JSON string array**(CLI 侧 `JSON.parse` 后校验,见 cli.ts parseStringArrayFlag)。
|
|
4106
|
+
// 这里给的是能逐字复制的真例子——写成自然语言一句话会当场抛 `--pending 必须是 JSON string array`。
|
|
4107
|
+
`\`\`\``,
|
|
4108
|
+
`oasis continuity-checkpoint --trigger stage_completed \\`,
|
|
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`,
|
|
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`,
|
|
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`
|
|
4096
4115
|
],
|
|
4097
4116
|
// 兜底(§10):上次失败了 → 明确告诉它发生了什么 + 怎么破(首选 add-revision 拆出去)
|
|
4098
4117
|
...args.lastFailure ? args.lastFailure.resumed ? [
|
|
@@ -158863,6 +158882,8 @@ async function listModels(runtime, executablePath) {
|
|
|
158863
158882
|
return cachedDiscovery(runtime, async () => await discoverACPModels(executablePath ?? "kimi", "kimi", ["acp"]) ?? []);
|
|
158864
158883
|
case "kiro":
|
|
158865
158884
|
return cachedDiscovery(runtime, async () => await discoverACPModels(executablePath ?? "kiro-cli", "kiro", ["acp"]) ?? []);
|
|
158885
|
+
case "reasonix":
|
|
158886
|
+
return cachedDiscovery(runtime, async () => await discoverACPModels(executablePath ?? "reasonix", "reasonix", ["acp"]) ?? []);
|
|
158866
158887
|
case "openclaw":
|
|
158867
158888
|
return cachedDiscovery(runtime, () => discoverOpenclawModels(executablePath));
|
|
158868
158889
|
default:
|
|
@@ -158888,7 +158909,12 @@ async function cachedDiscovery(key, fn) {
|
|
|
158888
158909
|
if (entry && now < entry.expiresAt) {
|
|
158889
158910
|
return entry.models;
|
|
158890
158911
|
}
|
|
158891
|
-
|
|
158912
|
+
let models;
|
|
158913
|
+
try {
|
|
158914
|
+
models = await fn();
|
|
158915
|
+
} catch {
|
|
158916
|
+
return [];
|
|
158917
|
+
}
|
|
158892
158918
|
modelCache.set(key, { models, expiresAt: now + CACHE_TTL_MS });
|
|
158893
158919
|
return models;
|
|
158894
158920
|
}
|
|
@@ -158958,12 +158984,77 @@ async function discoverCursorModels(bin) {
|
|
|
158958
158984
|
async function discoverOpenCodeModels(bin) {
|
|
158959
158985
|
throw new Error("discoverOpenCodeModels: TODO");
|
|
158960
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
|
+
}
|
|
158961
159019
|
async function discoverPiModels(bin) {
|
|
158962
|
-
|
|
159020
|
+
const out = await runCapture(bin ?? "pi", ["--list-models"]);
|
|
159021
|
+
return out === void 0 ? [] : parsePiModels(out);
|
|
158963
159022
|
}
|
|
158964
159023
|
async function discoverAntigravityModels(bin) {
|
|
158965
159024
|
throw new Error("discoverAntigravityModels: TODO");
|
|
158966
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
|
+
}
|
|
158967
159058
|
async function discoverACPModels(bin, provider, args = ["acp"]) {
|
|
158968
159059
|
const child = (() => {
|
|
158969
159060
|
try {
|
|
@@ -160122,6 +160213,20 @@ function joinOutputParts(parts) {
|
|
|
160122
160213
|
if (parts.every((p2) => typeof p2 === "string")) return parts.join("");
|
|
160123
160214
|
return parts;
|
|
160124
160215
|
}
|
|
160216
|
+
function pickApprovalOptionId(params) {
|
|
160217
|
+
const raw = params?.options;
|
|
160218
|
+
if (!Array.isArray(raw)) return LEGACY_APPROVE_OPTION_ID;
|
|
160219
|
+
const options = raw.filter(
|
|
160220
|
+
(o) => typeof o?.optionId === "string"
|
|
160221
|
+
);
|
|
160222
|
+
if (options.length === 0) return LEGACY_APPROVE_OPTION_ID;
|
|
160223
|
+
const byId = options.find((o) => o.optionId === LEGACY_APPROVE_OPTION_ID)?.optionId;
|
|
160224
|
+
const byKind = (kind) => options.find((o) => o.kind === kind)?.optionId;
|
|
160225
|
+
const nonReject = options.find(
|
|
160226
|
+
(o) => !String(o.kind ?? o.optionId).startsWith("reject")
|
|
160227
|
+
)?.optionId;
|
|
160228
|
+
return byId ?? byKind("allow_always") ?? byKind("allow_once") ?? nonReject ?? LEGACY_APPROVE_OPTION_ID;
|
|
160229
|
+
}
|
|
160125
160230
|
function normalizeACPUpdate(data) {
|
|
160126
160231
|
const d = data;
|
|
160127
160232
|
if (!d) return ["", data];
|
|
@@ -160370,7 +160475,8 @@ async function runACPSession(job, cfg) {
|
|
|
160370
160475
|
if (reason === "cancelled") finish({ code: null, reason: "cancelled", transcriptRef });
|
|
160371
160476
|
},
|
|
160372
160477
|
() => streamingCurrentTurn,
|
|
160373
|
-
cfg.finalUsageIsAuthoritative === true
|
|
160478
|
+
cfg.finalUsageIsAuthoritative === true,
|
|
160479
|
+
cfg.vendorUsageNotification
|
|
160374
160480
|
);
|
|
160375
160481
|
usageClient = client;
|
|
160376
160482
|
const rl = readline3.createInterface({ input: child.stdout });
|
|
@@ -160540,7 +160646,7 @@ ${task}` : task;
|
|
|
160540
160646
|
}
|
|
160541
160647
|
};
|
|
160542
160648
|
}
|
|
160543
|
-
var import_node_child_process10, import_node_crypto16, fs11, path11, readline3, ACPClient;
|
|
160649
|
+
var import_node_child_process10, import_node_crypto16, fs11, path11, readline3, ACPClient, LEGACY_APPROVE_OPTION_ID;
|
|
160544
160650
|
var init_acp = __esm({
|
|
160545
160651
|
"../adapters/src/_core/acp.ts"() {
|
|
160546
160652
|
"use strict";
|
|
@@ -160559,13 +160665,14 @@ var init_acp = __esm({
|
|
|
160559
160665
|
init_transcript();
|
|
160560
160666
|
init_filter_extra_args();
|
|
160561
160667
|
ACPClient = class {
|
|
160562
|
-
constructor(write, onOutput, onTelemetry, onStop, acceptNotification = () => true, finalUsageIsAuthoritative = false) {
|
|
160668
|
+
constructor(write, onOutput, onTelemetry, onStop, acceptNotification = () => true, finalUsageIsAuthoritative = false, vendorUsage) {
|
|
160563
160669
|
this.write = write;
|
|
160564
160670
|
this.onOutput = onOutput;
|
|
160565
160671
|
this.onTelemetry = onTelemetry;
|
|
160566
160672
|
this.onStop = onStop;
|
|
160567
160673
|
this.acceptNotification = acceptNotification;
|
|
160568
160674
|
this.finalUsageIsAuthoritative = finalUsageIsAuthoritative;
|
|
160675
|
+
this.vendorUsage = vendorUsage;
|
|
160569
160676
|
}
|
|
160570
160677
|
nextId = 0;
|
|
160571
160678
|
pending = /* @__PURE__ */ new Map();
|
|
@@ -160579,7 +160686,37 @@ var init_acp = __esm({
|
|
|
160579
160686
|
* 是否还在流。每收到一条 session/update / session/notification 就 +1,主循环轮询该值。
|
|
160580
160687
|
*/
|
|
160581
160688
|
notificationCount = 0;
|
|
160689
|
+
/** 厂商私有用量:已完成轮次的累计 + 当前轮的最新快照,两者相加即 this.usage。 */
|
|
160690
|
+
vendorTurnBase = newUsageAcc();
|
|
160691
|
+
vendorTurnSnapshot = newUsageAcc();
|
|
160692
|
+
applyVendorUsage(params) {
|
|
160693
|
+
const picked = this.vendorUsage?.pick(params);
|
|
160694
|
+
if (!picked) return;
|
|
160695
|
+
this.vendorTurnSnapshot = {
|
|
160696
|
+
inputTokens: picked.inputTokens ?? 0,
|
|
160697
|
+
outputTokens: picked.outputTokens ?? 0,
|
|
160698
|
+
cacheReadTokens: picked.cacheReadTokens ?? 0,
|
|
160699
|
+
cacheCreationTokens: picked.cacheCreationTokens ?? 0
|
|
160700
|
+
};
|
|
160701
|
+
this.usage = {
|
|
160702
|
+
inputTokens: this.vendorTurnBase.inputTokens + this.vendorTurnSnapshot.inputTokens,
|
|
160703
|
+
outputTokens: this.vendorTurnBase.outputTokens + this.vendorTurnSnapshot.outputTokens,
|
|
160704
|
+
cacheReadTokens: this.vendorTurnBase.cacheReadTokens + this.vendorTurnSnapshot.cacheReadTokens,
|
|
160705
|
+
cacheCreationTokens: this.vendorTurnBase.cacheCreationTokens + this.vendorTurnSnapshot.cacheCreationTokens
|
|
160706
|
+
};
|
|
160707
|
+
}
|
|
160708
|
+
/** 新一轮 prompt 发出前,把上一轮的快照折进基数(快照是「当前轮」口径,会归零重来)。 */
|
|
160709
|
+
foldVendorTurn() {
|
|
160710
|
+
this.vendorTurnBase = {
|
|
160711
|
+
inputTokens: this.vendorTurnBase.inputTokens + this.vendorTurnSnapshot.inputTokens,
|
|
160712
|
+
outputTokens: this.vendorTurnBase.outputTokens + this.vendorTurnSnapshot.outputTokens,
|
|
160713
|
+
cacheReadTokens: this.vendorTurnBase.cacheReadTokens + this.vendorTurnSnapshot.cacheReadTokens,
|
|
160714
|
+
cacheCreationTokens: this.vendorTurnBase.cacheCreationTokens + this.vendorTurnSnapshot.cacheCreationTokens
|
|
160715
|
+
};
|
|
160716
|
+
this.vendorTurnSnapshot = newUsageAcc();
|
|
160717
|
+
}
|
|
160582
160718
|
request(method, params) {
|
|
160719
|
+
if (this.vendorUsage && method === "session/prompt") this.foldVendorTurn();
|
|
160583
160720
|
const id = this.nextId++;
|
|
160584
160721
|
return new Promise((resolve10, reject) => {
|
|
160585
160722
|
this.pending.set(id, { resolve: resolve10, reject, method });
|
|
@@ -160631,11 +160768,15 @@ var init_acp = __esm({
|
|
|
160631
160768
|
handleAgentRequest(raw) {
|
|
160632
160769
|
const method = raw["method"];
|
|
160633
160770
|
const id = raw["id"];
|
|
160634
|
-
const resp = method === "session/request_permission" ? { jsonrpc: "2.0", id, result: { outcome: { outcome: "selected", optionId: "
|
|
160771
|
+
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
160772
|
this.write(JSON.stringify(resp) + "\n");
|
|
160636
160773
|
}
|
|
160637
160774
|
handleNotification(raw) {
|
|
160638
160775
|
const method = raw["method"];
|
|
160776
|
+
if (this.vendorUsage && method === this.vendorUsage.method) {
|
|
160777
|
+
this.applyVendorUsage(raw["params"]);
|
|
160778
|
+
return;
|
|
160779
|
+
}
|
|
160639
160780
|
if (method !== "session/update" && method !== "session/notification") return;
|
|
160640
160781
|
const params = raw["params"];
|
|
160641
160782
|
if (!params?.update) return;
|
|
@@ -160794,6 +160935,7 @@ var init_acp = __esm({
|
|
|
160794
160935
|
});
|
|
160795
160936
|
}
|
|
160796
160937
|
};
|
|
160938
|
+
LEGACY_APPROVE_OPTION_ID = "approve_for_session";
|
|
160797
160939
|
}
|
|
160798
160940
|
});
|
|
160799
160941
|
|
|
@@ -160895,6 +161037,72 @@ var init_kiro = __esm({
|
|
|
160895
161037
|
}
|
|
160896
161038
|
});
|
|
160897
161039
|
|
|
161040
|
+
// ../adapters/src/reasonix/index.ts
|
|
161041
|
+
var REASONIX_BLOCKED_FLAGS, REASONIX_USAGE_NOTIFICATION, ReasonixAdapter;
|
|
161042
|
+
var init_reasonix = __esm({
|
|
161043
|
+
"../adapters/src/reasonix/index.ts"() {
|
|
161044
|
+
"use strict";
|
|
161045
|
+
init_acp();
|
|
161046
|
+
REASONIX_BLOCKED_FLAGS = /* @__PURE__ */ new Map([
|
|
161047
|
+
["--model", "value"],
|
|
161048
|
+
["--planner", "value"],
|
|
161049
|
+
["--sandbox-network", "value"],
|
|
161050
|
+
["--sandbox-bash", "value"],
|
|
161051
|
+
["--workspace-only", "boolean"]
|
|
161052
|
+
]);
|
|
161053
|
+
REASONIX_USAGE_NOTIFICATION = {
|
|
161054
|
+
method: "_reasonix.io/session/status_update",
|
|
161055
|
+
pick(params) {
|
|
161056
|
+
const rec = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
161057
|
+
const num2 = (v2) => typeof v2 === "number" && Number.isFinite(v2) && v2 >= 0 ? v2 : void 0;
|
|
161058
|
+
const turn = rec(rec(rec(rec(params)?.["status"])?.["usage"])?.["turn"]);
|
|
161059
|
+
if (!turn) return void 0;
|
|
161060
|
+
const promptTokens = num2(turn["promptTokens"]);
|
|
161061
|
+
const cacheHit = num2(turn["cacheHitTokens"]);
|
|
161062
|
+
const cacheMiss = num2(turn["cacheMissTokens"]);
|
|
161063
|
+
const inputTokens = cacheMiss ?? (promptTokens === void 0 ? void 0 : Math.max(0, promptTokens - (cacheHit ?? 0)));
|
|
161064
|
+
const outputTokens = num2(turn["completionTokens"]);
|
|
161065
|
+
if (inputTokens === void 0 && outputTokens === void 0 && cacheHit === void 0) return void 0;
|
|
161066
|
+
return {
|
|
161067
|
+
...inputTokens !== void 0 ? { inputTokens } : {},
|
|
161068
|
+
...outputTokens !== void 0 ? { outputTokens } : {},
|
|
161069
|
+
...cacheHit !== void 0 ? { cacheReadTokens: cacheHit } : {}
|
|
161070
|
+
};
|
|
161071
|
+
}
|
|
161072
|
+
};
|
|
161073
|
+
ReasonixAdapter = class {
|
|
161074
|
+
constructor(opts = {}) {
|
|
161075
|
+
this.opts = opts;
|
|
161076
|
+
}
|
|
161077
|
+
/** ADR-0093:ACP 引擎原生支持对话追加(同 session 二次 session/prompt)。 */
|
|
161078
|
+
capabilities = { appendInput: true };
|
|
161079
|
+
spawn(job) {
|
|
161080
|
+
return runACPSession(job, {
|
|
161081
|
+
bin: this.opts.reasonixBin ?? "reasonix",
|
|
161082
|
+
args: [
|
|
161083
|
+
"acp",
|
|
161084
|
+
"--planner",
|
|
161085
|
+
"auto",
|
|
161086
|
+
"--sandbox-network",
|
|
161087
|
+
"auto",
|
|
161088
|
+
"--sandbox-bash",
|
|
161089
|
+
"auto",
|
|
161090
|
+
"--workspace-only"
|
|
161091
|
+
],
|
|
161092
|
+
model: this.opts.model,
|
|
161093
|
+
resumeMethod: "session/resume",
|
|
161094
|
+
vendorUsageNotification: REASONIX_USAGE_NOTIFICATION,
|
|
161095
|
+
blockedFlags: REASONIX_BLOCKED_FLAGS,
|
|
161096
|
+
workRoot: this.opts.workRoot,
|
|
161097
|
+
cleanupWorkdir: this.opts.cleanupWorkdir,
|
|
161098
|
+
env: this.opts.env,
|
|
161099
|
+
extraArgs: this.opts.extraArgs
|
|
161100
|
+
});
|
|
161101
|
+
}
|
|
161102
|
+
};
|
|
161103
|
+
}
|
|
161104
|
+
});
|
|
161105
|
+
|
|
160898
161106
|
// ../adapters/src/_core/subprocess.ts
|
|
160899
161107
|
async function materialize(job, cfg) {
|
|
160900
161108
|
const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
@@ -161975,6 +162183,7 @@ var init_src6 = __esm({
|
|
|
161975
162183
|
init_hermes();
|
|
161976
162184
|
init_kimi();
|
|
161977
162185
|
init_kiro();
|
|
162186
|
+
init_reasonix();
|
|
161978
162187
|
init_cursor();
|
|
161979
162188
|
init_codebuddy();
|
|
161980
162189
|
init_gemini();
|
|
@@ -163962,6 +164171,7 @@ async function startOasisServer(opts) {
|
|
|
163962
164171
|
...tokenClaims.artifactId !== void 0 ? { artifactId: tokenClaims.artifactId } : {},
|
|
163963
164172
|
durableRefs: tokenClaims.artifactId !== void 0 ? [{ kind: "artifact", id: tokenClaims.artifactId, label: body.command }] : [],
|
|
163964
164173
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
164174
|
+
...listArg("pendingSteps") ? { pendingSteps: listArg("pendingSteps") } : {},
|
|
163965
164175
|
...delivered ? { delivered } : {}
|
|
163966
164176
|
});
|
|
163967
164177
|
} catch (error2) {
|
|
@@ -166323,7 +166533,14 @@ var init_memory_registry_store = __esm({
|
|
|
166323
166533
|
this.skillFiles.delete(skillId);
|
|
166324
166534
|
}
|
|
166325
166535
|
async putVariable(v2) {
|
|
166326
|
-
this.
|
|
166536
|
+
const mk = this._varKey(v2.key, v2.actorId, v2.projectId);
|
|
166537
|
+
const ex = this.variables.get(mk);
|
|
166538
|
+
this.variables.set(mk, { ...v2, ...ex?.lastUsedAt !== void 0 ? { lastUsedAt: ex.lastUsedAt } : {} });
|
|
166539
|
+
}
|
|
166540
|
+
async touchVariableUsage(key, actorId, projectId, when) {
|
|
166541
|
+
const mk = this._varKey(key, actorId, projectId);
|
|
166542
|
+
const ex = this.variables.get(mk);
|
|
166543
|
+
if (ex) this.variables.set(mk, { ...ex, lastUsedAt: when });
|
|
166327
166544
|
}
|
|
166328
166545
|
async patchVariableValue(key, actorId, valueEncrypted, updatedAt) {
|
|
166329
166546
|
const mk = this._varKey(key, actorId);
|
|
@@ -166577,12 +166794,11 @@ function systemHandoffFor(run, checkpoint = null, effects = []) {
|
|
|
166577
166794
|
summary: `[system_reconstructed] attempt=${run.id} outcome=${outcome} reason=${terminalReason}; ${progress}`.slice(0, 400),
|
|
166578
166795
|
changedOutputs: structuredClone(run.outputRefs),
|
|
166579
166796
|
unresolvedIssues: [],
|
|
166580
|
-
risks
|
|
166581
|
-
|
|
166582
|
-
|
|
166583
|
-
],
|
|
166797
|
+
// 与 PG 触发器同口径(2026-08-18):risks / verificationGaps 只装业务语义的东西。会话怎么死的
|
|
166798
|
+
// 已在 summary 的 reason= 段里,不再冒充成「交付物的风险」;「没有断点」也不是「验证缺口」。
|
|
166799
|
+
risks: pendingEffects || failedEffects ? [`external effects: pending=${pendingEffects}, failed=${failedEffects}`] : [],
|
|
166584
166800
|
nextActions: structuredClone(checkpoint?.pendingSteps ?? []),
|
|
166585
|
-
verificationGaps:
|
|
166801
|
+
verificationGaps: [],
|
|
166586
166802
|
userHandoff: null,
|
|
166587
166803
|
createdAt: run.endedAt ?? run.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
166588
166804
|
};
|
|
@@ -166972,6 +167188,13 @@ var init_memory_trace_store = __esm({
|
|
|
166972
167188
|
const handoff = this.handoffs.get(attemptId);
|
|
166973
167189
|
return handoff ? structuredClone(handoff) : null;
|
|
166974
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
|
+
}
|
|
166975
167198
|
async listAttempts(workOrderId) {
|
|
166976
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)));
|
|
166977
167200
|
}
|
|
@@ -174471,9 +174694,37 @@ ${input.description}
|
|
|
174471
174694
|
// 非连接器写入到此 deliveryMode 必非空(上面已拦);连接器写入沿用 env(其值经 sensitiveVars 剔除,不进 env)。
|
|
174472
174695
|
deliveryMode: v2.deliveryMode ?? "env",
|
|
174473
174696
|
valueEncrypted: v2.encrypted === false ? `plain:${v2.value}` : this.encrypt(v2.value),
|
|
174474
|
-
updatedAt: this.now()
|
|
174697
|
+
updatedAt: this.now(),
|
|
174698
|
+
// ADR 凭据保险库补章 §D2.2:expiresAt 写侧穿透——**显式带 key**(含 undefined),使清空(传空→undefined)
|
|
174699
|
+
// 也落到底(store 两实现都按此覆盖)。lastUsedAt 从不由写侧传,取用时另刷(§D2.3)。
|
|
174700
|
+
expiresAt: v2.expiresAt
|
|
174475
174701
|
});
|
|
174476
174702
|
}
|
|
174703
|
+
/** ADR 凭据保险库补章 §D2.3:某一行变量「明文真被取用」→ 刷 lastUsedAt。行按 (key, actorId?, projectId?)
|
|
174704
|
+
* 唯一键定位(与 put/delete 同址)。store 未实现该方法时静默跳过(不影响主功能)。 */
|
|
174705
|
+
async touchVariableUsage(key, origin, when) {
|
|
174706
|
+
await this.opts.store.touchVariableUsage?.(key, origin?.actorId, origin?.projectId, when ?? this.now());
|
|
174707
|
+
}
|
|
174708
|
+
/**
|
|
174709
|
+
* ADR 凭据保险库补章 §D1.2:**人类控制台** reveal 的取值——不走 agent 的 `resolveActorProvisionEntries`
|
|
174710
|
+
* 解析链(人类既无 personal 变量也无派单 artifactId,那条链恒空)。直接按存储唯一键取该行、解出明文。
|
|
174711
|
+
* - `selector` 由控制台列表行给出(personal 带 actorId、project 带 projectId、global 两者皆空)——
|
|
174712
|
+
* 与 `GET /api/variables`「对所有人类返回全量」的可见口径一致(补章 §D1.3),列得到即 reveal 得到。
|
|
174713
|
+
* - 命中返回明文 + 该行的 origin(供刷 lastUsedAt);未命中(无此行)返回 null(路由映射 403,与 agent 同壳)。
|
|
174714
|
+
*/
|
|
174715
|
+
async revealHumanValue(key, selector) {
|
|
174716
|
+
const wantActor = selector?.actorId;
|
|
174717
|
+
const wantProject = selector?.projectId;
|
|
174718
|
+
const rows = await this.opts.store.listVariables();
|
|
174719
|
+
const row = rows.find(
|
|
174720
|
+
(r) => r.key === key && (r.actorId ?? void 0) === (wantActor ?? void 0) && (r.projectId ?? void 0) === (wantProject ?? void 0)
|
|
174721
|
+
);
|
|
174722
|
+
if (!row) return null;
|
|
174723
|
+
return {
|
|
174724
|
+
value: this.decodeCiphertext(row.valueEncrypted),
|
|
174725
|
+
origin: { ...row.actorId !== void 0 ? { actorId: row.actorId } : {}, ...row.projectId !== void 0 ? { projectId: row.projectId } : {} }
|
|
174726
|
+
};
|
|
174727
|
+
}
|
|
174477
174728
|
/** 更新已有变量的 encrypted 属性(重新加密或解密),不改其他字段 */
|
|
174478
174729
|
async patchVariableEncryption(key, actorId, encrypted) {
|
|
174479
174730
|
const ct = await this.opts.store.getVariableCiphertext(key, actorId);
|
|
@@ -174512,7 +174763,10 @@ ${input.description}
|
|
|
174512
174763
|
// 缺省视为 env(ADR §4.4;存量行读侧统一回填)
|
|
174513
174764
|
encrypted: !isPlain,
|
|
174514
174765
|
maskedValue: isPlain ? r.valueEncrypted.slice(6) : mask(this.decrypt(r.valueEncrypted)),
|
|
174515
|
-
updatedAt: r.updatedAt
|
|
174766
|
+
updatedAt: r.updatedAt,
|
|
174767
|
+
// ADR 凭据保险库补章 §D2.1:到期/取用时间戳透传(展示层据此染色;补章 §D2.4)。
|
|
174768
|
+
...r.expiresAt !== void 0 ? { expiresAt: r.expiresAt } : {},
|
|
174769
|
+
...r.lastUsedAt !== void 0 ? { lastUsedAt: r.lastUsedAt } : {}
|
|
174516
174770
|
};
|
|
174517
174771
|
});
|
|
174518
174772
|
}
|
|
@@ -174605,7 +174859,12 @@ ${input.description}
|
|
|
174605
174859
|
const gated = (row) => !row.connectorId || enabledConnectors.has(row.connectorId);
|
|
174606
174860
|
const put = (row) => {
|
|
174607
174861
|
if (!gated(row)) return;
|
|
174608
|
-
merged.set(row.key, {
|
|
174862
|
+
merged.set(row.key, {
|
|
174863
|
+
key: row.key,
|
|
174864
|
+
value: this.decodeCiphertext(row.valueEncrypted),
|
|
174865
|
+
deliveryMode: row.deliveryMode ?? "env",
|
|
174866
|
+
origin: { ...row.actorId !== void 0 ? { actorId: row.actorId } : {}, ...row.projectId !== void 0 ? { projectId: row.projectId } : {} }
|
|
174867
|
+
});
|
|
174609
174868
|
};
|
|
174610
174869
|
for (const row of rows) {
|
|
174611
174870
|
if (row.scope === "global" && !row.actorId) put(row);
|
|
@@ -174625,7 +174884,7 @@ ${input.description}
|
|
|
174625
174884
|
async resolveRevealValue(actorId, key, opts) {
|
|
174626
174885
|
const entries = await this.resolveActorProvisionEntries(actorId, { ...opts, refreshConnectors: false });
|
|
174627
174886
|
const hit = entries.find((e) => e.key === key);
|
|
174628
|
-
return hit ? { value: hit.value } : null;
|
|
174887
|
+
return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
|
|
174629
174888
|
}
|
|
174630
174889
|
encrypt(plain) {
|
|
174631
174890
|
const iv = (0, import_node_crypto26.randomBytes)(12);
|
|
@@ -175854,6 +176113,21 @@ var init_connector_skills = __esm({
|
|
|
175854
176113
|
function isKnownRevealSource(source) {
|
|
175855
176114
|
return CREDENTIAL_REVEAL_SOURCES.has(source) || source.startsWith("agent-skill:");
|
|
175856
176115
|
}
|
|
176116
|
+
function clientMetaFromReq(req) {
|
|
176117
|
+
const fwd = req.raw?.headers?.["x-forwarded-for"];
|
|
176118
|
+
const fwdFirst = (Array.isArray(fwd) ? fwd[0] : fwd)?.split(",")[0]?.trim();
|
|
176119
|
+
const clientIp = fwdFirst || req.raw?.socket?.remoteAddress || void 0;
|
|
176120
|
+
const ua = req.raw?.headers?.["user-agent"];
|
|
176121
|
+
const userAgent = (Array.isArray(ua) ? ua[0] : ua) || void 0;
|
|
176122
|
+
return { ...clientIp ? { clientIp } : {}, ...userAgent ? { userAgent } : {} };
|
|
176123
|
+
}
|
|
176124
|
+
function normalizeExpiresAt(raw) {
|
|
176125
|
+
if (raw === void 0 || raw === null || raw === "") return void 0;
|
|
176126
|
+
if (typeof raw !== "string") throw new ApiError(400, "BAD_REQUEST", "expiresAt \u987B\u4E3A ISO-8601 \u5B57\u7B26\u4E32");
|
|
176127
|
+
const t = Date.parse(raw);
|
|
176128
|
+
if (Number.isNaN(t)) throw new ApiError(400, "BAD_REQUEST", `expiresAt \u4E0D\u662F\u5408\u6CD5\u65E5\u671F\uFF1A${raw}`);
|
|
176129
|
+
return new Date(t).toISOString();
|
|
176130
|
+
}
|
|
175857
176131
|
function positionsFromPayload(body) {
|
|
175858
176132
|
if (!body) return void 0;
|
|
175859
176133
|
if (Object.prototype.hasOwnProperty.call(body, "roles")) {
|
|
@@ -175888,6 +176162,8 @@ function actorsDomain(opts) {
|
|
|
175888
176162
|
const { resolveCtx } = opts;
|
|
175889
176163
|
const revealLimits = opts.credentialRevealLimits ?? { perSession: 200, perSessionPerKey: 20 };
|
|
175890
176164
|
const revealLimiter = new RevealRateLimiter(revealLimits.perSession, revealLimits.perSessionPerKey);
|
|
176165
|
+
const consoleRevealLimits = opts.credentialRevealLimits?.console ?? { perSession: 60, perSessionPerKey: 10 };
|
|
176166
|
+
const consoleRevealLimiter = new RevealRateLimiter(consoleRevealLimits.perSession, consoleRevealLimits.perSessionPerKey);
|
|
175891
176167
|
return (router) => {
|
|
175892
176168
|
router.get("/api/actors", async (req) => {
|
|
175893
176169
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
@@ -176174,11 +176450,6 @@ function actorsDomain(opts) {
|
|
|
176174
176450
|
}
|
|
176175
176451
|
};
|
|
176176
176452
|
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
176453
|
await opts.credentialAudit?.({
|
|
176183
176454
|
kind,
|
|
176184
176455
|
actor: req.auth.actor,
|
|
@@ -176186,8 +176457,7 @@ function actorsDomain(opts) {
|
|
|
176186
176457
|
targetScope,
|
|
176187
176458
|
source: "console",
|
|
176188
176459
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
176189
|
-
...
|
|
176190
|
-
...userAgent ? { userAgent } : {}
|
|
176460
|
+
...clientMetaFromReq(req)
|
|
176191
176461
|
});
|
|
176192
176462
|
};
|
|
176193
176463
|
router.get("/api/variables", async (req) => {
|
|
@@ -176200,6 +176470,7 @@ function actorsDomain(opts) {
|
|
|
176200
176470
|
const { service } = await resolveCtx(req.auth.companyId);
|
|
176201
176471
|
const b2 = req.body;
|
|
176202
176472
|
if (!b2?.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
176473
|
+
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
176203
176474
|
if (b2.scope !== "global" && b2.scope !== "personal" && b2.scope !== "project") {
|
|
176204
176475
|
throw new ApiError(
|
|
176205
176476
|
400,
|
|
@@ -176240,7 +176511,8 @@ function actorsDomain(opts) {
|
|
|
176240
176511
|
...b2.deliveryMode !== void 0 ? { deliveryMode: b2.deliveryMode } : {},
|
|
176241
176512
|
...b2.connectorId !== void 0 ? { connectorId: b2.connectorId } : {},
|
|
176242
176513
|
...b2.overrides !== void 0 ? { overrides: b2.overrides } : {},
|
|
176243
|
-
...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {}
|
|
176514
|
+
...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {},
|
|
176515
|
+
expiresAt: expiresAt2
|
|
176244
176516
|
});
|
|
176245
176517
|
await auditVariableChange(
|
|
176246
176518
|
req,
|
|
@@ -176278,6 +176550,7 @@ function actorsDomain(opts) {
|
|
|
176278
176550
|
const actorId = req.params.id;
|
|
176279
176551
|
const b2 = req.body;
|
|
176280
176552
|
if (!b2?.key) throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 key");
|
|
176553
|
+
const expiresAt2 = normalizeExpiresAt(b2.expiresAt);
|
|
176281
176554
|
if (b2.deliveryMode !== void 0 && b2.deliveryMode !== "env" && b2.deliveryMode !== "ref" && b2.deliveryMode !== "broker") {
|
|
176282
176555
|
throw new ApiError(400, "BAD_REQUEST", "deliveryMode \u53EA\u80FD\u662F env\u3001ref \u6216 broker");
|
|
176283
176556
|
}
|
|
@@ -176308,7 +176581,8 @@ function actorsDomain(opts) {
|
|
|
176308
176581
|
...b2.deliveryMode !== void 0 ? { deliveryMode: b2.deliveryMode } : {},
|
|
176309
176582
|
...b2.connectorId !== void 0 ? { connectorId: b2.connectorId } : {},
|
|
176310
176583
|
...b2.overrides !== void 0 ? { overrides: b2.overrides } : {},
|
|
176311
|
-
...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {}
|
|
176584
|
+
...b2.encrypted !== void 0 ? { encrypted: b2.encrypted } : {},
|
|
176585
|
+
expiresAt: expiresAt2
|
|
176312
176586
|
});
|
|
176313
176587
|
await auditVariableChange(req, "credential_write", b2.key, `personal:${actorId}`);
|
|
176314
176588
|
return { status: 201, body: { ok: true } };
|
|
@@ -176329,25 +176603,33 @@ function actorsDomain(opts) {
|
|
|
176329
176603
|
const source = typeof b2?.source === "string" && b2.source.trim() || "agent-cli";
|
|
176330
176604
|
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
176605
|
const actor = req.auth.actor;
|
|
176606
|
+
const isHuman2 = isHumanActor(actor);
|
|
176607
|
+
const isConsole = source === "console";
|
|
176608
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
176332
176609
|
const artifactId = req.auth.dispatch?.artifactId;
|
|
176333
176610
|
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
176611
|
const dispatchFields = { ...sessionId ? { sessionId } : {}, ...artifactId ? { artifactId } : {} };
|
|
176338
|
-
const
|
|
176612
|
+
const consoleMeta = isConsole ? clientMetaFromReq(req) : {};
|
|
176613
|
+
if (isConsole && !isHuman2) {
|
|
176614
|
+
await opts.credentialAudit?.({ kind: "credential_reveal_denied", actor, variableKey: key, source, timestamp, reason: "no_permission", ...dispatchFields, ...consoleMeta });
|
|
176615
|
+
return { status: 403, body: { code: "denied", key } };
|
|
176616
|
+
}
|
|
176617
|
+
const now = Date.now();
|
|
176618
|
+
const sessionKey = isConsole ? actor : sessionId ?? `${actor}::${artifactId ?? "no-artifact"}`;
|
|
176619
|
+
const limiter = isConsole ? consoleRevealLimiter : revealLimiter;
|
|
176620
|
+
const throttled = limiter.check(sessionKey, key, now);
|
|
176339
176621
|
if (throttled) {
|
|
176340
|
-
await opts.credentialAudit?.({ kind: "credential_reveal_throttled", actor, variableKey: key, source, timestamp, scope: throttled, ...dispatchFields });
|
|
176622
|
+
await opts.credentialAudit?.({ kind: "credential_reveal_throttled", actor, variableKey: key, source, timestamp, scope: throttled, ...dispatchFields, ...consoleMeta });
|
|
176341
176623
|
return { status: 429, body: { code: "throttled", key, scope: throttled } };
|
|
176342
176624
|
}
|
|
176343
|
-
const
|
|
176344
|
-
const resolved = await service.resolveRevealValue(actor, key, scope);
|
|
176625
|
+
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
176626
|
if (!resolved) {
|
|
176346
176627
|
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 });
|
|
176628
|
+
await opts.credentialAudit?.({ kind: "credential_reveal_denied", actor, variableKey: key, source, timestamp, reason, ...dispatchFields, ...consoleMeta });
|
|
176348
176629
|
return { status: 403, body: { code: "denied", key } };
|
|
176349
176630
|
}
|
|
176350
|
-
await opts.credentialAudit?.({ kind: "credential_reveal", actor, variableKey: key, source, timestamp, ...dispatchFields });
|
|
176631
|
+
await opts.credentialAudit?.({ kind: "credential_reveal", actor, variableKey: key, source, timestamp, ...dispatchFields, ...consoleMeta });
|
|
176632
|
+
await service.touchVariableUsage(key, resolved.origin, timestamp);
|
|
176351
176633
|
return { status: 200, body: { value: resolved.value } };
|
|
176352
176634
|
});
|
|
176353
176635
|
router.get("/api/variables/reveal-audit", async (req) => {
|
|
@@ -176850,7 +177132,7 @@ var init_routes2 = __esm({
|
|
|
176850
177132
|
init_image_upload();
|
|
176851
177133
|
init_skill_materializer();
|
|
176852
177134
|
init_connector_skills();
|
|
176853
|
-
CREDENTIAL_REVEAL_SOURCES = /* @__PURE__ */ new Set(["agent-cli", "agent-exec", "smoke-test", "oasis-internal"]);
|
|
177135
|
+
CREDENTIAL_REVEAL_SOURCES = /* @__PURE__ */ new Set(["agent-cli", "agent-exec", "smoke-test", "oasis-internal", "console"]);
|
|
176854
177136
|
RevealRateLimiter = class {
|
|
176855
177137
|
constructor(perSession, perSessionPerKey, ttlMs = 2 * 60 * 6e4) {
|
|
176856
177138
|
this.perSession = perSession;
|
|
@@ -183066,8 +183348,8 @@ function executionContinuityDomain(service) {
|
|
|
183066
183348
|
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
183349
|
throw new ApiError(400, "BAD_REQUEST", "handoff arrays contain invalid values");
|
|
183068
183350
|
}
|
|
183069
|
-
if (!isUserHandoff(b2.userHandoff)) {
|
|
183070
|
-
throw new ApiError(400, "BAD_REQUEST", "\
|
|
183351
|
+
if (b2.userHandoff !== void 0 && b2.userHandoff !== null && !isUserHandoff(b2.userHandoff)) {
|
|
183352
|
+
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
183353
|
}
|
|
183072
183354
|
const handoff = await service.handoff({
|
|
183073
183355
|
attemptId,
|
|
@@ -183118,10 +183400,20 @@ function renderResumePack(pack) {
|
|
|
183118
183400
|
if (!pack.previousAttempt) lines.push("- This is the first attempt.");
|
|
183119
183401
|
else {
|
|
183120
183402
|
lines.push(`- Attempt ${pack.previousAttempt.attemptNo ?? "?"}: ${pack.previousHandoff?.summary || pack.previousAttempt.status}`);
|
|
183121
|
-
|
|
183122
|
-
|
|
183123
|
-
|
|
183124
|
-
|
|
183403
|
+
const cp = pack.latestCheckpoint;
|
|
183404
|
+
const done = cp?.completedStepIds ?? [];
|
|
183405
|
+
const durable = (cp?.durableRefs.length ? cp.durableRefs : pack.previousHandoff?.changedOutputs) ?? [];
|
|
183406
|
+
if (cp) lines.push(`- Recoverability: ${cp.recoverability}`);
|
|
183407
|
+
if (done.length > 0) lines.push(`- \u4E0A\u4E00\u8D9F\u5DF2\u5B8C\u6210\u7684\u6B65\u9AA4\uFF1A${done.join("\u3001")}`);
|
|
183408
|
+
for (const ref2 of durable) {
|
|
183409
|
+
lines.push(` - durable: ${ref2.kind}:${ref2.id}${ref2.version ? `@${ref2.version}` : ""}${ref2.label ? ` \u2014 ${ref2.label}` : ""}`);
|
|
183410
|
+
}
|
|
183411
|
+
if (cp && cp.pendingSteps.length > 0) {
|
|
183412
|
+
for (const step of cp.pendingSteps) lines.push(` - pending: ${step}`);
|
|
183413
|
+
} else {
|
|
183414
|
+
lines.push(
|
|
183415
|
+
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"
|
|
183416
|
+
);
|
|
183125
183417
|
}
|
|
183126
183418
|
}
|
|
183127
183419
|
lines.push("", "## External effects");
|
|
@@ -183230,6 +183522,7 @@ function renderCoordinatorView(view) {
|
|
|
183230
183522
|
function shouldInjectResumePack(pack) {
|
|
183231
183523
|
const status = pack?.previousAttempt?.status;
|
|
183232
183524
|
if (!status) return false;
|
|
183525
|
+
if (status === "running" || status === "queued") return false;
|
|
183233
183526
|
return status !== "succeeded" && status !== "no-output";
|
|
183234
183527
|
}
|
|
183235
183528
|
function renderContinuityProtocol() {
|
|
@@ -183462,9 +183755,6 @@ var init_service7 = __esm({
|
|
|
183462
183755
|
async handoff(input) {
|
|
183463
183756
|
if (!HANDOFF_OUTCOMES2.has(input.outcome)) throw new Error(`invalid handoff outcome: ${input.outcome}`);
|
|
183464
183757
|
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
183758
|
const userHandoff = input.userHandoff ? normalizeUserHandoff(input.outcome, input.changedOutputs ?? [], input.userHandoff) : void 0;
|
|
183469
183759
|
const attempt = await this.awaitAttempt(input.attemptId);
|
|
183470
183760
|
const handoff = await this.afterAttemptVisible(() => this.store.putHandoff({
|
|
@@ -183668,8 +183958,7 @@ var init_service7 = __esm({
|
|
|
183668
183958
|
"failed"
|
|
183669
183959
|
].map((state) => [state, nodes.filter((node) => node.nodeState === state).length]));
|
|
183670
183960
|
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
|
-
|
|
183672
|
-
return { workOrderId, mode: this.mode, collaborationStatus, handoffSummary, progress, nodes, dependencyBlocks, todo: todos };
|
|
183961
|
+
return { workOrderId, mode: this.mode, collaborationStatus, progress, nodes, dependencyBlocks, todo: todos };
|
|
183673
183962
|
}
|
|
183674
183963
|
};
|
|
183675
183964
|
}
|
|
@@ -183804,8 +184093,7 @@ function createUpstreamHandoffInputResolver(opts) {
|
|
|
183804
184093
|
const edge = snapshot.edges.find(
|
|
183805
184094
|
(candidate) => candidate.fromNodeId === input.upstreamNodeId && candidate.toNodeId === input.downstreamNodeId
|
|
183806
184095
|
);
|
|
183807
|
-
const
|
|
183808
|
-
const businessEdge = edge?.kind === "data" && edge.required && downstream?.fields?.[BUSINESS_HANDOFF_POLICY_FIELD] !== BUSINESS_HANDOFF_POLICY_EXEMPT;
|
|
184096
|
+
const businessEdge = edge?.kind === "data" && edge.required;
|
|
183809
184097
|
if (!businessEdge) return null;
|
|
183810
184098
|
if (edge.pinnedWorkId !== input.pinnedWorkId) {
|
|
183811
184099
|
warn(
|
|
@@ -183831,7 +184119,7 @@ function createUpstreamHandoffInputResolver(opts) {
|
|
|
183831
184119
|
version: input.pinnedWorkId,
|
|
183832
184120
|
...upstreamNode?.title ? { label: upstreamNode.title } : {}
|
|
183833
184121
|
}];
|
|
183834
|
-
const deliveredRow =
|
|
184122
|
+
const deliveredRow = await opts.getHandoffByOutputVersion(input.pinnedWorkId).catch(() => null);
|
|
183835
184123
|
const systemHandoff = () => renderDeliveredWorkHandoff({
|
|
183836
184124
|
upstreamNodeId: input.upstreamNodeId,
|
|
183837
184125
|
upstreamTitle: upstreamNode?.title,
|
|
@@ -183871,7 +184159,6 @@ var INJECTED_TEXT_LIMIT, NONE_TOKENS;
|
|
|
183871
184159
|
var init_upstream_handoff_input = __esm({
|
|
183872
184160
|
"../server/src/domains/execution-continuity/upstream-handoff-input.ts"() {
|
|
183873
184161
|
"use strict";
|
|
183874
|
-
init_src3();
|
|
183875
184162
|
INJECTED_TEXT_LIMIT = 4e3;
|
|
183876
184163
|
NONE_TOKENS = /* @__PURE__ */ new Set(["none", "n/a", "na", "nil", "\u65E0", "\u6CA1\u6709", "\u6682\u65E0"]);
|
|
183877
184164
|
}
|
|
@@ -187514,8 +187801,30 @@ ${ctx.nodeFault}
|
|
|
187514
187801
|
...prov?.connectorCreds && prov.connectorCreds.length > 0 ? { connectorCreds: prov.connectorCreds } : {}
|
|
187515
187802
|
};
|
|
187516
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
|
+
}
|
|
187517
187817
|
const handle = await this.deps.adapter.spawn(job);
|
|
187518
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
|
+
}
|
|
187519
187828
|
await this.finalizeStage(token);
|
|
187520
187829
|
this.registerRetained(artifactId, actorId, runtimeSessionId);
|
|
187521
187830
|
return { sessionId: runtimeSessionId, managerActorId: actorId, exit };
|
|
@@ -188084,7 +188393,10 @@ function rowToVariable(row) {
|
|
|
188084
188393
|
// **不塌成 env**,否则未知档位读回来变明文;仅 null/空回填 "env"(存量行)。派单侧按未知档保守处理。
|
|
188085
188394
|
deliveryMode: typeof row.delivery_mode === "string" && row.delivery_mode ? row.delivery_mode : "env",
|
|
188086
188395
|
valueEncrypted: row.value_encrypted,
|
|
188087
|
-
updatedAt: new Date(row.updated_at).toISOString()
|
|
188396
|
+
updatedAt: new Date(row.updated_at).toISOString(),
|
|
188397
|
+
// ADR 凭据保险库补章 §D2.1:到期/取用时间戳(text 列存 ISO 字符串,原样带出;null/空 = undefined)。
|
|
188398
|
+
...row.expires_at ? { expiresAt: row.expires_at } : {},
|
|
188399
|
+
...row.last_used_at ? { lastUsedAt: row.last_used_at } : {}
|
|
188088
188400
|
};
|
|
188089
188401
|
}
|
|
188090
188402
|
var ident4, PostgresRegistryStore, rowToActor, rowToConfig, rowToAgentPrefs;
|
|
@@ -188247,6 +188559,8 @@ var init_postgres_registry = __esm({
|
|
|
188247
188559
|
await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS project_id text`);
|
|
188248
188560
|
await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS environment text`);
|
|
188249
188561
|
await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS delivery_mode text`);
|
|
188562
|
+
await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS expires_at text`);
|
|
188563
|
+
await pool.query(`ALTER TABLE IF EXISTS "${s2}".variables ADD COLUMN IF NOT EXISTS last_used_at text`);
|
|
188250
188564
|
await pool.query(`DROP INDEX IF EXISTS "${s2}"."${s2}_variables_key_actor_uq"`);
|
|
188251
188565
|
await pool.query(`DROP INDEX IF EXISTS "${s2}"."${s2}_variables_scope_uq"`);
|
|
188252
188566
|
await pool.query(`
|
|
@@ -188723,10 +189037,10 @@ var init_postgres_registry = __esm({
|
|
|
188723
189037
|
/* ---------- 变量 ---------- */
|
|
188724
189038
|
async putVariable(v2) {
|
|
188725
189039
|
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)
|
|
189040
|
+
`INSERT INTO ${this.s}.variables (key, scope, actor_id, project_id, connector_id, overrides, delivery_mode, value_encrypted, updated_at, expires_at)
|
|
189041
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
|
|
188728
189042
|
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`,
|
|
189043
|
+
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
189044
|
[
|
|
188731
189045
|
v2.key,
|
|
188732
189046
|
v2.scope,
|
|
@@ -188736,10 +189050,18 @@ var init_postgres_registry = __esm({
|
|
|
188736
189050
|
v2.overrides ?? null,
|
|
188737
189051
|
v2.deliveryMode ?? null,
|
|
188738
189052
|
v2.valueEncrypted,
|
|
188739
|
-
v2.updatedAt
|
|
189053
|
+
v2.updatedAt,
|
|
189054
|
+
v2.expiresAt ?? null
|
|
188740
189055
|
]
|
|
188741
189056
|
);
|
|
188742
189057
|
}
|
|
189058
|
+
async touchVariableUsage(key, actorId, projectId, when) {
|
|
189059
|
+
await this.pool.query(
|
|
189060
|
+
`UPDATE ${this.s}.variables SET last_used_at=$4
|
|
189061
|
+
WHERE key=$1 AND COALESCE(actor_id,'')=COALESCE($2::text,'') AND COALESCE(project_id,'')=COALESCE($3::text,'')`,
|
|
189062
|
+
[key, actorId ?? null, projectId ?? null, when]
|
|
189063
|
+
);
|
|
189064
|
+
}
|
|
188743
189065
|
async patchVariableValue(key, actorId, valueEncrypted, updatedAt) {
|
|
188744
189066
|
const aid = actorId ?? null;
|
|
188745
189067
|
await this.pool.query(
|
|
@@ -190668,6 +190990,9 @@ var init_postgres_trace = __esm({
|
|
|
190668
190990
|
await pool.query(`ALTER TABLE "${s2}".node_handoffs ADD COLUMN IF NOT EXISTS part text`);
|
|
190669
190991
|
await pool.query(`ALTER TABLE "${s2}".node_handoffs ADD COLUMN IF NOT EXISTS user_handoff jsonb`);
|
|
190670
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
|
+
);
|
|
190671
190996
|
await pool.query(`
|
|
190672
190997
|
UPDATE "${s2}".node_handoffs h
|
|
190673
190998
|
SET job_key=COALESCE(NULLIF(h.job_key, ''), r.job_key, 'attempt:' || h.attempt_id), part=r.part
|
|
@@ -190777,15 +191102,26 @@ var init_postgres_trace = __esm({
|
|
|
190777
191102
|
END,
|
|
190778
191103
|
400
|
|
190779
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
|
|
190780
191120
|
reconstructed_risks :=
|
|
190781
|
-
CASE WHEN NEW.error_message IS NULL THEN '[]'::jsonb
|
|
190782
|
-
ELSE jsonb_build_array(left(NEW.error_message, 400)) END ||
|
|
190783
191121
|
CASE WHEN COALESCE(pending_effects, 0) = 0 AND COALESCE(failed_effects, 0) = 0 THEN '[]'::jsonb
|
|
190784
191122
|
ELSE jsonb_build_array('external effects: pending=' || COALESCE(pending_effects, 0) ||
|
|
190785
191123
|
', failed=' || COALESCE(failed_effects, 0)) END;
|
|
190786
|
-
reconstructed_gaps :=
|
|
190787
|
-
THEN jsonb_build_array('No valid pre-terminal checkpoint was available.')
|
|
190788
|
-
ELSE '[]'::jsonb END;
|
|
191124
|
+
reconstructed_gaps := '[]'::jsonb;
|
|
190789
191125
|
INSERT INTO "${s2}".node_handoffs AS current_handoff
|
|
190790
191126
|
(handoff_id, attempt_id, job_key, part, produced_by, outcome, summary, changed_outputs,
|
|
190791
191127
|
unresolved_issues, risks, next_actions, verification_gaps, user_handoff, created_at)
|
|
@@ -191733,6 +192069,15 @@ var init_postgres_trace = __esm({
|
|
|
191733
192069
|
const r = await this.pool.query(`SELECT * FROM ${this.s}.node_handoffs WHERE attempt_id=$1`, [attemptId]);
|
|
191734
192070
|
return r.rows[0] ? rowToHandoff(r.rows[0]) : null;
|
|
191735
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
|
+
}
|
|
191736
192081
|
async listAttempts(workOrderId) {
|
|
191737
192082
|
const r = await this.pool.query(
|
|
191738
192083
|
`SELECT r.*, (SELECT count(*) FROM ${this.s}.agent_tool_calls tc WHERE tc.run_id=r.id)::int AS tool_call_count
|
|
@@ -194470,6 +194815,15 @@ async function buildActorProvision(service, actorId, scope, onBrokerRefused) {
|
|
|
194470
194815
|
const brokerRefused = [];
|
|
194471
194816
|
applyRefDelivery(env, entries, void 0, (k2) => brokerRefused.push(k2));
|
|
194472
194817
|
if (onBrokerRefused) for (const k2 of brokerRefused) await onBrokerRefused(k2);
|
|
194818
|
+
const brokerSet = new Set(brokerRefused);
|
|
194819
|
+
for (const e of entries) {
|
|
194820
|
+
if (brokerSet.has(e.key)) continue;
|
|
194821
|
+
try {
|
|
194822
|
+
await service.touchVariableUsage(e.key, e.origin);
|
|
194823
|
+
} catch (err) {
|
|
194824
|
+
console.warn(`[credential] touchVariableUsage(${e.key}) \u5931\u8D25\uFF08\u4E0D\u963B\u65AD\u6D3E\u5355\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}`);
|
|
194825
|
+
}
|
|
194826
|
+
}
|
|
194473
194827
|
return {
|
|
194474
194828
|
env,
|
|
194475
194829
|
wrapperPaths: [oasisWrapperScript(), ...provision.wrapperPaths],
|
|
@@ -195781,7 +196135,10 @@ async function startServe(opts) {
|
|
|
195781
196135
|
...await materializeSkillFiles({ service: actors.service, actorId, runtimeKind })
|
|
195782
196136
|
}),
|
|
195783
196137
|
uploadChatAttachment: async ({ contentBase64 }) => ({ blobRef: await assets.put(new Uint8Array(Buffer.from(contentBase64, "base64"))) }),
|
|
195784
|
-
onDispatchCommandCompleted: async ({ dispatchId, command, durableRefs, at, delivered }) => {
|
|
196138
|
+
onDispatchCommandCompleted: async ({ dispatchId, command, durableRefs, at, delivered, pendingSteps }) => {
|
|
196139
|
+
if (pendingSteps && pendingSteps.length > 0) {
|
|
196140
|
+
traceStoreSink.checkpointState(dispatchId, { pendingSteps: [...pendingSteps] });
|
|
196141
|
+
}
|
|
195785
196142
|
traceStoreSink.checkpoint(dispatchId, {
|
|
195786
196143
|
trigger: "important_output",
|
|
195787
196144
|
// 交作业的那条命令带着版本号(`wk:<节点>:<n>`),比笼统的「动过这个产物」有用得多——
|
|
@@ -196909,7 +197266,8 @@ async function startServe(opts) {
|
|
|
196909
197266
|
if (!store) throw new Error(`engine store unavailable for ${companyId}`);
|
|
196910
197267
|
return store.transaction((tx) => tx.loadWorkorder(workOrderId));
|
|
196911
197268
|
},
|
|
196912
|
-
getHandoff: (attemptId) => traceStore.getHandoff(attemptId)
|
|
197269
|
+
getHandoff: (attemptId) => traceStore.getHandoff(attemptId),
|
|
197270
|
+
getHandoffByOutputVersion: (version2) => traceStore.getHandoffByOutputVersion(version2)
|
|
196913
197271
|
}),
|
|
196914
197272
|
executionContinuityInstructions: continuityMode === "off" ? renderBusinessHandoffProtocol() : renderContinuityProtocol(),
|
|
196915
197273
|
// ★ 恢复包注入(2026-08-17):从「只有 resume 实验组才给」改成「只要账本开着就给」——
|
|
@@ -197529,6 +197887,31 @@ ${st.detail}
|
|
|
197529
197887
|
const view = await executionContinuity.service.coordinatorView(workOrderId, defaultCompanyId);
|
|
197530
197888
|
return view ? renderCoordinatorView(view) : null;
|
|
197531
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
|
+
},
|
|
197532
197915
|
// 阻塞诊断(proposal D1/D3):派发器运行时信号(queued/fused/backoff/hasInFlight)注入诊断,
|
|
197533
197916
|
// 让协调者把"资源 / 运行时"病因和"图病"分开——资源排队的节点不会被误唤去砍流程。
|
|
197534
197917
|
runtimeSignals: (id) => {
|
|
@@ -197751,12 +198134,13 @@ var KNOWN2 = [
|
|
|
197751
198134
|
{ adapter: "copilot", binary: "copilot" },
|
|
197752
198135
|
{ adapter: "kimi", binary: "kimi" },
|
|
197753
198136
|
{ adapter: "kiro", binary: "kiro-cli" },
|
|
198137
|
+
{ adapter: "reasonix", binary: "reasonix" },
|
|
197754
198138
|
{ adapter: "pi", binary: "pi" },
|
|
197755
198139
|
{ adapter: "openclaw", binary: "openclaw" },
|
|
197756
198140
|
{ adapter: "codebuddy", binary: "codebuddy" },
|
|
197757
198141
|
{ adapter: "antigravity", binary: "agy" }
|
|
197758
198142
|
];
|
|
197759
|
-
var NATIVE_APPEND_RUNTIMES = /* @__PURE__ */ new Set(["hermes", "gemini", "kimi", "kiro"]);
|
|
198143
|
+
var NATIVE_APPEND_RUNTIMES = /* @__PURE__ */ new Set(["hermes", "gemini", "kimi", "kiro", "reasonix"]);
|
|
197760
198144
|
function onPath(binary) {
|
|
197761
198145
|
try {
|
|
197762
198146
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
@@ -198560,6 +198944,7 @@ async function startNode(opts) {
|
|
|
198560
198944
|
copilot: new CopilotAdapter(),
|
|
198561
198945
|
kimi: new KimiAdapter(),
|
|
198562
198946
|
kiro: new KiroAdapter(),
|
|
198947
|
+
reasonix: new ReasonixAdapter(),
|
|
198563
198948
|
pi: new PiAdapter(),
|
|
198564
198949
|
openclaw: new OpenClawAdapter(),
|
|
198565
198950
|
codebuddy: new CodebuddyAdapter(),
|
|
@@ -199044,7 +199429,8 @@ var COMMAND_DECLS = {
|
|
|
199044
199429
|
{ 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
199430
|
{ name: "risks", desc: "\u4E0B\u6E38\u8BE5\u77E5\u9053\u7684\u98CE\u9669\uFF08\u5206\u53F7\u5206\u9694\uFF09" },
|
|
199046
199431
|
{ 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" }
|
|
199432
|
+
{ 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" },
|
|
199433
|
+
{ 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
199434
|
],
|
|
199049
199435
|
examples: [
|
|
199050
199436
|
'oasis propose artifact:dev:abc-123 --from-dir deliverable/ --reason "\u4FEE\u590D\u767B\u5F55\u9875\u767D\u5C4F"',
|
|
@@ -199217,13 +199603,13 @@ var COMMAND_DECLS = {
|
|
|
199217
199603
|
},
|
|
199218
199604
|
"continuity-checkpoint": {
|
|
199219
199605
|
group: "\u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09",
|
|
199220
|
-
usage: "oasis continuity-checkpoint --pending <
|
|
199606
|
+
usage: "oasis continuity-checkpoint --pending <list> --recoverability full|partial|none [--trigger plan_completed|stage_completed] [--refs <json-array>] [--completed <list>]",
|
|
199221
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",
|
|
199222
199608
|
flags: [
|
|
199223
|
-
{ name: "pending", desc:
|
|
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 },
|
|
199224
199610
|
{ name: "recoverability", desc: "\u6062\u590D\u7A0B\u5EA6\uFF08full | partial | none\uFF09", required: true },
|
|
199225
199611
|
{ name: "refs", desc: "\u5DF2\u6301\u4E45\u5316\u4EA7\u51FA\u5F15\u7528 JSON array" },
|
|
199226
|
-
{ name: "completed", desc: "\u5DF2\u5B8C\u6210\u7A33\u5B9A\u6B65\u9AA4 id
|
|
199612
|
+
{ name: "completed", desc: "\u5DF2\u5B8C\u6210\u7684\u7A33\u5B9A\u6B65\u9AA4 id\u3002JSON \u6570\u7EC4\u6216\u5206\u53F7\u5206\u9694\u90FD\u6536" },
|
|
199227
199613
|
{ name: "trigger", desc: "\u7ED3\u6784\u5316\u8FB9\u754C\uFF08plan_completed | stage_completed\uFF1B\u7701\u7565\u4E3A\u666E\u901A agent checkpoint\uFF09" }
|
|
199228
199614
|
],
|
|
199229
199615
|
examples: [`oasis continuity-checkpoint --pending '["run tests"]' --recoverability full --refs '[{"kind":"file","id":"src/x.ts"}]'`]
|
|
@@ -200336,6 +200722,19 @@ function semicolonList(raw, field) {
|
|
|
200336
200722
|
const items = raw.split(";").map((x2) => x2.trim()).filter(Boolean);
|
|
200337
200723
|
return items.length > 0 ? { [field]: items } : {};
|
|
200338
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
|
+
}
|
|
200339
200738
|
async function readStdin() {
|
|
200340
200739
|
if (process.stdin.isTTY) return "";
|
|
200341
200740
|
const chunks = [];
|
|
@@ -200896,13 +201295,6 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
200896
201295
|
}
|
|
200897
201296
|
return parsed;
|
|
200898
201297
|
};
|
|
200899
|
-
const parseStringArrayFlag = (value, name) => {
|
|
200900
|
-
const parsed = JSON.parse(value);
|
|
200901
|
-
if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== "string")) {
|
|
200902
|
-
throw new Error(`--${name} \u5FC5\u987B\u662F JSON string array`);
|
|
200903
|
-
}
|
|
200904
|
-
return parsed;
|
|
200905
|
-
};
|
|
200906
201298
|
const parseArrayFlag = (value, name) => {
|
|
200907
201299
|
const parsed = JSON.parse(value);
|
|
200908
201300
|
if (!Array.isArray(parsed)) throw new Error(`--${name} \u5FC5\u987B\u662F JSON array`);
|
|
@@ -201730,7 +202122,9 @@ ${res.warning}`);
|
|
|
201730
202122
|
...semicolonList(flags.get("unresolved"), "unresolvedIssues"),
|
|
201731
202123
|
...semicolonList(flags.get("risks"), "risks"),
|
|
201732
202124
|
...semicolonList(flags.get("next"), "nextActions"),
|
|
201733
|
-
...semicolonList(flags.get("gaps"), "verificationGaps")
|
|
202125
|
+
...semicolonList(flags.get("gaps"), "verificationGaps"),
|
|
202126
|
+
// 「还剩什么没做」:唯一系统推不出来的字段,挂在本来就要跑的命令上(见 server 的 pendingSteps 注释)
|
|
202127
|
+
...semicolonList(flags.get("pending"), "pendingSteps")
|
|
201734
202128
|
});
|
|
201735
202129
|
println(message);
|
|
201736
202130
|
break;
|
|
@@ -203004,7 +203398,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
|
|
|
203004
203398
|
}
|
|
203005
203399
|
|
|
203006
203400
|
// src/index.ts
|
|
203007
|
-
var PKG_VERSION = true ? "0.1.
|
|
203401
|
+
var PKG_VERSION = true ? "0.1.110" : "dev";
|
|
203008
203402
|
var OASIS_DIR = path28.join(os11.homedir(), ".oasis");
|
|
203009
203403
|
var CONFIG_FILE = path28.join(OASIS_DIR, "node-config.json");
|
|
203010
203404
|
var PID_FILE = path28.join(OASIS_DIR, "node.pid");
|