@tea-agent/loop-agent 0.38.3 → 0.38.4
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/AGENTS.md +4 -1
- package/CHANGELOG.md +153 -96
- package/README.md +9 -5
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +16 -5
- package/dist/cli/program.js +16 -2
- package/dist/cli/update/notifier.js +2 -2
- package/dist/cli.js +2 -1
- package/dist/commands/dag-rerun.js +55 -1
- package/dist/commands/init-model-catalog.js +464 -0
- package/dist/commands/init-upgrade.js +265 -97
- package/dist/commands/init.js +428 -27
- package/dist/commands/inspect-next.js +8 -0
- package/dist/executors/dag-pi-executor.js +18 -9
- package/dist/executors/pi-playwright-cli-tool.js +51 -12
- package/dist/executors/shell-executor.js +209 -13
- package/dist/shared/dag-prompt-override.js +28 -0
- package/dist/shared/operator/capabilities.js +32 -0
- package/dist/shared/playwright-cli-command-policy.js +15 -0
- package/dist/shared/update/console-notifier.js +100 -0
- package/dist/{cli → shared}/update/npm-client.js +41 -8
- package/dist/{cli → shared}/update/state.js +41 -13
- package/dist/task/source-prepare/parse-intent.js +24 -4
- package/dist/worker/cli.js +31 -1
- package/dist/worker/console/chat/routes.js +1 -0
- package/dist/worker/console/dag-execution-receipt.js +33 -0
- package/dist/worker/console/operator-actions.js +116 -0
- package/dist/worker/console/operator-user-error.js +2 -2
- package/dist/worker/console/routes.js +43 -2
- package/dist/worker/console/security.js +63 -9
- package/dist/worker/console/server.js +36 -5
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4kVYweA.js → abnfDiagram-N423BO3Z-gauhD9kD.js} +1 -1
- package/dist/worker/console/static/assets/{arc-Bj2M8iO5.js → arc-pm3c2Rsl.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CLlXe4-6.js → architectureDiagram-T3A2C74G-D_JAg3wH.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-psEp5xH0.js → blockDiagram-VBNYF7ZC-Dk7-ex52.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DeKcOCGJ.js → c4Diagram-5PPSVZJV-Uval9oRI.js} +1 -1
- package/dist/worker/console/static/assets/channel-CVrnUdZl.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-K0C744p1.js → chunk-2GRJ4B5K-BSYjHs-v.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-xbNw4J9-.js → chunk-2Q5K7J3B-KGUuBXI8.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLaSDUO.js → chunk-5RXB4S5H-JqAtxD9N.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CtiPlKel.js → chunk-5VM5RSS4-D6EJOVQK.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DZtolir7.js → chunk-6Q2QTUOP-B1JriSjm.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CPcdNeew.js → chunk-GF5L2VYU-D62b96Jd.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-NgHc6V37.js → chunk-JWPE2WC7-BsNKEC_r.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DQ_T-hg8.js → chunk-KBJHAD2P-B56v6-ZP.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DgLsxcVP.js → chunk-RYQCIY6F-D2KPnd8K.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-UrVoM9z1.js → chunk-XXDRQBXY-kzKSCaaL.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-aX91WTya.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-aX91WTya.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CLkYvTb3.js → cose-bilkent-JH36ORCC-C6N6KNJd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BwT_xKrE.js → cynefin-VYW2F7L2-DiyymT2D.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bi9tuzif.js → cynefinDiagram-MW4NZA55-BeKAXvf3.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BCIqkWBV.js → dagre-VZM6K2ZE-TkIdXfPF.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dip6l9_Z.js → diagram-7IWD3JNH-BFmSG3ks.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B-xkh_wK.js → diagram-B4RE2ZJO-DqpJT2Fs.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DZO0kTt_.js → diagram-LBJQPF4R-r5ATN43t.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D6ZplNbZ.js → diagram-Q27KOJAE-DEcSCMuR.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPekbhoS.js → diagram-UB23O5K3-VOvYRLVc.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BtmaJpK5.js → ebnfDiagram-BXEA7PRR-D7f4Cb1u.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-6DS0Xc44.js → erDiagram-JOGREHBK-ziUf3U0G.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CihnROSm.js → flowDiagram-UKHOOZJN-BoRdQ-1y.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CZC4zOE2.js → ganttDiagram-PKOTCBZU-B1-GncNm.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js → gitGraphDiagram-DS77QQ5N-CTW-ph8W.js} +1 -1
- package/dist/worker/console/static/assets/{index-Ya5FE7cD.css → index-C8rOIAJr.css} +1 -1
- package/dist/worker/console/static/assets/{index-DTZOKgAn.js → index-DEbyrEfW.js} +71 -71
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DlSl4BGx.js → infoDiagram-6WML65LV-BFA337tZ.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-snnzFl_U.js → ishikawaDiagram-WSZJBQD7-BtEujgRR.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BDE7qpMx.js → journeyDiagram-NVQOT4AX-C8ZwD2Jp.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CD2Ci04G.js → kanban-definition-27J2QSJJ-Ck-z8B11.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DdnapKIH.js → linear-CAyXjQjN.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BVjAT9b8.js → mermaid.core-CcWKn6tS.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-D0yJk-zA.js → mindmap-definition-FAOFIHXS-C2NuDO7E.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVo9tFP-.js → pegDiagram-VL7TDLO6-BFub3PDz.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DnOV-mZ_.js → pieDiagram-7S7Q4E2Y-BJx5THZ5.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CzUJo58i.js → quadrantDiagram-CIZ2JOQS-DhalkDWV.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Bvikrolh.js → railroadDiagram-AXF67PYL-CVcBM36o.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DtaSVCap.js → requirementDiagram-LRYGKXZP-D_vy4n0w.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C2c9A0wW.js → sankeyDiagram-W5VNT64P-DGYdJL1D.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DmXJcU7r.js → sequenceDiagram-SI44F4Z6-C1xJFg3k.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B4GUFW92.js → sizeCapture-X5ZJPWSS-D_Fc43df.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Dsad2MXf.js → stateDiagram-OKZ733FA-BhGbIjbu.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DUt1lyFL.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DGq48Fbi.js → swimlanes-SLNWSIFB-DVkNcO-V.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BM6SGr7j.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CSSi6OFf.js → timeline-definition-Z64GVDOM-BQU9ufV0.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BqyzPrWv.js → vennDiagram-T6HMQDX7-BCQhRmYB.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DlznVb6S.js → wardleyDiagram-T6FBY63Y-DWerOyHO.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CfBcgJ_K.js → xychartDiagram-ELKLHX3M-DxLeebQU.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
- package/dist/worker/loop-agent/loop-agent-client.js +7 -3
- package/dist/worker/observe/node-input.js +2 -0
- package/dist/worker/observe/node-process.js +377 -0
- package/dist/worker/observe/routes.js +36 -3
- package/dist/worker/observe/shell-handler-keys.js +34 -0
- package/dist/worker/observe/static/api.js +66 -0
- package/dist/worker/observe/static/constants.js +8 -1
- package/dist/worker/observe/static/format.js +23 -0
- package/dist/worker/observe/static/markdown-render.js +20 -1
- package/dist/worker/observe/static/operator-chrome.js +4 -0
- package/dist/worker/observe/static/state.js +11 -0
- package/dist/worker/observe/static/styles.css +73 -0
- package/dist/worker/observe/static/views/dag-inspector.js +561 -8
- package/dist/worker/observe/static/views/dag.js +8 -1
- package/dist/worker/observe/static/views/failures.js +5 -2
- package/dist/worker/observe/static/views/session-timeline.js +60 -4
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +20 -2
- package/dist/workflows/dag/failure-category.js +8 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +5 -1
- package/dist/workflows/dag/frontend-repair.js +14 -0
- package/dist/workflows/dag/frontend-risk.js +15 -2
- package/dist/workflows/dag/frontend-test-case-checklist.js +26 -2
- package/dist/workflows/dag/frontend-test-case-manifest.js +5 -0
- package/dist/workflows/dag/frontend-test-result-contract.js +151 -11
- package/dist/workflows/dag/frontend-verification-trace.js +29 -4
- package/dist/workflows/dag/init-hybrid.js +125 -24
- package/dist/workflows/dag/node-execution.js +20 -2
- package/dist/workflows/dag/rerun-plan.js +112 -0
- package/dist/workflows/dag/rerun-run.js +58 -6
- package/dist/workflows/dag/retry-policy.js +91 -0
- package/dist/workflows/dag/types.js +9 -1
- package/docs/init-surface.manifest.json +5 -0
- package/docs/operations/README.md +1 -1
- package/docs/templates/init-managed-agents.md +13 -3
- package/harness.json +2 -2
- package/package.json +5 -1
- package/scripts/next-info.mjs +356 -0
- package/scripts/next-publish-gate.mjs +238 -0
- package/scripts/release-source-binding.mjs +251 -0
- package/skills/fe-test-ui-scout/SKILL.md +65 -0
- package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
- package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
- package/skills/loop-agent/references/command-reference.md +11 -4
- package/skills/playwright-cli/SKILL.md +22 -0
- package/skills/playwright-cli-case-generator/SKILL.md +20 -1
- package/dist/worker/console/static/assets/channel-CPF4N7pf.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +0 -8
|
@@ -116,6 +116,7 @@ async function handleRecoveryCandidates(_req, res, ctx, url) {
|
|
|
116
116
|
}
|
|
117
117
|
async function handleSessionPing(req, res, ctx) {
|
|
118
118
|
const failure = evaluateMutationGate(req, {
|
|
119
|
+
cookieName: ctx.bootToken.cookieName,
|
|
119
120
|
bootToken: ctx.bootToken.value,
|
|
120
121
|
confirmationToken: ctx.bootToken.confirmationToken,
|
|
121
122
|
consoleOrigin: ctx.getConsoleOrigin(),
|
|
@@ -130,6 +131,16 @@ async function handleSessionPing(req, res, ctx) {
|
|
|
130
131
|
}
|
|
131
132
|
sendJson(res, 200, { ok: true, pong: true });
|
|
132
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Actions the inspect-scoped mutation token may dispatch. Deliberately
|
|
136
|
+
* minimal: the experimental prompt-override rerun tab needs plan preflight +
|
|
137
|
+
* execution only. Everything else (task creation, runDag, reconcile, chat,
|
|
138
|
+
* worker actions…) requires the general Console token.
|
|
139
|
+
*/
|
|
140
|
+
export const INSPECT_MUTATION_ALLOWED_ACTIONS = new Set([
|
|
141
|
+
"dagRerunPlan",
|
|
142
|
+
"dagRerun",
|
|
143
|
+
]);
|
|
133
144
|
async function handleCreateOperation(req, res, ctx) {
|
|
134
145
|
if (!ctx.operator) {
|
|
135
146
|
sendJson(res, 503, {
|
|
@@ -141,12 +152,31 @@ async function handleCreateOperation(req, res, ctx) {
|
|
|
141
152
|
});
|
|
142
153
|
return;
|
|
143
154
|
}
|
|
144
|
-
const
|
|
155
|
+
const generalGateContext = {
|
|
156
|
+
cookieName: ctx.bootToken.cookieName,
|
|
145
157
|
bootToken: ctx.bootToken.value,
|
|
146
158
|
confirmationToken: ctx.bootToken.confirmationToken,
|
|
147
159
|
consoleOrigin: ctx.getConsoleOrigin(),
|
|
148
160
|
allowNonLoopbackAccess: ctx.allowNonLoopbackAccess === true,
|
|
149
|
-
}
|
|
161
|
+
};
|
|
162
|
+
let failure = evaluateMutationGate(req, generalGateContext);
|
|
163
|
+
let inspectScoped = false;
|
|
164
|
+
if (failure && ctx.inspectBootToken) {
|
|
165
|
+
// Scoped /inspect credentials: try the inspect gate before failing. The
|
|
166
|
+
// general gate already rejected, so passing here only ever yields the
|
|
167
|
+
// allowlisted actions below — never general write capability.
|
|
168
|
+
const scopedFailure = evaluateMutationGate(req, {
|
|
169
|
+
cookieName: ctx.inspectBootToken.cookieName,
|
|
170
|
+
bootToken: ctx.inspectBootToken.value,
|
|
171
|
+
confirmationToken: ctx.inspectBootToken.confirmationToken,
|
|
172
|
+
consoleOrigin: ctx.getConsoleOrigin(),
|
|
173
|
+
allowNonLoopbackAccess: ctx.allowNonLoopbackAccess === true,
|
|
174
|
+
});
|
|
175
|
+
if (!scopedFailure) {
|
|
176
|
+
inspectScoped = true;
|
|
177
|
+
failure = undefined;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
150
180
|
if (failure) {
|
|
151
181
|
sendJson(res, failure.status, {
|
|
152
182
|
ok: false,
|
|
@@ -173,6 +203,16 @@ async function handleCreateOperation(req, res, ctx) {
|
|
|
173
203
|
? body.actionParams
|
|
174
204
|
: {};
|
|
175
205
|
const clientRequestId = typeof body.clientRequestId === "string" ? body.clientRequestId : undefined;
|
|
206
|
+
if (inspectScoped && !INSPECT_MUTATION_ALLOWED_ACTIONS.has(action)) {
|
|
207
|
+
sendJson(res, 403, {
|
|
208
|
+
ok: false,
|
|
209
|
+
error: {
|
|
210
|
+
code: "ACTION_NOT_IN_INSPECT_SCOPE",
|
|
211
|
+
message: `inspect-scoped token only allows: ${[...INSPECT_MUTATION_ALLOWED_ACTIONS].join(", ")}`,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
176
216
|
const result = await dispatchOperatorAction(ctx.operator.actionContext, {
|
|
177
217
|
action,
|
|
178
218
|
actionParams,
|
|
@@ -428,6 +468,7 @@ export async function handleConsoleOperatorRequest(req, res, ctx) {
|
|
|
428
468
|
}
|
|
429
469
|
if (isMutationMethod(method)) {
|
|
430
470
|
const failure = evaluateMutationGate(req, {
|
|
471
|
+
cookieName: ctx.bootToken.cookieName,
|
|
431
472
|
bootToken: ctx.bootToken.value,
|
|
432
473
|
confirmationToken: ctx.bootToken.confirmationToken,
|
|
433
474
|
consoleOrigin: ctx.getConsoleOrigin(),
|
|
@@ -1,24 +1,78 @@
|
|
|
1
|
-
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
1
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { isLoopbackHost } from "./loopback.js";
|
|
3
|
+
/** Prefix for instance-scoped Cookie names; not a lookup name. */
|
|
3
4
|
export const BOOT_CAPABILITY_COOKIE = "loop_console_capability";
|
|
4
5
|
/** Custom mutation confirmation header (design §9). JS-readable; not the HttpOnly boot cookie. */
|
|
5
6
|
export const CONFIRMATION_TOKEN_HEADER = "x-loop-console-confirmation";
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
function normalizeInstanceScope(scope) {
|
|
8
|
+
const repoFingerprint = scope.repoFingerprint.trim();
|
|
9
|
+
if (!repoFingerprint) {
|
|
10
|
+
throw new Error("console instance scope requires a non-empty repoFingerprint");
|
|
11
|
+
}
|
|
12
|
+
const bindHost = scope.bindHost.trim();
|
|
13
|
+
if (!bindHost) {
|
|
14
|
+
throw new Error("console instance scope requires a non-empty bindHost");
|
|
15
|
+
}
|
|
16
|
+
if (!Number.isInteger(scope.configuredPort) || scope.configuredPort < 0) {
|
|
17
|
+
throw new Error(`console instance scope configuredPort must be an integer >= 0, got ${String(scope.configuredPort)}`);
|
|
18
|
+
}
|
|
19
|
+
const instanceNonce = scope.instanceNonce?.trim();
|
|
20
|
+
if (scope.configuredPort === 0) {
|
|
21
|
+
if (!instanceNonce) {
|
|
22
|
+
throw new Error("console instance scope requires a non-empty instanceNonce when configuredPort is 0");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
repoFingerprint,
|
|
26
|
+
bindHost,
|
|
27
|
+
configuredPort: 0,
|
|
28
|
+
instanceNonce,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
repoFingerprint,
|
|
33
|
+
bindHost,
|
|
34
|
+
configuredPort: scope.configuredPort,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Deterministic Cookie name for one Console instance; never includes repo path or token. */
|
|
38
|
+
export function deriveBootCapabilityCookieName(scope, variant) {
|
|
39
|
+
const normalized = normalizeInstanceScope(scope);
|
|
40
|
+
const digest = createHash("sha256")
|
|
41
|
+
.update("loop-console-capability-v1\0", "utf8")
|
|
42
|
+
.update(normalized.repoFingerprint, "utf8")
|
|
43
|
+
.update("\0", "utf8")
|
|
44
|
+
.update(normalized.bindHost, "utf8")
|
|
45
|
+
.update("\0", "utf8")
|
|
46
|
+
.update(String(normalized.configuredPort), "utf8")
|
|
47
|
+
.update("\0", "utf8")
|
|
48
|
+
.update(normalized.instanceNonce ?? "", "utf8")
|
|
49
|
+
.update("\0", "utf8")
|
|
50
|
+
.update(variant ?? "", "utf8")
|
|
51
|
+
.digest("hex")
|
|
52
|
+
.slice(0, 32);
|
|
53
|
+
return `${BOOT_CAPABILITY_COOKIE}_${digest}`;
|
|
54
|
+
}
|
|
55
|
+
/** Issue per-process unguessable boot capability + confirmation tokens.
|
|
56
|
+
* `variant` (e.g. "inspect") derives a separate cookie name so scoped
|
|
57
|
+
* credentials cannot be replayed against the general mutation surface. */
|
|
58
|
+
export function issueBootCapabilityToken(scope, options = {}) {
|
|
59
|
+
const cookieName = deriveBootCapabilityCookieName(scope, options.variant);
|
|
8
60
|
const value = randomBytes(32).toString("base64url");
|
|
9
61
|
const confirmationToken = randomBytes(32).toString("base64url");
|
|
10
62
|
const setCookieHeader = [
|
|
11
|
-
`${
|
|
63
|
+
`${cookieName}=${value}`,
|
|
12
64
|
"HttpOnly",
|
|
13
65
|
"SameSite=Strict",
|
|
14
66
|
"Path=/",
|
|
15
67
|
].join("; ");
|
|
16
|
-
return { value, setCookieHeader, confirmationToken };
|
|
68
|
+
return { cookieName, value, setCookieHeader, confirmationToken };
|
|
17
69
|
}
|
|
18
|
-
/** Inject confirmation token into HTML so the SPA can send the mutation
|
|
19
|
-
|
|
70
|
+
/** Inject confirmation token into HTML so the SPA can send the mutation
|
|
71
|
+
* header. `varName` separates the general Console token from the scoped
|
|
72
|
+
* inspect token on the read-only /inspect surface. */
|
|
73
|
+
export function injectConfirmationTokenScript(html, confirmationToken, varName = "__CONSOLE_CONFIRMATION_TOKEN__") {
|
|
20
74
|
const source = typeof html === "string" ? html : html.toString("utf8");
|
|
21
|
-
const script = `<script>window
|
|
75
|
+
const script = `<script>window.${varName}=${JSON.stringify(confirmationToken)};</script>`;
|
|
22
76
|
if (source.includes("</head>")) {
|
|
23
77
|
return Buffer.from(source.replace("</head>", `${script}</head>`), "utf8");
|
|
24
78
|
}
|
|
@@ -74,7 +128,7 @@ function loopbackOriginMatches(origin, consoleOrigin) {
|
|
|
74
128
|
return originKey !== null && consoleKey !== null && originKey === consoleKey;
|
|
75
129
|
}
|
|
76
130
|
export function evaluateMutationGate(req, ctx) {
|
|
77
|
-
const cookieToken = parseCookieHeader(req.headers.cookie,
|
|
131
|
+
const cookieToken = parseCookieHeader(req.headers.cookie, ctx.cookieName);
|
|
78
132
|
if (!cookieToken) {
|
|
79
133
|
return {
|
|
80
134
|
status: 403,
|
|
@@ -21,8 +21,9 @@ import { createOperationEventStore, } from "./operation-sse.js";
|
|
|
21
21
|
import { OperationStore } from "./operation-store.js";
|
|
22
22
|
import { probePiReadiness, } from "./pi-readiness.js";
|
|
23
23
|
import { handleConsoleHealthRequest, handleConsoleOperatorRequest, sendJson, serveConsoleStatic, } from "./routes.js";
|
|
24
|
-
import { issueBootCapabilityToken } from "./security.js";
|
|
24
|
+
import { issueBootCapabilityToken, injectConfirmationTokenScript, } from "./security.js";
|
|
25
25
|
import { resolveSiblingLoopAgentBin } from "./sibling-controller.js";
|
|
26
|
+
import { isDagRerunPromptOverrideEnabled } from "../../shared/dag-prompt-override.js";
|
|
26
27
|
import { NightAuxTicker } from "./night-aux-ticker.js";
|
|
27
28
|
import { deriveObserveRouteCapabilities } from "../observe/health.js";
|
|
28
29
|
import { createObserveRouteContext, defaultObserveStaticDir, handleMatchedObserveRoute, matchObserveGetRoute, ROUTES, serveObserveStatic, } from "../observe/routes.js";
|
|
@@ -66,7 +67,7 @@ export async function createConsoleServer(options) {
|
|
|
66
67
|
process.stderr.write(`console: binding non-loopback host ${host} (Operator mutations enabled; no network auth — expose only on trusted networks)\n`);
|
|
67
68
|
}
|
|
68
69
|
const repoRoot = path.resolve(options.repoRoot);
|
|
69
|
-
const
|
|
70
|
+
const configuredPort = options.port ?? 8790;
|
|
70
71
|
const debug = options.debug === true;
|
|
71
72
|
const keepAliveTimeoutMs = options.keepAliveTimeoutMs ?? 65_000;
|
|
72
73
|
const staticDir = options.staticDir ?? defaultConsoleStaticDir();
|
|
@@ -74,12 +75,27 @@ export async function createConsoleServer(options) {
|
|
|
74
75
|
const observeRouteContext = createObserveRouteContext(repoRoot, {
|
|
75
76
|
staticDir: inspectStaticDir,
|
|
76
77
|
});
|
|
77
|
-
const bootToken = issueBootCapabilityToken();
|
|
78
78
|
const operatorSessionId = `sess_${randomBytes(16).toString("hex")}`;
|
|
79
79
|
const appData = openConsoleAppData({
|
|
80
80
|
repoRoot,
|
|
81
81
|
appDataRoot: options.appDataRoot,
|
|
82
82
|
});
|
|
83
|
+
const instanceNonce = configuredPort === 0 ? randomBytes(16).toString("hex") : undefined;
|
|
84
|
+
const bootToken = issueBootCapabilityToken({
|
|
85
|
+
repoFingerprint: appData.fingerprint,
|
|
86
|
+
bindHost: host,
|
|
87
|
+
configuredPort,
|
|
88
|
+
...(instanceNonce ? { instanceNonce } : {}),
|
|
89
|
+
});
|
|
90
|
+
// Scoped credentials for the experimental /inspect prompt-override rerun:
|
|
91
|
+
// separate cookie name + confirmation token so the read-only inspect page
|
|
92
|
+
// can never replay them against the general Console mutation surface.
|
|
93
|
+
const inspectBootToken = issueBootCapabilityToken({
|
|
94
|
+
repoFingerprint: appData.fingerprint,
|
|
95
|
+
bindHost: host,
|
|
96
|
+
configuredPort,
|
|
97
|
+
...(instanceNonce ? { instanceNonce } : {}),
|
|
98
|
+
}, { variant: "inspect" });
|
|
83
99
|
const operations = new OperationStore(appData);
|
|
84
100
|
const events = createOperationEventStore({
|
|
85
101
|
persistenceDir: path.join(appData.operations, "events"),
|
|
@@ -137,7 +153,7 @@ export async function createConsoleServer(options) {
|
|
|
137
153
|
getConsoleOrigin: () => `http://${boundHost}:${boundPort}`,
|
|
138
154
|
};
|
|
139
155
|
let boundHost = host;
|
|
140
|
-
let boundPort =
|
|
156
|
+
let boundPort = configuredPort;
|
|
141
157
|
const getConsoleOrigin = () => `http://${boundHost}:${boundPort}`;
|
|
142
158
|
// Phase 4: General Operator Chat runtime. The actionContext is forwarded so
|
|
143
159
|
// custom-tool execute() calls dispatch into the operator action layer (Gate 3).
|
|
@@ -188,6 +204,7 @@ export async function createConsoleServer(options) {
|
|
|
188
204
|
repoRoot,
|
|
189
205
|
staticDir,
|
|
190
206
|
bootToken,
|
|
207
|
+
inspectBootToken,
|
|
191
208
|
getConsoleOrigin,
|
|
192
209
|
allowNonLoopbackAccess: !loopbackBind,
|
|
193
210
|
inspect: {
|
|
@@ -277,8 +294,22 @@ export async function createConsoleServer(options) {
|
|
|
277
294
|
}
|
|
278
295
|
}
|
|
279
296
|
if (pathname.startsWith("/inspect")) {
|
|
297
|
+
// Experimental prompt-override rerun: only while the internal switch
|
|
298
|
+
// is enabled do we hand the inspect page SCOPED mutation
|
|
299
|
+
// credentials (separate cookie + token, only strong enough for
|
|
300
|
+
// INSPECT_MUTATION_ALLOWED_ACTIONS — see routes.ts). Default stays
|
|
301
|
+
// strictly read-only: no token, no cookie, no tab.
|
|
302
|
+
const htmlEnhancer = isDagRerunPromptOverrideEnabled()
|
|
303
|
+
? (html) => ({
|
|
304
|
+
content: injectConfirmationTokenScript(html, routeContext.inspectBootToken?.confirmationToken ??
|
|
305
|
+
routeContext.bootToken.confirmationToken, "__INSPECT_MUTATION_TOKEN__"),
|
|
306
|
+
setCookie: routeContext.inspectBootToken?.setCookieHeader ??
|
|
307
|
+
routeContext.bootToken.setCookieHeader,
|
|
308
|
+
})
|
|
309
|
+
: undefined;
|
|
280
310
|
await serveObserveStatic(req, res, inspectStaticDir, {
|
|
281
311
|
urlPrefix: "/inspect",
|
|
312
|
+
...(htmlEnhancer ? { htmlEnhancer } : {}),
|
|
282
313
|
});
|
|
283
314
|
return;
|
|
284
315
|
}
|
|
@@ -289,7 +320,7 @@ export async function createConsoleServer(options) {
|
|
|
289
320
|
await serveConsoleStatic(req, res, routeContext);
|
|
290
321
|
}
|
|
291
322
|
server.on("error", reject);
|
|
292
|
-
server.listen(
|
|
323
|
+
server.listen(configuredPort, host, () => {
|
|
293
324
|
const addr = server.address();
|
|
294
325
|
if (!addr || typeof addr === "string") {
|
|
295
326
|
reject(new Error("Failed to get console server address"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-B1JriSjm.js";import{p as f}from"./chunk-JWPE2WC7-BsNKEC_r.js";import{_ as n,l as o}from"./mermaid.core-CcWKn6tS.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DiyymT2D.js";import"./index-DEbyrEfW.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-
|
|
1
|
+
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-CcWKn6tS.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|