@tea-agent/loop-agent 0.44.0-next.13 → 0.44.0-next.14
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/CHANGELOG.md +12 -0
- package/README.md +12 -12
- package/dist/adapters/loop-agent.js +34 -0
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +5 -5
- package/dist/cli/program.js +1 -4
- package/dist/commands/init-legacy-audit.js +330 -0
- package/dist/commands/init-upgrade.js +644 -104
- package/dist/commands/init.js +685 -330
- package/dist/commands/operator-guide.js +99 -0
- package/dist/commands/operator.js +16 -3
- package/dist/executors/pi-sdk-executor.js +3 -1
- package/dist/governance/harness.js +2 -7
- package/dist/governance/manifest-types.js +28 -9
- package/dist/governance/project-capability-scanner.js +263 -0
- package/dist/governance/project-config.js +96 -0
- package/dist/governance/resource-catalog.js +151 -0
- package/dist/infrastructure/console/app-data.js +6 -2
- package/dist/shared/operator/capabilities.js +2 -2
- package/dist/shared/package-metadata.js +23 -7
- package/dist/shared/pi-context-pressure/extension.js +23 -0
- package/dist/shared/pi-context-pressure/index.js +1 -0
- package/dist/shared/pi-context-pressure/telemetry.js +4 -0
- package/dist/shared/pi-context-pressure/tool-result-pruner.js +98 -0
- package/dist/shared/update/npm-client.js +49 -1
- package/dist/worker/cli.js +3 -5
- package/dist/worker/console/chat/browser-automation.js +114 -5
- package/dist/worker/console/chat/browser-routes.js +21 -0
- package/dist/worker/console/chat/chat-event-store.js +7 -6
- package/dist/worker/console/chat/context-insights.js +84 -19
- package/dist/worker/console/chat/pet/pet-affinity.js +169 -0
- package/dist/worker/console/chat/pet/pet-persist.js +109 -0
- package/dist/worker/console/chat/pet/pet-registry.js +142 -0
- package/dist/worker/console/chat/pet/pet-remarks.js +48 -0
- package/dist/worker/console/chat/pet/pet-routes.js +125 -0
- package/dist/worker/console/chat/pet/pet-service.js +262 -0
- package/dist/worker/console/chat/pet/pet-state.js +99 -0
- package/dist/worker/console/chat/pi-mode-loop-isolation.js +17 -2
- package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +2 -2
- package/dist/worker/console/chat/pi-runtime.js +7 -2
- package/dist/worker/console/chat/routes.js +43 -7
- package/dist/worker/console/chat/scheduled-goal-request.js +14 -6
- package/dist/worker/console/chat/session-store.js +20 -3
- package/dist/worker/console/console-shutdown.js +34 -0
- package/dist/worker/console/server.js +2 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BA7qCL_r.js → abnfDiagram-N423BO3Z-DASc69AM.js} +1 -1
- package/dist/worker/console/static/assets/{arc-Df09ajwL.js → arc-h09p-LAc.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CpF9sw5R.js → architectureDiagram-T3A2C74G-CZ3dtLkh.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-BtPys8ja.js → blockDiagram-VBNYF7ZC-DMrRhMXG.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DZPnTWqT.js → c4Diagram-5PPSVZJV-DQxisHV6.js} +1 -1
- package/dist/worker/console/static/assets/channel-D1zgKZfg.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-BD9D4h1p.js → chunk-2GRJ4B5K-CefVN9zh.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-Svn8yBmn.js → chunk-2Q5K7J3B-DmR1Koq2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-B8EbQj-S.js → chunk-5RXB4S5H-NlzrSW7L.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-tENZpcpF.js → chunk-5VM5RSS4-DfelJv-0.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DBx71Lco.js → chunk-6Q2QTUOP-BK6RFy58.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-1v_QamMz.js → chunk-GF5L2VYU-BAeh9lz4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BAMCNNBG.js → chunk-JWPE2WC7-ChPS5WzG.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BvuEury-.js → chunk-KBJHAD2P-BoVe5IM6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-YqFuHp8s.js → chunk-RYQCIY6F-C4q_0Lw9.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-ouI5T7Mr.js → chunk-XXDRQBXY-Bb9TvjeY.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CXNNsY2M.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CXNNsY2M.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-Bri0_Izk.js → cose-bilkent-JH36ORCC-DmNnL8Ff.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-e8Vhhi4X.js → cynefin-VYW2F7L2-Contvx58.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-tSIXGQiJ.js → cynefinDiagram-MW4NZA55-Cigq7cjk.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Rl-sF5pt.js → dagre-VZM6K2ZE-dEbC0nxb.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Db6ddPz8.js → diagram-7IWD3JNH-CzIztESV.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Jwd_Xw5S.js → diagram-B4RE2ZJO-Bo14zbaY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CeC_8InC.js → diagram-LBJQPF4R-C4xUyil6.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-LKPRaNq8.js → diagram-Q27KOJAE-CaBY_uYa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-DlVQytMW.js → diagram-UB23O5K3-ClUXUeiu.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DnfJZwO-.js → ebnfDiagram-BXEA7PRR-BbGCgjC6.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-3axVSXca.js → erDiagram-JOGREHBK-Dr-AcwSl.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-xe04-_L-.js → flowDiagram-UKHOOZJN-BG8Gcfyc.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-hpmRINiD.js → ganttDiagram-PKOTCBZU-CFVaPs5r.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-6HSNz9Ko.js → gitGraphDiagram-DS77QQ5N-ChJ8pm-O.js} +1 -1
- package/dist/worker/console/static/assets/index-B_5GhVIO.js +488 -0
- package/dist/worker/console/static/assets/index-C7YMBluX.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BF6ksWTX.js → infoDiagram-6WML65LV-C5J9-uCZ.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DXisdeD7.js → ishikawaDiagram-WSZJBQD7-BcfjqzDv.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BWu65wmu.js → journeyDiagram-NVQOT4AX-BzzCO-rD.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-hfNhHqAI.js → kanban-definition-27J2QSJJ-NCHUZ46h.js} +1 -1
- package/dist/worker/console/static/assets/{linear-D6HTfQcp.js → linear-BKZlWCUU.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Iv91R1WP.js → mermaid.core-DbTaQjFE.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CfPChwjR.js → mindmap-definition-FAOFIHXS-CroYl5xQ.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-B7TcoqHz.js → pegDiagram-VL7TDLO6-DgMBx-9k.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-ouyPKMtQ.js → pieDiagram-7S7Q4E2Y-CyWDmbq1.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-B9tuyLbh.js → quadrantDiagram-CIZ2JOQS-BgGEOqSP.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Ck4q9nJs.js → railroadDiagram-AXF67PYL-BMZ7oeeV.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-wXLX5Dnp.js → requirementDiagram-LRYGKXZP-DxqyGhcc.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-D2XWw6_m.js → sankeyDiagram-W5VNT64P-DnSvNCG8.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DzxKiug4.js → sequenceDiagram-SI44F4Z6-BiZh6f-R.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DWUqK5Us.js → sizeCapture-X5ZJPWSS-BKXSI8WB.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-D5Pa4O5g.js → stateDiagram-OKZ733FA-CfSgoYFm.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DgHi3vjb.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-VH7cRnsJ.js → swimlanes-SLNWSIFB-CyGADcHe.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bgvdt1Y0.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-C4HM5NoZ.js → timeline-definition-Z64GVDOM-HmPaSPOK.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-Bu-4hOlA.js → vennDiagram-T6HMQDX7-VA2VBbez.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CasFEvvl.js → wardleyDiagram-T6FBY63Y-BxjiBPZa.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-D-gpwPSA.js → xychartDiagram-ELKLHX3M--hUY-qFj.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static/pets/ember/pet.json +167 -0
- package/dist/worker/console/static/pets/ember/spritesheet.png +0 -0
- package/dist/worker/console/static-src/operator-chat/details-rail-surfaces.js +4 -3
- package/dist/worker/console/static-src/operator-chat/use-stat-dialog.js +95 -0
- package/dist/worker/console/workspace-context.js +14 -0
- package/dist/worker/console/workspace-initialization.js +25 -16
- package/dist/worker/delivery/package.js +4 -1
- package/dist/worker/observe/static/operator-chrome.js +1 -42
- package/dist/workflows/dag/backend-test-pytest-collection.js +4 -1
- package/dist/workflows/dag/final-verification.js +45 -10
- package/dist/workflows/dag/hybrid/sources.js +14 -14
- package/dist/workflows/dag/hybrid/templates/backend-test.js +5 -5
- package/dist/workflows/dag/hybrid/templates/frontend-test.js +4 -4
- package/dist/workflows/dag/hybrid/templates/kg-bootstrap.js +6 -6
- package/dist/workflows/dag/hybrid/templates/knowledge-sync.js +5 -5
- package/dist/workflows/dag/skill-instructions.js +102 -32
- package/dist/workflows/dag/skill-snapshot.js +3 -0
- package/dist/workflows/dag/skills.js +7 -7
- package/dist/workflows/dag/validate.js +2 -2
- package/dist/workflows/dag/workspace-checkpoint.js +13 -1
- package/docs/architecture/runtime-boundaries.md +28 -22
- package/docs/init-surface.manifest.json +43 -295
- package/docs/templates/agent-dag.base.json +9 -9
- package/docs/templates/agent-dag.final-verification.json +6 -6
- package/docs/templates/agent-dag.supervised-implementation.json +12 -12
- package/docs/templates/frontend-implementation-dag.json +2 -2
- package/docs/templates/frontend-test-dag.json +2 -2
- package/docs/templates/hybrid-dag.json +9 -9
- package/docs/templates/knowledge-sync-dag.json +8 -8
- package/package.json +6 -2
- package/resource-catalog.v1.json +1973 -0
- package/resources/agent-bridge/loop-agent/SKILL.md +40 -0
- package/resources/init-history/legacy-surface.v1.json +33 -0
- package/skills/init-update/SKILL.md +34 -0
- package/skills/init-update/agents/openai.yaml +6 -0
- package/dist/worker/console/static/assets/channel-DiTNLZUm.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DgL8aiyZ.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DgL8aiyZ.js +0 -1
- package/dist/worker/console/static/assets/index-C_8_gWal.css +0 -1
- package/dist/worker/console/static/assets/index-DybcVXCu.js +0 -488
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-C0QIbqO4.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BB9CzRHB.js +0 -8
|
@@ -70,7 +70,7 @@ export class WorkspaceInitializationService {
|
|
|
70
70
|
}
|
|
71
71
|
const surface = await this.jsonFile(".harness/init-surface.json");
|
|
72
72
|
const harness = await this.jsonFile("harness.json");
|
|
73
|
-
if (surface && (surface.schemaVersion
|
|
73
|
+
if (surface && (![1, 2].includes(Number(surface.schemaVersion)) || !surface.files || typeof surface.files !== "object" || Array.isArray(surface.files))) {
|
|
74
74
|
throw new Error("初始化记录不完整,请检查 .harness/init-surface.json");
|
|
75
75
|
}
|
|
76
76
|
if (!surface && !harness) {
|
|
@@ -83,10 +83,15 @@ export class WorkspaceInitializationService {
|
|
|
83
83
|
}
|
|
84
84
|
return snapshot;
|
|
85
85
|
}
|
|
86
|
-
const report = await this.command(["init", "check-update", "--json"], "check");
|
|
86
|
+
const report = await this.command(["init", "check-update", "--legacy-audit", "--json"], "check");
|
|
87
87
|
if (!["recorded", "inferred-baseline", "missing"].includes(String(report.surfaceState)) || typeof report.ok !== "boolean") {
|
|
88
88
|
throw new Error("初始化检查返回了未知状态");
|
|
89
89
|
}
|
|
90
|
+
const coreState = String(report.coreState);
|
|
91
|
+
const migrationState = String(report.migrationState);
|
|
92
|
+
if (!["ready", "blocked", "error"].includes(coreState) || !["clean", "retained", "review-required", "in-progress", "failed"].includes(migrationState)) {
|
|
93
|
+
throw new Error("初始化检查缺少核心或迁移状态");
|
|
94
|
+
}
|
|
90
95
|
const actions = entries(report.deterministicActions);
|
|
91
96
|
const merges = entries(report.modelMergeTasks);
|
|
92
97
|
const decisions = entries(report.humanDecisions);
|
|
@@ -98,17 +103,20 @@ export class WorkspaceInitializationService {
|
|
|
98
103
|
const detail = typeof item.reason === "string" ? item.reason : undefined;
|
|
99
104
|
const baseline = item.type === "bootstrap-surface";
|
|
100
105
|
const itemKind = baseline ? "confirmation" : kind;
|
|
106
|
+
const legacyCandidate = typeof item.candidateId === "string";
|
|
101
107
|
const reason = baseline ? "缺少可靠的初始化记录,不能直接判断哪些内容可覆盖。"
|
|
102
|
-
:
|
|
103
|
-
: kind === "
|
|
104
|
-
:
|
|
105
|
-
: /
|
|
106
|
-
: /
|
|
107
|
-
: "
|
|
108
|
+
: legacyCandidate ? "这是历史初始化候选,但当前证据不足以自动删除。"
|
|
109
|
+
: kind === "safe-update" ? "此项可由程序安全更新,保留项目自定义内容。"
|
|
110
|
+
: kind === "merge" ? "现有内容与新版初始化模板不同,需要保留项目配置后合并。"
|
|
111
|
+
: /not a directory/.test(detail ?? "") ? "这里需要一个目录,但当前路径被文件占用。"
|
|
112
|
+
: /removed.*local changes/.test(detail ?? "") ? "新版不再使用此文件,但它包含本地修改,需要决定保留还是删除。"
|
|
113
|
+
: /target path.*already exists/.test(detail ?? "") ? "迁移目标已有不同内容,需要确认两份文件如何保留。"
|
|
114
|
+
: "此项无法安全自动处理,请先核对检查详情,再确定处理方式。";
|
|
108
115
|
pendingItems.push({ path: item.path, kind: itemKind, reason,
|
|
109
116
|
nextStep: itemKind === "safe-update" ? "点击更新按钮即可处理。"
|
|
110
117
|
: itemKind === "merge" ? "可将下方处理说明交给智能体合并;只有需求冲突时才需你确认。"
|
|
111
|
-
: "
|
|
118
|
+
: legacyCandidate ? "在对话页手动调用 /skill:init-update;Skill 会解释证据并在需要时询问,不会直接删除文件。"
|
|
119
|
+
: "将处理说明交给智能体检查;需要取舍时确认方案,处理后重新检查。",
|
|
112
120
|
...(detail ? { detail } : {}) });
|
|
113
121
|
}
|
|
114
122
|
}
|
|
@@ -118,19 +126,20 @@ export class WorkspaceInitializationService {
|
|
|
118
126
|
reason: "当前模型配置或认证尚未就绪,更新文件不能解决此问题。",
|
|
119
127
|
nextStep: "检查模型定义及提供商认证,保留仍可用的模型配置,完成后重新检查。" });
|
|
120
128
|
const canUpdate = pendingItems.some(item => item.kind === "safe-update");
|
|
121
|
-
const needsAttention = pendingItems.some(item => item.kind !== "safe-update") ||
|
|
129
|
+
const needsAttention = pendingItems.some(item => item.kind !== "safe-update") || coreState !== "ready" || migrationState === "review-required" || migrationState === "failed" || report.surfaceState !== "recorded" && !canUpdate;
|
|
122
130
|
if (needsAttention || canUpdate) {
|
|
123
131
|
const safeCount = pendingItems.filter(item => item.kind === "safe-update").length;
|
|
132
|
+
const coreReadyPrefix = coreState === "ready" ? "核心初始化已就绪;" : "";
|
|
124
133
|
const message = canUpdate
|
|
125
|
-
?
|
|
126
|
-
:
|
|
134
|
+
? `${coreReadyPrefix}有 ${safeCount} 项可在此安全更新。${needsAttention ? "其余旧初始化待处理项见下方。" : "更新会保留项目自定义内容。"}`
|
|
135
|
+
: `${coreReadyPrefix}暂无可直接更新的内容。请按下方原因处理,完成后重新检查。`;
|
|
127
136
|
if (!pendingItems.length)
|
|
128
137
|
pendingItems.push({ path: "初始化配置", kind: "confirmation",
|
|
129
138
|
reason: "检查尚未通过,但没有返回可自动更新的项目。",
|
|
130
139
|
nextStep: "复制处理说明交给智能体检查初始化记录,完成后重新检查。" });
|
|
131
|
-
return { ...this.snapshot(needsAttention ? "needs-attention" : "update-available", message, [...new Set(pendingItems.map(item => item.path))]), canUpdate, pendingItems };
|
|
140
|
+
return { ...this.snapshot(needsAttention ? "needs-attention" : "update-available", message, [...new Set(pendingItems.map(item => item.path))]), canUpdate, pendingItems, coreState: coreState, migrationState: migrationState };
|
|
132
141
|
}
|
|
133
|
-
return this.snapshot("ready", "工作区配置已就绪");
|
|
142
|
+
return { ...this.snapshot("ready", migrationState === "retained" ? "核心初始化已就绪;旧初始化内容已按决定保留。" : "工作区配置已就绪"), coreState: coreState, migrationState: migrationState };
|
|
134
143
|
}
|
|
135
144
|
catch (error) {
|
|
136
145
|
return this.snapshot("error", error instanceof Error ? error.message : "初始化状态检查失败");
|
|
@@ -182,10 +191,10 @@ export class WorkspaceInitializationService {
|
|
|
182
191
|
if (before.state === "uninitialized") {
|
|
183
192
|
if (!model || !before.models?.some(item => item.reference === model))
|
|
184
193
|
throw new Error("请选择一个可用的初始模型;可在模型设置中完成认证后重新检查");
|
|
185
|
-
await this.command(["init", "--
|
|
194
|
+
await this.command(["init", "--merge", "--model", model, "--json"], "apply");
|
|
186
195
|
}
|
|
187
196
|
else if (before.canUpdate) {
|
|
188
|
-
await this.command(["init", "update", "--apply-safe", "--
|
|
197
|
+
await this.command(["init", "update", "--apply-safe", "--legacy-audit", "--json"], "apply");
|
|
189
198
|
}
|
|
190
199
|
else if (before.state !== "ready")
|
|
191
200
|
throw new Error("没有可安全更新的内容;请查看待处理项的原因和下一步。");
|
|
@@ -48,12 +48,15 @@ const controllerIdentityEvidenceSchema = z.object({
|
|
|
48
48
|
reportedVersion: z.string().min(1).optional(),
|
|
49
49
|
packageFingerprint: z.object({
|
|
50
50
|
algorithm: z.literal("sha256"),
|
|
51
|
-
scopeVersion: z.literal(
|
|
51
|
+
scopeVersion: z.literal(2),
|
|
52
52
|
scope: z.tuple([
|
|
53
53
|
z.literal("package.json"),
|
|
54
54
|
z.literal("bin/**"),
|
|
55
55
|
z.literal("dist/**"),
|
|
56
56
|
z.literal("skills/**"),
|
|
57
|
+
z.literal("docs/templates/**"),
|
|
58
|
+
z.literal("resources/**"),
|
|
59
|
+
z.literal("resource-catalog.v1.json"),
|
|
57
60
|
]),
|
|
58
61
|
value: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
59
62
|
fileCount: z.number().int().positive(),
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { withWorkspaceQuery } from "./router.js";
|
|
15
|
-
import {
|
|
16
|
-
export { CONSOLE_THEMES } from "./console-theme.js";
|
|
15
|
+
import { applyStoredConsoleTheme } from "./console-theme.js";
|
|
17
16
|
|
|
18
17
|
export const OPERATE_TABS = Object.freeze([
|
|
19
18
|
{ id: "tasks", label: "任务", href: "/#/operate/tasks" },
|
|
@@ -711,46 +710,6 @@ export function mountOperatorChrome(root, config = {}) {
|
|
|
711
710
|
|
|
712
711
|
global.appendChild(el("span", "och-spacer"));
|
|
713
712
|
|
|
714
|
-
const themePicker = el("div", "och-theme");
|
|
715
|
-
const trigger = el("button", "och-theme-trigger");
|
|
716
|
-
trigger.type = "button";
|
|
717
|
-
trigger.title = "主题";
|
|
718
|
-
trigger.setAttribute("aria-label", "主题");
|
|
719
|
-
trigger.appendChild(makeIcon("theme"));
|
|
720
|
-
trigger.setAttribute("aria-expanded", "false");
|
|
721
|
-
const menu = el("div", "och-theme-menu");
|
|
722
|
-
menu.id = `${popoverId}-theme`;
|
|
723
|
-
menu.popover = "auto";
|
|
724
|
-
menu.setAttribute("role", "group");
|
|
725
|
-
menu.setAttribute("aria-label", "选择主题");
|
|
726
|
-
trigger.setAttribute("aria-controls", menu.id);
|
|
727
|
-
trigger.popoverTargetElement = menu;
|
|
728
|
-
menu.addEventListener("beforetoggle", (event) => {
|
|
729
|
-
if (event.newState !== "open") return;
|
|
730
|
-
const rect = trigger.getBoundingClientRect();
|
|
731
|
-
menu.style.top = `${rect.bottom + 6}px`;
|
|
732
|
-
menu.style.left = `${Math.max(8, Math.min(rect.right - 112, window.innerWidth - 120))}px`;
|
|
733
|
-
});
|
|
734
|
-
menu.addEventListener("toggle", (event) => {
|
|
735
|
-
trigger.setAttribute("aria-expanded", String(event.newState === "open"));
|
|
736
|
-
});
|
|
737
|
-
for (const theme of CONSOLE_THEMES) {
|
|
738
|
-
const option = el("button", "och-theme-option", theme.label);
|
|
739
|
-
option.type = "button";
|
|
740
|
-
option.dataset.theme = theme.id;
|
|
741
|
-
option.setAttribute("aria-pressed", String(theme.id === (document.documentElement.dataset.consoleTheme ?? "default")));
|
|
742
|
-
option.addEventListener("click", () => {
|
|
743
|
-
setConsoleTheme(theme.id);
|
|
744
|
-
for (const item of menu.children) {
|
|
745
|
-
item.setAttribute("aria-pressed", String(item.dataset.theme === theme.id));
|
|
746
|
-
}
|
|
747
|
-
menu.hidePopover();
|
|
748
|
-
trigger.focus();
|
|
749
|
-
});
|
|
750
|
-
menu.appendChild(option);
|
|
751
|
-
}
|
|
752
|
-
themePicker.append(trigger, menu);
|
|
753
|
-
global.appendChild(themePicker);
|
|
754
713
|
|
|
755
714
|
if (model.statusVisible && model.freshness) {
|
|
756
715
|
const fresh = el("span", "och-fresh");
|
|
@@ -422,7 +422,10 @@ function classifyCollectionFailure(output, evidence) {
|
|
|
422
422
|
const blockedPatterns = [
|
|
423
423
|
[/No module named ['\"](?!testcase(?:\.|['\"]))/i, "missing-third-party-module"],
|
|
424
424
|
[/pytest(?:_|-)plugin|pluggy|unknown hook|unrecognized arguments/i, "pytest-plugin-or-config"],
|
|
425
|
-
|
|
425
|
+
// Windows Python installs live under ...\WindowsApps\...; after slash
|
|
426
|
+
// normalization that path suffix must not read as an `apps/…py`
|
|
427
|
+
// production import (pytest >= 9 includes the importlib bootstrap frame).
|
|
428
|
+
[/(?<!Windows)(?:apps|src|server|api)\/[A-Za-z0-9_./-]+\.py/i, "production-module-import"],
|
|
426
429
|
[/permission denied|access is denied|timed? out|not recognized as an internal|no such file or directory.*python/i, "environment-or-spawn"],
|
|
427
430
|
];
|
|
428
431
|
for (const [pattern, kind] of blockedPatterns) {
|
|
@@ -3,7 +3,8 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { DEFAULT_DAG_EXECUTOR_MODELS } from './types.js';
|
|
5
5
|
import { parseDagSpec } from './types.js';
|
|
6
|
-
import {
|
|
6
|
+
import { ProjectCapabilityScanner } from '../../governance/project-capability-scanner.js';
|
|
7
|
+
import { loadNormalizedProjectConfig } from '../../governance/project-config.js';
|
|
7
8
|
import { loadTaskConfig } from '../../task/runtime.js';
|
|
8
9
|
import { resolveCliPath } from '../../shared/path-refs.js';
|
|
9
10
|
const DEFAULT_OUTPUT_DIR = os.tmpdir();
|
|
@@ -22,14 +23,13 @@ export async function initFinalVerificationDagFromTask(repoRoot, taskId, options
|
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
25
|
export async function buildFinalVerificationDagFromTask(repoRoot, taskId, options = {}) {
|
|
25
|
-
const
|
|
26
|
-
loadTaskConfig(repoRoot, taskId),
|
|
27
|
-
loadHarnessManifest(repoRoot),
|
|
28
|
-
]);
|
|
26
|
+
const taskConfig = await loadTaskConfig(repoRoot, taskId);
|
|
29
27
|
const taskGlob = options.taskGlob ?? taskId;
|
|
30
28
|
const closeoutPath = options.closeoutPath ?? path.join(os.tmpdir(), `${taskId}-closeout-report.md`);
|
|
31
|
-
const
|
|
32
|
-
|
|
29
|
+
const finalVerifyCommands = await resolveFinalVerificationCommands({
|
|
30
|
+
repoRoot,
|
|
31
|
+
taskCommands: taskConfig.verifyCommands.map((entry) => entry.command),
|
|
32
|
+
});
|
|
33
33
|
const hasChangesetSignal = taskDeclaresReleaseImpact(taskConfig);
|
|
34
34
|
const tasks = [
|
|
35
35
|
shellTask({
|
|
@@ -142,12 +142,12 @@ export async function buildFinalVerificationDagFromTask(repoRoot, taskId, option
|
|
|
142
142
|
executor: 'shell',
|
|
143
143
|
contextProfile: 'slim',
|
|
144
144
|
writePolicy: 'read-only',
|
|
145
|
-
skills: ['ai-engineering-context'],
|
|
145
|
+
skills: ['builtin:ai-engineering-context'],
|
|
146
146
|
},
|
|
147
147
|
executorModels: DEFAULT_DAG_EXECUTOR_MODELS,
|
|
148
148
|
skillsByRole: {
|
|
149
|
-
verifier: ['verification-before-completion'],
|
|
150
|
-
closeout: ['loop-agent', 'verification-before-completion'],
|
|
149
|
+
verifier: ['builtin:verification-before-completion'],
|
|
150
|
+
closeout: ['builtin:loop-agent', 'builtin:verification-before-completion'],
|
|
151
151
|
},
|
|
152
152
|
tasks,
|
|
153
153
|
});
|
|
@@ -178,3 +178,38 @@ function taskDeclaresReleaseImpact(taskConfig) {
|
|
|
178
178
|
].join('\n');
|
|
179
179
|
return /changeset|release|publish|version/i.test(haystack);
|
|
180
180
|
}
|
|
181
|
+
export async function resolveFinalVerificationCommandSelection(input) {
|
|
182
|
+
if (input.taskCommands.length > 0) {
|
|
183
|
+
return {
|
|
184
|
+
source: 'task-contract',
|
|
185
|
+
commands: [...new Set(input.taskCommands)],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const verification = (await loadNormalizedProjectConfig(input.repoRoot)).verification;
|
|
189
|
+
const configured = verification.full.length > 0
|
|
190
|
+
? verification.full
|
|
191
|
+
: verification.standard.length > 0
|
|
192
|
+
? verification.standard
|
|
193
|
+
: verification.quick;
|
|
194
|
+
if (configured.length > 0) {
|
|
195
|
+
return {
|
|
196
|
+
source: 'project-config',
|
|
197
|
+
commands: [...new Set(configured)],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const scan = await new ProjectCapabilityScanner().scan(input.repoRoot);
|
|
201
|
+
const selected = scan.verification.commands.find((candidate) => candidate.id.endsWith(':test'))
|
|
202
|
+
?? scan.verification.commands.find((candidate) => candidate.id.endsWith(':typecheck'))
|
|
203
|
+
?? scan.verification.commands.find((candidate) => candidate.id.endsWith(':lint'))
|
|
204
|
+
?? scan.verification.commands[0];
|
|
205
|
+
if (scan.verification.status !== 'ready' || !selected) {
|
|
206
|
+
throw new Error(`final verification is ${scan.verification.status}; add Task Contract verification or .loop-agent/project.json verification`);
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
source: 'capability-scanner',
|
|
210
|
+
commands: [selected.command],
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async function resolveFinalVerificationCommands(input) {
|
|
214
|
+
return (await resolveFinalVerificationCommandSelection(input)).commands;
|
|
215
|
+
}
|
|
@@ -32,16 +32,16 @@ export const HYBRID_DEFAULTS = {
|
|
|
32
32
|
executor: "pi",
|
|
33
33
|
piBackend: "sdk-first",
|
|
34
34
|
contextProfile: "slim",
|
|
35
|
-
skills: ["ai-engineering-context"],
|
|
35
|
+
skills: ["builtin:ai-engineering-context"],
|
|
36
36
|
writePolicy: "read-only",
|
|
37
37
|
};
|
|
38
38
|
export const HYBRID_SKILLS_BY_ROLE = {
|
|
39
|
-
planner: ["loop-agent"],
|
|
40
|
-
scout: ["ai-engineering-context", "codebase-scout"],
|
|
41
|
-
implementer: ["test-driven-development", "verification-before-completion"],
|
|
42
|
-
reviewer: ["requesting-code-review", "code-review-core"],
|
|
43
|
-
verifier: ["verification-before-completion", "systematic-debugging"],
|
|
44
|
-
closeout: ["loop-agent", "verification-before-completion"],
|
|
39
|
+
planner: ["builtin:loop-agent"],
|
|
40
|
+
scout: ["builtin:ai-engineering-context", "builtin:codebase-scout"],
|
|
41
|
+
implementer: ["builtin:test-driven-development", "builtin:verification-before-completion"],
|
|
42
|
+
reviewer: ["builtin:requesting-code-review", "builtin:code-review-core"],
|
|
43
|
+
verifier: ["builtin:verification-before-completion", "builtin:systematic-debugging"],
|
|
44
|
+
closeout: ["builtin:loop-agent", "builtin:verification-before-completion"],
|
|
45
45
|
};
|
|
46
46
|
export const FRONTEND_DEFAULTS = {
|
|
47
47
|
...HYBRID_DEFAULTS,
|
|
@@ -56,13 +56,13 @@ export const FRONTEND_SKILLS_BY_ROLE = {
|
|
|
56
56
|
verifier: [],
|
|
57
57
|
closeout: [],
|
|
58
58
|
};
|
|
59
|
-
export const FRONTEND_CONTRACT_SKILLS = ["frontend-contract"];
|
|
60
|
-
export const FRONTEND_SCOUT_SKILLS = ["frontend-scout"];
|
|
61
|
-
export const FRONTEND_PLAN_SKILLS = ["frontend-plan"];
|
|
62
|
-
export const FRONTEND_BOUNDED_IMPLEMENT_SKILLS = ["frontend-bounded-implement"];
|
|
63
|
-
export const FRONTEND_DESIGN_REVIEW_SKILLS = ["frontend-design-review"];
|
|
64
|
-
export const FRONTEND_REVIEW_SKILLS = ["frontend-review"];
|
|
65
|
-
export const FRONTEND_VERIFICATION_SKILLS = ["frontend-verification"];
|
|
59
|
+
export const FRONTEND_CONTRACT_SKILLS = ["builtin:frontend-contract"];
|
|
60
|
+
export const FRONTEND_SCOUT_SKILLS = ["builtin:frontend-scout"];
|
|
61
|
+
export const FRONTEND_PLAN_SKILLS = ["builtin:frontend-plan"];
|
|
62
|
+
export const FRONTEND_BOUNDED_IMPLEMENT_SKILLS = ["builtin:frontend-bounded-implement"];
|
|
63
|
+
export const FRONTEND_DESIGN_REVIEW_SKILLS = ["builtin:frontend-design-review"];
|
|
64
|
+
export const FRONTEND_REVIEW_SKILLS = ["builtin:frontend-review"];
|
|
65
|
+
export const FRONTEND_VERIFICATION_SKILLS = ["builtin:frontend-verification"];
|
|
66
66
|
export const IMPLEMENT_WRITESET_PLACEHOLDER = "REPLACE/WITH/NARROW/IMPLEMENT/PATHS/**";
|
|
67
67
|
export const GENERATED_DAG_RUNTIME_CONTRACT = {
|
|
68
68
|
schemaVersion: DAG_RUNTIME_CONTRACT_SCHEMA_VERSION,
|
|
@@ -1787,12 +1787,12 @@ export const BACKEND_TEST_DEFAULTS = {
|
|
|
1787
1787
|
writePolicy: "read-only",
|
|
1788
1788
|
};
|
|
1789
1789
|
export const BACKEND_TEST_SKILLS_BY_ROLE = {
|
|
1790
|
-
planner: ["loop-agent"],
|
|
1790
|
+
planner: ["builtin:loop-agent"],
|
|
1791
1791
|
scout: [],
|
|
1792
|
-
implementer: ["test-driven-development", "verification-before-completion"],
|
|
1793
|
-
reviewer: ["requesting-code-review", "code-review-core"],
|
|
1794
|
-
verifier: ["verification-before-completion", "systematic-debugging"],
|
|
1795
|
-
closeout: ["loop-agent", "verification-before-completion"],
|
|
1792
|
+
implementer: ["builtin:test-driven-development", "builtin:verification-before-completion"],
|
|
1793
|
+
reviewer: ["builtin:requesting-code-review", "builtin:code-review-core"],
|
|
1794
|
+
verifier: ["builtin:verification-before-completion", "builtin:systematic-debugging"],
|
|
1795
|
+
closeout: ["builtin:loop-agent", "builtin:verification-before-completion"],
|
|
1796
1796
|
};
|
|
1797
1797
|
export function applyBackendTestWorkspaceControl(spec, control, layoutTestRoot, controlExplicit = false) {
|
|
1798
1798
|
// D4: the canonical `.harness/testcase` root is Git-ignored, so a Git-status
|
|
@@ -640,11 +640,11 @@ export function buildFrontendTestHybridDag(sources) {
|
|
|
640
640
|
},
|
|
641
641
|
skillsByRole: {
|
|
642
642
|
planner: [],
|
|
643
|
-
scout: ["playwright-cli"],
|
|
644
|
-
implementer: ["playwright-cli"],
|
|
643
|
+
scout: ["builtin:playwright-cli"],
|
|
644
|
+
implementer: ["builtin:playwright-cli"],
|
|
645
645
|
reviewer: [],
|
|
646
|
-
verifier: ["playwright-cli"],
|
|
647
|
-
closeout: ["verification-before-completion"],
|
|
646
|
+
verifier: ["builtin:playwright-cli"],
|
|
647
|
+
closeout: ["builtin:verification-before-completion"],
|
|
648
648
|
},
|
|
649
649
|
executorModels: sources.executorModelMatrix ?? DEFAULT_DAG_EXECUTOR_MODELS,
|
|
650
650
|
verifyStrategy: resolveDagVerifyStrategy(sources.taskConfig),
|
|
@@ -8,12 +8,12 @@ export const KG_BOOTSTRAP_DEFAULTS = {
|
|
|
8
8
|
writePolicy: "read-only",
|
|
9
9
|
};
|
|
10
10
|
export const KG_BOOTSTRAP_SKILLS_BY_ROLE = {
|
|
11
|
-
planner: ["loop-agent"],
|
|
12
|
-
scout: ["codebase-scout"],
|
|
13
|
-
implementer: ["verification-before-completion"],
|
|
14
|
-
reviewer: ["requesting-code-review"],
|
|
15
|
-
verifier: ["verification-before-completion", "systematic-debugging"],
|
|
16
|
-
closeout: ["loop-agent", "verification-before-completion"],
|
|
11
|
+
planner: ["builtin:loop-agent"],
|
|
12
|
+
scout: ["builtin:codebase-scout"],
|
|
13
|
+
implementer: ["builtin:verification-before-completion"],
|
|
14
|
+
reviewer: ["builtin:requesting-code-review"],
|
|
15
|
+
verifier: ["builtin:verification-before-completion", "builtin:systematic-debugging"],
|
|
16
|
+
closeout: ["builtin:loop-agent", "builtin:verification-before-completion"],
|
|
17
17
|
};
|
|
18
18
|
export function buildKgBootstrapInlineNodeScript(lines) {
|
|
19
19
|
return ["node", "-e", JSON.stringify(lines.join(""))].join(" ");
|
|
@@ -7,12 +7,12 @@ export const KNOWLEDGE_SYNC_DEFAULTS = {
|
|
|
7
7
|
writePolicy: "read-only",
|
|
8
8
|
};
|
|
9
9
|
export const KNOWLEDGE_SYNC_SKILLS_BY_ROLE = {
|
|
10
|
-
planner: ["loop-agent"],
|
|
10
|
+
planner: ["builtin:loop-agent"],
|
|
11
11
|
scout: [],
|
|
12
|
-
implementer: ["verification-before-completion"],
|
|
13
|
-
reviewer: ["requesting-code-review"],
|
|
14
|
-
verifier: ["verification-before-completion", "systematic-debugging"],
|
|
15
|
-
closeout: ["loop-agent", "verification-before-completion"],
|
|
12
|
+
implementer: ["builtin:verification-before-completion"],
|
|
13
|
+
reviewer: ["builtin:requesting-code-review"],
|
|
14
|
+
verifier: ["builtin:verification-before-completion", "builtin:systematic-debugging"],
|
|
15
|
+
closeout: ["builtin:loop-agent", "builtin:verification-before-completion"],
|
|
16
16
|
};
|
|
17
17
|
export function buildMultiPerspectiveReviewAggregateScript(fromNodeIds, label) {
|
|
18
18
|
if (fromNodeIds.length === 0) {
|
|
@@ -3,9 +3,20 @@ import { access, readFile } from "node:fs/promises";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { builtinSkillReferenceResourceId, builtinSkillResourceId, createControllerContextProvider, } from "../../governance/resource-catalog.js";
|
|
6
7
|
export const DEFAULT_SKILL_INSTRUCTION_MAX_CHARS = 3_000;
|
|
7
8
|
export const DEFAULT_SKILL_INSTRUCTION_TOTAL_MAX_CHARS = 12_000;
|
|
8
9
|
const SKILL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
10
|
+
const SKILL_REFERENCE_PATTERN = /^(?:(builtin|project|user):)?([A-Za-z0-9][A-Za-z0-9_-]*)$/;
|
|
11
|
+
function parseSkillReference(reference) {
|
|
12
|
+
const match = SKILL_REFERENCE_PATTERN.exec(reference);
|
|
13
|
+
if (!match)
|
|
14
|
+
return undefined;
|
|
15
|
+
return {
|
|
16
|
+
...(match[1] ? { source: match[1] } : {}),
|
|
17
|
+
name: match[2],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
9
20
|
async function fileExists(filePath) {
|
|
10
21
|
try {
|
|
11
22
|
await access(filePath);
|
|
@@ -35,22 +46,26 @@ function bundledSkillCandidatePaths(name) {
|
|
|
35
46
|
}
|
|
36
47
|
function buildSkillCandidatePaths(input) {
|
|
37
48
|
const candidates = [];
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
if (!input.source || input.source === "user") {
|
|
50
|
+
const agentDir = input.env.PI_CODING_AGENT_DIR;
|
|
51
|
+
if (agentDir) {
|
|
52
|
+
candidates.push(normalizeCandidate(path.join(agentDir, "skills", input.name, "SKILL.md")), normalizeCandidate(path.join(agentDir, "skills", `${input.name}.md`)));
|
|
53
|
+
}
|
|
54
|
+
const piSkillsDir = path.join(input.homeDir, ".pi", "agent", "skills");
|
|
55
|
+
candidates.push(normalizeCandidate(path.join(piSkillsDir, input.name, "SKILL.md")), normalizeCandidate(path.join(piSkillsDir, `${input.name}.md`)));
|
|
41
56
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
if (!input.source || input.source === "project") {
|
|
58
|
+
// Canonical target-project repo-local skill path.
|
|
59
|
+
candidates.push(normalizeCandidate(path.join(input.cwd, ".agents", "skills", input.name, "SKILL.md")));
|
|
60
|
+
// Legacy project-local Skill path. Explicit builtin references never consult it.
|
|
61
|
+
candidates.push(normalizeCandidate(path.join(input.cwd, "skills", input.name, "SKILL.md")));
|
|
62
|
+
if (input.name === "loop-agent") {
|
|
63
|
+
candidates.push(normalizeCandidate(path.join(input.cwd, "skill", "SKILL.md")));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!input.source || input.source === "builtin") {
|
|
67
|
+
candidates.push(...bundledSkillCandidatePaths(input.name));
|
|
52
68
|
}
|
|
53
|
-
candidates.push(...bundledSkillCandidatePaths(input.name));
|
|
54
69
|
return Array.from(new Set(candidates));
|
|
55
70
|
}
|
|
56
71
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
@@ -207,7 +222,7 @@ async function resolveSkillReferences(input) {
|
|
|
207
222
|
});
|
|
208
223
|
continue;
|
|
209
224
|
}
|
|
210
|
-
if (!(await fileExists(resolvedPath))) {
|
|
225
|
+
if (!input.packageSkill && !(await fileExists(resolvedPath))) {
|
|
211
226
|
unresolvedReferences.push({
|
|
212
227
|
name,
|
|
213
228
|
path: refPath,
|
|
@@ -216,7 +231,13 @@ async function resolveSkillReferences(input) {
|
|
|
216
231
|
continue;
|
|
217
232
|
}
|
|
218
233
|
try {
|
|
219
|
-
const
|
|
234
|
+
const packageResource = input.packageSkill
|
|
235
|
+
? await input.packageSkill.provider.readText(builtinSkillReferenceResourceId(input.packageSkill.name, refPath))
|
|
236
|
+
: undefined;
|
|
237
|
+
const content = packageResource?.text ?? await readFile(resolvedPath, "utf-8");
|
|
238
|
+
if (packageResource && path.resolve(packageResource.absolutePath) !== resolvedPath) {
|
|
239
|
+
throw new Error(`catalog path mismatch for ${refPath}`);
|
|
240
|
+
}
|
|
220
241
|
const contentSha256 = sha256(content);
|
|
221
242
|
const bytes = Buffer.byteLength(content, "utf-8");
|
|
222
243
|
const budget = Math.max(0, Math.min(declaration.maxChars ?? input.perReferenceMaxChars, remainingTotal));
|
|
@@ -224,7 +245,7 @@ async function resolveSkillReferences(input) {
|
|
|
224
245
|
input.resolvedReferencePaths.add(resolvedPath);
|
|
225
246
|
references.push({
|
|
226
247
|
name,
|
|
227
|
-
path: resolvedPath,
|
|
248
|
+
path: packageResource?.id ?? resolvedPath,
|
|
228
249
|
sha256: contentSha256,
|
|
229
250
|
bytes,
|
|
230
251
|
...(truncated ? { truncated: true } : {}),
|
|
@@ -232,7 +253,7 @@ async function resolveSkillReferences(input) {
|
|
|
232
253
|
remainingTotal = Math.max(0, remainingTotal - Math.min(content.length, budget));
|
|
233
254
|
sections.push([
|
|
234
255
|
`Reference: ${name}`,
|
|
235
|
-
|
|
256
|
+
`${packageResource ? "Resource" : "Path"}: ${packageResource?.id ?? resolvedPath}`,
|
|
236
257
|
`Sha256: ${contentSha256}`,
|
|
237
258
|
excerpt,
|
|
238
259
|
].join("\n"));
|
|
@@ -263,7 +284,7 @@ function buildResolvedPromptText(input) {
|
|
|
263
284
|
const lines = [
|
|
264
285
|
`Skill: ${input.name}`,
|
|
265
286
|
"Resolution: resolved",
|
|
266
|
-
|
|
287
|
+
`${input.locationKind}: ${input.location}`,
|
|
267
288
|
`Sha256: ${input.contentSha256}`,
|
|
268
289
|
"Injection mode: bounded-inline",
|
|
269
290
|
"Instructions:",
|
|
@@ -308,29 +329,62 @@ export async function resolveDagSkillInstructions(skills, options) {
|
|
|
308
329
|
let remainingTotal = options.totalMaxChars ?? DEFAULT_SKILL_INSTRUCTION_TOTAL_MAX_CHARS;
|
|
309
330
|
const resolved = [];
|
|
310
331
|
const resolvedReferencePaths = new Set();
|
|
332
|
+
let packageProvider;
|
|
311
333
|
for (const name of skills) {
|
|
312
|
-
|
|
334
|
+
const reference = parseSkillReference(name);
|
|
335
|
+
if (!reference || !SKILL_NAME_PATTERN.test(reference.name)) {
|
|
313
336
|
const error = `invalid skill name: ${name}`;
|
|
314
337
|
resolved.push({
|
|
315
338
|
name,
|
|
316
339
|
resolution: "error",
|
|
340
|
+
sourceKind: "auto",
|
|
317
341
|
error,
|
|
318
342
|
injectionMode: "name-only",
|
|
319
343
|
promptText: buildErrorPromptText({ name, error }),
|
|
320
344
|
});
|
|
321
345
|
continue;
|
|
322
346
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
347
|
+
let packageContent;
|
|
348
|
+
let filePath;
|
|
349
|
+
let searchedPaths = [];
|
|
350
|
+
if (reference.source === "builtin") {
|
|
351
|
+
const logicalResourceId = builtinSkillResourceId(reference.name);
|
|
352
|
+
try {
|
|
353
|
+
packageProvider ??= await createControllerContextProvider();
|
|
354
|
+
const resource = await packageProvider.readText(logicalResourceId);
|
|
355
|
+
filePath = resource.absolutePath;
|
|
356
|
+
packageContent = resource.text;
|
|
357
|
+
searchedPaths = [resource.absolutePath];
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
361
|
+
resolved.push({
|
|
362
|
+
name,
|
|
363
|
+
resolution: "error",
|
|
364
|
+
sourceKind: "builtin",
|
|
365
|
+
logicalResourceId,
|
|
366
|
+
error: message,
|
|
367
|
+
injectionMode: "name-only",
|
|
368
|
+
promptText: buildErrorPromptText({ name, error: message }),
|
|
369
|
+
});
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
searchedPaths = buildSkillCandidatePaths({
|
|
375
|
+
name: reference.name,
|
|
376
|
+
...(reference.source ? { source: reference.source } : {}),
|
|
377
|
+
cwd: options.cwd,
|
|
378
|
+
env,
|
|
379
|
+
homeDir,
|
|
380
|
+
});
|
|
381
|
+
filePath = await findFirstExistingFile(searchedPaths);
|
|
382
|
+
}
|
|
330
383
|
if (!filePath) {
|
|
331
384
|
resolved.push({
|
|
332
385
|
name,
|
|
333
386
|
resolution: "missing",
|
|
387
|
+
sourceKind: reference.source ?? "auto",
|
|
334
388
|
searchedPaths,
|
|
335
389
|
injectionMode: "name-only",
|
|
336
390
|
promptText: buildMissingPromptText({ name, searchedPaths }),
|
|
@@ -338,7 +392,7 @@ export async function resolveDagSkillInstructions(skills, options) {
|
|
|
338
392
|
continue;
|
|
339
393
|
}
|
|
340
394
|
try {
|
|
341
|
-
const content = await readFile(filePath, "utf-8");
|
|
395
|
+
const content = packageContent ?? await readFile(filePath, "utf-8");
|
|
342
396
|
const { frontmatter, body } = splitSkillFrontmatter(content);
|
|
343
397
|
const instructionContent = frontmatter ? body : content;
|
|
344
398
|
const referenceDeclarations = frontmatter
|
|
@@ -354,11 +408,17 @@ export async function resolveDagSkillInstructions(skills, options) {
|
|
|
354
408
|
remainingTotal,
|
|
355
409
|
perReferenceMaxChars: perSkillMaxChars,
|
|
356
410
|
resolvedReferencePaths,
|
|
411
|
+
...(reference.source === "builtin" && packageProvider
|
|
412
|
+
? { packageSkill: { name: reference.name, provider: packageProvider } }
|
|
413
|
+
: {}),
|
|
357
414
|
});
|
|
358
415
|
remainingTotal = afterReferences;
|
|
359
416
|
const { promptText, truncated } = buildResolvedPromptText({
|
|
360
417
|
name,
|
|
361
|
-
|
|
418
|
+
location: reference.source === "builtin"
|
|
419
|
+
? builtinSkillResourceId(reference.name)
|
|
420
|
+
: filePath,
|
|
421
|
+
locationKind: reference.source === "builtin" ? "Resource" : "Path",
|
|
362
422
|
content: instructionContent,
|
|
363
423
|
contentSha256,
|
|
364
424
|
bytes,
|
|
@@ -368,7 +428,13 @@ export async function resolveDagSkillInstructions(skills, options) {
|
|
|
368
428
|
resolved.push({
|
|
369
429
|
name,
|
|
370
430
|
resolution: "resolved",
|
|
371
|
-
|
|
431
|
+
sourceKind: reference.source ?? "auto",
|
|
432
|
+
...(reference.source === "builtin" && packageProvider
|
|
433
|
+
? {
|
|
434
|
+
logicalResourceId: builtinSkillResourceId(reference.name),
|
|
435
|
+
catalogDigest: packageProvider.identity.catalogDigest,
|
|
436
|
+
}
|
|
437
|
+
: { path: filePath }),
|
|
372
438
|
sha256: contentSha256,
|
|
373
439
|
bytes,
|
|
374
440
|
truncated,
|
|
@@ -385,14 +451,18 @@ export async function resolveDagSkillInstructions(skills, options) {
|
|
|
385
451
|
resolved.push({
|
|
386
452
|
name,
|
|
387
453
|
resolution: "error",
|
|
388
|
-
|
|
454
|
+
sourceKind: reference.source ?? "auto",
|
|
455
|
+
...(reference.source === "builtin"
|
|
456
|
+
? { logicalResourceId: builtinSkillResourceId(reference.name) }
|
|
457
|
+
: { path: filePath }),
|
|
389
458
|
error: message,
|
|
390
459
|
injectionMode: "name-only",
|
|
391
460
|
promptText: buildErrorPromptText({ name, error: message }),
|
|
392
461
|
});
|
|
393
462
|
}
|
|
394
463
|
}
|
|
395
|
-
if (options.includeLearnedPatterns
|
|
464
|
+
if (options.includeLearnedPatterns
|
|
465
|
+
&& skills.some((skill) => skill === "loop-agent" || skill === "builtin:loop-agent")) {
|
|
396
466
|
const learned = await resolveLearnedPatternInstructions({
|
|
397
467
|
cwd: options.cwd,
|
|
398
468
|
maxChars: Math.max(0, Math.min(perSkillMaxChars, remainingTotal)),
|