hebbian 0.5.2 → 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/digest.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export interface DigestResult {
2
2
  corrections: number;
3
3
  skipped: number;
4
+ toolFailures: number;
4
5
  transcriptPath: string;
5
6
  sessionId: string;
6
7
  }
@@ -10,6 +11,30 @@ export interface ExtractedCorrection {
10
11
  prefix: 'NO' | 'DO' | 'MUST' | 'WARN';
11
12
  keywords: string[];
12
13
  }
14
+ interface TranscriptLine {
15
+ type?: string;
16
+ message?: {
17
+ role?: string;
18
+ content?: string | Array<{
19
+ type: string;
20
+ text?: string;
21
+ tool_use_id?: string;
22
+ is_error?: boolean;
23
+ }>;
24
+ };
25
+ toolUseResult?: {
26
+ stdout?: string;
27
+ stderr?: string;
28
+ status?: string;
29
+ };
30
+ sessionId?: string;
31
+ uuid?: string;
32
+ }
33
+ export interface ToolFailure {
34
+ toolName: string;
35
+ exitCode: number;
36
+ errorText: string;
37
+ }
13
38
  /**
14
39
  * Parse hook input from stdin to extract transcript path and session ID.
15
40
  */
@@ -22,9 +47,26 @@ export declare function readHookInput(stdin: string): {
22
47
  * Auto-processes inbox and writes audit log.
23
48
  */
24
49
  export declare function digestTranscript(brainRoot: string, transcriptPath: string, sessionId?: string): DigestResult;
50
+ /**
51
+ * Parse tool_result blocks from a Claude Code transcript.
52
+ * Returns detected failures (exit code ≠ 0, is_error = true).
53
+ */
54
+ export declare function parseToolResults(transcriptPath: string): ToolFailure[];
55
+ /**
56
+ * Detect a tool failure from a tool_result block.
57
+ * Returns failure info if exit code ≠ 0, null otherwise.
58
+ */
59
+ export declare function detectToolFailure(block: {
60
+ content?: string | Array<{
61
+ type: string;
62
+ text?: string;
63
+ }>;
64
+ is_error?: boolean;
65
+ }, toolUseResult?: TranscriptLine['toolUseResult']): ToolFailure | null;
25
66
  /**
26
67
  * Extract corrections from user messages using pattern matching.
27
68
  * Returns up to MAX_CORRECTIONS_PER_SESSION corrections.
28
69
  */
29
70
  export declare function extractCorrections(messages: string[]): ExtractedCorrection[];
71
+ export {};
30
72
  //# sourceMappingURL=digest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAwDD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAYjG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAsD5G;AA6CD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,mBAAmB,EAAE,CA8B5E"}
1
+ {"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,UAAU,cAAc;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACpG,CAAC;IACF,aAAa,CAAC,EAAE;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AA+CD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAYjG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAsE5G;AAiDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW,EAAE,CA4BtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,EACxF,aAAa,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,GAC7C,WAAW,GAAG,IAAI,CA8BpB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,mBAAmB,EAAE,CAiC5E"}
package/dist/index.d.ts CHANGED
@@ -24,8 +24,8 @@ export { processInbox, ensureInbox, appendCorrection } from './inbox';
24
24
  export type { Correction, InboxResult } from './inbox';
25
25
  export { installHooks, uninstallHooks, checkHooks } from './hooks';
26
26
  export type { HookStatus } from './hooks';
27
- export { digestTranscript, extractCorrections, readHookInput } from './digest';
28
- export type { DigestResult, ExtractedCorrection } from './digest';
27
+ export { digestTranscript, extractCorrections, readHookInput, parseToolResults, detectToolFailure } from './digest';
28
+ export type { DigestResult, ExtractedCorrection, ToolFailure } from './digest';
29
29
  export { resolveBrainRoot } from './constants';
30
30
  export { growCandidate, promoteCandidates, listCandidates, toCandidatePath, fromCandidatePath } from './candidates';
31
31
  export type { CandidateInfo, PromoteResult } from './candidates';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,YAAY,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAG3G,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACnF,YAAY,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACrD,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACtE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC/E,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACpH,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACrG,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,YAAY,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAG3G,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACnF,YAAY,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACrD,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACtE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACpH,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACpH,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACrG,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -1694,12 +1694,15 @@ var NEGATION_PATTERNS = [
1694
1694
  /^no[,.\s!]/i,
1695
1695
  /\bdon[''\u2019]?t\s+use\b/i,
1696
1696
  /\bavoid\b/i,
1697
- // Korean negation
1697
+ // Korean negation — specific verb forms only to avoid matching incidental 않/대신 in explanations
1698
1698
  /하지\s*마/,
1699
1699
  /안\s*돼/,
1700
- /대신/,
1701
1700
  /쓰지\s*마/,
1702
- /않/
1701
+ /[가-힣]+지\s*마/,
1702
+ /하지\s*않/,
1703
+ // "do not" specifically
1704
+ /쓰지\s*않/
1705
+ // "do not use" specifically
1703
1706
  ];
1704
1707
  var AFFIRMATION_PATTERNS = [
1705
1708
  /\balways\b/i,
@@ -1743,14 +1746,25 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
1743
1746
  const logPath = join15(logDir, `${resolvedSessionId}.jsonl`);
1744
1747
  if (existsSync14(logPath)) {
1745
1748
  console.log(`\u23ED already digested session ${resolvedSessionId}, skip`);
1746
- return { corrections: 0, skipped: 0, transcriptPath, sessionId: resolvedSessionId };
1749
+ return { corrections: 0, skipped: 0, toolFailures: 0, transcriptPath, sessionId: resolvedSessionId };
1747
1750
  }
1748
1751
  const messages = parseTranscript(transcriptPath);
1752
+ const toolFailures = parseToolResults(transcriptPath);
1753
+ for (const failure of toolFailures) {
1754
+ logEpisode(brainRoot, "tool-failure", failure.toolName, failure.errorText);
1755
+ }
1756
+ if (toolFailures.length > 0) {
1757
+ console.log(`\u{1F527} digest: ${toolFailures.length} tool failure(s) logged as episodes`);
1758
+ }
1749
1759
  const corrections = extractCorrections(messages);
1750
- if (corrections.length === 0) {
1760
+ if (corrections.length === 0 && toolFailures.length === 0) {
1751
1761
  console.log(`\u{1F4DD} digest: no corrections found in session ${resolvedSessionId}`);
1752
1762
  writeAuditLog(brainRoot, resolvedSessionId, []);
1753
- return { corrections: 0, skipped: messages.length, transcriptPath, sessionId: resolvedSessionId };
1763
+ return { corrections: 0, skipped: messages.length, toolFailures: toolFailures.length, transcriptPath, sessionId: resolvedSessionId };
1764
+ }
1765
+ if (corrections.length === 0) {
1766
+ writeAuditLog(brainRoot, resolvedSessionId, []);
1767
+ return { corrections: 0, skipped: messages.length, toolFailures: toolFailures.length, transcriptPath, sessionId: resolvedSessionId };
1754
1768
  }
1755
1769
  let applied = 0;
1756
1770
  const auditEntries = [];
@@ -1770,6 +1784,7 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
1770
1784
  return {
1771
1785
  corrections: applied,
1772
1786
  skipped: messages.length - corrections.length,
1787
+ toolFailures: toolFailures.length,
1773
1788
  transcriptPath,
1774
1789
  sessionId: resolvedSessionId
1775
1790
  };
@@ -1801,6 +1816,48 @@ function extractText(content) {
1801
1816
  }
1802
1817
  return null;
1803
1818
  }
1819
+ var MAX_FAILURES_PER_SESSION = 20;
1820
+ function parseToolResults(transcriptPath) {
1821
+ const content = readFileSync6(transcriptPath, "utf8");
1822
+ const lines = content.split("\n").filter(Boolean);
1823
+ const failures = [];
1824
+ for (const line of lines) {
1825
+ if (failures.length >= MAX_FAILURES_PER_SESSION) break;
1826
+ let entry;
1827
+ try {
1828
+ entry = JSON.parse(line);
1829
+ } catch {
1830
+ continue;
1831
+ }
1832
+ if (entry.type !== "user") continue;
1833
+ if (!entry.message || !Array.isArray(entry.message.content)) continue;
1834
+ for (const block of entry.message.content) {
1835
+ if (block.type !== "tool_result") continue;
1836
+ if (!block.is_error) continue;
1837
+ const failure = detectToolFailure(block, entry.toolUseResult);
1838
+ if (failure) failures.push(failure);
1839
+ }
1840
+ }
1841
+ return failures;
1842
+ }
1843
+ function detectToolFailure(block, toolUseResult) {
1844
+ if (!block.is_error) return null;
1845
+ let errorText = "";
1846
+ if (typeof block.content === "string") {
1847
+ errorText = block.content;
1848
+ } else if (Array.isArray(block.content)) {
1849
+ errorText = block.content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("\n");
1850
+ }
1851
+ if (!errorText && typeof toolUseResult === "string") {
1852
+ errorText = toolUseResult;
1853
+ }
1854
+ if (!errorText) return null;
1855
+ const exitMatch = errorText.match(/^Exit code (\d+)/);
1856
+ const exitCode = exitMatch ? parseInt(exitMatch[1], 10) : 1;
1857
+ const firstLine = errorText.split("\n").find((l) => l.trim() && !l.startsWith("Exit code")) || "unknown";
1858
+ const toolName = firstLine.trim().slice(0, 80);
1859
+ return { toolName, exitCode, errorText: errorText.slice(0, 500) };
1860
+ }
1804
1861
  function extractCorrections(messages) {
1805
1862
  const corrections = [];
1806
1863
  for (const text of messages) {
@@ -1810,6 +1867,7 @@ function extractCorrections(messages) {
1810
1867
  if (text.trim().endsWith("?")) continue;
1811
1868
  if (/^<[a-zA-Z]/.test(text.trim())) continue;
1812
1869
  if (/^Base directory for this skill:/i.test(text.trim())) continue;
1870
+ if (/^[•·▸▶\-\*]\s/.test(text.trim())) continue;
1813
1871
  const correction = detectCorrection(text);
1814
1872
  if (correction) {
1815
1873
  corrections.push(correction);
@@ -2505,6 +2563,7 @@ export {
2505
2563
  clearReports,
2506
2564
  contraNeuron,
2507
2565
  detectOutcome,
2566
+ detectToolFailure,
2508
2567
  digestTranscript,
2509
2568
  emitBootstrap,
2510
2569
  emitIndex,
@@ -2525,6 +2584,7 @@ export {
2525
2584
  jaccardSimilarity,
2526
2585
  listCandidates,
2527
2586
  logEpisode,
2587
+ parseToolResults,
2528
2588
  printDiag,
2529
2589
  processInbox,
2530
2590
  promoteCandidates,