@wrongstack/core 0.5.6 → 0.6.0
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/{agent-bridge-B07AYFBk.d.ts → agent-bridge-BKNiE1VH.d.ts} +1 -1
- package/dist/{compactor-BWhJXxsW.d.ts → compactor-RIPuTtWK.d.ts} +1 -1
- package/dist/{config-BgM0BIpz.d.ts → config-BGGuP_Ar.d.ts} +1 -1
- package/dist/{context-CLZXPPYk.d.ts → context-CDRyrkKQ.d.ts} +7 -0
- package/dist/coordination/index.d.ts +9 -9
- package/dist/coordination/index.js +339 -80
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +20 -19
- package/dist/defaults/index.js +731 -180
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-qnDZbrtb.d.ts → events-DPQKFX7W.d.ts} +1 -1
- package/dist/execution/index.d.ts +152 -12
- package/dist/execution/index.js +474 -5
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/extension/index.js +2 -1
- package/dist/extension/index.js.map +1 -1
- package/dist/goal-store-BQ3YX1h1.d.ts +75 -0
- package/dist/{index-DPLJw_ZI.d.ts → index-B0qTujQW.d.ts} +52 -5
- package/dist/{index-BDnUCRvL.d.ts → index-DkdRz6yK.d.ts} +351 -15
- package/dist/index.d.ts +109 -28
- package/dist/index.js +1143 -234
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/kernel/index.d.ts +9 -9
- package/dist/{mcp-servers-CSMfaBuL.d.ts → mcp-servers-DBdh3cee.d.ts} +3 -3
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.js +2 -3
- package/dist/models/index.js.map +1 -1
- package/dist/{multi-agent-Cv8wk47i.d.ts → multi-agent-Cpp7FXUl.d.ts} +11 -3
- package/dist/observability/index.d.ts +2 -2
- package/dist/{path-resolver-DiCUvEg6.d.ts → path-resolver--g_hKJ7V.d.ts} +2 -2
- package/dist/{plan-templates-DaxTCPfk.d.ts → plan-templates-CKJs_sYh.d.ts} +9 -8
- package/dist/{provider-runner-3SHqk9zB.d.ts → provider-runner-hl4Il3xS.d.ts} +3 -3
- package/dist/{retry-policy-LLUxJmYY.d.ts → retry-policy-LKS8MHsB.d.ts} +1 -1
- package/dist/sdd/index.d.ts +6 -4
- package/dist/sdd/index.js +102 -68
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-scrubber-Z_VXuXQT.d.ts → secret-scrubber-BzQR5BiL.d.ts} +1 -1
- package/dist/{secret-scrubber-BhJTNr9v.d.ts → secret-scrubber-CfMdAJ_l.d.ts} +1 -1
- package/dist/security/index.d.ts +3 -3
- package/dist/security/index.js +82 -82
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-DB2-byKH.d.ts → selector-C7HqnZJU.d.ts} +1 -1
- package/dist/{session-reader-4jxsYLZ8.d.ts → session-reader-CzfRA6Vk.d.ts} +1 -1
- package/dist/skills/index.js +102 -38
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +6 -5
- package/dist/storage/index.js +131 -22
- package/dist/storage/index.js.map +1 -1
- package/dist/{system-prompt-DI4Dtc1I.d.ts → system-prompt-Dl2QY1_B.d.ts} +1 -1
- package/dist/{tool-executor-DSvmOBe6.d.ts → tool-executor-B03CRwu-.d.ts} +4 -4
- package/dist/types/index.d.ts +15 -15
- package/dist/types/index.js +100 -102
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/defaults/index.js
CHANGED
|
@@ -1,17 +1,104 @@
|
|
|
1
|
-
import * as fs5 from 'fs';
|
|
2
|
-
import * as path3 from 'path';
|
|
3
1
|
import * as crypto2 from 'crypto';
|
|
4
2
|
import { randomBytes, randomUUID, createCipheriv, createDecipheriv } from 'crypto';
|
|
5
3
|
import * as fsp from 'fs/promises';
|
|
4
|
+
import * as path3 from 'path';
|
|
5
|
+
import * as fs5 from 'fs';
|
|
6
6
|
import * as os from 'os';
|
|
7
|
+
import { execFile } from 'child_process';
|
|
8
|
+
import { promisify } from 'util';
|
|
7
9
|
import { EventEmitter } from 'events';
|
|
8
10
|
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
13
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
14
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
15
|
}) : x)(function(x) {
|
|
12
16
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
17
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
18
|
});
|
|
19
|
+
var __esm = (fn, res) => function __init() {
|
|
20
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
21
|
+
};
|
|
22
|
+
var __export = (target, all) => {
|
|
23
|
+
for (var name in all)
|
|
24
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// src/utils/atomic-write.ts
|
|
28
|
+
var atomic_write_exports = {};
|
|
29
|
+
__export(atomic_write_exports, {
|
|
30
|
+
atomicWrite: () => atomicWrite,
|
|
31
|
+
ensureDir: () => ensureDir
|
|
32
|
+
});
|
|
33
|
+
async function atomicWrite(targetPath, content, opts = {}) {
|
|
34
|
+
const dir = path3.dirname(targetPath);
|
|
35
|
+
await fsp.mkdir(dir, { recursive: true });
|
|
36
|
+
const tmp = path3.join(dir, `.${path3.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
37
|
+
try {
|
|
38
|
+
if (typeof content === "string") {
|
|
39
|
+
await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
40
|
+
} else {
|
|
41
|
+
await fsp.writeFile(tmp, content, { flag: "wx" });
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const fh = await fsp.open(tmp, "r+");
|
|
45
|
+
try {
|
|
46
|
+
await fh.sync();
|
|
47
|
+
} finally {
|
|
48
|
+
await fh.close();
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
let mode;
|
|
53
|
+
try {
|
|
54
|
+
const stat4 = await fsp.stat(targetPath);
|
|
55
|
+
mode = stat4.mode & 511;
|
|
56
|
+
} catch {
|
|
57
|
+
mode = opts.mode;
|
|
58
|
+
}
|
|
59
|
+
if (mode !== void 0) {
|
|
60
|
+
await fsp.chmod(tmp, mode);
|
|
61
|
+
}
|
|
62
|
+
await renameWithRetry(tmp, targetPath);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
try {
|
|
65
|
+
await fsp.unlink(tmp);
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function ensureDir(dir) {
|
|
72
|
+
await fsp.mkdir(dir, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
async function renameWithRetry(from, to) {
|
|
75
|
+
if (process.platform !== "win32") {
|
|
76
|
+
await fsp.rename(from, to);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const delays = [10, 25, 60, 120, 250];
|
|
80
|
+
let lastErr;
|
|
81
|
+
for (let i = 0; i <= delays.length; i++) {
|
|
82
|
+
try {
|
|
83
|
+
await fsp.rename(from, to);
|
|
84
|
+
return;
|
|
85
|
+
} catch (err) {
|
|
86
|
+
lastErr = err;
|
|
87
|
+
const code = err?.code;
|
|
88
|
+
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
await new Promise((resolve2) => setTimeout(resolve2, delays[i]));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw lastErr;
|
|
95
|
+
}
|
|
96
|
+
var TRANSIENT_RENAME_CODES;
|
|
97
|
+
var init_atomic_write = __esm({
|
|
98
|
+
"src/utils/atomic-write.ts"() {
|
|
99
|
+
TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
15
102
|
|
|
16
103
|
// src/utils/color.ts
|
|
17
104
|
var isColorTty = () => {
|
|
@@ -132,70 +219,9 @@ function formatCtx(ctx) {
|
|
|
132
219
|
return color.dim(String(ctx));
|
|
133
220
|
}
|
|
134
221
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const tmp = path3.join(dir, `.${path3.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
139
|
-
try {
|
|
140
|
-
if (typeof content === "string") {
|
|
141
|
-
await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
142
|
-
} else {
|
|
143
|
-
await fsp.writeFile(tmp, content, { flag: "wx" });
|
|
144
|
-
}
|
|
145
|
-
try {
|
|
146
|
-
const fh = await fsp.open(tmp, "r+");
|
|
147
|
-
try {
|
|
148
|
-
await fh.sync();
|
|
149
|
-
} finally {
|
|
150
|
-
await fh.close();
|
|
151
|
-
}
|
|
152
|
-
} catch {
|
|
153
|
-
}
|
|
154
|
-
let mode;
|
|
155
|
-
try {
|
|
156
|
-
const stat4 = await fsp.stat(targetPath);
|
|
157
|
-
mode = stat4.mode & 511;
|
|
158
|
-
} catch {
|
|
159
|
-
mode = opts.mode;
|
|
160
|
-
}
|
|
161
|
-
if (mode !== void 0) {
|
|
162
|
-
await fsp.chmod(tmp, mode);
|
|
163
|
-
}
|
|
164
|
-
await renameWithRetry(tmp, targetPath);
|
|
165
|
-
} catch (err) {
|
|
166
|
-
try {
|
|
167
|
-
await fsp.unlink(tmp);
|
|
168
|
-
} catch {
|
|
169
|
-
}
|
|
170
|
-
throw err;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
async function ensureDir(dir) {
|
|
174
|
-
await fsp.mkdir(dir, { recursive: true });
|
|
175
|
-
}
|
|
176
|
-
var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
177
|
-
async function renameWithRetry(from, to) {
|
|
178
|
-
if (process.platform !== "win32") {
|
|
179
|
-
await fsp.rename(from, to);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const delays = [10, 25, 60, 120, 250];
|
|
183
|
-
let lastErr;
|
|
184
|
-
for (let i = 0; i <= delays.length; i++) {
|
|
185
|
-
try {
|
|
186
|
-
await fsp.rename(from, to);
|
|
187
|
-
return;
|
|
188
|
-
} catch (err) {
|
|
189
|
-
lastErr = err;
|
|
190
|
-
const code = err?.code;
|
|
191
|
-
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
192
|
-
throw err;
|
|
193
|
-
}
|
|
194
|
-
await new Promise((resolve2) => setTimeout(resolve2, delays[i]));
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
throw lastErr;
|
|
198
|
-
}
|
|
222
|
+
|
|
223
|
+
// src/storage/session-store.ts
|
|
224
|
+
init_atomic_write();
|
|
199
225
|
|
|
200
226
|
// src/utils/message-invariants.ts
|
|
201
227
|
function repairToolUseAdjacency(messages) {
|
|
@@ -333,19 +359,25 @@ var DefaultSessionStore = class {
|
|
|
333
359
|
{ cause: err }
|
|
334
360
|
);
|
|
335
361
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
handle,
|
|
339
|
-
(/* @__PURE__ */ new Date()).toISOString(),
|
|
340
|
-
{
|
|
362
|
+
try {
|
|
363
|
+
const writer = new FileSessionWriter(
|
|
341
364
|
id,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
365
|
+
handle,
|
|
366
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
367
|
+
{
|
|
368
|
+
id,
|
|
369
|
+
model: data.metadata.model,
|
|
370
|
+
provider: data.metadata.provider
|
|
371
|
+
},
|
|
372
|
+
this.events,
|
|
373
|
+
{ resumed: true, dir: this.dir, filePath: file }
|
|
374
|
+
);
|
|
375
|
+
return { writer, data };
|
|
376
|
+
} catch (err) {
|
|
377
|
+
await handle.close().catch(() => {
|
|
378
|
+
});
|
|
379
|
+
throw err;
|
|
380
|
+
}
|
|
349
381
|
}
|
|
350
382
|
async load(id) {
|
|
351
383
|
const file = path3.join(this.dir, `${id}.jsonl`);
|
|
@@ -391,7 +423,7 @@ var DefaultSessionStore = class {
|
|
|
391
423
|
const full = path3.join(this.dir, `${id}.jsonl`);
|
|
392
424
|
const stat4 = await fsp.stat(full);
|
|
393
425
|
const summary = await this.summarize(id, stat4.mtime.toISOString());
|
|
394
|
-
await
|
|
426
|
+
await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
|
|
395
427
|
console.warn(
|
|
396
428
|
`[session-store] Failed to write manifest for "${id}":`,
|
|
397
429
|
err instanceof Error ? err.message : String(err)
|
|
@@ -619,7 +651,7 @@ var FileSessionWriter = class {
|
|
|
619
651
|
this.closed = true;
|
|
620
652
|
if (this.manifestFile) {
|
|
621
653
|
try {
|
|
622
|
-
await
|
|
654
|
+
await atomicWrite(this.manifestFile, JSON.stringify(this.summary), { mode: 384 });
|
|
623
655
|
} catch {
|
|
624
656
|
}
|
|
625
657
|
}
|
|
@@ -715,6 +747,9 @@ function userInputTitle(content) {
|
|
|
715
747
|
const text = content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
|
|
716
748
|
return (text || "(non-text input)").slice(0, 60);
|
|
717
749
|
}
|
|
750
|
+
|
|
751
|
+
// src/storage/queue-store.ts
|
|
752
|
+
init_atomic_write();
|
|
718
753
|
var QueueStore = class {
|
|
719
754
|
file;
|
|
720
755
|
constructor(opts) {
|
|
@@ -765,6 +800,9 @@ function isPersistedQueueItem(v) {
|
|
|
765
800
|
const o = v;
|
|
766
801
|
return typeof o["displayText"] === "string" && Array.isArray(o["blocks"]);
|
|
767
802
|
}
|
|
803
|
+
|
|
804
|
+
// src/storage/attachment-store.ts
|
|
805
|
+
init_atomic_write();
|
|
768
806
|
var DEFAULT_SPOOL_THRESHOLD = 256 * 1024;
|
|
769
807
|
var PLACEHOLDER_RE = /\[(pasted|image|file) #(\d+)\]/g;
|
|
770
808
|
var DefaultAttachmentStore = class {
|
|
@@ -786,7 +824,9 @@ var DefaultAttachmentStore = class {
|
|
|
786
824
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
787
825
|
await fsp.mkdir(this.spoolDir, { recursive: true });
|
|
788
826
|
spooledPath = path3.join(this.spoolDir, `${id}.bin`);
|
|
789
|
-
await
|
|
827
|
+
await atomicWrite(spooledPath, input.data, {
|
|
828
|
+
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
829
|
+
});
|
|
790
830
|
data = void 0;
|
|
791
831
|
}
|
|
792
832
|
const att = {
|
|
@@ -885,6 +925,9 @@ function mergeAdjacentText(blocks) {
|
|
|
885
925
|
}
|
|
886
926
|
return out;
|
|
887
927
|
}
|
|
928
|
+
|
|
929
|
+
// src/storage/memory-store.ts
|
|
930
|
+
init_atomic_write();
|
|
888
931
|
var MAX_BYTES_TOTAL = 32e3;
|
|
889
932
|
var DefaultMemoryStore = class {
|
|
890
933
|
files;
|
|
@@ -897,12 +940,13 @@ var DefaultMemoryStore = class {
|
|
|
897
940
|
* issue order. Different scopes still proceed in parallel.
|
|
898
941
|
*
|
|
899
942
|
* The chain tracks only the last pending write. If a write fails, its
|
|
900
|
-
* error is caught and swallowed
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
* backup whose worst case is losing a memory consolidation pass.
|
|
943
|
+
* error is caught and swallowed so the chain stays alive for subsequent
|
|
944
|
+
* calls. The error is stored in `writeErrors` so callers can learn about
|
|
945
|
+
* it on the next read operation.
|
|
904
946
|
*/
|
|
905
947
|
writeChain = /* @__PURE__ */ new Map();
|
|
948
|
+
/** Last write error per scope — surfaced as warnings on the next readAll(). */
|
|
949
|
+
writeErrors = /* @__PURE__ */ new Map();
|
|
906
950
|
constructor(opts) {
|
|
907
951
|
this.files = {
|
|
908
952
|
"project-agents": opts.paths.inProjectAgentsFile,
|
|
@@ -912,10 +956,16 @@ var DefaultMemoryStore = class {
|
|
|
912
956
|
}
|
|
913
957
|
async runSerialized(scope, work) {
|
|
914
958
|
const prior = this.writeChain.get(scope) ?? Promise.resolve();
|
|
959
|
+
prior.catch((err) => {
|
|
960
|
+
this.writeErrors.set(scope, err);
|
|
961
|
+
});
|
|
915
962
|
const next = prior.catch(() => void 0).then(work);
|
|
916
963
|
this.writeChain.set(scope, next);
|
|
917
964
|
try {
|
|
918
965
|
return await next;
|
|
966
|
+
} catch (err) {
|
|
967
|
+
this.writeErrors.set(scope, err);
|
|
968
|
+
throw err;
|
|
919
969
|
} finally {
|
|
920
970
|
if (this.writeChain.get(scope) === next) {
|
|
921
971
|
this.writeChain.delete(scope);
|
|
@@ -925,6 +975,10 @@ var DefaultMemoryStore = class {
|
|
|
925
975
|
async readAll() {
|
|
926
976
|
const parts = [];
|
|
927
977
|
for (const scope of ["project-agents", "project-memory", "user-memory"]) {
|
|
978
|
+
const writeErr = this.writeErrors.get(scope);
|
|
979
|
+
if (writeErr) {
|
|
980
|
+
parts.push(`> \u26A0\uFE0F Memory write error (${labelOf(scope)}): ${writeErr.message}`);
|
|
981
|
+
}
|
|
928
982
|
const body = await this.read(scope);
|
|
929
983
|
if (body.trim()) parts.push(`## ${labelOf(scope)}
|
|
930
984
|
|
|
@@ -1483,6 +1537,9 @@ function runConfigMigrations(input, targetVersion, migrations) {
|
|
|
1483
1537
|
return { config: current, applied, shouldPersist };
|
|
1484
1538
|
}
|
|
1485
1539
|
var DEFAULT_CONFIG_MIGRATIONS = [];
|
|
1540
|
+
|
|
1541
|
+
// src/storage/recovery-lock.ts
|
|
1542
|
+
init_atomic_write();
|
|
1486
1543
|
var LOCK_FILE = "active.json";
|
|
1487
1544
|
var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
1488
1545
|
var RecoveryLock = class {
|
|
@@ -1999,6 +2056,9 @@ var SessionAnalyzer = class {
|
|
|
1999
2056
|
return last - first;
|
|
2000
2057
|
}
|
|
2001
2058
|
};
|
|
2059
|
+
|
|
2060
|
+
// src/storage/todos-checkpoint.ts
|
|
2061
|
+
init_atomic_write();
|
|
2002
2062
|
async function loadTodosCheckpoint(filePath) {
|
|
2003
2063
|
let raw;
|
|
2004
2064
|
try {
|
|
@@ -2067,6 +2127,9 @@ function attachTodosCheckpoint(state, filePath, sessionId) {
|
|
|
2067
2127
|
}
|
|
2068
2128
|
};
|
|
2069
2129
|
}
|
|
2130
|
+
|
|
2131
|
+
// src/storage/plan-store.ts
|
|
2132
|
+
init_atomic_write();
|
|
2070
2133
|
async function loadPlan(filePath) {
|
|
2071
2134
|
let raw;
|
|
2072
2135
|
try {
|
|
@@ -2301,6 +2364,9 @@ ${cat}:`);
|
|
|
2301
2364
|
}
|
|
2302
2365
|
return lines.join("\n");
|
|
2303
2366
|
}
|
|
2367
|
+
|
|
2368
|
+
// src/storage/director-state.ts
|
|
2369
|
+
init_atomic_write();
|
|
2304
2370
|
async function loadDirectorState(filePath) {
|
|
2305
2371
|
let raw;
|
|
2306
2372
|
try {
|
|
@@ -2523,15 +2589,15 @@ var PATTERNS = [
|
|
|
2523
2589
|
{ type: "redis_uri", regex: /redis:\/\/[^\s"'`]+/g },
|
|
2524
2590
|
{
|
|
2525
2591
|
type: "bearer_token",
|
|
2526
|
-
//
|
|
2527
|
-
//
|
|
2528
|
-
regex: /(
|
|
2592
|
+
// Anchored with alternation instead of negative lookahead — avoids V8
|
|
2593
|
+
// backtracking risk on adversarial input. Bounded at 512 chars.
|
|
2594
|
+
regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{20,512}=*(?:$|[^A-Za-z0-9_.~+/-])/g
|
|
2529
2595
|
},
|
|
2530
2596
|
{
|
|
2531
2597
|
type: "high_entropy_env",
|
|
2532
|
-
//
|
|
2533
|
-
//
|
|
2534
|
-
regex:
|
|
2598
|
+
// Anchored with alternation instead of lookbehind to avoid backtracking.
|
|
2599
|
+
// Value bounded at 512 chars.
|
|
2600
|
+
regex: /(?:^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?:\s|$)/g
|
|
2535
2601
|
}
|
|
2536
2602
|
];
|
|
2537
2603
|
var SCRUB_CHUNK_BYTES = 64 * 1024;
|
|
@@ -2588,6 +2654,7 @@ var DefaultSecretScrubber = class {
|
|
|
2588
2654
|
var ENCRYPTED_PREFIX = "enc:v1:";
|
|
2589
2655
|
|
|
2590
2656
|
// src/security/secret-vault.ts
|
|
2657
|
+
init_atomic_write();
|
|
2591
2658
|
var KEY_BYTES = 32;
|
|
2592
2659
|
var IV_BYTES = 12;
|
|
2593
2660
|
var TAG_BYTES = 16;
|
|
@@ -2709,7 +2776,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
|
|
|
2709
2776
|
const merged = deepMerge2(current, patch ?? {});
|
|
2710
2777
|
const encrypted = encryptConfigSecrets(merged, vault);
|
|
2711
2778
|
await fsp.mkdir(path3.dirname(configPath), { recursive: true });
|
|
2712
|
-
await
|
|
2779
|
+
await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
2713
2780
|
try {
|
|
2714
2781
|
await fsp.chmod(configPath, 384);
|
|
2715
2782
|
} catch {
|
|
@@ -2731,7 +2798,7 @@ async function migratePlaintextSecrets(configPath, vault) {
|
|
|
2731
2798
|
const counter = { n: 0 };
|
|
2732
2799
|
const migrated = walkCount(parsed, vault, counter);
|
|
2733
2800
|
if (counter.n === 0) return { migrated: 0, file: configPath };
|
|
2734
|
-
await
|
|
2801
|
+
await atomicWrite(configPath, JSON.stringify(migrated, null, 2), { mode: 384 });
|
|
2735
2802
|
try {
|
|
2736
2803
|
await fsp.chmod(configPath, 384);
|
|
2737
2804
|
} catch {
|
|
@@ -2780,6 +2847,9 @@ function deepMerge2(a, b) {
|
|
|
2780
2847
|
return out;
|
|
2781
2848
|
}
|
|
2782
2849
|
|
|
2850
|
+
// src/security/permission-policy.ts
|
|
2851
|
+
init_atomic_write();
|
|
2852
|
+
|
|
2783
2853
|
// src/utils/glob-match.ts
|
|
2784
2854
|
function escapeRegex(s) {
|
|
2785
2855
|
return s.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
@@ -3279,7 +3349,7 @@ function buildRecoveryStrategies(opts) {
|
|
|
3279
3349
|
async attempt(err) {
|
|
3280
3350
|
if (!(err instanceof ProviderError) || err.status !== 429) return null;
|
|
3281
3351
|
const delayMs = err.body?.retryAfterMs ?? 5e3;
|
|
3282
|
-
const delay = Math.
|
|
3352
|
+
const delay = Math.min(6e4, Math.max(1e3, delayMs));
|
|
3283
3353
|
await new Promise((r) => setTimeout(r, delay));
|
|
3284
3354
|
return { action: "retry", reason: "rate_limit_backoff" };
|
|
3285
3355
|
}
|
|
@@ -5037,6 +5107,14 @@ var DoneConditionChecker = class {
|
|
|
5037
5107
|
};
|
|
5038
5108
|
}
|
|
5039
5109
|
break;
|
|
5110
|
+
case "directive":
|
|
5111
|
+
if (this.condition.maxIterations && state.iterations >= this.condition.maxIterations) {
|
|
5112
|
+
return { done: true, reason: `max iterations (${this.condition.maxIterations}) reached`, ...state };
|
|
5113
|
+
}
|
|
5114
|
+
if (this.condition.maxToolCalls && state.toolCalls >= this.condition.maxToolCalls) {
|
|
5115
|
+
return { done: true, reason: `max tool calls (${this.condition.maxToolCalls}) reached`, ...state };
|
|
5116
|
+
}
|
|
5117
|
+
break;
|
|
5040
5118
|
}
|
|
5041
5119
|
return { done: false, iterations: state.iterations, toolCalls: state.toolCalls };
|
|
5042
5120
|
}
|
|
@@ -5056,10 +5134,16 @@ var AutonomousRunner = class {
|
|
|
5056
5134
|
const offToolExecuted = this.opts.agent.events?.on?.("tool.executed", () => {
|
|
5057
5135
|
this.toolCalls++;
|
|
5058
5136
|
});
|
|
5137
|
+
const offIterationCompleted = this.opts.agent.events?.on?.("iteration.completed", () => {
|
|
5138
|
+
if (this.opts.enableAutonomousContinue && this.opts.doneCondition.type === "directive") {
|
|
5139
|
+
this.iterations++;
|
|
5140
|
+
}
|
|
5141
|
+
});
|
|
5059
5142
|
try {
|
|
5060
5143
|
return await this.runLoop();
|
|
5061
5144
|
} finally {
|
|
5062
5145
|
offToolExecuted?.();
|
|
5146
|
+
offIterationCompleted?.();
|
|
5063
5147
|
}
|
|
5064
5148
|
}
|
|
5065
5149
|
async runLoop() {
|
|
@@ -5083,12 +5167,14 @@ var AutonomousRunner = class {
|
|
|
5083
5167
|
const ctrl = new AbortController();
|
|
5084
5168
|
const timeout = setTimeout(() => ctrl.abort(), this.opts.iterationTimeoutMs ?? 3e4);
|
|
5085
5169
|
try {
|
|
5170
|
+
const isDirectiveMode = this.opts.doneCondition.type === "directive" && this.opts.enableAutonomousContinue;
|
|
5086
5171
|
const result = await this.opts.agent.run("", {
|
|
5087
5172
|
signal: ctrl.signal,
|
|
5088
|
-
maxIterations: 1,
|
|
5089
|
-
executionStrategy: "sequential"
|
|
5173
|
+
maxIterations: isDirectiveMode ? this.opts.doneCondition.maxIterations ?? 100 : 1,
|
|
5174
|
+
executionStrategy: "sequential",
|
|
5175
|
+
autonomousContinue: isDirectiveMode ? true : void 0
|
|
5090
5176
|
});
|
|
5091
|
-
this.iterations++;
|
|
5177
|
+
if (!isDirectiveMode) this.iterations++;
|
|
5092
5178
|
if (result.status === "done") {
|
|
5093
5179
|
this.lastOutput = result.finalText;
|
|
5094
5180
|
}
|
|
@@ -5141,6 +5227,399 @@ var AutonomousRunner = class {
|
|
|
5141
5227
|
}
|
|
5142
5228
|
};
|
|
5143
5229
|
|
|
5230
|
+
// src/storage/goal-store.ts
|
|
5231
|
+
init_atomic_write();
|
|
5232
|
+
var MAX_JOURNAL_ENTRIES = 500;
|
|
5233
|
+
function goalFilePath(projectRoot) {
|
|
5234
|
+
return path3.join(projectRoot, ".wrongstack", "goal.json");
|
|
5235
|
+
}
|
|
5236
|
+
async function loadGoal(filePath) {
|
|
5237
|
+
let raw;
|
|
5238
|
+
try {
|
|
5239
|
+
raw = await fsp.readFile(filePath, "utf8");
|
|
5240
|
+
} catch {
|
|
5241
|
+
return null;
|
|
5242
|
+
}
|
|
5243
|
+
try {
|
|
5244
|
+
const parsed = JSON.parse(raw);
|
|
5245
|
+
if (parsed?.version !== 1 || typeof parsed.goal !== "string" || !Array.isArray(parsed.journal)) {
|
|
5246
|
+
return null;
|
|
5247
|
+
}
|
|
5248
|
+
return parsed;
|
|
5249
|
+
} catch {
|
|
5250
|
+
return null;
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
async function saveGoal(filePath, goal) {
|
|
5254
|
+
await atomicWrite(filePath, JSON.stringify(goal, null, 2), { mode: 384 });
|
|
5255
|
+
}
|
|
5256
|
+
function appendJournal(goal, entry) {
|
|
5257
|
+
const iteration = goal.iterations + 1;
|
|
5258
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
5259
|
+
const full = { ...entry, iteration, at };
|
|
5260
|
+
const journal = [...goal.journal, full];
|
|
5261
|
+
const trimmed = journal.length > MAX_JOURNAL_ENTRIES ? journal.slice(journal.length - MAX_JOURNAL_ENTRIES) : journal;
|
|
5262
|
+
return {
|
|
5263
|
+
...goal,
|
|
5264
|
+
iterations: iteration,
|
|
5265
|
+
lastActivityAt: at,
|
|
5266
|
+
journal: trimmed
|
|
5267
|
+
};
|
|
5268
|
+
}
|
|
5269
|
+
|
|
5270
|
+
// src/execution/eternal-autonomy.ts
|
|
5271
|
+
var execFileP = promisify(execFile);
|
|
5272
|
+
var EternalAutonomyEngine = class {
|
|
5273
|
+
constructor(opts) {
|
|
5274
|
+
this.opts = opts;
|
|
5275
|
+
this.goalPath = goalFilePath(opts.projectRoot);
|
|
5276
|
+
}
|
|
5277
|
+
opts;
|
|
5278
|
+
state = "idle";
|
|
5279
|
+
stopRequested = false;
|
|
5280
|
+
consecutiveFailures = 0;
|
|
5281
|
+
currentCtrl = null;
|
|
5282
|
+
iterationsSinceCompact = 0;
|
|
5283
|
+
goalPath;
|
|
5284
|
+
/** Current engine state — readable for UIs. */
|
|
5285
|
+
get currentState() {
|
|
5286
|
+
return this.state;
|
|
5287
|
+
}
|
|
5288
|
+
/** Synchronously request stop. Resolves once the running iteration aborts. */
|
|
5289
|
+
stop() {
|
|
5290
|
+
this.stopRequested = true;
|
|
5291
|
+
this.currentCtrl?.abort();
|
|
5292
|
+
void this.persistEngineState("stopped").catch(() => {
|
|
5293
|
+
});
|
|
5294
|
+
this.state = "stopped";
|
|
5295
|
+
}
|
|
5296
|
+
/**
|
|
5297
|
+
* Mark the engine as 'running' on disk + reset stop state so a new
|
|
5298
|
+
* batch of `runOneIteration()` calls can proceed. Called by the REPL
|
|
5299
|
+
* when the user invokes `/autonomy eternal`. Idempotent.
|
|
5300
|
+
*/
|
|
5301
|
+
async prime() {
|
|
5302
|
+
this.stopRequested = false;
|
|
5303
|
+
this.state = "running";
|
|
5304
|
+
await this.persistEngineState("running").catch(() => {
|
|
5305
|
+
});
|
|
5306
|
+
}
|
|
5307
|
+
/**
|
|
5308
|
+
* Main loop. Returns when stop() is called or the goal file is removed.
|
|
5309
|
+
* Does NOT throw — every iteration is wrapped to keep the loop alive.
|
|
5310
|
+
*/
|
|
5311
|
+
async run() {
|
|
5312
|
+
this.state = "running";
|
|
5313
|
+
await this.persistEngineState("running");
|
|
5314
|
+
try {
|
|
5315
|
+
while (!this.stopRequested) {
|
|
5316
|
+
let iterationOk = false;
|
|
5317
|
+
try {
|
|
5318
|
+
iterationOk = await this.runOneIteration();
|
|
5319
|
+
} catch (err) {
|
|
5320
|
+
this.consecutiveFailures++;
|
|
5321
|
+
this.opts.onError?.(err instanceof Error ? err : new Error(String(err)), this.consecutiveFailures);
|
|
5322
|
+
await this.appendFailure("engine error", err instanceof Error ? err.message : String(err));
|
|
5323
|
+
}
|
|
5324
|
+
if (iterationOk) {
|
|
5325
|
+
this.consecutiveFailures = 0;
|
|
5326
|
+
}
|
|
5327
|
+
if (this.stopRequested) break;
|
|
5328
|
+
await sleep(this.opts.cycleGapMs ?? 1e3);
|
|
5329
|
+
}
|
|
5330
|
+
} finally {
|
|
5331
|
+
this.state = "stopped";
|
|
5332
|
+
await this.persistEngineState("stopped").catch(() => {
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
5335
|
+
}
|
|
5336
|
+
/**
|
|
5337
|
+
* Execute a single sense-decide-execute-reflect cycle.
|
|
5338
|
+
* Returns true on success, false on handled failure / no-op.
|
|
5339
|
+
*
|
|
5340
|
+
* Exposed publicly so the REPL can pace iterations from its main loop
|
|
5341
|
+
* — running the engine and the REPL as a single sequential consumer of
|
|
5342
|
+
* `agent.run()` avoids race conditions on the shared Context.
|
|
5343
|
+
*/
|
|
5344
|
+
async runOneIteration() {
|
|
5345
|
+
const goal = await loadGoal(this.goalPath);
|
|
5346
|
+
if (!goal) {
|
|
5347
|
+
this.stopRequested = true;
|
|
5348
|
+
return false;
|
|
5349
|
+
}
|
|
5350
|
+
const action = await this.decide(goal);
|
|
5351
|
+
if (!action) {
|
|
5352
|
+
await sleep(5e3);
|
|
5353
|
+
return false;
|
|
5354
|
+
}
|
|
5355
|
+
const ctrl = new AbortController();
|
|
5356
|
+
this.currentCtrl = ctrl;
|
|
5357
|
+
const timer = setTimeout(
|
|
5358
|
+
() => ctrl.abort(),
|
|
5359
|
+
this.opts.iterationTimeoutMs ?? 5 * 6e4
|
|
5360
|
+
);
|
|
5361
|
+
let status = "success";
|
|
5362
|
+
let note;
|
|
5363
|
+
const tc = this.opts.agent.ctx?.tokenCounter;
|
|
5364
|
+
const beforeUsage = tc?.total?.();
|
|
5365
|
+
const beforeCost = tc?.estimateCost?.().total;
|
|
5366
|
+
try {
|
|
5367
|
+
const result = await this.opts.agent.run(
|
|
5368
|
+
[{ type: "text", text: action.directive }],
|
|
5369
|
+
{ signal: ctrl.signal }
|
|
5370
|
+
);
|
|
5371
|
+
if (result.status === "aborted") {
|
|
5372
|
+
status = "aborted";
|
|
5373
|
+
note = "stopped by user";
|
|
5374
|
+
} else if (result.status === "failed") {
|
|
5375
|
+
status = "failure";
|
|
5376
|
+
note = result.error?.describe?.() ?? "agent run failed";
|
|
5377
|
+
} else if (result.status === "max_iterations") {
|
|
5378
|
+
status = "failure";
|
|
5379
|
+
note = `max iterations (${result.iterations})`;
|
|
5380
|
+
} else {
|
|
5381
|
+
status = "success";
|
|
5382
|
+
const tail = (result.finalText ?? "").slice(0, 240).replace(/\s+/g, " ").trim();
|
|
5383
|
+
if (tail) note = tail;
|
|
5384
|
+
}
|
|
5385
|
+
} catch (err) {
|
|
5386
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || err.message.includes("abort"));
|
|
5387
|
+
status = isAbort ? "aborted" : "failure";
|
|
5388
|
+
note = err instanceof Error ? err.message : String(err);
|
|
5389
|
+
} finally {
|
|
5390
|
+
clearTimeout(timer);
|
|
5391
|
+
this.currentCtrl = null;
|
|
5392
|
+
}
|
|
5393
|
+
const afterUsage = tc?.total?.();
|
|
5394
|
+
const afterCost = tc?.estimateCost?.().total;
|
|
5395
|
+
const tokens = beforeUsage && afterUsage ? {
|
|
5396
|
+
input: Math.max(0, afterUsage.input - beforeUsage.input),
|
|
5397
|
+
output: Math.max(0, afterUsage.output - beforeUsage.output)
|
|
5398
|
+
} : void 0;
|
|
5399
|
+
const costUsd = typeof beforeCost === "number" && typeof afterCost === "number" ? Math.max(0, afterCost - beforeCost) : void 0;
|
|
5400
|
+
await this.appendIterationEntry({
|
|
5401
|
+
source: action.source,
|
|
5402
|
+
task: action.task,
|
|
5403
|
+
status,
|
|
5404
|
+
note,
|
|
5405
|
+
tokens,
|
|
5406
|
+
costUsd
|
|
5407
|
+
});
|
|
5408
|
+
let iterationIndex = 0;
|
|
5409
|
+
try {
|
|
5410
|
+
const reloaded = await loadGoal(this.goalPath);
|
|
5411
|
+
iterationIndex = reloaded?.iterations ?? 0;
|
|
5412
|
+
} catch {
|
|
5413
|
+
}
|
|
5414
|
+
this.opts.onIteration?.({
|
|
5415
|
+
at: (this.opts.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
5416
|
+
iteration: iterationIndex,
|
|
5417
|
+
source: action.source,
|
|
5418
|
+
task: action.task,
|
|
5419
|
+
status,
|
|
5420
|
+
note,
|
|
5421
|
+
tokens,
|
|
5422
|
+
costUsd
|
|
5423
|
+
});
|
|
5424
|
+
if (status === "failure") {
|
|
5425
|
+
this.consecutiveFailures++;
|
|
5426
|
+
return false;
|
|
5427
|
+
}
|
|
5428
|
+
if (status === "aborted") {
|
|
5429
|
+
if (this.stopRequested) return false;
|
|
5430
|
+
this.consecutiveFailures++;
|
|
5431
|
+
return false;
|
|
5432
|
+
}
|
|
5433
|
+
this.iterationsSinceCompact++;
|
|
5434
|
+
await this.maybeCompact().catch((err) => {
|
|
5435
|
+
this.opts.onError?.(
|
|
5436
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
5437
|
+
this.consecutiveFailures
|
|
5438
|
+
);
|
|
5439
|
+
});
|
|
5440
|
+
return true;
|
|
5441
|
+
}
|
|
5442
|
+
/**
|
|
5443
|
+
* Run compaction when either trigger fires:
|
|
5444
|
+
* - We've done >= compactEveryNIterations since the last compact.
|
|
5445
|
+
* - Current request tokens exceed aggressiveCompactRatio * maxContext.
|
|
5446
|
+
*
|
|
5447
|
+
* The second check uses *aggressive* mode to free more headroom; the
|
|
5448
|
+
* cadence check uses non-aggressive (cheaper).
|
|
5449
|
+
*/
|
|
5450
|
+
async maybeCompact() {
|
|
5451
|
+
const compactor = this.opts.compactor;
|
|
5452
|
+
if (!compactor) return;
|
|
5453
|
+
const ctx = this.opts.agent.ctx;
|
|
5454
|
+
if (!ctx) return;
|
|
5455
|
+
const cadence = this.opts.compactEveryNIterations ?? 25;
|
|
5456
|
+
const threshold = this.opts.aggressiveCompactRatio ?? 0.85;
|
|
5457
|
+
const maxCtx = this.opts.maxContextTokens;
|
|
5458
|
+
let aggressive = false;
|
|
5459
|
+
let shouldRun = false;
|
|
5460
|
+
if (this.iterationsSinceCompact >= cadence) {
|
|
5461
|
+
shouldRun = true;
|
|
5462
|
+
}
|
|
5463
|
+
if (maxCtx && maxCtx > 0) {
|
|
5464
|
+
const used = ctx.tokenCounter?.currentRequestTokens?.();
|
|
5465
|
+
if (used) {
|
|
5466
|
+
const total = used.input + used.cacheRead;
|
|
5467
|
+
if (total / maxCtx >= threshold) {
|
|
5468
|
+
shouldRun = true;
|
|
5469
|
+
aggressive = true;
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
if (!shouldRun) return;
|
|
5474
|
+
const report = await compactor.compact(ctx, { aggressive });
|
|
5475
|
+
this.iterationsSinceCompact = 0;
|
|
5476
|
+
const saved = report.before - report.after;
|
|
5477
|
+
await this.appendIterationEntry({
|
|
5478
|
+
source: "manual",
|
|
5479
|
+
task: `compaction (${aggressive ? "aggressive" : "cadence"})`,
|
|
5480
|
+
status: "success",
|
|
5481
|
+
note: `saved ~${saved} tokens (${report.before}\u2192${report.after})`
|
|
5482
|
+
});
|
|
5483
|
+
}
|
|
5484
|
+
/**
|
|
5485
|
+
* Hybrid idea source.
|
|
5486
|
+
* 1. Pending todos on the agent's context.
|
|
5487
|
+
* 2. Dirty git working tree → propose a "review and finish this" task.
|
|
5488
|
+
* 3. Otherwise: brainstorm via the LLM against the goal.
|
|
5489
|
+
*
|
|
5490
|
+
* After failureBudget consecutive failures, force brainstorm so the
|
|
5491
|
+
* engine doesn't loop on the same broken todo or stuck git state.
|
|
5492
|
+
*/
|
|
5493
|
+
async decide(goal) {
|
|
5494
|
+
const forceBrainstorm = this.consecutiveFailures >= (this.opts.failureBudget ?? 3);
|
|
5495
|
+
if (!forceBrainstorm) {
|
|
5496
|
+
const todo = this.pickPendingTodo();
|
|
5497
|
+
if (todo) {
|
|
5498
|
+
return {
|
|
5499
|
+
source: "todo",
|
|
5500
|
+
task: todo.content,
|
|
5501
|
+
directive: this.buildDirective(goal, "todo", todo.content)
|
|
5502
|
+
};
|
|
5503
|
+
}
|
|
5504
|
+
const gitTask = await this.pickGitTask();
|
|
5505
|
+
if (gitTask) {
|
|
5506
|
+
return {
|
|
5507
|
+
source: "git",
|
|
5508
|
+
task: gitTask,
|
|
5509
|
+
directive: this.buildDirective(goal, "git", gitTask)
|
|
5510
|
+
};
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
const brainstormed = await this.brainstormTask(goal);
|
|
5514
|
+
if (!brainstormed) return null;
|
|
5515
|
+
return {
|
|
5516
|
+
source: "brainstorm",
|
|
5517
|
+
task: brainstormed,
|
|
5518
|
+
directive: this.buildDirective(goal, "brainstorm", brainstormed)
|
|
5519
|
+
};
|
|
5520
|
+
}
|
|
5521
|
+
pickPendingTodo() {
|
|
5522
|
+
const todos = this.opts.agent.ctx.todos;
|
|
5523
|
+
if (!Array.isArray(todos)) return null;
|
|
5524
|
+
return todos.find((t) => t.status === "pending") ?? null;
|
|
5525
|
+
}
|
|
5526
|
+
async pickGitTask() {
|
|
5527
|
+
let out;
|
|
5528
|
+
try {
|
|
5529
|
+
out = await (this.opts.gitStatusReader?.() ?? this.readGitStatus());
|
|
5530
|
+
} catch {
|
|
5531
|
+
return null;
|
|
5532
|
+
}
|
|
5533
|
+
const dirty = out.trim();
|
|
5534
|
+
if (!dirty) return null;
|
|
5535
|
+
const lines = dirty.split("\n").slice(0, 8);
|
|
5536
|
+
const preview = lines.join(", ");
|
|
5537
|
+
return `Inspect the dirty working tree and either finish the in-progress work or revert it. Files: ${preview}`;
|
|
5538
|
+
}
|
|
5539
|
+
async readGitStatus() {
|
|
5540
|
+
const { stdout } = await execFileP("git", ["status", "--porcelain"], {
|
|
5541
|
+
cwd: this.opts.projectRoot,
|
|
5542
|
+
timeout: 5e3
|
|
5543
|
+
});
|
|
5544
|
+
return stdout;
|
|
5545
|
+
}
|
|
5546
|
+
async brainstormTask(goal) {
|
|
5547
|
+
const lastFew = goal.journal.slice(-5).map((e) => ` - [${e.status}] ${e.task}`).join("\n");
|
|
5548
|
+
const directive = [
|
|
5549
|
+
"You are deciding the next action in an autonomous loop pursuing a long-running goal.",
|
|
5550
|
+
"",
|
|
5551
|
+
`Goal: ${goal.goal}`,
|
|
5552
|
+
"",
|
|
5553
|
+
lastFew ? `Recent iterations:
|
|
5554
|
+
${lastFew}` : "No prior iterations yet.",
|
|
5555
|
+
"",
|
|
5556
|
+
"Output ONE concrete, immediately-actionable task that advances the goal.",
|
|
5557
|
+
"Constraints:",
|
|
5558
|
+
"- One sentence, imperative form, under 200 chars.",
|
|
5559
|
+
"- No preamble, no explanation, no markdown \u2014 just the task line.",
|
|
5560
|
+
"- If recent iterations show repeated failures on the same target, pivot.",
|
|
5561
|
+
"- If the goal appears fully accomplished, output exactly: DONE"
|
|
5562
|
+
].join("\n");
|
|
5563
|
+
try {
|
|
5564
|
+
const ctrl = new AbortController();
|
|
5565
|
+
const timer = setTimeout(() => ctrl.abort(), 6e4);
|
|
5566
|
+
try {
|
|
5567
|
+
const result = await this.opts.agent.run(
|
|
5568
|
+
[{ type: "text", text: directive }],
|
|
5569
|
+
{ signal: ctrl.signal, maxIterations: 1 }
|
|
5570
|
+
);
|
|
5571
|
+
if (result.status !== "done") return null;
|
|
5572
|
+
const text = (result.finalText ?? "").trim();
|
|
5573
|
+
if (!text || text === "DONE") return null;
|
|
5574
|
+
const firstLine = text.split("\n").find((l) => l.trim().length > 0)?.trim();
|
|
5575
|
+
if (!firstLine) return null;
|
|
5576
|
+
return firstLine.slice(0, 240);
|
|
5577
|
+
} finally {
|
|
5578
|
+
clearTimeout(timer);
|
|
5579
|
+
}
|
|
5580
|
+
} catch {
|
|
5581
|
+
return null;
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
buildDirective(goal, source, task) {
|
|
5585
|
+
return [
|
|
5586
|
+
"[ETERNAL AUTONOMY \u2014 iteration directive]",
|
|
5587
|
+
"",
|
|
5588
|
+
`Goal: ${goal.goal}`,
|
|
5589
|
+
`Source: ${source}`,
|
|
5590
|
+
`Task: ${task}`,
|
|
5591
|
+
"",
|
|
5592
|
+
"Execute this task end-to-end using the tools available to you. Make the",
|
|
5593
|
+
"changes, run tests if relevant, and commit / push as appropriate. Do not",
|
|
5594
|
+
"ask for confirmation \u2014 YOLO mode is active. When the task is done, stop;",
|
|
5595
|
+
"the loop will pick the next action."
|
|
5596
|
+
].join("\n");
|
|
5597
|
+
}
|
|
5598
|
+
async appendIterationEntry(entry) {
|
|
5599
|
+
const current = await loadGoal(this.goalPath);
|
|
5600
|
+
if (!current) {
|
|
5601
|
+
return;
|
|
5602
|
+
}
|
|
5603
|
+
const updated = appendJournal(current, entry);
|
|
5604
|
+
await saveGoal(this.goalPath, updated);
|
|
5605
|
+
}
|
|
5606
|
+
async appendFailure(task, note) {
|
|
5607
|
+
await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
|
|
5608
|
+
}
|
|
5609
|
+
async persistEngineState(state) {
|
|
5610
|
+
const current = await loadGoal(this.goalPath);
|
|
5611
|
+
if (!current) return;
|
|
5612
|
+
if (current.engineState === state) return;
|
|
5613
|
+
await saveGoal(this.goalPath, { ...current, engineState: state });
|
|
5614
|
+
}
|
|
5615
|
+
};
|
|
5616
|
+
function sleep(ms) {
|
|
5617
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5620
|
+
// src/coordination/director.ts
|
|
5621
|
+
init_atomic_write();
|
|
5622
|
+
|
|
5144
5623
|
// src/coordination/in-memory-transport.ts
|
|
5145
5624
|
var InMemoryBridgeTransport = class {
|
|
5146
5625
|
subs = /* @__PURE__ */ new Map();
|
|
@@ -6431,10 +6910,10 @@ function makeSpawnTool(director, roster) {
|
|
|
6431
6910
|
const subagentId = await director.spawn(cfg);
|
|
6432
6911
|
return { subagentId, provider: cfg.provider, model: cfg.model, name: cfg.name };
|
|
6433
6912
|
} catch (err) {
|
|
6434
|
-
if (err instanceof
|
|
6913
|
+
if (err instanceof FleetSpawnBudgetError) {
|
|
6435
6914
|
return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
|
|
6436
6915
|
}
|
|
6437
|
-
if (err instanceof
|
|
6916
|
+
if (err instanceof FleetCostCapError) {
|
|
6438
6917
|
return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
|
|
6439
6918
|
}
|
|
6440
6919
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
@@ -6635,7 +7114,7 @@ function makeFleetHealthTool(director) {
|
|
|
6635
7114
|
}
|
|
6636
7115
|
|
|
6637
7116
|
// src/coordination/director.ts
|
|
6638
|
-
var
|
|
7117
|
+
var FleetSpawnBudgetError = class extends Error {
|
|
6639
7118
|
kind;
|
|
6640
7119
|
limit;
|
|
6641
7120
|
observed;
|
|
@@ -6643,13 +7122,13 @@ var DirectorBudgetError = class extends Error {
|
|
|
6643
7122
|
super(
|
|
6644
7123
|
kind === "max_spawns" ? `Director spawn budget exceeded: tried to spawn #${observed} but maxSpawns is ${limit}` : `Director spawn depth budget exceeded: this director is at depth ${observed} and maxSpawnDepth is ${limit}`
|
|
6645
7124
|
);
|
|
6646
|
-
this.name = "
|
|
7125
|
+
this.name = "FleetSpawnBudgetError";
|
|
6647
7126
|
this.kind = kind;
|
|
6648
7127
|
this.limit = limit;
|
|
6649
7128
|
this.observed = observed;
|
|
6650
7129
|
}
|
|
6651
7130
|
};
|
|
6652
|
-
var
|
|
7131
|
+
var FleetCostCapError = class extends Error {
|
|
6653
7132
|
kind;
|
|
6654
7133
|
limit;
|
|
6655
7134
|
observed;
|
|
@@ -6657,16 +7136,34 @@ var DirectorCostCapError = class extends Error {
|
|
|
6657
7136
|
super(
|
|
6658
7137
|
`Director cost cap exceeded: total fleet spend ${observed.toFixed(4)} exceeds maxCostUsd ${limit.toFixed(4)}`
|
|
6659
7138
|
);
|
|
6660
|
-
this.name = "
|
|
7139
|
+
this.name = "FleetCostCapError";
|
|
6661
7140
|
this.kind = "max_cost_usd";
|
|
6662
7141
|
this.limit = limit;
|
|
6663
7142
|
this.observed = observed;
|
|
6664
7143
|
}
|
|
6665
7144
|
};
|
|
6666
7145
|
var Director = class {
|
|
7146
|
+
/** Alias for the ICoordinator contract. `id` is retained for backward compatibility. */
|
|
7147
|
+
get coordinatorId() {
|
|
7148
|
+
return this.id;
|
|
7149
|
+
}
|
|
6667
7150
|
id;
|
|
7151
|
+
/**
|
|
7152
|
+
* The fleet event bus. Backed by `fleetManager?.fleet` when a FleetManager
|
|
7153
|
+
* is injected; otherwise own FleetBus instance (preserves existing behavior).
|
|
7154
|
+
*/
|
|
6668
7155
|
fleet;
|
|
7156
|
+
/**
|
|
7157
|
+
* Usage rollup. Backed by `fleetManager?.usage` when a FleetManager is
|
|
7158
|
+
* injected; otherwise own FleetUsageAggregator.
|
|
7159
|
+
*/
|
|
6669
7160
|
usage;
|
|
7161
|
+
/**
|
|
7162
|
+
* Optional fleet-level policy container. When provided the Director
|
|
7163
|
+
* delegates spawn budgeting, manifest entries, and checkpointing to it
|
|
7164
|
+
* instead of managing those internally. All other behavior is unchanged.
|
|
7165
|
+
*/
|
|
7166
|
+
fleetManager;
|
|
6670
7167
|
/**
|
|
6671
7168
|
* Director-side bridge endpoint. Subagents are wired to the same
|
|
6672
7169
|
* in-memory transport so the director can `ask()` them synchronously
|
|
@@ -6717,8 +7214,8 @@ var Director = class {
|
|
|
6717
7214
|
/** Debounce timer for periodic manifest writes. */
|
|
6718
7215
|
manifestTimer = null;
|
|
6719
7216
|
manifestDebounceMs;
|
|
6720
|
-
/** Fleet-wide cost cap. Infinity means no cap. */
|
|
6721
|
-
|
|
7217
|
+
/** Fleet-wide cost cap (entire fleet total, distinct from SubagentBudget limits). Infinity means no cap. */
|
|
7218
|
+
maxFleetCostUsd;
|
|
6722
7219
|
/** Max auto-extensions per subagent per budget kind before denying. */
|
|
6723
7220
|
maxBudgetExtensions;
|
|
6724
7221
|
/** Sessions root for direct subagent JSONL reads (fleet_session tool). */
|
|
@@ -6751,7 +7248,7 @@ var Director = class {
|
|
|
6751
7248
|
this.spawnDepth = opts.spawnDepth ?? 0;
|
|
6752
7249
|
this.sessionWriter = opts.sessionWriter ?? null;
|
|
6753
7250
|
this.manifestDebounceMs = opts.manifestDebounceMs ?? 2e3;
|
|
6754
|
-
this.
|
|
7251
|
+
this.maxFleetCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
|
|
6755
7252
|
this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 2;
|
|
6756
7253
|
this.sessionsRoot = opts.sessionsRoot;
|
|
6757
7254
|
this.directorRunId = opts.directorRunId ?? this.id;
|
|
@@ -6762,20 +7259,28 @@ var Director = class {
|
|
|
6762
7259
|
maxSpawnDepth: this.maxSpawnDepth,
|
|
6763
7260
|
directorBudget: opts.directorBudget
|
|
6764
7261
|
}, opts.checkpointDebounceMs ?? 250) : null;
|
|
7262
|
+
this.fleetManager = opts.fleetManager;
|
|
6765
7263
|
if (this.sharedScratchpadPath) {
|
|
6766
|
-
void fsp.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(
|
|
7264
|
+
void fsp.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(
|
|
7265
|
+
(err) => this.logShutdownError("shared_scratchpad_mkdir", err)
|
|
7266
|
+
);
|
|
6767
7267
|
}
|
|
6768
7268
|
this.transport = new InMemoryBridgeTransport();
|
|
6769
7269
|
this.bridge = new InMemoryAgentBridge(
|
|
6770
7270
|
{ agentId: this.id, coordinatorId: this.id },
|
|
6771
7271
|
this.transport
|
|
6772
7272
|
);
|
|
6773
|
-
this.
|
|
6774
|
-
|
|
6775
|
-
this.
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
7273
|
+
if (this.fleetManager) {
|
|
7274
|
+
this.fleet = this.fleetManager.fleet;
|
|
7275
|
+
this.usage = this.fleetManager.usage;
|
|
7276
|
+
} else {
|
|
7277
|
+
this.fleet = new FleetBus();
|
|
7278
|
+
this.usage = new FleetUsageAggregator(
|
|
7279
|
+
this.fleet,
|
|
7280
|
+
(id) => this.priceLookups.get(id),
|
|
7281
|
+
(id) => this.subagentMeta.get(id)
|
|
7282
|
+
);
|
|
7283
|
+
}
|
|
6779
7284
|
this.coordinator = new DefaultMultiAgentCoordinator(
|
|
6780
7285
|
{ ...opts.config, coordinatorId: this.id },
|
|
6781
7286
|
{ runner: opts.runner }
|
|
@@ -6864,7 +7369,9 @@ var Director = class {
|
|
|
6864
7369
|
if (this.manifestTimer) return;
|
|
6865
7370
|
this.manifestTimer = setTimeout(() => {
|
|
6866
7371
|
this.manifestTimer = null;
|
|
6867
|
-
void this.writeManifest().catch(
|
|
7372
|
+
void this.writeManifest().catch(
|
|
7373
|
+
(err) => this.logShutdownError("manifest_write_debounced", err)
|
|
7374
|
+
);
|
|
6868
7375
|
}, this.manifestDebounceMs);
|
|
6869
7376
|
}
|
|
6870
7377
|
/**
|
|
@@ -6877,58 +7384,73 @@ var Director = class {
|
|
|
6877
7384
|
* it the `cost` column in `usage.snapshot()` stays at 0.
|
|
6878
7385
|
*/
|
|
6879
7386
|
async spawn(config, priceLookup) {
|
|
6880
|
-
if (this.
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
if (
|
|
6889
|
-
throw new
|
|
7387
|
+
if (this.fleetManager) {
|
|
7388
|
+
const rejection = this.fleetManager.canSpawn(config);
|
|
7389
|
+
if (rejection) {
|
|
7390
|
+
if (rejection.kind === "max_spawn_depth") throw new FleetSpawnBudgetError("max_spawn_depth", rejection.limit, rejection.observed);
|
|
7391
|
+
if (rejection.kind === "max_spawns") throw new FleetSpawnBudgetError("max_spawns", rejection.limit, rejection.observed);
|
|
7392
|
+
if (rejection.kind === "max_cost_usd") throw new FleetCostCapError(rejection.limit, rejection.observed);
|
|
7393
|
+
}
|
|
7394
|
+
} else {
|
|
7395
|
+
if (this.spawnDepth >= this.maxSpawnDepth) {
|
|
7396
|
+
throw new FleetSpawnBudgetError("max_spawn_depth", this.maxSpawnDepth, this.spawnDepth);
|
|
7397
|
+
}
|
|
7398
|
+
if (this.spawnCount >= this.maxSpawns) {
|
|
7399
|
+
throw new FleetSpawnBudgetError("max_spawns", this.maxSpawns, this.spawnCount + 1);
|
|
7400
|
+
}
|
|
7401
|
+
if (this.maxFleetCostUsd < Number.POSITIVE_INFINITY) {
|
|
7402
|
+
const totalCost = this.usage.snapshot().total?.cost ?? 0;
|
|
7403
|
+
if (totalCost >= this.maxFleetCostUsd) {
|
|
7404
|
+
throw new FleetCostCapError(this.maxFleetCostUsd, totalCost);
|
|
7405
|
+
}
|
|
6890
7406
|
}
|
|
6891
7407
|
}
|
|
6892
7408
|
const result = await this.coordinator.spawn(config);
|
|
6893
|
-
this.
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
7409
|
+
if (this.fleetManager) {
|
|
7410
|
+
this.fleetManager.recordSpawn(result.subagentId, config, priceLookup);
|
|
7411
|
+
} else {
|
|
7412
|
+
this.spawnCount += 1;
|
|
7413
|
+
this.subagentMeta.set(result.subagentId, {
|
|
7414
|
+
provider: config.provider,
|
|
7415
|
+
model: config.model
|
|
7416
|
+
});
|
|
7417
|
+
if (priceLookup) this.priceLookups.set(result.subagentId, priceLookup);
|
|
7418
|
+
}
|
|
6899
7419
|
const subagentBridge = new InMemoryAgentBridge(
|
|
6900
7420
|
{ agentId: result.subagentId, coordinatorId: this.id },
|
|
6901
7421
|
this.transport
|
|
6902
7422
|
);
|
|
6903
7423
|
this.coordinator.setSubagentBridge(result.subagentId, subagentBridge);
|
|
6904
7424
|
this.subagentBridges.set(result.subagentId, subagentBridge);
|
|
6905
|
-
this.
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
role: config.role,
|
|
6909
|
-
provider: config.provider,
|
|
6910
|
-
model: config.model,
|
|
6911
|
-
taskIds: []
|
|
6912
|
-
});
|
|
6913
|
-
const spawnedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6914
|
-
this.stateCheckpoint?.recordSpawn(
|
|
6915
|
-
{
|
|
6916
|
-
id: result.subagentId,
|
|
7425
|
+
if (!this.fleetManager) {
|
|
7426
|
+
this.manifestEntries.set(result.subagentId, {
|
|
7427
|
+
subagentId: result.subagentId,
|
|
6917
7428
|
name: config.name,
|
|
6918
7429
|
role: config.role,
|
|
6919
7430
|
provider: config.provider,
|
|
6920
7431
|
model: config.model,
|
|
6921
|
-
|
|
6922
|
-
}
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
7432
|
+
taskIds: []
|
|
7433
|
+
});
|
|
7434
|
+
const spawnedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7435
|
+
this.stateCheckpoint?.recordSpawn(
|
|
7436
|
+
{
|
|
7437
|
+
id: result.subagentId,
|
|
7438
|
+
name: config.name,
|
|
7439
|
+
role: config.role,
|
|
7440
|
+
provider: config.provider,
|
|
7441
|
+
model: config.model,
|
|
7442
|
+
spawnedAt
|
|
7443
|
+
},
|
|
7444
|
+
this.spawnCount
|
|
7445
|
+
);
|
|
7446
|
+
void this.appendSessionEvent({
|
|
7447
|
+
type: "agent_spawned",
|
|
7448
|
+
ts: spawnedAt,
|
|
7449
|
+
agentId: result.subagentId,
|
|
7450
|
+
role: config.role ?? config.name
|
|
7451
|
+
});
|
|
7452
|
+
this.scheduleManifest();
|
|
7453
|
+
}
|
|
6932
7454
|
return result.subagentId;
|
|
6933
7455
|
}
|
|
6934
7456
|
/**
|
|
@@ -7040,7 +7562,7 @@ var Director = class {
|
|
|
7040
7562
|
usage: this.usage.snapshot()
|
|
7041
7563
|
};
|
|
7042
7564
|
await fsp.mkdir(path3.dirname(this.manifestPath), { recursive: true });
|
|
7043
|
-
await
|
|
7565
|
+
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
7044
7566
|
return this.manifestPath;
|
|
7045
7567
|
}
|
|
7046
7568
|
/**
|
|
@@ -7095,8 +7617,12 @@ var Director = class {
|
|
|
7095
7617
|
async assign(task) {
|
|
7096
7618
|
const taskWithId = task.id ? task : { ...task, id: randomUUID() };
|
|
7097
7619
|
if (task.subagentId) {
|
|
7098
|
-
|
|
7099
|
-
|
|
7620
|
+
if (this.fleetManager) {
|
|
7621
|
+
this.fleetManager.addTaskToSubagent(task.subagentId, taskWithId.id);
|
|
7622
|
+
} else {
|
|
7623
|
+
const entry = this.manifestEntries.get(task.subagentId);
|
|
7624
|
+
if (entry) entry.taskIds.push(taskWithId.id);
|
|
7625
|
+
}
|
|
7100
7626
|
}
|
|
7101
7627
|
await this.coordinator.assign(taskWithId);
|
|
7102
7628
|
this.taskDescriptions.set(taskWithId.id, taskWithId.description);
|
|
@@ -7294,8 +7820,9 @@ var Director = class {
|
|
|
7294
7820
|
* still permission-checked normally.
|
|
7295
7821
|
*/
|
|
7296
7822
|
tools(roster) {
|
|
7823
|
+
const effectiveRoster = roster ?? this.roster;
|
|
7297
7824
|
const t = [
|
|
7298
|
-
makeSpawnTool(this,
|
|
7825
|
+
makeSpawnTool(this, effectiveRoster),
|
|
7299
7826
|
makeAssignTool(this),
|
|
7300
7827
|
makeAwaitTasksTool(this),
|
|
7301
7828
|
makeAskTool(this),
|
|
@@ -7564,9 +8091,11 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
7564
8091
|
candidates.push(path3.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
|
|
7565
8092
|
} else {
|
|
7566
8093
|
try {
|
|
7567
|
-
const
|
|
7568
|
-
for (const
|
|
7569
|
-
|
|
8094
|
+
const entries = await fsp.readdir(opts.sessionsRoot, { withFileTypes: true });
|
|
8095
|
+
for (const entry of entries) {
|
|
8096
|
+
if (entry.isDirectory()) {
|
|
8097
|
+
candidates.push(path3.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
|
|
8098
|
+
}
|
|
7570
8099
|
}
|
|
7571
8100
|
} catch {
|
|
7572
8101
|
return void 0;
|
|
@@ -7761,6 +8290,12 @@ function makeDirectorSessionFactory(opts) {
|
|
|
7761
8290
|
}
|
|
7762
8291
|
};
|
|
7763
8292
|
}
|
|
8293
|
+
|
|
8294
|
+
// src/coordination/null-fleet-bus.ts
|
|
8295
|
+
var NULL_FLEET_BUS = new FleetBus();
|
|
8296
|
+
|
|
8297
|
+
// src/models/models-registry.ts
|
|
8298
|
+
init_atomic_write();
|
|
7764
8299
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
7765
8300
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
7766
8301
|
var FAMILY_BY_NPM = {
|
|
@@ -7929,6 +8464,9 @@ var DefaultModelsRegistry = class {
|
|
|
7929
8464
|
}
|
|
7930
8465
|
};
|
|
7931
8466
|
|
|
8467
|
+
// src/models/mode-store.ts
|
|
8468
|
+
init_atomic_write();
|
|
8469
|
+
|
|
7932
8470
|
// src/types/mode.ts
|
|
7933
8471
|
var DEFAULT_MODES = [
|
|
7934
8472
|
{
|
|
@@ -8229,10 +8767,9 @@ var DefaultModeStore = class {
|
|
|
8229
8767
|
try {
|
|
8230
8768
|
await fsp.mkdir(this.configDir, { recursive: true });
|
|
8231
8769
|
const configPath = path3.join(this.configDir, "mode.json");
|
|
8232
|
-
await
|
|
8770
|
+
await atomicWrite(
|
|
8233
8771
|
configPath,
|
|
8234
|
-
JSON.stringify({ activeMode: this.activeModeId }, null, 2)
|
|
8235
|
-
"utf8"
|
|
8772
|
+
JSON.stringify({ activeMode: this.activeModeId }, null, 2)
|
|
8236
8773
|
);
|
|
8237
8774
|
} catch {
|
|
8238
8775
|
}
|
|
@@ -9156,6 +9693,9 @@ var SpecDrivenDev = class {
|
|
|
9156
9693
|
}));
|
|
9157
9694
|
}
|
|
9158
9695
|
};
|
|
9696
|
+
|
|
9697
|
+
// src/sdd/spec-store.ts
|
|
9698
|
+
init_atomic_write();
|
|
9159
9699
|
var SpecStore = class {
|
|
9160
9700
|
baseDir;
|
|
9161
9701
|
indexPath;
|
|
@@ -9265,6 +9805,9 @@ var SpecStore = class {
|
|
|
9265
9805
|
await atomicWrite(this.indexPath, JSON.stringify(index, null, 2), { mode: 384 });
|
|
9266
9806
|
}
|
|
9267
9807
|
};
|
|
9808
|
+
|
|
9809
|
+
// src/sdd/task-graph-store.ts
|
|
9810
|
+
init_atomic_write();
|
|
9268
9811
|
function graphToJSON(graph) {
|
|
9269
9812
|
const serialisable = {
|
|
9270
9813
|
...graph,
|
|
@@ -9566,10 +10109,11 @@ var AISpecBuilder = class {
|
|
|
9566
10109
|
async saveSession() {
|
|
9567
10110
|
if (!this.sessionPath) return;
|
|
9568
10111
|
try {
|
|
9569
|
-
const
|
|
9570
|
-
const
|
|
9571
|
-
await
|
|
9572
|
-
await
|
|
10112
|
+
const fsp14 = await import('fs/promises');
|
|
10113
|
+
const path18 = await import('path');
|
|
10114
|
+
const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
|
|
10115
|
+
await fsp14.mkdir(path18.dirname(this.sessionPath), { recursive: true });
|
|
10116
|
+
await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
|
|
9573
10117
|
} catch {
|
|
9574
10118
|
}
|
|
9575
10119
|
}
|
|
@@ -9577,8 +10121,8 @@ var AISpecBuilder = class {
|
|
|
9577
10121
|
async loadSession() {
|
|
9578
10122
|
if (!this.sessionPath) return false;
|
|
9579
10123
|
try {
|
|
9580
|
-
const
|
|
9581
|
-
const raw = await
|
|
10124
|
+
const fsp14 = await import('fs/promises');
|
|
10125
|
+
const raw = await fsp14.readFile(this.sessionPath, "utf8");
|
|
9582
10126
|
const loaded = JSON.parse(raw);
|
|
9583
10127
|
if (loaded?.id && loaded?.phase && loaded?.title) {
|
|
9584
10128
|
this.session = loaded;
|
|
@@ -9592,14 +10136,21 @@ var AISpecBuilder = class {
|
|
|
9592
10136
|
async deleteSession() {
|
|
9593
10137
|
if (!this.sessionPath) return;
|
|
9594
10138
|
try {
|
|
9595
|
-
const
|
|
9596
|
-
await
|
|
10139
|
+
const fsp14 = await import('fs/promises');
|
|
10140
|
+
await fsp14.unlink(this.sessionPath);
|
|
9597
10141
|
} catch {
|
|
9598
10142
|
}
|
|
9599
10143
|
}
|
|
9600
|
-
/** Auto-save helper — calls saveSession() but never throws.
|
|
10144
|
+
/** Auto-save helper — calls saveSession() but never throws.
|
|
10145
|
+
* Failures are surfaced via process.emitWarning so a persistent
|
|
10146
|
+
* ENOSPC / EACCES doesn't silently strand session edits in memory. */
|
|
9601
10147
|
autoSave() {
|
|
9602
|
-
this.saveSession().catch(() => {
|
|
10148
|
+
this.saveSession().catch((err) => {
|
|
10149
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
10150
|
+
process.emitWarning(
|
|
10151
|
+
`SpecBuilder autoSave failed: ${detail}`,
|
|
10152
|
+
"SpecBuilderWarning"
|
|
10153
|
+
);
|
|
9603
10154
|
});
|
|
9604
10155
|
}
|
|
9605
10156
|
// ── Session Lifecycle ─────────────────────────────────────────────────────
|
|
@@ -10271,15 +10822,15 @@ function computeCriticalPath(graph, topoOrder, blockedByMap) {
|
|
|
10271
10822
|
maxId = id;
|
|
10272
10823
|
}
|
|
10273
10824
|
}
|
|
10274
|
-
const
|
|
10825
|
+
const path18 = [];
|
|
10275
10826
|
let current = maxId;
|
|
10276
10827
|
const visited = /* @__PURE__ */ new Set();
|
|
10277
10828
|
while (current && !visited.has(current)) {
|
|
10278
10829
|
visited.add(current);
|
|
10279
|
-
|
|
10830
|
+
path18.unshift(current);
|
|
10280
10831
|
current = prev.get(current) ?? null;
|
|
10281
10832
|
}
|
|
10282
|
-
return
|
|
10833
|
+
return path18;
|
|
10283
10834
|
}
|
|
10284
10835
|
function computeParallelGroups(graph, blockedByMap) {
|
|
10285
10836
|
const groups = [];
|
|
@@ -10989,7 +11540,7 @@ async function startMetricsServer(opts) {
|
|
|
10989
11540
|
const tls = opts.tls;
|
|
10990
11541
|
const useHttps = !!(tls?.cert && tls?.key);
|
|
10991
11542
|
const host = opts.host ?? "127.0.0.1";
|
|
10992
|
-
const
|
|
11543
|
+
const path18 = opts.path ?? "/metrics";
|
|
10993
11544
|
const healthPath = opts.healthPath ?? "/healthz";
|
|
10994
11545
|
const healthRegistry = opts.healthRegistry;
|
|
10995
11546
|
const listener = (req, res) => {
|
|
@@ -10999,7 +11550,7 @@ async function startMetricsServer(opts) {
|
|
|
10999
11550
|
return;
|
|
11000
11551
|
}
|
|
11001
11552
|
const url = req.url.split("?")[0];
|
|
11002
|
-
if (url ===
|
|
11553
|
+
if (url === path18) {
|
|
11003
11554
|
let body;
|
|
11004
11555
|
try {
|
|
11005
11556
|
body = renderPrometheus(opts.sink.snapshot());
|
|
@@ -11063,7 +11614,7 @@ async function startMetricsServer(opts) {
|
|
|
11063
11614
|
const protocol = useHttps ? "https" : "http";
|
|
11064
11615
|
return {
|
|
11065
11616
|
port: boundPort,
|
|
11066
|
-
url: `${protocol}://${host}:${boundPort}${
|
|
11617
|
+
url: `${protocol}://${host}:${boundPort}${path18}`,
|
|
11067
11618
|
close: () => new Promise((resolve2, reject) => {
|
|
11068
11619
|
server.close((err) => err ? reject(err) : resolve2());
|
|
11069
11620
|
})
|
|
@@ -11680,6 +12231,6 @@ var allServers = () => ({
|
|
|
11680
12231
|
"minimax-vision": { ...miniMaxVisionServer(), enabled: false }
|
|
11681
12232
|
});
|
|
11682
12233
|
|
|
11683
|
-
export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director,
|
|
12234
|
+
export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, decryptConfigSecrets2 as decryptConfigSecrets, deriveTodosFromPlanItem, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeDirectorSessionFactory, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
|
|
11684
12235
|
//# sourceMappingURL=index.js.map
|
|
11685
12236
|
//# sourceMappingURL=index.js.map
|