ai-obs-cli 0.0.0-stage → 0.5.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 (155) hide show
  1. package/README.md +666 -2
  2. package/bin/ai-obs.js +8 -0
  3. package/dist/adapters/claude-code/analyze.js +189 -0
  4. package/dist/adapters/claude-code/analyze.js.map +1 -0
  5. package/dist/adapters/claude-code/detect.js +60 -0
  6. package/dist/adapters/claude-code/detect.js.map +1 -0
  7. package/dist/adapters/claude-code/handlers.js +183 -0
  8. package/dist/adapters/claude-code/handlers.js.map +1 -0
  9. package/dist/adapters/claude-code/index.js +55 -0
  10. package/dist/adapters/claude-code/index.js.map +1 -0
  11. package/dist/adapters/claude-code/run-links.js +53 -0
  12. package/dist/adapters/claude-code/run-links.js.map +1 -0
  13. package/dist/adapters/claude-code/session.js +427 -0
  14. package/dist/adapters/claude-code/session.js.map +1 -0
  15. package/dist/adapters/claude-code/settings.js +161 -0
  16. package/dist/adapters/claude-code/settings.js.map +1 -0
  17. package/dist/adapters/claude-code/state.js +66 -0
  18. package/dist/adapters/claude-code/state.js.map +1 -0
  19. package/dist/adapters/claude-code/subagents.js +246 -0
  20. package/dist/adapters/claude-code/subagents.js.map +1 -0
  21. package/dist/adapters/claude-code/transcript.js +309 -0
  22. package/dist/adapters/claude-code/transcript.js.map +1 -0
  23. package/dist/adapters/codex/accumulator.js +135 -0
  24. package/dist/adapters/codex/accumulator.js.map +1 -0
  25. package/dist/adapters/codex/detect.js +93 -0
  26. package/dist/adapters/codex/detect.js.map +1 -0
  27. package/dist/adapters/codex/hooks-config.js +158 -0
  28. package/dist/adapters/codex/hooks-config.js.map +1 -0
  29. package/dist/adapters/codex/index.js +270 -0
  30. package/dist/adapters/codex/index.js.map +1 -0
  31. package/dist/adapters/codex/locate.js +72 -0
  32. package/dist/adapters/codex/locate.js.map +1 -0
  33. package/dist/adapters/codex/records.js +194 -0
  34. package/dist/adapters/codex/records.js.map +1 -0
  35. package/dist/adapters/codex/rollout.js +72 -0
  36. package/dist/adapters/codex/rollout.js.map +1 -0
  37. package/dist/adapters/codex/session.js +212 -0
  38. package/dist/adapters/codex/session.js.map +1 -0
  39. package/dist/adapters/codex/subagents.js +139 -0
  40. package/dist/adapters/codex/subagents.js.map +1 -0
  41. package/dist/adapters/codex/summarize.js +84 -0
  42. package/dist/adapters/codex/summarize.js.map +1 -0
  43. package/dist/adapters/codex/tools.js +145 -0
  44. package/dist/adapters/codex/tools.js.map +1 -0
  45. package/dist/adapters/hook-command.js +94 -0
  46. package/dist/adapters/hook-command.js.map +1 -0
  47. package/dist/adapters/index.js +12 -0
  48. package/dist/adapters/index.js.map +1 -0
  49. package/dist/adapters/types.js +2 -0
  50. package/dist/adapters/types.js.map +1 -0
  51. package/dist/analysis/corrections.js +79 -0
  52. package/dist/analysis/corrections.js.map +1 -0
  53. package/dist/analysis/digest.js +16 -0
  54. package/dist/analysis/digest.js.map +1 -0
  55. package/dist/analysis/outcome.js +76 -0
  56. package/dist/analysis/outcome.js.map +1 -0
  57. package/dist/analysis/phases.js +203 -0
  58. package/dist/analysis/phases.js.map +1 -0
  59. package/dist/analysis/summaries.js +350 -0
  60. package/dist/analysis/summaries.js.map +1 -0
  61. package/dist/analysis/tokens.js +67 -0
  62. package/dist/analysis/tokens.js.map +1 -0
  63. package/dist/analysis/usage.js +229 -0
  64. package/dist/analysis/usage.js.map +1 -0
  65. package/dist/cc-cache.js +81 -0
  66. package/dist/cc-cache.js.map +1 -0
  67. package/dist/cli.js +128 -0
  68. package/dist/cli.js.map +1 -0
  69. package/dist/commands/common.js +235 -0
  70. package/dist/commands/common.js.map +1 -0
  71. package/dist/commands/doctor.js +193 -0
  72. package/dist/commands/doctor.js.map +1 -0
  73. package/dist/commands/flush.js +131 -0
  74. package/dist/commands/flush.js.map +1 -0
  75. package/dist/commands/init.js +119 -0
  76. package/dist/commands/init.js.map +1 -0
  77. package/dist/commands/link.js +171 -0
  78. package/dist/commands/link.js.map +1 -0
  79. package/dist/commands/live.js +130 -0
  80. package/dist/commands/live.js.map +1 -0
  81. package/dist/commands/login.js +397 -0
  82. package/dist/commands/login.js.map +1 -0
  83. package/dist/commands/status.js +155 -0
  84. package/dist/commands/status.js.map +1 -0
  85. package/dist/commands/token.js +92 -0
  86. package/dist/commands/token.js.map +1 -0
  87. package/dist/commands/uninstall.js +56 -0
  88. package/dist/commands/uninstall.js.map +1 -0
  89. package/dist/config.js +305 -0
  90. package/dist/config.js.map +1 -0
  91. package/dist/context.js +109 -0
  92. package/dist/context.js.map +1 -0
  93. package/dist/delivery.js +151 -0
  94. package/dist/delivery.js.map +1 -0
  95. package/dist/dotfile.js +187 -0
  96. package/dist/dotfile.js.map +1 -0
  97. package/dist/events.js +259 -0
  98. package/dist/events.js.map +1 -0
  99. package/dist/fsutil.js +50 -0
  100. package/dist/fsutil.js.map +1 -0
  101. package/dist/git.js +139 -0
  102. package/dist/git.js.map +1 -0
  103. package/dist/hook.js +147 -0
  104. package/dist/hook.js.map +1 -0
  105. package/dist/http.js +35 -0
  106. package/dist/http.js.map +1 -0
  107. package/dist/jobs.js +53 -0
  108. package/dist/jobs.js.map +1 -0
  109. package/dist/live/claude-code.js +226 -0
  110. package/dist/live/claude-code.js.map +1 -0
  111. package/dist/live/codex.js +91 -0
  112. package/dist/live/codex.js.map +1 -0
  113. package/dist/live/monitor.js +229 -0
  114. package/dist/live/monitor.js.map +1 -0
  115. package/dist/live/render.js +92 -0
  116. package/dist/live/render.js.map +1 -0
  117. package/dist/lock.js +93 -0
  118. package/dist/lock.js.map +1 -0
  119. package/dist/log.js +36 -0
  120. package/dist/log.js.map +1 -0
  121. package/dist/migrate.js +109 -0
  122. package/dist/migrate.js.map +1 -0
  123. package/dist/nudge.js +231 -0
  124. package/dist/nudge.js.map +1 -0
  125. package/dist/paths.js +73 -0
  126. package/dist/paths.js.map +1 -0
  127. package/dist/pk-cache.js +110 -0
  128. package/dist/pk-cache.js.map +1 -0
  129. package/dist/prices.js +45 -0
  130. package/dist/prices.js.map +1 -0
  131. package/dist/project-key.js +144 -0
  132. package/dist/project-key.js.map +1 -0
  133. package/dist/protocol-types.js +30 -0
  134. package/dist/protocol-types.js.map +1 -0
  135. package/dist/queue.js +649 -0
  136. package/dist/queue.js.map +1 -0
  137. package/dist/routing.js +122 -0
  138. package/dist/routing.js.map +1 -0
  139. package/dist/runtime.js +54 -0
  140. package/dist/runtime.js.map +1 -0
  141. package/dist/sender.js +559 -0
  142. package/dist/sender.js.map +1 -0
  143. package/dist/state.js +59 -0
  144. package/dist/state.js.map +1 -0
  145. package/dist/ulid.js +73 -0
  146. package/dist/ulid.js.map +1 -0
  147. package/dist/version.js +26 -0
  148. package/dist/version.js.map +1 -0
  149. package/dist/warnings.js +71 -0
  150. package/dist/warnings.js.map +1 -0
  151. package/dist/worker-main.js +14 -0
  152. package/dist/worker-main.js.map +1 -0
  153. package/dist/worker.js +295 -0
  154. package/dist/worker.js.map +1 -0
  155. package/package.json +25 -4
@@ -0,0 +1,145 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { checkKind, classify } from '../../analysis/phases.js';
3
+ import { skillReadBy } from '../../analysis/usage.js';
4
+ /**
5
+ * Codex tool calls → phase / check / edit facts. Command lines and patch text are used ONLY here,
6
+ * locally, and never leave this module except as phases, counts and hashes.
7
+ */
8
+ /**
9
+ * Multi-agent tools: spawning a sub-agent, handing it work and waiting for it is `delegating` time.
10
+ * `assign_agent_task` is MultiAgentV2 (agents addressed by canonical task path; seen in the 0.154
11
+ * binary, not yet in a real rollout — see FORMAT.md).
12
+ */
13
+ const DELEGATING = new Set([
14
+ 'spawn_agent',
15
+ 'assign_agent_task',
16
+ 'wait',
17
+ 'wait_agent',
18
+ 'wait_for_agent',
19
+ 'wait_agents',
20
+ 'followup_task',
21
+ 'resume_agent',
22
+ ]);
23
+ const AGENT_PLUMBING = new Set(['send_input', 'send_message', 'close_agent', 'list_agents']);
24
+ /**
25
+ * Parses the Codex apply_patch envelope:
26
+ * *** Begin Patch / *** Add File: p / *** Update File: p / *** Move to: p / *** Delete File: p / @@ / +x / -y / *** End Patch
27
+ */
28
+ export function parseApplyPatch(text) {
29
+ const facts = { files: [], added: 0, removed: 0, edits: [] };
30
+ let cur = null;
31
+ for (const raw of text.split('\n')) {
32
+ const line = raw.replace(/\r$/, '');
33
+ const head = /^\*\*\* (Add|Update|Delete) File: (.+)$/.exec(line);
34
+ if (head) {
35
+ cur = { filePath: head[2].trim(), added: [], removed: [] };
36
+ facts.edits.push(cur);
37
+ facts.files.push(cur.filePath);
38
+ continue;
39
+ }
40
+ const move = /^\*\*\* Move to: (.+)$/.exec(line);
41
+ if (move) {
42
+ facts.files.push(move[1].trim());
43
+ continue;
44
+ }
45
+ if (!cur || line.startsWith('***'))
46
+ continue;
47
+ if (line.startsWith('+')) {
48
+ facts.added++;
49
+ cur.added.push(line.slice(1));
50
+ }
51
+ else if (line.startsWith('-')) {
52
+ facts.removed++;
53
+ cur.removed.push(line.slice(1));
54
+ }
55
+ }
56
+ return facts;
57
+ }
58
+ /** Patch text of an apply_patch call in any of its Codex shapes (freeform, JSON args, shell argv / heredoc). */
59
+ export function patchTextOf(name, args, input) {
60
+ if (name === 'apply_patch') {
61
+ if (input)
62
+ return input;
63
+ const a = args?.input ?? args?.patch;
64
+ return typeof a === 'string' ? a : null;
65
+ }
66
+ const cmd = commandOf(args);
67
+ if (Array.isArray(cmd) && /(^|\/)apply_patch$/.test(String(cmd[0] ?? '')) && typeof cmd[1] === 'string')
68
+ return cmd[1];
69
+ const line = Array.isArray(cmd) ? cmd.join(' ') : cmd;
70
+ if (typeof line === 'string' && /\bapply_patch\b/.test(line) && line.includes('*** Begin Patch'))
71
+ return line.slice(line.indexOf('*** Begin Patch'));
72
+ return null;
73
+ }
74
+ /** Shell command of exec_command (`cmd`), shell / local_shell (`command` argv or string). */
75
+ export function commandOf(args) {
76
+ const c = args?.cmd ?? args?.command;
77
+ if (typeof c === 'string')
78
+ return c;
79
+ if (Array.isArray(c) && c.every((x) => typeof x === 'string'))
80
+ return c;
81
+ return null;
82
+ }
83
+ /** Classifies one Codex tool call. `processPhase` resolves write_stdin to its process's phase. */
84
+ export function toolFacts(name, args, input, processPhase, isRevert) {
85
+ const base = { phase: 'other', check: null, revert: false, patch: null, processId: null };
86
+ if (DELEGATING.has(name))
87
+ return { ...base, phase: 'delegating' };
88
+ if (AGENT_PLUMBING.has(name))
89
+ return base;
90
+ if (name === 'write_stdin') {
91
+ const id = args?.session_id;
92
+ const pid = typeof id === 'number' || typeof id === 'string' ? String(id) : null;
93
+ const proc = pid ? processPhase(pid) : undefined;
94
+ return { ...base, phase: proc?.phase ?? 'other', processId: pid };
95
+ }
96
+ const patchText = patchTextOf(name, args, input);
97
+ if (patchText !== null) {
98
+ const patch = parseApplyPatch(patchText);
99
+ return { ...base, phase: classify('apply_patch', { filePaths: patch.files }), patch };
100
+ }
101
+ const cmd = commandOf(args);
102
+ if (cmd && /^(exec_command|shell|local_shell|container\.exec|shell_command|unified_exec|bash)$/.test(name)) {
103
+ const skill = skillReadBy(typeof cmd === 'string' ? cmd : cmd.join(' '));
104
+ return { ...base, phase: classify('shell', { command: cmd }), check: checkKind(cmd), revert: isRevert(cmd), ...(skill ? { skill } : {}) };
105
+ }
106
+ if (name === 'view_image')
107
+ return { ...base, phase: 'exploring' };
108
+ return { ...base, phase: classify(name) };
109
+ }
110
+ /**
111
+ * Exit code in a tool output: unified exec ("Process exited with code N"), legacy shell JSON
112
+ * ({"metadata": {"exit_code": N}}) or text ("Exit code: N"). `running` = the process is still alive
113
+ * ("Process running with session ID N"), continued via write_stdin.
114
+ */
115
+ export function parseExecOutput(output) {
116
+ const head = output.slice(0, 2000);
117
+ const exited = /Process exited with code (-?\d+)/.exec(head) ?? /^Exit code: (-?\d+)/m.exec(head);
118
+ if (exited)
119
+ return { exitCode: Number(exited[1]), runningId: null };
120
+ const running = /Process running with session ID (\d+)/.exec(head);
121
+ if (running)
122
+ return { exitCode: null, runningId: running[1] };
123
+ if (head.trimStart().startsWith('{')) {
124
+ try {
125
+ const j = JSON.parse(output);
126
+ if (typeof j.metadata?.exit_code === 'number')
127
+ return { exitCode: j.metadata.exit_code, runningId: null };
128
+ }
129
+ catch {
130
+ /* not JSON */
131
+ }
132
+ }
133
+ return { exitCode: null, runningId: null };
134
+ }
135
+ /** Short local-only hash of a file path (distinct-file counting without keeping paths). */
136
+ export const pathHash = (p) => createHash('sha256').update(p).digest('base64url').slice(0, 12);
137
+ /** Child thread ids returned by spawn_agent ({"agent_id": …} / {"thread_id": …} / plain text). */
138
+ export function spawnedAgentIds(output) {
139
+ const ids = new Set();
140
+ const re = /"(?:agent_id|thread_id|new_thread_id|id)"\s*:\s*"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"/gi;
141
+ for (const m of output.slice(0, 20_000).matchAll(re))
142
+ ids.add(m[1].toLowerCase());
143
+ return [...ids];
144
+ }
145
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/adapters/codex/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { accessSync, constants, existsSync } from 'node:fs';
2
+ import { isAbsolute } from 'node:path';
3
+ /** Marker present in every hook command we install; adapters use it to find our entries. */
4
+ export const HOOK_MARKER = 'ai-obs';
5
+ /** POSIX single-quote when needed. */
6
+ export function shellQuote(arg) {
7
+ return /^[A-Za-z0-9_@%+=:,./-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, `'\\''`)}'`;
8
+ }
9
+ /**
10
+ * Builds `hookCommand(hookName)` for InstallOptions. `entry` is the installed bin script
11
+ * (~/.ai-obs/app/bin/ai-obs.js); `home` is appended as `--home` only when non-default.
12
+ */
13
+ export function hookCommandFactory(input) {
14
+ return (hookName) => {
15
+ const argv = [input.node, input.entry, 'hook', input.harness, hookName, ...(input.home ? ['--home', input.home] : [])];
16
+ return { argv, shell: argv.map(shellQuote).join(' ') };
17
+ };
18
+ }
19
+ /** True for a hook command written by `ai-obs init` (any harness). */
20
+ export function isAiObsHookCommand(command) {
21
+ if (!command)
22
+ return false;
23
+ const s = typeof command === 'string' ? command : command.join(' ');
24
+ return /ai-obs/.test(s) && /\bhook\b/.test(s);
25
+ }
26
+ /** Splits a POSIX-shell command (single / double quotes, backslash) into words. Not a full shell. */
27
+ export function parseShellWords(command) {
28
+ const words = [];
29
+ let cur = '';
30
+ let started = false;
31
+ let quote = null;
32
+ for (let i = 0; i < command.length; i++) {
33
+ const c = command[i];
34
+ if (quote === "'") {
35
+ if (c === "'")
36
+ quote = null;
37
+ else
38
+ cur += c;
39
+ }
40
+ else if (quote === '"') {
41
+ if (c === '"')
42
+ quote = null;
43
+ else if (c === '\\' && i + 1 < command.length)
44
+ cur += command[++i];
45
+ else
46
+ cur += c;
47
+ }
48
+ else if (c === "'" || c === '"') {
49
+ quote = c;
50
+ started = true;
51
+ }
52
+ else if (c === '\\' && i + 1 < command.length) {
53
+ cur += command[++i];
54
+ started = true;
55
+ }
56
+ else if (/\s/.test(c)) {
57
+ if (started || cur)
58
+ words.push(cur);
59
+ cur = '';
60
+ started = false;
61
+ }
62
+ else
63
+ cur += c;
64
+ }
65
+ if (started || cur)
66
+ words.push(cur);
67
+ return words;
68
+ }
69
+ /**
70
+ * What is wrong with the runtime baked into an installed hook command (`<node> <entry> hook …`):
71
+ * the absolute node binary or the entry script is gone (e.g. an nvm Node version was removed, or
72
+ * `~/.ai-obs` was deleted). Hooks then fail without the harness telling anyone. A bare `node` is
73
+ * resolved through PATH at run time and is not checked.
74
+ */
75
+ export function hookRuntimeProblems(command) {
76
+ const [node, entry] = parseShellWords(command);
77
+ const out = [];
78
+ if (node && isAbsolute(node)) {
79
+ try {
80
+ accessSync(node, constants.X_OK);
81
+ }
82
+ catch {
83
+ out.push(`node binary ${node} is missing or not executable`);
84
+ }
85
+ }
86
+ if (entry && isAbsolute(entry) && !existsSync(entry))
87
+ out.push(`collector script ${entry} is missing`);
88
+ return out;
89
+ }
90
+ /** Node installs that live in a per-version directory and disappear when that version is removed. */
91
+ export function isVersionManagedNode(path) {
92
+ return /[\\/](\.nvm|\.fnm|fnm_multishells|\.volta|\.asdf|\.nodenv|\.nvs|n[\\/]versions|nvm[\\/]versions)[\\/]/.test(path) || /[\\/]node[\\/]v?\d+\.\d+\.\d+[\\/]/.test(path);
93
+ }
94
+ //# sourceMappingURL=hook-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-command.js","sourceRoot":"","sources":["../../src/adapters/hook-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { adapter as claudeCode } from './claude-code/index.js';
2
+ import { adapter as codex } from './codex/index.js';
3
+ /** Adapter registry. A new harness = a new adapter module + one line here. */
4
+ export const ADAPTERS = [claudeCode, codex];
5
+ export const HARNESS_NAMES = ['claude-code', 'codex'];
6
+ export function isHarnessName(s) {
7
+ return HARNESS_NAMES.includes(s);
8
+ }
9
+ export function getAdapter(name, adapters = ADAPTERS) {
10
+ return adapters.find((a) => a.name === name);
11
+ }
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGpD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,QAAQ,GAA8B,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,aAAa,GAA2B,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;AAE9E,MAAM,UAAU,aAAa,CAAC,CAAqB;IACjD,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAgB,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,QAAQ,GAA8B,QAAQ;IACrF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * "Was the next prompt a correction?" heuristics (BRIEF §5.5), EN + CZ. Runs locally; the prompt is
3
+ * never sent or stored. Czech phrases are written without diacritics because input is folded
4
+ * (`špatně` → `spatne`). Extend the lists (and the test table) for more languages.
5
+ */
6
+ /** Phrases that mark a correction when the prompt STARTS with them. */
7
+ export const CORRECTION_START_PHRASES = {
8
+ en: [
9
+ 'no', 'nope', 'nah', 'wrong', 'incorrect', 'not right', 'revert', 'undo', 'rollback', 'roll back',
10
+ "don't", 'dont', 'do not', 'not like that', 'not what', "that's not", 'thats not', 'that is not',
11
+ "this isn't", "that isn't", 'this is not', "it's broken", 'its broken', 'still broken', 'still failing',
12
+ 'still fails', 'still not', "still doesn't", 'still does not', "doesn't work", 'does not work',
13
+ "didn't work", 'did not work', 'not working', 'try again', 'you misunderstood', 'why did you',
14
+ 'put it back', 'go back', 'actually no', 'stop', 'you broke', 'it broke', 'it is broken',
15
+ ],
16
+ cs: [
17
+ 'ne', 'nee', 'neee', 'spatne', 'to je spatne', 'je to spatne', 'to neni', 'tohle neni', 'neni to',
18
+ 'nefunguje', 'porad nefunguje', 'porad to nefunguje', 'stale nefunguje', 'stale to nefunguje',
19
+ 'vrat', 'vratit', 'zrus', 'zrusit', 'nedelej', 'proc jsi', 'nespravne', 'to nechci', 'tohle nechci',
20
+ 'to jsem nechtel', 'to jsem nechtela', 'tak ne', 'zase spatne', 'opet spatne', 'zkus to znovu', 'rozbil',
21
+ ],
22
+ };
23
+ /** Phrases that mark a correction ANYWHERE in the first 200 characters. */
24
+ export const CORRECTION_ANYWHERE_PHRASES = {
25
+ en: [
26
+ "that's wrong", 'thats wrong', 'that is wrong', 'this is wrong', "it's wrong", 'is still broken',
27
+ 'still failing', 'still fails', "still doesn't work", 'still does not work', "that's not right",
28
+ 'not what i asked', 'not what i wanted', 'not what i meant', 'revert that', 'revert this', 'revert it',
29
+ 'revert your', 'revert the change', 'revert those', 'revert everything', 'undo that', 'undo this',
30
+ 'undo your', 'undo the change', 'undo those', 'undo everything', 'roll it back', 'roll that back',
31
+ 'roll this back', 'you broke', 'broke the build', 'you misunderstood', 'put it back', 'that broke',
32
+ 'why did you delete', 'why did you remove', 'why did you change',
33
+ ],
34
+ cs: [
35
+ 'to je spatne', 'je to spatne', 'udelal jsi to spatne', 'udelals to spatne', 'delas to spatne',
36
+ 'nefunguje to', 'porad nefunguje', 'porad to nefunguje', 'stale nefunguje', 'stale to nefunguje',
37
+ 'vrat to', 'vrat zpet', 'vrat zmeny', 'vrat to zpatky', 'zrus to', 'zrus zmeny', 'rozbil jsi',
38
+ 'rozbils', 'to jsem nechtel', 'to jsem nechtela', 'nechtel jsem', 'tohle jsem nechtel', 'neni to spravne',
39
+ 'to neni spravne', 'to neni ono', 'proc jsi smazal', 'proc jsi odstranil', 'proc jsi zmenil',
40
+ ],
41
+ };
42
+ /** "no" openers that are not corrections. */
43
+ const NOT_CORRECTION_AFTER_NO = ['problem', 'worries', 'rush', 'need', 'thanks', 'pressure'];
44
+ /** Openers that mean the previous turn was fine. */
45
+ const POSITIVE_START = [
46
+ 'thanks', 'thank you', 'great', 'perfect', 'nice', 'good', 'awesome', 'cool', 'lgtm', 'looks good', 'ok great',
47
+ 'diky', 'dekuji', 'super', 'vyborne', 'skvele', 'paradni', 'perfektni', 'dobre', 'v poradku', 'funguje',
48
+ ];
49
+ const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
50
+ const BOUNDARY_AFTER = `(?=$|[\\s,.!?:;…"')\\-])`;
51
+ const phraseAlt = (list) => list.map(escape).sort((a, b) => b.length - a.length).join('|');
52
+ const START_RE = new RegExp(`^(?:${phraseAlt([...CORRECTION_START_PHRASES.en, ...CORRECTION_START_PHRASES.cs])})${BOUNDARY_AFTER}`);
53
+ const ANYWHERE_RE = new RegExp(`(?:^|[\\s,.!?:;"'(])(?:${phraseAlt([...CORRECTION_ANYWHERE_PHRASES.en, ...CORRECTION_ANYWHERE_PHRASES.cs])})${BOUNDARY_AFTER}`);
54
+ const POSITIVE_RE = new RegExp(`^(?:${phraseAlt(POSITIVE_START)})${BOUNDARY_AFTER}`);
55
+ const BENIGN_NO_RE = new RegExp(`^no,?\\s+(?:${NOT_CORRECTION_AFTER_NO.join('|')})\\b`);
56
+ /** "stop" as a correction only when it stands alone ("stop!", "stop, that's…"), not "stop the server". */
57
+ const STOP_TASK_RE = /^stop\s+(?!it\b|that\b|this\b)[a-z]/;
58
+ /** Lowercase, strip diacritics, unify apostrophes, collapse whitespace, drop leading quotes/markup. */
59
+ export function foldPrompt(prompt) {
60
+ return prompt
61
+ .normalize('NFD')
62
+ .replace(/[̀-ͯ]/g, '')
63
+ .toLowerCase()
64
+ .replace(/[‘’ʼ`]/g, "'")
65
+ .replace(/\s+/g, ' ')
66
+ .replace(/^[\s>*_#"'(\-]+/, '')
67
+ .slice(0, 200)
68
+ .trim();
69
+ }
70
+ /** True when the prompt looks like the user correcting the previous turn. */
71
+ export function looksLikeCorrection(prompt) {
72
+ const p = foldPrompt(prompt);
73
+ if (!p)
74
+ return false;
75
+ if (POSITIVE_RE.test(p) || BENIGN_NO_RE.test(p) || STOP_TASK_RE.test(p))
76
+ return false;
77
+ return START_RE.test(p) || ANYWHERE_RE.test(p);
78
+ }
79
+ //# sourceMappingURL=corrections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corrections.js","sourceRoot":"","sources":["../../src/analysis/corrections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export const DIGEST_TEXT_LIMIT = 300;
2
+ export function truncate(text, max) {
3
+ const s = text.replace(/\s+/g, ' ').trim();
4
+ return s.length <= max ? s : `${s.slice(0, max - 1)}…`;
5
+ }
6
+ export function buildDigest(input) {
7
+ const tools = [...new Set(input.toolNames)].filter(Boolean).slice(0, 30);
8
+ return {
9
+ turnId: input.turnId,
10
+ ...(input.sessionId ? { sessionId: input.sessionId } : {}),
11
+ prompt: truncate(input.prompt ?? '', DIGEST_TEXT_LIMIT),
12
+ tools,
13
+ lastAssistantMessage: truncate(input.lastAssistantMessage ?? '', DIGEST_TEXT_LIMIT),
14
+ };
15
+ }
16
+ //# sourceMappingURL=digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.js","sourceRoot":"","sources":["../../src/analysis/digest.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAW;IAChD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAM3B;IACC,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzE,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,iBAAiB,CAAC;QACvD,KAAK;QACL,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,oBAAoB,IAAI,EAAE,EAAE,iBAAiB,CAAC;KACpF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { splitShellCommand } from './phases.js';
3
+ const uniq = (s) => [...new Set(s)];
4
+ /**
5
+ * Provisional outcome sent with the `turn` event at Stop. Precedence: stop failure > interrupt >
6
+ * last test/validate result > unknown (waits for the next prompt).
7
+ */
8
+ export function provisionalOutcome(s) {
9
+ if (s.stopFailure)
10
+ return { status: 'failed', signals: ['stop_failure'], provisional: true };
11
+ if (s.interrupted)
12
+ return { status: 'abandoned', signals: ['user_interrupt'], provisional: true };
13
+ if (s.lastCheck) {
14
+ const passed = s.lastCheck.exitCode === 0;
15
+ const signal = s.lastCheck.kind === 'testing' ? (passed ? 'tests_passed' : 'tests_failed') : passed ? 'validate_passed' : 'validate_failed';
16
+ return { status: passed ? 'success' : 'failed', signals: [signal], provisional: true };
17
+ }
18
+ return { status: 'unknown', signals: [], provisional: true };
19
+ }
20
+ /**
21
+ * Final outcome once the follow-up is known; sent as a `turn_outcome` patch (provisional: false).
22
+ * - a revert or correction makes a turn `failed` retroactively (an interrupted turn stays `abandoned`);
23
+ * - an `unknown` turn followed by a normal prompt becomes `success` (`no_failure_signal`);
24
+ * - an `unknown` last turn of a session stays `unknown`.
25
+ */
26
+ export function finalOutcome(provisional, follow) {
27
+ const signals = [...provisional.signals];
28
+ if (follow.revert || follow.correction) {
29
+ if (follow.revert)
30
+ signals.push('next_turn_revert');
31
+ if (follow.correction)
32
+ signals.push('next_prompt_correction');
33
+ const status = provisional.status === 'abandoned' ? 'abandoned' : 'failed';
34
+ return { status, signals: uniq(signals), provisional: false };
35
+ }
36
+ if (provisional.status === 'unknown' && !follow.sessionEnded) {
37
+ return { status: 'success', signals: uniq([...signals, 'no_failure_signal']), provisional: false };
38
+ }
39
+ return { status: provisional.status, signals: uniq(signals), provisional: false };
40
+ }
41
+ /** Whether a patch event is worth sending (anything changed beyond `provisional`). */
42
+ export function outcomeChanged(before, after) {
43
+ return before.status !== after.status || before.signals.join(',') !== after.signals.join(',') || before.provisional !== after.provisional;
44
+ }
45
+ // ---------------------------------------------------------------- revert detection (hook point)
46
+ /** Shell commands that throw away work (`git checkout -- f`, `git restore`, `git revert`, `git reset --hard`, `git stash`). */
47
+ export function isRevertCommand(command) {
48
+ const line = typeof command === 'string' ? command : command.join(' ');
49
+ return splitShellCommand(line).some((c) => /^git (checkout (--|\S+ --) |checkout \.$|restore\b(?! --staged\b)|revert\b|reset --hard\b|stash( push| save)?$|clean -\w*f)/.test(c));
50
+ }
51
+ const lineHash = (path, line) => createHash('sha256').update(`${path}\0${line.trim()}`).digest('base64url').slice(0, 16);
52
+ export function editFingerprint(edits) {
53
+ const added = new Set();
54
+ const removed = new Set();
55
+ for (const e of edits) {
56
+ for (const l of e.added)
57
+ if (l.trim())
58
+ added.add(lineHash(e.filePath, l));
59
+ for (const l of e.removed)
60
+ if (l.trim())
61
+ removed.add(lineHash(e.filePath, l));
62
+ }
63
+ return { added: [...added].slice(0, 5000), removed: [...removed].slice(0, 5000) };
64
+ }
65
+ /**
66
+ * True when `next` removes at least `threshold` (default 80 %) of the lines `prev` added (min. 3
67
+ * lines), i.e. the next turn reverted this one.
68
+ */
69
+ export function detectRevert(prev, next, threshold = 0.8) {
70
+ if (prev.added.length < 3)
71
+ return false;
72
+ const removed = new Set(next.removed);
73
+ const undone = prev.added.filter((h) => removed.has(h)).length;
74
+ return undone / prev.added.length >= threshold;
75
+ }
76
+ //# sourceMappingURL=outcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outcome.js","sourceRoot":"","sources":["../../src/analysis/outcome.ts"],"names":[],"mappings":"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"}