oasis_test 0.1.60 → 0.1.62
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 +757 -418
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1912,9 +1912,12 @@ var init_kernel = __esm({
|
|
|
1912
1912
|
};
|
|
1913
1913
|
FrozenError = class extends KernelError {
|
|
1914
1914
|
name = "FrozenError";
|
|
1915
|
-
retryable
|
|
1916
|
-
constructor(artifactId, scope) {
|
|
1917
|
-
super(
|
|
1915
|
+
retryable;
|
|
1916
|
+
constructor(artifactId, scope, opts) {
|
|
1917
|
+
super(
|
|
1918
|
+
opts?.reviewPending ? `artifact under review\uFF08\u6536\u5C3E\u8BC4\u5BA1\u8FDB\u884C\u4E2D\uFF0C\u7B49 reviewer/CI \u6295\u7968\u2014\u2014\u522B\u91CD\u8BD5\uFF1B\u6709\u672A\u7B54\u590D\u7684\u56DE\u538B\u5148\u5904\u7F6E\uFF09: ${artifactId}` : `artifact is frozen (scope=${scope}, retry after unfreeze): ${artifactId}`
|
|
1919
|
+
);
|
|
1920
|
+
this.retryable = !opts?.reviewPending;
|
|
1918
1921
|
}
|
|
1919
1922
|
};
|
|
1920
1923
|
Kernel = class _Kernel {
|
|
@@ -2305,15 +2308,15 @@ var init_kernel = __esm({
|
|
|
2305
2308
|
if (artifact.currentRev === null) {
|
|
2306
2309
|
throw new KernelError(`cannot conclude an empty artifact: ${args.artifactId}`);
|
|
2307
2310
|
}
|
|
2308
|
-
if (concludeMilestones(this.model, args.artifactId).some((m2) => m2.head === artifact.currentRev)) {
|
|
2309
|
-
return;
|
|
2310
|
-
}
|
|
2311
2311
|
const pending = queueOf(this.model, args.artifactId);
|
|
2312
2312
|
if (pending.length > 0) {
|
|
2313
2313
|
throw new KernelError(
|
|
2314
2314
|
`queue not quiescent (${pending.length} pending): \u4E0D\u80FD\u5BF9\u9A6C\u4E0A\u8981\u53D8\u7684 head \u5BA3\u5E03\u5B8C\u6210\u2014\u2014\u5148\u843D\u5B8C/\u62D2\u6389/\u96C6\u6210\uFF08\xA75.7\uFF09`
|
|
2315
2315
|
);
|
|
2316
2316
|
}
|
|
2317
|
+
if (concludeMilestones(this.model, args.artifactId).some((m2) => m2.head === artifact.currentRev)) {
|
|
2318
|
+
return { kind: "noop-concluded", head: artifact.currentRev };
|
|
2319
|
+
}
|
|
2317
2320
|
const openGaps = unresolvedGapsOf(this.model, args.artifactId);
|
|
2318
2321
|
if (openGaps.length > 0) {
|
|
2319
2322
|
throw new KernelError(
|
|
@@ -2395,7 +2398,11 @@ var init_kernel = __esm({
|
|
|
2395
2398
|
...gate ? { gate } : {}
|
|
2396
2399
|
};
|
|
2397
2400
|
await this.commit(args.artifactId, args.actor, "conclude", args.artifactId, payload);
|
|
2398
|
-
if (!gate)
|
|
2401
|
+
if (!gate) {
|
|
2402
|
+
await this.fireTriggers(args.artifactId);
|
|
2403
|
+
return { kind: "milestone", head: artifact.currentRev };
|
|
2404
|
+
}
|
|
2405
|
+
return { kind: "gate-pending" };
|
|
2399
2406
|
}
|
|
2400
2407
|
/**
|
|
2401
2408
|
* 收尾 gate 投票(§5.3/§5.7)。票落在被审的 head 快照上;
|
|
@@ -3354,7 +3361,7 @@ ${res.candidates.map((c) => ` - ${c.type}:${c.title ?? "(\u65E0title)"} \u2192
|
|
|
3354
3361
|
bounceHeadMovers(artifactId, opts) {
|
|
3355
3362
|
const scope = this.frozen.get(artifactId);
|
|
3356
3363
|
if (scope) throw new FrozenError(artifactId, scope);
|
|
3357
|
-
if (!opts?.allowPendingGate && pendingConcludeAttempt(this.model, artifactId)) throw new FrozenError(artifactId, "merge");
|
|
3364
|
+
if (!opts?.allowPendingGate && pendingConcludeAttempt(this.model, artifactId)) throw new FrozenError(artifactId, "merge", { reviewPending: true });
|
|
3358
3365
|
}
|
|
3359
3366
|
/** propose(emit)类:只有 write 档(§11.7 干预)才拦——merge 档下照常入队。 */
|
|
3360
3367
|
bounceWrites(artifactId) {
|
|
@@ -3860,14 +3867,29 @@ async function assembleContext(args) {
|
|
|
3860
3867
|
})
|
|
3861
3868
|
];
|
|
3862
3869
|
})() : canvasMode ? [
|
|
3863
|
-
`\u4F60\u8D1F\u8D23 **design \u4EA7\u7269 \`${artifactId}\`**\uFF0C\u8FD0\u884C\u5728**\u901A\u7528\u8FD0\u884C\u65F6**\u4E0A\u2014\u2014\
|
|
3870
|
+
`\u4F60\u8D1F\u8D23 **design \u4EA7\u7269 \`${artifactId}\`**\uFF0C\u8FD0\u884C\u5728**\u901A\u7528\u8FD0\u884C\u65F6**\u4E0A\u2014\u2014\u4F60\u662F**\u7532\u65B9\u8BBE\u8BA1\u8D1F\u8D23\u4EBA**\uFF0C\u591A\u8F6E\u5BF9\u8BDD\u9A71\u52A8**\u534F\u4F5C\u753B\u677F\u5F15\u64CE**\u6253\u78E8\u754C\u9762\u7A3F\uFF0C\u6EE1\u610F\u4E86\u624D\u4EA4\u4ED8\u3002`,
|
|
3871
|
+
``,
|
|
3872
|
+
`**\u7B2C 0 \u6B65\uFF08\u6BCF\u6B21\u88AB\u6D3E\u53D1\u90FD\u5148\u505A\uFF0C\u518D\u51B3\u5B9A\u5F00\u4E0D\u5F00\u65B0\u8F6E\uFF09\u2014\u2014\u5148\u53D6\u8D27\uFF1A**`,
|
|
3873
|
+
``,
|
|
3874
|
+
` oasis design status ${artifactId}`,
|
|
3864
3875
|
``,
|
|
3865
|
-
|
|
3876
|
+
`- \u677F\u4E0A**\u5DF2\u6709\u8DD1\u5B8C\u7684\u4EA4\u4ED8\u7269**\uFF08\u4E0A\u4E00\u4E2A\u4F1A\u8BDD\u59D4\u6258\u7684\u5F15\u64CE\u8DD1\u5B8C\u4E86\uFF0C\u8D27\u6CA1\u4EBA\u6536\uFF09\u2192 \`--pull\` \u62C9\u5230\u672C\u5730**\u76F4\u63A5\u8FDB\u300C\u8BFB\u4EA7\u7269\u300D**\uFF0C\u522B\u91CD\u8DD1\u5F15\u64CE\u767D\u70E7 20-40 \u5206\u949F\uFF1B`,
|
|
3877
|
+
`- **\u5F15\u64CE\u8FD8\u5728\u8DD1** \u2192 \u522B\u518D\u8D77\u65B0\u8F6E\uFF1B\u8FC7\u51E0\u5206\u949F\u518D status\uFF0C\u6216\u672C\u8F6E\u6536\u5DE5\uFF08\u5F15\u64CE\u5728\u670D\u52A1\u7AEF\u81EA\u5DF1\u8DD1\u5B8C\uFF0C\u4E0B\u6B21\u6D3E\u53D1\u6765\u53D6\uFF09\uFF1B`,
|
|
3878
|
+
`- \u4EC0\u4E48\u90FD\u6CA1\u6709 \u2192 \u8D77\u9996\u8F6E\u3002`,
|
|
3866
3879
|
``,
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3880
|
+
`**\u8D77\u4E00\u8F6E\uFF08\u4E0D\u963B\u585E\uFF0C\u79D2\u56DE\uFF09\uFF1A**`,
|
|
3881
|
+
``,
|
|
3882
|
+
` oasis design chat ${artifactId} --message "<\u8FD9\u4E00\u8F6E\u8981\u5F15\u64CE\u505A\u4EC0\u4E48\uFF1A\u8BBE\u8BA1\u9700\u6C42 + \u771F\u5B9E\u6570\u636E>" --async`,
|
|
3883
|
+
` oasis design chat ${artifactId} --turn continue --message "<\u8BFB\u5B8C\u4E0A\u4E00\u7248\u4EA7\u7269\u540E\uFF0C\u8981\u6539\u54EA\u91CC>" --async`,
|
|
3884
|
+
``,
|
|
3885
|
+
`\u5F15\u64CE\u4E00\u8F6E\u8981 13\u201344 \u5206\u949F\uFF0C\u5728 od \u670D\u52A1\u7AEF\u81EA\u5DF1\u8DD1\u3001**\u4E0E\u4F60\u7684\u4F1A\u8BDD\u751F\u6B7B\u65E0\u5173**\u2014\u2014\`--async\` \u4E0B\u5355\u5373\u8FD4\uFF0C**\u4E0D\u8981\u81EA\u5DF1\u53D1\u660E\u963B\u585E\u7B49\u5F85\u3001\u66F4\u522B\u7528 \`timeout\` \u5305\u547D\u4EE4**\u3002\u4E0B\u5355\u540E\u6BCF\u9694\u51E0\u5206\u949F \`oasis design status\` \u770B\u4E00\u773C\uFF1B\u4E00\u76F4\u6CA1\u5B8C\u4E5F\u53EF\u4EE5\u6536\u5DE5\uFF0C\u4E0B\u6B21\u6D3E\u53D1\u5148 status \u53D6\u8D27\u3002`,
|
|
3886
|
+
``,
|
|
3887
|
+
`**\u6BCF\u4E00\u8F6E\u7684\u95ED\u73AF\uFF08\u522B\u8DF3\u6B65\uFF09**\uFF1A`,
|
|
3888
|
+
`1. **\u5582\u9971\u5B83**\uFF1A\u9996\u8F6E \`--message\` \u628A\u8BBE\u8BA1\u9700\u6C42\u8FDE\u540C**\u771F\u5B9E\u793A\u4F8B\u6570\u636E**\u4E00\u8D77\u7ED9\u8DB3\u2014\u2014\u5F15\u64CE\u53EA\u62FF\u5230 \`DESIGN_BRIEF.md\`/\`inputs/\`\uFF0CPRD \u91CC\u6CA1\u6709\u7684 mock \u6570\u636E\u5B83\u4F1A**\u81EA\u5DF1\u7F16**\uFF08\u66FE\u628A\u5A74\u513F\u770B\u62A4\u5668\u7F16\u6210\u8033\u673A\uFF09\u3002\u771F\u5B9E\u4E1A\u52A1\u6570\u636E\uFF08\u4EA7\u54C1/\u4E70\u5BB6/\u8BA2\u5355\u7B49\uFF09\u5728\u54EA\u3001\u957F\u4EC0\u4E48\u6837\uFF0C\u4F60**\u5FC5\u987B\u5728 message \u91CC\u5199\u6E05\u6216\u544A\u8BC9\u5B83\u53BB\u54EA\u53D6**\uFF1B`,
|
|
3889
|
+
`2. **\u8BFB\u4EA7\u7269**\uFF1A\`oasis design status ${artifactId} --pull\` \u628A\u4EA4\u4ED8\u7269\u62C9\u5230\u672C\u5730\u2014\u2014**\u6253\u5F00 \`index.html\` \u771F\u8BFB\u4E00\u904D**\uFF0C\u5BF9\u7167 \`DESIGN_BRIEF.md\` \u4E0E \`inputs/\` \u6838\uFF1A\u6570\u636E\u5BF9\u4E0D\u5BF9\uFF1F\u72B6\u6001/\u8FB9\u754C\u6001\u5168\u4E0D\u5168\uFF1F\u6709\u6CA1\u6709\u7F16\u9020\uFF1F`,
|
|
3890
|
+
`3. **\u51B3\u5B9A**\uFF1A\u591F\u597D \u2192 \`oasis propose ${artifactId} --from-dir <\u62C9\u4E0B\u6765\u7684\u76EE\u5F55> --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"\` \u4EA4\u7A3F\uFF1B\u8FD8\u5DEE \u2192 \`--turn continue\` **\u518D\u4E00\u8F6E**\u6253\u78E8\uFF1B\u9047\u5230**\u4F60\u4E5F\u5B9A\u4E0D\u4E86\u7684\u53D6\u820D**\uFF08\u5982\u67D0\u6001\u7528\u54EA\u4E2A\u4E70\u5BB6\u627F\u8F7D\uFF09\u2192 \u5199\u8FDB acceptance.md \u7684\u300C\u5F00\u653E\u95EE\u9898\u300D\uFF0C\u6216 \`oasis gap ${artifactId} --desc "<\u8981\u4EBA\u5B9A\u4EC0\u4E48>"\` \u5192\u6CE1\u7ED9\u4EBA\uFF1B`,
|
|
3891
|
+
`- **\u522B\u628A\u7B2C\u4E00\u7248\u76F2\u76EE propose**\u2014\u2014\u5148\u8BFB\u3001\u5148\u81EA\u68C0\u3001\u4E0D\u591F\u5C31\u518D\u4E00\u8F6E\uFF0C\u6BD4 propose \u51FA\u53BB\u88AB\u4E0B\u6E38\u6253\u56DE\u3001\u7ED5\u6574\u5F20\u56FE\u4E00\u5708\u4FBF\u5B9C\u5F97\u591A\uFF1B`,
|
|
3892
|
+
`- \u7F3A**\u8FD8\u4E0D\u5B58\u5728\u7684\u4E0A\u6E38\u524D\u7F6E**\u505A\u4E0D\u4E0B\u53BB \u2192 \`oasis gap ${artifactId} --desc "<\u7F3A\u4EC0\u4E48>"\` \u62A5\u7F3A\u53E3\u540E\u6536\u5DE5\u3002`
|
|
3871
3893
|
] : (() => {
|
|
3872
3894
|
const codeRepo = args.codeRepo ?? null;
|
|
3873
3895
|
const repos = typeDef?.contentType === "code" ? codeRepo?.repos : void 0;
|
|
@@ -3922,7 +3944,7 @@ async function assembleContext(args) {
|
|
|
3922
3944
|
``,
|
|
3923
3945
|
...canvasMode ? [
|
|
3924
3946
|
`## \u5173\u4E8E\u5DE5\u5177`,
|
|
3925
|
-
`oasis CLI \u5DF2\u6CE8\u5165\uFF08\`OASIS_SERVER\` / \`OASIS_TOKEN\` \u5C31\u7EEA\uFF0C\u65E0\u9700\u914D\u7F6E\uFF09\u2014\u2014
|
|
3947
|
+
`oasis CLI \u5DF2\u6CE8\u5165\uFF08\`OASIS_SERVER\` / \`OASIS_TOKEN\` \u5C31\u7EEA\uFF0C\u65E0\u9700\u914D\u7F6E\uFF09\u2014\u2014\u5148 \`oasis design status\` \u53D6\u8D27\uFF0C\u518D\u7528 \`oasis design chat --async\` \u591A\u8F6E\u9A71\u52A8\u753B\u677F\u5F15\u64CE\u6253\u78E8\u754C\u9762\u7A3F\uFF0C\u8BFB\u4EA7\u7269\u540E\u7528 \`oasis propose\` \u4EA4\u7A3F\u3001\`oasis gap\` \u62A5\u7F3A\u53E3\uFF08\u90FD\u89C1\u4E0A\u9762\u300C\u600E\u4E48\u63D0\u4EA4\u300D\uFF09\u3002\u8BBE\u8BA1\u9700\u6C42\u89C1\u672C\u76EE\u5F55 \`DESIGN_BRIEF.md\`\uFF0C\u4E0A\u6E38\u8F93\u5165\u5728 \`inputs/\`\u3002`
|
|
3926
3948
|
] : commandReference({
|
|
3927
3949
|
artifactId,
|
|
3928
3950
|
action: args.action ?? "produce",
|
|
@@ -3950,12 +3972,14 @@ async function assembleContext(args) {
|
|
|
3950
3972
|
(s2) => `- ${s2.upstream}: pin=${s2.pinned ?? "\u2205"} \u2192 \u6700\u65B0 ${s2.latest}${s2.upstreamCancelled ? "\uFF08\u26A0 \u4E0A\u6E38\u5DF2 cancelled\uFF09" : ""}`
|
|
3951
3973
|
)
|
|
3952
3974
|
] : [],
|
|
3953
|
-
//
|
|
3975
|
+
// 画板模式:你在通用 runtime 上、CLI 齐全(design chat/propose/gap 都能用);引擎里的内层 agent 才没 CLI,那层不用你管
|
|
3954
3976
|
...canvasMode ? [
|
|
3955
3977
|
``,
|
|
3956
3978
|
`## \u751F\u4EA7\u8005\u5B88\u5219\uFF08\u753B\u677F\u7248\uFF09`,
|
|
3957
|
-
`- \u4F60\
|
|
3979
|
+
`- \u4F60\u662F\u7532\u65B9\uFF1A\u5148 \`oasis design status\` \u53D6\u8D27\uFF08\u5F15\u64CE\u7684\u6D3B\u4E0D\u767D\u5E72\uFF09\uFF0C\u518D\u591A\u8F6E \`oasis design chat --async\` \u9A71\u52A8\u5F15\u64CE\uFF1B\u6BCF\u8F6E**\u8BFB\u4EA7\u7269**\u518D\u51B3\u5B9A\u2014\u2014\u591F\u597D\u624D \`oasis propose\`\uFF0C\u522B\u628A\u7B2C\u4E00\u7248\u76F2\u76EE\u4EA4\u51FA\u53BB\u3002`,
|
|
3980
|
+
`- \u4F60\u53EA\u4EA7**\u8FD9\u4E00\u4E2A**\u8BBE\u8BA1\u4EA7\u7269\uFF1B**\u4E0D\u5F52\u4F60\u5B9A\u7684\u51B3\u7B56\u522B\u786C\u7F16**\uFF08\u4F1A\u88AB\u6253\u56DE\uFF09\u2014\u2014\u62FF\u4E0D\u51C6\u7684\u53D6\u820D\u5199\u8FDB acceptance.md \u7684\u300C\u5F00\u653E\u95EE\u9898\u300D\uFF0C\u6216 \`oasis gap\` \u5192\u6CE1\u7ED9\u4EBA\u3002`,
|
|
3958
3981
|
`- \u5FE0\u5B9E\u4E8E task-context/ \u91CC\u7684\u4E0A\u6E38\u8F93\u5165\uFF08PRD/\u603B\u7EB2\uFF09\uFF1B\u4E0E\u4E0A\u6E38\u51B2\u7A81\u5904\u4EE5\u4E0A\u6E38\u4E3A\u51C6\uFF0C\u5E76\u5728\u5F00\u653E\u95EE\u9898\u91CC\u6807\u6CE8\u5F02\u8BAE\u3002`,
|
|
3982
|
+
`- \u771F\u5B9E\u793A\u4F8B\u6570\u636E\uFF08\u4EA7\u54C1/\u4E70\u5BB6/\u8BA2\u5355\u7B49\uFF09**\u5FC5\u987B\u5728 \`--message\` \u91CC\u5582\u7ED9\u5F15\u64CE**\u2014\u2014\u5B83\u62FF\u4E0D\u5230\u7684\u4E1C\u897F\u4F1A\u81EA\u5DF1\u7F16\uFF0C\u522B\u8BA9\u5B83\u66FF\u4F60\u9020\u6570\u636E\u3002`,
|
|
3959
3983
|
`- \u754C\u9762\u7A3F\u5FC5\u987B**\u771F\u5B9E\u53EF\u6253\u5F00**\uFF08\u81EA\u5305\u542B HTML\uFF09\uFF0C\u522B\u4EA4\u793A\u610F\u63CF\u8FF0\u3002`
|
|
3960
3984
|
] : [],
|
|
3961
3985
|
// review 会话不产出、不该给生产者守则(它只投票,守则的 propose/conclude/gap/add-revision 全不适用)
|
|
@@ -4228,7 +4252,7 @@ var init_dispatcher = __esm({
|
|
|
4228
4252
|
}
|
|
4229
4253
|
};
|
|
4230
4254
|
SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT = 5;
|
|
4231
|
-
SELF_HEALING_EXITS = /* @__PURE__ */ new Set(["rate-limit"]);
|
|
4255
|
+
SELF_HEALING_EXITS = /* @__PURE__ */ new Set(["rate-limit", "session-not-found"]);
|
|
4232
4256
|
CANVAS_RUNTIME_KIND = "open-design";
|
|
4233
4257
|
NON_PRODUCE_FALLBACK_RUNTIME_KIND = "claude-code";
|
|
4234
4258
|
Dispatcher = class {
|
|
@@ -4284,7 +4308,8 @@ var init_dispatcher = __esm({
|
|
|
4284
4308
|
}
|
|
4285
4309
|
/** ann: 讨论/回踢 resume 用:该 artifact 最近一次 produce/integrate 会话的 runtimeSessionId */
|
|
4286
4310
|
retainedProduceSessionFor(artifactId) {
|
|
4287
|
-
|
|
4311
|
+
const rec = decodeProduceSession(this.produceSessions.get(`produce:${artifactId}`));
|
|
4312
|
+
return rec?.sessionMissing ? void 0 : rec?.rtId;
|
|
4288
4313
|
}
|
|
4289
4314
|
emitJournal(entry) {
|
|
4290
4315
|
try {
|
|
@@ -4681,8 +4706,8 @@ var init_dispatcher = __esm({
|
|
|
4681
4706
|
const sessionKey = this.produceSessionKeyFor(spec);
|
|
4682
4707
|
const prior = sessionKey ? decodeProduceSession(this.produceSessions.get(sessionKey)) : void 0;
|
|
4683
4708
|
const priorConsistent = prior !== void 0 && prior.nodeId === binding?.nodeId && prior.runtimeKind === binding?.runtimeKind;
|
|
4684
|
-
const retainedPartSession = spec.action === "produce" && spec.part !== void 0 && priorConsistent ? prior.rtId : void 0;
|
|
4685
|
-
const retainedWholeSession = spec.action === "produce" && spec.part === void 0 && priorConsistent ? this.resumableWholeSession(spec.artifactId, seqNow, prior.rtId) : void 0;
|
|
4709
|
+
const retainedPartSession = spec.action === "produce" && spec.part !== void 0 && priorConsistent && !prior.sessionMissing ? prior.rtId : void 0;
|
|
4710
|
+
const retainedWholeSession = spec.action === "produce" && spec.part === void 0 && priorConsistent && !prior.sessionMissing ? this.resumableWholeSession(spec.artifactId, seqNow, prior.rtId) : void 0;
|
|
4686
4711
|
const retainedSession = retainedPartSession ?? retainedWholeSession;
|
|
4687
4712
|
const runtimeSessionId = retainedSession ?? (isProduceLike ? (0, import_node_crypto3.randomUUID)() : void 0);
|
|
4688
4713
|
const resumeSession = retainedSession !== void 0;
|
|
@@ -4856,11 +4881,12 @@ var init_dispatcher = __esm({
|
|
|
4856
4881
|
const prev = decodeProduceSession(this.produceSessions.get(exitSessionKey));
|
|
4857
4882
|
if (prev) {
|
|
4858
4883
|
const isWholeProduce = spec.action === "produce" && spec.part === void 0;
|
|
4884
|
+
const sessionNotFound = info.reason === "session-not-found";
|
|
4859
4885
|
try {
|
|
4860
4886
|
this.produceSessions.set(exitSessionKey, encodeProduceSession({
|
|
4861
4887
|
...prev,
|
|
4862
4888
|
...info.runtimeSessionId ? { rtId: info.runtimeSessionId } : {},
|
|
4863
|
-
...isWholeProduce ? { seqAtExit } : { seqAtExit: void 0 },
|
|
4889
|
+
...sessionNotFound ? { sessionMissing: true, seqAtExit: void 0 } : { sessionMissing: void 0, ...isWholeProduce ? { seqAtExit } : { seqAtExit: void 0 } },
|
|
4864
4890
|
lastUsedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4865
4891
|
}));
|
|
4866
4892
|
} catch {
|
|
@@ -136048,8 +136074,22 @@ var init_planner = __esm({
|
|
|
136048
136074
|
name: "provision",
|
|
136049
136075
|
contentType: "text",
|
|
136050
136076
|
ownerRole: "devops",
|
|
136051
|
-
description: "\u4EE3\u7801\u4ED3\u5E93\u4F9B\u7ED9\uFF08\u5EFA\u4ED3\uFF09\uFF1A\u5F53\u9879\u76EE\u91CC\u6CA1\u6709\u4E0B\u6E38\u5B9E\u73B0\u6240\u9700\u7684\u4EE3\u7801\u4ED3\u5E93\u65F6\uFF0C\u7528\u6B64\u8282\u70B9\u5EFA\u4ED3\u2014\u2014\u6309\u7ED3\u6784\uFF08\u5355\u4ED3/\u4F1E\u4ED3\uFF09\u4E0E\u547D\u540D\u5EFA\u597D\u4ED3\u5E93\uFF0C\u521D\u59CB\u5316\u9879\u76EE\u6846\u67B6\u3001\u5FC5\u5907\u6587\u6863\u3001CI/CD \u57FA\u5EFA\u4E0E dev/prod \u73AF\u5883\u914D\u7F6E\uFF0C\u5E76
|
|
136052
|
-
reviews: { gates: [{ on: "conclude", reviewers: ["architect"], quorum: 1 }] }
|
|
136077
|
+
description: "\u4EE3\u7801\u4ED3\u5E93\u4F9B\u7ED9\uFF08\u5EFA\u4ED3\uFF09\uFF1A\u5F53\u9879\u76EE\u91CC\u6CA1\u6709\u4E0B\u6E38\u5B9E\u73B0\u6240\u9700\u7684\u4EE3\u7801\u4ED3\u5E93\u65F6\uFF0C\u7528\u6B64\u8282\u70B9\u5EFA\u4ED3\u2014\u2014\u6309\u7ED3\u6784\uFF08\u5355\u4ED3/\u4F1E\u4ED3\uFF09\u4E0E\u547D\u540D\u5EFA\u597D\u4ED3\u5E93\uFF0C\u521D\u59CB\u5316\u9879\u76EE\u6846\u67B6\u3001\u5FC5\u5907\u6587\u6863\u3001CI/CD \u57FA\u5EFA\uFF08GitHub Actions ci/cd workflow\uFF09\u4E0E dev/prod \u73AF\u5883\u914D\u7F6E\uFF0C\u5E76**\u767B\u8BB0\u5230\u9879\u76EE\u4E14\u6838\u9A8C\u767B\u8BB0\u771F\u7684\u843D\u8FDB\u5185\u6838**\uFF08\u4E0D\u662F\u5199\u7BC7\u6587\u6863\u8BF4\u914D\u597D\u4E86\u5C31\u7B97\uFF09\u3002**\u5EFA\u56FE/\u8865\u56FE\u65F6\uFF0C\u82E5\u53D1\u73B0\u9879\u76EE\u7F3A\u67D0\u4E2A dev\uFF08\u4EE3\u7801\u5B9E\u73B0\uFF09\u8282\u70B9\u6240\u9700\u7684\u4EE3\u7801\u4ED3\u5E93\uFF0C\u5E94\u65B0\u589E\u4E00\u4E2A\u6B64\u7C7B\u578B\u8282\u70B9\uFF0C\u4F5C\u4E3A\u90A3\u4E2A dev \u8282\u70B9\u7684\u524D\u7F6E\u3001\u6392\u5728\u5B83\u4E4B\u524D\u3002** \u4EA7\u51FA\u4E3A\u5EFA\u4ED3\u8BB0\u5F55\uFF08\u8BF4\u660E\u5EFA\u4E86\u54EA\u4E9B\u4ED3\u3001\u903B\u8F91 id \u4E0E\u7ED3\u6784\u3001CI/CD \u9AA8\u67B6\uFF09\uFF0C\u67B6\u6784\u5E08\u8BC4\u5BA1\u3002\u6536\u5C3E\u524D\u987B `oasis record-action <\u672C\u8282\u70B9> --name registration_verified --pass true` \u7559\u75D5\uFF08\u5148\u771F\u6838\u9A8C\u767B\u8BB0\u843D\u5E93\uFF09\u3002",
|
|
136078
|
+
reviews: { gates: [{ on: "conclude", reviewers: ["architect"], quorum: 1 }] },
|
|
136079
|
+
// grounding:登记必须真落库才收口(ADR-0070/§9.2)。防「写篇文档说仓配好了就算交付」(delivery C-2)。
|
|
136080
|
+
grounding: { requiredActions: [{ name: "registration_verified", mustPass: true }] }
|
|
136081
|
+
},
|
|
136082
|
+
{
|
|
136083
|
+
// deploy 此前只在生产经 API 手工新增、不在代码常量里(零审计,见 ADR-0067 背景与 ADR-0070)。
|
|
136084
|
+
// 收编进 DEFAULT_TYPES:给它一份规范定义作为新环境/测试/文档的事实源。
|
|
136085
|
+
// 注意 ensureDefaultWorkorderTypes 只“补缺”——生产已存在的 deploy 条目不会被此定义覆盖。
|
|
136086
|
+
name: "deploy",
|
|
136087
|
+
contentType: "text",
|
|
136088
|
+
ownerRole: "devops",
|
|
136089
|
+
description: "\u771F\u5B9E\u90E8\u7F72\u4E0E\u8054\u8C03\uFF1A\u628A\u5BF9\u5E94 dev\uFF08\u4EE3\u7801\u5B9E\u73B0\uFF09\u4EA7\u51FA\u90E8\u7F72\u5230\u76EE\u6807\u73AF\u5883\u5E76\u8DD1\u901A\u7AEF\u5230\u7AEF\u8054\u8C03\uFF0C\u4EA7\u51FA\u53EF\u8BBF\u95EE\u7684\u90E8\u7F72\u5730\u5740 + \u90E8\u7F72\u8BB0\u5F55\uFF08\u73AF\u5883/\u670D\u52A1/\u7AEF\u53E3/\u5065\u5EB7\u68C0\u67E5\u8BC1\u636E\uFF09\u3002**\u4F9D\u8D56\u5BF9\u5E94\u7684 dev \u8282\u70B9\uFF08required\uFF09\uFF0C\u6392\u5728\u5B83\u4E4B\u540E\uFF1B\u82E5\u672C\u5DE5\u5355\u6709 adr\uFF08\u6280\u672F\u65B9\u6848\uFF0C\u542B CI/CD \u4E0E\u90E8\u7F72\u73AF\u5883\u51B3\u7B56\uFF09\uFF0C\u4E5F\u5E94\u4F9D\u8D56\u8BE5 adr\u2014\u2014\u5982\u6B64\u6280\u672F\u65B9\u6848\u6216\u4EE3\u7801\u4E00\u51FA\u65B0\u91CC\u7A0B\u7891\uFF0C\u672C\u8282\u70B9\u5373\u88AB\u7EA7\u8054\u8FD4\u5DE5\u91CD\u65B0\u90E8\u7F72\uFF08ADR-0067\uFF09\u3002** \u5EFA\u56FE/\u8865\u56FE\u65F6\uFF0C\u5F53\u5DE5\u5355\u9700\u8981\u771F\u90E8\u7F72/\u4E0A\u7EBF\u800C\u975E\u4EC5\u4EA4\u4ED8\u4EE3\u7801\u65F6\u65B0\u589E\u6B64\u8282\u70B9\u3002\u5065\u5EB7\u68C0\u67E5\u987B\u5916\u90E8\u53EF\u8FBE\u3001\u7981\u5047\u7EFF\uFF1B\u4E0B\u6E38\uFF08\u5982 QA\uFF09\u53D1\u73B0\u90E8\u7F72\u7ED3\u679C\u4E0D\u5BF9\u65F6\u5BF9\u672C\u8282\u70B9\u56DE\u538B\uFF08annotate --from\uFF09\u3002\u6536\u5C3E\u524D\u987B\u5148\u771F\u8DD1\u5916\u90E8\u5065\u5EB7\u63A2\u9488\u3001\u518D `oasis record-action <\u672C\u8282\u70B9> --name health_probe --pass true` \u7559\u75D5\uFF0C\u5426\u5219\u6536\u4E0D\u4E86\u53E3\u3002",
|
|
136090
|
+
reviews: { gates: [{ on: "conclude", reviewers: ["qa"], quorum: 1 }] },
|
|
136091
|
+
// grounding:必须有「通过的健康探针」留痕才收口(ADR-0070/§9.2)。机械堵假绿——force 也豁免不了。
|
|
136092
|
+
grounding: { requiredActions: [{ name: "health_probe", mustPass: true }] }
|
|
136053
136093
|
}
|
|
136054
136094
|
];
|
|
136055
136095
|
WORKORDER_SPEC_PREFIX = "OASIS_WORKORDER_SPEC ";
|
|
@@ -137781,11 +137821,15 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}` : brief;
|
|
|
137781
137821
|
}
|
|
137782
137822
|
case "conclude": {
|
|
137783
137823
|
const artifactId = str(args, "artifactId");
|
|
137784
|
-
await kernel.conclude({ artifactId, actor, note: optStr(args, "note") });
|
|
137785
|
-
|
|
137786
|
-
|
|
137787
|
-
message:
|
|
137788
|
-
}
|
|
137824
|
+
const result = await kernel.conclude({ artifactId, actor, note: optStr(args, "note") });
|
|
137825
|
+
if (result.kind === "gate-pending") {
|
|
137826
|
+
const pending = pendingConcludeAttempt(kernel.model, artifactId);
|
|
137827
|
+
return { message: `conclude \u5DF2\u53D1\u8D77\uFF0Cgate \u5F85\u5BA1\uFF08quorum=${pending.gate.quorum}\uFF0Celigible=${pending.gate.eligible.join(", ")}\uFF09` };
|
|
137828
|
+
}
|
|
137829
|
+
if (result.kind === "noop-concluded") {
|
|
137830
|
+
return { message: `\u8BE5 head \u5DF2\u7ECF\u6536\u53E3\u8FC7\u4E86\u3001\u65E0\u65B0\u7248\u672C\u5F85\u6536\u53E3\uFF08head=${result.head}\uFF09\u2014\u2014\u82E5\u4F60\u521A propose \u4E86\u65B0\u7248\uFF0C\u5B83\u53EF\u80FD\u8FD8\u5728\u961F\u5217/\u8BC4\u5BA1\u4E2D\uFF0C\u5148\u8BA9\u5B83\u6210\u4E3A head \u518D\u6536\u53E3\u3002` };
|
|
137831
|
+
}
|
|
137832
|
+
return { message: `concluded\uFF1A\u91CC\u7A0B\u7891\u6210\u7ACB\uFF08head=${result.head}\uFF09` };
|
|
137789
137833
|
}
|
|
137790
137834
|
case "review": {
|
|
137791
137835
|
const revisionArg = optStr(args, "revisionId");
|
|
@@ -138416,7 +138460,7 @@ async function startOasisServer(opts) {
|
|
|
138416
138460
|
res.writeHead(status, { "content-type": "application/json" }).end(
|
|
138417
138461
|
JSON.stringify({
|
|
138418
138462
|
error: err instanceof Error ? err.message : String(err),
|
|
138419
|
-
...err instanceof FrozenError ? { retryable:
|
|
138463
|
+
...err instanceof FrozenError ? { retryable: err.retryable } : {}
|
|
138420
138464
|
})
|
|
138421
138465
|
);
|
|
138422
138466
|
}
|
|
@@ -139078,10 +139122,13 @@ async function startOasisServer(opts) {
|
|
|
139078
139122
|
...draftWorkspace ? { draftWorkspace } : {}
|
|
139079
139123
|
});
|
|
139080
139124
|
const effectiveSessionId = persistTarget ? runtimeChanged ? void 0 : persistTarget.runtimeSessionId ?? void 0 : body.sessionId || void 0;
|
|
139125
|
+
const resumeFallbackHistory = effectiveSessionId && chatStore && persistTarget ? (await chatStore.listMessages(persistTarget.id, 20)).filter((m2) => !(m2.role === "assistant" && m2.status === "running")).map((m2) => ({ role: m2.role, content: m2.role === "user" ? stripInjectedChatContext(m2.content) : m2.content })) : [];
|
|
139126
|
+
const fallbackMessage = resumeFallbackHistory.length ? buildRuntimeChatPrompt({ userMessage: persistedUserMessage, history: resumeFallbackHistory, ...draftWorkspace ? { draftWorkspace } : {} }) : void 0;
|
|
139081
139127
|
const session = await opts.dispatchChat({
|
|
139082
139128
|
actorId: body.actorId,
|
|
139083
139129
|
message: runtimeMessage,
|
|
139084
139130
|
...effectiveSessionId ? { sessionId: effectiveSessionId } : {},
|
|
139131
|
+
...fallbackMessage ? { fallbackMessage } : {},
|
|
139085
139132
|
...body.chatSessionId ? { chatSessionId: body.chatSessionId } : {},
|
|
139086
139133
|
...body.workspace ? { workspace: body.workspace } : {},
|
|
139087
139134
|
...currentCompanyId !== void 0 ? { companyId: currentCompanyId } : {},
|
|
@@ -139291,8 +139338,8 @@ async function startOasisServer(opts) {
|
|
|
139291
139338
|
if (actorCtx) {
|
|
139292
139339
|
const { mkdtempSync: mkdtempSync5, mkdirSync: mkdirSync17, writeFileSync: writeFileSync15 } = await import("node:fs");
|
|
139293
139340
|
const { join: join24, dirname: dirname20 } = await import("node:path");
|
|
139294
|
-
const { tmpdir:
|
|
139295
|
-
const dir = mkdtempSync5(join24(
|
|
139341
|
+
const { tmpdir: tmpdir9 } = await import("node:os");
|
|
139342
|
+
const dir = mkdtempSync5(join24(tmpdir9(), "oasis-chat-"));
|
|
139296
139343
|
if (actorCtx.config?.prompt) {
|
|
139297
139344
|
for (const [rel, content] of Object.entries(splitIdentityFiles2(actorCtx.config.prompt))) {
|
|
139298
139345
|
const file = join24(dir, rel);
|
|
@@ -143591,6 +143638,7 @@ async function seedRoleCatalog(store, src) {
|
|
|
143591
143638
|
await store.put({
|
|
143592
143639
|
name,
|
|
143593
143640
|
label: known?.label ?? fallbackLabel(name),
|
|
143641
|
+
...known?.description ? { description: known.description } : {},
|
|
143594
143642
|
...known?.accent ? { appearance: { accent: known.accent } } : {},
|
|
143595
143643
|
status: "active"
|
|
143596
143644
|
});
|
|
@@ -143605,13 +143653,17 @@ var init_roles_seed = __esm({
|
|
|
143605
143653
|
"use strict";
|
|
143606
143654
|
KNOWN = {
|
|
143607
143655
|
founder: { label: "\u521B\u59CB\u4EBA", accent: "slate" },
|
|
143608
|
-
pm: { label: "\u9700\u6C42\u5206\u6790", accent: "blue" },
|
|
143609
|
-
architect: { label: "\u67B6\u6784\u8BBE\u8BA1", accent: "violet" },
|
|
143610
|
-
designer: { label: "\u754C\u9762\u8BBE\u8BA1", accent: "fuchsia" },
|
|
143611
|
-
research: { label: "\u5E02\u573A\u8C03\u7814", accent: "cyan" },
|
|
143612
|
-
dev: { label: "\u4EE3\u7801\u5B9E\u73B0", accent: "emerald" },
|
|
143613
|
-
qa: { label: "\u8D28\u91CF\u4FDD\u969C", accent: "rose" },
|
|
143614
|
-
devops: {
|
|
143656
|
+
pm: { label: "\u9700\u6C42\u5206\u6790", accent: "blue", description: "\u628A\u8BC9\u6C42\u62C6\u6210 PRD \u4E0E\u9A8C\u6536\u6807\u51C6\uFF0C\u505A\u4EA7\u54C1\u51B3\u7B56\u4E0E\u4F18\u5148\u7EA7\u3002" },
|
|
143657
|
+
architect: { label: "\u67B6\u6784\u8BBE\u8BA1", accent: "violet", description: "\u6280\u672F\u9009\u578B\u3001\u7CFB\u7EDF\u67B6\u6784\u3001\u63A5\u53E3\u5951\u7EA6\u3001ADR\uFF1B\u628A\u6280\u672F\u65B9\u6848\u843D\u6210\u53EF\u5B9E\u73B0\u7684\u51B3\u7B56\u3002" },
|
|
143658
|
+
designer: { label: "\u754C\u9762\u8BBE\u8BA1", accent: "fuchsia", description: "\u754C\u9762\u4E0E\u4EA4\u4E92\u8BBE\u8BA1\u3001\u8BBE\u8BA1\u7CFB\u7EDF\u4E0E\u89C6\u89C9\u89C4\u8303\u3002" },
|
|
143659
|
+
research: { label: "\u5E02\u573A\u8C03\u7814", accent: "cyan", description: "\u7ADE\u54C1\u3001\u5E02\u573A\u3001\u7528\u6237\u4E0E\u5B9A\u4EF7\u7B49\u8C03\u7814\u3002" },
|
|
143660
|
+
dev: { label: "\u4EE3\u7801\u5B9E\u73B0", accent: "emerald", description: "\u6309\u63A5\u53E3\u5951\u7EA6\u5B9E\u73B0\u524D\u540E\u7AEF\u4EE3\u7801\u3002" },
|
|
143661
|
+
qa: { label: "\u8D28\u91CF\u4FDD\u969C", accent: "rose", description: "\u6D4B\u8BD5\u89C4\u5212\u3001\u771F\u673A\u9A8C\u6536\u4E0E\u56DE\u5F52\uFF1B\u53D1\u73B0\u95EE\u9898\u56DE\u538B\u5BF9\u5E94\u4EA7\u51FA\u8282\u70B9\u3002" },
|
|
143662
|
+
devops: {
|
|
143663
|
+
label: "\u8FD0\u7EF4\u90E8\u7F72",
|
|
143664
|
+
accent: "amber",
|
|
143665
|
+
description: "\u5E73\u53F0\u5DE5\u7A0B\uFF1A\u4EE3\u7801\u4ED3\u5E93\u4F9B\u7ED9\uFF08\u5EFA\u4ED3\uFF09\u3001CI/CD \u6D41\u6C34\u7EBF\u4E0E GitHub Actions\u3001\u7EC4\u7EC7\u8D44\u4EA7\u53F0\u8D26\u7EF4\u62A4\uFF0C\u4EE5\u53CA\u771F\u5B9E\u90E8\u7F72\u4E0E\u8054\u8C03\uFF1B\u5176\u5B83\u73AF\u8282\u51FA\u73B0\u90E8\u7F72/\u8FD0\u7EF4\u7C7B\u95EE\u9898\u65F6\u515C\u5E95\u3002\u8D1F\u8D23 provision \u4E0E deploy \u4EA4\u4ED8\u7269\u7C7B\u578B\u3002"
|
|
143666
|
+
},
|
|
143615
143667
|
writer: { label: "\u6587\u6863\u64B0\u5199", accent: "slate" },
|
|
143616
143668
|
"design-lead": { label: "\u8BBE\u8BA1\u8D1F\u8D23\u4EBA", accent: "fuchsia" },
|
|
143617
143669
|
"eng-lead": { label: "\u6280\u672F\u8D1F\u8D23\u4EBA", accent: "violet" }
|
|
@@ -146742,6 +146794,17 @@ function materializeContext(resolvedDir, files) {
|
|
|
146742
146794
|
fs8.writeFileSync(f2, content);
|
|
146743
146795
|
}
|
|
146744
146796
|
}
|
|
146797
|
+
async function putVisibleUserTurn(base, fetchImpl, args) {
|
|
146798
|
+
const messageId = (0, import_node_crypto11.randomUUID)();
|
|
146799
|
+
await odApi(
|
|
146800
|
+
base,
|
|
146801
|
+
fetchImpl,
|
|
146802
|
+
"PUT",
|
|
146803
|
+
`/api/projects/${encodeURIComponent(args.boardKey)}/conversations/${encodeURIComponent(args.conversationId)}/messages/${messageId}`,
|
|
146804
|
+
{ id: messageId, role: "user", content: args.content }
|
|
146805
|
+
);
|
|
146806
|
+
return messageId;
|
|
146807
|
+
}
|
|
146745
146808
|
async function startDesignRun(base, fetchImpl, args) {
|
|
146746
146809
|
const created = await odApi(base, fetchImpl, "POST", "/api/runs", {
|
|
146747
146810
|
agentId: args.agentId,
|
|
@@ -146750,10 +146813,55 @@ async function startDesignRun(base, fetchImpl, args) {
|
|
|
146750
146813
|
assistantMessageId: (0, import_node_crypto11.randomUUID)(),
|
|
146751
146814
|
clientRequestId: (0, import_node_crypto11.randomUUID)(),
|
|
146752
146815
|
message: args.message,
|
|
146753
|
-
systemPrompt
|
|
146816
|
+
// 提案 design-conversational-driving 坑②:systemPrompt 从写死改为可选——缺省用引擎侧默认,
|
|
146817
|
+
// 让设计意图由驱动方每轮的话(message)表达,而非焊死一句。
|
|
146818
|
+
...args.systemPrompt !== void 0 ? { systemPrompt: args.systemPrompt } : {}
|
|
146754
146819
|
});
|
|
146755
146820
|
return created.runId;
|
|
146756
146821
|
}
|
|
146822
|
+
async function fetchResultPackage(base, fetchImpl, runId) {
|
|
146823
|
+
const body = await odApi(base, fetchImpl, "GET", `/api/runs/${encodeURIComponent(runId)}/result-package`);
|
|
146824
|
+
const artifacts = (body.artifacts ?? []).map((a) => ({
|
|
146825
|
+
path: a.path ?? a.file ?? "",
|
|
146826
|
+
kind: a.kind ?? null,
|
|
146827
|
+
title: a.title ?? null,
|
|
146828
|
+
status: a.status ?? null
|
|
146829
|
+
}));
|
|
146830
|
+
return { artifacts, fileCount: body.project?.fileCount ?? artifacts.length };
|
|
146831
|
+
}
|
|
146832
|
+
async function fetchBoardStatus(base, fetchImpl, artifactId) {
|
|
146833
|
+
const boardKey = deriveBoardKey(artifactId);
|
|
146834
|
+
let boardExists = true;
|
|
146835
|
+
let artifacts = [];
|
|
146836
|
+
try {
|
|
146837
|
+
const listing = await odApi(
|
|
146838
|
+
base,
|
|
146839
|
+
fetchImpl,
|
|
146840
|
+
"GET",
|
|
146841
|
+
`/api/projects/${encodeURIComponent(boardKey)}/files`
|
|
146842
|
+
);
|
|
146843
|
+
artifacts = (listing.files ?? []).filter((f2) => !f2.path.startsWith("task-context/") && f2.artifactManifest !== void 0).map((f2) => ({ path: f2.path, kind: f2.kind ?? null, status: f2.artifactManifest?.status ?? null, mtime: f2.mtime ?? null })).sort((a, b2) => (b2.mtime ?? 0) - (a.mtime ?? 0));
|
|
146844
|
+
} catch {
|
|
146845
|
+
boardExists = false;
|
|
146846
|
+
}
|
|
146847
|
+
let runs = [];
|
|
146848
|
+
if (boardExists) {
|
|
146849
|
+
try {
|
|
146850
|
+
const body = await odApi(
|
|
146851
|
+
base,
|
|
146852
|
+
fetchImpl,
|
|
146853
|
+
"GET",
|
|
146854
|
+
`/api/runs?projectId=${encodeURIComponent(boardKey)}`
|
|
146855
|
+
);
|
|
146856
|
+
runs = (body.runs ?? []).map((r) => ({
|
|
146857
|
+
runId: String(r["runId"] ?? r["id"] ?? ""),
|
|
146858
|
+
status: String(r["status"] ?? "unknown")
|
|
146859
|
+
}));
|
|
146860
|
+
} catch {
|
|
146861
|
+
}
|
|
146862
|
+
}
|
|
146863
|
+
return { boardKey, boardExists, runs, artifacts };
|
|
146864
|
+
}
|
|
146757
146865
|
async function pumpDesignEvents(base, fetchImpl, runId, onLine) {
|
|
146758
146866
|
const res = await fetchImpl(`${base}/api/runs/${runId}/events`);
|
|
146759
146867
|
if (!res.ok || !res.body) return;
|
|
@@ -146807,11 +146915,16 @@ async function harvestBoard(base, fetchImpl, publicBase, workRoot, boardKey, run
|
|
|
146807
146915
|
if (!res.ok) throw new Error(`od export ${rel} \u2192 ${res.status}`);
|
|
146808
146916
|
return await res.text();
|
|
146809
146917
|
};
|
|
146918
|
+
const fetchRaw = async (rel) => {
|
|
146919
|
+
const res = await fetchImpl(`${base}/api/projects/${encodeURIComponent(boardKey)}/raw/${rel.split("/").map(encodeURIComponent).join("/")}`);
|
|
146920
|
+
if (!res.ok) throw new Error(`od raw ${rel} \u2192 ${res.status}`);
|
|
146921
|
+
return await res.text();
|
|
146922
|
+
};
|
|
146810
146923
|
fs8.writeFileSync(path7.join(dir, "index.html"), await fetchInline(entry));
|
|
146811
146924
|
for (const f2 of listing.files ?? []) {
|
|
146812
146925
|
if (f2.path.endsWith(".md") && !f2.path.includes("/")) {
|
|
146813
146926
|
try {
|
|
146814
|
-
fs8.writeFileSync(path7.join(dir, f2.path), await
|
|
146927
|
+
fs8.writeFileSync(path7.join(dir, f2.path), await fetchRaw(f2.path));
|
|
146815
146928
|
} catch {
|
|
146816
146929
|
}
|
|
146817
146930
|
}
|
|
@@ -146837,7 +146950,7 @@ async function runOpenDesignSession(opts) {
|
|
|
146837
146950
|
boardKey,
|
|
146838
146951
|
conversationId,
|
|
146839
146952
|
message: opts.message,
|
|
146840
|
-
systemPrompt: opts.systemPrompt
|
|
146953
|
+
...opts.systemPrompt !== void 0 ? { systemPrompt: opts.systemPrompt } : {}
|
|
146841
146954
|
});
|
|
146842
146955
|
if (opts.onLine) void pumpDesignEvents(opts.base, fetchImpl, runId, opts.onLine).catch(() => {
|
|
146843
146956
|
});
|
|
@@ -146850,6 +146963,35 @@ async function runOpenDesignSession(opts) {
|
|
|
146850
146963
|
const { dir, entry } = await harvestBoard(opts.base, fetchImpl, opts.publicBase, workRoot, boardKey, runId);
|
|
146851
146964
|
return { dir, entry, boardKey, runId };
|
|
146852
146965
|
}
|
|
146966
|
+
async function startDesignChatTurn(opts) {
|
|
146967
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
146968
|
+
const boardKey = deriveBoardKey(opts.artifactId);
|
|
146969
|
+
const { conversationId, resolvedDir } = await ensureProject(opts.base, fetchImpl, boardKey, opts.title);
|
|
146970
|
+
if (opts.contextFiles) materializeContext(resolvedDir, opts.contextFiles);
|
|
146971
|
+
const userMessageId = await putVisibleUserTurn(opts.base, fetchImpl, { boardKey, conversationId, content: opts.message });
|
|
146972
|
+
const runId = await startDesignRun(opts.base, fetchImpl, {
|
|
146973
|
+
agentId: opts.agentId,
|
|
146974
|
+
boardKey,
|
|
146975
|
+
conversationId,
|
|
146976
|
+
message: opts.message,
|
|
146977
|
+
...opts.systemPrompt !== void 0 ? { systemPrompt: opts.systemPrompt } : {}
|
|
146978
|
+
});
|
|
146979
|
+
return { boardKey, conversationId, runId, userMessageId };
|
|
146980
|
+
}
|
|
146981
|
+
async function runDesignChatTurn(opts) {
|
|
146982
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
146983
|
+
const { boardKey, conversationId, runId, userMessageId } = await startDesignChatTurn(opts);
|
|
146984
|
+
if (opts.onLine) void pumpDesignEvents(opts.base, fetchImpl, runId, opts.onLine).catch(() => {
|
|
146985
|
+
});
|
|
146986
|
+
const status = await pollDesignRun(opts.base, fetchImpl, runId, {
|
|
146987
|
+
...opts.pollIntervalMs !== void 0 ? { intervalMs: opts.pollIntervalMs } : {},
|
|
146988
|
+
...opts.pollMaxMs !== void 0 ? { maxMs: opts.pollMaxMs } : {}
|
|
146989
|
+
});
|
|
146990
|
+
if (status === "canceled") throw new Error(`od run ${runId} \u88AB\u53D6\u6D88`);
|
|
146991
|
+
if (status === "failed") throw new Error(`od run ${runId} \u5931\u8D25`);
|
|
146992
|
+
const { artifacts, fileCount } = await fetchResultPackage(opts.base, fetchImpl, runId);
|
|
146993
|
+
return { boardKey, conversationId, runId, userMessageId, artifacts, fileCount };
|
|
146994
|
+
}
|
|
146853
146995
|
var import_node_crypto11, fs8, os, path7;
|
|
146854
146996
|
var init_driver = __esm({
|
|
146855
146997
|
"../adapters/src/open-design/driver.ts"() {
|
|
@@ -146892,6 +147034,25 @@ var init_sync_skills = __esm({
|
|
|
146892
147034
|
}
|
|
146893
147035
|
});
|
|
146894
147036
|
|
|
147037
|
+
// ../adapters/src/_core/resume-classify.ts
|
|
147038
|
+
function isSessionNotFoundError(text) {
|
|
147039
|
+
if (!text) return false;
|
|
147040
|
+
const t = text.toLowerCase();
|
|
147041
|
+
return SESSION_NOT_FOUND_PATTERNS.some((p2) => t.includes(p2));
|
|
147042
|
+
}
|
|
147043
|
+
var SESSION_NOT_FOUND_PATTERNS;
|
|
147044
|
+
var init_resume_classify = __esm({
|
|
147045
|
+
"../adapters/src/_core/resume-classify.ts"() {
|
|
147046
|
+
"use strict";
|
|
147047
|
+
SESSION_NOT_FOUND_PATTERNS = [
|
|
147048
|
+
"no conversation found",
|
|
147049
|
+
// claude: `claude --resume <缺失的 id>`
|
|
147050
|
+
"no rollout found for thread id"
|
|
147051
|
+
// codex: `codex exec resume <缺失的 uuid>`
|
|
147052
|
+
];
|
|
147053
|
+
}
|
|
147054
|
+
});
|
|
147055
|
+
|
|
146895
147056
|
// ../adapters/src/_core/session-paths.ts
|
|
146896
147057
|
function resolveWorkRoot(workRoot) {
|
|
146897
147058
|
if (workRoot) return workRoot;
|
|
@@ -147219,29 +147380,17 @@ function classifyExit(result) {
|
|
|
147219
147380
|
if (result.is_error === true || String(result.subtype ?? "").startsWith("error")) return "error";
|
|
147220
147381
|
return void 0;
|
|
147221
147382
|
}
|
|
147222
|
-
|
|
147223
|
-
const configDir = process.env["CLAUDE_CONFIG_DIR"] || path9.join(os3.homedir(), ".claude");
|
|
147224
|
-
const projectsDir = path9.join(configDir, "projects");
|
|
147225
|
-
const target = `${sessionId}.jsonl`;
|
|
147226
|
-
try {
|
|
147227
|
-
for (const proj of fs10.readdirSync(projectsDir)) {
|
|
147228
|
-
if (fs10.existsSync(path9.join(projectsDir, proj, target))) return true;
|
|
147229
|
-
}
|
|
147230
|
-
} catch {
|
|
147231
|
-
}
|
|
147232
|
-
return false;
|
|
147233
|
-
}
|
|
147234
|
-
var import_node_child_process7, import_node_crypto13, fs10, os3, path9, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
147383
|
+
var import_node_child_process7, import_node_crypto13, fs10, path9, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
147235
147384
|
var init_claude_code = __esm({
|
|
147236
147385
|
"../adapters/src/claude-code/index.ts"() {
|
|
147237
147386
|
"use strict";
|
|
147238
147387
|
import_node_child_process7 = require("node:child_process");
|
|
147239
147388
|
import_node_crypto13 = require("node:crypto");
|
|
147240
147389
|
fs10 = __toESM(require("node:fs"), 1);
|
|
147241
|
-
os3 = __toESM(require("node:os"), 1);
|
|
147242
147390
|
path9 = __toESM(require("node:path"), 1);
|
|
147243
147391
|
readline = __toESM(require("node:readline"), 1);
|
|
147244
147392
|
init_sync_skills();
|
|
147393
|
+
init_resume_classify();
|
|
147245
147394
|
init_session_paths();
|
|
147246
147395
|
ONE_SHOT_UNSAFE_TOOLS = ["ScheduleWakeup", "CronCreate", "CronDelete", "CronList"];
|
|
147247
147396
|
ClaudeCodeAdapter = class {
|
|
@@ -147315,8 +147464,7 @@ var init_claude_code = __esm({
|
|
|
147315
147464
|
const prompt = job.bundle.files["TASK.md"];
|
|
147316
147465
|
if (!prompt) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
147317
147466
|
const promptViaStdin = Buffer.byteLength(prompt, "utf8") > 1e5;
|
|
147318
|
-
const
|
|
147319
|
-
const runtimeSessionArgs = job.runtimeSessionId ? canResume ? ["--resume", job.runtimeSessionId] : ["--session-id", job.runtimeSessionId] : [];
|
|
147467
|
+
const runtimeSessionArgs = job.runtimeSessionId ? job.resumeRuntimeSession ? ["--resume", job.runtimeSessionId] : ["--session-id", job.runtimeSessionId] : [];
|
|
147320
147468
|
const oneShotSafety = this.opts.oneShotSafety !== false;
|
|
147321
147469
|
const args = [
|
|
147322
147470
|
"-p",
|
|
@@ -147441,7 +147589,12 @@ var init_claude_code = __esm({
|
|
|
147441
147589
|
child.on("exit", (code) => {
|
|
147442
147590
|
clearTimeout(timer);
|
|
147443
147591
|
if (exited) return;
|
|
147444
|
-
|
|
147592
|
+
let reason = killReason ?? classifyExit(lastResult);
|
|
147593
|
+
const resultErrors = Array.isArray(lastResult?.errors) ? lastResult.errors.map(String) : [];
|
|
147594
|
+
const resumeErrText = [stderrTail.join("\n"), String(lastResult?.result ?? ""), ...resultErrors].join("\n");
|
|
147595
|
+
if (!killReason && job.resumeRuntimeSession && reason !== "clean" && isSessionNotFoundError(resumeErrText)) {
|
|
147596
|
+
reason = "session-not-found";
|
|
147597
|
+
}
|
|
147445
147598
|
const workdirRef = dir;
|
|
147446
147599
|
const isOneShot = job.workdirKey ? false : !job.runtimeSessionId;
|
|
147447
147600
|
unlockWorkdir(dir);
|
|
@@ -147652,7 +147805,7 @@ var init_resilient = __esm({
|
|
|
147652
147805
|
|
|
147653
147806
|
// ../adapters/src/_core/skill-cache.ts
|
|
147654
147807
|
function defaultCacheRoot() {
|
|
147655
|
-
return path10.join(
|
|
147808
|
+
return path10.join(os3.homedir(), ".oasis", "skill-cache");
|
|
147656
147809
|
}
|
|
147657
147810
|
function sessionSkillsSubdir(runtimeKind) {
|
|
147658
147811
|
switch (runtimeKind) {
|
|
@@ -147895,12 +148048,12 @@ async function syncSessionSymlinks(sessionDir, runtimeKind, actorDir, manifest,
|
|
|
147895
148048
|
}
|
|
147896
148049
|
}
|
|
147897
148050
|
}
|
|
147898
|
-
var fsp,
|
|
148051
|
+
var fsp, os3, path10, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
|
|
147899
148052
|
var init_skill_cache = __esm({
|
|
147900
148053
|
"../adapters/src/_core/skill-cache.ts"() {
|
|
147901
148054
|
"use strict";
|
|
147902
148055
|
fsp = __toESM(require("node:fs/promises"), 1);
|
|
147903
|
-
|
|
148056
|
+
os3 = __toESM(require("node:os"), 1);
|
|
147904
148057
|
path10 = __toESM(require("node:path"), 1);
|
|
147905
148058
|
MANIFEST_SCHEMA_VERSION = 1;
|
|
147906
148059
|
STALE_LOCK_MS = 6e4;
|
|
@@ -148271,7 +148424,7 @@ function codexSessionsRoot() {
|
|
|
148271
148424
|
const candidates = [];
|
|
148272
148425
|
const ch = process.env["CODEX_HOME"];
|
|
148273
148426
|
if (ch) candidates.push(path11.join(ch, "sessions"));
|
|
148274
|
-
const home = process.env["HOME"] ||
|
|
148427
|
+
const home = process.env["HOME"] || os4.homedir();
|
|
148275
148428
|
if (home) candidates.push(path11.join(home, ".codex", "sessions"));
|
|
148276
148429
|
for (const c of candidates) {
|
|
148277
148430
|
try {
|
|
@@ -148281,31 +148434,6 @@ function codexSessionsRoot() {
|
|
|
148281
148434
|
}
|
|
148282
148435
|
return "";
|
|
148283
148436
|
}
|
|
148284
|
-
function codexRolloutExists(sessionId, root = codexSessionsRoot()) {
|
|
148285
|
-
if (!sessionId || !root) return false;
|
|
148286
|
-
const suffix = `-${sessionId}.jsonl`;
|
|
148287
|
-
let hit = false;
|
|
148288
|
-
const walk = (d) => {
|
|
148289
|
-
if (hit) return;
|
|
148290
|
-
let ents;
|
|
148291
|
-
try {
|
|
148292
|
-
ents = fs11.readdirSync(d, { withFileTypes: true });
|
|
148293
|
-
} catch {
|
|
148294
|
-
return;
|
|
148295
|
-
}
|
|
148296
|
-
for (const ent of ents) {
|
|
148297
|
-
if (hit) return;
|
|
148298
|
-
const p2 = path11.join(d, ent.name);
|
|
148299
|
-
if (ent.isDirectory()) walk(p2);
|
|
148300
|
-
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) {
|
|
148301
|
-
hit = true;
|
|
148302
|
-
return;
|
|
148303
|
-
}
|
|
148304
|
-
}
|
|
148305
|
-
};
|
|
148306
|
-
walk(root);
|
|
148307
|
-
return hit;
|
|
148308
|
-
}
|
|
148309
148437
|
function listRecentRollouts(root, sinceMs) {
|
|
148310
148438
|
const margin = sinceMs - 6e4;
|
|
148311
148439
|
const found = [];
|
|
@@ -148547,17 +148675,18 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
|
|
|
148547
148675
|
tool.output.push(line);
|
|
148548
148676
|
return [];
|
|
148549
148677
|
}
|
|
148550
|
-
var import_node_child_process9, import_node_crypto14, fs11,
|
|
148678
|
+
var import_node_child_process9, import_node_crypto14, fs11, os4, path11, readline2, CodexAdapter;
|
|
148551
148679
|
var init_codex = __esm({
|
|
148552
148680
|
"../adapters/src/codex/index.ts"() {
|
|
148553
148681
|
"use strict";
|
|
148554
148682
|
import_node_child_process9 = require("node:child_process");
|
|
148555
148683
|
import_node_crypto14 = require("node:crypto");
|
|
148556
148684
|
fs11 = __toESM(require("node:fs"), 1);
|
|
148557
|
-
|
|
148685
|
+
os4 = __toESM(require("node:os"), 1);
|
|
148558
148686
|
path11 = __toESM(require("node:path"), 1);
|
|
148559
148687
|
readline2 = __toESM(require("node:readline"), 1);
|
|
148560
148688
|
init_sync_skills();
|
|
148689
|
+
init_resume_classify();
|
|
148561
148690
|
init_session_paths();
|
|
148562
148691
|
init_claude_code();
|
|
148563
148692
|
CodexAdapter = class {
|
|
@@ -148606,9 +148735,7 @@ var init_codex = __esm({
|
|
|
148606
148735
|
const task = job.bundle.files["TASK.md"];
|
|
148607
148736
|
if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
148608
148737
|
const prompt = job.systemPrompt ? ["# System Prompt", job.systemPrompt, "", "# Task", task].join("\n") : task;
|
|
148609
|
-
const isResume = Boolean(
|
|
148610
|
-
job.resumeRuntimeSession && job.runtimeSessionId && codexRolloutExists(job.runtimeSessionId)
|
|
148611
|
-
);
|
|
148738
|
+
const isResume = Boolean(job.resumeRuntimeSession && job.runtimeSessionId);
|
|
148612
148739
|
const args = [
|
|
148613
148740
|
"exec",
|
|
148614
148741
|
"-C",
|
|
@@ -148744,7 +148871,8 @@ var init_codex = __esm({
|
|
|
148744
148871
|
const sawStreamError = streamErrorMessages.length > 0;
|
|
148745
148872
|
const isError = !killReason && (typeof code === "number" && code !== 0 || sawStreamError);
|
|
148746
148873
|
const errorMessage = isError ? [...streamErrorMessages, ...stdoutErrorLines, ...stderrTail].join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
148747
|
-
const
|
|
148874
|
+
const sessionNotFound = !killReason && isResume && isSessionNotFoundError([...streamErrorMessages, ...stdoutErrorLines, ...stderrTail].join("\n"));
|
|
148875
|
+
const reason = killReason ? killReason : sessionNotFound ? "session-not-found" : sawStreamError ? "error" : code === 0 ? "clean" : "error";
|
|
148748
148876
|
finish({
|
|
148749
148877
|
code: killReason ? null : code,
|
|
148750
148878
|
reason,
|
|
@@ -153560,7 +153688,44 @@ var init_node_health = __esm({
|
|
|
153560
153688
|
});
|
|
153561
153689
|
|
|
153562
153690
|
// ../server/src/domains/nodes/routes.ts
|
|
153691
|
+
function daemonVersionLess(a, b2) {
|
|
153692
|
+
if (!a || !b2 || a === "\u2014" || b2 === "\u2014") return false;
|
|
153693
|
+
const parse2 = (v2) => v2.replace(/^v/, "").split(".").map((x2) => Number.parseInt(x2, 10));
|
|
153694
|
+
const pa = parse2(a);
|
|
153695
|
+
const pb = parse2(b2);
|
|
153696
|
+
if (pa.some(Number.isNaN) || pb.some(Number.isNaN)) return a < b2;
|
|
153697
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
153698
|
+
const ai = pa[i] ?? 0;
|
|
153699
|
+
const bi = pb[i] ?? 0;
|
|
153700
|
+
if (ai !== bi) return ai < bi;
|
|
153701
|
+
}
|
|
153702
|
+
return false;
|
|
153703
|
+
}
|
|
153563
153704
|
function nodesDomain(deps) {
|
|
153705
|
+
async function resolveLatestDaemonVersion() {
|
|
153706
|
+
const envVer = (process.env["OASIS_LATEST_NODE_DAEMON_VERSION"] ?? "").trim();
|
|
153707
|
+
if (envVer) return { version: envVer, source: "env" };
|
|
153708
|
+
if (deps.fetchLatestNpmDaemonVersion) {
|
|
153709
|
+
try {
|
|
153710
|
+
const v2 = (await deps.fetchLatestNpmDaemonVersion())?.trim();
|
|
153711
|
+
if (v2) return { version: v2, source: "npm" };
|
|
153712
|
+
} catch {
|
|
153713
|
+
}
|
|
153714
|
+
}
|
|
153715
|
+
try {
|
|
153716
|
+
const here = (0, import_node_path10.dirname)((0, import_node_url3.fileURLToPath)(__esm_import_meta_url));
|
|
153717
|
+
for (const rel of ["../../../../node-daemon/package.json", "../../../../../node-daemon/package.json"]) {
|
|
153718
|
+
try {
|
|
153719
|
+
const raw = (0, import_node_fs7.readFileSync)((0, import_node_path10.resolve)(here, rel), "utf8");
|
|
153720
|
+
const pkg = JSON.parse(raw);
|
|
153721
|
+
if (pkg.version) return { version: pkg.version, source: "monorepo" };
|
|
153722
|
+
} catch {
|
|
153723
|
+
}
|
|
153724
|
+
}
|
|
153725
|
+
} catch {
|
|
153726
|
+
}
|
|
153727
|
+
return { version: null, source: null };
|
|
153728
|
+
}
|
|
153564
153729
|
let hubWired = false;
|
|
153565
153730
|
function wireHub(hub) {
|
|
153566
153731
|
if (hubWired) return;
|
|
@@ -153770,30 +153935,23 @@ function nodesDomain(deps) {
|
|
|
153770
153935
|
return { status: 200, body: { ok: true } };
|
|
153771
153936
|
});
|
|
153772
153937
|
router.get("/api/nodes/expected-daemon-version", async () => {
|
|
153773
|
-
|
|
153774
|
-
if (envVer) return { status: 200, body: { version: envVer, source: "env" } };
|
|
153775
|
-
try {
|
|
153776
|
-
const here = (0, import_node_path10.dirname)((0, import_node_url3.fileURLToPath)(__esm_import_meta_url));
|
|
153777
|
-
for (const rel of ["../../../../node-daemon/package.json", "../../../../../node-daemon/package.json"]) {
|
|
153778
|
-
try {
|
|
153779
|
-
const raw = (0, import_node_fs7.readFileSync)((0, import_node_path10.resolve)(here, rel), "utf8");
|
|
153780
|
-
const pkg = JSON.parse(raw);
|
|
153781
|
-
if (pkg.version) return { status: 200, body: { version: pkg.version, source: "monorepo" } };
|
|
153782
|
-
} catch {
|
|
153783
|
-
}
|
|
153784
|
-
}
|
|
153785
|
-
} catch {
|
|
153786
|
-
}
|
|
153787
|
-
return { status: 200, body: { version: null, source: null } };
|
|
153938
|
+
return { status: 200, body: await resolveLatestDaemonVersion() };
|
|
153788
153939
|
});
|
|
153789
153940
|
router.post("/api/nodes/:nodeId/update", async (req) => {
|
|
153790
153941
|
const nodeId = req.params["nodeId"];
|
|
153791
153942
|
if (!nodeId) return { status: 400, body: { error: "missing nodeId" } };
|
|
153792
153943
|
const hub = deps.getHub();
|
|
153793
153944
|
if (!hub) return { status: 503, body: { error: "node gateway \u672A\u5C31\u7EEA" } };
|
|
153945
|
+
const daemon = hub.connectedDaemons().find((d) => d.daemonId === nodeId);
|
|
153946
|
+
if (!daemon) return { status: 409, body: { error: `\u8282\u70B9 ${nodeId} \u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u65E0\u6CD5\u66F4\u65B0` } };
|
|
153947
|
+
const current = daemon.meta.daemonVersion;
|
|
153948
|
+
const { version: latest } = await resolveLatestDaemonVersion();
|
|
153949
|
+
if (latest && current && !daemonVersionLess(current, latest)) {
|
|
153950
|
+
return { status: 200, body: { ok: true, alreadyLatest: true, version: current } };
|
|
153951
|
+
}
|
|
153794
153952
|
const sent = hub.dispatch(nodeId, { type: "update" });
|
|
153795
153953
|
if (!sent) return { status: 409, body: { error: `\u8282\u70B9 ${nodeId} \u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u65E0\u6CD5\u66F4\u65B0` } };
|
|
153796
|
-
return { status: 200, body: { ok: true } };
|
|
153954
|
+
return { status: 200, body: { ok: true, alreadyLatest: false } };
|
|
153797
153955
|
});
|
|
153798
153956
|
router.delete("/api/runtimes/:runtimeId", async (req) => {
|
|
153799
153957
|
const runtimeId = req.params["runtimeId"];
|
|
@@ -164189,19 +164347,19 @@ var init_trajectory = __esm({
|
|
|
164189
164347
|
|
|
164190
164348
|
// src/index.ts
|
|
164191
164349
|
var fs26 = __toESM(require("node:fs"));
|
|
164192
|
-
var
|
|
164350
|
+
var os9 = __toESM(require("node:os"));
|
|
164193
164351
|
var path21 = __toESM(require("node:path"));
|
|
164194
164352
|
var import_node_child_process15 = require("node:child_process");
|
|
164195
164353
|
|
|
164196
164354
|
// ../cli/src/cli.ts
|
|
164197
164355
|
var fs25 = __toESM(require("node:fs"), 1);
|
|
164198
|
-
var
|
|
164356
|
+
var os8 = __toESM(require("node:os"), 1);
|
|
164199
164357
|
var path20 = __toESM(require("node:path"), 1);
|
|
164200
164358
|
var import_node_crypto31 = require("node:crypto");
|
|
164201
164359
|
|
|
164202
164360
|
// ../cli/src/serve.ts
|
|
164203
164361
|
var fs23 = __toESM(require("node:fs"), 1);
|
|
164204
|
-
var
|
|
164362
|
+
var os5 = __toESM(require("node:os"), 1);
|
|
164205
164363
|
var path18 = __toESM(require("node:path"), 1);
|
|
164206
164364
|
var import_node_crypto28 = require("node:crypto");
|
|
164207
164365
|
var import_node_url4 = require("node:url");
|
|
@@ -168088,6 +168246,62 @@ function refreshConnectorSkillsInBackground(dataDir, apply) {
|
|
|
168088
168246
|
})();
|
|
168089
168247
|
}
|
|
168090
168248
|
var SESSION_TOKEN_GRACE_MS = 15 * 6e4;
|
|
168249
|
+
function makeResumeRetryProxy(first, spawnFallback) {
|
|
168250
|
+
const outCbs = [];
|
|
168251
|
+
const telCbs = [];
|
|
168252
|
+
const outBuf = [];
|
|
168253
|
+
const telBuf = [];
|
|
168254
|
+
let sawOutput = false;
|
|
168255
|
+
let active = first;
|
|
168256
|
+
const fanOut = (chunk) => {
|
|
168257
|
+
if (outCbs.length) for (const cb of outCbs) cb(chunk);
|
|
168258
|
+
else outBuf.push(chunk);
|
|
168259
|
+
};
|
|
168260
|
+
const fanTel = (e) => {
|
|
168261
|
+
if (telCbs.length) for (const cb of telCbs) cb(e);
|
|
168262
|
+
else telBuf.push(e);
|
|
168263
|
+
};
|
|
168264
|
+
const wire = (s2) => {
|
|
168265
|
+
s2.onOutput((c) => {
|
|
168266
|
+
sawOutput = true;
|
|
168267
|
+
fanOut(c);
|
|
168268
|
+
});
|
|
168269
|
+
s2.onTelemetry?.((e) => fanTel(e));
|
|
168270
|
+
};
|
|
168271
|
+
wire(first);
|
|
168272
|
+
const isSessionNotFound = (err) => {
|
|
168273
|
+
const chatExit = err instanceof Error ? err.chatExit : void 0;
|
|
168274
|
+
return chatExit?.reason === "session-not-found";
|
|
168275
|
+
};
|
|
168276
|
+
const done = first.done.catch(async (err) => {
|
|
168277
|
+
if (sawOutput || !isSessionNotFound(err)) throw err;
|
|
168278
|
+
const second = await spawnFallback();
|
|
168279
|
+
active = second;
|
|
168280
|
+
wire(second);
|
|
168281
|
+
await second.done;
|
|
168282
|
+
});
|
|
168283
|
+
return {
|
|
168284
|
+
get id() {
|
|
168285
|
+
return active.id;
|
|
168286
|
+
},
|
|
168287
|
+
get runId() {
|
|
168288
|
+
return active.runId;
|
|
168289
|
+
},
|
|
168290
|
+
onOutput(cb) {
|
|
168291
|
+
for (const c of outBuf.splice(0)) cb(c);
|
|
168292
|
+
outCbs.push(cb);
|
|
168293
|
+
},
|
|
168294
|
+
onTelemetry(cb) {
|
|
168295
|
+
for (const e of telBuf.splice(0)) cb(e);
|
|
168296
|
+
telCbs.push(cb);
|
|
168297
|
+
},
|
|
168298
|
+
done,
|
|
168299
|
+
kill: () => active.kill?.() ?? Promise.resolve(),
|
|
168300
|
+
get nativeSessionId() {
|
|
168301
|
+
return active.nativeSessionId;
|
|
168302
|
+
}
|
|
168303
|
+
};
|
|
168304
|
+
}
|
|
168091
168305
|
function normalizeHttpBaseUrl(raw) {
|
|
168092
168306
|
const url = new URL(raw);
|
|
168093
168307
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
@@ -168111,13 +168325,37 @@ function apiUrlFromGatewayUrl(raw) {
|
|
|
168111
168325
|
return void 0;
|
|
168112
168326
|
}
|
|
168113
168327
|
}
|
|
168328
|
+
var NODE_DAEMON_PKG = "oasis_test";
|
|
168329
|
+
var NPM_LATEST_TTL_MS = 5 * 6e4;
|
|
168330
|
+
var npmLatestCache = null;
|
|
168331
|
+
async function fetchLatestNpmDaemonVersion() {
|
|
168332
|
+
if (npmLatestCache && Date.now() - npmLatestCache.atMs < NPM_LATEST_TTL_MS) return npmLatestCache.version;
|
|
168333
|
+
let version2 = null;
|
|
168334
|
+
try {
|
|
168335
|
+
const ctrl = new AbortController();
|
|
168336
|
+
const timer = setTimeout(() => ctrl.abort(), 3e3);
|
|
168337
|
+
try {
|
|
168338
|
+
const resp = await fetch(`https://registry.npmjs.org/${NODE_DAEMON_PKG}/latest`, { signal: ctrl.signal });
|
|
168339
|
+
if (resp.ok) {
|
|
168340
|
+
const body = await resp.json();
|
|
168341
|
+
version2 = typeof body.version === "string" ? body.version : null;
|
|
168342
|
+
}
|
|
168343
|
+
} finally {
|
|
168344
|
+
clearTimeout(timer);
|
|
168345
|
+
}
|
|
168346
|
+
} catch {
|
|
168347
|
+
version2 = null;
|
|
168348
|
+
}
|
|
168349
|
+
if (version2) npmLatestCache = { version: version2, atMs: Date.now() };
|
|
168350
|
+
return version2;
|
|
168351
|
+
}
|
|
168114
168352
|
var oasisWrapperCache;
|
|
168115
168353
|
function oasisWrapperScript() {
|
|
168116
168354
|
if (oasisWrapperCache && fs23.existsSync(oasisWrapperCache)) return oasisWrapperCache;
|
|
168117
168355
|
const repoRoot = (0, import_node_url4.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
168118
168356
|
const tsx = path18.join(repoRoot, "node_modules/.bin/tsx");
|
|
168119
168357
|
const main = path18.join(repoRoot, "packages/cli/src/main.ts");
|
|
168120
|
-
const dir = fs23.mkdtempSync(path18.join(
|
|
168358
|
+
const dir = fs23.mkdtempSync(path18.join(os5.tmpdir(), "oasis-cli-"));
|
|
168121
168359
|
const wrapper = path18.join(dir, "oasis");
|
|
168122
168360
|
fs23.writeFileSync(wrapper, `#!/usr/bin/env bash
|
|
168123
168361
|
exec ${JSON.stringify(tsx)} ${JSON.stringify(main)} "$@"
|
|
@@ -168328,7 +168566,7 @@ async function startServe(opts) {
|
|
|
168328
168566
|
`[serve] \u8FD4\u5DE5\u6CE2\u7A33\u5B9A\u524D\u6CBF\uFF08rework-wavefront\uFF09\uFF1A${reworkWavefront ? "\u5DF2\u542F\u7528\uFF08\u9ED8\u8BA4\uFF09" : `\u26A0 \u5DF2\u88AB OASIS_REWORK_WAVEFRONT=${process.env.OASIS_REWORK_WAVEFRONT} \u663E\u5F0F\u5173\u95ED \u2014\u2014 \u56DE\u9000\u73B0\u72B6\u884C\u4E3A\uFF0C\u7B49\u7A33\u95E8/\u7B2C7\u9501/\u4E0A\u6E38\u5B88\u536B\u5168\u90E8\u4E0D\u751F\u6548`}`
|
|
168329
168567
|
);
|
|
168330
168568
|
const issuer = createTokenIssuer({ secretFile: path18.join(opts.dir, "session-token-secret") });
|
|
168331
|
-
const operatorActor = `actor:human:${
|
|
168569
|
+
const operatorActor = `actor:human:${os5.userInfo().username}`;
|
|
168332
168570
|
const operatorToken = issuer.issue(operatorActor);
|
|
168333
168571
|
fs23.writeFileSync(path18.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
|
|
168334
168572
|
let nodeTokens = createNodeTokenStore(path18.join(opts.dir, "node-tokens.json"));
|
|
@@ -168814,7 +169052,8 @@ async function startServe(opts) {
|
|
|
168814
169052
|
gatewayUrl: opts.gatewayUrl ?? `ws://127.0.0.1:${opts.port ?? 7320}/node-gateway`,
|
|
168815
169053
|
repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git",
|
|
168816
169054
|
nodeHealth,
|
|
168817
|
-
activeRunCountOf
|
|
169055
|
+
activeRunCountOf,
|
|
169056
|
+
fetchLatestNpmDaemonVersion
|
|
168818
169057
|
}),
|
|
168819
169058
|
collabDomain({
|
|
168820
169059
|
kernel,
|
|
@@ -168893,301 +169132,309 @@ async function startServe(opts) {
|
|
|
168893
169132
|
discussSessions: new FileSideMap(path18.join(opts.dir, "discuss-sessions.json")),
|
|
168894
169133
|
escalateDiscussRetain: new FileSideMap(path18.join(opts.dir, "escalate-discuss-retain.json")),
|
|
168895
169134
|
// 切片 2b:代署 escalate 发起会话保留(落盘)
|
|
168896
|
-
dispatchChat: async (
|
|
168897
|
-
const
|
|
168898
|
-
|
|
168899
|
-
|
|
168900
|
-
|
|
168901
|
-
|
|
168902
|
-
|
|
168903
|
-
|
|
168904
|
-
|
|
168905
|
-
|
|
168906
|
-
|
|
168907
|
-
|
|
168908
|
-
|
|
168909
|
-
|
|
168910
|
-
|
|
168911
|
-
|
|
168912
|
-
|
|
168913
|
-
|
|
168914
|
-
|
|
168915
|
-
|
|
168916
|
-
|
|
168917
|
-
|
|
168918
|
-
|
|
168919
|
-
|
|
168920
|
-
|
|
168921
|
-
|
|
168922
|
-
|
|
168923
|
-
|
|
168924
|
-
|
|
168925
|
-
|
|
168926
|
-
|
|
168927
|
-
|
|
168928
|
-
|
|
168929
|
-
|
|
168930
|
-
|
|
168931
|
-
|
|
168932
|
-
|
|
168933
|
-
|
|
168934
|
-
|
|
168935
|
-
|
|
168936
|
-
|
|
168937
|
-
|
|
168938
|
-
|
|
168939
|
-
|
|
168940
|
-
|
|
168941
|
-
|
|
168942
|
-
|
|
168943
|
-
|
|
168944
|
-
|
|
168945
|
-
|
|
168946
|
-
|
|
168947
|
-
|
|
168948
|
-
|
|
168949
|
-
|
|
168950
|
-
|
|
168951
|
-
|
|
168952
|
-
|
|
168953
|
-
|
|
168954
|
-
|
|
168955
|
-
|
|
168956
|
-
|
|
168957
|
-
|
|
168958
|
-
|
|
168959
|
-
|
|
168960
|
-
|
|
168961
|
-
|
|
168962
|
-
|
|
168963
|
-
|
|
168964
|
-
|
|
168965
|
-
|
|
168966
|
-
|
|
168967
|
-
|
|
168968
|
-
|
|
168969
|
-
|
|
168970
|
-
traceEnabled = false;
|
|
168971
|
-
console.warn(`[trace] chat run create failed: ${String(err)}`);
|
|
168972
|
-
});
|
|
168973
|
-
const enqueueTrace = (step) => {
|
|
168974
|
-
if (!traceEnabled) return;
|
|
168975
|
-
traceChain = traceChain.then(async () => {
|
|
168976
|
-
if (traceEnabled) await step();
|
|
169135
|
+
dispatchChat: async (chatReq) => {
|
|
169136
|
+
const dispatchChatImpl = async ({ actorId, message, sessionId, chatSessionId, attachments, workspace, companyId }) => {
|
|
169137
|
+
const runCompanyId = companyId ?? defaultCompanyId;
|
|
169138
|
+
const actorCtxForCompany = await actors.resolveCtx(runCompanyId);
|
|
169139
|
+
const actorService = actorCtxForCompany.service;
|
|
169140
|
+
const binding = await actorService.resolveBinding()(actorId);
|
|
169141
|
+
if (!binding) {
|
|
169142
|
+
throw new ApiError(409, "ACTOR_BINDING_MISSING", `\u6570\u5B57\u5458\u5DE5 ${actorId} \u6CA1\u6709 active runtime \u7ED1\u5B9A`);
|
|
169143
|
+
}
|
|
169144
|
+
const node = hub?.connectedDaemons().find((d) => d.daemonId === binding.nodeId);
|
|
169145
|
+
if (!node) {
|
|
169146
|
+
throw new ApiError(409, "NODE_OFFLINE", `\u7ED1\u5B9A\u8282\u70B9 ${binding.nodeId} \u5F53\u524D\u4E0D\u5728\u7EBF`);
|
|
169147
|
+
}
|
|
169148
|
+
if (!node.meta.adapters.includes(binding.runtimeKind)) {
|
|
169149
|
+
throw new ApiError(409, "RUNTIME_UNAVAILABLE", `\u8282\u70B9 ${binding.nodeId} \u672A\u4E0A\u62A5\u8FD0\u884C\u65F6 ${binding.runtimeKind}`);
|
|
169150
|
+
}
|
|
169151
|
+
if (!chatRemoteAdapter) {
|
|
169152
|
+
throw new ApiError(503, "NODE_GATEWAY_NOT_READY", "node-gateway \u5C1A\u672A\u5C31\u7EEA");
|
|
169153
|
+
}
|
|
169154
|
+
if (!localUrl) {
|
|
169155
|
+
throw new ApiError(503, "SERVER_URL_NOT_READY", "server URL \u5C1A\u672A\u5C31\u7EEA");
|
|
169156
|
+
}
|
|
169157
|
+
const priorChatSession = chatSessionId ? await chatSessionStore?.getSession(chatSessionId).catch(() => null) : null;
|
|
169158
|
+
const freshChatWorkdir = chatSessionId ? chatNodeChanged(
|
|
169159
|
+
{ nodeId: priorChatSession?.runtimeId, runtimeKind: priorChatSession?.runtimeKind },
|
|
169160
|
+
{ nodeId: binding.nodeId, runtimeKind: binding.runtimeKind }
|
|
169161
|
+
) : false;
|
|
169162
|
+
const runtimeSessionId = sessionId ?? (0, import_node_crypto28.randomUUID)();
|
|
169163
|
+
const resumeRuntimeSession = Boolean(sessionId);
|
|
169164
|
+
const traceRunId = `chat-run:${(0, import_node_crypto28.randomUUID)()}`;
|
|
169165
|
+
const artifactId = `artifact:chat:${(0, import_node_crypto28.randomUUID)()}`;
|
|
169166
|
+
const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
169167
|
+
let traceSeq = 0;
|
|
169168
|
+
let lastProgressTouchMs = 0;
|
|
169169
|
+
const PROGRESS_TOUCH_THROTTLE_MS2 = 2e4;
|
|
169170
|
+
let traceEnabled = true;
|
|
169171
|
+
const analyzedRunId = chatSessionId ? (await chatSessionStore.getSession(chatSessionId).catch(() => null))?.analyzedRunId ?? void 0 : void 0;
|
|
169172
|
+
let traceChain = traceStore.createRun({
|
|
169173
|
+
id: traceRunId,
|
|
169174
|
+
actorId,
|
|
169175
|
+
runtimeKind: traceRuntimeKind(binding.runtimeKind),
|
|
169176
|
+
runtimeInstanceId: `runtime:${binding.nodeId}:${binding.runtimeKind}`,
|
|
169177
|
+
triggerKind: "api",
|
|
169178
|
+
triggerRef: runtimeSessionId,
|
|
169179
|
+
jobKey: runtimeSessionId,
|
|
169180
|
+
artifactId,
|
|
169181
|
+
action: "chat",
|
|
169182
|
+
startedAt: traceStartedAt,
|
|
169183
|
+
metadata: {
|
|
169184
|
+
runtimeSessionId,
|
|
169185
|
+
nodeId: binding.nodeId,
|
|
169186
|
+
runtimeKind: binding.runtimeKind,
|
|
169187
|
+
messagePreview: message.slice(0, 500),
|
|
169188
|
+
...analyzedRunId ? { analyzedRunId } : {}
|
|
169189
|
+
}
|
|
169190
|
+
}).then(async () => {
|
|
169191
|
+
await traceStore.appendEvents(traceRunId, [
|
|
169192
|
+
{
|
|
169193
|
+
seq: ++traceSeq,
|
|
169194
|
+
eventType: "run.started",
|
|
169195
|
+
stream: "runtime",
|
|
169196
|
+
message: `chat ${actorId}`,
|
|
169197
|
+
startedAt: traceStartedAt
|
|
169198
|
+
},
|
|
169199
|
+
{
|
|
169200
|
+
seq: ++traceSeq,
|
|
169201
|
+
eventType: "input.message",
|
|
169202
|
+
stream: "model",
|
|
169203
|
+
actorId,
|
|
169204
|
+
message: message.slice(0, 500),
|
|
169205
|
+
payload: { text: message },
|
|
169206
|
+
startedAt: traceStartedAt
|
|
169207
|
+
}
|
|
169208
|
+
]);
|
|
168977
169209
|
}).catch((err) => {
|
|
168978
169210
|
traceEnabled = false;
|
|
168979
|
-
console.warn(`[trace] chat run
|
|
169211
|
+
console.warn(`[trace] chat run create failed: ${String(err)}`);
|
|
168980
169212
|
});
|
|
168981
|
-
|
|
168982
|
-
|
|
168983
|
-
|
|
168984
|
-
|
|
168985
|
-
|
|
168986
|
-
|
|
168987
|
-
|
|
168988
|
-
|
|
168989
|
-
|
|
168990
|
-
|
|
168991
|
-
|
|
168992
|
-
|
|
168993
|
-
|
|
168994
|
-
|
|
168995
|
-
|
|
168996
|
-
|
|
168997
|
-
|
|
168998
|
-
|
|
168999
|
-
|
|
169000
|
-
|
|
169001
|
-
|
|
169002
|
-
|
|
169003
|
-
|
|
169004
|
-
|
|
169005
|
-
|
|
169006
|
-
|
|
169213
|
+
const enqueueTrace = (step) => {
|
|
169214
|
+
if (!traceEnabled) return;
|
|
169215
|
+
traceChain = traceChain.then(async () => {
|
|
169216
|
+
if (traceEnabled) await step();
|
|
169217
|
+
}).catch((err) => {
|
|
169218
|
+
traceEnabled = false;
|
|
169219
|
+
console.warn(`[trace] chat run ${traceRunId} failed: ${String(err)}`);
|
|
169220
|
+
});
|
|
169221
|
+
};
|
|
169222
|
+
const provision = await buildActorProvision(actorService, actorId);
|
|
169223
|
+
const actorCtx = await buildActorContext(actorService, actorId).catch(() => null);
|
|
169224
|
+
const chatResolvedModel = (() => {
|
|
169225
|
+
if (actorCtx?.config?.model) return actorCtx.config.model;
|
|
169226
|
+
return void 0;
|
|
169227
|
+
})();
|
|
169228
|
+
const chatModel = chatResolvedModel ?? await registryStore.getRuntimeConfig(`runtime:${binding.nodeId}:${binding.runtimeKind}`).then((c) => c?.model).catch(() => void 0) ?? void 0;
|
|
169229
|
+
const chatModelSource = chatResolvedModel ? "actor_config" : chatModel ? "runtime_default" : null;
|
|
169230
|
+
const attachmentFiles = {};
|
|
169231
|
+
const attachmentBinary = {};
|
|
169232
|
+
const attachmentPaths = [];
|
|
169233
|
+
const usedRel = /* @__PURE__ */ new Set();
|
|
169234
|
+
for (const att of attachments ?? []) {
|
|
169235
|
+
const safe = (att.name || "attachment").replace(/[^\w.\-]+/g, "_").replace(/^\.+/, "").slice(0, 80) || "attachment";
|
|
169236
|
+
let rel = `inputs/attachments/${safe}`;
|
|
169237
|
+
let n = 1;
|
|
169238
|
+
while (usedRel.has(rel)) rel = `inputs/attachments/${n++}-${safe}`;
|
|
169239
|
+
usedRel.add(rel);
|
|
169240
|
+
if (typeof att.text === "string") {
|
|
169241
|
+
attachmentFiles[rel] = att.text;
|
|
169007
169242
|
attachmentPaths.push(rel);
|
|
169008
|
-
}
|
|
169009
|
-
|
|
169010
|
-
|
|
169011
|
-
|
|
169012
|
-
|
|
169013
|
-
|
|
169014
|
-
|
|
169015
|
-
|
|
169016
|
-
|
|
169017
|
-
|
|
169018
|
-
`
|
|
169019
|
-
|
|
169020
|
-
|
|
169021
|
-
CONVERSATIONAL_MANAGER_BODY
|
|
169022
|
-
] : [
|
|
169023
|
-
"# \u5373\u65F6\u8111\u66B4\u5BF9\u8BDD",
|
|
169024
|
-
"",
|
|
169025
|
-
sessionLine,
|
|
169026
|
-
`actor_id: ${actorId}`,
|
|
169027
|
-
"",
|
|
169028
|
-
"\u8BF7\u76F4\u63A5\u56DE\u7B54\u7528\u6237\u95EE\u9898\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u5199\u5165\u7CFB\u7EDF\uFF0C\u5426\u5219\u4E0D\u8981\u521B\u5EFA\u6216\u4FEE\u6539 artifact\u3002"
|
|
169029
|
-
];
|
|
169030
|
-
const files = {
|
|
169031
|
-
"TASK.md": [
|
|
169032
|
-
...taskHeader,
|
|
169033
|
-
...attachmentPaths.length ? ["", "## \u7528\u6237\u9644\u4EF6", "", "\u7528\u6237\u968F\u6D88\u606F\u9644\u5E26\u4E86\u4EE5\u4E0B\u6587\u4EF6\uFF08\u5728\u4F60\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0B\uFF0C\u53EF\u76F4\u63A5\u8BFB\u53D6\uFF09\uFF1A", ...attachmentPaths.map((p2) => `- ${p2}`)] : [],
|
|
169243
|
+
} else if (att.blobRef) {
|
|
169244
|
+
try {
|
|
169245
|
+
const bytes = await assets.get(att.blobRef);
|
|
169246
|
+
attachmentBinary[rel] = Buffer.from(bytes).toString("base64");
|
|
169247
|
+
attachmentPaths.push(rel);
|
|
169248
|
+
} catch (err) {
|
|
169249
|
+
console.warn(`[chat] \u9644\u4EF6 blob ${att.blobRef} \u8BFB\u53D6\u5931\u8D25: ${String(err)}`);
|
|
169250
|
+
}
|
|
169251
|
+
}
|
|
169252
|
+
}
|
|
169253
|
+
const sessionLine = chatSessionId ? `chat_session_id: ${chatSessionId}` : `runtime_session_id: ${runtimeSessionId}`;
|
|
169254
|
+
const taskHeader = workspace ? [
|
|
169255
|
+
"# \u4E0E\u5DE5\u5355\u7BA1\u7406\u8005\u5BF9\u8BDD",
|
|
169034
169256
|
"",
|
|
169035
|
-
|
|
169257
|
+
sessionLine,
|
|
169258
|
+
`actor_id: ${actorId}`,
|
|
169259
|
+
`workspace: ${workspace}`,
|
|
169036
169260
|
"",
|
|
169037
|
-
|
|
169038
|
-
]
|
|
169039
|
-
|
|
169040
|
-
|
|
169041
|
-
|
|
169042
|
-
|
|
169043
|
-
|
|
169044
|
-
|
|
169045
|
-
|
|
169046
|
-
|
|
169047
|
-
|
|
169048
|
-
|
|
169049
|
-
|
|
169050
|
-
|
|
169051
|
-
|
|
169052
|
-
|
|
169053
|
-
|
|
169054
|
-
|
|
169055
|
-
|
|
169056
|
-
|
|
169057
|
-
|
|
169058
|
-
|
|
169059
|
-
|
|
169060
|
-
|
|
169061
|
-
|
|
169062
|
-
|
|
169063
|
-
|
|
169064
|
-
|
|
169065
|
-
|
|
169066
|
-
|
|
169067
|
-
|
|
169068
|
-
|
|
169069
|
-
|
|
169070
|
-
|
|
169071
|
-
|
|
169072
|
-
|
|
169073
|
-
|
|
169074
|
-
|
|
169075
|
-
|
|
169076
|
-
|
|
169077
|
-
|
|
169078
|
-
|
|
169079
|
-
|
|
169080
|
-
|
|
169081
|
-
|
|
169082
|
-
|
|
169083
|
-
|
|
169084
|
-
|
|
169085
|
-
|
|
169086
|
-
|
|
169087
|
-
|
|
169088
|
-
|
|
169089
|
-
|
|
169090
|
-
|
|
169091
|
-
|
|
169092
|
-
|
|
169093
|
-
|
|
169094
|
-
|
|
169095
|
-
|
|
169096
|
-
|
|
169097
|
-
|
|
169098
|
-
|
|
169099
|
-
|
|
169100
|
-
|
|
169101
|
-
|
|
169102
|
-
|
|
169103
|
-
|
|
169104
|
-
|
|
169105
|
-
|
|
169106
|
-
|
|
169107
|
-
|
|
169261
|
+
CONVERSATIONAL_MANAGER_BODY
|
|
169262
|
+
] : [
|
|
169263
|
+
"# \u5373\u65F6\u8111\u66B4\u5BF9\u8BDD",
|
|
169264
|
+
"",
|
|
169265
|
+
sessionLine,
|
|
169266
|
+
`actor_id: ${actorId}`,
|
|
169267
|
+
"",
|
|
169268
|
+
"\u8BF7\u76F4\u63A5\u56DE\u7B54\u7528\u6237\u95EE\u9898\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u5199\u5165\u7CFB\u7EDF\uFF0C\u5426\u5219\u4E0D\u8981\u521B\u5EFA\u6216\u4FEE\u6539 artifact\u3002"
|
|
169269
|
+
];
|
|
169270
|
+
const files = {
|
|
169271
|
+
"TASK.md": [
|
|
169272
|
+
...taskHeader,
|
|
169273
|
+
...attachmentPaths.length ? ["", "## \u7528\u6237\u9644\u4EF6", "", "\u7528\u6237\u968F\u6D88\u606F\u9644\u5E26\u4E86\u4EE5\u4E0B\u6587\u4EF6\uFF08\u5728\u4F60\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0B\uFF0C\u53EF\u76F4\u63A5\u8BFB\u53D6\uFF09\uFF1A", ...attachmentPaths.map((p2) => `- ${p2}`)] : [],
|
|
169274
|
+
"",
|
|
169275
|
+
"## \u7528\u6237\u6D88\u606F",
|
|
169276
|
+
"",
|
|
169277
|
+
message
|
|
169278
|
+
].join("\n")
|
|
169279
|
+
};
|
|
169280
|
+
Object.assign(files, attachmentFiles);
|
|
169281
|
+
if (actorCtx?.config?.prompt) {
|
|
169282
|
+
Object.assign(files, splitIdentityFiles3(actorCtx.config.prompt));
|
|
169283
|
+
}
|
|
169284
|
+
if (!SKILL_CACHE_RUNTIMES.has(binding.runtimeKind)) {
|
|
169285
|
+
Object.assign(files, materializeBuiltins(builtinSkills, binding.runtimeKind));
|
|
169286
|
+
Object.assign(files, await materializeSkillFiles({
|
|
169287
|
+
service: actorService,
|
|
169288
|
+
actorId,
|
|
169289
|
+
runtimeKind: binding.runtimeKind
|
|
169290
|
+
}).catch((err) => {
|
|
169291
|
+
console.warn(`[chat] skill materialize failed for ${actorId}: ${String(err)}`);
|
|
169292
|
+
return {};
|
|
169293
|
+
}));
|
|
169294
|
+
}
|
|
169295
|
+
const limits = { wallClockMs: SESSION_WALL_CLOCK_MS.chat };
|
|
169296
|
+
const handle = await chatRemoteAdapter.spawn({
|
|
169297
|
+
actor: actorId,
|
|
169298
|
+
actorToken: issueSessionToken(actorId, { artifactId, action: "chat", limits, binding, sessionId: runtimeSessionId, companyId: runCompanyId, ...chatSessionId !== void 0 ? { chatSessionId } : {} }),
|
|
169299
|
+
artifactId,
|
|
169300
|
+
bundle: { files, ...Object.keys(attachmentBinary).length ? { binaryFiles: attachmentBinary } : {} },
|
|
169301
|
+
...actorCtx?.config?.prompt ? { systemPrompt: actorCtx.config.prompt } : {},
|
|
169302
|
+
...chatModel ? { model: chatModel } : {},
|
|
169303
|
+
// ADR-0053 D1:chat 的**会话线 id 是 chatSessionId**(Oasis 命名空间、跨轮不变),不是 rtId
|
|
169304
|
+
// (rtId 跨轮会变:换节点时服务端主动清掉它、codex/ACP 还会自己另分配)。
|
|
169305
|
+
//
|
|
169306
|
+
// 没有 chatSessionId → **不给 workdirKey** → 落 one-shot,这是契约的直接应用而不是折中:
|
|
169307
|
+
// 服务端对这种请求也不落库消息(persistTarget 要求 chatSessionId),没有会话线、没有历史,
|
|
169308
|
+
// 本就没什么可续的。产品路径跑不到这条分支(前端三个调用方都保证先建会话再传),只兜住
|
|
169309
|
+
// 裸 API 调用。
|
|
169310
|
+
...chatSessionId ? { workdirKey: `chat:${chatSessionId}` } : {},
|
|
169311
|
+
// 与上一条成对:稳定目录一上,A→B→A 回到 node1 就会撞见同名目录里 A 自己 N 轮前的陈旧
|
|
169312
|
+
// 文件(而注入的历史正告诉它「B 改了 X」)。切根前没这问题纯属侥幸——那时换节点会清掉
|
|
169313
|
+
// rtId、rtId 又是目录名,"新目录"是副产品;稳定目录一上,侥幸就没了。
|
|
169314
|
+
//
|
|
169315
|
+
// **在这儿算,不放进 ChatDispatchRequest**:本函数是唯一同时握着 binding 与 chatSessionId
|
|
169316
|
+
// 的地方,四个调用方(/api/chat、discuss、飞书入站、草案评审通知)全覆盖且谁都不用记得
|
|
169317
|
+
// 传。放进契约就等于要求每个调用方自己算,而其中三个压根不碰 binding。
|
|
169318
|
+
...freshChatWorkdir ? { freshWorkdir: true } : {},
|
|
169319
|
+
runtimeSessionId,
|
|
169320
|
+
resumeRuntimeSession,
|
|
169321
|
+
server: { url: serverUrlForBinding(binding) },
|
|
169322
|
+
binding,
|
|
169323
|
+
limits,
|
|
169324
|
+
// OASIS_STAGE=1:chat agent 的改图命令(edit/link/spawn/cancel)经 /api/stage → 草案路由
|
|
169325
|
+
// (建单/改图暂存统一,见 docs/proposals/draft-edit-unification.md)。
|
|
169326
|
+
// OASIS_WORKSPACE:给定工单(协调者对话)时绑上——staged 编辑的 type:title 在本工单范围解析,
|
|
169327
|
+
// 产出的草案 plan.workspace = 本工单,前端「待确认变更」按工单过滤才抓得到。普通脑暴不传,保持不绑。
|
|
169328
|
+
env: {
|
|
169329
|
+
...provision.env,
|
|
169330
|
+
OASIS_STAGE: "1",
|
|
169331
|
+
...chatSessionId ? { OASIS_CHAT_SESSION_ID: chatSessionId } : {},
|
|
169332
|
+
...workspace ? { OASIS_WORKSPACE: workspace } : {}
|
|
169333
|
+
},
|
|
169334
|
+
wrapperPaths: provision.wrapperPaths,
|
|
169335
|
+
...provision.requiredTools.length > 0 ? { requiredTools: provision.requiredTools } : {}
|
|
169108
169336
|
});
|
|
169109
|
-
|
|
169110
|
-
|
|
169111
|
-
|
|
169112
|
-
|
|
169113
|
-
|
|
169114
|
-
|
|
169115
|
-
|
|
169116
|
-
|
|
169117
|
-
|
|
169118
|
-
|
|
169119
|
-
|
|
169120
|
-
|
|
169121
|
-
|
|
169122
|
-
|
|
169123
|
-
|
|
169124
|
-
|
|
169125
|
-
|
|
169337
|
+
const chatJobKey = `chat::${artifactId}`;
|
|
169338
|
+
chatLiveSessions.set(chatJobKey, { artifactId, sessionId: traceRunId, dispatchId: handle.id, kill: () => handle.kill() });
|
|
169339
|
+
enqueueTrace(async () => {
|
|
169340
|
+
const run = await traceStore.getRun(traceRunId);
|
|
169341
|
+
if (!run) return;
|
|
169342
|
+
const base = run.metadata && typeof run.metadata === "object" && !Array.isArray(run.metadata) ? run.metadata : {};
|
|
169343
|
+
await traceStore.updateRun(traceRunId, {
|
|
169344
|
+
metadata: { ...base, dispatchId: handle.id },
|
|
169345
|
+
// 恢复路径拿不到 dispatchChat 闭包里的 fallback 解析结果,开跑时先写进账本;退出帧若上报
|
|
169346
|
+
// 更精确 model 仍会覆盖为 runtime 来源。
|
|
169347
|
+
...chatModel ? { effectiveModel: chatModel, modelSource: chatModelSource } : {}
|
|
169348
|
+
});
|
|
169349
|
+
});
|
|
169350
|
+
const buffered = [];
|
|
169351
|
+
const bufferedTelemetry = [];
|
|
169352
|
+
const outputCbs = [];
|
|
169353
|
+
const telemetryCbs = [];
|
|
169354
|
+
handle.onOutput?.((chunk) => {
|
|
169355
|
+
if (outputCbs.length === 0) buffered.push(chunk);
|
|
169356
|
+
for (const cb of outputCbs) cb(chunk);
|
|
169357
|
+
});
|
|
169358
|
+
handle.onTelemetry?.((event) => {
|
|
169359
|
+
if (telemetryCbs.length === 0) bufferedTelemetry.push(event);
|
|
169360
|
+
for (const cb of telemetryCbs) cb(event);
|
|
169361
|
+
if (event.kind === "system") {
|
|
169362
|
+
const ms = Date.parse(event.ts);
|
|
169363
|
+
if (!Number.isNaN(ms) && ms - lastProgressTouchMs >= PROGRESS_TOUCH_THROTTLE_MS2) {
|
|
169364
|
+
lastProgressTouchMs = ms;
|
|
169365
|
+
enqueueTrace(() => traceStore.updateRun(traceRunId, { lastProgressAt: event.ts }).then(() => void 0));
|
|
169366
|
+
}
|
|
169367
|
+
return;
|
|
169126
169368
|
}
|
|
169127
|
-
|
|
169128
|
-
}
|
|
169129
|
-
|
|
169130
|
-
|
|
169131
|
-
|
|
169132
|
-
|
|
169133
|
-
|
|
169134
|
-
|
|
169135
|
-
|
|
169136
|
-
|
|
169137
|
-
|
|
169138
|
-
|
|
169139
|
-
|
|
169140
|
-
|
|
169141
|
-
|
|
169142
|
-
|
|
169143
|
-
|
|
169144
|
-
|
|
169145
|
-
|
|
169146
|
-
|
|
169147
|
-
|
|
169148
|
-
|
|
169149
|
-
|
|
169150
|
-
|
|
169151
|
-
|
|
169152
|
-
|
|
169153
|
-
|
|
169154
|
-
|
|
169155
|
-
|
|
169156
|
-
|
|
169157
|
-
|
|
169158
|
-
|
|
169159
|
-
|
|
169369
|
+
enqueueTrace(() => traceStore.appendEvents(traceRunId, [trajectoryEventToRunEvent(event, ++traceSeq)]).then(() => void 0));
|
|
169370
|
+
});
|
|
169371
|
+
let capturedNativeSessionId;
|
|
169372
|
+
const done = new Promise((resolve5, reject) => {
|
|
169373
|
+
handle.onExit((info) => {
|
|
169374
|
+
chatLiveSessions.delete(chatJobKey);
|
|
169375
|
+
void provision.cleanup();
|
|
169376
|
+
const endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
169377
|
+
const durationMs = Date.parse(endedAt) - Date.parse(traceStartedAt);
|
|
169378
|
+
if (info.runtimeSessionId) capturedNativeSessionId = info.runtimeSessionId;
|
|
169379
|
+
enqueueTrace(async () => {
|
|
169380
|
+
await traceStore.appendEvents(traceRunId, [{
|
|
169381
|
+
seq: ++traceSeq,
|
|
169382
|
+
eventType: "run.finished",
|
|
169383
|
+
stream: "runtime",
|
|
169384
|
+
message: `exit code=${info.code ?? "killed"}`,
|
|
169385
|
+
startedAt: endedAt
|
|
169386
|
+
}]);
|
|
169387
|
+
const usage = info.usage ?? null;
|
|
169388
|
+
const effectiveModel = info.model ?? chatModel ?? null;
|
|
169389
|
+
const modelSource = info.model ? "runtime" : chatModelSource;
|
|
169390
|
+
await traceStore.updateRun(traceRunId, {
|
|
169391
|
+
status: info.reason === "timeout" ? "timeout" : info.reason === "cancelled" ? "cancelled" : info.code === 0 ? "succeeded" : "failed",
|
|
169392
|
+
endedAt,
|
|
169393
|
+
durationMs,
|
|
169394
|
+
exitCode: info.code,
|
|
169395
|
+
exitReason: info.reason ?? null,
|
|
169396
|
+
transcriptRef: info.transcriptRef ?? null,
|
|
169397
|
+
usage,
|
|
169398
|
+
effectiveModel,
|
|
169399
|
+
modelSource
|
|
169400
|
+
});
|
|
169401
|
+
if (usage && traceStore.updateUsageAggregates) {
|
|
169402
|
+
const run = await traceStore.getRun(traceRunId);
|
|
169403
|
+
if (run) void traceStore.updateUsageAggregates(run).catch(() => {
|
|
169404
|
+
});
|
|
169405
|
+
}
|
|
169160
169406
|
});
|
|
169161
|
-
|
|
169162
|
-
|
|
169163
|
-
|
|
169164
|
-
|
|
169407
|
+
const failed = info.code !== 0 || info.reason !== void 0 && info.reason !== "clean";
|
|
169408
|
+
if (!failed) resolve5();
|
|
169409
|
+
else {
|
|
169410
|
+
reject(buildChatExitError(info));
|
|
169165
169411
|
}
|
|
169166
169412
|
});
|
|
169167
|
-
const failed = info.code !== 0 || info.reason !== void 0 && info.reason !== "clean";
|
|
169168
|
-
if (!failed) resolve5();
|
|
169169
|
-
else {
|
|
169170
|
-
reject(buildChatExitError(info));
|
|
169171
|
-
}
|
|
169172
169413
|
});
|
|
169173
|
-
|
|
169174
|
-
|
|
169175
|
-
|
|
169176
|
-
|
|
169177
|
-
|
|
169178
|
-
|
|
169179
|
-
|
|
169180
|
-
|
|
169181
|
-
|
|
169182
|
-
|
|
169183
|
-
|
|
169184
|
-
|
|
169185
|
-
|
|
169186
|
-
|
|
169187
|
-
|
|
169188
|
-
|
|
169189
|
-
}
|
|
169414
|
+
return {
|
|
169415
|
+
id: runtimeSessionId,
|
|
169416
|
+
runId: traceRunId,
|
|
169417
|
+
onOutput(cb) {
|
|
169418
|
+
for (const chunk of buffered.splice(0)) cb(chunk);
|
|
169419
|
+
outputCbs.push(cb);
|
|
169420
|
+
},
|
|
169421
|
+
onTelemetry(cb) {
|
|
169422
|
+
for (const event of bufferedTelemetry.splice(0)) cb(event);
|
|
169423
|
+
telemetryCbs.push(cb);
|
|
169424
|
+
},
|
|
169425
|
+
done,
|
|
169426
|
+
kill: () => handle.kill(),
|
|
169427
|
+
get nativeSessionId() {
|
|
169428
|
+
return capturedNativeSessionId;
|
|
169429
|
+
}
|
|
169430
|
+
};
|
|
169190
169431
|
};
|
|
169432
|
+
const first = await dispatchChatImpl(chatReq);
|
|
169433
|
+
if (!chatReq.fallbackMessage || !chatReq.sessionId) return first;
|
|
169434
|
+
return makeResumeRetryProxy(
|
|
169435
|
+
first,
|
|
169436
|
+
() => dispatchChatImpl({ ...chatReq, sessionId: void 0, fallbackMessage: void 0, message: chatReq.fallbackMessage })
|
|
169437
|
+
);
|
|
169191
169438
|
},
|
|
169192
169439
|
trajectoryFeed: {
|
|
169193
169440
|
subscribe(sessionId, listener) {
|
|
@@ -170507,9 +170754,15 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
|
|
|
170507
170754
|
design run <artifactId> [--brief <t>] [--reason <t>] [--od-url <url>] [--title <t>] [--agent <id>]
|
|
170508
170755
|
# design \u4EA7\u7269\uFF1A\u5728\u901A\u7528 runtime \u4E0A\u9A71\u52A8 open-design \u753B\u677F\u5F15\u64CE\u4EA7\u754C\u9762\u7A3F\u5E76\u4EA4\u7A3F\uFF08\u63D0\u6848 design-node-runtime-to-cli-tool\uFF09\u3002
|
|
170509
170756
|
# --brief \u7F3A\u7701\u8BFB\u5F53\u524D\u76EE\u5F55 DESIGN_BRIEF.md\uFF08\u5176\u6B21 TASK.md\uFF09\uFF1B\u4E0A\u4E0B\u6587\u53D6\u5F53\u524D\u76EE\u5F55 inputs/\uFF1Bod \u5730\u5740\u7F3A\u7701 $OASIS_OPEN_DESIGN_URL \u6216\u672C\u673A 7457\u3002
|
|
170757
|
+
design chat <artifactId> --message <t> [--turn first|continue] [--async] [--system <t>]
|
|
170758
|
+
# \u591A\u8F6E\u5BF9\u8BDD\u9A71\u52A8\u753B\u677F\uFF08\u63D0\u6848 design-conversational-driving\uFF09\uFF1A\u4E0D\u81EA\u52A8\u4EA4\u7A3F\uFF0C\u8BFB\u4EA7\u7269\u540E\u81EA\u884C propose/gap\u3002
|
|
170759
|
+
# --async \u8D77\u5B8C\u5373\u8FD4\uFF08\u5F15\u64CE\u5728\u670D\u52A1\u7AEF\u8DD1 13\u201344min\uFF0C\u4E0E\u672C\u8FDB\u7A0B\u65E0\u5173\uFF09\uFF1B\u8FDB\u5EA6/\u53D6\u8D27\u7528 design status\u3002
|
|
170760
|
+
design status <artifactId> [--pull]
|
|
170761
|
+
# \u67E5\u753B\u677F\u73B0\u72B6\uFF08\u6062\u590D\u4F18\u5148\uFF09\uFF1A\u88AB\u6D3E\u53D1\u5148\u8DD1\u5B83\u2014\u2014\u5F15\u64CE\u5728\u8DD1\u5C31\u522B\u8D77\u65B0\u8F6E\uFF1B\u677F\u4E0A\u6709\u8D27 --pull \u62C9\u672C\u5730\u8BFB\uFF0C\u8BFB\u5B8C propose --from-dir\u3002
|
|
170510
170762
|
|
|
170511
170763
|
\u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09
|
|
170512
170764
|
annotate <artifactId> --body <text> [--from <\u4E0B\u6E38> --blocks true]
|
|
170765
|
+
record-action <artifactId> --name <\u52A8\u4F5C\u540D> [--pass true] [--result <json>] [--params <json>] # \xA79.2 grounding \u7559\u75D5\uFF1A\u4E3A action_vs_oplog \u8BB0\u4E00\u6761\u901A\u8FC7\u7684 tool_call\uFF08\u771F\u8DD1\u8FC7\u5065\u5EB7\u63A2\u9488\u540E record-action --name health_probe --pass true\uFF09\uFF1B\u58F0\u660E\u4E86 requiredActions \u7684\u7C7B\u578B\u6CA1\u6709\u5B83 conclude \u4F1A\u88AB\u673A\u68B0\u62E6
|
|
170513
170766
|
resolve <annotationId> [--as resolved|wontfix|acknowledged]
|
|
170514
170767
|
gap <artifactId> --desc <text>
|
|
170515
170768
|
add-revision <artifactId> --desc <\u8981\u5B83\u5B8C\u6210\u4EC0\u4E48> [--role <\u8C01\u6765\u505A\uFF0C\u9ED8\u8BA4owner\u81EA\u5DF1>] # \xA79 \u592A\u5927\u5C31\u6D3E\u4E00\u6761\u5B50revision\u51FA\u53BB\u5E76\u884C\uFF0C\u6D3E\u5B8C\u53EF\u6536\u5DE5\u7B49\u7ED3\u679C
|
|
@@ -170568,7 +170821,7 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
|
|
|
170568
170821
|
function parseArgs(argv) {
|
|
170569
170822
|
const positional = [];
|
|
170570
170823
|
const flags = /* @__PURE__ */ new Map();
|
|
170571
|
-
const booleanFlags = /* @__PURE__ */ new Set(["checkpoint", "continue"]);
|
|
170824
|
+
const booleanFlags = /* @__PURE__ */ new Set(["checkpoint", "continue", "async", "pull"]);
|
|
170572
170825
|
for (let i = 0; i < argv.length; i++) {
|
|
170573
170826
|
const a = argv[i];
|
|
170574
170827
|
if (a.startsWith("--")) {
|
|
@@ -170673,7 +170926,7 @@ async function runCli(argv, println = console.log) {
|
|
|
170673
170926
|
const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
|
|
170674
170927
|
method: "POST",
|
|
170675
170928
|
headers: { "content-type": "application/json" },
|
|
170676
|
-
body: JSON.stringify({ enrollToken, nodeId, hostname:
|
|
170929
|
+
body: JSON.stringify({ enrollToken, nodeId, hostname: os8.hostname() })
|
|
170677
170930
|
});
|
|
170678
170931
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
170679
170932
|
const body = await res.json();
|
|
@@ -170706,7 +170959,7 @@ async function runCli(argv, println = console.log) {
|
|
|
170706
170959
|
const binPath = path20.join(prefix, "bin", "oasis_test");
|
|
170707
170960
|
const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
|
|
170708
170961
|
if (process.platform === "linux") {
|
|
170709
|
-
const svcFile = path20.join(
|
|
170962
|
+
const svcFile = path20.join(os8.homedir(), ".config/systemd/user/oasis-node.service");
|
|
170710
170963
|
fs25.mkdirSync(path20.dirname(svcFile), { recursive: true });
|
|
170711
170964
|
if (spawnSync("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
|
|
170712
170965
|
spawnSync("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
|
|
@@ -170719,7 +170972,7 @@ async function runCli(argv, println = console.log) {
|
|
|
170719
170972
|
`ExecStart=${binPath} ${svcArgs}`,
|
|
170720
170973
|
// Carry the install-time PATH so the detached daemon detects CLIs in user dirs
|
|
170721
170974
|
// (~/.npm-global/bin, ~/.local/bin) — systemd --user otherwise gives a minimal PATH.
|
|
170722
|
-
`Environment=PATH=${process.env["PATH"] ?? ""}:${path20.join(
|
|
170975
|
+
`Environment=PATH=${process.env["PATH"] ?? ""}:${path20.join(os8.homedir(), ".npm-global/bin")}:${path20.join(os8.homedir(), ".local/bin")}:/usr/local/bin`,
|
|
170723
170976
|
"Restart=on-failure",
|
|
170724
170977
|
"RestartSec=5",
|
|
170725
170978
|
"StandardOutput=journal",
|
|
@@ -170731,23 +170984,23 @@ async function runCli(argv, println = console.log) {
|
|
|
170731
170984
|
].join("\n"));
|
|
170732
170985
|
spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
|
|
170733
170986
|
spawnSync("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
|
|
170734
|
-
spawnSync("loginctl", ["enable-linger",
|
|
170987
|
+
spawnSync("loginctl", ["enable-linger", os8.userInfo().username], { stdio: "ignore" });
|
|
170735
170988
|
println("\u2713 Oasis node service started (systemd --user oasis-node)");
|
|
170736
170989
|
println(" Status : systemctl --user status oasis-node");
|
|
170737
170990
|
println(" Logs : journalctl --user -u oasis-node -f");
|
|
170738
170991
|
println(" Stop : systemctl --user stop oasis-node");
|
|
170739
170992
|
} else if (process.platform === "darwin") {
|
|
170740
|
-
const plist = path20.join(
|
|
170993
|
+
const plist = path20.join(os8.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
|
|
170741
170994
|
fs25.mkdirSync(path20.dirname(plist), { recursive: true });
|
|
170742
170995
|
spawnSync("launchctl", ["unload", plist], { stdio: "ignore" });
|
|
170743
170996
|
const argXml = [binPath, "node", "--server-ws", serverUrl, "--dir", dir, ...nodeName ? ["--name", nodeName] : []].map((a) => `<string>${a}</string>`).join("");
|
|
170744
|
-
fs25.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${
|
|
170997
|
+
fs25.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${os8.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os8.homedir()}/.oasis-node.err</string></dict></plist>`);
|
|
170745
170998
|
spawnSync("launchctl", ["load", plist], { stdio: "inherit" });
|
|
170746
170999
|
println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
|
|
170747
|
-
println(` Logs : tail -f ${
|
|
171000
|
+
println(` Logs : tail -f ${os8.homedir()}/.oasis-node.log`);
|
|
170748
171001
|
println(` Stop : launchctl unload ${plist}`);
|
|
170749
171002
|
} else {
|
|
170750
|
-
spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path20.join(
|
|
171003
|
+
spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path20.join(os8.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
|
|
170751
171004
|
println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
|
|
170752
171005
|
println(" Note: no automatic restart on reboot in this environment.");
|
|
170753
171006
|
}
|
|
@@ -170818,8 +171071,8 @@ async function runCli(argv, println = console.log) {
|
|
|
170818
171071
|
if (command === "serve" && positional[0] === "install") {
|
|
170819
171072
|
const absDir = path20.resolve(dir);
|
|
170820
171073
|
const name = `oasis-serve-${path20.basename(absDir)}`;
|
|
170821
|
-
const unitDir = flags.get("unit-dir") ?? path20.join(
|
|
170822
|
-
const bin = flags.get("bin") ?? path20.join(
|
|
171074
|
+
const unitDir = flags.get("unit-dir") ?? path20.join(os8.homedir(), ".config", "systemd", "user");
|
|
171075
|
+
const bin = flags.get("bin") ?? path20.join(os8.homedir(), ".local", "bin", "oasis");
|
|
170823
171076
|
const port = flags.get("port") ?? "7320";
|
|
170824
171077
|
const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
|
|
170825
171078
|
const unit = [
|
|
@@ -171404,7 +171657,81 @@ ${res.warning}`);
|
|
|
171404
171657
|
}
|
|
171405
171658
|
case "design": {
|
|
171406
171659
|
const sub = positional[0];
|
|
171407
|
-
|
|
171660
|
+
const LEGACY_DESIGN_SYSTEM_PROMPT = "\u4F60\u662F\u8BBE\u8BA1\u5F15\u64CE\u4E2D\u7684\u754C\u9762\u8BBE\u8BA1\u5E08\u3002\u4EFB\u52A1\u4E66\u89C1\u672C\u6761\u6D88\u606F\uFF1B\u4E0A\u6E38\u8F93\u5165\u7B49\u4E0A\u4E0B\u6587\u6587\u4EF6\u5728\u9879\u76EE task-context/ \u76EE\u5F55\u3002\u6309\u4EFB\u52A1\u4E66\u7684\u300C\u600E\u4E48\u63D0\u4EA4\u300D\u534F\u8BAE\u5DE5\u4F5C\uFF1A\u4EA7\u51FA\u81EA\u5305\u542B HTML \u5165\u53E3\u7A3F\u4E0E acceptance.md\uFF0C\u5B8C\u6210\u5373\u7ED3\u675F\u56DE\u590D\uFF0C\u4EA4\u7A3F\u7531\u7CFB\u7EDF\u4EE3\u529E\u3002";
|
|
171661
|
+
if (sub === "chat") {
|
|
171662
|
+
const artifactId2 = needPos(positional, 1, "oasis design chat <artifactId> --message <t>");
|
|
171663
|
+
const message2 = flags.get("message") ?? (["DESIGN_BRIEF.md", "TASK.md"].map((f2) => fs25.existsSync(f2) ? fs25.readFileSync(f2, "utf8") : "").find((s2) => s2.trim()) ?? "");
|
|
171664
|
+
if (!message2.trim()) throw new Error("\u65E0\u5BF9\u8BDD\u5185\u5BB9\uFF1A\u7ED9 --message <text>\uFF0C\u6216\u5728\u5F53\u524D\u76EE\u5F55\u653E DESIGN_BRIEF.md / TASK.md");
|
|
171665
|
+
const odBase2 = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
|
|
171666
|
+
const isContinue = flags.get("turn") === "continue";
|
|
171667
|
+
const contextFiles2 = {};
|
|
171668
|
+
if (!isContinue) {
|
|
171669
|
+
contextFiles2["DESIGN_BRIEF.md"] = message2;
|
|
171670
|
+
if (fs25.existsSync("inputs") && fs25.statSync("inputs").isDirectory()) {
|
|
171671
|
+
for (const f2 of readDirFiles("inputs")) {
|
|
171672
|
+
contextFiles2[`inputs/${f2.path}`] = Buffer.from(f2.contentBase64, "base64").toString("utf8");
|
|
171673
|
+
}
|
|
171674
|
+
}
|
|
171675
|
+
}
|
|
171676
|
+
const baseTurnOpts = {
|
|
171677
|
+
base: odBase2,
|
|
171678
|
+
agentId: flags.get("agent") ?? "claude",
|
|
171679
|
+
artifactId: artifactId2,
|
|
171680
|
+
title: flags.get("title") ?? artifactId2,
|
|
171681
|
+
message: message2,
|
|
171682
|
+
...flags.get("system") !== void 0 ? { systemPrompt: flags.get("system") } : {},
|
|
171683
|
+
...isContinue ? {} : { contextFiles: contextFiles2 }
|
|
171684
|
+
};
|
|
171685
|
+
if (flags.get("async") === "true") {
|
|
171686
|
+
println(`[design] \u753B\u677F ${deriveBoardKey(artifactId2)} \u2190 ${artifactId2}\uFF1B${isContinue ? "\u7EED\u8F6E" : "\u9996\u8F6E"}\uFF08--async\uFF09\u2192 od \u5F15\u64CE ${odBase2} \u2026`);
|
|
171687
|
+
const started = await startDesignChatTurn(baseTurnOpts);
|
|
171688
|
+
println(`[design] \u5DF2\u4E0B\u5355\uFF1Arun ${started.runId.slice(0, 8)}\uFF08board ${started.boardKey}, \u53EF\u89C1 user \u56DE\u5408 ${started.userMessageId.slice(0, 8)}\uFF09\u3002\u5F15\u64CE\u901A\u5E38\u8981 13\u201344 \u5206\u949F\u3002`);
|
|
171689
|
+
println(`[design] \u4E4B\u540E\u7528 oasis design status ${artifactId2} \u67E5\u8FDB\u5EA6/\u53D6\u8D27\uFF08--pull \u62C9\u4EA7\u7269\u5230\u672C\u5730\u8BFB\uFF09\uFF1B\u4E0D\u5FC5\u5B88\u7740\u7B49\u3002`);
|
|
171690
|
+
break;
|
|
171691
|
+
}
|
|
171692
|
+
println(`[design] \u753B\u677F ${deriveBoardKey(artifactId2)} \u2190 ${artifactId2}\uFF1B${isContinue ? "\u7EED\u8F6E" : "\u9996\u8F6E"}\u5BF9\u8BDD\u9A71\u52A8 od \u5F15\u64CE ${odBase2} \u2026`);
|
|
171693
|
+
const turn = await runDesignChatTurn({
|
|
171694
|
+
...baseTurnOpts,
|
|
171695
|
+
onLine: (line) => println(`[od] ${line.length > 500 ? line.slice(0, 500) + "\u2026" : line}`)
|
|
171696
|
+
});
|
|
171697
|
+
println(`[design] \u672C\u8F6E\u4EA4\u4ED8\uFF08board ${turn.boardKey}, run ${turn.runId.slice(0, 8)}, \u53EF\u89C1 user \u56DE\u5408 ${turn.userMessageId.slice(0, 8)}\uFF09\uFF1A`);
|
|
171698
|
+
for (const a of turn.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.title ? ` \xB7 ${a.title}` : ""}`);
|
|
171699
|
+
println(`[design] \u8BFB\u4EA7\u7269\u540E\u81EA\u884C\u51B3\u5B9A\uFF1A\u591F\u597D \u2192 oasis propose\uFF1B\u6709\u5206\u6B67/\u7F3A\u4FE1\u606F \u2192 oasis gap\uFF1B\u4E0D\u591F \u2192 \u518D\u4E00\u8F6E oasis design chat ${artifactId2} --turn continue --message "<\u4E0B\u4E00\u53E5>"`);
|
|
171700
|
+
break;
|
|
171701
|
+
}
|
|
171702
|
+
if (sub === "status") {
|
|
171703
|
+
const artifactId2 = needPos(positional, 1, "oasis design status <artifactId> [--pull]");
|
|
171704
|
+
const odBase2 = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
|
|
171705
|
+
const st = await fetchBoardStatus(odBase2, fetch, artifactId2);
|
|
171706
|
+
if (!st.boardExists) {
|
|
171707
|
+
println(`[design] \u753B\u677F ${st.boardKey} \u5C1A\u4E0D\u5B58\u5728\u2014\u2014\u8FD8\u6CA1\u8D77\u8FC7\u4EFB\u4F55\u4E00\u8F6E\u3002\u5F00\u5DE5\uFF1Aoasis design chat ${artifactId2} --message "<\u8BBE\u8BA1\u9700\u6C42+\u771F\u5B9E\u6570\u636E>" --async`);
|
|
171708
|
+
break;
|
|
171709
|
+
}
|
|
171710
|
+
const live = st.runs.filter((r) => r.status === "running" || r.status === "queued");
|
|
171711
|
+
if (live.length > 0) {
|
|
171712
|
+
for (const r of live) println(`[design] \u5F15\u64CE\u5728\u8DD1\uFF1Arun ${r.runId.slice(0, 8)} \u72B6\u6001=${r.status}\u2014\u2014\u522B\u518D\u8D77\u65B0\u8F6E\uFF1B\u8FC7\u51E0\u5206\u949F\u518D status\uFF0C\u6216\u672C\u8F6E\u6536\u5DE5\u7B49\u91CD\u6D3E\u3002`);
|
|
171713
|
+
} else if (st.runs.length > 0) {
|
|
171714
|
+
for (const r of st.runs.slice(0, 3)) println(`[design] \u8FD1\u671F run\uFF1A${r.runId.slice(0, 8)} \u7EC8\u6001=${r.status}`);
|
|
171715
|
+
} else {
|
|
171716
|
+
println(`[design] \u65E0\u5728\u4E16 run \u8BB0\u5F55\uFF08od \u91CD\u542F\u540E\u4E3A\u7A7A\uFF0C\u5C5E\u6B63\u5E38\uFF09\u2014\u2014\u770B\u4E0B\u9762\u677F\u4E0A\u4EA7\u7269\u5373\u6301\u4E45\u771F\u76F8\u3002`);
|
|
171717
|
+
}
|
|
171718
|
+
if (st.artifacts.length === 0) {
|
|
171719
|
+
println(`[design] \u677F\u4E0A\u8FD8\u6CA1\u6709\u4EA4\u4ED8\u7269\u3002${live.length > 0 ? "\u7B49\u5F15\u64CE\u8DD1\u5B8C\u518D\u6765\u3002" : `\u8D77\u4E00\u8F6E\uFF1Aoasis design chat ${artifactId2} --message "<\u2026>" --async`}`);
|
|
171720
|
+
break;
|
|
171721
|
+
}
|
|
171722
|
+
println(`[design] \u677F\u4E0A\u4EA4\u4ED8\u7269\uFF08\u6301\u4E45\uFF0C\u65B0\u2192\u65E7\uFF09\uFF1A`);
|
|
171723
|
+
for (const a of st.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.mtime ? ` \xB7 ${new Date(a.mtime).toISOString()}` : ""}`);
|
|
171724
|
+
if (flags.get("pull") === "true") {
|
|
171725
|
+
const odPublic2 = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
171726
|
+
const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2, os8.tmpdir(), st.boardKey, st.runs[0]?.runId ?? "status-pull");
|
|
171727
|
+
println(`[design] \u5DF2\u62C9\u5230\u672C\u5730\uFF1A${dir3}\uFF08\u5165\u53E3 ${entry2}\uFF09`);
|
|
171728
|
+
println(`[design] \u8BFB\u5B8C\u6EE1\u610F\u5373\u4EA4\u7A3F\uFF1Aoasis propose ${artifactId2} --from-dir ${dir3} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"`);
|
|
171729
|
+
} else {
|
|
171730
|
+
println(`[design] \u53D6\u8D27\uFF1Aoasis design status ${artifactId2} --pull\uFF08\u62C9\u5230\u672C\u5730\u76EE\u5F55\u8BFB\uFF0C\u8BFB\u5B8C propose --from-dir \u4EA4\u7A3F\uFF09`);
|
|
171731
|
+
}
|
|
171732
|
+
break;
|
|
171733
|
+
}
|
|
171734
|
+
if (sub !== "run") throw new Error("\u7528\u6CD5\uFF1Aoasis design run <artifactId> \u2026\uFF1Boasis design chat <artifactId> --message <t> [--turn first|continue] [--async]\uFF1Boasis design status <artifactId> [--pull]");
|
|
171408
171735
|
const artifactId = needPos(positional, 1, "oasis design run <artifactId>");
|
|
171409
171736
|
const odBase = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
|
|
171410
171737
|
const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
@@ -171425,7 +171752,7 @@ ${res.warning}`);
|
|
|
171425
171752
|
artifactId,
|
|
171426
171753
|
title: flags.get("title") ?? artifactId,
|
|
171427
171754
|
message: brief,
|
|
171428
|
-
systemPrompt: "
|
|
171755
|
+
systemPrompt: flags.get("system") ?? LEGACY_DESIGN_SYSTEM_PROMPT,
|
|
171429
171756
|
contextFiles,
|
|
171430
171757
|
onLine: (line) => println(`[od] ${line.length > 500 ? line.slice(0, 500) + "\u2026" : line}`)
|
|
171431
171758
|
});
|
|
@@ -171502,6 +171829,18 @@ ${res.warning}`);
|
|
|
171502
171829
|
println(message);
|
|
171503
171830
|
break;
|
|
171504
171831
|
}
|
|
171832
|
+
case "record-action": {
|
|
171833
|
+
const artifactId = needPos(positional, 0, "oasis record-action <artifactId> --name <\u52A8\u4F5C\u540D> [--pass true] [--result <json>] [--params <json>]");
|
|
171834
|
+
const result = flags.get("result") !== void 0 ? JSON.parse(flags.get("result")) : { pass: flags.get("pass") === "true" };
|
|
171835
|
+
const { message } = await api.cmd("toolCall", {
|
|
171836
|
+
artifactId,
|
|
171837
|
+
name: need(flags, "name"),
|
|
171838
|
+
...flags.get("params") !== void 0 ? { params: JSON.parse(flags.get("params")) } : {},
|
|
171839
|
+
result
|
|
171840
|
+
});
|
|
171841
|
+
println(message);
|
|
171842
|
+
break;
|
|
171843
|
+
}
|
|
171505
171844
|
case "reply": {
|
|
171506
171845
|
const { message } = await api.cmd("reply", {
|
|
171507
171846
|
annotationId: needPos(positional, 0, "oasis reply <annotationId> --body <\u7B54\u590D>"),
|
|
@@ -172064,12 +172403,12 @@ ${res.warning}`);
|
|
|
172064
172403
|
init_src6();
|
|
172065
172404
|
|
|
172066
172405
|
// src/index.ts
|
|
172067
|
-
var PKG_VERSION = true ? "0.1.
|
|
172068
|
-
var OASIS_DIR = path21.join(
|
|
172406
|
+
var PKG_VERSION = true ? "0.1.62" : "dev";
|
|
172407
|
+
var OASIS_DIR = path21.join(os9.homedir(), ".oasis");
|
|
172069
172408
|
var CONFIG_FILE = path21.join(OASIS_DIR, "node-config.json");
|
|
172070
172409
|
var PID_FILE = path21.join(OASIS_DIR, "node.pid");
|
|
172071
172410
|
var BIN_FILE = path21.join(OASIS_DIR, "bin", "oasis.js");
|
|
172072
|
-
var LOCAL_BIN = path21.join(
|
|
172411
|
+
var LOCAL_BIN = path21.join(os9.homedir(), ".local", "bin", "oasis");
|
|
172073
172412
|
var LOG_FILE = path21.join(OASIS_DIR, "node.log");
|
|
172074
172413
|
var NPM_PREFIX = path21.join(OASIS_DIR, "npm-global");
|
|
172075
172414
|
var PKG_NAME = "oasis_test";
|
|
@@ -172119,7 +172458,7 @@ exec node "${BIN_FILE}" "$@"
|
|
|
172119
172458
|
}
|
|
172120
172459
|
function setupAutostart() {
|
|
172121
172460
|
const cmd = `${process.execPath} "${BIN_FILE}" --_daemon`;
|
|
172122
|
-
const home =
|
|
172461
|
+
const home = os9.homedir();
|
|
172123
172462
|
const extraBins = [
|
|
172124
172463
|
path21.join(home, ".npm-global", "bin"),
|
|
172125
172464
|
path21.join(home, ".local", "bin"),
|
|
@@ -172127,7 +172466,7 @@ function setupAutostart() {
|
|
|
172127
172466
|
];
|
|
172128
172467
|
const daemonPath = [process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":");
|
|
172129
172468
|
if (process.platform === "linux") {
|
|
172130
|
-
const unitDir = path21.join(
|
|
172469
|
+
const unitDir = path21.join(os9.homedir(), ".config", "systemd", "user");
|
|
172131
172470
|
fs26.mkdirSync(unitDir, { recursive: true });
|
|
172132
172471
|
fs26.writeFileSync(path21.join(unitDir, "oasis-node.service"), [
|
|
172133
172472
|
"[Unit]",
|
|
@@ -172151,7 +172490,7 @@ function setupAutostart() {
|
|
|
172151
172490
|
} catch {
|
|
172152
172491
|
}
|
|
172153
172492
|
} else if (process.platform === "darwin") {
|
|
172154
|
-
const plist = path21.join(
|
|
172493
|
+
const plist = path21.join(os9.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
|
|
172155
172494
|
fs26.mkdirSync(path21.dirname(plist), { recursive: true });
|
|
172156
172495
|
fs26.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
|
|
172157
172496
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -172314,7 +172653,7 @@ void (async () => {
|
|
|
172314
172653
|
const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
|
|
172315
172654
|
method: "POST",
|
|
172316
172655
|
headers: { "content-type": "application/json" },
|
|
172317
|
-
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname:
|
|
172656
|
+
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os9.hostname() })
|
|
172318
172657
|
});
|
|
172319
172658
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
172320
172659
|
const body = await res.json();
|