@visorcraft/idlehands 1.4.6 → 2.0.1

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 (180) hide show
  1. package/dist/agent/constants.js +12 -0
  2. package/dist/agent/constants.js.map +1 -0
  3. package/dist/agent/context-budget.js +103 -0
  4. package/dist/agent/context-budget.js.map +1 -0
  5. package/dist/agent/errors.js +8 -0
  6. package/dist/agent/errors.js.map +1 -0
  7. package/dist/agent/exec-helpers.js +105 -0
  8. package/dist/agent/exec-helpers.js.map +1 -0
  9. package/dist/agent/model-pick.js +21 -0
  10. package/dist/agent/model-pick.js.map +1 -0
  11. package/dist/agent/session-utils.js +63 -0
  12. package/dist/agent/session-utils.js.map +1 -0
  13. package/dist/agent/subagent-context.js +78 -0
  14. package/dist/agent/subagent-context.js.map +1 -0
  15. package/dist/agent/tool-loop-detection.js +91 -20
  16. package/dist/agent/tool-loop-detection.js.map +1 -1
  17. package/dist/agent/tool-loop-guard.js.map +1 -1
  18. package/dist/agent/tool-policy.js +54 -0
  19. package/dist/agent/tool-policy.js.map +1 -0
  20. package/dist/agent/tools-schema.js +281 -0
  21. package/dist/agent/tools-schema.js.map +1 -0
  22. package/dist/agent.js +191 -641
  23. package/dist/agent.js.map +1 -1
  24. package/dist/anton/controller.js +235 -163
  25. package/dist/anton/controller.js.map +1 -1
  26. package/dist/anton/lint-baseline.js +64 -0
  27. package/dist/anton/lint-baseline.js.map +1 -0
  28. package/dist/anton/preflight.js +7 -0
  29. package/dist/anton/preflight.js.map +1 -1
  30. package/dist/anton/prompt.js +71 -71
  31. package/dist/anton/reporter.js.map +1 -1
  32. package/dist/anton/runtime-ready.js +120 -0
  33. package/dist/anton/runtime-ready.js.map +1 -0
  34. package/dist/anton/session.js +7 -1
  35. package/dist/anton/session.js.map +1 -1
  36. package/dist/anton/verifier-utils.js +148 -0
  37. package/dist/anton/verifier-utils.js.map +1 -0
  38. package/dist/anton/verifier.js +26 -227
  39. package/dist/anton/verifier.js.map +1 -1
  40. package/dist/bot/anton-auto-pin.js +12 -0
  41. package/dist/bot/anton-auto-pin.js.map +1 -0
  42. package/dist/bot/anton-commands.js +137 -0
  43. package/dist/bot/anton-commands.js.map +1 -0
  44. package/dist/bot/anton-run.js +155 -0
  45. package/dist/bot/anton-run.js.map +1 -0
  46. package/dist/bot/anton-status-format.js +18 -0
  47. package/dist/bot/anton-status-format.js.map +1 -0
  48. package/dist/bot/basic-commands.js +114 -0
  49. package/dist/bot/basic-commands.js.map +1 -0
  50. package/dist/bot/command-format.js.map +1 -1
  51. package/dist/bot/command-logic.js +8 -728
  52. package/dist/bot/command-logic.js.map +1 -1
  53. package/dist/bot/commands.js +18 -1
  54. package/dist/bot/commands.js.map +1 -1
  55. package/dist/bot/discord-anton-autopin.js +29 -0
  56. package/dist/bot/discord-anton-autopin.js.map +1 -0
  57. package/dist/bot/discord-anton.js +45 -0
  58. package/dist/bot/discord-anton.js.map +1 -0
  59. package/dist/bot/discord-commands.js +20 -52
  60. package/dist/bot/discord-commands.js.map +1 -1
  61. package/dist/bot/discord-result.js +9 -0
  62. package/dist/bot/discord-result.js.map +1 -0
  63. package/dist/bot/discord-routing.js.map +1 -1
  64. package/dist/bot/discord.js +55 -12
  65. package/dist/bot/discord.js.map +1 -1
  66. package/dist/bot/escalation-commands.js +145 -0
  67. package/dist/bot/escalation-commands.js.map +1 -0
  68. package/dist/bot/escalation.js.map +1 -1
  69. package/dist/bot/format.js +0 -5
  70. package/dist/bot/format.js.map +1 -1
  71. package/dist/bot/git-status-command.js +28 -0
  72. package/dist/bot/git-status-command.js.map +1 -0
  73. package/dist/bot/model-endpoint.js +25 -0
  74. package/dist/bot/model-endpoint.js.map +1 -0
  75. package/dist/bot/session-history.js +61 -0
  76. package/dist/bot/session-history.js.map +1 -0
  77. package/dist/bot/session-settings.js +89 -0
  78. package/dist/bot/session-settings.js.map +1 -0
  79. package/dist/bot/telegram-commands.js +15 -7
  80. package/dist/bot/telegram-commands.js.map +1 -1
  81. package/dist/bot/telegram.js +15 -29
  82. package/dist/bot/telegram.js.map +1 -1
  83. package/dist/cli/agent-turn.js +8 -2
  84. package/dist/cli/agent-turn.js.map +1 -1
  85. package/dist/cli/commands/anton.js +6 -1
  86. package/dist/cli/commands/anton.js.map +1 -1
  87. package/dist/cli/commands/model.js +1 -3
  88. package/dist/cli/commands/model.js.map +1 -1
  89. package/dist/cli/commands/project.js +1 -1
  90. package/dist/cli/commands/project.js.map +1 -1
  91. package/dist/cli/commands/secrets.js +1 -1
  92. package/dist/cli/commands/secrets.js.map +1 -1
  93. package/dist/cli/commands/session.js +22 -12
  94. package/dist/cli/commands/session.js.map +1 -1
  95. package/dist/cli/guided-onboarding.js +20 -0
  96. package/dist/cli/guided-onboarding.js.map +1 -0
  97. package/dist/cli/runtime-cmds.js +8 -133
  98. package/dist/cli/runtime-cmds.js.map +1 -1
  99. package/dist/cli/runtime-common.js +35 -0
  100. package/dist/cli/runtime-common.js.map +1 -0
  101. package/dist/cli/runtime-detect.js +12 -0
  102. package/dist/cli/runtime-detect.js.map +1 -0
  103. package/dist/cli/runtime-host-command.js +7 -0
  104. package/dist/cli/runtime-host-command.js.map +1 -0
  105. package/dist/cli/runtime-probe-defaults.js +63 -0
  106. package/dist/cli/runtime-probe-defaults.js.map +1 -0
  107. package/dist/cli/runtime-scan-ports.js +30 -0
  108. package/dist/cli/runtime-scan-ports.js.map +1 -0
  109. package/dist/cli/setup-bot-step.js +51 -0
  110. package/dist/cli/setup-bot-step.js.map +1 -0
  111. package/dist/cli/setup-runtime-forms.js +214 -0
  112. package/dist/cli/setup-runtime-forms.js.map +1 -0
  113. package/dist/cli/setup-style.js +8 -0
  114. package/dist/cli/setup-style.js.map +1 -0
  115. package/dist/cli/setup-ui.js +146 -0
  116. package/dist/cli/setup-ui.js.map +1 -0
  117. package/dist/cli/setup.js +11 -449
  118. package/dist/cli/setup.js.map +1 -1
  119. package/dist/client/error-utils.js +37 -0
  120. package/dist/client/error-utils.js.map +1 -0
  121. package/dist/client/pressure.js +77 -0
  122. package/dist/client/pressure.js.map +1 -0
  123. package/dist/client.js +24 -122
  124. package/dist/client.js.map +1 -1
  125. package/dist/config.js +31 -14
  126. package/dist/config.js.map +1 -1
  127. package/dist/git.js +8 -2
  128. package/dist/git.js.map +1 -1
  129. package/dist/history.js +418 -0
  130. package/dist/history.js.map +1 -1
  131. package/dist/hooks/types.js.map +1 -1
  132. package/dist/index.js.map +1 -1
  133. package/dist/progress/message-edit-scheduler.js.map +1 -1
  134. package/dist/progress/turn-progress.js.map +1 -1
  135. package/dist/runtime/executor.js +4 -1
  136. package/dist/runtime/executor.js.map +1 -1
  137. package/dist/runtime/health.js.map +1 -1
  138. package/dist/runtime/host-runner.js.map +1 -1
  139. package/dist/safety.js +3 -2
  140. package/dist/safety.js.map +1 -1
  141. package/dist/shared/config-utils.js.map +1 -1
  142. package/dist/tools/exec-core.js +252 -0
  143. package/dist/tools/exec-core.js.map +1 -0
  144. package/dist/tools/exec-pty.js +89 -0
  145. package/dist/tools/exec-pty.js.map +1 -0
  146. package/dist/tools/exec-utils.js +94 -0
  147. package/dist/tools/exec-utils.js.map +1 -0
  148. package/dist/tools/file-discovery.js +144 -0
  149. package/dist/tools/file-discovery.js.map +1 -0
  150. package/dist/tools/file-mutations.js +326 -0
  151. package/dist/tools/file-mutations.js.map +1 -0
  152. package/dist/tools/file-read.js +133 -0
  153. package/dist/tools/file-read.js.map +1 -0
  154. package/dist/tools/patch-apply.js +168 -0
  155. package/dist/tools/patch-apply.js.map +1 -0
  156. package/dist/tools/path-safety.js.map +1 -1
  157. package/dist/tools/replay-utils.js +25 -0
  158. package/dist/tools/replay-utils.js.map +1 -0
  159. package/dist/tools/search-utils.js +55 -0
  160. package/dist/tools/search-utils.js.map +1 -0
  161. package/dist/tools/sys-notes.js +34 -0
  162. package/dist/tools/sys-notes.js.map +1 -0
  163. package/dist/tools/text-utils.js +164 -0
  164. package/dist/tools/text-utils.js.map +1 -0
  165. package/dist/tools/undo.js +1 -1
  166. package/dist/tools/undo.js.map +1 -1
  167. package/dist/tools/vault-tools.js +36 -0
  168. package/dist/tools/vault-tools.js.map +1 -0
  169. package/dist/tools.js +19 -1460
  170. package/dist/tools.js.map +1 -1
  171. package/dist/tui/controller.js +5 -2
  172. package/dist/tui/controller.js.map +1 -1
  173. package/dist/tui/render.js.map +1 -1
  174. package/dist/utils.js +2 -2
  175. package/dist/utils.js.map +1 -1
  176. package/dist/vault.js +134 -1
  177. package/dist/vault.js.map +1 -1
  178. package/dist/watchdog.js +1 -3
  179. package/dist/watchdog.js.map +1 -1
  180. package/package.json +2 -1
@@ -0,0 +1,120 @@
1
+ import { execute, loadActiveRuntime, runOnHost } from '../runtime/executor.js';
2
+ import { waitForModelsReady } from '../runtime/health.js';
3
+ import { plan } from '../runtime/planner.js';
4
+ import { loadRuntimes } from '../runtime/store.js';
5
+ function endpointBase(endpoint) {
6
+ if (!endpoint)
7
+ return null;
8
+ const e = endpoint.trim().replace(/\/+$/, '');
9
+ if (!e)
10
+ return null;
11
+ return e.endsWith('/v1') ? e : `${e}/v1`;
12
+ }
13
+ async function probeEndpointReady(endpoint) {
14
+ const base = endpointBase(endpoint);
15
+ if (!base)
16
+ return { ok: false, reason: 'endpoint-not-configured' };
17
+ const ctrl = new AbortController();
18
+ const t = setTimeout(() => ctrl.abort(), 7000);
19
+ try {
20
+ const res = await fetch(`${base}/models`, { signal: ctrl.signal });
21
+ if (res.status === 503)
22
+ return { ok: false, reason: 'loading-http-503' };
23
+ if (!res.ok)
24
+ return { ok: false, reason: `http-${res.status}` };
25
+ return { ok: true, reason: 'ok' };
26
+ }
27
+ catch (e) {
28
+ const msg = String(e?.message ?? e).toLowerCase();
29
+ if (msg.includes('aborted'))
30
+ return { ok: false, reason: 'timeout' };
31
+ return { ok: false, reason: msg.slice(0, 120) };
32
+ }
33
+ finally {
34
+ clearTimeout(t);
35
+ }
36
+ }
37
+ export function classifyInfraError(err) {
38
+ const msg = String(err?.message ?? err ?? '').toLowerCase();
39
+ if (!msg)
40
+ return 'other';
41
+ if (msg.includes('aborted') || msg.includes('cancel'))
42
+ return 'other';
43
+ if (msg.includes('503') || msg.includes('model is loading') || msg.includes('loading')) {
44
+ return 'loading';
45
+ }
46
+ const infraPatterns = [
47
+ 'econnrefused',
48
+ 'could not connect',
49
+ 'connection refused',
50
+ 'enotfound',
51
+ 'fetch failed',
52
+ 'connect timeout',
53
+ 'socket hang up',
54
+ 'no models found',
55
+ 'endpoint',
56
+ ];
57
+ if (infraPatterns.some((p) => msg.includes(p))) {
58
+ return 'infra_down';
59
+ }
60
+ return 'other';
61
+ }
62
+ export async function ensureAntonRuntimeReady(idlehandsConfig, opts) {
63
+ const endpointProbe = await probeEndpointReady(idlehandsConfig.endpoint);
64
+ if (endpointProbe.ok)
65
+ return { ok: true, detail: 'endpoint-ready' };
66
+ let rtConfig;
67
+ try {
68
+ rtConfig = await loadRuntimes();
69
+ }
70
+ catch {
71
+ return {
72
+ ok: false,
73
+ detail: `endpoint-not-ready (${endpointProbe.reason}); runtimes-unavailable`,
74
+ };
75
+ }
76
+ const active = await loadActiveRuntime();
77
+ let targetModelId;
78
+ if (active?.modelId && rtConfig.models.some((m) => m.id === active.modelId && m.enabled)) {
79
+ targetModelId = active.modelId;
80
+ }
81
+ else if (typeof idlehandsConfig.model === 'string' &&
82
+ rtConfig.models.some((m) => m.id === idlehandsConfig.model && m.enabled)) {
83
+ targetModelId = idlehandsConfig.model;
84
+ }
85
+ if (!targetModelId) {
86
+ return {
87
+ ok: false,
88
+ detail: `endpoint-not-ready (${endpointProbe.reason}); no-runtime-model-mapping`,
89
+ };
90
+ }
91
+ const planOut = plan({ modelId: targetModelId, mode: 'live', forceRestart: opts.forceRestart }, rtConfig, active);
92
+ if (!planOut.ok) {
93
+ return { ok: false, detail: `runtime-plan-failed ${planOut.code}: ${planOut.reason}` };
94
+ }
95
+ const execRes = await execute(planOut, {
96
+ force: true,
97
+ confirm: async () => true,
98
+ });
99
+ if (!execRes.ok) {
100
+ return { ok: false, detail: `runtime-exec-failed: ${execRes.error ?? 'unknown'}` };
101
+ }
102
+ const timeoutMs = Math.max(10_000, opts.timeoutMs ?? (planOut.model.launch.probe_timeout_sec ?? 600) * 1000);
103
+ for (const resolvedHost of planOut.hosts) {
104
+ const hostCfg = rtConfig.hosts.find((h) => h.id === resolvedHost.id);
105
+ if (!hostCfg)
106
+ continue;
107
+ const ready = await waitForModelsReady(runOnHost, hostCfg, planOut.model.runtime_defaults?.port ?? 8080, {
108
+ timeoutMs,
109
+ intervalMs: planOut.model.launch.probe_interval_ms ?? 2000,
110
+ });
111
+ if (!ready.ok) {
112
+ return {
113
+ ok: false,
114
+ detail: `wait-ready failed on ${resolvedHost.id}: ${ready.reason ?? 'timeout'}`,
115
+ };
116
+ }
117
+ }
118
+ return { ok: true, detail: 'runtime-ready' };
119
+ }
120
+ //# sourceMappingURL=runtime-ready.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-ready.js","sourceRoot":"","sources":["../../src/anton/runtime-ready.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Anton autonomous task runner — session config builders and factory wrapper.
3
3
  */
4
+ import path from 'node:path';
4
5
  import { createSession } from '../agent.js';
5
6
  /**
6
7
  * Build session config for main task execution sessions.
@@ -36,7 +37,8 @@ export function buildPreflightConfig(base, config, stageTimeoutSec, maxIteration
36
37
  const preflightTimeoutCapSec = Number.isFinite(config.preflightSessionTimeoutSec) &&
37
38
  Number(config.preflightSessionTimeoutSec) > 0
38
39
  ? Math.floor(Number(config.preflightSessionTimeoutSec))
39
- : 120;
40
+ : Math.max(10, Math.floor(Number(config.taskTimeoutSec) || 600));
41
+ const tasksDir = path.resolve(config.projectDir, '.agents', 'tasks');
40
42
  return {
41
43
  ...base,
42
44
  dir: config.projectDir,
@@ -48,6 +50,10 @@ export function buildPreflightConfig(base, config, stageTimeoutSec, maxIteration
48
50
  timeout: Math.max(10, Math.min(Math.floor(stageTimeoutSec), preflightTimeoutCapSec)),
49
51
  compact_at: 0.65,
50
52
  compact_min_tail: 4,
53
+ // Preflight can write only plan artifacts under .agents/tasks.
54
+ allowed_write_roots: [tasksDir],
55
+ require_dir_pin_for_mutations: false,
56
+ dir_pinned: true,
51
57
  no_tools: false,
52
58
  trifecta: { enabled: false },
53
59
  mcp: { servers: [] },
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/anton/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/anton/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAK5C;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAqB,EAAE,MAAsB;IAC9E,MAAM,iBAAiB,GACrB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,MAAM,CAAC,iBAAiB,GAAG,CAAC;QACvE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC;QACtC,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,GAAG,IAAI;QACP,GAAG,EAAE,MAAM,CAAC,UAAU;QACtB,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,UAAU,EAAE,MAAM,CAAC,YAAY,KAAK,MAAM;QAC1C,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,iBAAiB;QACjC,OAAO,EAAE,MAAM,CAAC,cAAc;QAC9B,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,CAAC;KACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAqB,EACrB,MAAsB,EACtB,eAAuB,EACvB,qBAA8B;IAE9B,MAAM,sBAAsB,GAC1B,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC;QACzE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAC3C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,6BAA6B,CAAC;YACnD,MAAM,CAAC,MAAM,CAAC,6BAA6B,CAAC,GAAG,CAAC;YAClD,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,6BAA6B,CAAC,CAAC;YAC1D,CAAC,CAAC,GAAG,CAAC;IAEZ,MAAM,sBAAsB,GAC1B,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,0BAA0B,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,GAAG,CAAC;QAC3C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;QACvD,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAErE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAErE,OAAO;QACL,GAAG,IAAI;QACP,GAAG,EAAE,MAAM,CAAC,UAAU;QACtB,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,UAAU,EAAE,MAAM,CAAC,YAAY,KAAK,MAAM;QAC1C,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,sBAAsB;QACtC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,sBAAsB,CAAC,CAAC;QACpF,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,CAAC;QACnB,+DAA+D;QAC/D,mBAAmB,EAAE,CAAC,QAAQ,CAAC;QAC/B,6BAA6B,EAAE,KAAK;QACpC,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC5B,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACvB,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;KAC/B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAqB,EACrB,MAAsB;IAEtB,OAAO;QACL,GAAG,IAAI;QACP,GAAG,EAAE,MAAM,CAAC,UAAU;QACtB,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,UAAU,EAAE,MAAM,CAAC,YAAY,KAAK,MAAM;QAC1C,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC,cAAc;QAC9B,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC5B,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACvB,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;KAC/B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAqB,EAAE,MAAsB;IAC7E,OAAO;QACL,GAAG,IAAI;QACP,GAAG,EAAE,MAAM,CAAC,UAAU;QACtB,KAAK,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,KAAK;QACvC,aAAa,EAAE,MAAe;QAC9B,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,CAAC;QACjB,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC5B,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACvB,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;KAC/B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAuB,EACvB,MAAe;IAEf,OAAO,aAAa,CAAC;QACnB,MAAM;QACN,MAAM;QACN,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,mCAAmC;KAC/D,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,148 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { getChangedFiles } from '../git.js';
3
+ /**
4
+ * If task text explicitly names files, enforce working tree changes stay in scope.
5
+ */
6
+ export function checkTaskScopeGuard(taskText, projectDir) {
7
+ const expected = extractExplicitTaskFiles(taskText);
8
+ if (expected.length === 0)
9
+ return { ok: true };
10
+ const changed = getChangedFiles(projectDir)
11
+ .map((p) => p.replace(/^\.\//, ''))
12
+ .filter(Boolean);
13
+ if (changed.length === 0)
14
+ return { ok: true };
15
+ const expectedSet = new Set(expected);
16
+ const outOfScope = changed.filter((f) => !expectedSet.has(f));
17
+ if (outOfScope.length === 0)
18
+ return { ok: true };
19
+ return {
20
+ ok: false,
21
+ reason: `Scope guard failed: task explicitly targets ${expected.join(', ')} but modified out-of-scope files`,
22
+ details: `Expected: ${expected.join(', ')}\nChanged: ${changed.join(', ')}\nOut-of-scope: ${outOfScope.join(', ')}`,
23
+ };
24
+ }
25
+ export function extractExplicitTaskFiles(taskText) {
26
+ const text = String(taskText || '');
27
+ const files = new Set();
28
+ const pathRegex = /\b([A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)+\.[A-Za-z0-9]{1,8})\b/g;
29
+ for (const m of text.matchAll(pathRegex)) {
30
+ files.add(m[1].replace(/^\.\//, ''));
31
+ }
32
+ const bareRegex = /\b([A-Za-z0-9._-]+\.[A-Za-z0-9]{1,8})\b/g;
33
+ for (const m of text.matchAll(bareRegex)) {
34
+ const file = m[1];
35
+ if (!file.includes('/'))
36
+ files.add(file);
37
+ }
38
+ return [...files];
39
+ }
40
+ export function isCommandAvailable(...cmd) {
41
+ const command = cmd.length === 1 ? cmd[0] : cmd.join(' ');
42
+ const result = spawnSync('which', [cmd[0]], {
43
+ timeout: 5000,
44
+ encoding: 'utf8',
45
+ stdio: ['ignore', 'pipe', 'ignore'],
46
+ });
47
+ if (result.status !== 0)
48
+ return false;
49
+ if (cmd.length > 1) {
50
+ const testResult = spawnSync('bash', ['-c', `${command} --help >/dev/null 2>&1`], {
51
+ timeout: 5000,
52
+ });
53
+ return testResult.status === 0;
54
+ }
55
+ return true;
56
+ }
57
+ export function makeTargetExists(cwd, target) {
58
+ try {
59
+ const result = spawnSync('make', ['-n', target], {
60
+ cwd,
61
+ timeout: 5000,
62
+ stdio: ['ignore', 'ignore', 'pipe'],
63
+ });
64
+ return result.status === 0;
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ }
70
+ export function truncateOutput(text, maxLen = 2000) {
71
+ const cleaned = text.trim();
72
+ return cleaned.length > maxLen ? `${cleaned.slice(0, maxLen)}...` : cleaned;
73
+ }
74
+ export function combineOutput(label, stdout, stderr) {
75
+ const parts = [`=== ${label} ===`];
76
+ const out = stdout.trim();
77
+ const err = stderr.trim();
78
+ if (out)
79
+ parts.push(`stdout:\n${out}`);
80
+ if (err)
81
+ parts.push(`stderr:\n${err}`);
82
+ if (!out && !err)
83
+ parts.push('(no output)');
84
+ return parts.join('\n');
85
+ }
86
+ export function parseVerifierResponse(raw) {
87
+ const text = raw.trim();
88
+ // 1. Try direct JSON parse
89
+ try {
90
+ const parsed = JSON.parse(text);
91
+ if (typeof parsed.pass === 'boolean') {
92
+ return { pass: parsed.pass, reason: parsed.reason || 'No reason provided' };
93
+ }
94
+ }
95
+ catch {
96
+ /* not valid JSON, continue */
97
+ }
98
+ // 2. Try extracting JSON from markdown code fences or inline braces
99
+ const jsonMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/) || text.match(/(\{[\s\S]*?"pass"[\s\S]*?\})/);
100
+ if (jsonMatch) {
101
+ try {
102
+ const parsed = JSON.parse(jsonMatch[1].trim());
103
+ if (typeof parsed.pass === 'boolean') {
104
+ return { pass: parsed.pass, reason: parsed.reason || 'No reason provided' };
105
+ }
106
+ }
107
+ catch {
108
+ /* still not valid, continue */
109
+ }
110
+ }
111
+ // 3. Keyword inference from prose
112
+ const lower = text.toLowerCase();
113
+ const passPatterns = [
114
+ /\bpass\b/,
115
+ /\bapproved?\b/,
116
+ /\blooks?\s+good\b/,
117
+ /\bcorrect(ly)?\b/,
118
+ /\bwell[- ]implemented\b/,
119
+ /\bno\s+(issues?|problems?|concerns?)\b/,
120
+ /\bcode\s+(is\s+)?clean\b/,
121
+ /\btask\s+(is\s+)?(complete|done)\b/,
122
+ ];
123
+ const failPatterns = [
124
+ /\bfail\b/,
125
+ /\breject(ed)?\b/,
126
+ /\bnot\s+(correct|approved?)\b/,
127
+ /\bissues?\s+found\b/,
128
+ /\bproblems?\s+found\b/,
129
+ /\bbug(s)?\b/,
130
+ /\bmissing\b/,
131
+ /\bincorrect\b/,
132
+ /\bbroken\b/,
133
+ ];
134
+ const passScore = passPatterns.filter((p) => p.test(lower)).length;
135
+ const failScore = failPatterns.filter((p) => p.test(lower)).length;
136
+ if (passScore > 0 && passScore > failScore) {
137
+ const snippet = text.length > 200 ? text.slice(0, 200) + '...' : text;
138
+ return { pass: true, reason: `(inferred from prose) ${snippet}` };
139
+ }
140
+ if (failScore > 0) {
141
+ const snippet = text.length > 200 ? text.slice(0, 200) + '...' : text;
142
+ return { pass: false, reason: `(inferred from prose) ${snippet}` };
143
+ }
144
+ // 4. Ambiguous — default to pass since L1 already validated build/test
145
+ const snippet = text.length > 200 ? text.slice(0, 200) + '...' : text;
146
+ return { pass: true, reason: `(ambiguous response, defaulting to pass) ${snippet}` };
147
+ }
148
+ //# sourceMappingURL=verifier-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier-utils.js","sourceRoot":"","sources":["../../src/anton/verifier-utils.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,9 @@ import { readFileSync, existsSync } from 'node:fs';
11
11
  import { join, extname } from 'node:path';
12
12
  import { getChangedFiles } from '../git.js';
13
13
  import { runCommand } from '../runtime/executor.js';
14
+ import { countLintErrors, filterLintErrorLines } from './lint-baseline.js';
15
+ export { captureLintBaseline } from './lint-baseline.js';
16
+ import { checkTaskScopeGuard, isCommandAvailable, makeTargetExists, truncateOutput, combineOutput, parseVerifierResponse, } from './verifier-utils.js';
14
17
  /**
15
18
  * Detect verification commands based on project files and overrides.
16
19
  * Priority: overrides → package.json → Cargo.toml → Makefile → Python configs
@@ -265,9 +268,22 @@ or
265
268
  // ── Pre-verify autofix ──────────────────────────────────────────
266
269
  /** File extensions eligible for autoformat/autofix. */
267
270
  const AUTOFIX_EXTENSIONS = new Set([
268
- '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
269
- '.css', '.scss', '.less', '.json', '.md', '.yaml', '.yml',
270
- '.vue', '.svelte', '.html',
271
+ '.ts',
272
+ '.tsx',
273
+ '.js',
274
+ '.jsx',
275
+ '.mjs',
276
+ '.cjs',
277
+ '.css',
278
+ '.scss',
279
+ '.less',
280
+ '.json',
281
+ '.md',
282
+ '.yaml',
283
+ '.yml',
284
+ '.vue',
285
+ '.svelte',
286
+ '.html',
271
287
  ]);
272
288
  /**
273
289
  * Attempt to auto-fix lint/format issues on files changed in the current attempt.
@@ -306,7 +322,12 @@ export async function tryAutofixChangedFiles(projectDir) {
306
322
  // Try prettier --write (only if prettier is available)
307
323
  if (isCommandAvailable('npx')) {
308
324
  try {
309
- const prettierRes = spawnSync('npx', ['prettier', '--write', '--ignore-unknown', ...batch], { cwd: projectDir, timeout: 60_000, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
325
+ const prettierRes = spawnSync('npx', ['prettier', '--write', '--ignore-unknown', ...batch], {
326
+ cwd: projectDir,
327
+ timeout: 60_000,
328
+ encoding: 'utf8',
329
+ stdio: ['ignore', 'pipe', 'pipe'],
330
+ });
310
331
  if (prettierRes.status === 0) {
311
332
  ran = true;
312
333
  console.error(`[anton:autofix] prettier --write ran on ${batch.length} files`);
@@ -318,227 +339,5 @@ export async function tryAutofixChangedFiles(projectDir) {
318
339
  }
319
340
  return ran;
320
341
  }
321
- /**
322
- * If task text explicitly names files (e.g. "create src/foo.ts"), enforce that
323
- * working tree changes stay within that set. This prevents task scope bleed.
324
- */
325
- function checkTaskScopeGuard(taskText, projectDir) {
326
- const expected = extractExplicitTaskFiles(taskText);
327
- if (expected.length === 0)
328
- return { ok: true };
329
- const changed = getChangedFiles(projectDir)
330
- .map((p) => p.replace(/^\.\//, ''))
331
- .filter(Boolean);
332
- if (changed.length === 0)
333
- return { ok: true };
334
- const expectedSet = new Set(expected);
335
- const outOfScope = changed.filter((f) => !expectedSet.has(f));
336
- if (outOfScope.length === 0)
337
- return { ok: true };
338
- return {
339
- ok: false,
340
- reason: `Scope guard failed: task explicitly targets ${expected.join(', ')} but modified out-of-scope files`,
341
- details: `Expected: ${expected.join(', ')}\nChanged: ${changed.join(', ')}\nOut-of-scope: ${outOfScope.join(', ')}`,
342
- };
343
- }
344
- function extractExplicitTaskFiles(taskText) {
345
- const text = String(taskText || '');
346
- const files = new Set();
347
- // Common explicit path pattern (supports nested dirs and dots/dashes/underscores)
348
- const pathRegex = /\b([A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)+\.[A-Za-z0-9]{1,8})\b/g;
349
- for (const m of text.matchAll(pathRegex)) {
350
- files.add(m[1].replace(/^\.\//, ''));
351
- }
352
- // Bare filename pattern (e.g. "agent.ts")
353
- const bareRegex = /\b([A-Za-z0-9._-]+\.[A-Za-z0-9]{1,8})\b/g;
354
- for (const m of text.matchAll(bareRegex)) {
355
- const file = m[1];
356
- if (!file.includes('/'))
357
- files.add(file);
358
- }
359
- return [...files];
360
- }
361
- function isCommandAvailable(...cmd) {
362
- const command = cmd.length === 1 ? cmd[0] : cmd.join(' ');
363
- const result = spawnSync('which', [cmd[0]], {
364
- timeout: 5000,
365
- encoding: 'utf8',
366
- stdio: ['ignore', 'pipe', 'ignore'],
367
- });
368
- if (result.status !== 0)
369
- return false;
370
- // For compound commands like 'cargo clippy', test the full command
371
- if (cmd.length > 1) {
372
- const testResult = spawnSync('bash', ['-c', `${command} --help >/dev/null 2>&1`], {
373
- timeout: 5000,
374
- });
375
- return testResult.status === 0;
376
- }
377
- return true;
378
- }
379
- function makeTargetExists(cwd, target) {
380
- try {
381
- const result = spawnSync('make', ['-n', target], {
382
- cwd,
383
- timeout: 5000,
384
- stdio: ['ignore', 'ignore', 'pipe'],
385
- });
386
- // make -n returns 0 if target exists and is valid
387
- return result.status === 0;
388
- }
389
- catch {
390
- return false;
391
- }
392
- }
393
- function truncateOutput(text, maxLen = 2000) {
394
- const cleaned = text.trim();
395
- return cleaned.length > maxLen ? `${cleaned.slice(0, maxLen)}...` : cleaned;
396
- }
397
- /** Combine stdout and stderr into a single labeled output block. */
398
- function combineOutput(label, stdout, stderr) {
399
- const parts = [`=== ${label} ===`];
400
- const out = stdout.trim();
401
- const err = stderr.trim();
402
- if (out)
403
- parts.push(`stdout:\n${out}`);
404
- if (err)
405
- parts.push(`stderr:\n${err}`);
406
- if (!out && !err)
407
- parts.push('(no output)');
408
- return parts.join('\n');
409
- }
410
- /**
411
- * Parse L2 verifier response with fault tolerance.
412
- * Tries JSON first, then extracts JSON from markdown fences,
413
- * then falls back to keyword inference from prose.
414
- */
415
- function parseVerifierResponse(raw) {
416
- const text = raw.trim();
417
- // 1. Try direct JSON parse
418
- try {
419
- const parsed = JSON.parse(text);
420
- if (typeof parsed.pass === 'boolean') {
421
- return { pass: parsed.pass, reason: parsed.reason || 'No reason provided' };
422
- }
423
- }
424
- catch { /* not valid JSON, continue */ }
425
- // 2. Try extracting JSON from markdown code fences or inline braces
426
- const jsonMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/) || text.match(/(\{[\s\S]*?"pass"[\s\S]*?\})/);
427
- if (jsonMatch) {
428
- try {
429
- const parsed = JSON.parse(jsonMatch[1].trim());
430
- if (typeof parsed.pass === 'boolean') {
431
- return { pass: parsed.pass, reason: parsed.reason || 'No reason provided' };
432
- }
433
- }
434
- catch { /* still not valid, continue */ }
435
- }
436
- // 3. Keyword inference from prose
437
- const lower = text.toLowerCase();
438
- const passPatterns = [
439
- /\bpass\b/, /\bapproved?\b/, /\blooks?\s+good\b/, /\bcorrect(ly)?\b/,
440
- /\bwell[- ]implemented\b/, /\bno\s+(issues?|problems?|concerns?)\b/,
441
- /\bcode\s+(is\s+)?clean\b/, /\btask\s+(is\s+)?(complete|done)\b/,
442
- ];
443
- const failPatterns = [
444
- /\bfail\b/, /\breject(ed)?\b/, /\bnot\s+(correct|approved?)\b/,
445
- /\bissues?\s+found\b/, /\bproblems?\s+found\b/, /\bbug(s)?\b/,
446
- /\bmissing\b/, /\bincorrect\b/, /\bbroken\b/,
447
- ];
448
- const passScore = passPatterns.filter(p => p.test(lower)).length;
449
- const failScore = failPatterns.filter(p => p.test(lower)).length;
450
- if (passScore > 0 && passScore > failScore) {
451
- const snippet = text.length > 200 ? text.slice(0, 200) + '...' : text;
452
- return { pass: true, reason: `(inferred from prose) ${snippet}` };
453
- }
454
- if (failScore > 0) {
455
- const snippet = text.length > 200 ? text.slice(0, 200) + '...' : text;
456
- return { pass: false, reason: `(inferred from prose) ${snippet}` };
457
- }
458
- // 4. Ambiguous — default to pass since L1 already validated build/test
459
- const snippet = text.length > 200 ? text.slice(0, 200) + '...' : text;
460
- return { pass: true, reason: `(ambiguous response, defaulting to pass) ${snippet}` };
461
- }
462
- // ── Lint output filtering ───────────────────────────────────────────
463
- /**
464
- * Filter lint output to only include error-level lines (not warnings).
465
- * Keeps file path headers for context. Returns empty string if no errors found.
466
- */
467
- export function filterLintErrorLines(output) {
468
- const lines = output.split('\n');
469
- const result = [];
470
- let lastFilePath = '';
471
- for (const line of lines) {
472
- // File path line (eslint): "/path/to/file.ts"
473
- if (/^\/.*\.\w+$/.test(line.trim()) || /^[A-Z]:\\/.test(line.trim())) {
474
- lastFilePath = line;
475
- continue;
476
- }
477
- // Error line: " 1:1 error ..."
478
- if (/\d+:\d+\s+error\s/.test(line) || /\berror\s+TS\d+/.test(line) || /\berror\[E\d+\]/.test(line)) {
479
- if (lastFilePath && (result.length === 0 || result[result.length - 1] !== lastFilePath)) {
480
- result.push(lastFilePath);
481
- }
482
- result.push(line);
483
- }
484
- // Summary line: "✖ N problems (N errors, N warnings)"
485
- if (/^\u2716\s+\d+\s+problem/.test(line) || /^\d+\s+error/.test(line)) {
486
- result.push(line);
487
- }
488
- }
489
- return result.join('\n');
490
- }
491
- // ── Lint baseline helpers ───────────────────────────────────────────
492
- /**
493
- * Count the number of "error" lines in lint output.
494
- * Works for eslint, tsc, ruff, clippy — all emit lines containing "error".
495
- */
496
- export function countLintErrors(output) {
497
- // Match lines like:
498
- // 1:1 error `./types.js` ... (eslint)
499
- // error TS2322: ... (tsc)
500
- // src/foo.rs:1:1: error[E0308]: ... (clippy)
501
- // src/foo.py:1:1: E302 ... (ruff — codes starting with E/W/F)
502
- const lines = output.split('\n');
503
- let count = 0;
504
- for (const line of lines) {
505
- // eslint: " 1:1 error ..."
506
- if (/\d+:\d+\s+error\s/.test(line)) {
507
- count++;
508
- continue;
509
- }
510
- // tsc: "error TS..." or "file.ts(1,1): error TS..."
511
- if (/\berror\s+TS\d+/.test(line)) {
512
- count++;
513
- continue;
514
- }
515
- // clippy/rustc: "error[E"
516
- if (/\berror\[E\d+\]/.test(line)) {
517
- count++;
518
- continue;
519
- }
520
- }
521
- return count;
522
- }
523
- /**
524
- * Capture baseline lint error count before Anton starts modifying files.
525
- * Returns the count, or undefined if lint is not configured or passes cleanly.
526
- */
527
- export async function captureLintBaseline(lintCommand, projectDir) {
528
- if (!lintCommand)
529
- return undefined;
530
- try {
531
- const result = await runCommand(lintCommand, 180_000, projectDir);
532
- if (result.exitCode === 0)
533
- return 0; // clean baseline
534
- const count = countLintErrors(result.stdout + '\n' + result.stderr);
535
- if (count > 0) {
536
- console.error(`[anton:baseline] pre-existing lint errors: ${count}`);
537
- }
538
- return count;
539
- }
540
- catch {
541
- return undefined;
542
- }
543
- }
342
+ // Helper functions
544
343
  //# sourceMappingURL=verifier.js.map