@drisp/cli 0.5.22 → 0.5.24
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/{WorkflowInstallWizard-IPLYZPLS.js → WorkflowInstallWizard-IMU47QWB.js} +2 -2
- package/dist/athena-gateway.js +26 -39
- package/dist/{chunk-MRAM6EYI.js → chunk-7GEQJQMR.js} +2 -2
- package/dist/{chunk-DSWRVUOO.js → chunk-7UUPLAP4.js} +163 -178
- package/dist/{chunk-HXW5N4GE.js → chunk-QBMYQJFX.js} +734 -838
- package/dist/{chunk-BTY7MYYT.js → chunk-YU2WMPRC.js} +54 -8
- package/dist/cli.js +140 -135
- package/dist/dashboard-daemon.js +3 -3
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
installWorkflowPlugins,
|
|
9
9
|
resolveWorkflow,
|
|
10
10
|
writeGlobalConfig
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7UUPLAP4.js";
|
|
12
12
|
|
|
13
13
|
// src/setup/steps/WorkflowInstallWizard.tsx
|
|
14
14
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
@@ -92,4 +92,4 @@ function WorkflowInstallWizard({ source, onDone }) {
|
|
|
92
92
|
export {
|
|
93
93
|
WorkflowInstallWizard as default
|
|
94
94
|
};
|
|
95
|
-
//# sourceMappingURL=WorkflowInstallWizard-
|
|
95
|
+
//# sourceMappingURL=WorkflowInstallWizard-IMU47QWB.js.map
|
package/dist/athena-gateway.js
CHANGED
|
@@ -3,13 +3,14 @@ import {
|
|
|
3
3
|
loadOrCreateToken,
|
|
4
4
|
requireTokenForBind,
|
|
5
5
|
timingSafeTokenEqual
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7GEQJQMR.js";
|
|
7
7
|
import {
|
|
8
8
|
CHANNEL_REQUEST_ID_REGEX,
|
|
9
9
|
createUdsServerTransport,
|
|
10
10
|
generateChannelRequestId,
|
|
11
11
|
isLoopbackHost,
|
|
12
12
|
isValidChannelRequestId,
|
|
13
|
+
openVersionedDb,
|
|
13
14
|
refreshDashboardAccessToken,
|
|
14
15
|
resolveGatewayPaths,
|
|
15
16
|
resolveListenSpec,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
trackGatewayTransportConnect,
|
|
20
21
|
trackGatewayTransportDisconnect,
|
|
21
22
|
writeGatewayTrace
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-YU2WMPRC.js";
|
|
23
24
|
|
|
24
25
|
// src/gateway/daemon.ts
|
|
25
26
|
import fs4 from "fs";
|
|
@@ -2440,7 +2441,7 @@ var cachedVersion = null;
|
|
|
2440
2441
|
function readVersion() {
|
|
2441
2442
|
if (cachedVersion !== null) return cachedVersion;
|
|
2442
2443
|
try {
|
|
2443
|
-
const injected = "0.5.
|
|
2444
|
+
const injected = "0.5.24";
|
|
2444
2445
|
if (typeof injected === "string" && injected.length > 0) {
|
|
2445
2446
|
cachedVersion = injected;
|
|
2446
2447
|
return cachedVersion;
|
|
@@ -3758,31 +3759,9 @@ function questionFingerprint(req) {
|
|
|
3758
3759
|
|
|
3759
3760
|
// src/gateway/state/db.ts
|
|
3760
3761
|
import fs3 from "fs";
|
|
3761
|
-
import path3 from "path";
|
|
3762
|
-
import Database from "better-sqlite3";
|
|
3763
3762
|
var GATEWAY_STATE_VERSION = 2;
|
|
3764
|
-
|
|
3765
|
-
if (dbPath !== ":memory:") {
|
|
3766
|
-
fs3.mkdirSync(path3.dirname(dbPath), { recursive: true, mode: 448 });
|
|
3767
|
-
}
|
|
3768
|
-
const db = new Database(dbPath);
|
|
3769
|
-
db.exec("PRAGMA journal_mode = WAL");
|
|
3770
|
-
db.exec("PRAGMA foreign_keys = ON");
|
|
3771
|
-
initGatewayStateSchema(db);
|
|
3772
|
-
if (dbPath !== ":memory:" && process.platform !== "win32") {
|
|
3773
|
-
try {
|
|
3774
|
-
fs3.chmodSync(dbPath, 384);
|
|
3775
|
-
} catch {
|
|
3776
|
-
}
|
|
3777
|
-
}
|
|
3778
|
-
return db;
|
|
3779
|
-
}
|
|
3780
|
-
function initGatewayStateSchema(db) {
|
|
3763
|
+
var migrateGatewayState = (db, fromVersion) => {
|
|
3781
3764
|
db.exec(`
|
|
3782
|
-
CREATE TABLE IF NOT EXISTS schema_version (
|
|
3783
|
-
version INTEGER NOT NULL
|
|
3784
|
-
);
|
|
3785
|
-
|
|
3786
3765
|
-- Inbound chat messages parked while no runtime is registered. Drained
|
|
3787
3766
|
-- in FIFO id order on session.register. Idempotency key prevents the
|
|
3788
3767
|
-- same provider message from being parked twice if an adapter retries.
|
|
@@ -3814,27 +3793,35 @@ function initGatewayStateSchema(db) {
|
|
|
3814
3793
|
CREATE INDEX IF NOT EXISTS ix_channel_outbox_due
|
|
3815
3794
|
ON channel_outbox(next_attempt_at);
|
|
3816
3795
|
`);
|
|
3817
|
-
|
|
3818
|
-
if (existing && existing.version > GATEWAY_STATE_VERSION) {
|
|
3819
|
-
throw new Error(
|
|
3820
|
-
`Gateway state DB has newer schema version ${existing.version} (expected <= ${GATEWAY_STATE_VERSION}). Update athena-cli.`
|
|
3821
|
-
);
|
|
3822
|
-
}
|
|
3823
|
-
if (!existing) {
|
|
3824
|
-
db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(
|
|
3825
|
-
GATEWAY_STATE_VERSION
|
|
3826
|
-
);
|
|
3827
|
-
return;
|
|
3828
|
-
}
|
|
3796
|
+
if (fromVersion === void 0) return;
|
|
3829
3797
|
const inboundColumns = db.prepare("PRAGMA table_info(inbound_queue)").all();
|
|
3830
3798
|
if (!inboundColumns.some((column) => column.name === "attachment_id")) {
|
|
3831
3799
|
db.prepare("ALTER TABLE inbound_queue ADD COLUMN attachment_id TEXT").run();
|
|
3832
3800
|
}
|
|
3833
|
-
if (
|
|
3801
|
+
if (fromVersion < GATEWAY_STATE_VERSION) {
|
|
3834
3802
|
db.prepare("UPDATE schema_version SET version = ?").run(
|
|
3835
3803
|
GATEWAY_STATE_VERSION
|
|
3836
3804
|
);
|
|
3837
3805
|
}
|
|
3806
|
+
};
|
|
3807
|
+
function openGatewayState(dbPath) {
|
|
3808
|
+
const db = openVersionedDb(dbPath, {
|
|
3809
|
+
version: GATEWAY_STATE_VERSION,
|
|
3810
|
+
migrate: migrateGatewayState,
|
|
3811
|
+
foreignKeys: true,
|
|
3812
|
+
ensureDir: true,
|
|
3813
|
+
dirMode: 448,
|
|
3814
|
+
onNewerVersion: (found, expected) => new Error(
|
|
3815
|
+
`Gateway state DB has newer schema version ${found} (expected <= ${expected}). Update athena-cli.`
|
|
3816
|
+
)
|
|
3817
|
+
});
|
|
3818
|
+
if (dbPath !== ":memory:" && process.platform !== "win32") {
|
|
3819
|
+
try {
|
|
3820
|
+
fs3.chmodSync(dbPath, 384);
|
|
3821
|
+
} catch {
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
return db;
|
|
3838
3825
|
}
|
|
3839
3826
|
|
|
3840
3827
|
// src/gateway/transport/tlsWs.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isLoopbackHost
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YU2WMPRC.js";
|
|
4
4
|
|
|
5
5
|
// src/gateway/auth.ts
|
|
6
6
|
import crypto from "crypto";
|
|
@@ -73,4 +73,4 @@ export {
|
|
|
73
73
|
timingSafeTokenEqual,
|
|
74
74
|
requireTokenForBind
|
|
75
75
|
};
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
76
|
+
//# sourceMappingURL=chunk-7GEQJQMR.js.map
|
|
@@ -1138,7 +1138,7 @@ import fs7 from "fs";
|
|
|
1138
1138
|
import os4 from "os";
|
|
1139
1139
|
import path5 from "path";
|
|
1140
1140
|
|
|
1141
|
-
// src/core/workflows/
|
|
1141
|
+
// src/core/workflows/trackerReader.ts
|
|
1142
1142
|
import fs6 from "fs";
|
|
1143
1143
|
|
|
1144
1144
|
// src/core/workflows/templateVars.ts
|
|
@@ -1157,66 +1157,60 @@ function substituteVariables(text, ctx) {
|
|
|
1157
1157
|
return result;
|
|
1158
1158
|
}
|
|
1159
1159
|
|
|
1160
|
-
// src/core/workflows/
|
|
1160
|
+
// src/core/workflows/trackerReader.ts
|
|
1161
1161
|
var DEFAULT_COMPLETION_MARKER = "<!-- WORKFLOW_COMPLETE -->";
|
|
1162
1162
|
var DEFAULT_BLOCKED_MARKER = "<!-- WORKFLOW_BLOCKED";
|
|
1163
1163
|
var DEFAULT_TRACKER_PATH = ".athena/{sessionId}/tracker.md";
|
|
1164
1164
|
var TRACKER_SKELETON_MARKER = "<!-- TRACKER_SKELETON -->";
|
|
1165
|
-
var DEFAULT_CONTINUE_PROMPT = "Continue the task. Read the tracker at {trackerPath} for current progress.";
|
|
1166
|
-
function
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
function readTracker() {
|
|
1172
|
-
try {
|
|
1173
|
-
return fs6.readFileSync(trackerPath, "utf-8");
|
|
1174
|
-
} catch {
|
|
1175
|
-
return "";
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
function getTerminalLine(content) {
|
|
1179
|
-
const lines = content.trimEnd().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1180
|
-
return lines.at(-1);
|
|
1181
|
-
}
|
|
1182
|
-
function extractBlockedReason(line) {
|
|
1183
|
-
if (!line.startsWith(blockedMarker)) return void 0;
|
|
1184
|
-
const afterMarker = line.slice(blockedMarker.length);
|
|
1185
|
-
const match = afterMarker.match(/^:\s*(.+?)(?:\s*-->|$)/);
|
|
1186
|
-
return match?.[1]?.trim();
|
|
1187
|
-
}
|
|
1188
|
-
function getState() {
|
|
1189
|
-
const content = readTracker();
|
|
1190
|
-
const terminalLine = getTerminalLine(content);
|
|
1191
|
-
const completed = terminalLine === completionMarker;
|
|
1192
|
-
const blocked = terminalLine !== void 0 && (terminalLine === `${blockedMarker} -->` || terminalLine.startsWith(`${blockedMarker}:`));
|
|
1193
|
-
const blockedReason = blocked && terminalLine ? extractBlockedReason(terminalLine) : void 0;
|
|
1194
|
-
const reachedLimit = iteration >= config.maxIterations;
|
|
1195
|
-
const skeletonNotReplaced = content.includes(TRACKER_SKELETON_MARKER);
|
|
1196
|
-
return {
|
|
1197
|
-
active,
|
|
1198
|
-
iteration,
|
|
1199
|
-
maxIterations: config.maxIterations,
|
|
1200
|
-
completionMarker,
|
|
1201
|
-
blockedMarker,
|
|
1202
|
-
completed,
|
|
1203
|
-
blocked,
|
|
1204
|
-
blockedReason,
|
|
1205
|
-
reachedLimit,
|
|
1206
|
-
skeletonNotReplaced
|
|
1207
|
-
};
|
|
1208
|
-
}
|
|
1209
|
-
function incrementIteration() {
|
|
1210
|
-
iteration++;
|
|
1165
|
+
var DEFAULT_CONTINUE_PROMPT = "Continue the task. Read the tracker at {trackerPath} for current progress. If the work is complete or blocked, the terminal marker must be the final non-empty line of the tracker; do not write any prose after it.";
|
|
1166
|
+
function readTracker(trackerPath) {
|
|
1167
|
+
try {
|
|
1168
|
+
return fs6.readFileSync(trackerPath, "utf-8");
|
|
1169
|
+
} catch {
|
|
1170
|
+
return "";
|
|
1211
1171
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1172
|
+
}
|
|
1173
|
+
function getNonEmptyLines(content) {
|
|
1174
|
+
return content.trimEnd().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1175
|
+
}
|
|
1176
|
+
function isBlockedLine(line, blockedMarker) {
|
|
1177
|
+
return line === `${blockedMarker} -->` || line.startsWith(`${blockedMarker}:`);
|
|
1178
|
+
}
|
|
1179
|
+
function isTerminalMarkerLine(line, completionMarker, blockedMarker) {
|
|
1180
|
+
return line === completionMarker || isBlockedLine(line, blockedMarker);
|
|
1181
|
+
}
|
|
1182
|
+
function getMisplacedTerminalMarker(lines, completionMarker, blockedMarker) {
|
|
1183
|
+
if (lines.length < 2) return void 0;
|
|
1184
|
+
const terminalLine = lines.at(-1);
|
|
1185
|
+
if (terminalLine && isTerminalMarkerLine(terminalLine, completionMarker, blockedMarker)) {
|
|
1186
|
+
return void 0;
|
|
1214
1187
|
}
|
|
1188
|
+
return lines.slice(0, -1).find((line) => isTerminalMarkerLine(line, completionMarker, blockedMarker));
|
|
1189
|
+
}
|
|
1190
|
+
function extractBlockedReason(line, blockedMarker) {
|
|
1191
|
+
if (!line.startsWith(blockedMarker)) return void 0;
|
|
1192
|
+
const afterMarker = line.slice(blockedMarker.length);
|
|
1193
|
+
const match = afterMarker.match(/^:\s*(.+?)(?:\s*-->|$)/);
|
|
1194
|
+
return match?.[1]?.trim();
|
|
1195
|
+
}
|
|
1196
|
+
function parseTrackerState(content, markers = {}) {
|
|
1197
|
+
const completionMarker = markers.completionMarker ?? DEFAULT_COMPLETION_MARKER;
|
|
1198
|
+
const blockedMarker = markers.blockedMarker ?? DEFAULT_BLOCKED_MARKER;
|
|
1199
|
+
const lines = getNonEmptyLines(content);
|
|
1200
|
+
const terminalLine = lines.at(-1);
|
|
1201
|
+
const completed = terminalLine === completionMarker;
|
|
1202
|
+
const blocked = terminalLine !== void 0 && isBlockedLine(terminalLine, blockedMarker);
|
|
1203
|
+
const blockedReason = blocked && terminalLine ? extractBlockedReason(terminalLine, blockedMarker) : void 0;
|
|
1215
1204
|
return {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1205
|
+
completed,
|
|
1206
|
+
blocked,
|
|
1207
|
+
blockedReason,
|
|
1208
|
+
misplacedTerminalMarker: getMisplacedTerminalMarker(
|
|
1209
|
+
lines,
|
|
1210
|
+
completionMarker,
|
|
1211
|
+
blockedMarker
|
|
1212
|
+
),
|
|
1213
|
+
skeletonNotReplaced: content.includes(TRACKER_SKELETON_MARKER)
|
|
1220
1214
|
};
|
|
1221
1215
|
}
|
|
1222
1216
|
function buildContinuePrompt(loop) {
|
|
@@ -1271,15 +1265,17 @@ After completing meaningful work, update the tracker:
|
|
|
1271
1265
|
|
|
1272
1266
|
When all steps are complete:
|
|
1273
1267
|
1. Update the tracker with all steps checked off
|
|
1274
|
-
2.
|
|
1275
|
-
3.
|
|
1268
|
+
2. Put any final summary or outcome notes above the terminal marker
|
|
1269
|
+
3. Add \`${DEFAULT_COMPLETION_MARKER}\` as the final non-empty line of the tracker file
|
|
1270
|
+
4. Do not write any tracker content after the terminal marker
|
|
1276
1271
|
|
|
1277
1272
|
### Blocked
|
|
1278
1273
|
|
|
1279
1274
|
If you are blocked and cannot make further progress:
|
|
1280
1275
|
1. Document what is blocking you in the Notes section
|
|
1281
|
-
2.
|
|
1282
|
-
3.
|
|
1276
|
+
2. Explain what needs to happen to unblock the task whenever possible above the terminal marker
|
|
1277
|
+
3. Add \`${DEFAULT_BLOCKED_CLOSED_MARKER}\` or \`${DEFAULT_BLOCKED_REASON_MARKER}\` as the final non-empty line of the tracker file
|
|
1278
|
+
4. Do not write any tracker content after the terminal marker
|
|
1283
1279
|
`;
|
|
1284
1280
|
function ensureSystemPromptFile() {
|
|
1285
1281
|
const dir = path5.join(
|
|
@@ -1693,7 +1689,7 @@ import fs10 from "fs";
|
|
|
1693
1689
|
import path8 from "path";
|
|
1694
1690
|
|
|
1695
1691
|
// src/core/workflows/stateMachine.md
|
|
1696
|
-
var stateMachine_default = "# Stateless Turn Protocol\n\nYou run in a stateless loop. Each Turn is a fresh process with no memory of prior Turns. **The tracker file is your only continuity** \u2014 read it, work, write it. Assume interruption: the runner may kill a long Turn, your context may collapse under tool output, you may hit token limits mid-task. Anything not in the tracker is gone.\n\n## First action, every Turn\n\n1. Read the tracker at the configured path (default: `.athena/<session_id>/tracker.md`). The runner provides the session ID \u2014 do not invent one.\n2. If the tracker contains `<!-- TRACKER_SKELETON -->` \u2192 this is Turn 1, run [**Orient**](#orient-turn-1).\n3. Otherwise \u2192 this is a continuation, run [**Execute**](#execute-turn-2) from where the tracker says, not from the start of the flow.\n\nReading first prevents two failure modes that waste whole Turns: redoing work already done, or contradicting decisions a prior Turn made.\n\n## Tracker contract\n\nThe tracker must always answer four questions:\n\n1. What are we trying to accomplish?\n2. What has been done?\n3. What's left?\n4. What should the next Turn do first?\n\nA future Turn has no other context. If something isn't here, it doesn't exist. Section headings may vary by workflow, but these four answers must be explicit and easy to find.\n\n### Terminal markers\n\nDefault markers (workflows may override \u2014 use the markers configured for the active workflow):\n\n- `<!-- WORKFLOW_COMPLETE -->` \u2014 all work done and verified\n- `<!-- WORKFLOW_BLOCKED -->` or `<!-- WORKFLOW_BLOCKED: reason -->` \u2014 cannot proceed without external intervention\n\nRules:\n\n- Only the last non-empty line of the tracker is authoritative. Marker-like text in notes, examples, or quoted instructions earlier in the file is ignored.\n- The runner trusts markers unconditionally. A premature marker ends the loop with no automatic recovery \u2014 write one only when its criteria are fully met.\n- Include a concrete reason after `WORKFLOW_BLOCKED:` whenever possible; the bare form is still valid.\n\n## Phases\n\n### Orient (Turn 1)\n\n1. **Replace the skeleton immediately**, before any domain work. Even a three-line tracker (goal + \"orienting\") protects you if the Turn dies during setup.\n2. Identify and load the applicable workflow skills before doing domain work. If a workflow, plugin, or local skill table names a relevant skill, read it fully and follow it. Do not assume you already know the workflow's conventions, tool sequence, quality gates, or implementation details.\n3. Use a dedicated git worktree for repository-changing work. If you are not already inside a task-specific worktree, create or enter one before editing files, record its branch/path in the tracker, and continue there. Skip this only when the workflow explicitly forbids it or the task is read-only.\n4. Run the workflow's orientation steps exactly as written. These vary by domain \u2014 a test-writing workflow explores the product in a browser; a migration workflow audits the schema. The workflow defines what orientation means. Do not skip, reorder, reinterpret, or replace workflow steps with a generic approach unless the workflow explicitly allows it or the tracker records a concrete blocker that makes the written step impossible.\n5. Refine the tracker into a granular plan. Each task a concrete, verifiable unit of work, including verification steps (running checks, reviewing output) \u2014 not just implementation. Vague tasks (\"write tests\") cannot be meaningfully resumed by a future Turn that has no idea what they mean here.\n6. Record concrete observations \u2014 what you actually saw, not what you assumed. Wrong assumptions burn entire future Turns on rework.\n7. **Single-Turn requests still go through this phase.** If the entire request is satisfied in one Turn, write a minimal tracker (what was asked, what was done, the outcome) and append `<!-- WORKFLOW_COMPLETE -->`. Leaving the skeleton in place causes the runner to classify the Turn as a failure.\n\n### Execute (Turn 2+)\n\n- Work from where the tracker says, in the workflow's prescribed sequence. Not every Turn covers every step.\n- Be strict with workflow steps. Before starting each unit, identify the next required workflow step from the workflow document and tracker, follow it as written, and record completion or blockers against that step. Do not substitute your own process, collapse separate gates into one, or advance past an unchecked step.\n- Be strict with skills. Before each new activity, check the workflow, plugin metadata, local skill table, and tracker for relevant skills. Load the appropriate skill first, read it completely, and follow its instructions. If no skill applies, record that explicitly in the tracker before proceeding. Skills carry the implementation detail (scaffolding steps, locator rules, anti-patterns, code templates) that this protocol intentionally doesn't repeat.\n- Keep repository work inside the recorded git worktree. If a continuation Turn starts outside the recorded worktree, enter it before editing. If no worktree is recorded and edits are still required, create or enter one before proceeding.\n- Delegate heavy exploration or generation to subagents via the Task tool. Pass file paths, conventions, and concrete output expectations; tell them which skill to load. Respect the workflow's **delegation constraints** \u2014 some operations must run in the main agent because their output is proof, or because the main agent needs to interpret results in context.\n- Run quality gates in order. Do not skip \u2014 they exist because skipping cascades into rework. On a failing verdict, address the issues and re-run before proceeding. Respect the workflow's **retry limits**: repeated failure usually signals a deeper issue another retry won't fix.\n\n### End\n\n1. Tracker reflects all progress, discoveries, and blockers.\n2. Tracker says clearly what the next Turn should do first.\n3. If all work is verified: append the completion marker.\n4. If an unrecoverable blocker prevents progress: append the blocked marker, with a reason if you have one.\n\n## When to write the tracker\n\nWrite on **concrete triggers**, not on a vague sense of \"meaningful progress.\" The right cadence sits between every-tool-call (noisy log, wastes tokens) and end-of-Turn (everything lost if you die mid-task).\n\n- **Discrete unit done** \u2014 file written, fix applied, test run, gate passed. Reflect the new reality before starting the next unit.\n- **Insight learned** \u2014 API quirk, config field that turned out to matter, dead end ruled out, decision between two approaches. Insights are tracker-worthy even when no code changed; rediscovering them costs the next Turn a full re-exploration. The tracker is a knowledge ledger, not just a task log.\n- **About to do something risky or long-running** \u2014 subagent dispatch, long build, flaky external call, large refactor. Write _first_, then act. If the operation kills your Turn, only what's on disk survives.\n- **Plan changed** \u2014 task resequenced, new task surfaced, planned task no longer needed. Stale plans poison continuation Turns.\n- **You haven't written in a while** \u2014 if you can't remember the last update, you've gone too long. A short defensive update (\"doing X, last completed Y, next is Z\") beats nothing.\n\nEach update covers: what changed (work or knowledge), what's now next, and any caveat the next Turn needs. Don't transcribe tool calls \u2014 the tracker is a contract with your future self, not a replay log.\n\nThe cost of one extra tracker update is a few tokens. The cost of dying without one is a whole wasted Turn. Bias toward writing.\n\n## Task UI projection\n\nThe tracker is the durable source of truth. Your harness's task tools are a Turn-scoped UI projection of the same plan, shown to the user in their CLI widget. They do not survive process exit.\n\n{{TASK_TOOL_INSTRUCTIONS}}\n\n- **Turn 1, after orientation:** project the tracker's task plan into the task tools.\n- **Turn 2+, after reading the tracker:** recreate the projection from the tracker; do not assume task IDs from prior Turns still exist.\n- **During work:** update both \u2014 the task tools for immediate UI feedback, the tracker for persistence \u2014 in the same working phase.\n\n## Turn bounding\n\nEach fresh Turn starts with a clean context window and a compact tracker \u2014 effectively self-compaction. As you work, context fills with tool outputs and intermediate state. The longer you run, the more attention is spread across tokens that are no longer relevant, degrading precision on the work that matters now.\n\nWork a bounded chunk per Turn. Ending early and letting the next Turn pick up from a clean tracker is almost always better than pushing through with a heavy context. Natural checkpoints:\n\n- After a quality gate\n- After crossing multiple phases (explored \u2192 planned \u2192 wrote specs) \u2014 stop before pushing into the next\n- When your context is visibly heavy with tool output from earlier work\n\n## Quick reference\n\n- [ ] Read the tracker before doing anything else\n- [ ] Replace the skeleton immediately, even for single-Turn requests\n- [ ] Update on concrete triggers \u2014 unit done, insight learned, risky op pending, plan changed\n- [ ] Project the tracker plan into task tools at Turn start; keep both in sync as work lands\n- [ ] Follow the workflow steps as written; do not skip, reorder, or substitute your own process\n- [ ] Load the appropriate skill before each activity; do not rely on assumed knowledge\n- [ ] Use and record a dedicated git worktree for repository-changing work\n- [ ] Run quality gates in order; respect delegation constraints and retry limits\n- [ ] Write the completion marker only when all work is verified\n- [ ] Checkpoint and end before context goes stale\n";
|
|
1692
|
+
var stateMachine_default = "# Stateless Turn Protocol\n\nYou run in a stateless loop. Each Turn is a fresh process with no memory of prior Turns. **The tracker file is your only continuity** \u2014 read it, work, write it. Assume interruption: the runner may kill a long Turn, your context may collapse under tool output, you may hit token limits mid-task. Anything not in the tracker is gone.\n\n## First action, every Turn\n\n1. Read the tracker at the configured path (default: `.athena/<session_id>/tracker.md`). The runner provides the session ID \u2014 do not invent one.\n2. If the tracker contains `<!-- TRACKER_SKELETON -->` \u2192 this is Turn 1, run [**Orient**](#orient-turn-1).\n3. Otherwise \u2192 this is a continuation, run [**Execute**](#execute-turn-2) from where the tracker says, not from the start of the flow.\n\nReading first prevents two failure modes that waste whole Turns: redoing work already done, or contradicting decisions a prior Turn made.\n\n## Tracker contract\n\nThe tracker must always answer four questions:\n\n1. What are we trying to accomplish?\n2. What has been done?\n3. What's left?\n4. What should the next Turn do first?\n\nA future Turn has no other context. If something isn't here, it doesn't exist. Section headings may vary by workflow, but these four answers must be explicit and easy to find.\n\n### Terminal markers\n\nDefault markers (workflows may override \u2014 use the markers configured for the active workflow):\n\n- `<!-- WORKFLOW_COMPLETE -->` \u2014 all work done and verified\n- `<!-- WORKFLOW_BLOCKED -->` or `<!-- WORKFLOW_BLOCKED: reason -->` \u2014 cannot proceed without external intervention\n\nRules:\n\n- Only the last non-empty line of the tracker is authoritative. Marker-like text in notes, examples, or quoted instructions earlier in the file is ignored.\n- When you write a terminal marker, it must be the final non-empty line of the tracker. Put every summary, status note, and next-step sentence before the marker. Never append prose after it.\n- The runner trusts markers unconditionally. A premature marker ends the loop with no automatic recovery \u2014 write one only when its criteria are fully met.\n- Include a concrete reason after `WORKFLOW_BLOCKED:` whenever possible; the bare form is still valid.\n\n## Phases\n\n### Orient (Turn 1)\n\n1. **Replace the skeleton immediately**, before any domain work. Even a three-line tracker (goal + \"orienting\") protects you if the Turn dies during setup.\n2. Identify and load the applicable workflow skills before doing domain work. If a workflow, plugin, or local skill table names a relevant skill, read it fully and follow it. Do not assume you already know the workflow's conventions, tool sequence, quality gates, or implementation details.\n3. Use a dedicated git worktree for repository-changing work. If you are not already inside a task-specific worktree, create or enter one before editing files, record its branch/path in the tracker, and continue there. Skip this only when the workflow explicitly forbids it or the task is read-only.\n4. Run the workflow's orientation steps exactly as written. These vary by domain \u2014 a test-writing workflow explores the product in a browser; a migration workflow audits the schema. The workflow defines what orientation means. Do not skip, reorder, reinterpret, or replace workflow steps with a generic approach unless the workflow explicitly allows it or the tracker records a concrete blocker that makes the written step impossible.\n5. Refine the tracker into a granular plan. Each task a concrete, verifiable unit of work, including verification steps (running checks, reviewing output) \u2014 not just implementation. Vague tasks (\"write tests\") cannot be meaningfully resumed by a future Turn that has no idea what they mean here.\n6. Record concrete observations \u2014 what you actually saw, not what you assumed. Wrong assumptions burn entire future Turns on rework.\n7. **Single-Turn requests still go through this phase.** If the entire request is satisfied in one Turn, write a minimal tracker (what was asked, what was done, the outcome) and append `<!-- WORKFLOW_COMPLETE -->`. Leaving the skeleton in place causes the runner to classify the Turn as a failure.\n\n### Execute (Turn 2+)\n\n- Work from where the tracker says, in the workflow's prescribed sequence. Not every Turn covers every step.\n- Be strict with workflow steps. Before starting each unit, identify the next required workflow step from the workflow document and tracker, follow it as written, and record completion or blockers against that step. Do not substitute your own process, collapse separate gates into one, or advance past an unchecked step.\n- Be strict with skills. Before each new activity, check the workflow, plugin metadata, local skill table, and tracker for relevant skills. Load the appropriate skill first, read it completely, and follow its instructions. If no skill applies, record that explicitly in the tracker before proceeding. Skills carry the implementation detail (scaffolding steps, locator rules, anti-patterns, code templates) that this protocol intentionally doesn't repeat.\n- Keep repository work inside the recorded git worktree. If a continuation Turn starts outside the recorded worktree, enter it before editing. If no worktree is recorded and edits are still required, create or enter one before proceeding.\n- Delegate heavy exploration or generation to subagents via the Task tool. Pass file paths, conventions, and concrete output expectations; tell them which skill to load. Respect the workflow's **delegation constraints** \u2014 some operations must run in the main agent because their output is proof, or because the main agent needs to interpret results in context.\n- Run quality gates in order. Do not skip \u2014 they exist because skipping cascades into rework. On a failing verdict, address the issues and re-run before proceeding. Respect the workflow's **retry limits**: repeated failure usually signals a deeper issue another retry won't fix.\n\n### End\n\n1. Tracker reflects all progress, discoveries, and blockers.\n2. Tracker says clearly what the next Turn should do first.\n3. If all work is verified: append the completion marker as the final non-empty line.\n4. If an unrecoverable blocker prevents progress: append the blocked marker as the final non-empty line, with a reason if you have one.\n\n## When to write the tracker\n\nWrite on **concrete triggers**, not on a vague sense of \"meaningful progress.\" The right cadence sits between every-tool-call (noisy log, wastes tokens) and end-of-Turn (everything lost if you die mid-task).\n\n- **Discrete unit done** \u2014 file written, fix applied, test run, gate passed. Reflect the new reality before starting the next unit.\n- **Insight learned** \u2014 API quirk, config field that turned out to matter, dead end ruled out, decision between two approaches. Insights are tracker-worthy even when no code changed; rediscovering them costs the next Turn a full re-exploration. The tracker is a knowledge ledger, not just a task log.\n- **About to do something risky or long-running** \u2014 subagent dispatch, long build, flaky external call, large refactor. Write _first_, then act. If the operation kills your Turn, only what's on disk survives.\n- **Plan changed** \u2014 task resequenced, new task surfaced, planned task no longer needed. Stale plans poison continuation Turns.\n- **You haven't written in a while** \u2014 if you can't remember the last update, you've gone too long. A short defensive update (\"doing X, last completed Y, next is Z\") beats nothing.\n\nEach update covers: what changed (work or knowledge), what's now next, and any caveat the next Turn needs. Don't transcribe tool calls \u2014 the tracker is a contract with your future self, not a replay log.\n\nThe cost of one extra tracker update is a few tokens. The cost of dying without one is a whole wasted Turn. Bias toward writing.\n\n## Task UI projection\n\nThe tracker is the durable source of truth. Your harness's task tools are a Turn-scoped UI projection of the same plan, shown to the user in their CLI widget. They do not survive process exit.\n\n{{TASK_TOOL_INSTRUCTIONS}}\n\n- **Turn 1, after orientation:** project the tracker's task plan into the task tools.\n- **Turn 2+, after reading the tracker:** recreate the projection from the tracker; do not assume task IDs from prior Turns still exist.\n- **During work:** update both \u2014 the task tools for immediate UI feedback, the tracker for persistence \u2014 in the same working phase.\n\n## Turn bounding\n\nEach fresh Turn starts with a clean context window and a compact tracker \u2014 effectively self-compaction. As you work, context fills with tool outputs and intermediate state. The longer you run, the more attention is spread across tokens that are no longer relevant, degrading precision on the work that matters now.\n\nWork a bounded chunk per Turn. Ending early and letting the next Turn pick up from a clean tracker is almost always better than pushing through with a heavy context. Natural checkpoints:\n\n- After a quality gate\n- After crossing multiple phases (explored \u2192 planned \u2192 wrote specs) \u2014 stop before pushing into the next\n- When your context is visibly heavy with tool output from earlier work\n\n## Quick reference\n\n- [ ] Read the tracker before doing anything else\n- [ ] Replace the skeleton immediately, even for single-Turn requests\n- [ ] Update on concrete triggers \u2014 unit done, insight learned, risky op pending, plan changed\n- [ ] Project the tracker plan into task tools at Turn start; keep both in sync as work lands\n- [ ] Follow the workflow steps as written; do not skip, reorder, or substitute your own process\n- [ ] Load the appropriate skill before each activity; do not rely on assumed knowledge\n- [ ] Use and record a dedicated git worktree for repository-changing work\n- [ ] Run quality gates in order; respect delegation constraints and retry limits\n- [ ] Write the completion marker only when all work is verified, and make it the final non-empty line\n- [ ] Checkpoint and end before context goes stale\n";
|
|
1697
1693
|
|
|
1698
1694
|
// src/core/workflows/stateMachine.ts
|
|
1699
1695
|
function buildTaskToolInstructions(harness) {
|
|
@@ -1788,7 +1784,6 @@ function resolveTrackerPath(input) {
|
|
|
1788
1784
|
function createWorkflowRunState(input) {
|
|
1789
1785
|
const { projectDir, sessionId, workflow, harness } = input;
|
|
1790
1786
|
const trackerResolved = resolveTrackerPath({ projectDir, sessionId, workflow });
|
|
1791
|
-
const loopManager = workflow?.loop?.enabled === true && trackerResolved ? createLoopManager(trackerResolved.absolutePath, workflow.loop) : null;
|
|
1792
1787
|
const { workflowOverride, warnings } = readWorkflowOverride(
|
|
1793
1788
|
projectDir,
|
|
1794
1789
|
workflow,
|
|
@@ -1798,15 +1793,16 @@ function createWorkflowRunState(input) {
|
|
|
1798
1793
|
);
|
|
1799
1794
|
return {
|
|
1800
1795
|
workflow,
|
|
1801
|
-
loopManager,
|
|
1802
1796
|
trackerPathForPrompt: trackerResolved?.promptPath,
|
|
1803
1797
|
workflowOverride,
|
|
1804
1798
|
warnings
|
|
1805
1799
|
};
|
|
1806
1800
|
}
|
|
1807
1801
|
function prepareWorkflowTurn(state, input) {
|
|
1808
|
-
const { workflow
|
|
1809
|
-
const
|
|
1802
|
+
const { workflow } = state;
|
|
1803
|
+
const iteration = input.iteration ?? 1;
|
|
1804
|
+
const isContinuation = workflow?.loop?.enabled === true && iteration > 1;
|
|
1805
|
+
const prompt = isContinuation ? buildContinuePrompt({
|
|
1810
1806
|
...workflow.loop,
|
|
1811
1807
|
trackerPath: state.trackerPathForPrompt ?? workflow.loop?.trackerPath
|
|
1812
1808
|
}) : workflow ? applyPromptTemplate(workflow.promptTemplate, input.prompt) : input.prompt;
|
|
@@ -1819,60 +1815,57 @@ function prepareWorkflowTurn(state, input) {
|
|
|
1819
1815
|
warnings: state.warnings
|
|
1820
1816
|
};
|
|
1821
1817
|
}
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1818
|
+
|
|
1819
|
+
// src/core/workflows/useWorkflowSessionController.ts
|
|
1820
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
1821
|
+
|
|
1822
|
+
// src/core/workflows/workflowRunner.ts
|
|
1823
|
+
import crypto from "crypto";
|
|
1824
|
+
import fs12 from "fs";
|
|
1825
|
+
import path9 from "path";
|
|
1826
|
+
|
|
1827
|
+
// src/core/workflows/terminalOutcome.ts
|
|
1828
|
+
import fs11 from "fs";
|
|
1829
|
+
var MISSING_TRACKER_MESSAGE = "the tracker file went missing during the run \u2014 the workflow can no longer verify progress";
|
|
1830
|
+
var SKELETON_NOT_REPLACED_MESSAGE = "tracker skeleton was never replaced \u2014 Claude did not bootstrap the tracker";
|
|
1831
|
+
var MISPLACED_TERMINAL_MARKER_MESSAGE = "terminal workflow marker is not the final non-empty line of the tracker; move all summary text above the marker";
|
|
1832
|
+
function resolveTurnOutcome(input) {
|
|
1833
|
+
const { trackerPath, loop, iteration } = input;
|
|
1834
|
+
if (!fs11.existsSync(trackerPath)) {
|
|
1830
1835
|
return {
|
|
1831
|
-
|
|
1832
|
-
|
|
1836
|
+
kind: "stop",
|
|
1837
|
+
status: "failed",
|
|
1838
|
+
stopReason: MISSING_TRACKER_MESSAGE
|
|
1833
1839
|
};
|
|
1834
1840
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1841
|
+
const tracker = parseTrackerState(readTracker(trackerPath), loop);
|
|
1842
|
+
if (tracker.skeletonNotReplaced) {
|
|
1837
1843
|
return {
|
|
1838
|
-
|
|
1839
|
-
|
|
1844
|
+
kind: "stop",
|
|
1845
|
+
status: "failed",
|
|
1846
|
+
stopReason: SKELETON_NOT_REPLACED_MESSAGE
|
|
1840
1847
|
};
|
|
1841
1848
|
}
|
|
1842
|
-
|
|
1843
|
-
if (loopState.completed) {
|
|
1844
|
-
reason = "completed";
|
|
1845
|
-
} else if (loopState.blocked) {
|
|
1846
|
-
reason = "blocked";
|
|
1847
|
-
} else if (loopState.iteration + 1 >= loopState.maxIterations) {
|
|
1848
|
-
reason = "max_iterations";
|
|
1849
|
-
}
|
|
1850
|
-
if (reason) {
|
|
1851
|
-
cleanupWorkflowRun(state);
|
|
1849
|
+
if (tracker.misplacedTerminalMarker) {
|
|
1852
1850
|
return {
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1851
|
+
kind: "stop",
|
|
1852
|
+
status: "failed",
|
|
1853
|
+
stopReason: MISPLACED_TERMINAL_MARKER_MESSAGE
|
|
1856
1854
|
};
|
|
1857
1855
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
}
|
|
1861
|
-
function cleanupWorkflowRun(state) {
|
|
1862
|
-
if (!state.loopManager) {
|
|
1863
|
-
return;
|
|
1856
|
+
if (tracker.completed) {
|
|
1857
|
+
return { kind: "stop", status: "completed" };
|
|
1864
1858
|
}
|
|
1865
|
-
|
|
1866
|
-
|
|
1859
|
+
if (tracker.blocked) {
|
|
1860
|
+
return { kind: "stop", status: "blocked", stopReason: tracker.blockedReason };
|
|
1861
|
+
}
|
|
1862
|
+
if (iteration >= loop.maxIterations) {
|
|
1863
|
+
return { kind: "stop", status: "exhausted" };
|
|
1864
|
+
}
|
|
1865
|
+
return { kind: "continue" };
|
|
1867
1866
|
}
|
|
1868
1867
|
|
|
1869
|
-
// src/core/workflows/useWorkflowSessionController.ts
|
|
1870
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
1871
|
-
|
|
1872
1868
|
// src/core/workflows/workflowRunner.ts
|
|
1873
|
-
import crypto from "crypto";
|
|
1874
|
-
import fs11 from "fs";
|
|
1875
|
-
import path9 from "path";
|
|
1876
1869
|
var NULL_TOKENS = {
|
|
1877
1870
|
input: null,
|
|
1878
1871
|
output: null,
|
|
@@ -1929,9 +1922,9 @@ function mergeTokens(base, next) {
|
|
|
1929
1922
|
};
|
|
1930
1923
|
}
|
|
1931
1924
|
function defaultCreateTracker(trackerPath, content) {
|
|
1932
|
-
|
|
1925
|
+
fs12.mkdirSync(path9.dirname(trackerPath), { recursive: true });
|
|
1933
1926
|
try {
|
|
1934
|
-
|
|
1927
|
+
fs12.writeFileSync(trackerPath, content, { encoding: "utf-8", flag: "wx" });
|
|
1935
1928
|
} catch (e) {
|
|
1936
1929
|
if (e.code !== "EEXIST") throw e;
|
|
1937
1930
|
}
|
|
@@ -1989,80 +1982,72 @@ function createWorkflowRunner(input) {
|
|
|
1989
1982
|
let nextContinuation = input.initialContinuation ?? {
|
|
1990
1983
|
mode: "fresh"
|
|
1991
1984
|
};
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
}
|
|
2018
|
-
if (turnResult.lastStderr) {
|
|
2019
|
-
parts.push(turnResult.lastStderr);
|
|
2020
|
-
}
|
|
2021
|
-
stopReason = parts.join(": ") || "Turn failed";
|
|
2022
|
-
persist();
|
|
2023
|
-
break;
|
|
2024
|
-
}
|
|
2025
|
-
const transport = turnResult.diagnostics?.transport;
|
|
2026
|
-
if (transport && transport.streamToolUses > 0 && transport.preToolUseEvents === 0) {
|
|
2027
|
-
status = "failed";
|
|
2028
|
-
stopReason = `Hook transport broken: observed ${transport.streamToolUses} tool use(s) in Claude stream but received no PreToolUse events.`;
|
|
2029
|
-
persist();
|
|
2030
|
-
break;
|
|
2031
|
-
}
|
|
2032
|
-
if (!input.workflow?.loop?.enabled) {
|
|
2033
|
-
status = "completed";
|
|
2034
|
-
persist();
|
|
2035
|
-
break;
|
|
1985
|
+
const loop = input.workflow?.loop;
|
|
1986
|
+
while (!cancelled) {
|
|
1987
|
+
iterations++;
|
|
1988
|
+
const prepared = prepareWorkflowTurn(workflowState, {
|
|
1989
|
+
prompt: input.prompt,
|
|
1990
|
+
iteration: iterations,
|
|
1991
|
+
configOverride: void 0
|
|
1992
|
+
});
|
|
1993
|
+
const turnResult = await input.startTurn({
|
|
1994
|
+
prompt: prepared.prompt,
|
|
1995
|
+
continuation: nextContinuation,
|
|
1996
|
+
configOverride: prepared.configOverride
|
|
1997
|
+
});
|
|
1998
|
+
if (cancelled) {
|
|
1999
|
+
status = "cancelled";
|
|
2000
|
+
persist();
|
|
2001
|
+
break;
|
|
2002
|
+
}
|
|
2003
|
+
cumulativeTokens = mergeTokens(cumulativeTokens, turnResult.tokens);
|
|
2004
|
+
if (turnResult.error || turnResult.exitCode !== null && turnResult.exitCode !== 0) {
|
|
2005
|
+
status = "failed";
|
|
2006
|
+
const parts = [];
|
|
2007
|
+
if (turnResult.error?.message) {
|
|
2008
|
+
parts.push(turnResult.error.message);
|
|
2009
|
+
} else if (turnResult.exitCode !== null) {
|
|
2010
|
+
parts.push(`Process exited with code ${turnResult.exitCode}`);
|
|
2036
2011
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
if (loopStop.reason === "completed") {
|
|
2040
|
-
status = "completed";
|
|
2041
|
-
} else if (loopStop.reason === "blocked") {
|
|
2042
|
-
status = "blocked";
|
|
2043
|
-
stopReason = loopStop.blockedReason;
|
|
2044
|
-
} else if (loopStop.reason === "max_iterations") {
|
|
2045
|
-
status = "exhausted";
|
|
2046
|
-
} else if (loopStop.reason === "skeleton_not_replaced") {
|
|
2047
|
-
status = "failed";
|
|
2048
|
-
stopReason = "tracker skeleton was never replaced \u2014 Claude did not bootstrap the tracker";
|
|
2049
|
-
} else {
|
|
2050
|
-
status = "failed";
|
|
2051
|
-
stopReason = `Loop stopped: ${loopStop.reason}`;
|
|
2052
|
-
}
|
|
2053
|
-
persist();
|
|
2054
|
-
break;
|
|
2012
|
+
if (turnResult.lastStderr) {
|
|
2013
|
+
parts.push(turnResult.lastStderr);
|
|
2055
2014
|
}
|
|
2015
|
+
stopReason = parts.join(": ") || "Turn failed";
|
|
2056
2016
|
persist();
|
|
2057
|
-
|
|
2058
|
-
nextContinuation = { mode: "fresh" };
|
|
2017
|
+
break;
|
|
2059
2018
|
}
|
|
2060
|
-
|
|
2061
|
-
|
|
2019
|
+
const transport = turnResult.diagnostics?.transport;
|
|
2020
|
+
if (transport && transport.streamToolUses > 0 && transport.preToolUseEvents === 0) {
|
|
2021
|
+
status = "failed";
|
|
2022
|
+
stopReason = `Hook transport broken: observed ${transport.streamToolUses} tool use(s) in Claude stream but received no PreToolUse events.`;
|
|
2062
2023
|
persist();
|
|
2024
|
+
break;
|
|
2063
2025
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2026
|
+
if (!loop?.enabled) {
|
|
2027
|
+
status = "completed";
|
|
2028
|
+
persist();
|
|
2029
|
+
break;
|
|
2030
|
+
}
|
|
2031
|
+
if (trackerAbsPath) {
|
|
2032
|
+
const outcome = resolveTurnOutcome({
|
|
2033
|
+
trackerPath: trackerAbsPath,
|
|
2034
|
+
loop,
|
|
2035
|
+
iteration: iterations
|
|
2036
|
+
});
|
|
2037
|
+
if (outcome.kind === "stop") {
|
|
2038
|
+
status = outcome.status;
|
|
2039
|
+
stopReason = outcome.stopReason;
|
|
2040
|
+
persist();
|
|
2041
|
+
break;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
persist();
|
|
2045
|
+
input.onIterationComplete?.(snapshot());
|
|
2046
|
+
nextContinuation = { mode: "fresh" };
|
|
2047
|
+
}
|
|
2048
|
+
if (cancelled && status === "running") {
|
|
2049
|
+
status = "cancelled";
|
|
2050
|
+
persist();
|
|
2066
2051
|
}
|
|
2067
2052
|
return {
|
|
2068
2053
|
runId,
|
|
@@ -2189,17 +2174,17 @@ function useWorkflowSessionController(base, input) {
|
|
|
2189
2174
|
}
|
|
2190
2175
|
|
|
2191
2176
|
// src/infra/plugins/mcpOptions.ts
|
|
2192
|
-
import
|
|
2177
|
+
import fs13 from "fs";
|
|
2193
2178
|
import path10 from "path";
|
|
2194
2179
|
function collectMcpServersWithOptions(pluginDirs) {
|
|
2195
2180
|
const result = [];
|
|
2196
2181
|
const seen = /* @__PURE__ */ new Set();
|
|
2197
2182
|
for (const dir of pluginDirs) {
|
|
2198
2183
|
const mcpPath = path10.join(dir, ".mcp.json");
|
|
2199
|
-
if (!
|
|
2184
|
+
if (!fs13.existsSync(mcpPath)) {
|
|
2200
2185
|
continue;
|
|
2201
2186
|
}
|
|
2202
|
-
const config = JSON.parse(
|
|
2187
|
+
const config = JSON.parse(fs13.readFileSync(mcpPath, "utf-8"));
|
|
2203
2188
|
for (const [serverName, serverConfig] of Object.entries(
|
|
2204
2189
|
config.mcpServers ?? {}
|
|
2205
2190
|
)) {
|
|
@@ -2244,4 +2229,4 @@ export {
|
|
|
2244
2229
|
compileWorkflowPlan,
|
|
2245
2230
|
collectMcpServersWithOptions
|
|
2246
2231
|
};
|
|
2247
|
-
//# sourceMappingURL=chunk-
|
|
2232
|
+
//# sourceMappingURL=chunk-7UUPLAP4.js.map
|