@wrongstack/core 0.5.7 → 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.
Files changed (38) hide show
  1. package/dist/coordination/index.d.ts +2 -2
  2. package/dist/coordination/index.js +40 -24
  3. package/dist/coordination/index.js.map +1 -1
  4. package/dist/defaults/index.d.ts +6 -5
  5. package/dist/defaults/index.js +608 -120
  6. package/dist/defaults/index.js.map +1 -1
  7. package/dist/execution/index.d.ts +136 -3
  8. package/dist/execution/index.js +455 -2
  9. package/dist/execution/index.js.map +1 -1
  10. package/dist/extension/index.d.ts +1 -1
  11. package/dist/extension/index.js +2 -1
  12. package/dist/extension/index.js.map +1 -1
  13. package/dist/goal-store-BQ3YX1h1.d.ts +75 -0
  14. package/dist/{index-j2WyAyML.d.ts → index-B0qTujQW.d.ts} +33 -1
  15. package/dist/{index-Bf9Bpkdc.d.ts → index-DkdRz6yK.d.ts} +1 -1
  16. package/dist/index.d.ts +8 -7
  17. package/dist/index.js +739 -163
  18. package/dist/index.js.map +1 -1
  19. package/dist/models/index.js +2 -3
  20. package/dist/models/index.js.map +1 -1
  21. package/dist/{plan-templates-Bveo2W8n.d.ts → plan-templates-CKJs_sYh.d.ts} +5 -4
  22. package/dist/sdd/index.d.ts +3 -1
  23. package/dist/sdd/index.js +102 -68
  24. package/dist/sdd/index.js.map +1 -1
  25. package/dist/security/index.js +82 -82
  26. package/dist/security/index.js.map +1 -1
  27. package/dist/skills/index.js +102 -38
  28. package/dist/skills/index.js.map +1 -1
  29. package/dist/storage/index.d.ts +2 -1
  30. package/dist/storage/index.js +131 -22
  31. package/dist/storage/index.js.map +1 -1
  32. package/dist/{tool-executor-DbAFkHdP.d.ts → tool-executor-B03CRwu-.d.ts} +1 -1
  33. package/dist/types/index.d.ts +2 -2
  34. package/dist/types/index.js +100 -102
  35. package/dist/types/index.js.map +1 -1
  36. package/dist/utils/index.js +5 -0
  37. package/dist/utils/index.js.map +1 -1
  38. package/package.json +1 -1
@@ -1,12 +1,13 @@
1
- export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-DbAFkHdP.js';
1
+ export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-B03CRwu-.js';
2
2
  import { g as Provider, a2 as Context } from '../context-CDRyrkKQ.js';
3
3
  import { a as Compactor, C as CompactReport } from '../compactor-RIPuTtWK.js';
4
4
  import { M as MessageSelector } from '../selector-C7HqnZJU.js';
5
5
  import { E as EventBus } from '../events-DPQKFX7W.js';
6
6
  import { c as MiddlewareHandler } from '../system-prompt-Dl2QY1_B.js';
7
7
  import { e as ContextWindowAggressiveOn, i as ContextWindowPolicy } from '../config-BGGuP_Ar.js';
8
- import { r as Agent, R as RunResult } from '../index-j2WyAyML.js';
8
+ import { r as Agent, R as RunResult } from '../index-B0qTujQW.js';
9
9
  import { D as DoneCondition } from '../multi-agent-Cpp7FXUl.js';
10
+ import { J as JournalEntry } from '../goal-store-BQ3YX1h1.js';
10
11
  import { a as SkillLoader, b as SkillManifest, S as SkillEntry } from '../skill-CxuWrsKK.js';
11
12
  import { W as WstackPaths } from '../wstack-paths-86YPFktR.js';
12
13
  import '../retry-policy-LKS8MHsB.js';
@@ -273,4 +274,136 @@ declare class AutonomousRunner {
273
274
  stop(): void;
274
275
  }
275
276
 
276
- export { AutoCompactionMiddleware, AutonomousRunner, type AutonomousRunnerOptions, DefaultSkillLoader, type DoneCheckResult, DoneConditionChecker, IntelligentCompactor, type IntelligentCompactorOptions, SelectiveCompactor, type SelectiveCompactorOptions, type SkillLoaderOptions };
277
+ /**
278
+ * Sense-decide-execute-reflect loop on top of a long-running Goal.
279
+ *
280
+ * Each iteration:
281
+ * 1. Sense — read goal, pending todos, `git status --porcelain`.
282
+ * 2. Decide — pick a source (todo / git / brainstorm) and a task.
283
+ * 3. Execute — single agent.run with a directive prompt.
284
+ * 4. Reflect — append a journal entry, persist state to disk.
285
+ *
286
+ * The loop runs forever until `stop()` is called externally (REPL SIGINT
287
+ * handler, /autonomy stop). No internal time/cost cap by design — the
288
+ * user wants "sittin sene". Failures are logged and the loop continues
289
+ * with a different source on the next tick.
290
+ */
291
+ interface EternalAutonomyOptions {
292
+ agent: Agent;
293
+ projectRoot: string;
294
+ /**
295
+ * Per-iteration agent timeout. Defaults to 5 minutes. A single hung
296
+ * provider call should not freeze the whole eternal loop.
297
+ */
298
+ iterationTimeoutMs?: number;
299
+ /**
300
+ * Minimum sleep between iterations. Defaults to 1 s — enough for
301
+ * SIGINT handlers to fire mid-loop without pegging a core when the
302
+ * provider is being rate-limited.
303
+ */
304
+ cycleGapMs?: number;
305
+ /**
306
+ * Maximum consecutive failures before the source rotation forces a
307
+ * brainstorm cycle. Default 3. Acts as a soft-recovery, not a stop.
308
+ */
309
+ failureBudget?: number;
310
+ /** Side-channel notifications (logging, UI updates). */
311
+ onIteration?: (entry: JournalEntry) => void;
312
+ onError?: (err: Error, iteration: number) => void;
313
+ /**
314
+ * Optional injected git status reader — production code uses git, tests
315
+ * stub this out so they don't shell out.
316
+ */
317
+ gitStatusReader?: () => Promise<string>;
318
+ /**
319
+ * Optional clock — tests stub for deterministic timestamps.
320
+ */
321
+ now?: () => Date;
322
+ /**
323
+ * Optional compactor. When provided, the engine runs compaction every
324
+ * `compactEveryNIterations` iterations to keep the agent's message
325
+ * history under control during multi-day eternal loops. Without
326
+ * compaction, an infinite loop will eventually overflow the provider's
327
+ * context window and start failing.
328
+ */
329
+ compactor?: Compactor;
330
+ /** How many iterations between compaction calls. Default 25. */
331
+ compactEveryNIterations?: number;
332
+ /**
333
+ * Aggressive compaction threshold. When ctx token usage exceeds this
334
+ * fraction of `maxContextTokens`, compaction runs in aggressive mode
335
+ * regardless of the iteration cadence. 0.85 by default.
336
+ */
337
+ aggressiveCompactRatio?: number;
338
+ /**
339
+ * Model's max context window in tokens. When set, the engine watches
340
+ * `currentRequestTokens()` against this and triggers aggressive compact
341
+ * before the next iteration would overflow. Omit to disable threshold
342
+ * checks (iteration cadence still applies).
343
+ */
344
+ maxContextTokens?: number;
345
+ }
346
+ type EternalEngineState = 'idle' | 'running' | 'stopped';
347
+ declare class EternalAutonomyEngine {
348
+ private readonly opts;
349
+ private state;
350
+ private stopRequested;
351
+ private consecutiveFailures;
352
+ private currentCtrl;
353
+ private iterationsSinceCompact;
354
+ private readonly goalPath;
355
+ constructor(opts: EternalAutonomyOptions);
356
+ /** Current engine state — readable for UIs. */
357
+ get currentState(): EternalEngineState;
358
+ /** Synchronously request stop. Resolves once the running iteration aborts. */
359
+ stop(): void;
360
+ /**
361
+ * Mark the engine as 'running' on disk + reset stop state so a new
362
+ * batch of `runOneIteration()` calls can proceed. Called by the REPL
363
+ * when the user invokes `/autonomy eternal`. Idempotent.
364
+ */
365
+ prime(): Promise<void>;
366
+ /**
367
+ * Main loop. Returns when stop() is called or the goal file is removed.
368
+ * Does NOT throw — every iteration is wrapped to keep the loop alive.
369
+ */
370
+ run(): Promise<void>;
371
+ /**
372
+ * Execute a single sense-decide-execute-reflect cycle.
373
+ * Returns true on success, false on handled failure / no-op.
374
+ *
375
+ * Exposed publicly so the REPL can pace iterations from its main loop
376
+ * — running the engine and the REPL as a single sequential consumer of
377
+ * `agent.run()` avoids race conditions on the shared Context.
378
+ */
379
+ runOneIteration(): Promise<boolean>;
380
+ /**
381
+ * Run compaction when either trigger fires:
382
+ * - We've done >= compactEveryNIterations since the last compact.
383
+ * - Current request tokens exceed aggressiveCompactRatio * maxContext.
384
+ *
385
+ * The second check uses *aggressive* mode to free more headroom; the
386
+ * cadence check uses non-aggressive (cheaper).
387
+ */
388
+ private maybeCompact;
389
+ /**
390
+ * Hybrid idea source.
391
+ * 1. Pending todos on the agent's context.
392
+ * 2. Dirty git working tree → propose a "review and finish this" task.
393
+ * 3. Otherwise: brainstorm via the LLM against the goal.
394
+ *
395
+ * After failureBudget consecutive failures, force brainstorm so the
396
+ * engine doesn't loop on the same broken todo or stuck git state.
397
+ */
398
+ private decide;
399
+ private pickPendingTodo;
400
+ private pickGitTask;
401
+ private readGitStatus;
402
+ private brainstormTask;
403
+ private buildDirective;
404
+ private appendIterationEntry;
405
+ private appendFailure;
406
+ private persistEngineState;
407
+ }
408
+
409
+ export { AutoCompactionMiddleware, AutonomousRunner, type AutonomousRunnerOptions, DefaultSkillLoader, type DoneCheckResult, DoneConditionChecker, EternalAutonomyEngine, type EternalAutonomyOptions, type EternalEngineState, IntelligentCompactor, type IntelligentCompactorOptions, SelectiveCompactor, type SelectiveCompactorOptions, type SkillLoaderOptions };
@@ -1,5 +1,8 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
1
3
  import * as fs from 'fs/promises';
2
4
  import * as path from 'path';
5
+ import { randomBytes } from 'crypto';
3
6
 
4
7
  // src/utils/token-estimate.ts
5
8
  var RoughTokenEstimate = (text) => Math.max(1, Math.ceil(text.length / 4));
@@ -1533,6 +1536,456 @@ var AutonomousRunner = class {
1533
1536
  this.stopped = true;
1534
1537
  }
1535
1538
  };
1539
+ async function atomicWrite(targetPath, content, opts = {}) {
1540
+ const dir = path.dirname(targetPath);
1541
+ await fs.mkdir(dir, { recursive: true });
1542
+ const tmp = path.join(dir, `.${path.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
1543
+ try {
1544
+ if (typeof content === "string") {
1545
+ await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
1546
+ } else {
1547
+ await fs.writeFile(tmp, content, { flag: "wx" });
1548
+ }
1549
+ try {
1550
+ const fh = await fs.open(tmp, "r+");
1551
+ try {
1552
+ await fh.sync();
1553
+ } finally {
1554
+ await fh.close();
1555
+ }
1556
+ } catch {
1557
+ }
1558
+ let mode;
1559
+ try {
1560
+ const stat2 = await fs.stat(targetPath);
1561
+ mode = stat2.mode & 511;
1562
+ } catch {
1563
+ mode = opts.mode;
1564
+ }
1565
+ if (mode !== void 0) {
1566
+ await fs.chmod(tmp, mode);
1567
+ }
1568
+ await renameWithRetry(tmp, targetPath);
1569
+ } catch (err) {
1570
+ try {
1571
+ await fs.unlink(tmp);
1572
+ } catch {
1573
+ }
1574
+ throw err;
1575
+ }
1576
+ }
1577
+ var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
1578
+ async function renameWithRetry(from, to) {
1579
+ if (process.platform !== "win32") {
1580
+ await fs.rename(from, to);
1581
+ return;
1582
+ }
1583
+ const delays = [10, 25, 60, 120, 250];
1584
+ let lastErr;
1585
+ for (let i = 0; i <= delays.length; i++) {
1586
+ try {
1587
+ await fs.rename(from, to);
1588
+ return;
1589
+ } catch (err) {
1590
+ lastErr = err;
1591
+ const code = err?.code;
1592
+ if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
1593
+ throw err;
1594
+ }
1595
+ await new Promise((resolve) => setTimeout(resolve, delays[i]));
1596
+ }
1597
+ }
1598
+ throw lastErr;
1599
+ }
1600
+
1601
+ // src/storage/goal-store.ts
1602
+ var MAX_JOURNAL_ENTRIES = 500;
1603
+ function goalFilePath(projectRoot) {
1604
+ return path.join(projectRoot, ".wrongstack", "goal.json");
1605
+ }
1606
+ async function loadGoal(filePath) {
1607
+ let raw;
1608
+ try {
1609
+ raw = await fs.readFile(filePath, "utf8");
1610
+ } catch {
1611
+ return null;
1612
+ }
1613
+ try {
1614
+ const parsed = JSON.parse(raw);
1615
+ if (parsed?.version !== 1 || typeof parsed.goal !== "string" || !Array.isArray(parsed.journal)) {
1616
+ return null;
1617
+ }
1618
+ return parsed;
1619
+ } catch {
1620
+ return null;
1621
+ }
1622
+ }
1623
+ async function saveGoal(filePath, goal) {
1624
+ await atomicWrite(filePath, JSON.stringify(goal, null, 2), { mode: 384 });
1625
+ }
1626
+ function appendJournal(goal, entry) {
1627
+ const iteration = goal.iterations + 1;
1628
+ const at = (/* @__PURE__ */ new Date()).toISOString();
1629
+ const full = { ...entry, iteration, at };
1630
+ const journal = [...goal.journal, full];
1631
+ const trimmed = journal.length > MAX_JOURNAL_ENTRIES ? journal.slice(journal.length - MAX_JOURNAL_ENTRIES) : journal;
1632
+ return {
1633
+ ...goal,
1634
+ iterations: iteration,
1635
+ lastActivityAt: at,
1636
+ journal: trimmed
1637
+ };
1638
+ }
1639
+
1640
+ // src/execution/eternal-autonomy.ts
1641
+ var execFileP = promisify(execFile);
1642
+ var EternalAutonomyEngine = class {
1643
+ constructor(opts) {
1644
+ this.opts = opts;
1645
+ this.goalPath = goalFilePath(opts.projectRoot);
1646
+ }
1647
+ opts;
1648
+ state = "idle";
1649
+ stopRequested = false;
1650
+ consecutiveFailures = 0;
1651
+ currentCtrl = null;
1652
+ iterationsSinceCompact = 0;
1653
+ goalPath;
1654
+ /** Current engine state — readable for UIs. */
1655
+ get currentState() {
1656
+ return this.state;
1657
+ }
1658
+ /** Synchronously request stop. Resolves once the running iteration aborts. */
1659
+ stop() {
1660
+ this.stopRequested = true;
1661
+ this.currentCtrl?.abort();
1662
+ void this.persistEngineState("stopped").catch(() => {
1663
+ });
1664
+ this.state = "stopped";
1665
+ }
1666
+ /**
1667
+ * Mark the engine as 'running' on disk + reset stop state so a new
1668
+ * batch of `runOneIteration()` calls can proceed. Called by the REPL
1669
+ * when the user invokes `/autonomy eternal`. Idempotent.
1670
+ */
1671
+ async prime() {
1672
+ this.stopRequested = false;
1673
+ this.state = "running";
1674
+ await this.persistEngineState("running").catch(() => {
1675
+ });
1676
+ }
1677
+ /**
1678
+ * Main loop. Returns when stop() is called or the goal file is removed.
1679
+ * Does NOT throw — every iteration is wrapped to keep the loop alive.
1680
+ */
1681
+ async run() {
1682
+ this.state = "running";
1683
+ await this.persistEngineState("running");
1684
+ try {
1685
+ while (!this.stopRequested) {
1686
+ let iterationOk = false;
1687
+ try {
1688
+ iterationOk = await this.runOneIteration();
1689
+ } catch (err) {
1690
+ this.consecutiveFailures++;
1691
+ this.opts.onError?.(err instanceof Error ? err : new Error(String(err)), this.consecutiveFailures);
1692
+ await this.appendFailure("engine error", err instanceof Error ? err.message : String(err));
1693
+ }
1694
+ if (iterationOk) {
1695
+ this.consecutiveFailures = 0;
1696
+ }
1697
+ if (this.stopRequested) break;
1698
+ await sleep(this.opts.cycleGapMs ?? 1e3);
1699
+ }
1700
+ } finally {
1701
+ this.state = "stopped";
1702
+ await this.persistEngineState("stopped").catch(() => {
1703
+ });
1704
+ }
1705
+ }
1706
+ /**
1707
+ * Execute a single sense-decide-execute-reflect cycle.
1708
+ * Returns true on success, false on handled failure / no-op.
1709
+ *
1710
+ * Exposed publicly so the REPL can pace iterations from its main loop
1711
+ * — running the engine and the REPL as a single sequential consumer of
1712
+ * `agent.run()` avoids race conditions on the shared Context.
1713
+ */
1714
+ async runOneIteration() {
1715
+ const goal = await loadGoal(this.goalPath);
1716
+ if (!goal) {
1717
+ this.stopRequested = true;
1718
+ return false;
1719
+ }
1720
+ const action = await this.decide(goal);
1721
+ if (!action) {
1722
+ await sleep(5e3);
1723
+ return false;
1724
+ }
1725
+ const ctrl = new AbortController();
1726
+ this.currentCtrl = ctrl;
1727
+ const timer = setTimeout(
1728
+ () => ctrl.abort(),
1729
+ this.opts.iterationTimeoutMs ?? 5 * 6e4
1730
+ );
1731
+ let status = "success";
1732
+ let note;
1733
+ const tc = this.opts.agent.ctx?.tokenCounter;
1734
+ const beforeUsage = tc?.total?.();
1735
+ const beforeCost = tc?.estimateCost?.().total;
1736
+ try {
1737
+ const result = await this.opts.agent.run(
1738
+ [{ type: "text", text: action.directive }],
1739
+ { signal: ctrl.signal }
1740
+ );
1741
+ if (result.status === "aborted") {
1742
+ status = "aborted";
1743
+ note = "stopped by user";
1744
+ } else if (result.status === "failed") {
1745
+ status = "failure";
1746
+ note = result.error?.describe?.() ?? "agent run failed";
1747
+ } else if (result.status === "max_iterations") {
1748
+ status = "failure";
1749
+ note = `max iterations (${result.iterations})`;
1750
+ } else {
1751
+ status = "success";
1752
+ const tail = (result.finalText ?? "").slice(0, 240).replace(/\s+/g, " ").trim();
1753
+ if (tail) note = tail;
1754
+ }
1755
+ } catch (err) {
1756
+ const isAbort = err instanceof Error && (err.name === "AbortError" || err.message.includes("abort"));
1757
+ status = isAbort ? "aborted" : "failure";
1758
+ note = err instanceof Error ? err.message : String(err);
1759
+ } finally {
1760
+ clearTimeout(timer);
1761
+ this.currentCtrl = null;
1762
+ }
1763
+ const afterUsage = tc?.total?.();
1764
+ const afterCost = tc?.estimateCost?.().total;
1765
+ const tokens = beforeUsage && afterUsage ? {
1766
+ input: Math.max(0, afterUsage.input - beforeUsage.input),
1767
+ output: Math.max(0, afterUsage.output - beforeUsage.output)
1768
+ } : void 0;
1769
+ const costUsd = typeof beforeCost === "number" && typeof afterCost === "number" ? Math.max(0, afterCost - beforeCost) : void 0;
1770
+ await this.appendIterationEntry({
1771
+ source: action.source,
1772
+ task: action.task,
1773
+ status,
1774
+ note,
1775
+ tokens,
1776
+ costUsd
1777
+ });
1778
+ let iterationIndex = 0;
1779
+ try {
1780
+ const reloaded = await loadGoal(this.goalPath);
1781
+ iterationIndex = reloaded?.iterations ?? 0;
1782
+ } catch {
1783
+ }
1784
+ this.opts.onIteration?.({
1785
+ at: (this.opts.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
1786
+ iteration: iterationIndex,
1787
+ source: action.source,
1788
+ task: action.task,
1789
+ status,
1790
+ note,
1791
+ tokens,
1792
+ costUsd
1793
+ });
1794
+ if (status === "failure") {
1795
+ this.consecutiveFailures++;
1796
+ return false;
1797
+ }
1798
+ if (status === "aborted") {
1799
+ if (this.stopRequested) return false;
1800
+ this.consecutiveFailures++;
1801
+ return false;
1802
+ }
1803
+ this.iterationsSinceCompact++;
1804
+ await this.maybeCompact().catch((err) => {
1805
+ this.opts.onError?.(
1806
+ err instanceof Error ? err : new Error(String(err)),
1807
+ this.consecutiveFailures
1808
+ );
1809
+ });
1810
+ return true;
1811
+ }
1812
+ /**
1813
+ * Run compaction when either trigger fires:
1814
+ * - We've done >= compactEveryNIterations since the last compact.
1815
+ * - Current request tokens exceed aggressiveCompactRatio * maxContext.
1816
+ *
1817
+ * The second check uses *aggressive* mode to free more headroom; the
1818
+ * cadence check uses non-aggressive (cheaper).
1819
+ */
1820
+ async maybeCompact() {
1821
+ const compactor = this.opts.compactor;
1822
+ if (!compactor) return;
1823
+ const ctx = this.opts.agent.ctx;
1824
+ if (!ctx) return;
1825
+ const cadence = this.opts.compactEveryNIterations ?? 25;
1826
+ const threshold = this.opts.aggressiveCompactRatio ?? 0.85;
1827
+ const maxCtx = this.opts.maxContextTokens;
1828
+ let aggressive = false;
1829
+ let shouldRun = false;
1830
+ if (this.iterationsSinceCompact >= cadence) {
1831
+ shouldRun = true;
1832
+ }
1833
+ if (maxCtx && maxCtx > 0) {
1834
+ const used = ctx.tokenCounter?.currentRequestTokens?.();
1835
+ if (used) {
1836
+ const total = used.input + used.cacheRead;
1837
+ if (total / maxCtx >= threshold) {
1838
+ shouldRun = true;
1839
+ aggressive = true;
1840
+ }
1841
+ }
1842
+ }
1843
+ if (!shouldRun) return;
1844
+ const report = await compactor.compact(ctx, { aggressive });
1845
+ this.iterationsSinceCompact = 0;
1846
+ const saved = report.before - report.after;
1847
+ await this.appendIterationEntry({
1848
+ source: "manual",
1849
+ task: `compaction (${aggressive ? "aggressive" : "cadence"})`,
1850
+ status: "success",
1851
+ note: `saved ~${saved} tokens (${report.before}\u2192${report.after})`
1852
+ });
1853
+ }
1854
+ /**
1855
+ * Hybrid idea source.
1856
+ * 1. Pending todos on the agent's context.
1857
+ * 2. Dirty git working tree → propose a "review and finish this" task.
1858
+ * 3. Otherwise: brainstorm via the LLM against the goal.
1859
+ *
1860
+ * After failureBudget consecutive failures, force brainstorm so the
1861
+ * engine doesn't loop on the same broken todo or stuck git state.
1862
+ */
1863
+ async decide(goal) {
1864
+ const forceBrainstorm = this.consecutiveFailures >= (this.opts.failureBudget ?? 3);
1865
+ if (!forceBrainstorm) {
1866
+ const todo = this.pickPendingTodo();
1867
+ if (todo) {
1868
+ return {
1869
+ source: "todo",
1870
+ task: todo.content,
1871
+ directive: this.buildDirective(goal, "todo", todo.content)
1872
+ };
1873
+ }
1874
+ const gitTask = await this.pickGitTask();
1875
+ if (gitTask) {
1876
+ return {
1877
+ source: "git",
1878
+ task: gitTask,
1879
+ directive: this.buildDirective(goal, "git", gitTask)
1880
+ };
1881
+ }
1882
+ }
1883
+ const brainstormed = await this.brainstormTask(goal);
1884
+ if (!brainstormed) return null;
1885
+ return {
1886
+ source: "brainstorm",
1887
+ task: brainstormed,
1888
+ directive: this.buildDirective(goal, "brainstorm", brainstormed)
1889
+ };
1890
+ }
1891
+ pickPendingTodo() {
1892
+ const todos = this.opts.agent.ctx.todos;
1893
+ if (!Array.isArray(todos)) return null;
1894
+ return todos.find((t) => t.status === "pending") ?? null;
1895
+ }
1896
+ async pickGitTask() {
1897
+ let out;
1898
+ try {
1899
+ out = await (this.opts.gitStatusReader?.() ?? this.readGitStatus());
1900
+ } catch {
1901
+ return null;
1902
+ }
1903
+ const dirty = out.trim();
1904
+ if (!dirty) return null;
1905
+ const lines = dirty.split("\n").slice(0, 8);
1906
+ const preview = lines.join(", ");
1907
+ return `Inspect the dirty working tree and either finish the in-progress work or revert it. Files: ${preview}`;
1908
+ }
1909
+ async readGitStatus() {
1910
+ const { stdout } = await execFileP("git", ["status", "--porcelain"], {
1911
+ cwd: this.opts.projectRoot,
1912
+ timeout: 5e3
1913
+ });
1914
+ return stdout;
1915
+ }
1916
+ async brainstormTask(goal) {
1917
+ const lastFew = goal.journal.slice(-5).map((e) => ` - [${e.status}] ${e.task}`).join("\n");
1918
+ const directive = [
1919
+ "You are deciding the next action in an autonomous loop pursuing a long-running goal.",
1920
+ "",
1921
+ `Goal: ${goal.goal}`,
1922
+ "",
1923
+ lastFew ? `Recent iterations:
1924
+ ${lastFew}` : "No prior iterations yet.",
1925
+ "",
1926
+ "Output ONE concrete, immediately-actionable task that advances the goal.",
1927
+ "Constraints:",
1928
+ "- One sentence, imperative form, under 200 chars.",
1929
+ "- No preamble, no explanation, no markdown \u2014 just the task line.",
1930
+ "- If recent iterations show repeated failures on the same target, pivot.",
1931
+ "- If the goal appears fully accomplished, output exactly: DONE"
1932
+ ].join("\n");
1933
+ try {
1934
+ const ctrl = new AbortController();
1935
+ const timer = setTimeout(() => ctrl.abort(), 6e4);
1936
+ try {
1937
+ const result = await this.opts.agent.run(
1938
+ [{ type: "text", text: directive }],
1939
+ { signal: ctrl.signal, maxIterations: 1 }
1940
+ );
1941
+ if (result.status !== "done") return null;
1942
+ const text = (result.finalText ?? "").trim();
1943
+ if (!text || text === "DONE") return null;
1944
+ const firstLine = text.split("\n").find((l) => l.trim().length > 0)?.trim();
1945
+ if (!firstLine) return null;
1946
+ return firstLine.slice(0, 240);
1947
+ } finally {
1948
+ clearTimeout(timer);
1949
+ }
1950
+ } catch {
1951
+ return null;
1952
+ }
1953
+ }
1954
+ buildDirective(goal, source, task) {
1955
+ return [
1956
+ "[ETERNAL AUTONOMY \u2014 iteration directive]",
1957
+ "",
1958
+ `Goal: ${goal.goal}`,
1959
+ `Source: ${source}`,
1960
+ `Task: ${task}`,
1961
+ "",
1962
+ "Execute this task end-to-end using the tools available to you. Make the",
1963
+ "changes, run tests if relevant, and commit / push as appropriate. Do not",
1964
+ "ask for confirmation \u2014 YOLO mode is active. When the task is done, stop;",
1965
+ "the loop will pick the next action."
1966
+ ].join("\n");
1967
+ }
1968
+ async appendIterationEntry(entry) {
1969
+ const current = await loadGoal(this.goalPath);
1970
+ if (!current) {
1971
+ return;
1972
+ }
1973
+ const updated = appendJournal(current, entry);
1974
+ await saveGoal(this.goalPath, updated);
1975
+ }
1976
+ async appendFailure(task, note) {
1977
+ await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
1978
+ }
1979
+ async persistEngineState(state) {
1980
+ const current = await loadGoal(this.goalPath);
1981
+ if (!current) return;
1982
+ if (current.engineState === state) return;
1983
+ await saveGoal(this.goalPath, { ...current, engineState: state });
1984
+ }
1985
+ };
1986
+ function sleep(ms) {
1987
+ return new Promise((resolve) => setTimeout(resolve, ms));
1988
+ }
1536
1989
 
1537
1990
  // src/types/provider.ts
1538
1991
  var ProviderError = class extends WrongStackError {
@@ -1664,7 +2117,7 @@ function buildRecoveryStrategies(opts) {
1664
2117
  async attempt(err) {
1665
2118
  if (!(err instanceof ProviderError) || err.status !== 429) return null;
1666
2119
  const delayMs = err.body?.retryAfterMs ?? 5e3;
1667
- const delay = Math.max(1e3, Math.min(delayMs, 6e4));
2120
+ const delay = Math.min(6e4, Math.max(1e3, delayMs));
1668
2121
  await new Promise((r) => setTimeout(r, delay));
1669
2122
  return { action: "retry", reason: "rate_limit_backoff" };
1670
2123
  }
@@ -1846,6 +2299,6 @@ function parseDescription(raw) {
1846
2299
  return { trigger, scope };
1847
2300
  }
1848
2301
 
1849
- export { AutoCompactionMiddleware, AutonomousRunner, DefaultErrorHandler, DefaultRetryPolicy, DefaultSkillLoader, DoneConditionChecker, HybridCompactor, IntelligentCompactor, SelectiveCompactor, ToolExecutor };
2302
+ export { AutoCompactionMiddleware, AutonomousRunner, DefaultErrorHandler, DefaultRetryPolicy, DefaultSkillLoader, DoneConditionChecker, EternalAutonomyEngine, HybridCompactor, IntelligentCompactor, SelectiveCompactor, ToolExecutor };
1850
2303
  //# sourceMappingURL=index.js.map
1851
2304
  //# sourceMappingURL=index.js.map