oasis_test_v2 2.2.84 → 2.2.86
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 +1008 -619
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2524,368 +2524,26 @@ var init_sealed_node_receipt = __esm({
|
|
|
2524
2524
|
}
|
|
2525
2525
|
});
|
|
2526
2526
|
|
|
2527
|
-
// ../server/src/domains/chat-sessions/session-runtime-target.ts
|
|
2528
|
-
function sessionRuntimeOverride(session) {
|
|
2529
|
-
const nodeId = session?.overrideNodeId?.trim();
|
|
2530
|
-
const runtimeKind = session?.overrideRuntimeKind?.trim();
|
|
2531
|
-
if (!nodeId || !runtimeKind) return null;
|
|
2532
|
-
return { nodeId, runtimeKind };
|
|
2533
|
-
}
|
|
2534
|
-
function chatSessionInitialRuntime(input) {
|
|
2535
|
-
const trimmed = (v2) => typeof v2 === "string" && v2.trim() ? v2.trim() : null;
|
|
2536
|
-
const binding = input.binding?.nodeId && input.binding?.runtimeKind ? { nodeId: input.binding.nodeId, runtimeKind: input.binding.runtimeKind } : null;
|
|
2537
|
-
const requestedOverride = input.requested?.override;
|
|
2538
|
-
const picked = requestedOverride?.nodeId && requestedOverride?.runtimeKind ? { nodeId: requestedOverride.nodeId, runtimeKind: requestedOverride.runtimeKind } : null;
|
|
2539
|
-
const target = picked ?? binding;
|
|
2540
|
-
const followsAgentTarget = !picked || !!binding && picked.nodeId === binding.nodeId && picked.runtimeKind === binding.runtimeKind;
|
|
2541
|
-
const requestedModel = input.requested?.model;
|
|
2542
|
-
const model = requestedModel !== void 0 ? trimmed(requestedModel) : followsAgentTarget ? trimmed(input.agentModel) : null;
|
|
2543
|
-
return {
|
|
2544
|
-
overrideNodeId: target?.nodeId ?? null,
|
|
2545
|
-
overrideRuntimeKind: target?.runtimeKind ?? null,
|
|
2546
|
-
model
|
|
2547
|
-
};
|
|
2548
|
-
}
|
|
2549
|
-
function sessionRuntimeOverrideChangesTarget(session, binding) {
|
|
2550
|
-
const override = sessionRuntimeOverride(session);
|
|
2551
|
-
if (!override) return false;
|
|
2552
|
-
if (!binding) return true;
|
|
2553
|
-
return override.nodeId !== binding.nodeId || override.runtimeKind !== binding.runtimeKind;
|
|
2554
|
-
}
|
|
2555
|
-
async function resolveSessionRuntimeTarget(input) {
|
|
2556
|
-
const { probe } = input;
|
|
2557
|
-
const override = sessionRuntimeOverride(input.session);
|
|
2558
|
-
if (!override) {
|
|
2559
|
-
return probe.binding ? { binding: probe.binding, source: "actor_binding" } : null;
|
|
2560
|
-
}
|
|
2561
|
-
const kinds = await probe.availableRuntimeKinds(override.nodeId);
|
|
2562
|
-
const nodeName = (await probe.nodeDisplayName?.(override.nodeId))?.trim() || override.nodeId;
|
|
2563
|
-
if (kinds === null) {
|
|
2564
|
-
throw new SessionRuntimeOverrideError(
|
|
2565
|
-
"CHAT_SESSION_NODE_UNAVAILABLE",
|
|
2566
|
-
`\u8FD9\u6761\u4F1A\u8BDD\u9009\u5B9A\u7684\u8282\u70B9\u300C${nodeName}\u300D\u5F53\u524D\u4E0D\u53EF\u7528\uFF08\u53EF\u80FD\u5DF2\u79BB\u7EBF\u3001\u5DF2\u5220\u9664\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8\uFF09\u3002\u8BF7\u786E\u8BA4\u90A3\u53F0\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u540E\u518D\u53D1\uFF1B\u6216${CLEAR_SESSION_RUNTIME_HINT}`
|
|
2567
|
-
);
|
|
2568
|
-
}
|
|
2569
|
-
if (!kinds.includes(override.runtimeKind)) {
|
|
2570
|
-
throw new SessionRuntimeOverrideError(
|
|
2571
|
-
"CHAT_SESSION_RUNTIME_UNAVAILABLE",
|
|
2572
|
-
`\u8282\u70B9\u300C${nodeName}\u300D\u4E0A\u6CA1\u6709\u53EF\u7528\u7684\u8FD0\u884C\u65F6 ${override.runtimeKind}\uFF08\u53EF\u80FD\u5DF2\u5378\u8F7D\u3001\u8FD8\u6CA1\u88C5\u597D\uFF0C\u6216\u672A\u4E0A\u62A5\uFF09\u3002\u8BF7\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u88C5\u597D\u540E\u518D\u53D1\uFF1B\u6216${CLEAR_SESSION_RUNTIME_HINT}`
|
|
2573
|
-
);
|
|
2574
|
-
}
|
|
2575
|
-
if (!probe.binding) {
|
|
2576
|
-
throw new SessionRuntimeOverrideError(
|
|
2577
|
-
"ACTOR_BINDING_MISSING",
|
|
2578
|
-
`\u8FD9\u4F4D Agent \u8FD8\u6CA1\u6709\u7ED1\u5B9A\u8FD0\u884C\u65F6\uFF0C\u9009\u5B9A\u8282\u70B9\u4E5F\u6D3E\u4E0D\u51FA\u53BB\u3002\u8BF7\u5148\u7ED9\u4ED6\u7ED1\u5B9A\u4E00\u4E2A\u53EF\u7528\u7684\u8FD0\u884C\u65F6\uFF1B\u6216${CLEAR_SESSION_RUNTIME_HINT}`
|
|
2579
|
-
);
|
|
2580
|
-
}
|
|
2581
|
-
return {
|
|
2582
|
-
binding: { actorId: probe.binding.actorId, nodeId: override.nodeId, runtimeKind: override.runtimeKind, status: probe.binding.status },
|
|
2583
|
-
source: "session_override"
|
|
2584
|
-
};
|
|
2585
|
-
}
|
|
2586
|
-
function canAnnounceRuntimeSwitch(prior) {
|
|
2587
|
-
const nodeId = prior?.runtimeId?.trim();
|
|
2588
|
-
const kind = prior?.runtimeKind?.trim();
|
|
2589
|
-
return Boolean(nodeId && kind && nodeId !== "unknown");
|
|
2590
|
-
}
|
|
2591
|
-
function runtimeSwitchedNotice(target) {
|
|
2592
|
-
const name = target.nodeName?.trim();
|
|
2593
|
-
const where = name ? `${name} \xB7 ${target.runtimeKind}` : target.runtimeKind;
|
|
2594
|
-
return `\u8FD0\u884C\u65F6\u5DF2\u5207\u5230 ${where}\uFF0C\u672C\u8F6E\u8D77\u5728\u65B0\u7684\u8FD0\u884C\u65F6\u4F1A\u8BDD\u4E2D\u7EE7\u7EED\uFF0C\u5DE5\u4F5C\u533A\u4E0E\u4E0A\u4E0B\u6587\u4E0D\u6CBF\u7528\u3002`;
|
|
2595
|
-
}
|
|
2596
|
-
var SessionRuntimeOverrideError, CLEAR_SESSION_RUNTIME_HINT;
|
|
2597
|
-
var init_session_runtime_target = __esm({
|
|
2598
|
-
"../server/src/domains/chat-sessions/session-runtime-target.ts"() {
|
|
2599
|
-
"use strict";
|
|
2600
|
-
SessionRuntimeOverrideError = class extends Error {
|
|
2601
|
-
constructor(code2, message, status = 409) {
|
|
2602
|
-
super(message);
|
|
2603
|
-
this.code = code2;
|
|
2604
|
-
this.status = status;
|
|
2605
|
-
this.name = "SessionRuntimeOverrideError";
|
|
2606
|
-
}
|
|
2607
|
-
};
|
|
2608
|
-
CLEAR_SESSION_RUNTIME_HINT = "\u5728\u8F93\u5165\u6846\u5E95\u90E8\u7684\u8FD0\u884C\u65F6\u9009\u62E9\u91CC\u6362\u4E00\u53F0\u53EF\u7528\u7684\u670D\u52A1\u5668\u6216\u8FD0\u884C\u65F6\u5373\u53EF\u7EE7\u7EED\uFF08\u5458\u5DE5\u81EA\u5DF1\u7684\u90A3\u4E00\u5957\u6807\u7740\u300C\u5F53\u524D\u5458\u5DE5\u6240\u5728\u670D\u52A1\u5668\u300D\u300C\u5F53\u524D\u5458\u5DE5\u8FD0\u884C\u65F6\u300D\uFF09\u3002";
|
|
2609
|
-
}
|
|
2610
|
-
});
|
|
2611
|
-
|
|
2612
|
-
// ../server/src/artifact-content.ts
|
|
2613
|
-
async function currentOutput(kernel, artifactId) {
|
|
2614
|
-
await kernel.refreshModel();
|
|
2615
|
-
const artifact = kernel.model.artifacts.get(artifactId);
|
|
2616
|
-
if (!artifact) throw new ApiError(404, "NOT_FOUND", "\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
2617
|
-
const snap = await kernel.getStore().transaction((tx) => tx.loadWorkorder(artifact.workspace));
|
|
2618
|
-
const node2 = snap?.nodes.find((n) => n.id === artifactId);
|
|
2619
|
-
const latest = snap?.works.find((w2) => w2.id === node2?.latestWorkId);
|
|
2620
|
-
const workId = latest && (latest.status === "failed" || latest.status === "dead") && node2?.latestProposedWorkId ? node2.latestProposedWorkId : node2?.latestWorkId;
|
|
2621
|
-
const output = snap?.artifacts.filter((a) => a.workId === workId).sort((a, b2) => a.ordinal - b2.ordinal)[0];
|
|
2622
|
-
if (!node2 || !output) throw new ApiError(404, "NOT_FOUND", "\u8FD9\u4E2A\u8282\u70B9\u5C1A\u672A\u4EA4\u4ED8\u6587\u4EF6");
|
|
2623
|
-
return { node: node2, output };
|
|
2624
|
-
}
|
|
2625
|
-
function looksLikeFileName(name) {
|
|
2626
|
-
return /^\.[a-z]{1,8}[0-9]?$/.test(fileExtensionOf(name));
|
|
2627
|
-
}
|
|
2628
|
-
function decodeText(bytes2) {
|
|
2629
|
-
if (bytes2.length > currentFileLimits().textEditBytes || bytes2.includes(0)) return null;
|
|
2630
|
-
try {
|
|
2631
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
|
|
2632
|
-
} catch {
|
|
2633
|
-
return null;
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
async function readEditable(kernel, blobs, artifactId, path47) {
|
|
2637
|
-
const { node: node2, output } = await currentOutput(kernel, artifactId);
|
|
2638
|
-
let text7 = null;
|
|
2639
|
-
if (output.contentKind === "manifest" && path47 !== null) {
|
|
2640
|
-
const manifest = parseManifest(await blobs.get(output.contentRef));
|
|
2641
|
-
const entry = manifest.entries.find((e) => e.path === path47);
|
|
2642
|
-
if (!entry) throw new ApiError(404, "NOT_FOUND", "\u5305\u5185\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
2643
|
-
if (isEditableFileName(entry.path)) text7 = decodeText(await blobs.get(entry.hash));
|
|
2644
|
-
} else if (output.contentKind === "inline") {
|
|
2645
|
-
const name = node2.title || output.name;
|
|
2646
|
-
if (!looksLikeFileName(name) || isEditableFileName(name)) text7 = decodeText(await blobs.get(output.contentRef));
|
|
2647
|
-
}
|
|
2648
|
-
const view = {
|
|
2649
|
-
artifactId,
|
|
2650
|
-
revisionId: output.workId,
|
|
2651
|
-
contentRef: output.contentRef,
|
|
2652
|
-
path: path47,
|
|
2653
|
-
editable: text7 !== null,
|
|
2654
|
-
text: text7
|
|
2655
|
-
};
|
|
2656
|
-
return { view, node: node2, output };
|
|
2657
|
-
}
|
|
2658
|
-
async function readArtifactEditableContent(kernel, blobs, artifactId, path47) {
|
|
2659
|
-
return (await readEditable(kernel, blobs, artifactId, path47)).view;
|
|
2660
|
-
}
|
|
2661
|
-
async function saveArtifactContent(kernel, blobs, actor, input) {
|
|
2662
|
-
if (!input || typeof input.artifactId !== "string" || typeof input.revisionId !== "string" || typeof input.contentRef !== "string" || typeof input.text !== "string" || input.path != null && typeof input.path !== "string") {
|
|
2663
|
-
throw new ApiError(400, "BAD_REQUEST", "\u4FDD\u5B58\u53C2\u6570\u4E0D\u5B8C\u6574");
|
|
2664
|
-
}
|
|
2665
|
-
const bytes2 = new TextEncoder().encode(input.text);
|
|
2666
|
-
if (bytes2.length > currentFileLimits().textEditBytes || bytes2.includes(0)) {
|
|
2667
|
-
throw new ApiError(400, "BAD_REQUEST", `\u4EC5\u652F\u6301\u4E0D\u8D85\u8FC7 ${currentFileLimits().textEditBytes / 1024 / 1024} MiB \u7684 UTF-8 \u6587\u672C`);
|
|
2668
|
-
}
|
|
2669
|
-
const path47 = input.path ?? null;
|
|
2670
|
-
const { view, node: node2, output } = await readEditable(kernel, blobs, input.artifactId, path47);
|
|
2671
|
-
if (view.revisionId !== input.revisionId || view.contentRef !== input.contentRef) {
|
|
2672
|
-
throw new ApiError(409, "CONTENT_CONFLICT", "\u5185\u5BB9\u5DF2\u88AB\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6587\u4EF6\u540E\u518D\u4FDD\u5B58");
|
|
2673
|
-
}
|
|
2674
|
-
if (!view.editable) throw new ApiError(400, "NOT_EDITABLE", "\u6B64\u6587\u4EF6\u4E0D\u652F\u6301\u5728\u7EBF\u7F16\u8F91");
|
|
2675
|
-
let contentRef = await blobs.put(bytes2);
|
|
2676
|
-
if (output.contentKind === "manifest") {
|
|
2677
|
-
const manifest = parseManifest(await blobs.get(output.contentRef));
|
|
2678
|
-
contentRef = await blobs.put(serializeManifest(manifest.entries.map((e) => e.path === path47 ? { ...e, hash: contentRef, size: bytes2.length } : e)));
|
|
2679
|
-
}
|
|
2680
|
-
try {
|
|
2681
|
-
await kernel.editArtifactContent({
|
|
2682
|
-
artifactId: input.artifactId,
|
|
2683
|
-
actor,
|
|
2684
|
-
workId: output.workId,
|
|
2685
|
-
outputId: output.id,
|
|
2686
|
-
expectedLatestWorkId: node2.latestWorkId,
|
|
2687
|
-
previousRef: output.contentRef,
|
|
2688
|
-
contentRef,
|
|
2689
|
-
path: path47
|
|
2690
|
-
});
|
|
2691
|
-
} catch (error2) {
|
|
2692
|
-
if (error2.code === "content-conflict") {
|
|
2693
|
-
throw new ApiError(409, "CONTENT_CONFLICT", "\u5185\u5BB9\u5DF2\u88AB\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6587\u4EF6\u540E\u518D\u4FDD\u5B58");
|
|
2694
|
-
}
|
|
2695
|
-
throw error2;
|
|
2696
|
-
}
|
|
2697
|
-
return { ...view, contentRef, text: input.text };
|
|
2698
|
-
}
|
|
2699
|
-
async function readArtifactFile(kernel, blobs, artifactId, path47, expectedRef, revisionId = null) {
|
|
2700
|
-
await kernel.refreshModel();
|
|
2701
|
-
const artifact = kernel.model.artifacts.get(artifactId);
|
|
2702
|
-
const selectedRevision = revisionId ?? artifact?.currentRev;
|
|
2703
|
-
const output = selectedRevision ? kernel.model.revisions.get(selectedRevision) : void 0;
|
|
2704
|
-
if (!artifact || !output || output.artifactId !== artifactId) {
|
|
2705
|
-
throw new ApiError(404, "NOT_FOUND", revisionId !== null ? "\u8BE5\u4EA7\u7269\u7248\u672C\u4E0D\u5B58\u5728" : "\u6B64\u4EA7\u7269\u6CA1\u6709\u53EF\u4E0B\u8F7D\u7684\u539F\u6587\u4EF6");
|
|
2706
|
-
}
|
|
2707
|
-
if (expectedRef && output.contentRef !== expectedRef) throw new ApiError(409, "CONTENT_CONFLICT", "\u6587\u4EF6\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00");
|
|
2708
|
-
let hash3 = output.contentRef;
|
|
2709
|
-
let name = artifact.title || artifactId;
|
|
2710
|
-
if (output.contentKind === "manifest") {
|
|
2711
|
-
if (!path47) throw new ApiError(400, "PATH_REQUIRED", "\u8BF7\u9009\u62E9\u6587\u4EF6\u5939\u4E2D\u7684\u5177\u4F53\u6587\u4EF6");
|
|
2712
|
-
const entry = parseManifest(await blobs.get(output.contentRef)).entries.find((e) => e.path === path47);
|
|
2713
|
-
if (!entry) throw new ApiError(404, "NOT_FOUND", "\u5305\u5185\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
2714
|
-
hash3 = entry.hash;
|
|
2715
|
-
name = entry.path;
|
|
2716
|
-
if (entry.size !== void 0 && entry.size > currentFileReadMaxBytes()) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${currentFileReadMaxBytes() / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
2717
|
-
} else if (output.contentKind !== "inline-blob") {
|
|
2718
|
-
throw new ApiError(404, "NOT_FOUND", "\u6B64\u4EA7\u7269\u6CA1\u6709\u53EF\u4E0B\u8F7D\u7684\u539F\u6587\u4EF6");
|
|
2719
|
-
}
|
|
2720
|
-
const meta = await blobs.meta?.(hash3);
|
|
2721
|
-
if (meta && meta.size > currentFileReadMaxBytes()) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${currentFileReadMaxBytes() / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
2722
|
-
try {
|
|
2723
|
-
return { bytes: await blobs.get(hash3), name, contentType: meta?.contentType };
|
|
2724
|
-
} catch {
|
|
2725
|
-
throw new ApiError(404, "NOT_FOUND", "\u5F53\u524D\u516C\u53F8\u4E2D\u627E\u4E0D\u5230\u8BE5\u6587\u4EF6\u6B63\u6587");
|
|
2726
|
-
}
|
|
2727
|
-
}
|
|
2728
|
-
var init_artifact_content2 = __esm({
|
|
2729
|
-
"../server/src/artifact-content.ts"() {
|
|
2730
|
-
"use strict";
|
|
2731
|
-
init_file_limits2();
|
|
2732
|
-
init_src();
|
|
2733
|
-
init_router();
|
|
2734
|
-
}
|
|
2735
|
-
});
|
|
2736
|
-
|
|
2737
|
-
// ../server/src/file-http.ts
|
|
2738
|
-
async function serveFileRequest(req, res, url, engine) {
|
|
2739
|
-
try {
|
|
2740
|
-
if (req.method !== "GET" || url.pathname !== "/api/files/content") throw new ApiError(404, "NOT_FOUND", "\u6587\u4EF6\u63A5\u53E3\u4E0D\u5B58\u5728");
|
|
2741
|
-
const { bytes: bytes2, name, contentType } = await readArtifactFile(
|
|
2742
|
-
engine.kernel,
|
|
2743
|
-
engine.blobs,
|
|
2744
|
-
url.searchParams.get("artifact") ?? "",
|
|
2745
|
-
url.searchParams.get("path"),
|
|
2746
|
-
url.searchParams.get("ref"),
|
|
2747
|
-
url.searchParams.get("revisionId")
|
|
2748
|
-
);
|
|
2749
|
-
if (bytes2.length > currentFileReadMaxBytes()) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${currentFileReadMaxBytes() / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
2750
|
-
res.writeHead(200, {
|
|
2751
|
-
"content-type": contentType ?? sniffContentType(bytes2) ?? "application/octet-stream",
|
|
2752
|
-
"content-length": String(bytes2.length),
|
|
2753
|
-
"cache-control": "private, no-store",
|
|
2754
|
-
"x-content-type-options": "nosniff",
|
|
2755
|
-
"content-disposition": `attachment; filename*=UTF-8''${encodeURIComponent(name.split(/[\\/]/).pop() || "file").replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)}`
|
|
2756
|
-
}).end(Buffer.from(bytes2));
|
|
2757
|
-
} catch (error2) {
|
|
2758
|
-
if (res.destroyed) return;
|
|
2759
|
-
const status = error2 instanceof ApiError ? error2.status : 500;
|
|
2760
|
-
if (!req.complete) {
|
|
2761
|
-
res.setHeader("connection", "close");
|
|
2762
|
-
req.resume();
|
|
2763
|
-
}
|
|
2764
|
-
res.writeHead(status, { "content-type": "application/json", "cache-control": "no-store" }).end(JSON.stringify({
|
|
2765
|
-
error: {
|
|
2766
|
-
code: error2 instanceof ApiError ? error2.code : "FILE_READ_FAILED",
|
|
2767
|
-
message: error2 instanceof ApiError ? error2.message : "\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"
|
|
2768
|
-
}
|
|
2769
|
-
}));
|
|
2770
|
-
}
|
|
2771
|
-
}
|
|
2772
|
-
var init_file_http = __esm({
|
|
2773
|
-
"../server/src/file-http.ts"() {
|
|
2774
|
-
"use strict";
|
|
2775
|
-
init_src();
|
|
2776
|
-
init_artifact_content2();
|
|
2777
|
-
init_router();
|
|
2778
|
-
init_file_limits2();
|
|
2779
|
-
}
|
|
2780
|
-
});
|
|
2781
|
-
|
|
2782
|
-
// ../server/src/build-info.ts
|
|
2783
|
-
function findRepoRoot() {
|
|
2784
|
-
let dir;
|
|
2785
|
-
try {
|
|
2786
|
-
dir = path.dirname((0, import_node_url.fileURLToPath)(__esm_import_meta_url));
|
|
2787
|
-
} catch {
|
|
2788
|
-
return null;
|
|
2789
|
-
}
|
|
2790
|
-
for (let i = 0; i < 12; i++) {
|
|
2791
|
-
if (fs.existsSync(path.join(dir, ".git"))) return dir;
|
|
2792
|
-
const parent = path.dirname(dir);
|
|
2793
|
-
if (parent === dir) break;
|
|
2794
|
-
dir = parent;
|
|
2795
|
-
}
|
|
2796
|
-
return null;
|
|
2797
|
-
}
|
|
2798
|
-
function git(root, args) {
|
|
2799
|
-
try {
|
|
2800
|
-
const out = (0, import_node_child_process.execFileSync)("git", args, {
|
|
2801
|
-
cwd: root,
|
|
2802
|
-
encoding: "utf8",
|
|
2803
|
-
timeout: 3e3,
|
|
2804
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
2805
|
-
});
|
|
2806
|
-
const v2 = out.trim();
|
|
2807
|
-
return v2 || null;
|
|
2808
|
-
} catch {
|
|
2809
|
-
return null;
|
|
2810
|
-
}
|
|
2811
|
-
}
|
|
2812
|
-
function getBuildInfo() {
|
|
2813
|
-
if (cached) return cached;
|
|
2814
|
-
const envSha = process.env["OASIS_GIT_SHA"]?.trim();
|
|
2815
|
-
const envBranch = process.env["OASIS_GIT_BRANCH"]?.trim();
|
|
2816
|
-
let gitSha = envSha || null;
|
|
2817
|
-
let gitBranch = envBranch || null;
|
|
2818
|
-
if (!gitSha || !gitBranch) {
|
|
2819
|
-
const root = findRepoRoot();
|
|
2820
|
-
if (root) {
|
|
2821
|
-
if (!gitSha) gitSha = git(root, ["rev-parse", "HEAD"]);
|
|
2822
|
-
if (!gitBranch) {
|
|
2823
|
-
const b2 = git(root, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
2824
|
-
gitBranch = b2 === "HEAD" ? null : b2;
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
}
|
|
2828
|
-
cached = { gitSha, gitBranch, startedAt: STARTED_AT };
|
|
2829
|
-
return cached;
|
|
2830
|
-
}
|
|
2831
|
-
function resetBuildInfoCacheForTest() {
|
|
2832
|
-
cached = void 0;
|
|
2833
|
-
}
|
|
2834
|
-
var import_node_child_process, fs, path, import_node_url, STARTED_AT, cached;
|
|
2835
|
-
var init_build_info = __esm({
|
|
2836
|
-
"../server/src/build-info.ts"() {
|
|
2837
|
-
"use strict";
|
|
2838
|
-
import_node_child_process = require("node:child_process");
|
|
2839
|
-
fs = __toESM(require("node:fs"), 1);
|
|
2840
|
-
path = __toESM(require("node:path"), 1);
|
|
2841
|
-
import_node_url = require("node:url");
|
|
2842
|
-
STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
2843
|
-
}
|
|
2844
|
-
});
|
|
2845
|
-
|
|
2846
|
-
// ../server/src/command-policy.ts
|
|
2847
|
-
function classifyCommand(command2) {
|
|
2848
|
-
return COMMAND_POLICY[command2] ?? { risk: "direct" };
|
|
2849
|
-
}
|
|
2850
|
-
var shortId, COMMAND_POLICY;
|
|
2851
|
-
var init_command_policy = __esm({
|
|
2852
|
-
"../server/src/command-policy.ts"() {
|
|
2853
|
-
"use strict";
|
|
2854
|
-
shortId = (v2) => typeof v2 === "string" ? v2.replace(/^artifact:[^:]+:/, "") : String(v2 ?? "?");
|
|
2855
|
-
COMMAND_POLICY = {
|
|
2856
|
-
forceConclude: {
|
|
2857
|
-
risk: "authorize",
|
|
2858
|
-
idempotent: false,
|
|
2859
|
-
effect: (a) => `\u5F3A\u5236\u6536\u53E3\u8282\u70B9 ${shortId(a.artifactId)}\uFF08\u7ED5\u8FC7\u8BC4\u5BA1\u95F8\u76F4\u63A5\u76D6\u91CC\u7A0B\u7891\uFF09`
|
|
2860
|
-
},
|
|
2861
|
-
promote: {
|
|
2862
|
-
risk: "authorize",
|
|
2863
|
-
idempotent: true,
|
|
2864
|
-
effect: (a) => `\u628A\u8282\u70B9 ${shortId(a.artifactId)} \u8F6C\u4E3A\u6301\u4E45\uFF08temp \u2192 persistent\uFF09`
|
|
2865
|
-
},
|
|
2866
|
-
resolveEscalation: {
|
|
2867
|
-
risk: "authorize",
|
|
2868
|
-
idempotent: true,
|
|
2869
|
-
// 重复关同一条是幂等的(kernel.resolveEscalation 内部按 escalationId 去重)
|
|
2870
|
-
// 「关错=静默停摆」的唯一防线是人在卡上一眼看出「关的是哪一条」——escalationId 与 reason 摘要必须上卡。
|
|
2871
|
-
// a 里 escalationId/artifactId 由 server.ts 起草时冻进 commandArgs(已四级解析),保证是真值、非 `?`。
|
|
2872
|
-
effect: (a) => typeof a.gapId === "string" ? `\u91C7\u7528\u65B9\u6848\uFF1A${String(a.reason ?? "")}\uFF1B\u89E3\u51B3\u7F3A\u53E3 ${a.gapId}\uFF1B\u5173\u95ED\u5173\u8054\u4E0A\u62A5 ${String(a.escalationId)}\uFF1B\u7EE7\u7EED\u6267\u884C\uFF1A\u662F\uFF08\u4ECD\u987B\u6EE1\u8DB3\u5176\u4ED6\u963B\u585E\u6761\u4EF6\uFF09` : `\u5173\u95ED\u4E0A\u62A5 ${shortId(a.escalationId)}\uFF08\u8282\u70B9 ${shortId(a.artifactId)}${typeof a.reason === "string" ? `\uFF0C\u7406\u7531\uFF1A${a.reason}` : ""}\uFF09`
|
|
2873
|
-
},
|
|
2874
|
-
gc: {
|
|
2875
|
-
risk: "forbidden",
|
|
2876
|
-
forbiddenReason: "gc \u662F\u56DE\u6536\u5B64\u513F blob \u7684\u57FA\u7840\u8BBE\u65BD\u7EF4\u62A4\uFF0C\u7531 serve \u8FDB\u7A0B/\u4EBA\u7C7B operator \u6267\u884C\uFF0C\u4E0D\u5C5E\u4E8E\u7BA1\u7406\u8005\u80FD\u529B\u8303\u56F4\u3002"
|
|
2877
|
-
}
|
|
2878
|
-
};
|
|
2879
|
-
}
|
|
2880
|
-
});
|
|
2881
|
-
|
|
2882
2527
|
// ../adapters/src/open-design/driver.ts
|
|
2883
|
-
function
|
|
2528
|
+
function boardKeyOf(artifactId, fingerprintInput) {
|
|
2884
2529
|
const tail = artifactId.split(":").pop() ?? artifactId;
|
|
2885
2530
|
const ascii = tail.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 24);
|
|
2886
|
-
const sha8 = (0, import_node_crypto2.createHash)("sha256").update(
|
|
2531
|
+
const sha8 = (0, import_node_crypto2.createHash)("sha256").update(fingerprintInput).digest("hex").slice(0, 8);
|
|
2887
2532
|
return ascii ? `od-${ascii}-${sha8}` : `od-${sha8}`;
|
|
2888
2533
|
}
|
|
2534
|
+
function deriveBoardKey(companyId, artifactId) {
|
|
2535
|
+
const company = companyId.trim();
|
|
2536
|
+
if (company.length === 0) throw new Error(`\u6D3E\u751F\u753B\u677F\u540D\u9700\u8981\u516C\u53F8 id\uFF08${artifactId}\uFF09\u2014\u2014\u62FF\u4E0D\u5230\u516C\u53F8\u65F6\u4E0D\u80FD\u56DE\u843D\u5230\u4E0D\u5E26\u516C\u53F8\u7684\u65E7\u540D\u5B57`);
|
|
2537
|
+
return boardKeyOf(artifactId, `${company}\0${artifactId}`);
|
|
2538
|
+
}
|
|
2539
|
+
function parseBoardLinkBoardKey(text7) {
|
|
2540
|
+
for (const line2 of text7.split(/\r?\n/)) {
|
|
2541
|
+
const m2 = /\/projects\/([^/\s?#]+)\s*$/.exec(line2.trim());
|
|
2542
|
+
if (!m2) continue;
|
|
2543
|
+
return BOARD_KEY_RE.test(m2[1]) ? m2[1] : null;
|
|
2544
|
+
}
|
|
2545
|
+
return null;
|
|
2546
|
+
}
|
|
2889
2547
|
function withOdToken(fetchImpl, token) {
|
|
2890
2548
|
if (!token) return fetchImpl;
|
|
2891
2549
|
return (input, init) => {
|
|
@@ -2977,6 +2635,7 @@ async function fetchResultPackage(base, fetchImpl, runId) {
|
|
|
2977
2635
|
function toEpochMs(v2) {
|
|
2978
2636
|
if (typeof v2 === "number" && Number.isFinite(v2)) return v2;
|
|
2979
2637
|
if (typeof v2 === "string" && v2.length > 0) {
|
|
2638
|
+
if (/^\d+(\.\d+)?$/.test(v2.trim())) return Number(v2.trim());
|
|
2980
2639
|
const ms = Date.parse(v2);
|
|
2981
2640
|
return Number.isNaN(ms) ? void 0 : ms;
|
|
2982
2641
|
}
|
|
@@ -2993,8 +2652,99 @@ function latestSucceededRun(runs) {
|
|
|
2993
2652
|
}
|
|
2994
2653
|
return best;
|
|
2995
2654
|
}
|
|
2996
|
-
|
|
2997
|
-
const
|
|
2655
|
+
function liveBoardRuns(st) {
|
|
2656
|
+
const out = [];
|
|
2657
|
+
const known = /* @__PURE__ */ new Set();
|
|
2658
|
+
for (const t of st.turns ?? []) {
|
|
2659
|
+
if (t.runId !== null) known.add(t.runId);
|
|
2660
|
+
if (isTerminalRunStatus(t.status)) continue;
|
|
2661
|
+
out.push({ key: t.runId ?? `msg:${t.messageId ?? "?"}`, status: t.status, ...t.agentId ? { agentId: t.agentId } : {}, source: "conversation" });
|
|
2662
|
+
}
|
|
2663
|
+
for (const r of st.runs) {
|
|
2664
|
+
if (known.has(r.runId) || r.runId.length === 0) continue;
|
|
2665
|
+
if (r.status !== "running" && r.status !== "queued") continue;
|
|
2666
|
+
out.push({ key: r.runId, status: r.status, ...r.agentId ? { agentId: r.agentId } : {}, source: "registry" });
|
|
2667
|
+
}
|
|
2668
|
+
return out;
|
|
2669
|
+
}
|
|
2670
|
+
function latestEndedRun(st) {
|
|
2671
|
+
let best;
|
|
2672
|
+
for (const t of st.turns ?? []) {
|
|
2673
|
+
if (!isTerminalRunStatus(t.status)) continue;
|
|
2674
|
+
if (best === void 0 || (t.endedAt ?? Number.NEGATIVE_INFINITY) > (best.endedAt ?? Number.NEGATIVE_INFINITY)) best = t;
|
|
2675
|
+
}
|
|
2676
|
+
if (best) return { runId: best.runId, status: best.status, ...best.agentId ? { agentId: best.agentId } : {}, ...best.error ? { error: best.error } : {} };
|
|
2677
|
+
const r = st.runs.find((x2) => isTerminalRunStatus(x2.status));
|
|
2678
|
+
return r ? { runId: r.runId, status: r.status, ...r.agentId ? { agentId: r.agentId } : {}, ...r.error ? { error: r.error } : {} } : void 0;
|
|
2679
|
+
}
|
|
2680
|
+
function snapshotSourceRunId(st) {
|
|
2681
|
+
let best;
|
|
2682
|
+
for (const t of st.turns ?? []) {
|
|
2683
|
+
if (t.status !== "succeeded" || t.runId === null) continue;
|
|
2684
|
+
if (best === void 0 || (t.endedAt ?? Number.NEGATIVE_INFINITY) > (best.endedAt ?? Number.NEGATIVE_INFINITY)) best = t;
|
|
2685
|
+
}
|
|
2686
|
+
return best?.runId ?? latestSucceededRun(st.runs)?.runId;
|
|
2687
|
+
}
|
|
2688
|
+
function nonEmptyStr(v2) {
|
|
2689
|
+
return typeof v2 === "string" && v2.trim().length > 0 ? v2 : void 0;
|
|
2690
|
+
}
|
|
2691
|
+
function turnError(m2, status) {
|
|
2692
|
+
const events = Array.isArray(m2["events"]) ? m2["events"] : [];
|
|
2693
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
2694
|
+
const e = events[i];
|
|
2695
|
+
if (!e || typeof e !== "object") continue;
|
|
2696
|
+
const ev = e;
|
|
2697
|
+
if (ev["kind"] === "status" && ev["label"] === "error" && nonEmptyStr(ev["detail"])) return ev["detail"];
|
|
2698
|
+
}
|
|
2699
|
+
return status !== "succeeded" && isTerminalRunStatus(status) ? nonEmptyStr(m2["content"]) : void 0;
|
|
2700
|
+
}
|
|
2701
|
+
async function fetchBoardTurns(base, fetchImpl, boardKey) {
|
|
2702
|
+
const convPath = `/api/projects/${encodeURIComponent(boardKey)}/conversations`;
|
|
2703
|
+
const guard = (err) => {
|
|
2704
|
+
if (err instanceof OdHttpError && (err.status === 401 || err.status === 403)) throw err;
|
|
2705
|
+
return null;
|
|
2706
|
+
};
|
|
2707
|
+
let convs;
|
|
2708
|
+
try {
|
|
2709
|
+
convs = (await odApi(base, fetchImpl, "GET", convPath)).conversations ?? [];
|
|
2710
|
+
} catch (err) {
|
|
2711
|
+
if (err instanceof OdHttpError && err.status === 404) return [];
|
|
2712
|
+
return guard(err);
|
|
2713
|
+
}
|
|
2714
|
+
const turns = [];
|
|
2715
|
+
for (const c of convs) {
|
|
2716
|
+
const cid = nonEmptyStr(c["id"]);
|
|
2717
|
+
if (cid === void 0) continue;
|
|
2718
|
+
let msgs;
|
|
2719
|
+
try {
|
|
2720
|
+
msgs = (await odApi(base, fetchImpl, "GET", `${convPath}/${encodeURIComponent(cid)}/messages`)).messages ?? [];
|
|
2721
|
+
} catch (err) {
|
|
2722
|
+
if (err instanceof OdHttpError && err.status === 404) continue;
|
|
2723
|
+
return guard(err);
|
|
2724
|
+
}
|
|
2725
|
+
for (const m2 of msgs) {
|
|
2726
|
+
if (!m2 || typeof m2 !== "object" || m2["role"] !== "assistant") continue;
|
|
2727
|
+
const status = nonEmptyStr(m2["runStatus"]);
|
|
2728
|
+
if (status === void 0) continue;
|
|
2729
|
+
const runId = nonEmptyStr(m2["runId"]) ?? null;
|
|
2730
|
+
const messageId = nonEmptyStr(m2["id"]) ?? null;
|
|
2731
|
+
if (runId === null && messageId === null) continue;
|
|
2732
|
+
const turn = { conversationId: cid, runId, messageId, status };
|
|
2733
|
+
const agentId = nonEmptyStr(m2["agentId"]);
|
|
2734
|
+
if (agentId) turn.agentId = agentId;
|
|
2735
|
+
const error2 = turnError(m2, status);
|
|
2736
|
+
if (error2) turn.error = error2;
|
|
2737
|
+
const startedAt = toEpochMs(m2["startedAt"]) ?? toEpochMs(m2["createdAt"]);
|
|
2738
|
+
if (startedAt !== void 0) turn.startedAt = startedAt;
|
|
2739
|
+
const endedAt = toEpochMs(m2["endedAt"]);
|
|
2740
|
+
if (endedAt !== void 0) turn.endedAt = endedAt;
|
|
2741
|
+
turns.push(turn);
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
turns.sort((a, b2) => (b2.startedAt ?? Number.NEGATIVE_INFINITY) - (a.startedAt ?? Number.NEGATIVE_INFINITY) || 0);
|
|
2745
|
+
return turns;
|
|
2746
|
+
}
|
|
2747
|
+
async function fetchBoardStatus(base, fetchImpl, boardKey) {
|
|
2998
2748
|
let boardExists = true;
|
|
2999
2749
|
let artifacts = [];
|
|
3000
2750
|
try {
|
|
@@ -3035,7 +2785,31 @@ async function fetchBoardStatus(base, fetchImpl, artifactId) {
|
|
|
3035
2785
|
} catch {
|
|
3036
2786
|
}
|
|
3037
2787
|
}
|
|
3038
|
-
|
|
2788
|
+
const turns = boardExists ? await fetchBoardTurns(base, fetchImpl, boardKey) : [];
|
|
2789
|
+
return { boardKey, boardExists, runs, turns, artifacts };
|
|
2790
|
+
}
|
|
2791
|
+
async function waitBoardSettled(base, fetchImpl, boardKey, opts = {}) {
|
|
2792
|
+
const interval = opts.intervalMs ?? 2e4;
|
|
2793
|
+
const timeout = opts.timeoutMs ?? 100 * 6e4;
|
|
2794
|
+
const sleep6 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
2795
|
+
const now = opts.now ?? Date.now;
|
|
2796
|
+
const started = now();
|
|
2797
|
+
let lastKey = null;
|
|
2798
|
+
let waited = false;
|
|
2799
|
+
for (; ; ) {
|
|
2800
|
+
const st = await fetchBoardStatus(base, fetchImpl, boardKey);
|
|
2801
|
+
const elapsedMs = now() - started;
|
|
2802
|
+
if (!st.boardExists) return { status: st, settled: true, waited, live: [], elapsedMs };
|
|
2803
|
+
const live = liveBoardRuns(st);
|
|
2804
|
+
const unreadable = st.turns === null;
|
|
2805
|
+
if (live.length === 0 && !unreadable) return { status: st, settled: true, waited, live, elapsedMs };
|
|
2806
|
+
const key2 = unreadable && live.length === 0 ? "?" : live.map((r) => `${r.key}=${r.status}`).sort().join(",");
|
|
2807
|
+
opts.onPoll?.({ live, elapsedMs, changed: key2 !== lastKey, unreadable });
|
|
2808
|
+
lastKey = key2;
|
|
2809
|
+
if (elapsedMs >= timeout) return { status: st, settled: false, waited: true, live, elapsedMs };
|
|
2810
|
+
waited = true;
|
|
2811
|
+
await sleep6(Math.min(interval, Math.max(0, timeout - elapsedMs)));
|
|
2812
|
+
}
|
|
3039
2813
|
}
|
|
3040
2814
|
async function pumpDesignEvents(base, fetchImpl, runId, onLine) {
|
|
3041
2815
|
const res = await fetchImpl(`${base}/api/runs/${runId}/events`);
|
|
@@ -3084,7 +2858,7 @@ async function harvestBoard(base, fetchImpl, publicBase, workRoot, boardKey, run
|
|
|
3084
2858
|
const htmls = (listing.files ?? []).filter((f2) => f2.kind === "html" && !f2.path.startsWith("task-context/")).filter((f2) => (f2.artifactManifest?.status ?? "complete") === "complete").sort((a, b2) => (b2.mtime ?? 0) - (a.mtime ?? 0));
|
|
3085
2859
|
const entry = htmls[0]?.path;
|
|
3086
2860
|
if (!entry) throw new Error("\u753B\u677F\u9879\u76EE\u65E0\u5DF2\u5B8C\u6210\u7684 HTML \u5165\u53E3\u7A3F\u2014\u2014\u8BBE\u8BA1\u4F1A\u8BDD\u672A\u4EA7\u51FA\u53EF\u4EA4\u4ED8\u754C\u9762");
|
|
3087
|
-
const dir =
|
|
2861
|
+
const dir = fs.mkdtempSync(path.join(workRoot, "od-deliverable-"));
|
|
3088
2862
|
const fetchInline = async (rel) => {
|
|
3089
2863
|
const res = await fetchImpl(`${base}/api/projects/${encodeURIComponent(boardKey)}/export/${encodeURIComponent(rel)}?inline=1`);
|
|
3090
2864
|
if (!res.ok) throw new Error(`od export ${rel} \u2192 ${res.status}`);
|
|
@@ -3095,28 +2869,37 @@ async function harvestBoard(base, fetchImpl, publicBase, workRoot, boardKey, run
|
|
|
3095
2869
|
if (!res.ok) throw new Error(`od raw ${rel} \u2192 ${res.status}`);
|
|
3096
2870
|
return await res.text();
|
|
3097
2871
|
};
|
|
3098
|
-
|
|
2872
|
+
fs.writeFileSync(path.join(dir, "index.html"), await fetchInline(entry));
|
|
3099
2873
|
for (const f2 of listing.files ?? []) {
|
|
3100
2874
|
if (f2.path.endsWith(".md") && !f2.path.includes("/")) {
|
|
3101
2875
|
try {
|
|
3102
|
-
|
|
2876
|
+
fs.writeFileSync(path.join(dir, f2.path), await fetchRaw(f2.path));
|
|
3103
2877
|
} catch {
|
|
3104
2878
|
}
|
|
3105
2879
|
}
|
|
3106
2880
|
}
|
|
3107
|
-
|
|
3108
|
-
path2.join(dir, "board.link"),
|
|
3109
|
-
`${publicBase}/projects/${boardKey}
|
|
3110
|
-
\u5165\u53E3\u7A3F\uFF1A${entry}
|
|
3111
|
-
\u5FEB\u7167\u6765\u6E90 run\uFF1A${runId}
|
|
3112
|
-
\uFF08\u6D3B\u753B\u677F\u2014\u2014\u7EE7\u7EED\u8FED\u4EE3\u8BF7\u56DE\u5230\u8BE5\u9879\u76EE\uFF1B\u672C\u88C5\u7BB1\u5355\u4E3A\u8BE5\u6B21\u4EA4\u4ED8\u7684\u51BB\u7ED3\u5FEB\u7167\uFF09
|
|
3113
|
-
`
|
|
3114
|
-
);
|
|
2881
|
+
fs.writeFileSync(path.join(dir, BOARD_LINK_FILE), formatBoardLink({ publicBase, boardKey, entry, runId }));
|
|
3115
2882
|
return { dir, entry };
|
|
3116
2883
|
}
|
|
2884
|
+
function formatBoardLink(args) {
|
|
2885
|
+
return `${args.publicBase}/projects/${args.boardKey}
|
|
2886
|
+
\u5165\u53E3\u7A3F\uFF1A${args.entry}
|
|
2887
|
+
${SOURCE_RUN_LABEL}${args.runId}
|
|
2888
|
+
\uFF08\u6D3B\u753B\u677F\u2014\u2014\u7EE7\u7EED\u8FED\u4EE3\u8BF7\u56DE\u5230\u8BE5\u9879\u76EE\uFF1B\u672C\u88C5\u7BB1\u5355\u4E3A\u8BE5\u6B21\u4EA4\u4ED8\u7684\u51BB\u7ED3\u5FEB\u7167\uFF09
|
|
2889
|
+
`;
|
|
2890
|
+
}
|
|
2891
|
+
function parseBoardLinkSourceRun(text7) {
|
|
2892
|
+
for (const line2 of text7.split(/\r?\n/)) {
|
|
2893
|
+
const t = line2.trim();
|
|
2894
|
+
if (!t.startsWith(SOURCE_RUN_LABEL)) continue;
|
|
2895
|
+
const id = t.slice(SOURCE_RUN_LABEL.length).trim();
|
|
2896
|
+
return id.length > 0 && id !== UNKNOWN_SOURCE_RUN ? id : null;
|
|
2897
|
+
}
|
|
2898
|
+
return null;
|
|
2899
|
+
}
|
|
3117
2900
|
async function startDesignChatTurn(opts) {
|
|
3118
2901
|
const fetchImpl = withOdToken(opts.fetchImpl ?? fetch, opts.token);
|
|
3119
|
-
const boardKey =
|
|
2902
|
+
const boardKey = opts.boardKey;
|
|
3120
2903
|
const { conversationId } = await ensureProject(opts.base, fetchImpl, boardKey, opts.title);
|
|
3121
2904
|
if (opts.contextFiles) await materializeContext(opts.base, fetchImpl, boardKey, opts.contextFiles);
|
|
3122
2905
|
const userMessageId = await putVisibleUserTurn(opts.base, fetchImpl, { boardKey, conversationId, content: opts.message });
|
|
@@ -3143,13 +2926,14 @@ async function runDesignChatTurn(opts) {
|
|
|
3143
2926
|
const { artifacts, fileCount } = await fetchResultPackage(opts.base, fetchImpl, runId);
|
|
3144
2927
|
return { boardKey, conversationId, runId, userMessageId, artifacts, fileCount };
|
|
3145
2928
|
}
|
|
3146
|
-
var import_node_crypto2,
|
|
2929
|
+
var import_node_crypto2, fs, path, BOARD_KEY_RE, OdHttpError, TASK_CONTEXT_DIR, TERMINAL_TURN_STATUS, isTerminalRunStatus, BOARD_LINK_FILE, SOURCE_RUN_LABEL, UNKNOWN_SOURCE_RUN;
|
|
3147
2930
|
var init_driver = __esm({
|
|
3148
2931
|
"../adapters/src/open-design/driver.ts"() {
|
|
3149
2932
|
"use strict";
|
|
3150
2933
|
import_node_crypto2 = require("node:crypto");
|
|
3151
|
-
|
|
3152
|
-
|
|
2934
|
+
fs = __toESM(require("node:fs"), 1);
|
|
2935
|
+
path = __toESM(require("node:path"), 1);
|
|
2936
|
+
BOARD_KEY_RE = /^[A-Za-z0-9-]{1,64}$/;
|
|
3153
2937
|
OdHttpError = class extends Error {
|
|
3154
2938
|
constructor(message, status) {
|
|
3155
2939
|
super(message);
|
|
@@ -3157,6 +2941,11 @@ var init_driver = __esm({
|
|
|
3157
2941
|
}
|
|
3158
2942
|
};
|
|
3159
2943
|
TASK_CONTEXT_DIR = "task-context/";
|
|
2944
|
+
TERMINAL_TURN_STATUS = /* @__PURE__ */ new Set(["succeeded", "failed", "canceled", "cancelled"]);
|
|
2945
|
+
isTerminalRunStatus = (s2) => TERMINAL_TURN_STATUS.has(s2);
|
|
2946
|
+
BOARD_LINK_FILE = "board.link";
|
|
2947
|
+
SOURCE_RUN_LABEL = "\u5FEB\u7167\u6765\u6E90 run\uFF1A";
|
|
2948
|
+
UNKNOWN_SOURCE_RUN = "status-pull";
|
|
3160
2949
|
}
|
|
3161
2950
|
});
|
|
3162
2951
|
|
|
@@ -3197,20 +2986,20 @@ function materializeBundle(dir, bundle) {
|
|
|
3197
2986
|
for (const [rel, entry] of Object.entries(bundle.restoreFiles ?? {})) {
|
|
3198
2987
|
try {
|
|
3199
2988
|
const parts = rel.split("/");
|
|
3200
|
-
if (!rel ||
|
|
2989
|
+
if (!rel || path2.isAbsolute(rel) || rel.includes("\\") || parts.some((p2) => !p2 || p2 === "." || p2 === "..")) {
|
|
3201
2990
|
throw new Error("\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84");
|
|
3202
2991
|
}
|
|
3203
|
-
let parent =
|
|
2992
|
+
let parent = fs2.realpathSync(dir);
|
|
3204
2993
|
for (const component of parts.slice(0, -1)) {
|
|
3205
|
-
parent =
|
|
3206
|
-
if (!
|
|
3207
|
-
const st =
|
|
2994
|
+
parent = path2.join(parent, component);
|
|
2995
|
+
if (!fs2.existsSync(parent)) fs2.mkdirSync(parent);
|
|
2996
|
+
const st = fs2.lstatSync(parent);
|
|
3208
2997
|
if (st.isSymbolicLink() || !st.isDirectory()) throw new Error("\u6062\u590D\u8DEF\u5F84\u5305\u542B\u975E\u76EE\u5F55\u6216\u8F6F\u94FE\u63A5");
|
|
3209
2998
|
}
|
|
3210
|
-
const file =
|
|
2999
|
+
const file = path2.join(parent, parts.at(-1));
|
|
3211
3000
|
let exists = false;
|
|
3212
3001
|
try {
|
|
3213
|
-
const st =
|
|
3002
|
+
const st = fs2.lstatSync(file);
|
|
3214
3003
|
if (!st.isFile() || st.isSymbolicLink()) throw new Error("\u6062\u590D\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
3215
3004
|
exists = true;
|
|
3216
3005
|
} catch (error2) {
|
|
@@ -3220,37 +3009,37 @@ function materializeBundle(dir, bundle) {
|
|
|
3220
3009
|
if (exists && !entry.overwrite) continue;
|
|
3221
3010
|
const bytes2 = Buffer.from(entry.contentBase64, "base64");
|
|
3222
3011
|
if ((0, import_node_crypto3.createHash)("sha256").update(bytes2).digest("hex") !== entry.sha256) throw new Error("\u5185\u5BB9\u6821\u9A8C\u5931\u8D25");
|
|
3223
|
-
const temp =
|
|
3012
|
+
const temp = path2.join(parent, `.oasis-restore-${(0, import_node_crypto3.randomUUID)()}`);
|
|
3224
3013
|
try {
|
|
3225
|
-
|
|
3226
|
-
|
|
3014
|
+
fs2.writeFileSync(temp, bytes2, { flag: "wx", mode: 384 });
|
|
3015
|
+
fs2.renameSync(temp, file);
|
|
3227
3016
|
} finally {
|
|
3228
|
-
|
|
3017
|
+
fs2.rmSync(temp, { force: true });
|
|
3229
3018
|
}
|
|
3230
3019
|
} catch (error2) {
|
|
3231
3020
|
throw new BundleRestoreError(rel, error2 instanceof Error ? error2.message : String(error2));
|
|
3232
3021
|
}
|
|
3233
3022
|
}
|
|
3234
3023
|
for (const [rel, content3] of Object.entries(bundle.files)) {
|
|
3235
|
-
const file =
|
|
3236
|
-
|
|
3237
|
-
|
|
3024
|
+
const file = path2.join(dir, rel);
|
|
3025
|
+
fs2.mkdirSync(path2.dirname(file), { recursive: true });
|
|
3026
|
+
fs2.writeFileSync(file, content3);
|
|
3238
3027
|
}
|
|
3239
3028
|
for (const [rel, b64] of Object.entries(bundle.binaryFiles ?? {})) {
|
|
3240
|
-
const file =
|
|
3241
|
-
|
|
3242
|
-
|
|
3029
|
+
const file = path2.join(dir, rel);
|
|
3030
|
+
fs2.mkdirSync(path2.dirname(file), { recursive: true });
|
|
3031
|
+
fs2.writeFileSync(file, Buffer.from(b64, "base64"));
|
|
3243
3032
|
}
|
|
3244
3033
|
const task = bundle.files["TASK.md"];
|
|
3245
3034
|
if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
|
|
3246
3035
|
return task;
|
|
3247
3036
|
}
|
|
3248
|
-
var
|
|
3037
|
+
var fs2, path2, import_node_crypto3, BundleRestoreError;
|
|
3249
3038
|
var init_materialize_bundle = __esm({
|
|
3250
3039
|
"../adapters/src/_core/materialize-bundle.ts"() {
|
|
3251
3040
|
"use strict";
|
|
3252
|
-
|
|
3253
|
-
|
|
3041
|
+
fs2 = __toESM(require("node:fs"), 1);
|
|
3042
|
+
path2 = __toESM(require("node:path"), 1);
|
|
3254
3043
|
import_node_crypto3 = require("node:crypto");
|
|
3255
3044
|
BundleRestoreError = class extends Error {
|
|
3256
3045
|
constructor(filePath, detail) {
|
|
@@ -3494,7 +3283,7 @@ function containerEnv(job, extraEarly, extraLate) {
|
|
|
3494
3283
|
...extraLate
|
|
3495
3284
|
};
|
|
3496
3285
|
if (job.wrapperPaths?.length) {
|
|
3497
|
-
env["PATH"] = `${job.wrapperPaths.map((p2) =>
|
|
3286
|
+
env["PATH"] = `${job.wrapperPaths.map((p2) => path4.dirname(p2)).join(path4.delimiter)}${path4.delimiter}${CONTAINER_DEFAULT_PATH}`;
|
|
3498
3287
|
}
|
|
3499
3288
|
env["OASIS_SERVER"] = job.server.url;
|
|
3500
3289
|
env["OASIS_TOKEN"] = job.actorToken;
|
|
@@ -3503,7 +3292,7 @@ function containerEnv(job, extraEarly, extraLate) {
|
|
|
3503
3292
|
}
|
|
3504
3293
|
function commonArgs(p2, name) {
|
|
3505
3294
|
const ee = p2.executionEnv;
|
|
3506
|
-
const binMount = `/usr/local/bin/${p2.binName ??
|
|
3295
|
+
const binMount = `/usr/local/bin/${p2.binName ?? path4.basename(p2.binHostPath)}`;
|
|
3507
3296
|
const args = [
|
|
3508
3297
|
// 不用 --userns=keep-id:rootless 默认映射已是「容器内 root = 宿主调用用户」,bind 挂载上的
|
|
3509
3298
|
// 文件属主内外天然一致(agent 写的文件宿主侧可读可删);keep-id 反而在部分主机的 overlay
|
|
@@ -3522,7 +3311,7 @@ function commonArgs(p2, name) {
|
|
|
3522
3311
|
`${p2.homeHostDir}:${CONTAINER_HOME}`
|
|
3523
3312
|
];
|
|
3524
3313
|
for (const dir of /* @__PURE__ */ new Set([
|
|
3525
|
-
...(p2.job.wrapperPaths ?? []).map((w2) =>
|
|
3314
|
+
...(p2.job.wrapperPaths ?? []).map((w2) => path4.dirname(w2)),
|
|
3526
3315
|
...p2.extraRoBindDirs ?? []
|
|
3527
3316
|
])) {
|
|
3528
3317
|
args.push("-v", `${dir}:${dir}:ro`);
|
|
@@ -3546,7 +3335,7 @@ function droppedEnvNames(env) {
|
|
|
3546
3335
|
}
|
|
3547
3336
|
function wrapForContainer(p2) {
|
|
3548
3337
|
const ee = p2.executionEnv;
|
|
3549
|
-
const binInContainer = p2.binPackageDir ? p2.binHostPath : `/usr/local/bin/${p2.binName ??
|
|
3338
|
+
const binInContainer = p2.binPackageDir ? p2.binHostPath : `/usr/local/bin/${p2.binName ?? path4.basename(p2.binHostPath)}`;
|
|
3550
3339
|
const eeHash = executionEnvHash(p2);
|
|
3551
3340
|
if (ee.persist && p2.job.workdirKey) {
|
|
3552
3341
|
const name2 = persistContainerName(p2.job.workdirKey);
|
|
@@ -3573,8 +3362,8 @@ function wrapForContainer(p2) {
|
|
|
3573
3362
|
droppedEnvNames: droppedEnvNames(p2.env)
|
|
3574
3363
|
};
|
|
3575
3364
|
}
|
|
3576
|
-
const name = ephemeralContainerName(p2.job,
|
|
3577
|
-
const cidFile =
|
|
3365
|
+
const name = ephemeralContainerName(p2.job, path4.basename(p2.cwd));
|
|
3366
|
+
const cidFile = path4.join(p2.cwd, ".oasis-container-cid");
|
|
3578
3367
|
return {
|
|
3579
3368
|
bin: "podman",
|
|
3580
3369
|
args: [
|
|
@@ -3604,12 +3393,12 @@ function wrapForContainer(p2) {
|
|
|
3604
3393
|
function killContainerArgs(containerName) {
|
|
3605
3394
|
return ["kill", containerName];
|
|
3606
3395
|
}
|
|
3607
|
-
var import_node_crypto5,
|
|
3396
|
+
var import_node_crypto5, path4, CONTAINER_DEFAULT_PATH, CONTAINER_HOME, EE_HASH_LABEL;
|
|
3608
3397
|
var init_container_wrap = __esm({
|
|
3609
3398
|
"../adapters/src/_core/container-wrap.ts"() {
|
|
3610
3399
|
"use strict";
|
|
3611
3400
|
import_node_crypto5 = require("node:crypto");
|
|
3612
|
-
|
|
3401
|
+
path4 = __toESM(require("node:path"), 1);
|
|
3613
3402
|
init_session_paths();
|
|
3614
3403
|
CONTAINER_DEFAULT_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
3615
3404
|
CONTAINER_HOME = "/oasis-home";
|
|
@@ -3621,7 +3410,7 @@ var init_container_wrap = __esm({
|
|
|
3621
3410
|
function podmanAvailable() {
|
|
3622
3411
|
if (podmanProbe === void 0) {
|
|
3623
3412
|
try {
|
|
3624
|
-
podmanProbe = (0,
|
|
3413
|
+
podmanProbe = (0, import_node_child_process.spawnSync)(PODMAN, ["--version"], { timeout: 1e4 }).status === 0;
|
|
3625
3414
|
} catch {
|
|
3626
3415
|
podmanProbe = false;
|
|
3627
3416
|
}
|
|
@@ -3629,19 +3418,19 @@ function podmanAvailable() {
|
|
|
3629
3418
|
return podmanProbe;
|
|
3630
3419
|
}
|
|
3631
3420
|
function resolveBinHostPath(bin) {
|
|
3632
|
-
if (bin.includes(
|
|
3421
|
+
if (bin.includes(path5.sep)) {
|
|
3633
3422
|
try {
|
|
3634
|
-
return
|
|
3423
|
+
return fs4.realpathSync(path5.resolve(bin));
|
|
3635
3424
|
} catch {
|
|
3636
|
-
return
|
|
3425
|
+
return path5.resolve(bin);
|
|
3637
3426
|
}
|
|
3638
3427
|
}
|
|
3639
|
-
for (const dir of (process.env["PATH"] ?? "").split(
|
|
3428
|
+
for (const dir of (process.env["PATH"] ?? "").split(path5.delimiter)) {
|
|
3640
3429
|
if (!dir) continue;
|
|
3641
|
-
const candidate =
|
|
3430
|
+
const candidate = path5.join(dir, bin);
|
|
3642
3431
|
try {
|
|
3643
|
-
|
|
3644
|
-
return
|
|
3432
|
+
fs4.accessSync(candidate, fs4.constants.X_OK);
|
|
3433
|
+
return fs4.realpathSync(candidate);
|
|
3645
3434
|
} catch {
|
|
3646
3435
|
}
|
|
3647
3436
|
}
|
|
@@ -3649,25 +3438,25 @@ function resolveBinHostPath(bin) {
|
|
|
3649
3438
|
}
|
|
3650
3439
|
function resolveBinPackageDir(binHostPath) {
|
|
3651
3440
|
if (!/\.(js|mjs|cjs)$/i.test(binHostPath)) return null;
|
|
3652
|
-
let dir =
|
|
3441
|
+
let dir = path5.dirname(binHostPath);
|
|
3653
3442
|
for (let i = 0; i < 8; i++) {
|
|
3654
|
-
if (
|
|
3655
|
-
if (dir === "/" || dir === os2.tmpdir() || dir.split(
|
|
3443
|
+
if (fs4.existsSync(path5.join(dir, "package.json"))) {
|
|
3444
|
+
if (dir === "/" || dir === os2.tmpdir() || dir.split(path5.sep).length <= 2) return null;
|
|
3656
3445
|
return dir;
|
|
3657
3446
|
}
|
|
3658
|
-
const parent =
|
|
3447
|
+
const parent = path5.dirname(dir);
|
|
3659
3448
|
if (parent === dir) break;
|
|
3660
3449
|
dir = parent;
|
|
3661
3450
|
}
|
|
3662
3451
|
return null;
|
|
3663
3452
|
}
|
|
3664
3453
|
function containerHomeHostDir(workRoot) {
|
|
3665
|
-
const dir =
|
|
3666
|
-
|
|
3454
|
+
const dir = path5.join(resolveWorkRoot(workRoot), "container-home");
|
|
3455
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
3667
3456
|
return dir;
|
|
3668
3457
|
}
|
|
3669
3458
|
async function ensureImage(image) {
|
|
3670
|
-
const exists = (0,
|
|
3459
|
+
const exists = (0, import_node_child_process.spawnSync)(PODMAN, ["image", "exists", image], { timeout: 15e3 }).status === 0;
|
|
3671
3460
|
if (!exists) {
|
|
3672
3461
|
try {
|
|
3673
3462
|
await execFileP(PODMAN, ["pull", image], { timeout: 6e5 });
|
|
@@ -3685,7 +3474,7 @@ async function ensureImage(image) {
|
|
|
3685
3474
|
async function ensurePersistContainer(plan) {
|
|
3686
3475
|
if (plan.mode !== "exec" || !plan.ensureArgs) return;
|
|
3687
3476
|
const name = plan.containerName;
|
|
3688
|
-
const exists = (0,
|
|
3477
|
+
const exists = (0, import_node_child_process.spawnSync)(PODMAN, ["container", "exists", name], { timeout: 15e3 }).status === 0;
|
|
3689
3478
|
if (exists) {
|
|
3690
3479
|
const { stdout: label2 } = await execFileP(
|
|
3691
3480
|
PODMAN,
|
|
@@ -3704,7 +3493,7 @@ async function ensurePersistContainer(plan) {
|
|
|
3704
3493
|
}
|
|
3705
3494
|
function killContainerBestEffort(containerName, _mode) {
|
|
3706
3495
|
try {
|
|
3707
|
-
(0,
|
|
3496
|
+
(0, import_node_child_process.execFile)(PODMAN, killContainerArgs(containerName), { timeout: 3e4 }, () => {
|
|
3708
3497
|
});
|
|
3709
3498
|
} catch {
|
|
3710
3499
|
}
|
|
@@ -3725,8 +3514,8 @@ async function reapEphemeralContainers() {
|
|
|
3725
3514
|
}
|
|
3726
3515
|
function removePersistContainerForDir(workdir) {
|
|
3727
3516
|
if (!podmanAvailable()) return;
|
|
3728
|
-
const name = `oasis-wd-${
|
|
3729
|
-
(0,
|
|
3517
|
+
const name = `oasis-wd-${path5.basename(workdir)}`;
|
|
3518
|
+
(0, import_node_child_process.execFile)(PODMAN, ["rm", "-f", name], { timeout: 3e4 }, () => {
|
|
3730
3519
|
});
|
|
3731
3520
|
}
|
|
3732
3521
|
async function maybeContainerize(params) {
|
|
@@ -3739,12 +3528,12 @@ async function maybeContainerize(params) {
|
|
|
3739
3528
|
const env = containerEnv(params.job, params.extraEnvEarly, params.extraEnvLate);
|
|
3740
3529
|
const extraRoBindDirs = [...new Set((params.job.wrapperPaths ?? []).flatMap((w2) => {
|
|
3741
3530
|
try {
|
|
3742
|
-
const target =
|
|
3743
|
-
const targetDir =
|
|
3744
|
-
const baseSibling =
|
|
3531
|
+
const target = fs4.realpathSync(w2);
|
|
3532
|
+
const targetDir = path5.dirname(target);
|
|
3533
|
+
const baseSibling = path5.join(path5.dirname(targetDir), "_base");
|
|
3745
3534
|
const dirs = [targetDir];
|
|
3746
|
-
if (
|
|
3747
|
-
return dirs.filter((d) => d !== "/" && d !== os2.tmpdir() && d.split(
|
|
3535
|
+
if (fs4.existsSync(baseSibling)) dirs.push(baseSibling);
|
|
3536
|
+
return dirs.filter((d) => d !== "/" && d !== os2.tmpdir() && d.split(path5.sep).length > 2);
|
|
3748
3537
|
} catch {
|
|
3749
3538
|
return [];
|
|
3750
3539
|
}
|
|
@@ -3753,7 +3542,7 @@ async function maybeContainerize(params) {
|
|
|
3753
3542
|
const binPackageDir = resolveBinPackageDir(binHostPath);
|
|
3754
3543
|
const plan = wrapForContainer({
|
|
3755
3544
|
binHostPath,
|
|
3756
|
-
binName:
|
|
3545
|
+
binName: path5.basename(params.bin),
|
|
3757
3546
|
// realpath 前的名字("claude")——argv[0] 语义要保住
|
|
3758
3547
|
...binPackageDir ? { binPackageDir } : {},
|
|
3759
3548
|
args: params.args,
|
|
@@ -3768,22 +3557,22 @@ async function maybeContainerize(params) {
|
|
|
3768
3557
|
if (plan.droppedEnvNames.length > 0) {
|
|
3769
3558
|
console.warn(`[container] \u8FD9\u4E9B\u53D8\u91CF\u540D\u653E\u4E0D\u8FDB\u5BB9\u5668\uFF08\u5F00\u5934\u7A7A\u767D / \u542B = / \u7A7A\u5B57\u7B26\uFF09\uFF0C\u672C\u8F6E\u672A\u6CE8\u5165\uFF1A${plan.droppedEnvNames.map((k2) => JSON.stringify(k2)).join(", ")}`);
|
|
3770
3559
|
}
|
|
3771
|
-
if (plan.cidFile)
|
|
3560
|
+
if (plan.cidFile) fs4.rmSync(plan.cidFile, { force: true });
|
|
3772
3561
|
await ensurePersistContainer(plan);
|
|
3773
3562
|
return { bin: plan.bin, args: plan.args, env, containerName: plan.containerName, mode: plan.mode, imageDigest };
|
|
3774
3563
|
}
|
|
3775
|
-
var
|
|
3564
|
+
var import_node_child_process, fs4, os2, path5, import_node_util, execFileP, PODMAN, podmanProbe;
|
|
3776
3565
|
var init_container_runtime = __esm({
|
|
3777
3566
|
"../adapters/src/_core/container-runtime.ts"() {
|
|
3778
3567
|
"use strict";
|
|
3779
|
-
|
|
3780
|
-
|
|
3568
|
+
import_node_child_process = require("node:child_process");
|
|
3569
|
+
fs4 = __toESM(require("node:fs"), 1);
|
|
3781
3570
|
os2 = __toESM(require("node:os"), 1);
|
|
3782
|
-
|
|
3571
|
+
path5 = __toESM(require("node:path"), 1);
|
|
3783
3572
|
import_node_util = require("node:util");
|
|
3784
3573
|
init_container_wrap();
|
|
3785
3574
|
init_session_paths();
|
|
3786
|
-
execFileP = (0, import_node_util.promisify)(
|
|
3575
|
+
execFileP = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
3787
3576
|
PODMAN = "podman";
|
|
3788
3577
|
}
|
|
3789
3578
|
});
|
|
@@ -3987,16 +3776,16 @@ var init_model_report = __esm({
|
|
|
3987
3776
|
|
|
3988
3777
|
// ../adapters/src/_core/transcript.ts
|
|
3989
3778
|
function openTranscript(file) {
|
|
3990
|
-
const out =
|
|
3779
|
+
const out = fs5.createWriteStream(file);
|
|
3991
3780
|
out.on("error", () => {
|
|
3992
3781
|
});
|
|
3993
3782
|
return out;
|
|
3994
3783
|
}
|
|
3995
|
-
var
|
|
3784
|
+
var fs5;
|
|
3996
3785
|
var init_transcript = __esm({
|
|
3997
3786
|
"../adapters/src/_core/transcript.ts"() {
|
|
3998
3787
|
"use strict";
|
|
3999
|
-
|
|
3788
|
+
fs5 = __toESM(require("node:fs"), 1);
|
|
4000
3789
|
}
|
|
4001
3790
|
});
|
|
4002
3791
|
|
|
@@ -4104,10 +3893,10 @@ function byModelOf(calls) {
|
|
|
4104
3893
|
}
|
|
4105
3894
|
function readSubagentTranscriptCalls(outputFile) {
|
|
4106
3895
|
try {
|
|
4107
|
-
const stat4 =
|
|
3896
|
+
const stat4 = fs6.statSync(outputFile);
|
|
4108
3897
|
if (!stat4.isFile() || stat4.size > SUBAGENT_TRANSCRIPT_MAX_BYTES) return void 0;
|
|
4109
3898
|
const calls = /* @__PURE__ */ new Map();
|
|
4110
|
-
for (const line2 of
|
|
3899
|
+
for (const line2 of fs6.readFileSync(outputFile, "utf8").split("\n")) {
|
|
4111
3900
|
if (!line2.includes('"assistant"') || !line2.includes('"usage"')) continue;
|
|
4112
3901
|
let parsed;
|
|
4113
3902
|
try {
|
|
@@ -4362,14 +4151,14 @@ function newClaudeUsageAcc() {
|
|
|
4362
4151
|
};
|
|
4363
4152
|
}
|
|
4364
4153
|
function findClaudeSessionFile(configDir, cwd, runtimeSessionId) {
|
|
4365
|
-
const root =
|
|
4154
|
+
const root = path6.join(configDir, "projects");
|
|
4366
4155
|
const name = `${runtimeSessionId}.jsonl`;
|
|
4367
|
-
const direct =
|
|
4368
|
-
if (
|
|
4156
|
+
const direct = path6.join(root, cwd.replace(/[^a-zA-Z0-9]/g, "-"), name);
|
|
4157
|
+
if (fs6.existsSync(direct)) return direct;
|
|
4369
4158
|
try {
|
|
4370
|
-
for (const slug6 of
|
|
4371
|
-
const candidate =
|
|
4372
|
-
if (
|
|
4159
|
+
for (const slug6 of fs6.readdirSync(root)) {
|
|
4160
|
+
const candidate = path6.join(root, slug6, name);
|
|
4161
|
+
if (fs6.existsSync(candidate)) return candidate;
|
|
4373
4162
|
}
|
|
4374
4163
|
} catch {
|
|
4375
4164
|
}
|
|
@@ -4377,15 +4166,15 @@ function findClaudeSessionFile(configDir, cwd, runtimeSessionId) {
|
|
|
4377
4166
|
}
|
|
4378
4167
|
function readClaudeRestoredCost(sessionFile) {
|
|
4379
4168
|
try {
|
|
4380
|
-
const stat4 =
|
|
4169
|
+
const stat4 = fs6.statSync(sessionFile);
|
|
4381
4170
|
if (!stat4.isFile() || stat4.size === 0) return null;
|
|
4382
4171
|
const length = Math.min(stat4.size, RESTORED_COST_TAIL_BYTES);
|
|
4383
4172
|
const buf = Buffer.alloc(length);
|
|
4384
|
-
const fd =
|
|
4173
|
+
const fd = fs6.openSync(sessionFile, "r");
|
|
4385
4174
|
try {
|
|
4386
|
-
|
|
4175
|
+
fs6.readSync(fd, buf, 0, length, stat4.size - length);
|
|
4387
4176
|
} finally {
|
|
4388
|
-
|
|
4177
|
+
fs6.closeSync(fd);
|
|
4389
4178
|
}
|
|
4390
4179
|
const lines = buf.toString("utf8").split("\n");
|
|
4391
4180
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -4609,15 +4398,15 @@ function classifyExit(result) {
|
|
|
4609
4398
|
if (status === 429 || status === 529) return "rate-limit";
|
|
4610
4399
|
return "error";
|
|
4611
4400
|
}
|
|
4612
|
-
var
|
|
4401
|
+
var import_node_child_process2, import_node_crypto6, fs6, os3, path6, readline, CLAUDE_BLOCKED_FLAGS, SUBAGENT_TRANSCRIPT_MAX_BYTES, SUBAGENT_TERMINAL, RESTORED_COST_TAIL_BYTES, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
4613
4402
|
var init_claude_code = __esm({
|
|
4614
4403
|
"../adapters/src/claude-code/index.ts"() {
|
|
4615
4404
|
"use strict";
|
|
4616
|
-
|
|
4405
|
+
import_node_child_process2 = require("node:child_process");
|
|
4617
4406
|
import_node_crypto6 = require("node:crypto");
|
|
4618
|
-
|
|
4407
|
+
fs6 = __toESM(require("node:fs"), 1);
|
|
4619
4408
|
os3 = __toESM(require("node:os"), 1);
|
|
4620
|
-
|
|
4409
|
+
path6 = __toESM(require("node:path"), 1);
|
|
4621
4410
|
readline = __toESM(require("node:readline"), 1);
|
|
4622
4411
|
init_sync_skills();
|
|
4623
4412
|
init_materialize_bundle();
|
|
@@ -4721,7 +4510,7 @@ var init_claude_code = __esm({
|
|
|
4721
4510
|
runtimeKind: "claude"
|
|
4722
4511
|
}
|
|
4723
4512
|
});
|
|
4724
|
-
|
|
4513
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
4725
4514
|
await runSyncSkills(this.opts.syncSkills, {
|
|
4726
4515
|
actorId: job.actor,
|
|
4727
4516
|
actorToken: job.actorToken,
|
|
@@ -4762,7 +4551,7 @@ var init_claude_code = __esm({
|
|
|
4762
4551
|
{ runtime: "claude-code", actor: job.actor, ...job.dispatchId ? { dispatchId: job.dispatchId } : {} }
|
|
4763
4552
|
)
|
|
4764
4553
|
];
|
|
4765
|
-
const claudeConfigDir = job.env?.["CLAUDE_CONFIG_DIR"] || this.opts.env?.["CLAUDE_CONFIG_DIR"] || process.env["CLAUDE_CONFIG_DIR"] ||
|
|
4554
|
+
const claudeConfigDir = job.env?.["CLAUDE_CONFIG_DIR"] || this.opts.env?.["CLAUDE_CONFIG_DIR"] || process.env["CLAUDE_CONFIG_DIR"] || path6.join(os3.homedir(), ".claude");
|
|
4766
4555
|
const resumedSessionFile = job.runtimeSessionId && job.resumeRuntimeSession ? findClaudeSessionFile(claudeConfigDir, dir, job.runtimeSessionId) : void 0;
|
|
4767
4556
|
const restoredCost = resumedSessionFile ? readClaudeRestoredCost(resumedSessionFile) : null;
|
|
4768
4557
|
const otelEnv = this.resolveOtelEnv(job, id);
|
|
@@ -4780,11 +4569,11 @@ var init_claude_code = __esm({
|
|
|
4780
4569
|
...otelEnv
|
|
4781
4570
|
}
|
|
4782
4571
|
});
|
|
4783
|
-
const child = containerized ? (0,
|
|
4572
|
+
const child = containerized ? (0, import_node_child_process2.spawn)(containerized.bin, containerized.args, {
|
|
4784
4573
|
cwd: dir,
|
|
4785
4574
|
env: scrubLeakyEnv(process.env),
|
|
4786
4575
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4787
|
-
}) : (0,
|
|
4576
|
+
}) : (0, import_node_child_process2.spawn)(this.opts.claudeBin ?? "claude", args, {
|
|
4788
4577
|
cwd: dir,
|
|
4789
4578
|
env: {
|
|
4790
4579
|
// 凭证泄漏防护:剔除 pnpm/npm 脚本注入的变量——npm_lifecycle_script 等会把 serve 的启动命令
|
|
@@ -4795,7 +4584,7 @@ var init_claude_code = __esm({
|
|
|
4795
4584
|
...job.env,
|
|
4796
4585
|
// BUG-4 缓冲:抬高单响应输出 token 上限(临时缓冲,根治靠分解)
|
|
4797
4586
|
...this.opts.maxOutputTokens ? { CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(this.opts.maxOutputTokens) } : {},
|
|
4798
|
-
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) =>
|
|
4587
|
+
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path6.dirname(p2)).join(path6.delimiter)}${path6.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
|
|
4799
4588
|
OASIS_SERVER: job.server.url,
|
|
4800
4589
|
OASIS_TOKEN: job.actorToken,
|
|
4801
4590
|
// OTel 遥测(默认关;resolveOtelEnv 决定开不开,runId 进 resource 属性自然归位到本次 run)。
|
|
@@ -4875,7 +4664,7 @@ var init_claude_code = __esm({
|
|
|
4875
4664
|
if (promptViaStdin) child.stdin.write(prompt2);
|
|
4876
4665
|
child.stdin.end();
|
|
4877
4666
|
}
|
|
4878
|
-
let transcriptRef =
|
|
4667
|
+
let transcriptRef = path6.join(dir, "transcript.txt");
|
|
4879
4668
|
const out = openTranscript(transcriptRef);
|
|
4880
4669
|
diag = (event, extra) => {
|
|
4881
4670
|
try {
|
|
@@ -5016,14 +4805,14 @@ var init_claude_code = __esm({
|
|
|
5016
4805
|
touchMetaExit(dir, { at: (/* @__PURE__ */ new Date()).toISOString(), ...reason ? { reason } : {}, runId: id });
|
|
5017
4806
|
if (this.opts.cleanupWorkdir && isOneShot) {
|
|
5018
4807
|
try {
|
|
5019
|
-
const keepDir =
|
|
5020
|
-
|
|
5021
|
-
const kept =
|
|
4808
|
+
const keepDir = path6.join(resolveWorkRoot(this.opts.workRoot), "oasis-transcripts");
|
|
4809
|
+
fs6.mkdirSync(keepDir, { recursive: true });
|
|
4810
|
+
const kept = path6.join(keepDir, `${id}.txt`);
|
|
5022
4811
|
const src = transcriptRef;
|
|
5023
4812
|
out.end(() => {
|
|
5024
4813
|
try {
|
|
5025
|
-
|
|
5026
|
-
|
|
4814
|
+
fs6.renameSync(src, kept);
|
|
4815
|
+
fs6.rmSync(dir, { recursive: true, force: true });
|
|
5027
4816
|
} catch {
|
|
5028
4817
|
}
|
|
5029
4818
|
});
|
|
@@ -5369,7 +5158,7 @@ var init_resilient = __esm({
|
|
|
5369
5158
|
|
|
5370
5159
|
// ../adapters/src/_core/skill-cache.ts
|
|
5371
5160
|
function defaultCacheRoot() {
|
|
5372
|
-
return
|
|
5161
|
+
return path7.join(os4.homedir(), ".oasis", "skill-cache");
|
|
5373
5162
|
}
|
|
5374
5163
|
function sessionSkillsSubdir(runtimeKind) {
|
|
5375
5164
|
switch (runtimeKind) {
|
|
@@ -5390,7 +5179,7 @@ async function syncActorSkills(opts) {
|
|
|
5390
5179
|
});
|
|
5391
5180
|
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
5392
5181
|
const actorDir = pathForActor(cacheRoot, opts.actorId);
|
|
5393
|
-
const manifestPath =
|
|
5182
|
+
const manifestPath = path7.join(actorDir, "manifest.json");
|
|
5394
5183
|
await fsp.mkdir(actorDir, { recursive: true, mode: 493 });
|
|
5395
5184
|
const release = await acquireLock(cacheRoot, opts.actorId, now, log3);
|
|
5396
5185
|
try {
|
|
@@ -5411,7 +5200,7 @@ async function syncActorSkills(opts) {
|
|
|
5411
5200
|
for (const [id, entry] of Object.entries(manifest.skills)) {
|
|
5412
5201
|
if (cloudIds.has(id)) continue;
|
|
5413
5202
|
try {
|
|
5414
|
-
await fsp.rm(
|
|
5203
|
+
await fsp.rm(path7.join(actorDir, entry.dir), { recursive: true, force: true });
|
|
5415
5204
|
} catch (err) {
|
|
5416
5205
|
log3("warn", `\u5220\u9664\u5B64\u513F\u6280\u80FD\u76EE\u5F55\u5931\u8D25 ${entry.dir}`, err);
|
|
5417
5206
|
}
|
|
@@ -5423,7 +5212,7 @@ async function syncActorSkills(opts) {
|
|
|
5423
5212
|
const forceClearForSession = /* @__PURE__ */ new Set();
|
|
5424
5213
|
for (const cloud of cloudMetadata) {
|
|
5425
5214
|
const variantSlug = variantSlugFor(cloud.contentHash);
|
|
5426
|
-
const variantDir =
|
|
5215
|
+
const variantDir = path7.join(actorDir, cloud.dir, variantSlug);
|
|
5427
5216
|
const cached3 = manifest.skills[cloud.id];
|
|
5428
5217
|
const alreadyMaterialized = await dirLooksValid(variantDir, cloud.fileList);
|
|
5429
5218
|
let actualFiles = null;
|
|
@@ -5445,7 +5234,7 @@ async function syncActorSkills(opts) {
|
|
|
5445
5234
|
fileList: cloud.fileList
|
|
5446
5235
|
};
|
|
5447
5236
|
if (cached3 && cached3.dir !== cloud.dir) {
|
|
5448
|
-
await fsp.rm(
|
|
5237
|
+
await fsp.rm(path7.join(actorDir, cached3.dir), { recursive: true, force: true }).catch(() => {
|
|
5449
5238
|
});
|
|
5450
5239
|
}
|
|
5451
5240
|
desiredForSession.set(cloud.dir, { variantDir, variantSlug });
|
|
@@ -5507,7 +5296,7 @@ async function syncActorSkills(opts) {
|
|
|
5507
5296
|
fileList: cloud.fileList
|
|
5508
5297
|
};
|
|
5509
5298
|
if (cached3 && cached3.dir !== cloud.dir) {
|
|
5510
|
-
await fsp.rm(
|
|
5299
|
+
await fsp.rm(path7.join(actorDir, cached3.dir), { recursive: true, force: true }).catch(() => {
|
|
5511
5300
|
});
|
|
5512
5301
|
}
|
|
5513
5302
|
desiredForSession.set(cloud.dir, { variantDir, variantSlug });
|
|
@@ -5537,10 +5326,10 @@ async function syncActorSkills(opts) {
|
|
|
5537
5326
|
}
|
|
5538
5327
|
}
|
|
5539
5328
|
function pathForActor(cacheRoot, actorId) {
|
|
5540
|
-
return
|
|
5329
|
+
return path7.join(cacheRoot, "actors", encodeURIComponent(actorId));
|
|
5541
5330
|
}
|
|
5542
5331
|
function lockPathFor(cacheRoot, actorId) {
|
|
5543
|
-
return
|
|
5332
|
+
return path7.join(cacheRoot, "locks", `${encodeURIComponent(actorId)}.lock`);
|
|
5544
5333
|
}
|
|
5545
5334
|
function aggregateSkillContentHash(files) {
|
|
5546
5335
|
const sorted = [...files].sort((a, b2) => a.path.localeCompare(b2.path));
|
|
@@ -5562,7 +5351,7 @@ function variantSlugFor(contentHash) {
|
|
|
5562
5351
|
}
|
|
5563
5352
|
async function acquireLock(cacheRoot, actorId, now, log3) {
|
|
5564
5353
|
const lockPath = lockPathFor(cacheRoot, actorId);
|
|
5565
|
-
await fsp.mkdir(
|
|
5354
|
+
await fsp.mkdir(path7.dirname(lockPath), { recursive: true, mode: 493 });
|
|
5566
5355
|
const started = now().getTime();
|
|
5567
5356
|
while (true) {
|
|
5568
5357
|
try {
|
|
@@ -5628,28 +5417,28 @@ async function readManifest(manifestPath, actorId, log3) {
|
|
|
5628
5417
|
};
|
|
5629
5418
|
}
|
|
5630
5419
|
async function writeManifest(manifestPath, manifest) {
|
|
5631
|
-
const dir =
|
|
5420
|
+
const dir = path7.dirname(manifestPath);
|
|
5632
5421
|
await fsp.mkdir(dir, { recursive: true });
|
|
5633
5422
|
const tmp = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;
|
|
5634
5423
|
await fsp.writeFile(tmp, JSON.stringify(manifest, null, 2), { mode: 420 });
|
|
5635
5424
|
await fsp.rename(tmp, manifestPath);
|
|
5636
5425
|
}
|
|
5637
5426
|
async function materializeVariantDir(actorDir, targetDir, variantSlug, files) {
|
|
5638
|
-
const parentPath =
|
|
5427
|
+
const parentPath = path7.join(actorDir, targetDir);
|
|
5639
5428
|
await fsp.mkdir(parentPath, { recursive: true, mode: 493 });
|
|
5640
|
-
const targetPath =
|
|
5641
|
-
const tmpPath =
|
|
5642
|
-
const oldBackup =
|
|
5429
|
+
const targetPath = path7.join(parentPath, variantSlug);
|
|
5430
|
+
const tmpPath = path7.join(parentPath, `${variantSlug}.new.${process.pid}.${Date.now()}`);
|
|
5431
|
+
const oldBackup = path7.join(parentPath, `${variantSlug}.old.${process.pid}.${Date.now()}`);
|
|
5643
5432
|
await fsp.rm(tmpPath, { recursive: true, force: true });
|
|
5644
5433
|
await fsp.mkdir(tmpPath, { recursive: true, mode: 493 });
|
|
5645
5434
|
for (const f2 of files) {
|
|
5646
5435
|
if (!f2.content) continue;
|
|
5647
|
-
const dest =
|
|
5648
|
-
const rel =
|
|
5649
|
-
if (rel.startsWith("..") ||
|
|
5436
|
+
const dest = path7.join(tmpPath, f2.path);
|
|
5437
|
+
const rel = path7.relative(tmpPath, dest);
|
|
5438
|
+
if (rel.startsWith("..") || path7.isAbsolute(rel)) {
|
|
5650
5439
|
throw new Error(`SkillFile.path \u4E0D\u5408\u6CD5: ${f2.path}`);
|
|
5651
5440
|
}
|
|
5652
|
-
await fsp.mkdir(
|
|
5441
|
+
await fsp.mkdir(path7.dirname(dest), { recursive: true });
|
|
5653
5442
|
await fsp.writeFile(dest, f2.content, { mode: 420 });
|
|
5654
5443
|
}
|
|
5655
5444
|
let hadOld = false;
|
|
@@ -5667,7 +5456,7 @@ async function dirLooksValid(dir, expectFileList) {
|
|
|
5667
5456
|
if (expectFileList.length === 0) return false;
|
|
5668
5457
|
try {
|
|
5669
5458
|
for (const rel of expectFileList) {
|
|
5670
|
-
await fsp.stat(
|
|
5459
|
+
await fsp.stat(path7.join(dir, rel));
|
|
5671
5460
|
}
|
|
5672
5461
|
return true;
|
|
5673
5462
|
} catch {
|
|
@@ -5679,7 +5468,7 @@ async function hashMaterializedDir(dir, fileList) {
|
|
|
5679
5468
|
try {
|
|
5680
5469
|
const files = [];
|
|
5681
5470
|
for (const rel of fileList) {
|
|
5682
|
-
const content3 = await fsp.readFile(
|
|
5471
|
+
const content3 = await fsp.readFile(path7.join(dir, rel), "utf8");
|
|
5683
5472
|
files.push({ path: rel, content: content3 });
|
|
5684
5473
|
}
|
|
5685
5474
|
return aggregateSkillContentHash(files);
|
|
@@ -5691,10 +5480,10 @@ async function listMaterializedFiles(dir) {
|
|
|
5691
5480
|
try {
|
|
5692
5481
|
const out = [];
|
|
5693
5482
|
const walk = async (sub) => {
|
|
5694
|
-
const abs = sub ?
|
|
5483
|
+
const abs = sub ? path7.join(dir, sub) : dir;
|
|
5695
5484
|
const entries = await fsp.readdir(abs, { withFileTypes: true });
|
|
5696
5485
|
for (const e of entries) {
|
|
5697
|
-
const rel = sub ?
|
|
5486
|
+
const rel = sub ? path7.join(sub, e.name) : e.name;
|
|
5698
5487
|
if (e.isDirectory()) {
|
|
5699
5488
|
await walk(rel);
|
|
5700
5489
|
} else {
|
|
@@ -5710,14 +5499,14 @@ async function listMaterializedFiles(dir) {
|
|
|
5710
5499
|
}
|
|
5711
5500
|
async function syncSessionSymlinks(sessionDir, runtimeKind, desired, pending, forceClear, log3) {
|
|
5712
5501
|
const subdir = sessionSkillsSubdir(runtimeKind);
|
|
5713
|
-
const skillsDir =
|
|
5502
|
+
const skillsDir = path7.join(sessionDir, subdir);
|
|
5714
5503
|
await fsp.mkdir(skillsDir, { recursive: true, mode: 493 });
|
|
5715
5504
|
for (const [name, { variantDir }] of desired) {
|
|
5716
|
-
const link =
|
|
5505
|
+
const link = path7.join(skillsDir, name);
|
|
5717
5506
|
let ok3 = false;
|
|
5718
5507
|
try {
|
|
5719
5508
|
const current = await fsp.readlink(link);
|
|
5720
|
-
ok3 =
|
|
5509
|
+
ok3 = path7.resolve(skillsDir, current) === variantDir;
|
|
5721
5510
|
} catch {
|
|
5722
5511
|
}
|
|
5723
5512
|
if (!ok3) {
|
|
@@ -5744,22 +5533,22 @@ async function syncSessionSymlinks(sessionDir, runtimeKind, desired, pending, fo
|
|
|
5744
5533
|
}
|
|
5745
5534
|
}
|
|
5746
5535
|
try {
|
|
5747
|
-
await fsp.rm(
|
|
5536
|
+
await fsp.rm(path7.join(skillsDir, name), { recursive: true, force: true });
|
|
5748
5537
|
} catch (err) {
|
|
5749
5538
|
log3("warn", `\u6E05\u5B64\u513F\u5931\u8D25 ${name}`, err);
|
|
5750
5539
|
}
|
|
5751
5540
|
}
|
|
5752
5541
|
}
|
|
5753
5542
|
async function verifyPendingLink(skillsDir, name, pend, log3) {
|
|
5754
|
-
const link =
|
|
5543
|
+
const link = path7.join(skillsDir, name);
|
|
5755
5544
|
let resolved;
|
|
5756
5545
|
try {
|
|
5757
5546
|
const current = await fsp.readlink(link);
|
|
5758
|
-
resolved =
|
|
5547
|
+
resolved = path7.resolve(skillsDir, current);
|
|
5759
5548
|
} catch {
|
|
5760
5549
|
return false;
|
|
5761
5550
|
}
|
|
5762
|
-
if (
|
|
5551
|
+
if (path7.basename(resolved) !== pend.wantedVariantSlug) return false;
|
|
5763
5552
|
const actual = await listMaterializedFiles(resolved);
|
|
5764
5553
|
const expected = [...pend.fileList].sort();
|
|
5765
5554
|
const setsMatch = actual !== null && actual.length === expected.length && actual.every((p2, i) => p2 === expected[i]);
|
|
@@ -5774,14 +5563,14 @@ async function verifyPendingLink(skillsDir, name, pend, log3) {
|
|
|
5774
5563
|
}
|
|
5775
5564
|
return true;
|
|
5776
5565
|
}
|
|
5777
|
-
var import_node_crypto7, fsp, os4,
|
|
5566
|
+
var import_node_crypto7, fsp, os4, path7, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
|
|
5778
5567
|
var init_skill_cache = __esm({
|
|
5779
5568
|
"../adapters/src/_core/skill-cache.ts"() {
|
|
5780
5569
|
"use strict";
|
|
5781
5570
|
import_node_crypto7 = require("node:crypto");
|
|
5782
5571
|
fsp = __toESM(require("node:fs/promises"), 1);
|
|
5783
5572
|
os4 = __toESM(require("node:os"), 1);
|
|
5784
|
-
|
|
5573
|
+
path7 = __toESM(require("node:path"), 1);
|
|
5785
5574
|
MANIFEST_SCHEMA_VERSION = 2;
|
|
5786
5575
|
STALE_LOCK_MS = 6e4;
|
|
5787
5576
|
LOCK_ACQUIRE_TIMEOUT_MS = 3e4;
|
|
@@ -5836,7 +5625,7 @@ var init_skill_cache_http = __esm({
|
|
|
5836
5625
|
function resolveOnPath(binary) {
|
|
5837
5626
|
try {
|
|
5838
5627
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
5839
|
-
const out = (0,
|
|
5628
|
+
const out = (0, import_node_child_process3.execFileSync)(cmd, [binary], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
5840
5629
|
const first = out.split("\n")[0]?.trim();
|
|
5841
5630
|
return first || void 0;
|
|
5842
5631
|
} catch {
|
|
@@ -5845,7 +5634,7 @@ function resolveOnPath(binary) {
|
|
|
5845
5634
|
}
|
|
5846
5635
|
function verifyCursorAcpIdentity(binary) {
|
|
5847
5636
|
try {
|
|
5848
|
-
(0,
|
|
5637
|
+
(0, import_node_child_process3.execFileSync)(binary, ["acp", "--help"], {
|
|
5849
5638
|
stdio: ["ignore", "ignore", "ignore"],
|
|
5850
5639
|
timeout: ACP_HELP_TIMEOUT_MS
|
|
5851
5640
|
});
|
|
@@ -5861,11 +5650,11 @@ function resolveCursorBinary() {
|
|
|
5861
5650
|
if (agent && verifyCursorAcpIdentity(agent)) return agent;
|
|
5862
5651
|
return void 0;
|
|
5863
5652
|
}
|
|
5864
|
-
var
|
|
5653
|
+
var import_node_child_process3, DEFAULT_CURSOR_BIN, ACP_HELP_TIMEOUT_MS;
|
|
5865
5654
|
var init_binary = __esm({
|
|
5866
5655
|
"../adapters/src/cursor/binary.ts"() {
|
|
5867
5656
|
"use strict";
|
|
5868
|
-
|
|
5657
|
+
import_node_child_process3 = require("node:child_process");
|
|
5869
5658
|
DEFAULT_CURSOR_BIN = "cursor-agent";
|
|
5870
5659
|
ACP_HELP_TIMEOUT_MS = 1500;
|
|
5871
5660
|
}
|
|
@@ -6073,7 +5862,7 @@ async function probeCodexAppServer(bin, timeoutMs = 15e3) {
|
|
|
6073
5862
|
}
|
|
6074
5863
|
let child;
|
|
6075
5864
|
try {
|
|
6076
|
-
child = (0,
|
|
5865
|
+
child = (0, import_node_child_process4.spawn)(bin, ["app-server", "--stdio", "-c", "allow_login_shell=false"], {
|
|
6077
5866
|
cwd: dir,
|
|
6078
5867
|
stdio: ["pipe", "pipe", "ignore"],
|
|
6079
5868
|
env: { ...process.env }
|
|
@@ -6253,7 +6042,7 @@ async function discoverPiModels(bin) {
|
|
|
6253
6042
|
async function discoverPiModelsRPC(bin) {
|
|
6254
6043
|
const child = (() => {
|
|
6255
6044
|
try {
|
|
6256
|
-
return (0,
|
|
6045
|
+
return (0, import_node_child_process4.spawn)(bin, ["--mode", "rpc", "--no-session", "--no-skills", "--no-prompt-templates", "--no-context-files"], {
|
|
6257
6046
|
stdio: ["pipe", "pipe", "ignore"],
|
|
6258
6047
|
env: { ...process.env }
|
|
6259
6048
|
});
|
|
@@ -6330,7 +6119,7 @@ async function runCapture(bin, args, timeoutMs = 15e3) {
|
|
|
6330
6119
|
return await new Promise((resolve12) => {
|
|
6331
6120
|
let child;
|
|
6332
6121
|
try {
|
|
6333
|
-
child = (0,
|
|
6122
|
+
child = (0, import_node_child_process4.spawn)(bin, args, { stdio: ["ignore", "pipe", "ignore"], env: { ...process.env } });
|
|
6334
6123
|
} catch {
|
|
6335
6124
|
resolve12(void 0);
|
|
6336
6125
|
return;
|
|
@@ -6361,7 +6150,7 @@ async function runCapture(bin, args, timeoutMs = 15e3) {
|
|
|
6361
6150
|
async function discoverACPModels(bin, provider, args = ["acp"], timeoutMs = 12e3) {
|
|
6362
6151
|
const child = (() => {
|
|
6363
6152
|
try {
|
|
6364
|
-
return (0,
|
|
6153
|
+
return (0, import_node_child_process4.spawn)(bin, args, {
|
|
6365
6154
|
stdio: ["pipe", "pipe", "ignore"],
|
|
6366
6155
|
env: { ...process.env, ...provider === "hermes" ? { HERMES_YOLO_MODE: "1" } : {} }
|
|
6367
6156
|
});
|
|
@@ -6532,11 +6321,11 @@ function parseOpenclawAgentsText(output) {
|
|
|
6532
6321
|
function isSafeIdentifier(value2) {
|
|
6533
6322
|
return /^[A-Za-z][A-Za-z0-9._/-]*$/.test(value2);
|
|
6534
6323
|
}
|
|
6535
|
-
var
|
|
6324
|
+
var import_node_child_process4, import_node_fs2, import_node_os2, import_node_path3, modelCache, CACHE_TTL_MS;
|
|
6536
6325
|
var init_models = __esm({
|
|
6537
6326
|
"../adapters/src/_core/models.ts"() {
|
|
6538
6327
|
"use strict";
|
|
6539
|
-
|
|
6328
|
+
import_node_child_process4 = require("node:child_process");
|
|
6540
6329
|
import_node_fs2 = require("node:fs");
|
|
6541
6330
|
import_node_os2 = require("node:os");
|
|
6542
6331
|
import_node_path3 = require("node:path");
|
|
@@ -6594,16 +6383,16 @@ async function runProtocolSession(job, cfg) {
|
|
|
6594
6383
|
...cfg.env,
|
|
6595
6384
|
...job.env,
|
|
6596
6385
|
...cfg.yoloEnv ?? {},
|
|
6597
|
-
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) =>
|
|
6386
|
+
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path8.dirname(p2)).join(path8.delimiter)}${path8.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
|
|
6598
6387
|
OASIS_SERVER: job.server.url,
|
|
6599
6388
|
OASIS_TOKEN: job.actorToken,
|
|
6600
6389
|
...cfg.rootBypassRuntime ? rootBypassEnv(cfg.rootBypassRuntime) : {}
|
|
6601
6390
|
};
|
|
6602
|
-
const child = containerized ? (0,
|
|
6391
|
+
const child = containerized ? (0, import_node_child_process5.spawn)(containerized.bin, containerized.args, { cwd: dir, env: scrubLeakyEnv(process.env), stdio: ["pipe", "pipe", "pipe"] }) : (0, import_node_child_process5.spawn)(cfg.bin, args, { cwd: dir, env, stdio: ["pipe", "pipe", "pipe"] });
|
|
6603
6392
|
child.stdin.on("error", () => {
|
|
6604
6393
|
});
|
|
6605
6394
|
if (child.pid !== void 0 && job.workdirKey) lockWorkdir(dir, child.pid, "session", job.workdirKey);
|
|
6606
|
-
const transcriptRef =
|
|
6395
|
+
const transcriptRef = path8.join(dir, "transcript.txt");
|
|
6607
6396
|
const transcript = openTranscript(transcriptRef);
|
|
6608
6397
|
const outputCbs = [];
|
|
6609
6398
|
const telemetryCbs = [];
|
|
@@ -6825,13 +6614,13 @@ async function runProtocolSession(job, cfg) {
|
|
|
6825
6614
|
}
|
|
6826
6615
|
};
|
|
6827
6616
|
}
|
|
6828
|
-
var
|
|
6617
|
+
var import_node_child_process5, import_node_crypto8, path8, ProtocolCommandRejected, ProtocolSessionClosing;
|
|
6829
6618
|
var init_protocol_session = __esm({
|
|
6830
6619
|
"../adapters/src/_core/protocol-session.ts"() {
|
|
6831
6620
|
"use strict";
|
|
6832
|
-
|
|
6621
|
+
import_node_child_process5 = require("node:child_process");
|
|
6833
6622
|
import_node_crypto8 = require("node:crypto");
|
|
6834
|
-
|
|
6623
|
+
path8 = __toESM(require("node:path"), 1);
|
|
6835
6624
|
init_claude_code();
|
|
6836
6625
|
init_usage();
|
|
6837
6626
|
init_container_runtime();
|
|
@@ -6988,12 +6777,12 @@ function pickCodexReportedModel(sources) {
|
|
|
6988
6777
|
function codexSessionsRoot() {
|
|
6989
6778
|
const candidates = [];
|
|
6990
6779
|
const ch = process.env["CODEX_HOME"];
|
|
6991
|
-
if (ch) candidates.push(
|
|
6780
|
+
if (ch) candidates.push(path9.join(ch, "sessions"));
|
|
6992
6781
|
const home2 = process.env["HOME"] || os5.homedir();
|
|
6993
|
-
if (home2) candidates.push(
|
|
6782
|
+
if (home2) candidates.push(path9.join(home2, ".codex", "sessions"));
|
|
6994
6783
|
for (const c of candidates) {
|
|
6995
6784
|
try {
|
|
6996
|
-
if (
|
|
6785
|
+
if (fs7.statSync(c).isDirectory()) return c;
|
|
6997
6786
|
} catch {
|
|
6998
6787
|
}
|
|
6999
6788
|
}
|
|
@@ -7005,17 +6794,17 @@ function listRecentRollouts(root, sinceMs) {
|
|
|
7005
6794
|
const walk = (d) => {
|
|
7006
6795
|
let ents;
|
|
7007
6796
|
try {
|
|
7008
|
-
ents =
|
|
6797
|
+
ents = fs7.readdirSync(d, { withFileTypes: true });
|
|
7009
6798
|
} catch {
|
|
7010
6799
|
return;
|
|
7011
6800
|
}
|
|
7012
6801
|
for (const ent of ents) {
|
|
7013
|
-
const p2 =
|
|
6802
|
+
const p2 = path9.join(d, ent.name);
|
|
7014
6803
|
if (ent.isDirectory()) walk(p2);
|
|
7015
6804
|
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(".jsonl")) {
|
|
7016
6805
|
let m2 = 0;
|
|
7017
6806
|
try {
|
|
7018
|
-
m2 =
|
|
6807
|
+
m2 = fs7.statSync(p2).mtimeMs;
|
|
7019
6808
|
} catch {
|
|
7020
6809
|
}
|
|
7021
6810
|
if (m2 >= margin) found2.push({ f: p2, m: m2 });
|
|
@@ -7031,12 +6820,12 @@ function findRolloutsBySessionId(root, sessionId) {
|
|
|
7031
6820
|
const walk = (d) => {
|
|
7032
6821
|
let ents;
|
|
7033
6822
|
try {
|
|
7034
|
-
ents =
|
|
6823
|
+
ents = fs7.readdirSync(d, { withFileTypes: true });
|
|
7035
6824
|
} catch {
|
|
7036
6825
|
return;
|
|
7037
6826
|
}
|
|
7038
6827
|
for (const ent of ents) {
|
|
7039
|
-
const p2 =
|
|
6828
|
+
const p2 = path9.join(d, ent.name);
|
|
7040
6829
|
if (ent.isDirectory()) walk(p2);
|
|
7041
6830
|
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) found2.push(p2);
|
|
7042
6831
|
}
|
|
@@ -7066,7 +6855,7 @@ function locateCodexRollout(workdir, sinceMs, sessionsRoot = codexSessionsRoot()
|
|
|
7066
6855
|
const files = listRecentRollouts(sessionsRoot, sinceMs);
|
|
7067
6856
|
const readLines = (f2) => {
|
|
7068
6857
|
try {
|
|
7069
|
-
return
|
|
6858
|
+
return fs7.readFileSync(f2, "utf8").split("\n");
|
|
7070
6859
|
} catch {
|
|
7071
6860
|
return null;
|
|
7072
6861
|
}
|
|
@@ -7312,16 +7101,16 @@ function codexTurnErrorMessage(value2) {
|
|
|
7312
7101
|
const detail = typeof error2?.additionalDetails === "string" ? error2.additionalDetails.trim() : "";
|
|
7313
7102
|
return [summary, detail].filter(Boolean).join("\n").slice(0, 4e3);
|
|
7314
7103
|
}
|
|
7315
|
-
var
|
|
7104
|
+
var import_node_child_process6, import_node_crypto9, fs7, os5, path9, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CodexRolloutLineTail, CodexRolloutUsageTail, CodexRolloutModelTail, CODEX_APP_SERVER_BLOCKED_FLAGS, CodexAdapter;
|
|
7316
7105
|
var init_codex = __esm({
|
|
7317
7106
|
"../adapters/src/codex/index.ts"() {
|
|
7318
7107
|
"use strict";
|
|
7319
|
-
|
|
7108
|
+
import_node_child_process6 = require("node:child_process");
|
|
7320
7109
|
init_container_runtime();
|
|
7321
7110
|
import_node_crypto9 = require("node:crypto");
|
|
7322
|
-
|
|
7111
|
+
fs7 = __toESM(require("node:fs"), 1);
|
|
7323
7112
|
os5 = __toESM(require("node:os"), 1);
|
|
7324
|
-
|
|
7113
|
+
path9 = __toESM(require("node:path"), 1);
|
|
7325
7114
|
readline2 = __toESM(require("node:readline"), 1);
|
|
7326
7115
|
init_sync_skills();
|
|
7327
7116
|
init_materialize_bundle();
|
|
@@ -7359,9 +7148,9 @@ var init_codex = __esm({
|
|
|
7359
7148
|
rest = "";
|
|
7360
7149
|
/** 读新追加的整行逐行回调;文件被截短时先回调 onReset 再从头读。读失败抛给调用方(调用方吞)。 */
|
|
7361
7150
|
read(onLine, onReset) {
|
|
7362
|
-
const fd =
|
|
7151
|
+
const fd = fs7.openSync(this.file, "r");
|
|
7363
7152
|
try {
|
|
7364
|
-
const size =
|
|
7153
|
+
const size = fs7.fstatSync(fd).size;
|
|
7365
7154
|
if (size < this.offset) {
|
|
7366
7155
|
this.offset = 0;
|
|
7367
7156
|
this.rest = "";
|
|
@@ -7369,7 +7158,7 @@ var init_codex = __esm({
|
|
|
7369
7158
|
}
|
|
7370
7159
|
if (size > this.offset) {
|
|
7371
7160
|
const buf = Buffer.alloc(size - this.offset);
|
|
7372
|
-
const n =
|
|
7161
|
+
const n = fs7.readSync(fd, buf, 0, buf.length, this.offset);
|
|
7373
7162
|
this.offset += n;
|
|
7374
7163
|
const text7 = this.rest + buf.subarray(0, n).toString("utf8");
|
|
7375
7164
|
const lines = text7.split("\n");
|
|
@@ -7377,7 +7166,7 @@ var init_codex = __esm({
|
|
|
7377
7166
|
for (const line2 of lines) onLine(line2);
|
|
7378
7167
|
}
|
|
7379
7168
|
} finally {
|
|
7380
|
-
|
|
7169
|
+
fs7.closeSync(fd);
|
|
7381
7170
|
}
|
|
7382
7171
|
}
|
|
7383
7172
|
};
|
|
@@ -7640,7 +7429,7 @@ ${task}` : task;
|
|
|
7640
7429
|
let fromRollout;
|
|
7641
7430
|
if (state.rolloutPath) {
|
|
7642
7431
|
try {
|
|
7643
|
-
fromRollout = parseCodexModel(
|
|
7432
|
+
fromRollout = parseCodexModel(fs7.readFileSync(state.rolloutPath, "utf8").split("\n"));
|
|
7644
7433
|
} catch {
|
|
7645
7434
|
}
|
|
7646
7435
|
}
|
|
@@ -7792,19 +7581,19 @@ ${task}` : task;
|
|
|
7792
7581
|
...this.opts.workRoot !== void 0 ? { workRoot: this.opts.workRoot } : {},
|
|
7793
7582
|
...this.opts.env !== void 0 ? { extraEnvEarly: this.opts.env } : {}
|
|
7794
7583
|
});
|
|
7795
|
-
const child = containerized ? (0,
|
|
7584
|
+
const child = containerized ? (0, import_node_child_process6.spawn)(containerized.bin, containerized.args, {
|
|
7796
7585
|
cwd: dir,
|
|
7797
7586
|
env: scrubLeakyEnv(process.env),
|
|
7798
7587
|
// stdin 的开合口径与宿主分支一致:codex 只在走 stdin 时才该收到管道(见下方长注释)。
|
|
7799
7588
|
// 容器包装本身带 `-i`,podman 会把这条管道透传给容器内进程。
|
|
7800
7589
|
stdio: [promptViaStdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
7801
|
-
}) : (0,
|
|
7590
|
+
}) : (0, import_node_child_process6.spawn)(this.opts.codexBin ?? "codex", args, {
|
|
7802
7591
|
cwd: dir,
|
|
7803
7592
|
env: {
|
|
7804
7593
|
...scrubLeakyEnv(process.env),
|
|
7805
7594
|
...this.opts.env,
|
|
7806
7595
|
...job.env,
|
|
7807
|
-
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) =>
|
|
7596
|
+
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path9.dirname(p2)).join(path9.delimiter)}${path9.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
|
|
7808
7597
|
OASIS_SERVER: job.server.url,
|
|
7809
7598
|
OASIS_TOKEN: job.actorToken
|
|
7810
7599
|
},
|
|
@@ -7821,7 +7610,7 @@ ${task}` : task;
|
|
|
7821
7610
|
child.stdin.end(prompt2);
|
|
7822
7611
|
}
|
|
7823
7612
|
if (child.pid !== void 0 && job.workdirKey) lockWorkdir(dir, child.pid, "session", job.workdirKey);
|
|
7824
|
-
let transcriptRef =
|
|
7613
|
+
let transcriptRef = path9.join(dir, "transcript.txt");
|
|
7825
7614
|
const out = openTranscript(transcriptRef);
|
|
7826
7615
|
const outputCbs = [];
|
|
7827
7616
|
const telemetryCbs = [];
|
|
@@ -7923,14 +7712,14 @@ ${task}` : task;
|
|
|
7923
7712
|
}
|
|
7924
7713
|
if (this.opts.cleanupWorkdir && !job.workdirKey) {
|
|
7925
7714
|
try {
|
|
7926
|
-
const keepDir =
|
|
7927
|
-
|
|
7928
|
-
const kept =
|
|
7715
|
+
const keepDir = path9.join(resolveWorkRoot(this.opts.workRoot), "oasis-transcripts");
|
|
7716
|
+
fs7.mkdirSync(keepDir, { recursive: true });
|
|
7717
|
+
const kept = path9.join(keepDir, `${id}.txt`);
|
|
7929
7718
|
const src = transcriptRef;
|
|
7930
7719
|
out.end(() => {
|
|
7931
7720
|
try {
|
|
7932
|
-
|
|
7933
|
-
|
|
7721
|
+
fs7.renameSync(src, kept);
|
|
7722
|
+
fs7.rmSync(dir, { recursive: true, force: true });
|
|
7934
7723
|
} catch {
|
|
7935
7724
|
}
|
|
7936
7725
|
});
|
|
@@ -8448,10 +8237,10 @@ function buildReportedUsage(acc, model, inputTokensIncludeCacheRead) {
|
|
|
8448
8237
|
}
|
|
8449
8238
|
async function runACPSession(job, cfg) {
|
|
8450
8239
|
if (job.executionEnv) {
|
|
8451
|
-
throw new Error(`executionEnv\uFF1A${
|
|
8240
|
+
throw new Error(`executionEnv\uFF1A${path10.basename(cfg.bin)}\uFF08ACP runtime\uFF09\u5C1A\u672A\u652F\u6301\u5BB9\u5668\u5316\u6267\u884C\uFF08ADR-0147\uFF09\uFF0C\u8BF7\u6539\u6D3E claude-code \u5458\u5DE5\u6216\u53BB\u6389\u8BE5\u8282\u70B9\u7684 executionEnv \u58F0\u660E`);
|
|
8452
8241
|
}
|
|
8453
8242
|
const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
8454
|
-
const binTag =
|
|
8243
|
+
const binTag = path10.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
|
|
8455
8244
|
const id = `${binTag}-${slug6}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
|
|
8456
8245
|
const dir = job.workdirKey ? prepareWorkdir({
|
|
8457
8246
|
workRoot: cfg.workRoot,
|
|
@@ -8485,7 +8274,7 @@ async function runACPSession(job, cfg) {
|
|
|
8485
8274
|
});
|
|
8486
8275
|
}
|
|
8487
8276
|
const task = materializeBundle(dir, job.bundle);
|
|
8488
|
-
const child = (0,
|
|
8277
|
+
const child = (0, import_node_child_process7.spawn)(cfg.bin, [...cfg.args ?? [], ...prepareExtraArgs(
|
|
8489
8278
|
job.extraArgs,
|
|
8490
8279
|
cfg.extraArgs,
|
|
8491
8280
|
cfg.blockedFlags,
|
|
@@ -8497,9 +8286,9 @@ async function runACPSession(job, cfg) {
|
|
|
8497
8286
|
...cfg.env,
|
|
8498
8287
|
...job.env,
|
|
8499
8288
|
...cfg.yoloEnv ?? {},
|
|
8500
|
-
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) =>
|
|
8289
|
+
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path10.dirname(p2)).join(path10.delimiter)}${path10.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
|
|
8501
8290
|
// 每会话技能目录绝对路径 → env(供不扫 cwd 的 runtime 经 config external_dirs 发现,见 injectSkillsDirEnv)。
|
|
8502
|
-
...cfg.injectSkillsDirEnv ? { [cfg.injectSkillsDirEnv]:
|
|
8291
|
+
...cfg.injectSkillsDirEnv ? { [cfg.injectSkillsDirEnv]: path10.join(dir, sessionSkillsSubdir(cfg.runtimeKind ?? "")) } : {},
|
|
8503
8292
|
OASIS_SERVER: job.server.url,
|
|
8504
8293
|
OASIS_TOKEN: job.actorToken,
|
|
8505
8294
|
...cfg.rootBypassRuntime ? rootBypassEnv(cfg.rootBypassRuntime) : {}
|
|
@@ -8509,7 +8298,7 @@ async function runACPSession(job, cfg) {
|
|
|
8509
8298
|
child.stdin.on("error", () => {
|
|
8510
8299
|
});
|
|
8511
8300
|
if (child.pid !== void 0 && job.workdirKey) lockWorkdir(dir, child.pid, "session", job.workdirKey);
|
|
8512
|
-
let transcriptRef =
|
|
8301
|
+
let transcriptRef = path10.join(dir, "transcript.txt");
|
|
8513
8302
|
const transcriptOut = openTranscript(transcriptRef);
|
|
8514
8303
|
const outputCbs = [];
|
|
8515
8304
|
const telemetryCbs = [];
|
|
@@ -8611,14 +8400,14 @@ ${note}` : note };
|
|
|
8611
8400
|
}
|
|
8612
8401
|
if (cfg.cleanupWorkdir && !job.workdirKey) {
|
|
8613
8402
|
try {
|
|
8614
|
-
const keepDir =
|
|
8615
|
-
|
|
8616
|
-
const kept =
|
|
8403
|
+
const keepDir = path10.join(resolveWorkRoot(cfg.workRoot), "oasis-transcripts");
|
|
8404
|
+
fs8.mkdirSync(keepDir, { recursive: true });
|
|
8405
|
+
const kept = path10.join(keepDir, `${id}.txt`);
|
|
8617
8406
|
const src = transcriptRef;
|
|
8618
8407
|
transcriptOut.end(() => {
|
|
8619
8408
|
try {
|
|
8620
|
-
|
|
8621
|
-
|
|
8409
|
+
fs8.renameSync(src, kept);
|
|
8410
|
+
fs8.rmSync(dir, { recursive: true, force: true });
|
|
8622
8411
|
} catch {
|
|
8623
8412
|
}
|
|
8624
8413
|
});
|
|
@@ -8968,14 +8757,14 @@ ${task}` : task;
|
|
|
8968
8757
|
return run;
|
|
8969
8758
|
}
|
|
8970
8759
|
}
|
|
8971
|
-
var
|
|
8760
|
+
var import_node_child_process7, import_node_crypto10, fs8, path10, readline3, PROMPT_TURN_MESSAGE_MAX, PROMPT_TURN_STDERR_MAX_LINES, PROMPT_FAILURE_STDERR_SETTLE_MS, ACPClient, LEGACY_APPROVE_OPTION_ID;
|
|
8972
8761
|
var init_acp = __esm({
|
|
8973
8762
|
"../adapters/src/_core/acp.ts"() {
|
|
8974
8763
|
"use strict";
|
|
8975
|
-
|
|
8764
|
+
import_node_child_process7 = require("node:child_process");
|
|
8976
8765
|
import_node_crypto10 = require("node:crypto");
|
|
8977
|
-
|
|
8978
|
-
|
|
8766
|
+
fs8 = __toESM(require("node:fs"), 1);
|
|
8767
|
+
path10 = __toESM(require("node:path"), 1);
|
|
8979
8768
|
readline3 = __toESM(require("node:readline"), 1);
|
|
8980
8769
|
init_sync_skills();
|
|
8981
8770
|
init_session_paths();
|
|
@@ -9577,10 +9366,10 @@ function cursorAcpSessionStorePath(sessionId, env = process.env) {
|
|
|
9577
9366
|
if (!sessionId) return void 0;
|
|
9578
9367
|
const home2 = env["CURSOR_HOME"] || env["HOME"] || os6.homedir();
|
|
9579
9368
|
if (!home2) return void 0;
|
|
9580
|
-
const base = env["CURSOR_HOME"] ? home2 :
|
|
9581
|
-
const file =
|
|
9369
|
+
const base = env["CURSOR_HOME"] ? home2 : path11.join(home2, ".cursor");
|
|
9370
|
+
const file = path11.join(base, "acp-sessions", sessionId, "store.db");
|
|
9582
9371
|
try {
|
|
9583
|
-
return
|
|
9372
|
+
return fs9.existsSync(file) ? file : void 0;
|
|
9584
9373
|
} catch {
|
|
9585
9374
|
return void 0;
|
|
9586
9375
|
}
|
|
@@ -9715,13 +9504,13 @@ async function readCursorRoutedModel(sessionId, window3) {
|
|
|
9715
9504
|
}
|
|
9716
9505
|
}
|
|
9717
9506
|
}
|
|
9718
|
-
var
|
|
9507
|
+
var fs9, os6, path11, MAX_TABLES, MAX_ROWS_PER_TABLE, TURN_CLOCK_TOLERANCE_MS, TIME_KEY_TAILS;
|
|
9719
9508
|
var init_local_store = __esm({
|
|
9720
9509
|
"../adapters/src/cursor/local-store.ts"() {
|
|
9721
9510
|
"use strict";
|
|
9722
|
-
|
|
9511
|
+
fs9 = __toESM(require("node:fs"), 1);
|
|
9723
9512
|
os6 = __toESM(require("node:os"), 1);
|
|
9724
|
-
|
|
9513
|
+
path11 = __toESM(require("node:path"), 1);
|
|
9725
9514
|
MAX_TABLES = 24;
|
|
9726
9515
|
MAX_ROWS_PER_TABLE = 200;
|
|
9727
9516
|
TURN_CLOCK_TOLERANCE_MS = 1e3;
|
|
@@ -9996,12 +9785,12 @@ function normalizePi(line2) {
|
|
|
9996
9785
|
function piReportedModel(state, requested) {
|
|
9997
9786
|
return pickReportedModel({ runtime: [state.model, state.startupModel], requested });
|
|
9998
9787
|
}
|
|
9999
|
-
var
|
|
9788
|
+
var fs10, path12, PI_SESSION_FILE, PI_BLOCKED_FLAGS, PiAdapter;
|
|
10000
9789
|
var init_pi = __esm({
|
|
10001
9790
|
"../adapters/src/pi/index.ts"() {
|
|
10002
9791
|
"use strict";
|
|
10003
|
-
|
|
10004
|
-
|
|
9792
|
+
fs10 = __toESM(require("node:fs"), 1);
|
|
9793
|
+
path12 = __toESM(require("node:path"), 1);
|
|
10005
9794
|
init_protocol_session();
|
|
10006
9795
|
init_usage();
|
|
10007
9796
|
init_model_report();
|
|
@@ -10028,9 +9817,9 @@ var init_pi = __esm({
|
|
|
10028
9817
|
buildArgs(job2, dir) {
|
|
10029
9818
|
const model = job2.model ?? opts.model;
|
|
10030
9819
|
if (!job2.workdirKey) return ["--mode", "rpc", "--no-session", ...model ? ["--model", model] : []];
|
|
10031
|
-
const sessionFile =
|
|
9820
|
+
const sessionFile = path12.join(dir, PI_SESSION_FILE);
|
|
10032
9821
|
try {
|
|
10033
|
-
if (!
|
|
9822
|
+
if (!fs10.existsSync(sessionFile)) fs10.writeFileSync(sessionFile, "");
|
|
10034
9823
|
} catch {
|
|
10035
9824
|
return ["--mode", "rpc", "--no-session"];
|
|
10036
9825
|
}
|
|
@@ -10137,7 +9926,7 @@ function pdeathsigAvailable(probe = defaultProbe) {
|
|
|
10137
9926
|
function defaultProbe() {
|
|
10138
9927
|
if (os7.platform() !== "linux") return false;
|
|
10139
9928
|
try {
|
|
10140
|
-
const help = (0,
|
|
9929
|
+
const help = (0, import_node_child_process8.execFileSync)("setpriv", ["--help"], { stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 }).toString();
|
|
10141
9930
|
return help.includes("--pdeathsig");
|
|
10142
9931
|
} catch {
|
|
10143
9932
|
return false;
|
|
@@ -10149,11 +9938,11 @@ function pdeathsigWrap(bin, args) {
|
|
|
10149
9938
|
function shouldBindRuntimePdeathsig() {
|
|
10150
9939
|
return process.env["OASIS_BIND_RUNTIME_PDEATHSIG"] === "1" && pdeathsigAvailable();
|
|
10151
9940
|
}
|
|
10152
|
-
var
|
|
9941
|
+
var import_node_child_process8, os7, cachedAvailable;
|
|
10153
9942
|
var init_pdeathsig = __esm({
|
|
10154
9943
|
"../adapters/src/_core/pdeathsig.ts"() {
|
|
10155
9944
|
"use strict";
|
|
10156
|
-
|
|
9945
|
+
import_node_child_process8 = require("node:child_process");
|
|
10157
9946
|
os7 = __toESM(require("node:os"), 1);
|
|
10158
9947
|
}
|
|
10159
9948
|
});
|
|
@@ -10201,7 +9990,7 @@ function buildEnv(job, cfg) {
|
|
|
10201
9990
|
...scrubLeakyEnv(process.env),
|
|
10202
9991
|
...cfg.env,
|
|
10203
9992
|
...job.env,
|
|
10204
|
-
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) =>
|
|
9993
|
+
...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path13.dirname(p2)).join(path13.delimiter)}${path13.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
|
|
10205
9994
|
OASIS_SERVER: job.server.url,
|
|
10206
9995
|
OASIS_TOKEN: job.actorToken,
|
|
10207
9996
|
// root 下放行 bypassPermissions(仅 claude 家族 runtime 声明;见 _core/root-bypass.ts)。
|
|
@@ -10226,14 +10015,14 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, workdirKey, r
|
|
|
10226
10015
|
}
|
|
10227
10016
|
if (cfg.cleanupWorkdir && !workdirKey) {
|
|
10228
10017
|
try {
|
|
10229
|
-
const keepDir =
|
|
10230
|
-
|
|
10231
|
-
const kept =
|
|
10018
|
+
const keepDir = path13.join(resolveWorkRoot(cfg.workRoot), "oasis-transcripts");
|
|
10019
|
+
fs11.mkdirSync(keepDir, { recursive: true });
|
|
10020
|
+
const kept = path13.join(keepDir, `${id}.txt`);
|
|
10232
10021
|
const src = transcriptRefPtr.value;
|
|
10233
10022
|
transcriptOut.end(() => {
|
|
10234
10023
|
try {
|
|
10235
|
-
|
|
10236
|
-
|
|
10024
|
+
fs11.renameSync(src, kept);
|
|
10025
|
+
fs11.rmSync(dir, { recursive: true, force: true });
|
|
10237
10026
|
} catch {
|
|
10238
10027
|
}
|
|
10239
10028
|
});
|
|
@@ -10264,17 +10053,17 @@ async function runStreamJson(job, cfg) {
|
|
|
10264
10053
|
...cfg.env !== void 0 ? { extraEnvEarly: cfg.env } : {}
|
|
10265
10054
|
});
|
|
10266
10055
|
const direct = shouldBindRuntimePdeathsig() ? pdeathsigWrap(cfg.bin, args) : { bin: cfg.bin, args };
|
|
10267
|
-
const child = containerized ? (0,
|
|
10056
|
+
const child = containerized ? (0, import_node_child_process9.spawn)(containerized.bin, containerized.args, {
|
|
10268
10057
|
cwd: dir,
|
|
10269
10058
|
env: scrubLeakyEnv(process.env),
|
|
10270
10059
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10271
|
-
}) : (0,
|
|
10060
|
+
}) : (0, import_node_child_process9.spawn)(direct.bin, direct.args, {
|
|
10272
10061
|
cwd: dir,
|
|
10273
10062
|
env: buildEnv(job, cfg),
|
|
10274
10063
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10275
10064
|
});
|
|
10276
10065
|
if (child.pid !== void 0 && job.workdirKey) lockWorkdir(dir, child.pid, "session", job.workdirKey);
|
|
10277
|
-
const transcriptRefPtr = { value:
|
|
10066
|
+
const transcriptRefPtr = { value: path13.join(dir, "transcript.txt") };
|
|
10278
10067
|
const transcriptOut = openTranscript(transcriptRefPtr.value);
|
|
10279
10068
|
const outputCbs = [];
|
|
10280
10069
|
const telemetryCbs = [];
|
|
@@ -10374,17 +10163,17 @@ async function runOneShotText(job, cfg) {
|
|
|
10374
10163
|
...cfg.env !== void 0 ? { extraEnvEarly: cfg.env } : {}
|
|
10375
10164
|
});
|
|
10376
10165
|
const direct = shouldBindRuntimePdeathsig() ? pdeathsigWrap(cfg.bin, args) : { bin: cfg.bin, args };
|
|
10377
|
-
const child = containerized ? (0,
|
|
10166
|
+
const child = containerized ? (0, import_node_child_process9.spawn)(containerized.bin, containerized.args, {
|
|
10378
10167
|
cwd: dir,
|
|
10379
10168
|
env: scrubLeakyEnv(process.env),
|
|
10380
10169
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10381
|
-
}) : (0,
|
|
10170
|
+
}) : (0, import_node_child_process9.spawn)(direct.bin, direct.args, {
|
|
10382
10171
|
cwd: dir,
|
|
10383
10172
|
env: buildEnv(job, cfg),
|
|
10384
10173
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10385
10174
|
});
|
|
10386
10175
|
if (child.pid !== void 0 && job.workdirKey) lockWorkdir(dir, child.pid, "session", job.workdirKey);
|
|
10387
|
-
const transcriptRefPtr = { value:
|
|
10176
|
+
const transcriptRefPtr = { value: path13.join(dir, "transcript.txt") };
|
|
10388
10177
|
const transcriptOut = openTranscript(transcriptRefPtr.value);
|
|
10389
10178
|
const outputCbs = [];
|
|
10390
10179
|
const exitCbs = [];
|
|
@@ -10457,14 +10246,14 @@ async function runOneShotText(job, cfg) {
|
|
|
10457
10246
|
}
|
|
10458
10247
|
});
|
|
10459
10248
|
}
|
|
10460
|
-
var
|
|
10249
|
+
var import_node_child_process9, import_node_crypto11, fs11, path13, readline4;
|
|
10461
10250
|
var init_subprocess = __esm({
|
|
10462
10251
|
"../adapters/src/_core/subprocess.ts"() {
|
|
10463
10252
|
"use strict";
|
|
10464
|
-
|
|
10253
|
+
import_node_child_process9 = require("node:child_process");
|
|
10465
10254
|
import_node_crypto11 = require("node:crypto");
|
|
10466
|
-
|
|
10467
|
-
|
|
10255
|
+
fs11 = __toESM(require("node:fs"), 1);
|
|
10256
|
+
path13 = __toESM(require("node:path"), 1);
|
|
10468
10257
|
readline4 = __toESM(require("node:readline"), 1);
|
|
10469
10258
|
init_claude_code();
|
|
10470
10259
|
init_container_runtime();
|
|
@@ -11338,6 +11127,398 @@ var init_src2 = __esm({
|
|
|
11338
11127
|
}
|
|
11339
11128
|
});
|
|
11340
11129
|
|
|
11130
|
+
// ../server/src/design/board-key.ts
|
|
11131
|
+
async function boardLinkOf(blobs, rev, cache) {
|
|
11132
|
+
if (rev.contentKind !== "manifest" || rev.contentRef.length === 0) return null;
|
|
11133
|
+
const hit = cache?.get(rev.id);
|
|
11134
|
+
if (hit !== void 0) return hit;
|
|
11135
|
+
const manifest = parseManifest(await blobs.get(rev.contentRef));
|
|
11136
|
+
const entry = manifest.entries.find((e) => e.path === BOARD_LINK_FILE);
|
|
11137
|
+
const text7 = entry ? new TextDecoder().decode(await blobs.get(entry.hash)) : null;
|
|
11138
|
+
cache?.set(rev.id, text7);
|
|
11139
|
+
return text7;
|
|
11140
|
+
}
|
|
11141
|
+
async function latestBoardLink(model, blobs, a, cache) {
|
|
11142
|
+
const head = a.currentRev ? model.revisions.get(a.currentRev) : void 0;
|
|
11143
|
+
const rest = [...model.revisions.values()].filter((r) => r.artifactId === a.id && r.id !== head?.id && r.contentKind === "manifest").sort((x2, y) => y.createdAt.localeCompare(x2.createdAt));
|
|
11144
|
+
for (const rev of head ? [head, ...rest] : rest) {
|
|
11145
|
+
const text7 = await boardLinkOf(blobs, rev, cache);
|
|
11146
|
+
if (text7 !== null) return text7;
|
|
11147
|
+
}
|
|
11148
|
+
return null;
|
|
11149
|
+
}
|
|
11150
|
+
async function resolveDesignBoard(args, deps = {}) {
|
|
11151
|
+
if (args.companyId.trim().length === 0) {
|
|
11152
|
+
throw new Error(`\u62FF\u4E0D\u5230 ${args.artifact.id} \u6240\u5728\u7684\u516C\u53F8\uFF0C\u4E0D\u80FD\u786E\u5B9A\u753B\u677F\u2014\u2014\u4E0D\u56DE\u843D\u5230\u4E0D\u5E26\u516C\u53F8\u7684\u65E7\u753B\u677F\u540D`);
|
|
11153
|
+
}
|
|
11154
|
+
const boardLink = args.blobs ? await latestBoardLink(args.model, args.blobs, args.artifact, deps.cache) : null;
|
|
11155
|
+
const fromLink = boardLink !== null ? parseBoardLinkBoardKey(boardLink) : null;
|
|
11156
|
+
if (fromLink !== null) return { boardKey: fromLink, source: "board-link" };
|
|
11157
|
+
return { boardKey: (deps.deriveKey ?? deriveBoardKey)(args.companyId, args.artifact.id), source: "derived" };
|
|
11158
|
+
}
|
|
11159
|
+
var init_board_key = __esm({
|
|
11160
|
+
"../server/src/design/board-key.ts"() {
|
|
11161
|
+
"use strict";
|
|
11162
|
+
init_src();
|
|
11163
|
+
init_src2();
|
|
11164
|
+
}
|
|
11165
|
+
});
|
|
11166
|
+
|
|
11167
|
+
// ../server/src/domains/chat-sessions/session-runtime-target.ts
|
|
11168
|
+
function sessionRuntimeOverride(session) {
|
|
11169
|
+
const nodeId = session?.overrideNodeId?.trim();
|
|
11170
|
+
const runtimeKind = session?.overrideRuntimeKind?.trim();
|
|
11171
|
+
if (!nodeId || !runtimeKind) return null;
|
|
11172
|
+
return { nodeId, runtimeKind };
|
|
11173
|
+
}
|
|
11174
|
+
function chatSessionInitialRuntime(input) {
|
|
11175
|
+
const trimmed = (v2) => typeof v2 === "string" && v2.trim() ? v2.trim() : null;
|
|
11176
|
+
const binding = input.binding?.nodeId && input.binding?.runtimeKind ? { nodeId: input.binding.nodeId, runtimeKind: input.binding.runtimeKind } : null;
|
|
11177
|
+
const requestedOverride = input.requested?.override;
|
|
11178
|
+
const picked = requestedOverride?.nodeId && requestedOverride?.runtimeKind ? { nodeId: requestedOverride.nodeId, runtimeKind: requestedOverride.runtimeKind } : null;
|
|
11179
|
+
const target = picked ?? binding;
|
|
11180
|
+
const followsAgentTarget = !picked || !!binding && picked.nodeId === binding.nodeId && picked.runtimeKind === binding.runtimeKind;
|
|
11181
|
+
const requestedModel = input.requested?.model;
|
|
11182
|
+
const model = requestedModel !== void 0 ? trimmed(requestedModel) : followsAgentTarget ? trimmed(input.agentModel) : null;
|
|
11183
|
+
return {
|
|
11184
|
+
overrideNodeId: target?.nodeId ?? null,
|
|
11185
|
+
overrideRuntimeKind: target?.runtimeKind ?? null,
|
|
11186
|
+
model
|
|
11187
|
+
};
|
|
11188
|
+
}
|
|
11189
|
+
function sessionRuntimeOverrideChangesTarget(session, binding) {
|
|
11190
|
+
const override = sessionRuntimeOverride(session);
|
|
11191
|
+
if (!override) return false;
|
|
11192
|
+
if (!binding) return true;
|
|
11193
|
+
return override.nodeId !== binding.nodeId || override.runtimeKind !== binding.runtimeKind;
|
|
11194
|
+
}
|
|
11195
|
+
async function resolveSessionRuntimeTarget(input) {
|
|
11196
|
+
const { probe } = input;
|
|
11197
|
+
const override = sessionRuntimeOverride(input.session);
|
|
11198
|
+
if (!override) {
|
|
11199
|
+
return probe.binding ? { binding: probe.binding, source: "actor_binding" } : null;
|
|
11200
|
+
}
|
|
11201
|
+
const kinds = await probe.availableRuntimeKinds(override.nodeId);
|
|
11202
|
+
const nodeName = (await probe.nodeDisplayName?.(override.nodeId))?.trim() || override.nodeId;
|
|
11203
|
+
if (kinds === null) {
|
|
11204
|
+
throw new SessionRuntimeOverrideError(
|
|
11205
|
+
"CHAT_SESSION_NODE_UNAVAILABLE",
|
|
11206
|
+
`\u8FD9\u6761\u4F1A\u8BDD\u9009\u5B9A\u7684\u8282\u70B9\u300C${nodeName}\u300D\u5F53\u524D\u4E0D\u53EF\u7528\uFF08\u53EF\u80FD\u5DF2\u79BB\u7EBF\u3001\u5DF2\u5220\u9664\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8\uFF09\u3002\u8BF7\u786E\u8BA4\u90A3\u53F0\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u540E\u518D\u53D1\uFF1B\u6216${CLEAR_SESSION_RUNTIME_HINT}`
|
|
11207
|
+
);
|
|
11208
|
+
}
|
|
11209
|
+
if (!kinds.includes(override.runtimeKind)) {
|
|
11210
|
+
throw new SessionRuntimeOverrideError(
|
|
11211
|
+
"CHAT_SESSION_RUNTIME_UNAVAILABLE",
|
|
11212
|
+
`\u8282\u70B9\u300C${nodeName}\u300D\u4E0A\u6CA1\u6709\u53EF\u7528\u7684\u8FD0\u884C\u65F6 ${override.runtimeKind}\uFF08\u53EF\u80FD\u5DF2\u5378\u8F7D\u3001\u8FD8\u6CA1\u88C5\u597D\uFF0C\u6216\u672A\u4E0A\u62A5\uFF09\u3002\u8BF7\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u88C5\u597D\u540E\u518D\u53D1\uFF1B\u6216${CLEAR_SESSION_RUNTIME_HINT}`
|
|
11213
|
+
);
|
|
11214
|
+
}
|
|
11215
|
+
if (!probe.binding) {
|
|
11216
|
+
throw new SessionRuntimeOverrideError(
|
|
11217
|
+
"ACTOR_BINDING_MISSING",
|
|
11218
|
+
`\u8FD9\u4F4D Agent \u8FD8\u6CA1\u6709\u7ED1\u5B9A\u8FD0\u884C\u65F6\uFF0C\u9009\u5B9A\u8282\u70B9\u4E5F\u6D3E\u4E0D\u51FA\u53BB\u3002\u8BF7\u5148\u7ED9\u4ED6\u7ED1\u5B9A\u4E00\u4E2A\u53EF\u7528\u7684\u8FD0\u884C\u65F6\uFF1B\u6216${CLEAR_SESSION_RUNTIME_HINT}`
|
|
11219
|
+
);
|
|
11220
|
+
}
|
|
11221
|
+
return {
|
|
11222
|
+
binding: { actorId: probe.binding.actorId, nodeId: override.nodeId, runtimeKind: override.runtimeKind, status: probe.binding.status },
|
|
11223
|
+
source: "session_override"
|
|
11224
|
+
};
|
|
11225
|
+
}
|
|
11226
|
+
function canAnnounceRuntimeSwitch(prior) {
|
|
11227
|
+
const nodeId = prior?.runtimeId?.trim();
|
|
11228
|
+
const kind = prior?.runtimeKind?.trim();
|
|
11229
|
+
return Boolean(nodeId && kind && nodeId !== "unknown");
|
|
11230
|
+
}
|
|
11231
|
+
function runtimeSwitchedNotice(target) {
|
|
11232
|
+
const name = target.nodeName?.trim();
|
|
11233
|
+
const where = name ? `${name} \xB7 ${target.runtimeKind}` : target.runtimeKind;
|
|
11234
|
+
return `\u8FD0\u884C\u65F6\u5DF2\u5207\u5230 ${where}\uFF0C\u672C\u8F6E\u8D77\u5728\u65B0\u7684\u8FD0\u884C\u65F6\u4F1A\u8BDD\u4E2D\u7EE7\u7EED\uFF0C\u5DE5\u4F5C\u533A\u4E0E\u4E0A\u4E0B\u6587\u4E0D\u6CBF\u7528\u3002`;
|
|
11235
|
+
}
|
|
11236
|
+
var SessionRuntimeOverrideError, CLEAR_SESSION_RUNTIME_HINT;
|
|
11237
|
+
var init_session_runtime_target = __esm({
|
|
11238
|
+
"../server/src/domains/chat-sessions/session-runtime-target.ts"() {
|
|
11239
|
+
"use strict";
|
|
11240
|
+
SessionRuntimeOverrideError = class extends Error {
|
|
11241
|
+
constructor(code2, message, status = 409) {
|
|
11242
|
+
super(message);
|
|
11243
|
+
this.code = code2;
|
|
11244
|
+
this.status = status;
|
|
11245
|
+
this.name = "SessionRuntimeOverrideError";
|
|
11246
|
+
}
|
|
11247
|
+
};
|
|
11248
|
+
CLEAR_SESSION_RUNTIME_HINT = "\u5728\u8F93\u5165\u6846\u5E95\u90E8\u7684\u8FD0\u884C\u65F6\u9009\u62E9\u91CC\u6362\u4E00\u53F0\u53EF\u7528\u7684\u670D\u52A1\u5668\u6216\u8FD0\u884C\u65F6\u5373\u53EF\u7EE7\u7EED\uFF08\u5458\u5DE5\u81EA\u5DF1\u7684\u90A3\u4E00\u5957\u6807\u7740\u300C\u5F53\u524D\u5458\u5DE5\u6240\u5728\u670D\u52A1\u5668\u300D\u300C\u5F53\u524D\u5458\u5DE5\u8FD0\u884C\u65F6\u300D\uFF09\u3002";
|
|
11249
|
+
}
|
|
11250
|
+
});
|
|
11251
|
+
|
|
11252
|
+
// ../server/src/artifact-content.ts
|
|
11253
|
+
async function currentOutput(kernel, artifactId) {
|
|
11254
|
+
await kernel.refreshModel();
|
|
11255
|
+
const artifact = kernel.model.artifacts.get(artifactId);
|
|
11256
|
+
if (!artifact) throw new ApiError(404, "NOT_FOUND", "\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
11257
|
+
const snap = await kernel.getStore().transaction((tx) => tx.loadWorkorder(artifact.workspace));
|
|
11258
|
+
const node2 = snap?.nodes.find((n) => n.id === artifactId);
|
|
11259
|
+
const latest = snap?.works.find((w2) => w2.id === node2?.latestWorkId);
|
|
11260
|
+
const workId = latest && (latest.status === "failed" || latest.status === "dead") && node2?.latestProposedWorkId ? node2.latestProposedWorkId : node2?.latestWorkId;
|
|
11261
|
+
const output = snap?.artifacts.filter((a) => a.workId === workId).sort((a, b2) => a.ordinal - b2.ordinal)[0];
|
|
11262
|
+
if (!node2 || !output) throw new ApiError(404, "NOT_FOUND", "\u8FD9\u4E2A\u8282\u70B9\u5C1A\u672A\u4EA4\u4ED8\u6587\u4EF6");
|
|
11263
|
+
return { node: node2, output };
|
|
11264
|
+
}
|
|
11265
|
+
function looksLikeFileName(name) {
|
|
11266
|
+
return /^\.[a-z]{1,8}[0-9]?$/.test(fileExtensionOf(name));
|
|
11267
|
+
}
|
|
11268
|
+
function decodeText(bytes2) {
|
|
11269
|
+
if (bytes2.length > currentFileLimits().textEditBytes || bytes2.includes(0)) return null;
|
|
11270
|
+
try {
|
|
11271
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
|
|
11272
|
+
} catch {
|
|
11273
|
+
return null;
|
|
11274
|
+
}
|
|
11275
|
+
}
|
|
11276
|
+
async function readEditable(kernel, blobs, artifactId, path47) {
|
|
11277
|
+
const { node: node2, output } = await currentOutput(kernel, artifactId);
|
|
11278
|
+
let text7 = null;
|
|
11279
|
+
if (output.contentKind === "manifest" && path47 !== null) {
|
|
11280
|
+
const manifest = parseManifest(await blobs.get(output.contentRef));
|
|
11281
|
+
const entry = manifest.entries.find((e) => e.path === path47);
|
|
11282
|
+
if (!entry) throw new ApiError(404, "NOT_FOUND", "\u5305\u5185\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
11283
|
+
if (isEditableFileName(entry.path)) text7 = decodeText(await blobs.get(entry.hash));
|
|
11284
|
+
} else if (output.contentKind === "inline") {
|
|
11285
|
+
const name = node2.title || output.name;
|
|
11286
|
+
if (!looksLikeFileName(name) || isEditableFileName(name)) text7 = decodeText(await blobs.get(output.contentRef));
|
|
11287
|
+
}
|
|
11288
|
+
const view = {
|
|
11289
|
+
artifactId,
|
|
11290
|
+
revisionId: output.workId,
|
|
11291
|
+
contentRef: output.contentRef,
|
|
11292
|
+
path: path47,
|
|
11293
|
+
editable: text7 !== null,
|
|
11294
|
+
text: text7
|
|
11295
|
+
};
|
|
11296
|
+
return { view, node: node2, output };
|
|
11297
|
+
}
|
|
11298
|
+
async function readArtifactEditableContent(kernel, blobs, artifactId, path47) {
|
|
11299
|
+
return (await readEditable(kernel, blobs, artifactId, path47)).view;
|
|
11300
|
+
}
|
|
11301
|
+
async function saveArtifactContent(kernel, blobs, actor, input) {
|
|
11302
|
+
if (!input || typeof input.artifactId !== "string" || typeof input.revisionId !== "string" || typeof input.contentRef !== "string" || typeof input.text !== "string" || input.path != null && typeof input.path !== "string") {
|
|
11303
|
+
throw new ApiError(400, "BAD_REQUEST", "\u4FDD\u5B58\u53C2\u6570\u4E0D\u5B8C\u6574");
|
|
11304
|
+
}
|
|
11305
|
+
const bytes2 = new TextEncoder().encode(input.text);
|
|
11306
|
+
if (bytes2.length > currentFileLimits().textEditBytes || bytes2.includes(0)) {
|
|
11307
|
+
throw new ApiError(400, "BAD_REQUEST", `\u4EC5\u652F\u6301\u4E0D\u8D85\u8FC7 ${currentFileLimits().textEditBytes / 1024 / 1024} MiB \u7684 UTF-8 \u6587\u672C`);
|
|
11308
|
+
}
|
|
11309
|
+
const path47 = input.path ?? null;
|
|
11310
|
+
const { view, node: node2, output } = await readEditable(kernel, blobs, input.artifactId, path47);
|
|
11311
|
+
if (view.revisionId !== input.revisionId || view.contentRef !== input.contentRef) {
|
|
11312
|
+
throw new ApiError(409, "CONTENT_CONFLICT", "\u5185\u5BB9\u5DF2\u88AB\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6587\u4EF6\u540E\u518D\u4FDD\u5B58");
|
|
11313
|
+
}
|
|
11314
|
+
if (!view.editable) throw new ApiError(400, "NOT_EDITABLE", "\u6B64\u6587\u4EF6\u4E0D\u652F\u6301\u5728\u7EBF\u7F16\u8F91");
|
|
11315
|
+
let contentRef = await blobs.put(bytes2);
|
|
11316
|
+
if (output.contentKind === "manifest") {
|
|
11317
|
+
const manifest = parseManifest(await blobs.get(output.contentRef));
|
|
11318
|
+
contentRef = await blobs.put(serializeManifest(manifest.entries.map((e) => e.path === path47 ? { ...e, hash: contentRef, size: bytes2.length } : e)));
|
|
11319
|
+
}
|
|
11320
|
+
try {
|
|
11321
|
+
await kernel.editArtifactContent({
|
|
11322
|
+
artifactId: input.artifactId,
|
|
11323
|
+
actor,
|
|
11324
|
+
workId: output.workId,
|
|
11325
|
+
outputId: output.id,
|
|
11326
|
+
expectedLatestWorkId: node2.latestWorkId,
|
|
11327
|
+
previousRef: output.contentRef,
|
|
11328
|
+
contentRef,
|
|
11329
|
+
path: path47
|
|
11330
|
+
});
|
|
11331
|
+
} catch (error2) {
|
|
11332
|
+
if (error2.code === "content-conflict") {
|
|
11333
|
+
throw new ApiError(409, "CONTENT_CONFLICT", "\u5185\u5BB9\u5DF2\u88AB\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6587\u4EF6\u540E\u518D\u4FDD\u5B58");
|
|
11334
|
+
}
|
|
11335
|
+
throw error2;
|
|
11336
|
+
}
|
|
11337
|
+
return { ...view, contentRef, text: input.text };
|
|
11338
|
+
}
|
|
11339
|
+
async function readArtifactFile(kernel, blobs, artifactId, path47, expectedRef, revisionId = null) {
|
|
11340
|
+
await kernel.refreshModel();
|
|
11341
|
+
const artifact = kernel.model.artifacts.get(artifactId);
|
|
11342
|
+
const selectedRevision = revisionId ?? artifact?.currentRev;
|
|
11343
|
+
const output = selectedRevision ? kernel.model.revisions.get(selectedRevision) : void 0;
|
|
11344
|
+
if (!artifact || !output || output.artifactId !== artifactId) {
|
|
11345
|
+
throw new ApiError(404, "NOT_FOUND", revisionId !== null ? "\u8BE5\u4EA7\u7269\u7248\u672C\u4E0D\u5B58\u5728" : "\u6B64\u4EA7\u7269\u6CA1\u6709\u53EF\u4E0B\u8F7D\u7684\u539F\u6587\u4EF6");
|
|
11346
|
+
}
|
|
11347
|
+
if (expectedRef && output.contentRef !== expectedRef) throw new ApiError(409, "CONTENT_CONFLICT", "\u6587\u4EF6\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00");
|
|
11348
|
+
let hash3 = output.contentRef;
|
|
11349
|
+
let name = artifact.title || artifactId;
|
|
11350
|
+
if (output.contentKind === "manifest") {
|
|
11351
|
+
if (!path47) throw new ApiError(400, "PATH_REQUIRED", "\u8BF7\u9009\u62E9\u6587\u4EF6\u5939\u4E2D\u7684\u5177\u4F53\u6587\u4EF6");
|
|
11352
|
+
const entry = parseManifest(await blobs.get(output.contentRef)).entries.find((e) => e.path === path47);
|
|
11353
|
+
if (!entry) throw new ApiError(404, "NOT_FOUND", "\u5305\u5185\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
11354
|
+
hash3 = entry.hash;
|
|
11355
|
+
name = entry.path;
|
|
11356
|
+
if (entry.size !== void 0 && entry.size > currentFileReadMaxBytes()) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${currentFileReadMaxBytes() / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
11357
|
+
} else if (output.contentKind !== "inline-blob") {
|
|
11358
|
+
throw new ApiError(404, "NOT_FOUND", "\u6B64\u4EA7\u7269\u6CA1\u6709\u53EF\u4E0B\u8F7D\u7684\u539F\u6587\u4EF6");
|
|
11359
|
+
}
|
|
11360
|
+
const meta = await blobs.meta?.(hash3);
|
|
11361
|
+
if (meta && meta.size > currentFileReadMaxBytes()) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${currentFileReadMaxBytes() / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
11362
|
+
try {
|
|
11363
|
+
return { bytes: await blobs.get(hash3), name, contentType: meta?.contentType };
|
|
11364
|
+
} catch {
|
|
11365
|
+
throw new ApiError(404, "NOT_FOUND", "\u5F53\u524D\u516C\u53F8\u4E2D\u627E\u4E0D\u5230\u8BE5\u6587\u4EF6\u6B63\u6587");
|
|
11366
|
+
}
|
|
11367
|
+
}
|
|
11368
|
+
var init_artifact_content2 = __esm({
|
|
11369
|
+
"../server/src/artifact-content.ts"() {
|
|
11370
|
+
"use strict";
|
|
11371
|
+
init_file_limits2();
|
|
11372
|
+
init_src();
|
|
11373
|
+
init_router();
|
|
11374
|
+
}
|
|
11375
|
+
});
|
|
11376
|
+
|
|
11377
|
+
// ../server/src/file-http.ts
|
|
11378
|
+
async function serveFileRequest(req, res, url, engine) {
|
|
11379
|
+
try {
|
|
11380
|
+
if (req.method !== "GET" || url.pathname !== "/api/files/content") throw new ApiError(404, "NOT_FOUND", "\u6587\u4EF6\u63A5\u53E3\u4E0D\u5B58\u5728");
|
|
11381
|
+
const { bytes: bytes2, name, contentType } = await readArtifactFile(
|
|
11382
|
+
engine.kernel,
|
|
11383
|
+
engine.blobs,
|
|
11384
|
+
url.searchParams.get("artifact") ?? "",
|
|
11385
|
+
url.searchParams.get("path"),
|
|
11386
|
+
url.searchParams.get("ref"),
|
|
11387
|
+
url.searchParams.get("revisionId")
|
|
11388
|
+
);
|
|
11389
|
+
if (bytes2.length > currentFileReadMaxBytes()) throw new ApiError(413, "FILE_TOO_LARGE", `\u6587\u4EF6\u8D85\u8FC7 ${currentFileReadMaxBytes() / 1024 / 1024} MiB \u8BFB\u53D6\u9650\u5236`);
|
|
11390
|
+
res.writeHead(200, {
|
|
11391
|
+
"content-type": contentType ?? sniffContentType(bytes2) ?? "application/octet-stream",
|
|
11392
|
+
"content-length": String(bytes2.length),
|
|
11393
|
+
"cache-control": "private, no-store",
|
|
11394
|
+
"x-content-type-options": "nosniff",
|
|
11395
|
+
"content-disposition": `attachment; filename*=UTF-8''${encodeURIComponent(name.split(/[\\/]/).pop() || "file").replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)}`
|
|
11396
|
+
}).end(Buffer.from(bytes2));
|
|
11397
|
+
} catch (error2) {
|
|
11398
|
+
if (res.destroyed) return;
|
|
11399
|
+
const status = error2 instanceof ApiError ? error2.status : 500;
|
|
11400
|
+
if (!req.complete) {
|
|
11401
|
+
res.setHeader("connection", "close");
|
|
11402
|
+
req.resume();
|
|
11403
|
+
}
|
|
11404
|
+
res.writeHead(status, { "content-type": "application/json", "cache-control": "no-store" }).end(JSON.stringify({
|
|
11405
|
+
error: {
|
|
11406
|
+
code: error2 instanceof ApiError ? error2.code : "FILE_READ_FAILED",
|
|
11407
|
+
message: error2 instanceof ApiError ? error2.message : "\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"
|
|
11408
|
+
}
|
|
11409
|
+
}));
|
|
11410
|
+
}
|
|
11411
|
+
}
|
|
11412
|
+
var init_file_http = __esm({
|
|
11413
|
+
"../server/src/file-http.ts"() {
|
|
11414
|
+
"use strict";
|
|
11415
|
+
init_src();
|
|
11416
|
+
init_artifact_content2();
|
|
11417
|
+
init_router();
|
|
11418
|
+
init_file_limits2();
|
|
11419
|
+
}
|
|
11420
|
+
});
|
|
11421
|
+
|
|
11422
|
+
// ../server/src/build-info.ts
|
|
11423
|
+
function findRepoRoot() {
|
|
11424
|
+
let dir;
|
|
11425
|
+
try {
|
|
11426
|
+
dir = path15.dirname((0, import_node_url.fileURLToPath)(__esm_import_meta_url));
|
|
11427
|
+
} catch {
|
|
11428
|
+
return null;
|
|
11429
|
+
}
|
|
11430
|
+
for (let i = 0; i < 12; i++) {
|
|
11431
|
+
if (fs13.existsSync(path15.join(dir, ".git"))) return dir;
|
|
11432
|
+
const parent = path15.dirname(dir);
|
|
11433
|
+
if (parent === dir) break;
|
|
11434
|
+
dir = parent;
|
|
11435
|
+
}
|
|
11436
|
+
return null;
|
|
11437
|
+
}
|
|
11438
|
+
function git(root, args) {
|
|
11439
|
+
try {
|
|
11440
|
+
const out = (0, import_node_child_process10.execFileSync)("git", args, {
|
|
11441
|
+
cwd: root,
|
|
11442
|
+
encoding: "utf8",
|
|
11443
|
+
timeout: 3e3,
|
|
11444
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
11445
|
+
});
|
|
11446
|
+
const v2 = out.trim();
|
|
11447
|
+
return v2 || null;
|
|
11448
|
+
} catch {
|
|
11449
|
+
return null;
|
|
11450
|
+
}
|
|
11451
|
+
}
|
|
11452
|
+
function getBuildInfo() {
|
|
11453
|
+
if (cached) return cached;
|
|
11454
|
+
const envSha = process.env["OASIS_GIT_SHA"]?.trim();
|
|
11455
|
+
const envBranch = process.env["OASIS_GIT_BRANCH"]?.trim();
|
|
11456
|
+
let gitSha = envSha || null;
|
|
11457
|
+
let gitBranch = envBranch || null;
|
|
11458
|
+
if (!gitSha || !gitBranch) {
|
|
11459
|
+
const root = findRepoRoot();
|
|
11460
|
+
if (root) {
|
|
11461
|
+
if (!gitSha) gitSha = git(root, ["rev-parse", "HEAD"]);
|
|
11462
|
+
if (!gitBranch) {
|
|
11463
|
+
const b2 = git(root, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
11464
|
+
gitBranch = b2 === "HEAD" ? null : b2;
|
|
11465
|
+
}
|
|
11466
|
+
}
|
|
11467
|
+
}
|
|
11468
|
+
cached = { gitSha, gitBranch, startedAt: STARTED_AT };
|
|
11469
|
+
return cached;
|
|
11470
|
+
}
|
|
11471
|
+
function resetBuildInfoCacheForTest() {
|
|
11472
|
+
cached = void 0;
|
|
11473
|
+
}
|
|
11474
|
+
var import_node_child_process10, fs13, path15, import_node_url, STARTED_AT, cached;
|
|
11475
|
+
var init_build_info = __esm({
|
|
11476
|
+
"../server/src/build-info.ts"() {
|
|
11477
|
+
"use strict";
|
|
11478
|
+
import_node_child_process10 = require("node:child_process");
|
|
11479
|
+
fs13 = __toESM(require("node:fs"), 1);
|
|
11480
|
+
path15 = __toESM(require("node:path"), 1);
|
|
11481
|
+
import_node_url = require("node:url");
|
|
11482
|
+
STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
11483
|
+
}
|
|
11484
|
+
});
|
|
11485
|
+
|
|
11486
|
+
// ../server/src/command-policy.ts
|
|
11487
|
+
function classifyCommand(command2) {
|
|
11488
|
+
return COMMAND_POLICY[command2] ?? { risk: "direct" };
|
|
11489
|
+
}
|
|
11490
|
+
var shortId, COMMAND_POLICY;
|
|
11491
|
+
var init_command_policy = __esm({
|
|
11492
|
+
"../server/src/command-policy.ts"() {
|
|
11493
|
+
"use strict";
|
|
11494
|
+
shortId = (v2) => typeof v2 === "string" ? v2.replace(/^artifact:[^:]+:/, "") : String(v2 ?? "?");
|
|
11495
|
+
COMMAND_POLICY = {
|
|
11496
|
+
forceConclude: {
|
|
11497
|
+
risk: "authorize",
|
|
11498
|
+
idempotent: false,
|
|
11499
|
+
effect: (a) => `\u5F3A\u5236\u6536\u53E3\u8282\u70B9 ${shortId(a.artifactId)}\uFF08\u7ED5\u8FC7\u8BC4\u5BA1\u95F8\u76F4\u63A5\u76D6\u91CC\u7A0B\u7891\uFF09`
|
|
11500
|
+
},
|
|
11501
|
+
promote: {
|
|
11502
|
+
risk: "authorize",
|
|
11503
|
+
idempotent: true,
|
|
11504
|
+
effect: (a) => `\u628A\u8282\u70B9 ${shortId(a.artifactId)} \u8F6C\u4E3A\u6301\u4E45\uFF08temp \u2192 persistent\uFF09`
|
|
11505
|
+
},
|
|
11506
|
+
resolveEscalation: {
|
|
11507
|
+
risk: "authorize",
|
|
11508
|
+
idempotent: true,
|
|
11509
|
+
// 重复关同一条是幂等的(kernel.resolveEscalation 内部按 escalationId 去重)
|
|
11510
|
+
// 「关错=静默停摆」的唯一防线是人在卡上一眼看出「关的是哪一条」——escalationId 与 reason 摘要必须上卡。
|
|
11511
|
+
// a 里 escalationId/artifactId 由 server.ts 起草时冻进 commandArgs(已四级解析),保证是真值、非 `?`。
|
|
11512
|
+
effect: (a) => typeof a.gapId === "string" ? `\u91C7\u7528\u65B9\u6848\uFF1A${String(a.reason ?? "")}\uFF1B\u89E3\u51B3\u7F3A\u53E3 ${a.gapId}\uFF1B\u5173\u95ED\u5173\u8054\u4E0A\u62A5 ${String(a.escalationId)}\uFF1B\u7EE7\u7EED\u6267\u884C\uFF1A\u662F\uFF08\u4ECD\u987B\u6EE1\u8DB3\u5176\u4ED6\u963B\u585E\u6761\u4EF6\uFF09` : `\u5173\u95ED\u4E0A\u62A5 ${shortId(a.escalationId)}\uFF08\u8282\u70B9 ${shortId(a.artifactId)}${typeof a.reason === "string" ? `\uFF0C\u7406\u7531\uFF1A${a.reason}` : ""}\uFF09`
|
|
11513
|
+
},
|
|
11514
|
+
gc: {
|
|
11515
|
+
risk: "forbidden",
|
|
11516
|
+
forbiddenReason: "gc \u662F\u56DE\u6536\u5B64\u513F blob \u7684\u57FA\u7840\u8BBE\u65BD\u7EF4\u62A4\uFF0C\u7531 serve \u8FDB\u7A0B/\u4EBA\u7C7B operator \u6267\u884C\uFF0C\u4E0D\u5C5E\u4E8E\u7BA1\u7406\u8005\u80FD\u529B\u8303\u56F4\u3002"
|
|
11517
|
+
}
|
|
11518
|
+
};
|
|
11519
|
+
}
|
|
11520
|
+
});
|
|
11521
|
+
|
|
11341
11522
|
// ../server/src/domains/actors/model-pricing.ts
|
|
11342
11523
|
function lookupInMap(map, prefixKeys, candidates) {
|
|
11343
11524
|
for (const candidate of candidates) {
|
|
@@ -141016,14 +141197,19 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
|
|
|
141016
141197
|
})() : canvasMode ? [
|
|
141017
141198
|
// 内核只出「你产什么 + 内核权威锚点」——**设计工作流散文全在你的人设(identity/AGENTS.md「产出流程」)**,
|
|
141018
141199
|
// 那是单一真源、改它=改配置不发版(提案 design-conversational-driving 治本,2026-07-17)。这里不重复正文,
|
|
141019
|
-
//
|
|
141200
|
+
// 只钉住内核不能漂的几件事:真实 artifactId、缺前置的逃生口 gap,以及「下单后在会话里 status --wait 等结果」
|
|
141201
|
+
//(2026-09-24 加:它直接关系引擎的零产出判定——下单即退出会被判零产出→协议续唤→连败熔断;人设各公司
|
|
141202
|
+
// 各一份、未必同步更新,这条放内核才保证每个设计员工都拿得到)。
|
|
141020
141203
|
`\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\u3002`,
|
|
141021
141204
|
``,
|
|
141022
141205
|
`**\u5B8C\u6574\u5DE5\u4F5C\u6D41\uFF08\u600E\u4E48\u53D6\u8D27/\u8D77\u8F6E/\u8BFB\u4EA7\u7269/\u4EA4\u7A3F/\u522B\u624B\u6539\u677F\u6587\u4EF6\u2026\uFF09\u89C1\u4F60\u7684\u4EBA\u8BBE \`identity/AGENTS.md\` \u7684\u300C\u4EA7\u51FA\u6D41\u7A0B\uFF08design \u4EA7\u7269\uFF09\u300D**\u2014\u2014\u628A\u91CC\u9762 \`<artifactId>\` \u90FD\u6362\u6210\u672C\u4EA7\u7269 \`${artifactId}\`\u3002`,
|
|
141023
141206
|
``,
|
|
141024
|
-
`\u5185\u6838\u53EA\u5728\u6B64\u9489\
|
|
141207
|
+
`\u5185\u6838\u53EA\u5728\u6B64\u9489\u51E0\u6761\u4E0D\u53EF\u6F02\u7684\uFF1A`,
|
|
141025
141208
|
`- **\u4EA4\u7A3F\u8D70 \`oasis propose ${artifactId} --from-dir <\u76EE\u5F55> --reason "\u2026"\`**\uFF08proposed \u624D\u8FDB\u7248\u672C\u53F2\u3001\u4E0B\u6E38\u624D\u62FF\u5F97\u5230\uFF1B\u4E0D propose = head \u4ECD \u2205\uFF09\uFF1B`,
|
|
141026
|
-
`- \u7F3A**\u8FD8\u4E0D\u5B58\u5728\u7684\u4E0A\u6E38\u524D\u7F6E** \u2192 \`oasis gap ${artifactId} --desc "<\u7F3A\u4EC0\u4E48>"\` \u4EA4\u4E0A\u53BB\uFF1B\u5DF2\u505A\u5B8C\u7684\u90E8\u5206\u7167\u5E38 \`propose\`\uFF0C\u4F46\u8FD9\u4E00\u8F6E \`conclude\` \u4F1A\u88AB\u62D2\uFF0C\u63D0\u4EA4\u5B8C\u5373\u6536\u5DE5\u3002
|
|
141209
|
+
`- \u7F3A**\u8FD8\u4E0D\u5B58\u5728\u7684\u4E0A\u6E38\u524D\u7F6E** \u2192 \`oasis gap ${artifactId} --desc "<\u7F3A\u4EC0\u4E48>"\` \u4EA4\u4E0A\u53BB\uFF1B\u5DF2\u505A\u5B8C\u7684\u90E8\u5206\u7167\u5E38 \`propose\`\uFF0C\u4F46\u8FD9\u4E00\u8F6E \`conclude\` \u4F1A\u88AB\u62D2\uFF0C\u63D0\u4EA4\u5B8C\u5373\u6536\u5DE5\u3002`,
|
|
141210
|
+
`- **\u5728\u672C\u4F1A\u8BDD\u91CC\u7B49\u753B\u677F\u51FA\u7ED3\u679C**\uFF08\u540C\u5F00\u53D1\u7B49 CI\uFF09\uFF1A\u5F00\u5DE5\u5148 \`oasis design status ${artifactId}\`\uFF08\u6062\u590D\u4F18\u5148\uFF0C\u677F\u4E0A\u5DF2\u6709\u8D27/\u5DF2\u6709\u5728\u8DD1\u7684\u8F6E\u6B21\u5C31\u522B\u91CD\u4E0B\uFF09\uFF1B\u4E0B\u5355\u7528 \`oasis design chat ${artifactId} \u2026 --async\`\uFF0C\u7136\u540E**\u7ACB\u523B** \`oasis design status ${artifactId} --wait --pull\` \u963B\u585E\u7B49\u8FD9\u4E00\u8F6E\u8DD1\u5B8C\u5E76\u62C9\u8D27\uFF08\u6700\u957F\u7EA6 100 \u5206\u949F\uFF1B\u963B\u585E\u671F\u95F4\u4E0D\u8017 token\uFF09\u3002\u6210\u529F \u2192 \u6838\u5BF9 \u2192 propose\uFF1B\u5931\u8D25 \u2192 \u6309\u5B83\u7ED9\u7684\u539F\u56E0\u6362\u5F15\u64CE\uFF08\`--agent\`\uFF09\u6216\u8865\u6E05\u9700\u6C42\u540E\u91CD\u4E0B\uFF0C\u518D \`--wait\`\u3002`,
|
|
141211
|
+
` - **\u4E0D\u8981\u4E0B\u5355\u540E\u76F4\u63A5\u7ED3\u675F\u4F1A\u8BDD**\u2014\u2014\u6CA1\u4EA4\u4E1C\u897F\u5C31\u6536\u5DE5\u4F1A\u88AB\u5224\u96F6\u4EA7\u51FA\uFF1B**\u4E5F\u4E0D\u8981\u81EA\u5DF1\u9694\u51E0\u5206\u949F\u624B\u52A8 status \u8F6E\u8BE2**\u2014\u2014\u6BCF\u67E5\u4E00\u6B21\u90FD\u8981\u63A8\u7406\u4E00\u6B21\u3002\u547D\u4EE4\u82E5\u88AB\u6267\u884C\u5DE5\u5177\u7684\u5355\u6761\u8D85\u65F6\u6253\u65AD\u6216\u8D85\u65F6\u9000\u51FA\uFF0C\u539F\u6837\u518D\u8DD1\u4E00\u6B21 \`--wait\` \u63A5\u7740\u7B49\uFF08\u5B83\u7B49\u7684\u662F\u753B\u677F\uFF0C\u4E0D\u4F1A\u91CD\u590D\u4E0B\u5355\uFF09\u3002`,
|
|
141212
|
+
`- \u88AB\u753B\u677F\u5DE1\u68C0\u7684\u4FE1\u5524\u9192\u65F6\uFF1A\u5148\u770B\u5F53\u524D\u7248\u672C\u88C5\u7BB1\u5355 board.link \u91CC\u7684\u300C\u5FEB\u7167\u6765\u6E90 run\u300D\u662F\u4E0D\u662F\u5C31\u662F\u4FE1\u91CC\u90A3\u4E00\u8F6E\u2014\u2014\u662F\u5C31 \`oasis resolve <\u4FE1 id>\`\uFF0C\u522B\u91CD\u590D propose\u3002`
|
|
141027
141213
|
] : (() => {
|
|
141028
141214
|
const codeRepo = args.codeRepo ?? null;
|
|
141029
141215
|
const repos = typeDef?.contentType === "code" ? codeRepo?.repos : void 0;
|
|
@@ -213709,6 +213895,16 @@ async function startOasisServer(opts) {
|
|
|
213709
213895
|
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ data: data2 }));
|
|
213710
213896
|
return;
|
|
213711
213897
|
}
|
|
213898
|
+
if (viewName === "design-board") {
|
|
213899
|
+
const artifactId = url.searchParams.get("artifact");
|
|
213900
|
+
if (!artifactId) throw new Error("\u8BE5\u89C6\u56FE\u9700\u8981 artifact \u53C2\u6570");
|
|
213901
|
+
if (!currentCompanyId) throw new Error("\u62FF\u4E0D\u5230\u5F53\u524D\u516C\u53F8\uFF08\u4F1A\u8BDD token \u6CA1\u7B7E\u516C\u53F8\u3001\u8BF7\u6C42\u4E5F\u6CA1\u6307\u5B9A\u516C\u53F8\uFF09\uFF0C\u4E0D\u80FD\u786E\u5B9A\u753B\u677F\u2014\u2014\u4E0D\u56DE\u843D\u5230\u4E0D\u5E26\u516C\u53F8\u7684\u65E7\u753B\u677F\u540D");
|
|
213902
|
+
const artifact = engine.kernel.model.artifacts.get(artifactId);
|
|
213903
|
+
if (!artifact) throw new Error(`artifact \u4E0D\u5B58\u5728: ${artifactId}`);
|
|
213904
|
+
const board = await resolveDesignBoard({ companyId: currentCompanyId, model: engine.kernel.model, blobs: engine.blobs, artifact });
|
|
213905
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ data: { companyId: currentCompanyId, ...board } }));
|
|
213906
|
+
return;
|
|
213907
|
+
}
|
|
213712
213908
|
const customView = opts.views?.[viewName];
|
|
213713
213909
|
if (customView) {
|
|
213714
213910
|
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ data: await customView() }));
|
|
@@ -216141,6 +216337,7 @@ var init_server3 = __esm({
|
|
|
216141
216337
|
init_chat_session();
|
|
216142
216338
|
init_chat_system_message();
|
|
216143
216339
|
init_sealed_node_receipt();
|
|
216340
|
+
init_board_key();
|
|
216144
216341
|
init_session_runtime_target();
|
|
216145
216342
|
init_src();
|
|
216146
216343
|
init_src();
|
|
@@ -277486,11 +277683,19 @@ function messageError(m2, status) {
|
|
|
277486
277683
|
}
|
|
277487
277684
|
return { error: null, errorCode: null };
|
|
277488
277685
|
}
|
|
277686
|
+
function ownerIsWorking(model, a) {
|
|
277687
|
+
if (a.latestWorkState !== "running") return false;
|
|
277688
|
+
const latest = [...model.revisions.values()].filter((r) => r.artifactId === a.id && r.lane !== "reply").sort((x2, y) => y.createdAt.localeCompare(x2.createdAt))[0];
|
|
277689
|
+
return latest !== void 0 && latest.author === a.owner;
|
|
277690
|
+
}
|
|
277489
277691
|
var RUN_MARKER_PREFIX, boardWatchRunMarker, parseRunMarker, SINCE_MARKER_PREFIX, boardWatchSinceMarker, parseSinceMarker, TERMINAL_RUN_STATUS, MAX_REASON_CHARS, MAX_LISTED_FILES, BoardWatcher;
|
|
277490
277692
|
var init_board_watch = __esm({
|
|
277491
277693
|
"../server/src/design/board-watch.ts"() {
|
|
277492
277694
|
"use strict";
|
|
277695
|
+
init_src();
|
|
277493
277696
|
init_src7();
|
|
277697
|
+
init_src2();
|
|
277698
|
+
init_board_key();
|
|
277494
277699
|
RUN_MARKER_PREFIX = "[od-board-watch run:";
|
|
277495
277700
|
boardWatchRunMarker = (roundKey) => `${RUN_MARKER_PREFIX}${roundKey}]`;
|
|
277496
277701
|
parseRunMarker = (body2) => {
|
|
@@ -277523,6 +277728,20 @@ var init_board_watch = __esm({
|
|
|
277523
277728
|
seenConvAt = /* @__PURE__ */ new Map();
|
|
277524
277729
|
/** 公司 → 上次记下的失败原文(同样的错只记一次;成功一轮就清掉)。 */
|
|
277525
277730
|
companyLastError = /* @__PURE__ */ new Map();
|
|
277731
|
+
/** `<公司>\0<artifactId>\0<轮次键>` → 这一轮已被取走(head 来自它或更晚的一轮),不再重判。只在内存,不写假信。 */
|
|
277732
|
+
takenRounds = /* @__PURE__ */ new Set();
|
|
277733
|
+
/** `<公司>\0<boardKey>` → (runId → endedAt):判断 head 的快照来源 run 是不是「更晚的一轮」用。 */
|
|
277734
|
+
roundEndedAt = /* @__PURE__ */ new Map();
|
|
277735
|
+
/** `<公司>\0<revisionId>` → 该版 board.link 的快照来源 runId(null = 没有/读不到)。revision 内容不可变,缓存安全。 */
|
|
277736
|
+
revisionSourceRun = /* @__PURE__ */ new Map();
|
|
277737
|
+
/** 因 owner 在做而压着没写的 `<公司>\0<artifactId>`(只为日志只打一次)。 */
|
|
277738
|
+
deferredLogged = /* @__PURE__ */ new Set();
|
|
277739
|
+
/** 公司 → (revisionId → board.link 正文):解析画板用。revision id 跨公司可能同名,所以按公司分开。 */
|
|
277740
|
+
boardLinks = /* @__PURE__ */ new Map();
|
|
277741
|
+
/** `<公司>\0<artifactId>` → 上次解析画板失败的原文(同样的错只记一次)。 */
|
|
277742
|
+
boardResolveError = /* @__PURE__ */ new Map();
|
|
277743
|
+
/** 已经报过的串板(`<boardKey>\0<公司,…>`),同一组只报一次。 */
|
|
277744
|
+
sharedBoardLogged = /* @__PURE__ */ new Set();
|
|
277526
277745
|
async odGet(path47) {
|
|
277527
277746
|
const fetchImpl = this.deps.fetchImpl ?? fetch;
|
|
277528
277747
|
try {
|
|
@@ -277579,11 +277798,13 @@ var init_board_watch = __esm({
|
|
|
277579
277798
|
async tick(now = Date.now()) {
|
|
277580
277799
|
const { log: log3 } = this.deps;
|
|
277581
277800
|
const denied = [];
|
|
277801
|
+
const boardUsers = /* @__PURE__ */ new Map();
|
|
277582
277802
|
const { listCompanies, kernelFor } = this.deps;
|
|
277583
277803
|
if (listCompanies && kernelFor) {
|
|
277584
277804
|
for (const companyId of await listCompanies()) {
|
|
277585
277805
|
try {
|
|
277586
|
-
|
|
277806
|
+
const blobs = this.deps.blobsFor ? await this.deps.blobsFor(companyId) : void 0;
|
|
277807
|
+
await this.tickCompany(companyId, await kernelFor(companyId), now, denied, blobs, boardUsers);
|
|
277587
277808
|
this.companyLastError.delete(companyId);
|
|
277588
277809
|
} catch (err) {
|
|
277589
277810
|
const msg = String(err);
|
|
@@ -277593,8 +277814,9 @@ var init_board_watch = __esm({
|
|
|
277593
277814
|
}
|
|
277594
277815
|
}
|
|
277595
277816
|
} else {
|
|
277596
|
-
await this.tickCompany("", this.deps.kernel, now, denied);
|
|
277817
|
+
await this.tickCompany("", this.deps.kernel, now, denied, this.deps.blobs, boardUsers);
|
|
277597
277818
|
}
|
|
277819
|
+
this.logSharedBoards(boardUsers);
|
|
277598
277820
|
if (denied.length > 0) {
|
|
277599
277821
|
const codes = [...new Set(denied.map((d) => d.status))].join("/");
|
|
277600
277822
|
const eg = denied[0];
|
|
@@ -277604,8 +277826,8 @@ var init_board_watch = __esm({
|
|
|
277604
277826
|
}
|
|
277605
277827
|
}
|
|
277606
277828
|
/** 巡一家公司(company 为空串 = 单 kernel 模式);被拒的板记进 denied,由 tick 统一汇总成一行。 */
|
|
277607
|
-
async tickCompany(company, kernel, now, denied) {
|
|
277608
|
-
const {
|
|
277829
|
+
async tickCompany(company, kernel, now, denied, blobs, boardUsers) {
|
|
277830
|
+
const { log: log3 } = this.deps;
|
|
277609
277831
|
const graceMs = this.deps.firstLookGraceMs ?? 10 * 6e4;
|
|
277610
277832
|
const maxPerTick = this.deps.maxLettersPerTick ?? 2;
|
|
277611
277833
|
const actor = this.deps.actor ?? "actor:system";
|
|
@@ -277619,8 +277841,12 @@ var init_board_watch = __esm({
|
|
|
277619
277841
|
}
|
|
277620
277842
|
if (a.type !== "design") continue;
|
|
277621
277843
|
if (lifecycleOf(model, a.id) !== "active") continue;
|
|
277622
|
-
const boardKey = boardKeyOf(a.id);
|
|
277623
277844
|
const pinKey = `${company}\0${a.id}`;
|
|
277845
|
+
const boardKey = await this.boardOf(company, model, blobs, a, tag);
|
|
277846
|
+
if (boardKey === null) continue;
|
|
277847
|
+
const users = boardUsers.get(boardKey) ?? [];
|
|
277848
|
+
users.push({ company, artifactId: a.id });
|
|
277849
|
+
boardUsers.set(boardKey, users);
|
|
277624
277850
|
const watchLetters = annotationsOf(model, a.id).filter((x2) => x2.author === actor && x2.body.includes("[od-board-watch "));
|
|
277625
277851
|
const lettered = new Set(watchLetters.map((x2) => parseRunMarker(x2.body)).filter((s2) => s2 !== null));
|
|
277626
277852
|
const recordedSince = watchLetters.reduce((mn, x2) => {
|
|
@@ -277639,12 +277865,40 @@ var init_board_watch = __esm({
|
|
|
277639
277865
|
continue;
|
|
277640
277866
|
}
|
|
277641
277867
|
if (recordedSince === null && !this.pinnedSince.has(pinKey)) this.pinnedSince.set(pinKey, since);
|
|
277642
|
-
const
|
|
277868
|
+
const endedAtOf = this.roundEndedAt.get(`${company}\0${boardKey}`) ?? /* @__PURE__ */ new Map();
|
|
277869
|
+
this.roundEndedAt.set(`${company}\0${boardKey}`, endedAtOf);
|
|
277870
|
+
for (const r of read3.value.rounds) if (r.runId !== null) endedAtOf.set(r.runId, r.endedAt);
|
|
277871
|
+
const takenKey = (r) => `${company}\0${a.id}\0${r.key}`;
|
|
277872
|
+
const fresh = read3.value.rounds.filter((r) => r.endedAt > since && !lettered.has(r.key) && !this.takenRounds.has(takenKey(r))).sort((x2, y) => x2.endedAt - y.endedAt);
|
|
277873
|
+
const deferKey = `${company}\0${a.id}`;
|
|
277874
|
+
if (fresh.length > 0 && ownerIsWorking(model, a)) {
|
|
277875
|
+
if (!this.deferredLogged.has(deferKey)) {
|
|
277876
|
+
this.deferredLogged.add(deferKey);
|
|
277877
|
+
log3?.(`[board-watch] ${tag}${a.id} \u7684 owner \u6B63\u5728\u6267\u884C\u8FD9\u4E2A\u8282\u70B9\uFF0C\u677F ${boardKey} \u4E0A ${fresh.length} \u8F6E\u7ED3\u675F\u7684\u5BF9\u8BDD\u5148\u4E0D\u5199\u4FE1\uFF0C\u7B49\u5B83\u8FD9\u8F6E work \u7ED3\u675F\u518D\u770B`);
|
|
277878
|
+
}
|
|
277879
|
+
continue;
|
|
277880
|
+
}
|
|
277881
|
+
this.deferredLogged.delete(deferKey);
|
|
277882
|
+
const sourceRuns = fresh.length > 0 && blobs ? await this.headSourceRuns(company, blobs, model, a, log3, tag) : [];
|
|
277883
|
+
const takenBy = (r) => {
|
|
277884
|
+
for (const src of sourceRuns) {
|
|
277885
|
+
if (r.runId !== null && src === r.runId) return src;
|
|
277886
|
+
const srcEnded = endedAtOf.get(src);
|
|
277887
|
+
if (srcEnded !== void 0 && srcEnded >= r.endedAt) return src;
|
|
277888
|
+
}
|
|
277889
|
+
return null;
|
|
277890
|
+
};
|
|
277643
277891
|
const seen = /* @__PURE__ */ new Set();
|
|
277644
277892
|
for (const r of fresh) {
|
|
277645
277893
|
if (written >= maxPerTick) break;
|
|
277646
277894
|
if (seen.has(r.key)) continue;
|
|
277647
277895
|
seen.add(r.key);
|
|
277896
|
+
const src = takenBy(r);
|
|
277897
|
+
if (src !== null) {
|
|
277898
|
+
this.takenRounds.add(takenKey(r));
|
|
277899
|
+
log3?.(`[board-watch] ${tag}${a.id} \u2190 \u677F ${boardKey} \u4E00\u8F6E\u5BF9\u8BDD\u7ED3\u675F\uFF08${r.key.slice(0, 12)} ${r.status}\uFF09\uFF0C\u5F53\u524D\u7248\u672C\u7684\u5FEB\u7167\u6765\u6E90 run ${src} \u5DF2\u8986\u76D6\u5B83 \u2192 \u4E0D\u5199\u4FE1`);
|
|
277900
|
+
continue;
|
|
277901
|
+
}
|
|
277648
277902
|
const ok3 = r.status === "succeeded";
|
|
277649
277903
|
const reason = ok3 ? null : r.error ?? (r.runId !== null ? await this.runErrorFromRegistry(boardKey, r.runId) : null);
|
|
277650
277904
|
await kernel.annotate({ artifactId: a.id, actor, body: this.letterBody(a.id, boardKey, r, since, reason), kind: "comment" });
|
|
@@ -277657,6 +277911,73 @@ var init_board_watch = __esm({
|
|
|
277657
277911
|
}
|
|
277658
277912
|
}
|
|
277659
277913
|
}
|
|
277914
|
+
/** 这个产物实际用的画板(与 CLI 同一个解析函数);解析不了(没有公司、装箱单读不到)→ 记一行日志、本轮跳过它。 */
|
|
277915
|
+
async boardOf(company, model, blobs, a, tag) {
|
|
277916
|
+
const errKey = `${company}\0${a.id}`;
|
|
277917
|
+
let cache = this.boardLinks.get(company);
|
|
277918
|
+
if (!cache) this.boardLinks.set(company, cache = /* @__PURE__ */ new Map());
|
|
277919
|
+
try {
|
|
277920
|
+
const { boardKey } = await resolveDesignBoard(
|
|
277921
|
+
{ companyId: company || (this.deps.companyId ?? ""), model, blobs, artifact: a },
|
|
277922
|
+
{ deriveKey: this.deps.boardKeyOf, cache }
|
|
277923
|
+
);
|
|
277924
|
+
this.boardResolveError.delete(errKey);
|
|
277925
|
+
return boardKey;
|
|
277926
|
+
} catch (err) {
|
|
277927
|
+
const msg = String(err);
|
|
277928
|
+
if (this.boardResolveError.get(errKey) !== msg) {
|
|
277929
|
+
this.boardResolveError.set(errKey, msg);
|
|
277930
|
+
this.deps.log?.(`[board-watch] ${tag}${a.id} \u89E3\u6790\u4E0D\u51FA\u753B\u677F\uFF0C\u672C\u8F6E\u8DF3\u8FC7\uFF1A${msg}`);
|
|
277931
|
+
}
|
|
277932
|
+
return null;
|
|
277933
|
+
}
|
|
277934
|
+
}
|
|
277935
|
+
/**
|
|
277936
|
+
* 同一块板这一轮同时是不止一家公司的 design 画板 → 记一行(同一组只记一次)。只会出现在旧规则遗留的存量板上:
|
|
277937
|
+
* 两家同名产物都已经交过稿、board.link 都指向同一块只由 artifactId 起名的旧板。不自动处理,交给人看。
|
|
277938
|
+
*/
|
|
277939
|
+
logSharedBoards(boardUsers) {
|
|
277940
|
+
for (const [boardKey, users] of boardUsers) {
|
|
277941
|
+
const companies = [...new Set(users.map((u) => u.company))].sort();
|
|
277942
|
+
if (companies.length < 2) continue;
|
|
277943
|
+
const key2 = `${boardKey}\0${companies.join(",")}`;
|
|
277944
|
+
if (this.sharedBoardLogged.has(key2)) continue;
|
|
277945
|
+
this.sharedBoardLogged.add(key2);
|
|
277946
|
+
this.deps.log?.(
|
|
277947
|
+
`[board-watch] \u4E32\u677F\uFF1A\u753B\u677F ${boardKey} \u540C\u65F6\u662F ${users.map((u) => `[${u.company}] ${u.artifactId}`).join("\u3001")} \u7684\u753B\u677F\uFF08\u65E7\u547D\u540D\u89C4\u5219\u53EA\u6309\u4EA7\u7269 id \u8D77\u540D\u3001\u4E24\u5BB6\u90FD\u5DF2\u5728\u8FD9\u5757\u677F\u4E0A\u4EA4\u8FC7\u7A3F\uFF09\u3002\u4E24\u5BB6\u4E92\u76F8\u770B\u5F97\u5230\u5BF9\u65B9\u7684\u6750\u6599\u548C\u7A3F\u5B50\uFF0C\u9700\u8981\u4EBA\u5904\u7406\uFF1B\u5DE1\u68C0\u4E0D\u81EA\u52A8\u6539`
|
|
277948
|
+
);
|
|
277949
|
+
}
|
|
277950
|
+
}
|
|
277951
|
+
/**
|
|
277952
|
+
* 当前 head 与最近一版装箱单(两者可能不同:head 在跑空壳/被打回时回落)各自 board.link 里的快照来源 runId。
|
|
277953
|
+
* 读不到(非装箱单、没有 board.link、blob 缺失、占位 status-pull)的不算。
|
|
277954
|
+
*/
|
|
277955
|
+
async headSourceRuns(company, blobs, model, a, log3, tag) {
|
|
277956
|
+
const candidates = [];
|
|
277957
|
+
const head = a.currentRev ? model.revisions.get(a.currentRev) : void 0;
|
|
277958
|
+
if (head) candidates.push(head);
|
|
277959
|
+
const latestManifest = [...model.revisions.values()].filter((r) => r.artifactId === a.id && r.contentKind === "manifest" && r.contentRef.length > 0).sort((x2, y) => y.createdAt.localeCompare(x2.createdAt))[0];
|
|
277960
|
+
if (latestManifest && latestManifest.id !== head?.id) candidates.push(latestManifest);
|
|
277961
|
+
const out = [];
|
|
277962
|
+
for (const rev of candidates) {
|
|
277963
|
+
if (rev.contentKind !== "manifest" || rev.contentRef.length === 0) continue;
|
|
277964
|
+
const cacheKey = `${company}\0${rev.id}`;
|
|
277965
|
+
let src = this.revisionSourceRun.get(cacheKey);
|
|
277966
|
+
if (src === void 0) {
|
|
277967
|
+
try {
|
|
277968
|
+
const manifest = parseManifest(await blobs.get(rev.contentRef));
|
|
277969
|
+
const entry = manifest.entries.find((e) => e.path === BOARD_LINK_FILE);
|
|
277970
|
+
src = entry ? parseBoardLinkSourceRun(new TextDecoder().decode(await blobs.get(entry.hash))) : null;
|
|
277971
|
+
} catch (err) {
|
|
277972
|
+
log3?.(`[board-watch] ${tag}\u8BFB ${a.id} \u7248\u672C ${rev.id} \u7684 board.link \u5931\u8D25\uFF08${String(err)}\uFF09\uFF0C\u6309\u300C\u4E0D\u77E5\u9053\u6765\u81EA\u54EA\u4E00\u8F6E\u300D\u5904\u7406`);
|
|
277973
|
+
src = null;
|
|
277974
|
+
}
|
|
277975
|
+
this.revisionSourceRun.set(cacheKey, src);
|
|
277976
|
+
}
|
|
277977
|
+
if (src !== null) out.push(src);
|
|
277978
|
+
}
|
|
277979
|
+
return out;
|
|
277980
|
+
}
|
|
277660
277981
|
letterBody(artifactId, boardKey, r, since, reason) {
|
|
277661
277982
|
const marker = `${boardWatchRunMarker(r.key)} ${boardWatchSinceMarker(since)}`;
|
|
277662
277983
|
const round = `${r.runId !== null ? `run ${r.runId.slice(0, 8)}` : `\u6D88\u606F ${r.key.slice(4, 12)}`}\uFF0C\u5F15\u64CE=${r.agentId ?? "?"}\uFF0C\u7ED3\u675F\u4E8E ${new Date(r.endedAt).toISOString()}`;
|
|
@@ -277667,7 +277988,8 @@ var init_board_watch = __esm({
|
|
|
277667
277988
|
`\u753B\u677F ${boardKey} \u4E0A\u6709\u4E00\u8F6E\u5BF9\u8BDD\u8DD1\u5B8C\u4E86\uFF08${round}\uFF09\uFF0C\u8FD9\u4E00\u8F6E\u4EA7\u51FA\uFF1A`,
|
|
277668
277989
|
files,
|
|
277669
277990
|
``,
|
|
277670
|
-
`\
|
|
277991
|
+
`\u5148\u770B\u8FD9\u4E00\u8F6E\u662F\u4E0D\u662F\u5DF2\u7ECF\u4EA4\u8FC7\uFF1A\u5F53\u524D\u7248\u672C\u88C5\u7BB1\u5355\u91CC board.link \u7684\u300C\u5FEB\u7167\u6765\u6E90 run\u300D\u5982\u679C\u5C31\u662F ${r.runId ?? "\u8FD9\u4E00\u8F6E"}\uFF0C\u8BF4\u660E\u5DF2\u53D6\u8D70\uFF0C\`oasis resolve <\u672C\u4FE1 id> --as resolved\` \u5373\u53EF\uFF0C\u522B\u91CD\u590D propose\u3002`,
|
|
277992
|
+
`\u6CA1\u4EA4\u8FC7\u5C31\u53D6\u8D27\u6838\u5BF9\uFF1A\`oasis design status ${artifactId} --wait --pull\`\uFF08\u677F\u4E0A\u8FD8\u6709\u5728\u8DD1\u7684\u8F6E\u6B21\u4F1A\u5148\u7B49\u5B83\u8DD1\u5B8C\uFF09\u2192 \u5BF9\u7740 DESIGN_BRIEF.md \u4E0E inputs/ \u9010\u5B57\u6BB5\u6838\uFF08\u6570\u636E\u5BF9\u4E0D\u5BF9\u3001\u72B6\u6001\u5168\u4E0D\u5168\u3001\u6709\u6CA1\u6709\u7F16\u9020\uFF09\u3002\u591F\u597D\u5C31 \`oasis propose ${artifactId} --from-dir <\u76EE\u5F55> --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"\`\uFF1B\u8981\u6539\u5C31\u56DE\u677F\u4E0A\u518D\u6765\u4E00\u8F6E \`oasis design chat ${artifactId} --turn continue --message "<\u8981\u6539\u4EC0\u4E48>" --async\`\uFF0C\u968F\u540E \`oasis design status ${artifactId} --wait --pull\` \u7B49\u7ED3\u679C\uFF08\u26D4 \u522B\u628A --pull \u4E0B\u6765\u7684\u6587\u4EF6\u5728\u672C\u5730\u624B\u6539\u540E propose\uFF09\u3002\u8FD9\u4E00\u8F6E\u82E5\u662F\u4EBA\u76F4\u63A5\u5728\u677F\u4E0A\u804A\u51FA\u6765\u7684\u3001\u5185\u5BB9\u4E0D\u5FC5\u6536\u5F55\uFF0C\u56DE\u5E16\u8BF4\u660E\u540E\u6309 wontfix \u5904\u7406\u5373\u53EF\uFF08\u540C\u4E00\u8F6E\u4E0D\u4F1A\u518D\u6765\u4FE1\uFF09\u3002`
|
|
277671
277993
|
].join("\n");
|
|
277672
277994
|
}
|
|
277673
277995
|
const quoted = reason === null ? null : reason.length > MAX_REASON_CHARS ? `${reason.slice(0, MAX_REASON_CHARS)}\u2026` : reason;
|
|
@@ -277676,7 +277998,7 @@ var init_board_watch = __esm({
|
|
|
277676
277998
|
`\u753B\u677F ${boardKey} \u4E0A\u6709\u4E00\u8F6E\u5BF9\u8BDD**\u6CA1\u8DD1\u6210**\uFF08\u7EC8\u6001=${r.status}\uFF0C${round}\uFF09\u3002`,
|
|
277677
277999
|
quoted !== null ? `od \u8BB0\u7684\u539F\u56E0\uFF08\u539F\u6587\uFF09\uFF1A${quoted}${r.errorCode !== null ? `\uFF08\u9519\u8BEF\u7801 ${r.errorCode}\uFF09` : ""}` : `od \u6CA1\u6709\u8BB0\u5F55\u8FD9\u4E00\u8F6E\u7684\u5931\u8D25\u539F\u56E0\u3002`,
|
|
277678
278000
|
``,
|
|
277679
|
-
`\u5148 \`oasis design status ${artifactId}\` \u770B\u677F\u4E0A\u6709\u6CA1\u6709\u53EF\u7528\u7684\u4E0A\u4E00\u7248\uFF1A\u6709\u5C31\u7167\u5E38\u53D6\u8D27\u6838\u5BF9\u3002\u8981\u91CD\u8DD1\u5C31\u81EA\u5DF1\u5224\u65AD\uFF1A\u50CF\u662F\u989D\u5EA6/\u9650\u6D41\u5C31\u7B49\u6062\u590D\u540E\u518D\u6765\uFF0C\u6216\u6362\u4E2A\u5F15\u64CE \`oasis design chat ${artifactId} --agent <\u5F15\u64CE> --message "<\u2026>" --async\`\uFF1B\u50CF\u662F\u9700\u6C42/\u6570\u636E\u95EE\u9898\u5C31\u628A\u5B83\u4EEC\u9489\u5F97\u66F4\u6B7B\u540E\u91CD\u8D77\u4E00\u8F6E\
|
|
278001
|
+
`\u5148 \`oasis design status ${artifactId}\` \u770B\u677F\u4E0A\u6709\u6CA1\u6709\u53EF\u7528\u7684\u4E0A\u4E00\u7248\uFF1A\u6709\u5C31\u7167\u5E38\u53D6\u8D27\u6838\u5BF9\u3002\u8981\u91CD\u8DD1\u5C31\u81EA\u5DF1\u5224\u65AD\uFF1A\u50CF\u662F\u989D\u5EA6/\u9650\u6D41\u5C31\u7B49\u6062\u590D\u540E\u518D\u6765\uFF0C\u6216\u6362\u4E2A\u5F15\u64CE \`oasis design chat ${artifactId} --turn continue --agent <\u5F15\u64CE> --message "<\u2026>" --async\`\uFF1B\u50CF\u662F\u9700\u6C42/\u6570\u636E\u95EE\u9898\u5C31\u628A\u5B83\u4EEC\u9489\u5F97\u66F4\u6B7B\u540E\u91CD\u8D77\u4E00\u8F6E\u3002\u91CD\u4E0B\u4E4B\u540E\u7ACB\u523B \`oasis design status ${artifactId} --wait --pull\` \u5728\u4F1A\u8BDD\u91CC\u7B49\u7ED3\u679C\uFF0C\u522B\u4E0B\u5355\u5C31\u6536\u5DE5\u3002\u4ECD\u4E0D\u884C\u7528 \`oasis gap ${artifactId} --desc "<\u5361\u5728\u54EA>"\` \u5192\u6CE1\u7ED9\u4EBA\u3002`
|
|
277680
278002
|
].join("\n");
|
|
277681
278003
|
}
|
|
277682
278004
|
};
|
|
@@ -278763,6 +279085,7 @@ __export(src_exports2, {
|
|
|
278763
279085
|
knowledgeSearchTokenStream: () => knowledgeSearchTokenStream,
|
|
278764
279086
|
knowledgeSynthesisPrompt: () => knowledgeSynthesisPrompt,
|
|
278765
279087
|
knowledgeTerms: () => knowledgeTerms,
|
|
279088
|
+
latestBoardLink: () => latestBoardLink,
|
|
278766
279089
|
letterBackfillDoneScope: () => letterBackfillDoneScope,
|
|
278767
279090
|
linkChatAttachmentsToWorkOrder: () => linkChatAttachmentsToWorkOrder,
|
|
278768
279091
|
listActiveCoordinatorAgents: () => listActiveCoordinatorAgents,
|
|
@@ -278809,6 +279132,7 @@ __export(src_exports2, {
|
|
|
278809
279132
|
openNewEngine: () => openNewEngine,
|
|
278810
279133
|
operatorCrossCompanyRead: () => operatorCrossCompanyRead,
|
|
278811
279134
|
outputsPartProvider: () => outputsPartProvider,
|
|
279135
|
+
ownerIsWorking: () => ownerIsWorking,
|
|
278812
279136
|
packMatches: () => packMatches,
|
|
278813
279137
|
parentConversationTaskLines: () => parentConversationTaskLines,
|
|
278814
279138
|
parseConnectorSkillId: () => parseConnectorSkillId,
|
|
@@ -278893,6 +279217,7 @@ __export(src_exports2, {
|
|
|
278893
279217
|
resolveChatItemsTurnId: () => resolveChatItemsTurnId,
|
|
278894
279218
|
resolveCoordinatorProvisionScope: () => resolveCoordinatorProvisionScope,
|
|
278895
279219
|
resolveDefaultCompanyConfig: () => resolveDefaultCompanyConfig,
|
|
279220
|
+
resolveDesignBoard: () => resolveDesignBoard,
|
|
278896
279221
|
resolveDispatchScope: () => resolveDispatchScope,
|
|
278897
279222
|
resolveListenTarget: () => resolveListenTarget,
|
|
278898
279223
|
resolveManagerBinding: () => resolveManagerBinding,
|
|
@@ -279110,6 +279435,7 @@ var init_src11 = __esm({
|
|
|
279110
279435
|
init_connector_tool_versions();
|
|
279111
279436
|
init_agent_manage_guard();
|
|
279112
279437
|
init_board_watch();
|
|
279438
|
+
init_board_key();
|
|
279113
279439
|
init_uncategorized_project();
|
|
279114
279440
|
init_run_settlement();
|
|
279115
279441
|
init_reconcile_terminal_runs();
|
|
@@ -289309,6 +289635,8 @@ ${nodeFault}` : "");
|
|
|
289309
289635
|
return [defaultCompanyId, ...active.filter((id) => id !== defaultCompanyId)];
|
|
289310
289636
|
},
|
|
289311
289637
|
kernelFor: async (companyId) => (await getEngine(companyId)).kernel,
|
|
289638
|
+
// 读 head 装箱单里的 board.link(「快照来源 run」)判断这一轮是否已被取走,已取走就不写信
|
|
289639
|
+
blobsFor: async (companyId) => (await getEngine(companyId)).blobs,
|
|
289312
289640
|
odBase,
|
|
289313
289641
|
...odToken ? { odToken } : {},
|
|
289314
289642
|
boardKeyOf: deriveBoardKey,
|
|
@@ -292568,29 +292896,32 @@ var COMMAND_DECLS = {
|
|
|
292568
292896
|
flags: [
|
|
292569
292897
|
{ name: "message", desc: "\u6D88\u606F\u5185\u5BB9", required: true },
|
|
292570
292898
|
{ name: "turn", desc: "\u5BF9\u8BDD\u8F6E\u6B21\uFF08first | continue\uFF09" },
|
|
292571
|
-
{ name: "async", desc: "\
|
|
292899
|
+
{ name: "async", desc: "\u4E0B\u5355\u5373\u8FD4\uFF1B\u968F\u540E\u7528 design status --wait --pull \u963B\u585E\u7B49\u7ED3\u679C" },
|
|
292572
292900
|
{ name: "system", desc: "\u7CFB\u7EDF\u63D0\u793A" }
|
|
292573
292901
|
],
|
|
292574
292902
|
examples: ['oasis design chat artifact:design:xyz --message "\u628A\u6309\u94AE\u6539\u6210\u84DD\u8272" --turn continue']
|
|
292575
292903
|
},
|
|
292576
292904
|
"design status": {
|
|
292577
292905
|
group: "\u8BBE\u8BA1\u7A3F",
|
|
292578
|
-
usage: "oasis design status <artifactId> [--pull]",
|
|
292579
|
-
description: "\u67E5\u753B\u677F\u73B0\u72B6\uFF08\u6062\u590D\u4F18\u5148\uFF09\u3002\u88AB\u6D3E\u53D1\u5148\u8DD1\u5B83\u2014\u2014\u5F15\u64CE\u5728\u8DD1\u5C31\u522B\u8D77\u65B0\u8F6E\u3002",
|
|
292906
|
+
usage: "oasis design status <artifactId> [--pull] [--wait [--wait-timeout <\u5206\u949F>]]",
|
|
292907
|
+
description: "\u67E5\u753B\u677F\u73B0\u72B6\uFF08\u6062\u590D\u4F18\u5148\uFF09\u3002\u88AB\u6D3E\u53D1\u5148\u8DD1\u5B83\u2014\u2014\u5F15\u64CE\u5728\u8DD1\u5C31\u522B\u8D77\u65B0\u8F6E\u3002--wait\uFF1A\u677F\u4E0A\u6709\u5728\u8DD1\u7684\u8F6E\u6B21\u5C31\u963B\u585E\u7B49\u5230\u5168\u90E8\u7ED3\u675F\uFF08\u4E0D\u7BA1\u662F\u8C01\u8D77\u7684\uFF09\uFF0C\u518D\u6253\u5370\u7ED3\u679C\uFF1B\u8D85\u65F6\u975E\u96F6\u9000\u51FA\u3002",
|
|
292580
292908
|
positional: [
|
|
292581
292909
|
{ name: "<artifactId>", required: true, desc: "\u4EA7\u7269 id" }
|
|
292582
292910
|
],
|
|
292583
292911
|
flags: [
|
|
292584
|
-
{ name: "pull", desc: "\u62C9\u53D6\u6700\u65B0\u753B\u677F\u5185\u5BB9\u5230\u672C\u5730" }
|
|
292912
|
+
{ name: "pull", desc: "\u62C9\u53D6\u6700\u65B0\u753B\u677F\u5185\u5BB9\u5230\u672C\u5730\uFF08\u5E26 --wait \u65F6\uFF1A\u7B49\u5B8C\u4E14\u6700\u8FD1\u4E00\u8F6E\u6210\u529F\u624D\u62C9\uFF09" },
|
|
292913
|
+
{ name: "wait", desc: "\u677F\u4E0A\u6709\u5728\u8DD1\u7684\u8F6E\u6B21\u5C31\u963B\u585E\u7B49\u5B83\u4EEC\u7ED3\u675F\uFF08\u540C gh pr checks --watch\uFF09", boolean: true },
|
|
292914
|
+
{ name: "wait-timeout", desc: "--wait \u6700\u591A\u7B49\u51E0\u5206\u949F\uFF08\u9ED8\u8BA4 100\uFF09" },
|
|
292915
|
+
{ name: "wait-interval", desc: "--wait \u8F6E\u8BE2\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 20\uFF09" }
|
|
292585
292916
|
],
|
|
292586
|
-
examples: ["oasis design status artifact:design:xyz --pull"]
|
|
292917
|
+
examples: ["oasis design status artifact:design:xyz --wait --pull", "oasis design status artifact:design:xyz --pull"]
|
|
292587
292918
|
},
|
|
292588
292919
|
design: {
|
|
292589
292920
|
group: "\u8BBE\u8BA1\u7A3F",
|
|
292590
292921
|
usage: "oasis design <chat|status> <artifactId> ...",
|
|
292591
292922
|
description: "\u8BBE\u8BA1\u4EA7\u7269\u76F8\u5173\u64CD\u4F5C\u3002\u8FDE\u54EA\u4E2A open-design\uFF1A\u5458\u5DE5\u5F00\u4E86 open-design \u8FDE\u63A5\u5668\u5C31\u8FDE\u5B83\u767B\u8BB0\u7684\u5730\u5740\u5E76\u5E26\u4EE4\u724C\uFF08\u4EFB\u610F\u8282\u70B9\u53EF\u7528\uFF09\uFF0C\u5426\u5219 $OASIS_OPEN_DESIGN_URL\uFF0C\u518D\u5426\u5219\u672C\u673A\u3002",
|
|
292592
292923
|
subCommands: ["design chat", "design status"],
|
|
292593
|
-
examples: ['oasis design chat artifact:design:xyz --message "\u8BBE\u8BA1\u767B\u5F55\u9875" --async']
|
|
292924
|
+
examples: ['oasis design chat artifact:design:xyz --message "\u8BBE\u8BA1\u767B\u5F55\u9875" --async', "oasis design status artifact:design:xyz --wait --pull"]
|
|
292594
292925
|
},
|
|
292595
292926
|
// —— 图机制(§6/§7) ——
|
|
292596
292927
|
annotate: {
|
|
@@ -294268,6 +294599,15 @@ function needPos(positional, i, usage) {
|
|
|
294268
294599
|
if (v2 === void 0) throw new Error(`\u7528\u6CD5: ${usage}`);
|
|
294269
294600
|
return v2;
|
|
294270
294601
|
}
|
|
294602
|
+
function positiveNumberFlag(flags, name, dflt) {
|
|
294603
|
+
const raw = flags.get(name);
|
|
294604
|
+
if (raw === void 0) return dflt;
|
|
294605
|
+
const n = Number(raw);
|
|
294606
|
+
if (!Number.isFinite(n) || n <= 0) throw new Error(`--${name} \u8981\u4E00\u4E2A\u6B63\u6570\uFF08\u6536\u5230\uFF1A${raw}\uFF09`);
|
|
294607
|
+
return n;
|
|
294608
|
+
}
|
|
294609
|
+
var shortRunKey = (key2) => key2.startsWith("msg:") ? `\u6D88\u606F ${key2.slice(4, 12)}` : `run ${key2.slice(0, 8)}`;
|
|
294610
|
+
var clipReason = (reason) => reason.length > 300 ? `${reason.slice(0, 300)}\u2026` : reason;
|
|
294271
294611
|
function semicolonList(raw, field) {
|
|
294272
294612
|
if (raw === void 0) return {};
|
|
294273
294613
|
const items = raw.split(";").map((x2) => x2.trim()).filter(Boolean);
|
|
@@ -294470,7 +294810,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
294470
294810
|
}
|
|
294471
294811
|
}
|
|
294472
294812
|
}
|
|
294473
|
-
var CLI_VERSION = "2.2.
|
|
294813
|
+
var CLI_VERSION = "2.2.86" ? "2.2.86" : "dev";
|
|
294474
294814
|
function apiHeaders(token, company) {
|
|
294475
294815
|
const headers = {
|
|
294476
294816
|
authorization: `Bearer ${token}`,
|
|
@@ -296209,6 +296549,16 @@ ${res.warning}`);
|
|
|
296209
296549
|
}
|
|
296210
296550
|
case "design": {
|
|
296211
296551
|
const sub = positional[0];
|
|
296552
|
+
const resolveBoard = async (artifactId) => {
|
|
296553
|
+
let b2;
|
|
296554
|
+
try {
|
|
296555
|
+
b2 = await api.view("design-board", artifactId);
|
|
296556
|
+
} catch (err) {
|
|
296557
|
+
throw new Error(`\u62FF\u4E0D\u5230 ${artifactId} \u7684\u753B\u677F\uFF08\u753B\u677F\u540D\u8981\u5E26\u5F53\u524D\u516C\u53F8\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}\u3002\u4E0D\u56DE\u843D\u5230\u4E0D\u5E26\u516C\u53F8\u7684\u65E7\u753B\u677F\u540D`);
|
|
296558
|
+
}
|
|
296559
|
+
if (!b2?.companyId || !b2.boardKey) throw new Error(`\u62FF\u4E0D\u5230 ${artifactId} \u7684\u753B\u677F\uFF1A\u670D\u52A1\u7AEF\u6CA1\u7ED9\u51FA\u516C\u53F8\u6216\u753B\u677F\u540D\u3002\u4E0D\u56DE\u843D\u5230\u4E0D\u5E26\u516C\u53F8\u7684\u65E7\u753B\u677F\u540D`);
|
|
296560
|
+
return { boardKey: b2.boardKey, note: b2.source === "board-link" ? "\uFF08\u6CBF\u7528\u5DF2\u4EA4\u7A3F\u8BB0\u5F55\u91CC\u7684\u753B\u677F\uFF09" : "" };
|
|
296561
|
+
};
|
|
296212
296562
|
if (sub === "chat") {
|
|
296213
296563
|
const artifactId = needPos(positional, 1, "oasis design chat <artifactId> --message <t>");
|
|
296214
296564
|
const message = flags.get("message") ?? (["DESIGN_BRIEF.md", "TASK.md"].map((f2) => fs44.existsSync(f2) ? fs44.readFileSync(f2, "utf8") : "").find((s2) => s2.trim()) ?? "");
|
|
@@ -296226,24 +296576,26 @@ ${res.warning}`);
|
|
|
296226
296576
|
}
|
|
296227
296577
|
}
|
|
296228
296578
|
}
|
|
296579
|
+
const board = await resolveBoard(artifactId);
|
|
296229
296580
|
const baseTurnOpts = {
|
|
296230
296581
|
base: odBase,
|
|
296231
296582
|
...od.token ? { token: od.token } : {},
|
|
296232
296583
|
agentId: flags.get("agent") ?? "claude",
|
|
296233
296584
|
artifactId,
|
|
296585
|
+
boardKey: board.boardKey,
|
|
296234
296586
|
title: flags.get("title") ?? artifactId,
|
|
296235
296587
|
message,
|
|
296236
296588
|
...flags.get("system") !== void 0 ? { systemPrompt: flags.get("system") } : {},
|
|
296237
296589
|
...isContinue ? {} : { contextFiles }
|
|
296238
296590
|
};
|
|
296239
296591
|
if (flags.get("async") === "true") {
|
|
296240
|
-
println(`[design] \u753B\u677F ${
|
|
296592
|
+
println(`[design] \u753B\u677F ${board.boardKey}${board.note} \u2190 ${artifactId}\uFF1B${isContinue ? "\u7EED\u8F6E" : "\u9996\u8F6E"}\uFF08--async\uFF09\u2192 od \u5F15\u64CE ${odLabel} \u2026`);
|
|
296241
296593
|
const started = await startDesignChatTurn(baseTurnOpts);
|
|
296242
296594
|
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`);
|
|
296243
|
-
println(`[design] \
|
|
296595
|
+
println(`[design] \u4E0B\u4E00\u6B65\u7ACB\u523B\u6267\u884C\uFF1Aoasis design status ${artifactId} --wait --pull\uFF08\u963B\u585E\u7B49\u8FD9\u4E00\u8F6E\u8DD1\u5B8C\u5E76\u62C9\u8D27\uFF0C\u6700\u957F\u7B49 100 \u5206\u949F\uFF09\u3002\u522B\u4E0B\u5355\u540E\u76F4\u63A5\u7ED3\u675F\u4F1A\u8BDD\uFF0C\u4E5F\u522B\u81EA\u5DF1\u9694\u51E0\u5206\u949F\u624B\u52A8 status\u3002`);
|
|
296244
296596
|
break;
|
|
296245
296597
|
}
|
|
296246
|
-
println(`[design] \u753B\u677F ${
|
|
296598
|
+
println(`[design] \u753B\u677F ${board.boardKey}${board.note} \u2190 ${artifactId}\uFF1B${isContinue ? "\u7EED\u8F6E" : "\u9996\u8F6E"}\u5BF9\u8BDD\u9A71\u52A8 od \u5F15\u64CE ${odLabel} \u2026`);
|
|
296247
296599
|
const turn = await runDesignChatTurn({
|
|
296248
296600
|
...baseTurnOpts,
|
|
296249
296601
|
onLine: (line2) => println(`[od] ${line2.length > 500 ? line2.slice(0, 500) + "\u2026" : line2}`)
|
|
@@ -296254,46 +296606,83 @@ ${res.warning}`);
|
|
|
296254
296606
|
break;
|
|
296255
296607
|
}
|
|
296256
296608
|
if (sub === "status") {
|
|
296257
|
-
const artifactId = needPos(positional, 1, "oasis design status <artifactId> [--pull]");
|
|
296609
|
+
const artifactId = needPos(positional, 1, "oasis design status <artifactId> [--pull] [--wait]");
|
|
296258
296610
|
const od = resolveOpenDesignEndpoint(flags.get("od-url"));
|
|
296259
296611
|
const odBase = od.base;
|
|
296260
296612
|
const odFetch = withOdToken(fetch, od.token);
|
|
296261
|
-
const
|
|
296613
|
+
const { boardKey } = await resolveBoard(artifactId);
|
|
296614
|
+
let st;
|
|
296615
|
+
let waitedForRun = false;
|
|
296616
|
+
if (flags.get("wait") === "true") {
|
|
296617
|
+
const timeoutMin = positiveNumberFlag(flags, "wait-timeout", 100);
|
|
296618
|
+
const intervalSec = positiveNumberFlag(flags, "wait-interval", 20);
|
|
296619
|
+
const fmt = (ms) => `${Math.floor(ms / 6e4)} \u5206 ${Math.floor(ms % 6e4 / 1e3)} \u79D2`;
|
|
296620
|
+
const waited = await waitBoardSettled(odBase, odFetch, boardKey, {
|
|
296621
|
+
timeoutMs: timeoutMin * 6e4,
|
|
296622
|
+
intervalMs: intervalSec * 1e3,
|
|
296623
|
+
// 每次轮询打一行撑 liveness;状态没变只打短的一行,别刷屏
|
|
296624
|
+
onPoll: ({ live: live2, elapsedMs, changed, unreadable }) => {
|
|
296625
|
+
if (!changed) return println(`[design] \u2026\u4ECD\u5728\u7B49\uFF08\u5DF2\u7B49 ${fmt(elapsedMs)}\uFF09`);
|
|
296626
|
+
if (live2.length === 0 && unreadable) return println(`[design] \u8FD9\u6B21\u6CA1\u8BFB\u5230\u753B\u677F\u5BF9\u8BDD\u8BB0\u5F55\uFF08od \u6682\u65F6\u4E0D\u901A\uFF1F\uFF09\uFF0C\u63A5\u7740\u7B49\uFF08\u5DF2\u7B49 ${fmt(elapsedMs)}\uFF09`);
|
|
296627
|
+
const runs = live2.map((r) => `${shortRunKey(r.key)} \u72B6\u6001=${r.status}${r.agentId ? ` \u5F15\u64CE=${r.agentId}` : ""}`).join("\uFF1B");
|
|
296628
|
+
println(`[design] \u7B49\u753B\u677F\u8FD9\u4E00\u8F6E\u8DD1\u5B8C\uFF1A${runs}\uFF08\u5DF2\u7B49 ${fmt(elapsedMs)}\uFF0C\u4E0A\u9650 ${timeoutMin} \u5206\u949F\uFF09`);
|
|
296629
|
+
}
|
|
296630
|
+
});
|
|
296631
|
+
st = waited.status;
|
|
296632
|
+
waitedForRun = waited.waited;
|
|
296633
|
+
if (!waited.settled) {
|
|
296634
|
+
const runs = waited.live.map((r) => `${shortRunKey(r.key)} \u72B6\u6001=${r.status}`).join("\u3001") || "\u5BF9\u8BDD\u8BB0\u5F55\u8BFB\u4E0D\u5230";
|
|
296635
|
+
println(`[design] \u7B49\u4E86 ${fmt(waited.elapsedMs)}\uFF0C\u753B\u677F\u4E0A\u8FD9\u4E00\u8F6E\u8FD8\u6CA1\u7ED3\u675F\uFF08${runs}\uFF09\u2014\u2014\u5F15\u64CE\u8FD8\u5728\u8DD1\uFF0C\u53EF\u7A0D\u540E\u518D oasis design status ${artifactId} --wait${flags.get("pull") === "true" ? " --pull" : ""}\u3002\u522B\u53E6\u8D77\u65B0\u8F6E\u3002`);
|
|
296636
|
+
process.exitCode = 2;
|
|
296637
|
+
break;
|
|
296638
|
+
}
|
|
296639
|
+
if (waitedForRun) println(`[design] \u753B\u677F\u4E0A\u7684\u8F6E\u6B21\u90FD\u5DF2\u7ED3\u675F\uFF08\u7B49\u4E86 ${fmt(waited.elapsedMs)}\uFF09\u3002`);
|
|
296640
|
+
} else {
|
|
296641
|
+
st = await fetchBoardStatus(odBase, odFetch, boardKey);
|
|
296642
|
+
}
|
|
296262
296643
|
if (!st.boardExists) {
|
|
296263
|
-
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 ${artifactId} --message "<\u8BBE\u8BA1\u9700\u6C42+\u771F\u5B9E\u6570\u636E>" --async`);
|
|
296644
|
+
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 ${artifactId} --message "<\u8BBE\u8BA1\u9700\u6C42+\u771F\u5B9E\u6570\u636E>" --async\uFF0C\u968F\u540E oasis design status ${artifactId} --wait --pull`);
|
|
296264
296645
|
break;
|
|
296265
296646
|
}
|
|
296266
|
-
const live = st
|
|
296647
|
+
const live = liveBoardRuns(st);
|
|
296267
296648
|
if (live.length > 0) {
|
|
296268
|
-
for (const r of live) println(`[design] \u5F15\u64CE\u5728\u8DD1\
|
|
296649
|
+
for (const r of live) println(`[design] \u5F15\u64CE\u5728\u8DD1\uFF1A${shortRunKey(r.key)} \u72B6\u6001=${r.status}${r.agentId ? ` \u5F15\u64CE=${r.agentId}` : ""}\u2014\u2014\u522B\u518D\u8D77\u65B0\u8F6E\uFF1B\u7528 oasis design status ${artifactId} --wait --pull \u963B\u585E\u7B49\u5B83\u8DD1\u5B8C\u5E76\u62C9\u8D27\u3002`);
|
|
296269
296650
|
} else if (st.runs.length > 0) {
|
|
296270
296651
|
for (const r of st.runs.slice(0, 3)) {
|
|
296271
296652
|
println(`[design] \u8FD1\u671F run\uFF1A${r.runId.slice(0, 8)} \u7EC8\u6001=${r.status}${r.agentId ? ` \u5F15\u64CE=${r.agentId}` : ""}`);
|
|
296272
|
-
if (r.status === "failed" && r.error) {
|
|
296273
|
-
|
|
296274
|
-
|
|
296275
|
-
|
|
296653
|
+
if (r.status === "failed" && r.error) println(`[design] \u5931\u8D25\u539F\u56E0\uFF08od \u539F\u6587\uFF09\uFF1A${clipReason(r.error)}`);
|
|
296654
|
+
}
|
|
296655
|
+
} else if ((st.turns ?? []).length > 0) {
|
|
296656
|
+
for (const t of (st.turns ?? []).slice(0, 3)) {
|
|
296657
|
+
println(`[design] \u8FD1\u671F run\uFF08\u5BF9\u8BDD\u8BB0\u5F55\uFF09\uFF1A${(t.runId ?? t.messageId ?? "?").slice(0, 8)} \u7EC8\u6001=${t.status}${t.agentId ? ` \u5F15\u64CE=${t.agentId}` : ""}`);
|
|
296658
|
+
if (t.status !== "succeeded" && t.error) println(`[design] \u5931\u8D25\u539F\u56E0\uFF08od \u539F\u6587\uFF09\uFF1A${clipReason(t.error)}`);
|
|
296276
296659
|
}
|
|
296277
296660
|
} else {
|
|
296278
296661
|
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`);
|
|
296279
296662
|
}
|
|
296663
|
+
const last = latestEndedRun(st);
|
|
296664
|
+
const lastFailed = waitedForRun && last !== void 0 && last.status !== "succeeded";
|
|
296665
|
+
if (lastFailed) {
|
|
296666
|
+
println(`[design] \u521A\u7ED3\u675F\u7684\u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u6210\uFF08\u7EC8\u6001=${last.status}${last.agentId ? ` \u5F15\u64CE=${last.agentId}` : ""}\uFF09${last.error ? `\uFF1A${clipReason(last.error)}` : "\uFF0Cod \u6CA1\u8BB0\u539F\u56E0"}\u3002`);
|
|
296667
|
+
println(`[design] \u50CF\u989D\u5EA6/\u9650\u6D41/\u5F15\u64CE\u6545\u969C \u2192 \u6362\u5F15\u64CE\u91CD\u4E0B\uFF1Aoasis design chat ${artifactId} --turn continue --agent <\u53E6\u4E00\u4E2A\u5F15\u64CE> --message "<\u2026>" --async\uFF1B\u50CF\u9700\u6C42/\u6570\u636E\u4E0D\u6E05 \u2192 \u8865\u6E05\u695A\u540E\u91CD\u4E0B\uFF1B\u4E0B\u5B8C\u7167\u65E7 oasis design status ${artifactId} --wait --pull\u3002`);
|
|
296668
|
+
}
|
|
296280
296669
|
if (st.artifacts.length === 0) {
|
|
296281
|
-
println(`[design] \u677F\u4E0A\u8FD8\u6CA1\u6709\u4EA4\u4ED8\u7269\u3002${live.length > 0 ?
|
|
296670
|
+
println(`[design] \u677F\u4E0A\u8FD8\u6CA1\u6709\u4EA4\u4ED8\u7269\u3002${live.length > 0 ? `\u7B49\u5F15\u64CE\u8DD1\u5B8C\uFF1Aoasis design status ${artifactId} --wait --pull` : `\u8D77\u4E00\u8F6E\uFF1Aoasis design chat ${artifactId} --message "<\u2026>" --async\uFF0C\u968F\u540E oasis design status ${artifactId} --wait --pull`}`);
|
|
296282
296671
|
break;
|
|
296283
296672
|
}
|
|
296284
296673
|
println(`[design] \u677F\u4E0A\u4EA4\u4ED8\u7269\uFF08\u6301\u4E45\uFF0C\u65B0\u2192\u65E7\uFF09\uFF1A`);
|
|
296285
296674
|
for (const a of st.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.mtime ? ` \xB7 ${new Date(a.mtime).toISOString()}` : ""}`);
|
|
296286
|
-
if (flags.get("pull") === "true") {
|
|
296675
|
+
if (flags.get("pull") === "true" && !lastFailed) {
|
|
296287
296676
|
const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
296288
|
-
const { dir: dir2, entry } = await harvestBoard(odBase, odFetch, odPublic, os13.tmpdir(), st.boardKey,
|
|
296677
|
+
const { dir: dir2, entry } = await harvestBoard(odBase, odFetch, odPublic, os13.tmpdir(), st.boardKey, snapshotSourceRunId(st) ?? "status-pull");
|
|
296289
296678
|
println(`[design] \u5DF2\u62C9\u5230\u672C\u5730\uFF1A${dir2}\uFF08\u5165\u53E3 ${entry}\uFF09`);
|
|
296290
296679
|
println(`[design] \u8BFB\u5B8C\u6EE1\u610F\u5373\u4EA4\u7A3F\uFF1Aoasis propose ${artifactId} --from-dir ${dir2} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"`);
|
|
296291
|
-
} else {
|
|
296680
|
+
} else if (!lastFailed) {
|
|
296292
296681
|
println(`[design] \u53D6\u8D27\uFF1Aoasis design status ${artifactId} --pull\uFF08\u62C9\u5230\u672C\u5730\u76EE\u5F55\u8BFB\uFF0C\u8BFB\u5B8C propose --from-dir \u4EA4\u7A3F\uFF09`);
|
|
296293
296682
|
}
|
|
296294
296683
|
break;
|
|
296295
296684
|
}
|
|
296296
|
-
throw new Error("\u7528\u6CD5\uFF1Aoasis design chat <artifactId> --message <t> [--turn first|continue] [--async]\uFF1Boasis design status <artifactId> [--pull]");
|
|
296685
|
+
throw new Error("\u7528\u6CD5\uFF1Aoasis design chat <artifactId> --message <t> [--turn first|continue] [--async]\uFF1Boasis design status <artifactId> [--pull] [--wait [--wait-timeout <\u5206\u949F>]]");
|
|
296297
296686
|
}
|
|
296298
296687
|
case "merge": {
|
|
296299
296688
|
const artifactId = needPos(positional, 0, "oasis merge <artifactId> [revisionId]");
|
|
@@ -298390,7 +298779,7 @@ function shimScript() {
|
|
|
298390
298779
|
}
|
|
298391
298780
|
|
|
298392
298781
|
// src/index.ts
|
|
298393
|
-
var PKG_VERSION = true ? "2.2.
|
|
298782
|
+
var PKG_VERSION = true ? "2.2.86" : "dev";
|
|
298394
298783
|
var LOCAL_BIN = localBin();
|
|
298395
298784
|
var NPM_PREFIX = npmPrefix();
|
|
298396
298785
|
var INSTANCE = DEFAULT_INSTANCE;
|