oasis_test 0.1.60 → 0.1.61
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 +611 -405
- 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,18 @@ 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\uFF1A`,
|
|
3864
3871
|
``,
|
|
3865
|
-
` oasis design
|
|
3872
|
+
` oasis design chat ${artifactId} --message "<\u8FD9\u4E00\u8F6E\u8981\u5F15\u64CE\u505A\u4EC0\u4E48\uFF1A\u8BBE\u8BA1\u9700\u6C42 + \u771F\u5B9E\u6570\u636E>"`,
|
|
3873
|
+
` oasis design chat ${artifactId} --turn continue --message "<\u8BFB\u5B8C\u4E0A\u4E00\u7248\u4EA7\u7269\u540E\uFF0C\u8981\u6539\u54EA\u91CC>"`,
|
|
3866
3874
|
``,
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3875
|
+
`**\u6BCF\u4E00\u8F6E\u7684\u95ED\u73AF\uFF08\u522B\u8DF3\u6B65\uFF09**\uFF1A`,
|
|
3876
|
+
`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`,
|
|
3877
|
+
`2. **\u8BFB\u4EA7\u7269**\uFF1A\u547D\u4EE4\u8DD1\u5B8C\u4F1A\u6253\u5370\u672C\u8F6E\u4EA4\u4ED8\u7684 artifact \u6E05\u5355\uFF08\`index.html\` / \`acceptance.md\` \u53CA status\uFF09\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`,
|
|
3878
|
+
`3. **\u51B3\u5B9A**\uFF1A\u591F\u597D \u2192 \`oasis propose ${artifactId} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"\` \u4EA4\u7A3F\uFF1B\u8FD8\u5DEE \u2192 \`oasis design chat ${artifactId} --turn continue --message "<\u5177\u4F53\u6539\u4EC0\u4E48>"\` **\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`,
|
|
3879
|
+
`- **\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`,
|
|
3880
|
+
`- \u5F15\u64CE\u4E00\u8F6E\u8981 13\u201344 \u5206\u949F\uFF08\u771F\u5728\u753B\u5E03\u4E0A\u753B\uFF09\uFF0C\`oasis design chat\` \u5185\u90E8\u5DF2\u8F6E\u8BE2 30 \u5206\u949F\u3002**\u522B\u7528 \`timeout\` \u5305\u5B83\u3001\u522B 15 \u5206\u949F\u5C31\u5F53\u5B83\u5931\u8D25**\u2014\u2014\u8010\u5FC3\u7B49\u5B83\u8DD1\u5B8C\uFF1B`,
|
|
3881
|
+
`- \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
3882
|
] : (() => {
|
|
3872
3883
|
const codeRepo = args.codeRepo ?? null;
|
|
3873
3884
|
const repos = typeDef?.contentType === "code" ? codeRepo?.repos : void 0;
|
|
@@ -3922,7 +3933,7 @@ async function assembleContext(args) {
|
|
|
3922
3933
|
``,
|
|
3923
3934
|
...canvasMode ? [
|
|
3924
3935
|
`## \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
|
|
3936
|
+
`oasis CLI \u5DF2\u6CE8\u5165\uFF08\`OASIS_SERVER\` / \`OASIS_TOKEN\` \u5C31\u7EEA\uFF0C\u65E0\u9700\u914D\u7F6E\uFF09\u2014\u2014\u4F60\u7528 \`oasis design chat\` \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
3937
|
] : commandReference({
|
|
3927
3938
|
artifactId,
|
|
3928
3939
|
action: args.action ?? "produce",
|
|
@@ -3950,12 +3961,14 @@ async function assembleContext(args) {
|
|
|
3950
3961
|
(s2) => `- ${s2.upstream}: pin=${s2.pinned ?? "\u2205"} \u2192 \u6700\u65B0 ${s2.latest}${s2.upstreamCancelled ? "\uFF08\u26A0 \u4E0A\u6E38\u5DF2 cancelled\uFF09" : ""}`
|
|
3951
3962
|
)
|
|
3952
3963
|
] : [],
|
|
3953
|
-
//
|
|
3964
|
+
// 画板模式:你在通用 runtime 上、CLI 齐全(design chat/propose/gap 都能用);引擎里的内层 agent 才没 CLI,那层不用你管
|
|
3954
3965
|
...canvasMode ? [
|
|
3955
3966
|
``,
|
|
3956
3967
|
`## \u751F\u4EA7\u8005\u5B88\u5219\uFF08\u753B\u677F\u7248\uFF09`,
|
|
3957
|
-
`- \u4F60\
|
|
3968
|
+
`- \u4F60\u662F\u7532\u65B9\uFF1A\u591A\u8F6E \`oasis design chat\` \u9A71\u52A8\u5F15\u64CE\uFF0C\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`,
|
|
3969
|
+
`- \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
3970
|
`- \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`,
|
|
3971
|
+
`- \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
3972
|
`- \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
3973
|
] : [],
|
|
3961
3974
|
// review 会话不产出、不该给生产者守则(它只投票,守则的 propose/conclude/gap/add-revision 全不适用)
|
|
@@ -4228,7 +4241,7 @@ var init_dispatcher = __esm({
|
|
|
4228
4241
|
}
|
|
4229
4242
|
};
|
|
4230
4243
|
SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT = 5;
|
|
4231
|
-
SELF_HEALING_EXITS = /* @__PURE__ */ new Set(["rate-limit"]);
|
|
4244
|
+
SELF_HEALING_EXITS = /* @__PURE__ */ new Set(["rate-limit", "session-not-found"]);
|
|
4232
4245
|
CANVAS_RUNTIME_KIND = "open-design";
|
|
4233
4246
|
NON_PRODUCE_FALLBACK_RUNTIME_KIND = "claude-code";
|
|
4234
4247
|
Dispatcher = class {
|
|
@@ -4284,7 +4297,8 @@ var init_dispatcher = __esm({
|
|
|
4284
4297
|
}
|
|
4285
4298
|
/** ann: 讨论/回踢 resume 用:该 artifact 最近一次 produce/integrate 会话的 runtimeSessionId */
|
|
4286
4299
|
retainedProduceSessionFor(artifactId) {
|
|
4287
|
-
|
|
4300
|
+
const rec = decodeProduceSession(this.produceSessions.get(`produce:${artifactId}`));
|
|
4301
|
+
return rec?.sessionMissing ? void 0 : rec?.rtId;
|
|
4288
4302
|
}
|
|
4289
4303
|
emitJournal(entry) {
|
|
4290
4304
|
try {
|
|
@@ -4681,8 +4695,8 @@ var init_dispatcher = __esm({
|
|
|
4681
4695
|
const sessionKey = this.produceSessionKeyFor(spec);
|
|
4682
4696
|
const prior = sessionKey ? decodeProduceSession(this.produceSessions.get(sessionKey)) : void 0;
|
|
4683
4697
|
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;
|
|
4698
|
+
const retainedPartSession = spec.action === "produce" && spec.part !== void 0 && priorConsistent && !prior.sessionMissing ? prior.rtId : void 0;
|
|
4699
|
+
const retainedWholeSession = spec.action === "produce" && spec.part === void 0 && priorConsistent && !prior.sessionMissing ? this.resumableWholeSession(spec.artifactId, seqNow, prior.rtId) : void 0;
|
|
4686
4700
|
const retainedSession = retainedPartSession ?? retainedWholeSession;
|
|
4687
4701
|
const runtimeSessionId = retainedSession ?? (isProduceLike ? (0, import_node_crypto3.randomUUID)() : void 0);
|
|
4688
4702
|
const resumeSession = retainedSession !== void 0;
|
|
@@ -4856,11 +4870,12 @@ var init_dispatcher = __esm({
|
|
|
4856
4870
|
const prev = decodeProduceSession(this.produceSessions.get(exitSessionKey));
|
|
4857
4871
|
if (prev) {
|
|
4858
4872
|
const isWholeProduce = spec.action === "produce" && spec.part === void 0;
|
|
4873
|
+
const sessionNotFound = info.reason === "session-not-found";
|
|
4859
4874
|
try {
|
|
4860
4875
|
this.produceSessions.set(exitSessionKey, encodeProduceSession({
|
|
4861
4876
|
...prev,
|
|
4862
4877
|
...info.runtimeSessionId ? { rtId: info.runtimeSessionId } : {},
|
|
4863
|
-
...isWholeProduce ? { seqAtExit } : { seqAtExit: void 0 },
|
|
4878
|
+
...sessionNotFound ? { sessionMissing: true, seqAtExit: void 0 } : { sessionMissing: void 0, ...isWholeProduce ? { seqAtExit } : { seqAtExit: void 0 } },
|
|
4864
4879
|
lastUsedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4865
4880
|
}));
|
|
4866
4881
|
} catch {
|
|
@@ -137781,11 +137796,15 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}` : brief;
|
|
|
137781
137796
|
}
|
|
137782
137797
|
case "conclude": {
|
|
137783
137798
|
const artifactId = str(args, "artifactId");
|
|
137784
|
-
await kernel.conclude({ artifactId, actor, note: optStr(args, "note") });
|
|
137785
|
-
|
|
137786
|
-
|
|
137787
|
-
message:
|
|
137788
|
-
}
|
|
137799
|
+
const result = await kernel.conclude({ artifactId, actor, note: optStr(args, "note") });
|
|
137800
|
+
if (result.kind === "gate-pending") {
|
|
137801
|
+
const pending = pendingConcludeAttempt(kernel.model, artifactId);
|
|
137802
|
+
return { message: `conclude \u5DF2\u53D1\u8D77\uFF0Cgate \u5F85\u5BA1\uFF08quorum=${pending.gate.quorum}\uFF0Celigible=${pending.gate.eligible.join(", ")}\uFF09` };
|
|
137803
|
+
}
|
|
137804
|
+
if (result.kind === "noop-concluded") {
|
|
137805
|
+
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` };
|
|
137806
|
+
}
|
|
137807
|
+
return { message: `concluded\uFF1A\u91CC\u7A0B\u7891\u6210\u7ACB\uFF08head=${result.head}\uFF09` };
|
|
137789
137808
|
}
|
|
137790
137809
|
case "review": {
|
|
137791
137810
|
const revisionArg = optStr(args, "revisionId");
|
|
@@ -138416,7 +138435,7 @@ async function startOasisServer(opts) {
|
|
|
138416
138435
|
res.writeHead(status, { "content-type": "application/json" }).end(
|
|
138417
138436
|
JSON.stringify({
|
|
138418
138437
|
error: err instanceof Error ? err.message : String(err),
|
|
138419
|
-
...err instanceof FrozenError ? { retryable:
|
|
138438
|
+
...err instanceof FrozenError ? { retryable: err.retryable } : {}
|
|
138420
138439
|
})
|
|
138421
138440
|
);
|
|
138422
138441
|
}
|
|
@@ -139078,10 +139097,13 @@ async function startOasisServer(opts) {
|
|
|
139078
139097
|
...draftWorkspace ? { draftWorkspace } : {}
|
|
139079
139098
|
});
|
|
139080
139099
|
const effectiveSessionId = persistTarget ? runtimeChanged ? void 0 : persistTarget.runtimeSessionId ?? void 0 : body.sessionId || void 0;
|
|
139100
|
+
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 })) : [];
|
|
139101
|
+
const fallbackMessage = resumeFallbackHistory.length ? buildRuntimeChatPrompt({ userMessage: persistedUserMessage, history: resumeFallbackHistory, ...draftWorkspace ? { draftWorkspace } : {} }) : void 0;
|
|
139081
139102
|
const session = await opts.dispatchChat({
|
|
139082
139103
|
actorId: body.actorId,
|
|
139083
139104
|
message: runtimeMessage,
|
|
139084
139105
|
...effectiveSessionId ? { sessionId: effectiveSessionId } : {},
|
|
139106
|
+
...fallbackMessage ? { fallbackMessage } : {},
|
|
139085
139107
|
...body.chatSessionId ? { chatSessionId: body.chatSessionId } : {},
|
|
139086
139108
|
...body.workspace ? { workspace: body.workspace } : {},
|
|
139087
139109
|
...currentCompanyId !== void 0 ? { companyId: currentCompanyId } : {},
|
|
@@ -146742,6 +146764,17 @@ function materializeContext(resolvedDir, files) {
|
|
|
146742
146764
|
fs8.writeFileSync(f2, content);
|
|
146743
146765
|
}
|
|
146744
146766
|
}
|
|
146767
|
+
async function putVisibleUserTurn(base, fetchImpl, args) {
|
|
146768
|
+
const messageId = (0, import_node_crypto11.randomUUID)();
|
|
146769
|
+
await odApi(
|
|
146770
|
+
base,
|
|
146771
|
+
fetchImpl,
|
|
146772
|
+
"PUT",
|
|
146773
|
+
`/api/projects/${encodeURIComponent(args.boardKey)}/conversations/${encodeURIComponent(args.conversationId)}/messages/${messageId}`,
|
|
146774
|
+
{ id: messageId, role: "user", content: args.content }
|
|
146775
|
+
);
|
|
146776
|
+
return messageId;
|
|
146777
|
+
}
|
|
146745
146778
|
async function startDesignRun(base, fetchImpl, args) {
|
|
146746
146779
|
const created = await odApi(base, fetchImpl, "POST", "/api/runs", {
|
|
146747
146780
|
agentId: args.agentId,
|
|
@@ -146750,10 +146783,22 @@ async function startDesignRun(base, fetchImpl, args) {
|
|
|
146750
146783
|
assistantMessageId: (0, import_node_crypto11.randomUUID)(),
|
|
146751
146784
|
clientRequestId: (0, import_node_crypto11.randomUUID)(),
|
|
146752
146785
|
message: args.message,
|
|
146753
|
-
systemPrompt
|
|
146786
|
+
// 提案 design-conversational-driving 坑②:systemPrompt 从写死改为可选——缺省用引擎侧默认,
|
|
146787
|
+
// 让设计意图由驱动方每轮的话(message)表达,而非焊死一句。
|
|
146788
|
+
...args.systemPrompt !== void 0 ? { systemPrompt: args.systemPrompt } : {}
|
|
146754
146789
|
});
|
|
146755
146790
|
return created.runId;
|
|
146756
146791
|
}
|
|
146792
|
+
async function fetchResultPackage(base, fetchImpl, runId) {
|
|
146793
|
+
const body = await odApi(base, fetchImpl, "GET", `/api/runs/${encodeURIComponent(runId)}/result-package`);
|
|
146794
|
+
const artifacts = (body.artifacts ?? []).map((a) => ({
|
|
146795
|
+
path: a.path ?? "",
|
|
146796
|
+
kind: a.kind ?? null,
|
|
146797
|
+
title: a.title ?? null,
|
|
146798
|
+
status: a.status ?? null
|
|
146799
|
+
}));
|
|
146800
|
+
return { artifacts, fileCount: body.project?.fileCount ?? artifacts.length };
|
|
146801
|
+
}
|
|
146757
146802
|
async function pumpDesignEvents(base, fetchImpl, runId, onLine) {
|
|
146758
146803
|
const res = await fetchImpl(`${base}/api/runs/${runId}/events`);
|
|
146759
146804
|
if (!res.ok || !res.body) return;
|
|
@@ -146837,7 +146882,7 @@ async function runOpenDesignSession(opts) {
|
|
|
146837
146882
|
boardKey,
|
|
146838
146883
|
conversationId,
|
|
146839
146884
|
message: opts.message,
|
|
146840
|
-
systemPrompt: opts.systemPrompt
|
|
146885
|
+
...opts.systemPrompt !== void 0 ? { systemPrompt: opts.systemPrompt } : {}
|
|
146841
146886
|
});
|
|
146842
146887
|
if (opts.onLine) void pumpDesignEvents(opts.base, fetchImpl, runId, opts.onLine).catch(() => {
|
|
146843
146888
|
});
|
|
@@ -146850,6 +146895,30 @@ async function runOpenDesignSession(opts) {
|
|
|
146850
146895
|
const { dir, entry } = await harvestBoard(opts.base, fetchImpl, opts.publicBase, workRoot, boardKey, runId);
|
|
146851
146896
|
return { dir, entry, boardKey, runId };
|
|
146852
146897
|
}
|
|
146898
|
+
async function runDesignChatTurn(opts) {
|
|
146899
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
146900
|
+
const boardKey = deriveBoardKey(opts.artifactId);
|
|
146901
|
+
const { conversationId, resolvedDir } = await ensureProject(opts.base, fetchImpl, boardKey, opts.title);
|
|
146902
|
+
if (opts.contextFiles) materializeContext(resolvedDir, opts.contextFiles);
|
|
146903
|
+
const userMessageId = await putVisibleUserTurn(opts.base, fetchImpl, { boardKey, conversationId, content: opts.message });
|
|
146904
|
+
const runId = await startDesignRun(opts.base, fetchImpl, {
|
|
146905
|
+
agentId: opts.agentId,
|
|
146906
|
+
boardKey,
|
|
146907
|
+
conversationId,
|
|
146908
|
+
message: opts.message,
|
|
146909
|
+
...opts.systemPrompt !== void 0 ? { systemPrompt: opts.systemPrompt } : {}
|
|
146910
|
+
});
|
|
146911
|
+
if (opts.onLine) void pumpDesignEvents(opts.base, fetchImpl, runId, opts.onLine).catch(() => {
|
|
146912
|
+
});
|
|
146913
|
+
const status = await pollDesignRun(opts.base, fetchImpl, runId, {
|
|
146914
|
+
...opts.pollIntervalMs !== void 0 ? { intervalMs: opts.pollIntervalMs } : {},
|
|
146915
|
+
...opts.pollMaxMs !== void 0 ? { maxMs: opts.pollMaxMs } : {}
|
|
146916
|
+
});
|
|
146917
|
+
if (status === "canceled") throw new Error(`od run ${runId} \u88AB\u53D6\u6D88`);
|
|
146918
|
+
if (status === "failed") throw new Error(`od run ${runId} \u5931\u8D25`);
|
|
146919
|
+
const { artifacts, fileCount } = await fetchResultPackage(opts.base, fetchImpl, runId);
|
|
146920
|
+
return { boardKey, conversationId, runId, userMessageId, artifacts, fileCount };
|
|
146921
|
+
}
|
|
146853
146922
|
var import_node_crypto11, fs8, os, path7;
|
|
146854
146923
|
var init_driver = __esm({
|
|
146855
146924
|
"../adapters/src/open-design/driver.ts"() {
|
|
@@ -146892,6 +146961,25 @@ var init_sync_skills = __esm({
|
|
|
146892
146961
|
}
|
|
146893
146962
|
});
|
|
146894
146963
|
|
|
146964
|
+
// ../adapters/src/_core/resume-classify.ts
|
|
146965
|
+
function isSessionNotFoundError(text) {
|
|
146966
|
+
if (!text) return false;
|
|
146967
|
+
const t = text.toLowerCase();
|
|
146968
|
+
return SESSION_NOT_FOUND_PATTERNS.some((p2) => t.includes(p2));
|
|
146969
|
+
}
|
|
146970
|
+
var SESSION_NOT_FOUND_PATTERNS;
|
|
146971
|
+
var init_resume_classify = __esm({
|
|
146972
|
+
"../adapters/src/_core/resume-classify.ts"() {
|
|
146973
|
+
"use strict";
|
|
146974
|
+
SESSION_NOT_FOUND_PATTERNS = [
|
|
146975
|
+
"no conversation found",
|
|
146976
|
+
// claude: `claude --resume <缺失的 id>`
|
|
146977
|
+
"no rollout found for thread id"
|
|
146978
|
+
// codex: `codex exec resume <缺失的 uuid>`
|
|
146979
|
+
];
|
|
146980
|
+
}
|
|
146981
|
+
});
|
|
146982
|
+
|
|
146895
146983
|
// ../adapters/src/_core/session-paths.ts
|
|
146896
146984
|
function resolveWorkRoot(workRoot) {
|
|
146897
146985
|
if (workRoot) return workRoot;
|
|
@@ -147219,29 +147307,17 @@ function classifyExit(result) {
|
|
|
147219
147307
|
if (result.is_error === true || String(result.subtype ?? "").startsWith("error")) return "error";
|
|
147220
147308
|
return void 0;
|
|
147221
147309
|
}
|
|
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;
|
|
147310
|
+
var import_node_child_process7, import_node_crypto13, fs10, path9, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
147235
147311
|
var init_claude_code = __esm({
|
|
147236
147312
|
"../adapters/src/claude-code/index.ts"() {
|
|
147237
147313
|
"use strict";
|
|
147238
147314
|
import_node_child_process7 = require("node:child_process");
|
|
147239
147315
|
import_node_crypto13 = require("node:crypto");
|
|
147240
147316
|
fs10 = __toESM(require("node:fs"), 1);
|
|
147241
|
-
os3 = __toESM(require("node:os"), 1);
|
|
147242
147317
|
path9 = __toESM(require("node:path"), 1);
|
|
147243
147318
|
readline = __toESM(require("node:readline"), 1);
|
|
147244
147319
|
init_sync_skills();
|
|
147320
|
+
init_resume_classify();
|
|
147245
147321
|
init_session_paths();
|
|
147246
147322
|
ONE_SHOT_UNSAFE_TOOLS = ["ScheduleWakeup", "CronCreate", "CronDelete", "CronList"];
|
|
147247
147323
|
ClaudeCodeAdapter = class {
|
|
@@ -147315,8 +147391,7 @@ var init_claude_code = __esm({
|
|
|
147315
147391
|
const prompt = job.bundle.files["TASK.md"];
|
|
147316
147392
|
if (!prompt) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
147317
147393
|
const promptViaStdin = Buffer.byteLength(prompt, "utf8") > 1e5;
|
|
147318
|
-
const
|
|
147319
|
-
const runtimeSessionArgs = job.runtimeSessionId ? canResume ? ["--resume", job.runtimeSessionId] : ["--session-id", job.runtimeSessionId] : [];
|
|
147394
|
+
const runtimeSessionArgs = job.runtimeSessionId ? job.resumeRuntimeSession ? ["--resume", job.runtimeSessionId] : ["--session-id", job.runtimeSessionId] : [];
|
|
147320
147395
|
const oneShotSafety = this.opts.oneShotSafety !== false;
|
|
147321
147396
|
const args = [
|
|
147322
147397
|
"-p",
|
|
@@ -147441,7 +147516,12 @@ var init_claude_code = __esm({
|
|
|
147441
147516
|
child.on("exit", (code) => {
|
|
147442
147517
|
clearTimeout(timer);
|
|
147443
147518
|
if (exited) return;
|
|
147444
|
-
|
|
147519
|
+
let reason = killReason ?? classifyExit(lastResult);
|
|
147520
|
+
const resultErrors = Array.isArray(lastResult?.errors) ? lastResult.errors.map(String) : [];
|
|
147521
|
+
const resumeErrText = [stderrTail.join("\n"), String(lastResult?.result ?? ""), ...resultErrors].join("\n");
|
|
147522
|
+
if (!killReason && job.resumeRuntimeSession && reason !== "clean" && isSessionNotFoundError(resumeErrText)) {
|
|
147523
|
+
reason = "session-not-found";
|
|
147524
|
+
}
|
|
147445
147525
|
const workdirRef = dir;
|
|
147446
147526
|
const isOneShot = job.workdirKey ? false : !job.runtimeSessionId;
|
|
147447
147527
|
unlockWorkdir(dir);
|
|
@@ -147652,7 +147732,7 @@ var init_resilient = __esm({
|
|
|
147652
147732
|
|
|
147653
147733
|
// ../adapters/src/_core/skill-cache.ts
|
|
147654
147734
|
function defaultCacheRoot() {
|
|
147655
|
-
return path10.join(
|
|
147735
|
+
return path10.join(os3.homedir(), ".oasis", "skill-cache");
|
|
147656
147736
|
}
|
|
147657
147737
|
function sessionSkillsSubdir(runtimeKind) {
|
|
147658
147738
|
switch (runtimeKind) {
|
|
@@ -147895,12 +147975,12 @@ async function syncSessionSymlinks(sessionDir, runtimeKind, actorDir, manifest,
|
|
|
147895
147975
|
}
|
|
147896
147976
|
}
|
|
147897
147977
|
}
|
|
147898
|
-
var fsp,
|
|
147978
|
+
var fsp, os3, path10, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
|
|
147899
147979
|
var init_skill_cache = __esm({
|
|
147900
147980
|
"../adapters/src/_core/skill-cache.ts"() {
|
|
147901
147981
|
"use strict";
|
|
147902
147982
|
fsp = __toESM(require("node:fs/promises"), 1);
|
|
147903
|
-
|
|
147983
|
+
os3 = __toESM(require("node:os"), 1);
|
|
147904
147984
|
path10 = __toESM(require("node:path"), 1);
|
|
147905
147985
|
MANIFEST_SCHEMA_VERSION = 1;
|
|
147906
147986
|
STALE_LOCK_MS = 6e4;
|
|
@@ -148271,7 +148351,7 @@ function codexSessionsRoot() {
|
|
|
148271
148351
|
const candidates = [];
|
|
148272
148352
|
const ch = process.env["CODEX_HOME"];
|
|
148273
148353
|
if (ch) candidates.push(path11.join(ch, "sessions"));
|
|
148274
|
-
const home = process.env["HOME"] ||
|
|
148354
|
+
const home = process.env["HOME"] || os4.homedir();
|
|
148275
148355
|
if (home) candidates.push(path11.join(home, ".codex", "sessions"));
|
|
148276
148356
|
for (const c of candidates) {
|
|
148277
148357
|
try {
|
|
@@ -148281,31 +148361,6 @@ function codexSessionsRoot() {
|
|
|
148281
148361
|
}
|
|
148282
148362
|
return "";
|
|
148283
148363
|
}
|
|
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
148364
|
function listRecentRollouts(root, sinceMs) {
|
|
148310
148365
|
const margin = sinceMs - 6e4;
|
|
148311
148366
|
const found = [];
|
|
@@ -148547,17 +148602,18 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
|
|
|
148547
148602
|
tool.output.push(line);
|
|
148548
148603
|
return [];
|
|
148549
148604
|
}
|
|
148550
|
-
var import_node_child_process9, import_node_crypto14, fs11,
|
|
148605
|
+
var import_node_child_process9, import_node_crypto14, fs11, os4, path11, readline2, CodexAdapter;
|
|
148551
148606
|
var init_codex = __esm({
|
|
148552
148607
|
"../adapters/src/codex/index.ts"() {
|
|
148553
148608
|
"use strict";
|
|
148554
148609
|
import_node_child_process9 = require("node:child_process");
|
|
148555
148610
|
import_node_crypto14 = require("node:crypto");
|
|
148556
148611
|
fs11 = __toESM(require("node:fs"), 1);
|
|
148557
|
-
|
|
148612
|
+
os4 = __toESM(require("node:os"), 1);
|
|
148558
148613
|
path11 = __toESM(require("node:path"), 1);
|
|
148559
148614
|
readline2 = __toESM(require("node:readline"), 1);
|
|
148560
148615
|
init_sync_skills();
|
|
148616
|
+
init_resume_classify();
|
|
148561
148617
|
init_session_paths();
|
|
148562
148618
|
init_claude_code();
|
|
148563
148619
|
CodexAdapter = class {
|
|
@@ -148606,9 +148662,7 @@ var init_codex = __esm({
|
|
|
148606
148662
|
const task = job.bundle.files["TASK.md"];
|
|
148607
148663
|
if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
148608
148664
|
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
|
-
);
|
|
148665
|
+
const isResume = Boolean(job.resumeRuntimeSession && job.runtimeSessionId);
|
|
148612
148666
|
const args = [
|
|
148613
148667
|
"exec",
|
|
148614
148668
|
"-C",
|
|
@@ -148744,7 +148798,8 @@ var init_codex = __esm({
|
|
|
148744
148798
|
const sawStreamError = streamErrorMessages.length > 0;
|
|
148745
148799
|
const isError = !killReason && (typeof code === "number" && code !== 0 || sawStreamError);
|
|
148746
148800
|
const errorMessage = isError ? [...streamErrorMessages, ...stdoutErrorLines, ...stderrTail].join("\n").trim().slice(-4e3) || void 0 : void 0;
|
|
148747
|
-
const
|
|
148801
|
+
const sessionNotFound = !killReason && isResume && isSessionNotFoundError([...streamErrorMessages, ...stdoutErrorLines, ...stderrTail].join("\n"));
|
|
148802
|
+
const reason = killReason ? killReason : sessionNotFound ? "session-not-found" : sawStreamError ? "error" : code === 0 ? "clean" : "error";
|
|
148748
148803
|
finish({
|
|
148749
148804
|
code: killReason ? null : code,
|
|
148750
148805
|
reason,
|
|
@@ -153560,7 +153615,44 @@ var init_node_health = __esm({
|
|
|
153560
153615
|
});
|
|
153561
153616
|
|
|
153562
153617
|
// ../server/src/domains/nodes/routes.ts
|
|
153618
|
+
function daemonVersionLess(a, b2) {
|
|
153619
|
+
if (!a || !b2 || a === "\u2014" || b2 === "\u2014") return false;
|
|
153620
|
+
const parse2 = (v2) => v2.replace(/^v/, "").split(".").map((x2) => Number.parseInt(x2, 10));
|
|
153621
|
+
const pa = parse2(a);
|
|
153622
|
+
const pb = parse2(b2);
|
|
153623
|
+
if (pa.some(Number.isNaN) || pb.some(Number.isNaN)) return a < b2;
|
|
153624
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
153625
|
+
const ai = pa[i] ?? 0;
|
|
153626
|
+
const bi = pb[i] ?? 0;
|
|
153627
|
+
if (ai !== bi) return ai < bi;
|
|
153628
|
+
}
|
|
153629
|
+
return false;
|
|
153630
|
+
}
|
|
153563
153631
|
function nodesDomain(deps) {
|
|
153632
|
+
async function resolveLatestDaemonVersion() {
|
|
153633
|
+
const envVer = (process.env["OASIS_LATEST_NODE_DAEMON_VERSION"] ?? "").trim();
|
|
153634
|
+
if (envVer) return { version: envVer, source: "env" };
|
|
153635
|
+
if (deps.fetchLatestNpmDaemonVersion) {
|
|
153636
|
+
try {
|
|
153637
|
+
const v2 = (await deps.fetchLatestNpmDaemonVersion())?.trim();
|
|
153638
|
+
if (v2) return { version: v2, source: "npm" };
|
|
153639
|
+
} catch {
|
|
153640
|
+
}
|
|
153641
|
+
}
|
|
153642
|
+
try {
|
|
153643
|
+
const here = (0, import_node_path10.dirname)((0, import_node_url3.fileURLToPath)(__esm_import_meta_url));
|
|
153644
|
+
for (const rel of ["../../../../node-daemon/package.json", "../../../../../node-daemon/package.json"]) {
|
|
153645
|
+
try {
|
|
153646
|
+
const raw = (0, import_node_fs7.readFileSync)((0, import_node_path10.resolve)(here, rel), "utf8");
|
|
153647
|
+
const pkg = JSON.parse(raw);
|
|
153648
|
+
if (pkg.version) return { version: pkg.version, source: "monorepo" };
|
|
153649
|
+
} catch {
|
|
153650
|
+
}
|
|
153651
|
+
}
|
|
153652
|
+
} catch {
|
|
153653
|
+
}
|
|
153654
|
+
return { version: null, source: null };
|
|
153655
|
+
}
|
|
153564
153656
|
let hubWired = false;
|
|
153565
153657
|
function wireHub(hub) {
|
|
153566
153658
|
if (hubWired) return;
|
|
@@ -153770,30 +153862,23 @@ function nodesDomain(deps) {
|
|
|
153770
153862
|
return { status: 200, body: { ok: true } };
|
|
153771
153863
|
});
|
|
153772
153864
|
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 } };
|
|
153865
|
+
return { status: 200, body: await resolveLatestDaemonVersion() };
|
|
153788
153866
|
});
|
|
153789
153867
|
router.post("/api/nodes/:nodeId/update", async (req) => {
|
|
153790
153868
|
const nodeId = req.params["nodeId"];
|
|
153791
153869
|
if (!nodeId) return { status: 400, body: { error: "missing nodeId" } };
|
|
153792
153870
|
const hub = deps.getHub();
|
|
153793
153871
|
if (!hub) return { status: 503, body: { error: "node gateway \u672A\u5C31\u7EEA" } };
|
|
153872
|
+
const daemon = hub.connectedDaemons().find((d) => d.daemonId === nodeId);
|
|
153873
|
+
if (!daemon) return { status: 409, body: { error: `\u8282\u70B9 ${nodeId} \u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u65E0\u6CD5\u66F4\u65B0` } };
|
|
153874
|
+
const current = daemon.meta.daemonVersion;
|
|
153875
|
+
const { version: latest } = await resolveLatestDaemonVersion();
|
|
153876
|
+
if (latest && current && !daemonVersionLess(current, latest)) {
|
|
153877
|
+
return { status: 200, body: { ok: true, alreadyLatest: true, version: current } };
|
|
153878
|
+
}
|
|
153794
153879
|
const sent = hub.dispatch(nodeId, { type: "update" });
|
|
153795
153880
|
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 } };
|
|
153881
|
+
return { status: 200, body: { ok: true, alreadyLatest: false } };
|
|
153797
153882
|
});
|
|
153798
153883
|
router.delete("/api/runtimes/:runtimeId", async (req) => {
|
|
153799
153884
|
const runtimeId = req.params["runtimeId"];
|
|
@@ -164189,19 +164274,19 @@ var init_trajectory = __esm({
|
|
|
164189
164274
|
|
|
164190
164275
|
// src/index.ts
|
|
164191
164276
|
var fs26 = __toESM(require("node:fs"));
|
|
164192
|
-
var
|
|
164277
|
+
var os9 = __toESM(require("node:os"));
|
|
164193
164278
|
var path21 = __toESM(require("node:path"));
|
|
164194
164279
|
var import_node_child_process15 = require("node:child_process");
|
|
164195
164280
|
|
|
164196
164281
|
// ../cli/src/cli.ts
|
|
164197
164282
|
var fs25 = __toESM(require("node:fs"), 1);
|
|
164198
|
-
var
|
|
164283
|
+
var os8 = __toESM(require("node:os"), 1);
|
|
164199
164284
|
var path20 = __toESM(require("node:path"), 1);
|
|
164200
164285
|
var import_node_crypto31 = require("node:crypto");
|
|
164201
164286
|
|
|
164202
164287
|
// ../cli/src/serve.ts
|
|
164203
164288
|
var fs23 = __toESM(require("node:fs"), 1);
|
|
164204
|
-
var
|
|
164289
|
+
var os5 = __toESM(require("node:os"), 1);
|
|
164205
164290
|
var path18 = __toESM(require("node:path"), 1);
|
|
164206
164291
|
var import_node_crypto28 = require("node:crypto");
|
|
164207
164292
|
var import_node_url4 = require("node:url");
|
|
@@ -168088,6 +168173,62 @@ function refreshConnectorSkillsInBackground(dataDir, apply) {
|
|
|
168088
168173
|
})();
|
|
168089
168174
|
}
|
|
168090
168175
|
var SESSION_TOKEN_GRACE_MS = 15 * 6e4;
|
|
168176
|
+
function makeResumeRetryProxy(first, spawnFallback) {
|
|
168177
|
+
const outCbs = [];
|
|
168178
|
+
const telCbs = [];
|
|
168179
|
+
const outBuf = [];
|
|
168180
|
+
const telBuf = [];
|
|
168181
|
+
let sawOutput = false;
|
|
168182
|
+
let active = first;
|
|
168183
|
+
const fanOut = (chunk) => {
|
|
168184
|
+
if (outCbs.length) for (const cb of outCbs) cb(chunk);
|
|
168185
|
+
else outBuf.push(chunk);
|
|
168186
|
+
};
|
|
168187
|
+
const fanTel = (e) => {
|
|
168188
|
+
if (telCbs.length) for (const cb of telCbs) cb(e);
|
|
168189
|
+
else telBuf.push(e);
|
|
168190
|
+
};
|
|
168191
|
+
const wire = (s2) => {
|
|
168192
|
+
s2.onOutput((c) => {
|
|
168193
|
+
sawOutput = true;
|
|
168194
|
+
fanOut(c);
|
|
168195
|
+
});
|
|
168196
|
+
s2.onTelemetry?.((e) => fanTel(e));
|
|
168197
|
+
};
|
|
168198
|
+
wire(first);
|
|
168199
|
+
const isSessionNotFound = (err) => {
|
|
168200
|
+
const chatExit = err instanceof Error ? err.chatExit : void 0;
|
|
168201
|
+
return chatExit?.reason === "session-not-found";
|
|
168202
|
+
};
|
|
168203
|
+
const done = first.done.catch(async (err) => {
|
|
168204
|
+
if (sawOutput || !isSessionNotFound(err)) throw err;
|
|
168205
|
+
const second = await spawnFallback();
|
|
168206
|
+
active = second;
|
|
168207
|
+
wire(second);
|
|
168208
|
+
await second.done;
|
|
168209
|
+
});
|
|
168210
|
+
return {
|
|
168211
|
+
get id() {
|
|
168212
|
+
return active.id;
|
|
168213
|
+
},
|
|
168214
|
+
get runId() {
|
|
168215
|
+
return active.runId;
|
|
168216
|
+
},
|
|
168217
|
+
onOutput(cb) {
|
|
168218
|
+
for (const c of outBuf.splice(0)) cb(c);
|
|
168219
|
+
outCbs.push(cb);
|
|
168220
|
+
},
|
|
168221
|
+
onTelemetry(cb) {
|
|
168222
|
+
for (const e of telBuf.splice(0)) cb(e);
|
|
168223
|
+
telCbs.push(cb);
|
|
168224
|
+
},
|
|
168225
|
+
done,
|
|
168226
|
+
kill: () => active.kill?.() ?? Promise.resolve(),
|
|
168227
|
+
get nativeSessionId() {
|
|
168228
|
+
return active.nativeSessionId;
|
|
168229
|
+
}
|
|
168230
|
+
};
|
|
168231
|
+
}
|
|
168091
168232
|
function normalizeHttpBaseUrl(raw) {
|
|
168092
168233
|
const url = new URL(raw);
|
|
168093
168234
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
@@ -168111,13 +168252,37 @@ function apiUrlFromGatewayUrl(raw) {
|
|
|
168111
168252
|
return void 0;
|
|
168112
168253
|
}
|
|
168113
168254
|
}
|
|
168255
|
+
var NODE_DAEMON_PKG = "oasis_test";
|
|
168256
|
+
var NPM_LATEST_TTL_MS = 5 * 6e4;
|
|
168257
|
+
var npmLatestCache = null;
|
|
168258
|
+
async function fetchLatestNpmDaemonVersion() {
|
|
168259
|
+
if (npmLatestCache && Date.now() - npmLatestCache.atMs < NPM_LATEST_TTL_MS) return npmLatestCache.version;
|
|
168260
|
+
let version2 = null;
|
|
168261
|
+
try {
|
|
168262
|
+
const ctrl = new AbortController();
|
|
168263
|
+
const timer = setTimeout(() => ctrl.abort(), 3e3);
|
|
168264
|
+
try {
|
|
168265
|
+
const resp = await fetch(`https://registry.npmjs.org/${NODE_DAEMON_PKG}/latest`, { signal: ctrl.signal });
|
|
168266
|
+
if (resp.ok) {
|
|
168267
|
+
const body = await resp.json();
|
|
168268
|
+
version2 = typeof body.version === "string" ? body.version : null;
|
|
168269
|
+
}
|
|
168270
|
+
} finally {
|
|
168271
|
+
clearTimeout(timer);
|
|
168272
|
+
}
|
|
168273
|
+
} catch {
|
|
168274
|
+
version2 = null;
|
|
168275
|
+
}
|
|
168276
|
+
if (version2) npmLatestCache = { version: version2, atMs: Date.now() };
|
|
168277
|
+
return version2;
|
|
168278
|
+
}
|
|
168114
168279
|
var oasisWrapperCache;
|
|
168115
168280
|
function oasisWrapperScript() {
|
|
168116
168281
|
if (oasisWrapperCache && fs23.existsSync(oasisWrapperCache)) return oasisWrapperCache;
|
|
168117
168282
|
const repoRoot = (0, import_node_url4.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
|
|
168118
168283
|
const tsx = path18.join(repoRoot, "node_modules/.bin/tsx");
|
|
168119
168284
|
const main = path18.join(repoRoot, "packages/cli/src/main.ts");
|
|
168120
|
-
const dir = fs23.mkdtempSync(path18.join(
|
|
168285
|
+
const dir = fs23.mkdtempSync(path18.join(os5.tmpdir(), "oasis-cli-"));
|
|
168121
168286
|
const wrapper = path18.join(dir, "oasis");
|
|
168122
168287
|
fs23.writeFileSync(wrapper, `#!/usr/bin/env bash
|
|
168123
168288
|
exec ${JSON.stringify(tsx)} ${JSON.stringify(main)} "$@"
|
|
@@ -168328,7 +168493,7 @@ async function startServe(opts) {
|
|
|
168328
168493
|
`[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
168494
|
);
|
|
168330
168495
|
const issuer = createTokenIssuer({ secretFile: path18.join(opts.dir, "session-token-secret") });
|
|
168331
|
-
const operatorActor = `actor:human:${
|
|
168496
|
+
const operatorActor = `actor:human:${os5.userInfo().username}`;
|
|
168332
168497
|
const operatorToken = issuer.issue(operatorActor);
|
|
168333
168498
|
fs23.writeFileSync(path18.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
|
|
168334
168499
|
let nodeTokens = createNodeTokenStore(path18.join(opts.dir, "node-tokens.json"));
|
|
@@ -168814,7 +168979,8 @@ async function startServe(opts) {
|
|
|
168814
168979
|
gatewayUrl: opts.gatewayUrl ?? `ws://127.0.0.1:${opts.port ?? 7320}/node-gateway`,
|
|
168815
168980
|
repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git",
|
|
168816
168981
|
nodeHealth,
|
|
168817
|
-
activeRunCountOf
|
|
168982
|
+
activeRunCountOf,
|
|
168983
|
+
fetchLatestNpmDaemonVersion
|
|
168818
168984
|
}),
|
|
168819
168985
|
collabDomain({
|
|
168820
168986
|
kernel,
|
|
@@ -168893,301 +169059,309 @@ async function startServe(opts) {
|
|
|
168893
169059
|
discussSessions: new FileSideMap(path18.join(opts.dir, "discuss-sessions.json")),
|
|
168894
169060
|
escalateDiscussRetain: new FileSideMap(path18.join(opts.dir, "escalate-discuss-retain.json")),
|
|
168895
169061
|
// 切片 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();
|
|
169062
|
+
dispatchChat: async (chatReq) => {
|
|
169063
|
+
const dispatchChatImpl = async ({ actorId, message, sessionId, chatSessionId, attachments, workspace, companyId }) => {
|
|
169064
|
+
const runCompanyId = companyId ?? defaultCompanyId;
|
|
169065
|
+
const actorCtxForCompany = await actors.resolveCtx(runCompanyId);
|
|
169066
|
+
const actorService = actorCtxForCompany.service;
|
|
169067
|
+
const binding = await actorService.resolveBinding()(actorId);
|
|
169068
|
+
if (!binding) {
|
|
169069
|
+
throw new ApiError(409, "ACTOR_BINDING_MISSING", `\u6570\u5B57\u5458\u5DE5 ${actorId} \u6CA1\u6709 active runtime \u7ED1\u5B9A`);
|
|
169070
|
+
}
|
|
169071
|
+
const node = hub?.connectedDaemons().find((d) => d.daemonId === binding.nodeId);
|
|
169072
|
+
if (!node) {
|
|
169073
|
+
throw new ApiError(409, "NODE_OFFLINE", `\u7ED1\u5B9A\u8282\u70B9 ${binding.nodeId} \u5F53\u524D\u4E0D\u5728\u7EBF`);
|
|
169074
|
+
}
|
|
169075
|
+
if (!node.meta.adapters.includes(binding.runtimeKind)) {
|
|
169076
|
+
throw new ApiError(409, "RUNTIME_UNAVAILABLE", `\u8282\u70B9 ${binding.nodeId} \u672A\u4E0A\u62A5\u8FD0\u884C\u65F6 ${binding.runtimeKind}`);
|
|
169077
|
+
}
|
|
169078
|
+
if (!chatRemoteAdapter) {
|
|
169079
|
+
throw new ApiError(503, "NODE_GATEWAY_NOT_READY", "node-gateway \u5C1A\u672A\u5C31\u7EEA");
|
|
169080
|
+
}
|
|
169081
|
+
if (!localUrl) {
|
|
169082
|
+
throw new ApiError(503, "SERVER_URL_NOT_READY", "server URL \u5C1A\u672A\u5C31\u7EEA");
|
|
169083
|
+
}
|
|
169084
|
+
const priorChatSession = chatSessionId ? await chatSessionStore?.getSession(chatSessionId).catch(() => null) : null;
|
|
169085
|
+
const freshChatWorkdir = chatSessionId ? chatNodeChanged(
|
|
169086
|
+
{ nodeId: priorChatSession?.runtimeId, runtimeKind: priorChatSession?.runtimeKind },
|
|
169087
|
+
{ nodeId: binding.nodeId, runtimeKind: binding.runtimeKind }
|
|
169088
|
+
) : false;
|
|
169089
|
+
const runtimeSessionId = sessionId ?? (0, import_node_crypto28.randomUUID)();
|
|
169090
|
+
const resumeRuntimeSession = Boolean(sessionId);
|
|
169091
|
+
const traceRunId = `chat-run:${(0, import_node_crypto28.randomUUID)()}`;
|
|
169092
|
+
const artifactId = `artifact:chat:${(0, import_node_crypto28.randomUUID)()}`;
|
|
169093
|
+
const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
169094
|
+
let traceSeq = 0;
|
|
169095
|
+
let lastProgressTouchMs = 0;
|
|
169096
|
+
const PROGRESS_TOUCH_THROTTLE_MS2 = 2e4;
|
|
169097
|
+
let traceEnabled = true;
|
|
169098
|
+
const analyzedRunId = chatSessionId ? (await chatSessionStore.getSession(chatSessionId).catch(() => null))?.analyzedRunId ?? void 0 : void 0;
|
|
169099
|
+
let traceChain = traceStore.createRun({
|
|
169100
|
+
id: traceRunId,
|
|
169101
|
+
actorId,
|
|
169102
|
+
runtimeKind: traceRuntimeKind(binding.runtimeKind),
|
|
169103
|
+
runtimeInstanceId: `runtime:${binding.nodeId}:${binding.runtimeKind}`,
|
|
169104
|
+
triggerKind: "api",
|
|
169105
|
+
triggerRef: runtimeSessionId,
|
|
169106
|
+
jobKey: runtimeSessionId,
|
|
169107
|
+
artifactId,
|
|
169108
|
+
action: "chat",
|
|
169109
|
+
startedAt: traceStartedAt,
|
|
169110
|
+
metadata: {
|
|
169111
|
+
runtimeSessionId,
|
|
169112
|
+
nodeId: binding.nodeId,
|
|
169113
|
+
runtimeKind: binding.runtimeKind,
|
|
169114
|
+
messagePreview: message.slice(0, 500),
|
|
169115
|
+
...analyzedRunId ? { analyzedRunId } : {}
|
|
169116
|
+
}
|
|
169117
|
+
}).then(async () => {
|
|
169118
|
+
await traceStore.appendEvents(traceRunId, [
|
|
169119
|
+
{
|
|
169120
|
+
seq: ++traceSeq,
|
|
169121
|
+
eventType: "run.started",
|
|
169122
|
+
stream: "runtime",
|
|
169123
|
+
message: `chat ${actorId}`,
|
|
169124
|
+
startedAt: traceStartedAt
|
|
169125
|
+
},
|
|
169126
|
+
{
|
|
169127
|
+
seq: ++traceSeq,
|
|
169128
|
+
eventType: "input.message",
|
|
169129
|
+
stream: "model",
|
|
169130
|
+
actorId,
|
|
169131
|
+
message: message.slice(0, 500),
|
|
169132
|
+
payload: { text: message },
|
|
169133
|
+
startedAt: traceStartedAt
|
|
169134
|
+
}
|
|
169135
|
+
]);
|
|
168977
169136
|
}).catch((err) => {
|
|
168978
169137
|
traceEnabled = false;
|
|
168979
|
-
console.warn(`[trace] chat run
|
|
169138
|
+
console.warn(`[trace] chat run create failed: ${String(err)}`);
|
|
168980
169139
|
});
|
|
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
|
-
|
|
169140
|
+
const enqueueTrace = (step) => {
|
|
169141
|
+
if (!traceEnabled) return;
|
|
169142
|
+
traceChain = traceChain.then(async () => {
|
|
169143
|
+
if (traceEnabled) await step();
|
|
169144
|
+
}).catch((err) => {
|
|
169145
|
+
traceEnabled = false;
|
|
169146
|
+
console.warn(`[trace] chat run ${traceRunId} failed: ${String(err)}`);
|
|
169147
|
+
});
|
|
169148
|
+
};
|
|
169149
|
+
const provision = await buildActorProvision(actorService, actorId);
|
|
169150
|
+
const actorCtx = await buildActorContext(actorService, actorId).catch(() => null);
|
|
169151
|
+
const chatResolvedModel = (() => {
|
|
169152
|
+
if (actorCtx?.config?.model) return actorCtx.config.model;
|
|
169153
|
+
return void 0;
|
|
169154
|
+
})();
|
|
169155
|
+
const chatModel = chatResolvedModel ?? await registryStore.getRuntimeConfig(`runtime:${binding.nodeId}:${binding.runtimeKind}`).then((c) => c?.model).catch(() => void 0) ?? void 0;
|
|
169156
|
+
const chatModelSource = chatResolvedModel ? "actor_config" : chatModel ? "runtime_default" : null;
|
|
169157
|
+
const attachmentFiles = {};
|
|
169158
|
+
const attachmentBinary = {};
|
|
169159
|
+
const attachmentPaths = [];
|
|
169160
|
+
const usedRel = /* @__PURE__ */ new Set();
|
|
169161
|
+
for (const att of attachments ?? []) {
|
|
169162
|
+
const safe = (att.name || "attachment").replace(/[^\w.\-]+/g, "_").replace(/^\.+/, "").slice(0, 80) || "attachment";
|
|
169163
|
+
let rel = `inputs/attachments/${safe}`;
|
|
169164
|
+
let n = 1;
|
|
169165
|
+
while (usedRel.has(rel)) rel = `inputs/attachments/${n++}-${safe}`;
|
|
169166
|
+
usedRel.add(rel);
|
|
169167
|
+
if (typeof att.text === "string") {
|
|
169168
|
+
attachmentFiles[rel] = att.text;
|
|
169007
169169
|
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}`)] : [],
|
|
169170
|
+
} else if (att.blobRef) {
|
|
169171
|
+
try {
|
|
169172
|
+
const bytes = await assets.get(att.blobRef);
|
|
169173
|
+
attachmentBinary[rel] = Buffer.from(bytes).toString("base64");
|
|
169174
|
+
attachmentPaths.push(rel);
|
|
169175
|
+
} catch (err) {
|
|
169176
|
+
console.warn(`[chat] \u9644\u4EF6 blob ${att.blobRef} \u8BFB\u53D6\u5931\u8D25: ${String(err)}`);
|
|
169177
|
+
}
|
|
169178
|
+
}
|
|
169179
|
+
}
|
|
169180
|
+
const sessionLine = chatSessionId ? `chat_session_id: ${chatSessionId}` : `runtime_session_id: ${runtimeSessionId}`;
|
|
169181
|
+
const taskHeader = workspace ? [
|
|
169182
|
+
"# \u4E0E\u5DE5\u5355\u7BA1\u7406\u8005\u5BF9\u8BDD",
|
|
169034
169183
|
"",
|
|
169035
|
-
|
|
169184
|
+
sessionLine,
|
|
169185
|
+
`actor_id: ${actorId}`,
|
|
169186
|
+
`workspace: ${workspace}`,
|
|
169036
169187
|
"",
|
|
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
|
-
|
|
169188
|
+
CONVERSATIONAL_MANAGER_BODY
|
|
169189
|
+
] : [
|
|
169190
|
+
"# \u5373\u65F6\u8111\u66B4\u5BF9\u8BDD",
|
|
169191
|
+
"",
|
|
169192
|
+
sessionLine,
|
|
169193
|
+
`actor_id: ${actorId}`,
|
|
169194
|
+
"",
|
|
169195
|
+
"\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"
|
|
169196
|
+
];
|
|
169197
|
+
const files = {
|
|
169198
|
+
"TASK.md": [
|
|
169199
|
+
...taskHeader,
|
|
169200
|
+
...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}`)] : [],
|
|
169201
|
+
"",
|
|
169202
|
+
"## \u7528\u6237\u6D88\u606F",
|
|
169203
|
+
"",
|
|
169204
|
+
message
|
|
169205
|
+
].join("\n")
|
|
169206
|
+
};
|
|
169207
|
+
Object.assign(files, attachmentFiles);
|
|
169208
|
+
if (actorCtx?.config?.prompt) {
|
|
169209
|
+
Object.assign(files, splitIdentityFiles3(actorCtx.config.prompt));
|
|
169210
|
+
}
|
|
169211
|
+
if (!SKILL_CACHE_RUNTIMES.has(binding.runtimeKind)) {
|
|
169212
|
+
Object.assign(files, materializeBuiltins(builtinSkills, binding.runtimeKind));
|
|
169213
|
+
Object.assign(files, await materializeSkillFiles({
|
|
169214
|
+
service: actorService,
|
|
169215
|
+
actorId,
|
|
169216
|
+
runtimeKind: binding.runtimeKind
|
|
169217
|
+
}).catch((err) => {
|
|
169218
|
+
console.warn(`[chat] skill materialize failed for ${actorId}: ${String(err)}`);
|
|
169219
|
+
return {};
|
|
169220
|
+
}));
|
|
169221
|
+
}
|
|
169222
|
+
const limits = { wallClockMs: SESSION_WALL_CLOCK_MS.chat };
|
|
169223
|
+
const handle = await chatRemoteAdapter.spawn({
|
|
169224
|
+
actor: actorId,
|
|
169225
|
+
actorToken: issueSessionToken(actorId, { artifactId, action: "chat", limits, binding, sessionId: runtimeSessionId, companyId: runCompanyId, ...chatSessionId !== void 0 ? { chatSessionId } : {} }),
|
|
169226
|
+
artifactId,
|
|
169227
|
+
bundle: { files, ...Object.keys(attachmentBinary).length ? { binaryFiles: attachmentBinary } : {} },
|
|
169228
|
+
...actorCtx?.config?.prompt ? { systemPrompt: actorCtx.config.prompt } : {},
|
|
169229
|
+
...chatModel ? { model: chatModel } : {},
|
|
169230
|
+
// ADR-0053 D1:chat 的**会话线 id 是 chatSessionId**(Oasis 命名空间、跨轮不变),不是 rtId
|
|
169231
|
+
// (rtId 跨轮会变:换节点时服务端主动清掉它、codex/ACP 还会自己另分配)。
|
|
169232
|
+
//
|
|
169233
|
+
// 没有 chatSessionId → **不给 workdirKey** → 落 one-shot,这是契约的直接应用而不是折中:
|
|
169234
|
+
// 服务端对这种请求也不落库消息(persistTarget 要求 chatSessionId),没有会话线、没有历史,
|
|
169235
|
+
// 本就没什么可续的。产品路径跑不到这条分支(前端三个调用方都保证先建会话再传),只兜住
|
|
169236
|
+
// 裸 API 调用。
|
|
169237
|
+
...chatSessionId ? { workdirKey: `chat:${chatSessionId}` } : {},
|
|
169238
|
+
// 与上一条成对:稳定目录一上,A→B→A 回到 node1 就会撞见同名目录里 A 自己 N 轮前的陈旧
|
|
169239
|
+
// 文件(而注入的历史正告诉它「B 改了 X」)。切根前没这问题纯属侥幸——那时换节点会清掉
|
|
169240
|
+
// rtId、rtId 又是目录名,"新目录"是副产品;稳定目录一上,侥幸就没了。
|
|
169241
|
+
//
|
|
169242
|
+
// **在这儿算,不放进 ChatDispatchRequest**:本函数是唯一同时握着 binding 与 chatSessionId
|
|
169243
|
+
// 的地方,四个调用方(/api/chat、discuss、飞书入站、草案评审通知)全覆盖且谁都不用记得
|
|
169244
|
+
// 传。放进契约就等于要求每个调用方自己算,而其中三个压根不碰 binding。
|
|
169245
|
+
...freshChatWorkdir ? { freshWorkdir: true } : {},
|
|
169246
|
+
runtimeSessionId,
|
|
169247
|
+
resumeRuntimeSession,
|
|
169248
|
+
server: { url: serverUrlForBinding(binding) },
|
|
169249
|
+
binding,
|
|
169250
|
+
limits,
|
|
169251
|
+
// OASIS_STAGE=1:chat agent 的改图命令(edit/link/spawn/cancel)经 /api/stage → 草案路由
|
|
169252
|
+
// (建单/改图暂存统一,见 docs/proposals/draft-edit-unification.md)。
|
|
169253
|
+
// OASIS_WORKSPACE:给定工单(协调者对话)时绑上——staged 编辑的 type:title 在本工单范围解析,
|
|
169254
|
+
// 产出的草案 plan.workspace = 本工单,前端「待确认变更」按工单过滤才抓得到。普通脑暴不传,保持不绑。
|
|
169255
|
+
env: {
|
|
169256
|
+
...provision.env,
|
|
169257
|
+
OASIS_STAGE: "1",
|
|
169258
|
+
...chatSessionId ? { OASIS_CHAT_SESSION_ID: chatSessionId } : {},
|
|
169259
|
+
...workspace ? { OASIS_WORKSPACE: workspace } : {}
|
|
169260
|
+
},
|
|
169261
|
+
wrapperPaths: provision.wrapperPaths,
|
|
169262
|
+
...provision.requiredTools.length > 0 ? { requiredTools: provision.requiredTools } : {}
|
|
169108
169263
|
});
|
|
169109
|
-
|
|
169110
|
-
|
|
169111
|
-
|
|
169112
|
-
|
|
169113
|
-
|
|
169114
|
-
|
|
169115
|
-
|
|
169116
|
-
|
|
169117
|
-
|
|
169118
|
-
|
|
169119
|
-
|
|
169120
|
-
|
|
169121
|
-
|
|
169122
|
-
|
|
169123
|
-
|
|
169124
|
-
|
|
169125
|
-
|
|
169264
|
+
const chatJobKey = `chat::${artifactId}`;
|
|
169265
|
+
chatLiveSessions.set(chatJobKey, { artifactId, sessionId: traceRunId, dispatchId: handle.id, kill: () => handle.kill() });
|
|
169266
|
+
enqueueTrace(async () => {
|
|
169267
|
+
const run = await traceStore.getRun(traceRunId);
|
|
169268
|
+
if (!run) return;
|
|
169269
|
+
const base = run.metadata && typeof run.metadata === "object" && !Array.isArray(run.metadata) ? run.metadata : {};
|
|
169270
|
+
await traceStore.updateRun(traceRunId, {
|
|
169271
|
+
metadata: { ...base, dispatchId: handle.id },
|
|
169272
|
+
// 恢复路径拿不到 dispatchChat 闭包里的 fallback 解析结果,开跑时先写进账本;退出帧若上报
|
|
169273
|
+
// 更精确 model 仍会覆盖为 runtime 来源。
|
|
169274
|
+
...chatModel ? { effectiveModel: chatModel, modelSource: chatModelSource } : {}
|
|
169275
|
+
});
|
|
169276
|
+
});
|
|
169277
|
+
const buffered = [];
|
|
169278
|
+
const bufferedTelemetry = [];
|
|
169279
|
+
const outputCbs = [];
|
|
169280
|
+
const telemetryCbs = [];
|
|
169281
|
+
handle.onOutput?.((chunk) => {
|
|
169282
|
+
if (outputCbs.length === 0) buffered.push(chunk);
|
|
169283
|
+
for (const cb of outputCbs) cb(chunk);
|
|
169284
|
+
});
|
|
169285
|
+
handle.onTelemetry?.((event) => {
|
|
169286
|
+
if (telemetryCbs.length === 0) bufferedTelemetry.push(event);
|
|
169287
|
+
for (const cb of telemetryCbs) cb(event);
|
|
169288
|
+
if (event.kind === "system") {
|
|
169289
|
+
const ms = Date.parse(event.ts);
|
|
169290
|
+
if (!Number.isNaN(ms) && ms - lastProgressTouchMs >= PROGRESS_TOUCH_THROTTLE_MS2) {
|
|
169291
|
+
lastProgressTouchMs = ms;
|
|
169292
|
+
enqueueTrace(() => traceStore.updateRun(traceRunId, { lastProgressAt: event.ts }).then(() => void 0));
|
|
169293
|
+
}
|
|
169294
|
+
return;
|
|
169126
169295
|
}
|
|
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
|
-
|
|
169296
|
+
enqueueTrace(() => traceStore.appendEvents(traceRunId, [trajectoryEventToRunEvent(event, ++traceSeq)]).then(() => void 0));
|
|
169297
|
+
});
|
|
169298
|
+
let capturedNativeSessionId;
|
|
169299
|
+
const done = new Promise((resolve5, reject) => {
|
|
169300
|
+
handle.onExit((info) => {
|
|
169301
|
+
chatLiveSessions.delete(chatJobKey);
|
|
169302
|
+
void provision.cleanup();
|
|
169303
|
+
const endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
169304
|
+
const durationMs = Date.parse(endedAt) - Date.parse(traceStartedAt);
|
|
169305
|
+
if (info.runtimeSessionId) capturedNativeSessionId = info.runtimeSessionId;
|
|
169306
|
+
enqueueTrace(async () => {
|
|
169307
|
+
await traceStore.appendEvents(traceRunId, [{
|
|
169308
|
+
seq: ++traceSeq,
|
|
169309
|
+
eventType: "run.finished",
|
|
169310
|
+
stream: "runtime",
|
|
169311
|
+
message: `exit code=${info.code ?? "killed"}`,
|
|
169312
|
+
startedAt: endedAt
|
|
169313
|
+
}]);
|
|
169314
|
+
const usage = info.usage ?? null;
|
|
169315
|
+
const effectiveModel = info.model ?? chatModel ?? null;
|
|
169316
|
+
const modelSource = info.model ? "runtime" : chatModelSource;
|
|
169317
|
+
await traceStore.updateRun(traceRunId, {
|
|
169318
|
+
status: info.reason === "timeout" ? "timeout" : info.reason === "cancelled" ? "cancelled" : info.code === 0 ? "succeeded" : "failed",
|
|
169319
|
+
endedAt,
|
|
169320
|
+
durationMs,
|
|
169321
|
+
exitCode: info.code,
|
|
169322
|
+
exitReason: info.reason ?? null,
|
|
169323
|
+
transcriptRef: info.transcriptRef ?? null,
|
|
169324
|
+
usage,
|
|
169325
|
+
effectiveModel,
|
|
169326
|
+
modelSource
|
|
169327
|
+
});
|
|
169328
|
+
if (usage && traceStore.updateUsageAggregates) {
|
|
169329
|
+
const run = await traceStore.getRun(traceRunId);
|
|
169330
|
+
if (run) void traceStore.updateUsageAggregates(run).catch(() => {
|
|
169331
|
+
});
|
|
169332
|
+
}
|
|
169160
169333
|
});
|
|
169161
|
-
|
|
169162
|
-
|
|
169163
|
-
|
|
169164
|
-
|
|
169334
|
+
const failed = info.code !== 0 || info.reason !== void 0 && info.reason !== "clean";
|
|
169335
|
+
if (!failed) resolve5();
|
|
169336
|
+
else {
|
|
169337
|
+
reject(buildChatExitError(info));
|
|
169165
169338
|
}
|
|
169166
169339
|
});
|
|
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
169340
|
});
|
|
169173
|
-
|
|
169174
|
-
|
|
169175
|
-
|
|
169176
|
-
|
|
169177
|
-
|
|
169178
|
-
|
|
169179
|
-
|
|
169180
|
-
|
|
169181
|
-
|
|
169182
|
-
|
|
169183
|
-
|
|
169184
|
-
|
|
169185
|
-
|
|
169186
|
-
|
|
169187
|
-
|
|
169188
|
-
|
|
169189
|
-
}
|
|
169341
|
+
return {
|
|
169342
|
+
id: runtimeSessionId,
|
|
169343
|
+
runId: traceRunId,
|
|
169344
|
+
onOutput(cb) {
|
|
169345
|
+
for (const chunk of buffered.splice(0)) cb(chunk);
|
|
169346
|
+
outputCbs.push(cb);
|
|
169347
|
+
},
|
|
169348
|
+
onTelemetry(cb) {
|
|
169349
|
+
for (const event of bufferedTelemetry.splice(0)) cb(event);
|
|
169350
|
+
telemetryCbs.push(cb);
|
|
169351
|
+
},
|
|
169352
|
+
done,
|
|
169353
|
+
kill: () => handle.kill(),
|
|
169354
|
+
get nativeSessionId() {
|
|
169355
|
+
return capturedNativeSessionId;
|
|
169356
|
+
}
|
|
169357
|
+
};
|
|
169190
169358
|
};
|
|
169359
|
+
const first = await dispatchChatImpl(chatReq);
|
|
169360
|
+
if (!chatReq.fallbackMessage || !chatReq.sessionId) return first;
|
|
169361
|
+
return makeResumeRetryProxy(
|
|
169362
|
+
first,
|
|
169363
|
+
() => dispatchChatImpl({ ...chatReq, sessionId: void 0, fallbackMessage: void 0, message: chatReq.fallbackMessage })
|
|
169364
|
+
);
|
|
169191
169365
|
},
|
|
169192
169366
|
trajectoryFeed: {
|
|
169193
169367
|
subscribe(sessionId, listener) {
|
|
@@ -170673,7 +170847,7 @@ async function runCli(argv, println = console.log) {
|
|
|
170673
170847
|
const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
|
|
170674
170848
|
method: "POST",
|
|
170675
170849
|
headers: { "content-type": "application/json" },
|
|
170676
|
-
body: JSON.stringify({ enrollToken, nodeId, hostname:
|
|
170850
|
+
body: JSON.stringify({ enrollToken, nodeId, hostname: os8.hostname() })
|
|
170677
170851
|
});
|
|
170678
170852
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
170679
170853
|
const body = await res.json();
|
|
@@ -170706,7 +170880,7 @@ async function runCli(argv, println = console.log) {
|
|
|
170706
170880
|
const binPath = path20.join(prefix, "bin", "oasis_test");
|
|
170707
170881
|
const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
|
|
170708
170882
|
if (process.platform === "linux") {
|
|
170709
|
-
const svcFile = path20.join(
|
|
170883
|
+
const svcFile = path20.join(os8.homedir(), ".config/systemd/user/oasis-node.service");
|
|
170710
170884
|
fs25.mkdirSync(path20.dirname(svcFile), { recursive: true });
|
|
170711
170885
|
if (spawnSync("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
|
|
170712
170886
|
spawnSync("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
|
|
@@ -170719,7 +170893,7 @@ async function runCli(argv, println = console.log) {
|
|
|
170719
170893
|
`ExecStart=${binPath} ${svcArgs}`,
|
|
170720
170894
|
// Carry the install-time PATH so the detached daemon detects CLIs in user dirs
|
|
170721
170895
|
// (~/.npm-global/bin, ~/.local/bin) — systemd --user otherwise gives a minimal PATH.
|
|
170722
|
-
`Environment=PATH=${process.env["PATH"] ?? ""}:${path20.join(
|
|
170896
|
+
`Environment=PATH=${process.env["PATH"] ?? ""}:${path20.join(os8.homedir(), ".npm-global/bin")}:${path20.join(os8.homedir(), ".local/bin")}:/usr/local/bin`,
|
|
170723
170897
|
"Restart=on-failure",
|
|
170724
170898
|
"RestartSec=5",
|
|
170725
170899
|
"StandardOutput=journal",
|
|
@@ -170731,23 +170905,23 @@ async function runCli(argv, println = console.log) {
|
|
|
170731
170905
|
].join("\n"));
|
|
170732
170906
|
spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
|
|
170733
170907
|
spawnSync("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
|
|
170734
|
-
spawnSync("loginctl", ["enable-linger",
|
|
170908
|
+
spawnSync("loginctl", ["enable-linger", os8.userInfo().username], { stdio: "ignore" });
|
|
170735
170909
|
println("\u2713 Oasis node service started (systemd --user oasis-node)");
|
|
170736
170910
|
println(" Status : systemctl --user status oasis-node");
|
|
170737
170911
|
println(" Logs : journalctl --user -u oasis-node -f");
|
|
170738
170912
|
println(" Stop : systemctl --user stop oasis-node");
|
|
170739
170913
|
} else if (process.platform === "darwin") {
|
|
170740
|
-
const plist = path20.join(
|
|
170914
|
+
const plist = path20.join(os8.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
|
|
170741
170915
|
fs25.mkdirSync(path20.dirname(plist), { recursive: true });
|
|
170742
170916
|
spawnSync("launchctl", ["unload", plist], { stdio: "ignore" });
|
|
170743
170917
|
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>${
|
|
170918
|
+
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
170919
|
spawnSync("launchctl", ["load", plist], { stdio: "inherit" });
|
|
170746
170920
|
println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
|
|
170747
|
-
println(` Logs : tail -f ${
|
|
170921
|
+
println(` Logs : tail -f ${os8.homedir()}/.oasis-node.log`);
|
|
170748
170922
|
println(` Stop : launchctl unload ${plist}`);
|
|
170749
170923
|
} else {
|
|
170750
|
-
spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path20.join(
|
|
170924
|
+
spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path20.join(os8.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
|
|
170751
170925
|
println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
|
|
170752
170926
|
println(" Note: no automatic restart on reboot in this environment.");
|
|
170753
170927
|
}
|
|
@@ -170818,8 +170992,8 @@ async function runCli(argv, println = console.log) {
|
|
|
170818
170992
|
if (command === "serve" && positional[0] === "install") {
|
|
170819
170993
|
const absDir = path20.resolve(dir);
|
|
170820
170994
|
const name = `oasis-serve-${path20.basename(absDir)}`;
|
|
170821
|
-
const unitDir = flags.get("unit-dir") ?? path20.join(
|
|
170822
|
-
const bin = flags.get("bin") ?? path20.join(
|
|
170995
|
+
const unitDir = flags.get("unit-dir") ?? path20.join(os8.homedir(), ".config", "systemd", "user");
|
|
170996
|
+
const bin = flags.get("bin") ?? path20.join(os8.homedir(), ".local", "bin", "oasis");
|
|
170823
170997
|
const port = flags.get("port") ?? "7320";
|
|
170824
170998
|
const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
|
|
170825
170999
|
const unit = [
|
|
@@ -171404,7 +171578,39 @@ ${res.warning}`);
|
|
|
171404
171578
|
}
|
|
171405
171579
|
case "design": {
|
|
171406
171580
|
const sub = positional[0];
|
|
171407
|
-
|
|
171581
|
+
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";
|
|
171582
|
+
if (sub === "chat") {
|
|
171583
|
+
const artifactId2 = needPos(positional, 1, "oasis design chat <artifactId> --message <t>");
|
|
171584
|
+
const message2 = flags.get("message") ?? (["DESIGN_BRIEF.md", "TASK.md"].map((f2) => fs25.existsSync(f2) ? fs25.readFileSync(f2, "utf8") : "").find((s2) => s2.trim()) ?? "");
|
|
171585
|
+
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");
|
|
171586
|
+
const odBase2 = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
|
|
171587
|
+
const isContinue = flags.get("turn") === "continue";
|
|
171588
|
+
const contextFiles2 = {};
|
|
171589
|
+
if (!isContinue) {
|
|
171590
|
+
contextFiles2["DESIGN_BRIEF.md"] = message2;
|
|
171591
|
+
if (fs25.existsSync("inputs") && fs25.statSync("inputs").isDirectory()) {
|
|
171592
|
+
for (const f2 of readDirFiles("inputs")) {
|
|
171593
|
+
contextFiles2[`inputs/${f2.path}`] = Buffer.from(f2.contentBase64, "base64").toString("utf8");
|
|
171594
|
+
}
|
|
171595
|
+
}
|
|
171596
|
+
}
|
|
171597
|
+
println(`[design] \u753B\u677F ${deriveBoardKey(artifactId2)} \u2190 ${artifactId2}\uFF1B${isContinue ? "\u7EED\u8F6E" : "\u9996\u8F6E"}\u5BF9\u8BDD\u9A71\u52A8 od \u5F15\u64CE ${odBase2} \u2026`);
|
|
171598
|
+
const turn = await runDesignChatTurn({
|
|
171599
|
+
base: odBase2,
|
|
171600
|
+
agentId: flags.get("agent") ?? "claude",
|
|
171601
|
+
artifactId: artifactId2,
|
|
171602
|
+
title: flags.get("title") ?? artifactId2,
|
|
171603
|
+
message: message2,
|
|
171604
|
+
...flags.get("system") !== void 0 ? { systemPrompt: flags.get("system") } : {},
|
|
171605
|
+
...isContinue ? {} : { contextFiles: contextFiles2 },
|
|
171606
|
+
onLine: (line) => println(`[od] ${line.length > 500 ? line.slice(0, 500) + "\u2026" : line}`)
|
|
171607
|
+
});
|
|
171608
|
+
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`);
|
|
171609
|
+
for (const a of turn.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.title ? ` \xB7 ${a.title}` : ""}`);
|
|
171610
|
+
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>"`);
|
|
171611
|
+
break;
|
|
171612
|
+
}
|
|
171613
|
+
if (sub !== "run") throw new Error("\u7528\u6CD5\uFF1Aoasis design run <artifactId> \u2026\uFF0C\u6216 oasis design chat <artifactId> --message <t> [--turn first|continue]");
|
|
171408
171614
|
const artifactId = needPos(positional, 1, "oasis design run <artifactId>");
|
|
171409
171615
|
const odBase = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
|
|
171410
171616
|
const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
@@ -171425,7 +171631,7 @@ ${res.warning}`);
|
|
|
171425
171631
|
artifactId,
|
|
171426
171632
|
title: flags.get("title") ?? artifactId,
|
|
171427
171633
|
message: brief,
|
|
171428
|
-
systemPrompt: "
|
|
171634
|
+
systemPrompt: flags.get("system") ?? LEGACY_DESIGN_SYSTEM_PROMPT,
|
|
171429
171635
|
contextFiles,
|
|
171430
171636
|
onLine: (line) => println(`[od] ${line.length > 500 ? line.slice(0, 500) + "\u2026" : line}`)
|
|
171431
171637
|
});
|
|
@@ -172064,12 +172270,12 @@ ${res.warning}`);
|
|
|
172064
172270
|
init_src6();
|
|
172065
172271
|
|
|
172066
172272
|
// src/index.ts
|
|
172067
|
-
var PKG_VERSION = true ? "0.1.
|
|
172068
|
-
var OASIS_DIR = path21.join(
|
|
172273
|
+
var PKG_VERSION = true ? "0.1.61" : "dev";
|
|
172274
|
+
var OASIS_DIR = path21.join(os9.homedir(), ".oasis");
|
|
172069
172275
|
var CONFIG_FILE = path21.join(OASIS_DIR, "node-config.json");
|
|
172070
172276
|
var PID_FILE = path21.join(OASIS_DIR, "node.pid");
|
|
172071
172277
|
var BIN_FILE = path21.join(OASIS_DIR, "bin", "oasis.js");
|
|
172072
|
-
var LOCAL_BIN = path21.join(
|
|
172278
|
+
var LOCAL_BIN = path21.join(os9.homedir(), ".local", "bin", "oasis");
|
|
172073
172279
|
var LOG_FILE = path21.join(OASIS_DIR, "node.log");
|
|
172074
172280
|
var NPM_PREFIX = path21.join(OASIS_DIR, "npm-global");
|
|
172075
172281
|
var PKG_NAME = "oasis_test";
|
|
@@ -172119,7 +172325,7 @@ exec node "${BIN_FILE}" "$@"
|
|
|
172119
172325
|
}
|
|
172120
172326
|
function setupAutostart() {
|
|
172121
172327
|
const cmd = `${process.execPath} "${BIN_FILE}" --_daemon`;
|
|
172122
|
-
const home =
|
|
172328
|
+
const home = os9.homedir();
|
|
172123
172329
|
const extraBins = [
|
|
172124
172330
|
path21.join(home, ".npm-global", "bin"),
|
|
172125
172331
|
path21.join(home, ".local", "bin"),
|
|
@@ -172127,7 +172333,7 @@ function setupAutostart() {
|
|
|
172127
172333
|
];
|
|
172128
172334
|
const daemonPath = [process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":");
|
|
172129
172335
|
if (process.platform === "linux") {
|
|
172130
|
-
const unitDir = path21.join(
|
|
172336
|
+
const unitDir = path21.join(os9.homedir(), ".config", "systemd", "user");
|
|
172131
172337
|
fs26.mkdirSync(unitDir, { recursive: true });
|
|
172132
172338
|
fs26.writeFileSync(path21.join(unitDir, "oasis-node.service"), [
|
|
172133
172339
|
"[Unit]",
|
|
@@ -172151,7 +172357,7 @@ function setupAutostart() {
|
|
|
172151
172357
|
} catch {
|
|
172152
172358
|
}
|
|
172153
172359
|
} else if (process.platform === "darwin") {
|
|
172154
|
-
const plist = path21.join(
|
|
172360
|
+
const plist = path21.join(os9.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
|
|
172155
172361
|
fs26.mkdirSync(path21.dirname(plist), { recursive: true });
|
|
172156
172362
|
fs26.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
|
|
172157
172363
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -172314,7 +172520,7 @@ void (async () => {
|
|
|
172314
172520
|
const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
|
|
172315
172521
|
method: "POST",
|
|
172316
172522
|
headers: { "content-type": "application/json" },
|
|
172317
|
-
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname:
|
|
172523
|
+
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os9.hostname() })
|
|
172318
172524
|
});
|
|
172319
172525
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
172320
172526
|
const body = await res.json();
|