aiwcli 0.12.8 → 0.13.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 (89) hide show
  1. package/dist/commands/clean.d.ts +7 -0
  2. package/dist/commands/clean.js +17 -8
  3. package/dist/commands/clear.d.ts +85 -0
  4. package/dist/commands/clear.js +455 -347
  5. package/dist/commands/init/index.d.ts +15 -0
  6. package/dist/commands/init/index.js +79 -38
  7. package/dist/lib/gitignore-manager.js +12 -13
  8. package/dist/lib/settings-hierarchy.d.ts +13 -1
  9. package/dist/lib/settings-hierarchy.js +1 -1
  10. package/dist/lib/template-linter.d.ts +4 -0
  11. package/dist/lib/template-linter.js +1 -1
  12. package/dist/lib/tty-detection.d.ts +1 -0
  13. package/dist/lib/tty-detection.js +1 -0
  14. package/dist/templates/CLAUDE.md +1 -1
  15. package/dist/templates/_shared/.claude/settings.json +64 -9
  16. package/dist/templates/_shared/.claude/skills/handoff/SKILL.md +1 -1
  17. package/dist/templates/_shared/.claude/skills/handoff-resume/SKILL.md +1 -1
  18. package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +43 -0
  19. package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
  20. package/dist/templates/_shared/.codex/workflows/meta-plan.md +347 -0
  21. package/dist/templates/_shared/.windsurf/workflows/handoff.md +4 -221
  22. package/dist/templates/_shared/.windsurf/workflows/meta-plan.md +11 -0
  23. package/dist/templates/_shared/hooks-ts/context_monitor.ts +2 -2
  24. package/dist/templates/_shared/hooks-ts/lint_after_edit.ts +59 -0
  25. package/dist/templates/_shared/hooks-ts/session_end.ts +11 -10
  26. package/dist/templates/_shared/hooks-ts/session_start.ts +15 -12
  27. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -12
  28. package/dist/templates/_shared/lib-ts/CLAUDE.md +27 -2
  29. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +26 -7
  30. package/dist/templates/_shared/lib-ts/base/inference.ts +16 -16
  31. package/dist/templates/_shared/lib-ts/base/lint-dispatch.ts +339 -0
  32. package/dist/templates/_shared/lib-ts/base/state-io.ts +4 -3
  33. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +3 -3
  34. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +16 -15
  35. package/dist/templates/_shared/lib-ts/context/context-selector.ts +16 -16
  36. package/dist/templates/_shared/lib-ts/context/context-store.ts +15 -14
  37. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +2 -2
  38. package/dist/templates/_shared/scripts/resolve-run.ts +62 -0
  39. package/dist/templates/_shared/scripts/resolve_context.ts +1 -1
  40. package/dist/templates/_shared/scripts/status_line.ts +74 -65
  41. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/CLAUDE.md +14 -14
  42. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/document-generator.ts +10 -9
  43. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/handoff-reader.ts +5 -4
  44. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/resume_handoff.ts +6 -6
  45. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/save_handoff.ts +19 -20
  46. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff-resume.md +2 -2
  47. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff.md +5 -5
  48. package/dist/templates/_shared/skills/meta-plan/CLAUDE.md +46 -0
  49. package/dist/templates/_shared/skills/meta-plan/workflows/meta-plan.md +277 -0
  50. package/dist/templates/cc-native/.claude/settings.json +13 -111
  51. package/dist/templates/cc-native/_cc-native/artifacts/lib/format.ts +22 -20
  52. package/dist/templates/cc-native/_cc-native/artifacts/lib/index.ts +11 -11
  53. package/dist/templates/cc-native/_cc-native/artifacts/lib/tracker.ts +7 -6
  54. package/dist/templates/cc-native/_cc-native/artifacts/lib/write.ts +17 -16
  55. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +32 -2
  56. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +9 -7
  57. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +25 -0
  58. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +2 -2
  59. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +15 -16
  60. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +19 -19
  61. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +3 -3
  62. package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +6 -1
  63. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +16 -12
  64. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +2 -3
  65. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
  66. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +7 -6
  67. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +9 -7
  68. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +17 -14
  69. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +41 -37
  70. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +43 -33
  71. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
  72. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +9 -8
  73. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +4 -3
  74. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +8 -9
  75. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +20 -19
  76. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +1 -1
  77. package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +1 -0
  78. package/dist/templates/cc-native/_cc-native/plan-review/CODING-STANDARDS-CHECKLIST.md +75 -0
  79. package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +2 -3
  80. package/dist/templates/cc-native/_cc-native/plan-review/lib/corroboration.ts +69 -16
  81. package/dist/templates/cc-native/_cc-native/plan-review/lib/graduation.ts +1 -1
  82. package/dist/templates/cc-native/_cc-native/plan-review/lib/orchestrator.ts +1 -1
  83. package/dist/templates/cc-native/_cc-native/plan-review/lib/output-builder.ts +12 -21
  84. package/dist/templates/cc-native/_cc-native/plan-review/lib/plan-questions.ts +3 -4
  85. package/dist/templates/cc-native/_cc-native/plan-review/lib/review-pipeline.ts +35 -39
  86. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/agent.ts +2 -3
  87. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/codex-agent.ts +1 -1
  88. package/oclif.manifest.json +1 -1
  89. package/package.json +6 -5
@@ -13,6 +13,11 @@
13
13
  */
14
14
 
15
15
  import { z } from "zod";
16
+
17
+ import { hydeQueryEmbedding } from "./hyde.js";
18
+ import { logInfo, logWarn, logError } from "./logger.js";
19
+ import { checkOllamaHealth, embedOne } from "./ollama-client.js";
20
+ import { loadTranscript } from "./transcript-loader.js";
16
21
  import {
17
22
  VECTOR_TOP_K,
18
23
  MAX_PARALLEL_SUMMARIZERS,
@@ -26,11 +31,7 @@ import {
26
31
  type RankedSession,
27
32
  type RetrievalResult,
28
33
  } from "./types.js";
29
- import { logInfo, logWarn, logError, logDebug } from "./logger.js";
30
- import { checkOllamaHealth, embedOne } from "./ollama-client.js";
31
34
  import { openVectorDb, searchKnn } from "./vector-store.js";
32
- import { loadTranscript } from "./transcript-loader.js";
33
- import { hydeQueryEmbedding } from "./hyde.js";
34
35
 
35
36
  const HOOK_NAME = "rlm_retrieve";
36
37
 
@@ -78,10 +79,12 @@ if (!query) {
78
79
  );
79
80
  process.exitCode = 1;
80
81
  } else {
81
- runPipeline(query, topK, projectFilter).catch((e) => {
82
- logError(HOOK_NAME, `Fatal: ${e}`, { stderr: true });
82
+ try {
83
+ await runPipeline(query, topK, projectFilter);
84
+ } catch (error) {
85
+ logError(HOOK_NAME, `Fatal: ${error}`, { stderr: true });
83
86
  process.exitCode = 1;
84
- });
87
+ }
85
88
  }
86
89
 
87
90
  // ---------------------------------------------------------------------------
@@ -127,8 +130,8 @@ async function runPipeline(
127
130
  });
128
131
  hydeTiming = Date.now() - hydeStart;
129
132
  logInfo(HOOK_NAME, `HyDE query embedding completed in ${hydeTiming}ms`);
130
- } catch (e) {
131
- logWarn(HOOK_NAME, `HyDE failed: ${e}, falling back to direct query embedding`);
133
+ } catch (error) {
134
+ logWarn(HOOK_NAME, `HyDE failed: ${error}, falling back to direct query embedding`);
132
135
  queryEmbedding = await embedOne(query);
133
136
  }
134
137
  } else {
@@ -182,7 +185,7 @@ async function runPipeline(
182
185
  }
183
186
  }
184
187
  }
185
- const sessions = Array.from(sessionMap.values());
188
+ const sessions = [...sessionMap.values()];
186
189
  logInfo(
187
190
  HOOK_NAME,
188
191
  `Stage 2: ${results.length} chunks → ${sessions.length} sessions`,
@@ -254,10 +257,10 @@ async function summarizeSessions(
254
257
  const promises = batch.map(async (session) => {
255
258
  try {
256
259
  return await summarizeOneSession(query, session);
257
- } catch (e) {
260
+ } catch (error) {
258
261
  logWarn(
259
262
  HOOK_NAME,
260
- `Summarize failed for ${session.result.session_id}: ${e}`,
263
+ `Summarize failed for ${session.result.session_id}: ${error}`,
261
264
  );
262
265
  return null;
263
266
  }
@@ -397,8 +400,8 @@ async function rankSessions(
397
400
  key_findings: r.key_findings,
398
401
  };
399
402
  }).filter((r): r is RankedSession => r !== null);
400
- } catch (e) {
401
- logWarn(HOOK_NAME, `Rank parse failed: ${e}, marking all as relevant`);
403
+ } catch (error) {
404
+ logWarn(HOOK_NAME, `Rank parse failed: ${error}, marking all as relevant`);
402
405
  return summaries.map((s) => ({
403
406
  session_id: s.session_id,
404
407
  project: s.project,
@@ -12,18 +12,18 @@
12
12
  * bun transcript-indexer.ts --batch --project=aiwcli # Index matching project only
13
13
  */
14
14
 
15
- import { readdir, stat, mkdir, readFile, writeFile } from "fs/promises";
16
- import { createReadStream, existsSync, readFileSync } from "fs";
17
- import { join, basename } from "path";
18
- import { createInterface } from "readline";
15
+ import { createReadStream, existsSync } from "node:fs";
16
+ import { readdir, stat, mkdir, writeFile } from "node:fs/promises";
17
+ import { join, basename } from "node:path";
18
+ import { createInterface } from "node:readline";
19
+
20
+ import { logInfo, logWarn, logError } from "./logger.js";
19
21
  import {
20
22
  CURRENT_SCHEMA_VERSION,
21
23
  CLAUDE_PROJECTS_DIR,
22
24
  RLM_INDEX_DIR,
23
25
  type SessionIndex,
24
- type IndexSegment,
25
26
  } from "./types.js";
26
- import { logInfo, logWarn, logError, logDebug } from "./logger.js";
27
27
 
28
28
  const HOOK_NAME = "rlm_indexer";
29
29
 
@@ -39,10 +39,12 @@ const projectArg = args.find((a) => a.startsWith("--project="));
39
39
  const projectFilter = projectArg ? projectArg.split("=")[1] : null;
40
40
 
41
41
  if (isBatch) {
42
- runBatch().catch((e) => {
43
- logError(HOOK_NAME, `Fatal: ${e}`, { stderr: true });
42
+ try {
43
+ await runBatch();
44
+ } catch (error) {
45
+ logError(HOOK_NAME, `Fatal: ${error}`, { stderr: true });
44
46
  process.exitCode = 1;
45
- });
47
+ }
46
48
  }
47
49
 
48
50
  // ---------------------------------------------------------------------------
@@ -89,22 +91,24 @@ async function discoverSessions(): Promise<SessionFile[]> {
89
91
  return sessions;
90
92
  }
91
93
 
92
- function needsIndexing(session: SessionFile, sourceMtime: number): boolean {
94
+ function needsIndexing(session: SessionFile, _sourceMtime: number): boolean {
93
95
  const indexPath = join(RLM_INDEX_DIR, session.project, `${session.sessionId}.index.json`);
94
96
  if (!existsSync(indexPath)) return true;
95
97
  try {
96
98
  // Fast path: Read only first 100 bytes to check schema_version
97
99
  // If version matches, skip without checking mtime (schema bumps trigger full reindex anyway)
98
- const fd = require("fs").openSync(indexPath, "r");
100
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, no-undef -- dynamic fs for perf
101
+ const nodeFs = require("node:fs");
102
+ const fd = nodeFs.openSync(indexPath, "r");
99
103
  const buffer = Buffer.alloc(100);
100
- const bytesRead = require("fs").readSync(fd, buffer, 0, 100, 0);
101
- require("fs").closeSync(fd);
104
+ const bytesRead = nodeFs.readSync(fd, buffer, 0, 100, 0);
105
+ nodeFs.closeSync(fd);
102
106
 
103
107
  const partial = buffer.toString("utf-8", 0, bytesRead);
104
108
  const versionMatch = partial.match(/"schema_version"\s*:\s*(\d+)/);
105
109
 
106
110
  // If version matches, skip (no mtime check needed - schema version bump handles major changes)
107
- if (versionMatch && parseInt(versionMatch[1]) === CURRENT_SCHEMA_VERSION) {
111
+ if (versionMatch && parseInt(versionMatch[1], 10) === CURRENT_SCHEMA_VERSION) {
108
112
  return false; // Skip - index is current
109
113
  }
110
114
 
@@ -152,9 +156,9 @@ async function runBatch(): Promise<void> {
152
156
  if (indexed % 10 === 0 || indexed === 1) {
153
157
  logInfo(HOOK_NAME, `Indexing: ${indexed} indexed, ${skipped} skipped, ${errors} errors (of ${allSessions.length} total)`, { stderr: true });
154
158
  }
155
- } catch (e) {
159
+ } catch (error) {
156
160
  errors++;
157
- logError(HOOK_NAME, `Error indexing ${session.sessionId}: ${e}`);
161
+ logError(HOOK_NAME, `Error indexing ${session.sessionId}: ${error}`);
158
162
  }
159
163
  }
160
164
 
@@ -234,7 +238,7 @@ async function indexSession(session: SessionFile, sourceMtime: number): Promise<
234
238
  index.user_message_count++;
235
239
  const msg = obj.message as Record<string, unknown> | undefined;
236
240
  if (msg) {
237
- const content = msg.content;
241
+ const {content} = msg;
238
242
  if (typeof content === "string") {
239
243
  const snippet = content.slice(0, 200);
240
244
  userSnippets.push(snippet);
@@ -244,7 +248,7 @@ async function indexSession(session: SessionFile, sourceMtime: number): Promise<
244
248
  } else if (Array.isArray(content)) {
245
249
  for (const block of content) {
246
250
  if (typeof block === "object" && block !== null && "text" in block) {
247
- const text = (block as Record<string, unknown>).text;
251
+ const {text} = (block as Record<string, unknown>);
248
252
  if (typeof text === "string") {
249
253
  extractKeywords(text, keywordBag);
250
254
  extractKeywords(text, segmentKeywordBag);
@@ -255,8 +259,8 @@ async function indexSession(session: SessionFile, sourceMtime: number): Promise<
255
259
  // Extract cwd for context
256
260
  const cwd = obj.cwd as string | undefined;
257
261
  if (cwd) {
258
- const parts = cwd.replace(/\\/g, "/").split("/");
259
- const last = parts[parts.length - 1];
262
+ const parts = cwd.replaceAll('\\', "/").split("/");
263
+ const last = parts.at(-1);
260
264
  if (last) addKeyword(keywordBag, last);
261
265
  }
262
266
  // Git branch
@@ -269,7 +273,7 @@ async function indexSession(session: SessionFile, sourceMtime: number): Promise<
269
273
  index.assistant_message_count++;
270
274
  const msg = obj.message as Record<string, unknown> | undefined;
271
275
  if (msg) {
272
- const content = msg.content;
276
+ const {content} = msg;
273
277
  if (Array.isArray(content)) {
274
278
  for (const block of content) {
275
279
  if (typeof block !== "object" || block === null) continue;
@@ -340,19 +344,19 @@ async function indexSession(session: SessionFile, sourceMtime: number): Promise<
340
344
  // ---------------------------------------------------------------------------
341
345
 
342
346
  const STOP_WORDS = new Set([
343
- "the", "a", "an", "is", "are", "was", "were", "be", "been", "being",
344
- "have", "has", "had", "do", "does", "did", "will", "would", "shall",
345
- "should", "may", "might", "must", "can", "could", "of", "in", "to",
346
- "for", "with", "on", "at", "from", "by", "about", "as", "into",
347
- "through", "during", "before", "after", "above", "below", "between",
348
- "and", "but", "or", "nor", "not", "no", "so", "yet", "both", "either",
349
- "neither", "each", "every", "all", "any", "few", "more", "most", "other",
350
- "some", "such", "than", "too", "very", "just", "also", "now", "then",
351
- "here", "there", "when", "where", "why", "how", "what", "which", "who",
352
- "this", "that", "these", "those", "it", "its", "i", "me", "my", "we",
353
- "our", "you", "your", "he", "she", "they", "them", "their", "if",
354
- "true", "false", "null", "undefined", "function", "return", "const",
355
- "let", "var", "import", "export", "default", "class", "new", "type",
347
+ "a", "about", "above", "after", "all", "also", "an", "and", "any", "are",
348
+ "as", "at", "be", "been", "before", "being", "below", "between", "both",
349
+ "but", "by", "can", "class", "const", "could", "default", "did", "do",
350
+ "does", "during", "each", "either", "every", "export", "false", "few", "for",
351
+ "from", "function", "had", "has", "have", "he", "here",
352
+ "how", "i", "if", "import", "in", "into", "is", "it", "its", "just",
353
+ "let", "may", "me", "might", "more", "most", "must", "my", "neither",
354
+ "new", "no", "nor", "not", "now", "null", "of", "on", "or",
355
+ "other", "our", "return", "shall", "she", "should", "so", "some", "such",
356
+ "than", "that", "the", "their", "them", "then", "there", "these", "they", "this",
357
+ "those", "through", "to", "too", "true", "type", "undefined", "var", "very",
358
+ "was", "we", "were", "what", "when", "where", "which",
359
+ "who", "why", "will", "with", "would", "yet", "you", "your",
356
360
  ]);
357
361
 
358
362
  function extractKeywords(text: string, bag: Map<string, number>): void {
@@ -391,9 +395,9 @@ function extractToolMetadata(
391
395
  // File paths from Read, Edit, Write, Glob
392
396
  const filePath = input.file_path as string | undefined;
393
397
  if (filePath) {
394
- const normalized = filePath.replace(/\\/g, "/");
398
+ const normalized = filePath.replaceAll('\\', "/");
395
399
  const parts = normalized.split("/");
396
- const fileName = parts[parts.length - 1];
400
+ const fileName = parts.at(-1);
397
401
  if (fileName) {
398
402
  files.add(fileName);
399
403
  addKeyword(keywords, fileName.replace(/\.[^.]+$/, "")); // stem
@@ -443,4 +447,4 @@ async function writeIndex(project: string, sessionId: string, index: SessionInde
443
447
  // Exports for programmatic use
444
448
  // ---------------------------------------------------------------------------
445
449
 
446
- export { discoverSessions, indexSession, writeIndex, needsIndexing, runBatch };
450
+ export { discoverSessions, indexSession, needsIndexing, runBatch, writeIndex };
@@ -11,11 +11,12 @@
11
11
  * bun transcript-loader.ts <jsonl-path> --lines=46-120
12
12
  */
13
13
 
14
- import { createReadStream } from "fs";
15
- import { createInterface } from "readline";
16
- import { basename } from "path";
14
+ import { createReadStream } from "node:fs";
15
+ import { basename } from "node:path";
16
+ import { createInterface } from "node:readline";
17
+
18
+ import { logInfo, logError } from "./logger.js";
17
19
  import { MAX_LOADER_CHARS, type LoadedSegment } from "./types.js";
18
- import { logInfo, logWarn, logError } from "./logger.js";
19
20
 
20
21
  const HOOK_NAME = "rlm_loader";
21
22
 
@@ -35,17 +36,16 @@ if (linesArg) {
35
36
  }
36
37
 
37
38
  if (jsonlPath && !process.env.RLM_LIB_MODE) {
38
- loadTranscript(jsonlPath, lineRange)
39
- .then((seg) => {
40
- process.stdout.write(seg.content);
41
- if (seg.truncated) {
42
- logInfo(HOOK_NAME, "Output truncated at 50K chars", { stderr: true });
43
- }
44
- })
45
- .catch((e) => {
46
- logError(HOOK_NAME, `Load failed: ${e}`, { stderr: true });
47
- process.exitCode = 1;
48
- });
39
+ try {
40
+ const seg = await loadTranscript(jsonlPath, lineRange);
41
+ process.stdout.write(seg.content);
42
+ if (seg.truncated) {
43
+ logInfo(HOOK_NAME, "Output truncated at 50K chars", { stderr: true });
44
+ }
45
+ } catch (error) {
46
+ logError(HOOK_NAME, `Load failed: ${error}`, { stderr: true });
47
+ process.exitCode = 1;
48
+ }
49
49
  }
50
50
 
51
51
  // ---------------------------------------------------------------------------
@@ -135,9 +135,9 @@ async function loadTranscript(
135
135
  }
136
136
 
137
137
  // Derive project from path
138
- const pathParts = filePath.replace(/\\/g, "/").split("/");
138
+ const pathParts = filePath.replaceAll('\\', "/").split("/");
139
139
  const projectsIdx = pathParts.indexOf("projects");
140
- if (projectsIdx >= 0 && projectsIdx + 1 < pathParts.length) {
140
+ if (projectsIdx !== -1 && projectsIdx + 1 < pathParts.length) {
141
141
  project = pathParts[projectsIdx + 1];
142
142
  }
143
143
 
@@ -155,7 +155,7 @@ async function loadTranscript(
155
155
  // ---------------------------------------------------------------------------
156
156
 
157
157
  function extractContent(msg: Record<string, unknown>): string | null {
158
- const content = msg.content;
158
+ const {content} = msg;
159
159
  if (typeof content === "string") return content;
160
160
  if (Array.isArray(content)) {
161
161
  const texts: string[] = [];
@@ -187,7 +187,7 @@ function extractAssistantContent(msg: Record<string, unknown>): {
187
187
  text: string;
188
188
  toolUses: ToolUse[];
189
189
  } {
190
- const content = msg.content;
190
+ const {content} = msg;
191
191
  let text = "";
192
192
  const toolUses: ToolUse[] = [];
193
193
 
@@ -219,26 +219,36 @@ function extractAssistantContent(msg: Record<string, unknown>): {
219
219
  function summarizeToolInput(toolName: string, input?: Record<string, unknown>): string {
220
220
  if (!input) return "";
221
221
  switch (toolName) {
222
- case "Read":
223
- return input.file_path ? `${input.file_path}` : "";
224
- case "Write":
225
- return input.file_path ? `${input.file_path}` : "";
226
- case "Edit":
227
- return input.file_path ? `${input.file_path}` : "";
228
- case "Bash":
222
+ case "Bash": {
229
223
  return input.command ? `${(input.command as string).slice(0, 80)}` : "";
230
- case "Glob":
224
+ }
225
+ case "Edit": {
226
+ return input.file_path ? `${input.file_path}` : "";
227
+ }
228
+ case "Glob": {
231
229
  return input.pattern ? `${input.pattern}` : "";
232
- case "Grep":
230
+ }
231
+ case "Grep": {
233
232
  return input.pattern ? `/${input.pattern}/` : "";
234
- case "Task":
233
+ }
234
+ case "Read": {
235
+ return input.file_path ? `${input.file_path}` : "";
236
+ }
237
+ case "Task": {
235
238
  return input.description ? `${input.description}` : "";
236
- case "WebSearch":
237
- return input.query ? `"${input.query}"` : "";
238
- case "WebFetch":
239
+ }
240
+ case "WebFetch": {
239
241
  return input.url ? `${input.url}` : "";
240
- default:
242
+ }
243
+ case "WebSearch": {
244
+ return input.query ? `"${input.query}"` : "";
245
+ }
246
+ case "Write": {
247
+ return input.file_path ? `${input.file_path}` : "";
248
+ }
249
+ default: {
241
250
  return Object.keys(input).slice(0, 3).join(", ");
251
+ }
242
252
  }
243
253
  }
244
254
 
@@ -11,12 +11,11 @@
11
11
  * bun transcript-searcher.ts "plan review" --project=aiwcli
12
12
  */
13
13
 
14
- import { readdir, readFile } from "fs/promises";
15
- import { existsSync } from "fs";
16
- import { join } from "path";
17
- import { logInfo, logWarn, logError, logDebug } from "./logger.js";
14
+ import { existsSync } from "node:fs";
15
+ import { readdir, readFile } from "node:fs/promises";
16
+ import { join } from "node:path";
18
17
 
19
- const HOOK_NAME = "rlm_searcher";
18
+ import { logInfo, logWarn, logError } from "./logger.js";
20
19
  import {
21
20
  CURRENT_SCHEMA_VERSION,
22
21
  CLAUDE_PROJECTS_DIR,
@@ -28,6 +27,8 @@ import {
28
27
  type IndexSegment,
29
28
  } from "./types.js";
30
29
 
30
+ const HOOK_NAME = "rlm_searcher";
31
+
31
32
  // ---------------------------------------------------------------------------
32
33
  // CLI entry
33
34
  // ---------------------------------------------------------------------------
@@ -40,20 +41,19 @@ const projectArg = args.find((a) => a.startsWith("--project="));
40
41
  const projectFilter = projectArg ? projectArg.split("=")[1] : null;
41
42
 
42
43
  if (query && !process.env.RLM_LIB_MODE) {
43
- search(query, { topN, projectFilter })
44
- .then((results) => {
45
- if (typeof results === "string") {
46
- logWarn(HOOK_NAME, results, { stderr: true });
47
- process.exitCode = 1;
48
- } else {
49
- logInfo(HOOK_NAME, `Search returned ${results.length} results`);
50
- process.stdout.write(JSON.stringify(results, null, 2) + "\n");
51
- }
52
- })
53
- .catch((e) => {
54
- logError(HOOK_NAME, `Search failed: ${e}`, { stderr: true });
44
+ try {
45
+ const results = await search(query, { topN, projectFilter });
46
+ if (typeof results === "string") {
47
+ logWarn(HOOK_NAME, results, { stderr: true });
55
48
  process.exitCode = 1;
56
- });
49
+ } else {
50
+ logInfo(HOOK_NAME, `Search returned ${results.length} results`);
51
+ process.stdout.write(JSON.stringify(results, null, 2) + "\n");
52
+ }
53
+ } catch (error) {
54
+ logError(HOOK_NAME, `Search failed: ${error}`, { stderr: true });
55
+ process.exitCode = 1;
56
+ }
57
57
  }
58
58
 
59
59
  // ---------------------------------------------------------------------------
@@ -251,7 +251,7 @@ function tokenize(query: string): string[] {
251
251
  return query
252
252
  .toLowerCase()
253
253
  .split(/\s+/)
254
- .map((t) => t.replace(/[^a-z0-9_-]/g, ""))
254
+ .map((t) => t.replaceAll(/[^a-z0-9_-]/g, ""))
255
255
  .filter((t) => t.length >= 2);
256
256
  }
257
257
 
@@ -271,4 +271,4 @@ function insertSorted(arr: SearchResult[], item: SearchResult, maxSize: number):
271
271
  // Exports
272
272
  // ---------------------------------------------------------------------------
273
273
 
274
- export { search, scoreIndex, tokenize, type SearchOptions };
274
+ export { scoreIndex, search, type SearchOptions, tokenize };
@@ -5,8 +5,9 @@
5
5
  * Claude Code session transcripts across all projects.
6
6
  */
7
7
 
8
- import { homedir } from "os";
9
- import { join } from "path";
8
+ import { homedir } from "node:os";
9
+ import { join } from "node:path";
10
+
10
11
  import { getProjectRoot } from "../../../_shared/lib-ts/base/constants.js";
11
12
  import { loadConfig } from "../config.js";
12
13
 
@@ -34,12 +35,12 @@ export const TOP_N_HEAP = 50;
34
35
  // ---------------------------------------------------------------------------
35
36
 
36
37
  export const WEIGHT = {
37
- summary: 3.0,
38
- segmentTopic: 3.0,
39
- keywords: 2.0,
40
- filesTouched: 2.0,
38
+ summary: 3,
39
+ segmentTopic: 3,
40
+ keywords: 2,
41
+ filesTouched: 2,
41
42
  commandsRun: 1.5,
42
- toolCalls: 1.0,
43
+ toolCalls: 1,
43
44
  } as const;
44
45
 
45
46
  // ---------------------------------------------------------------------------
@@ -141,7 +142,7 @@ export const HYDE_NUM_RESPONSES = _ccNativeConfig.numResponses ?? 5;
141
142
  export const HYDE_MAX_TOKENS = _ccNativeConfig.maxTokens ?? 200;
142
143
 
143
144
  /** Per-response generation timeout in milliseconds. Local models usually respond in 500-1500ms. */
144
- export const HYDE_TIMEOUT_MS = _ccNativeConfig.timeoutMs ?? 10000;
145
+ export const HYDE_TIMEOUT_MS = _ccNativeConfig.timeoutMs ?? 10_000;
145
146
 
146
147
  /** Fallback to direct query embedding if HyDE fails? true = graceful degradation (recommended). */
147
148
  export const HYDE_FALLBACK_TO_QUERY = _ccNativeConfig.fallbackToQuery ?? true;
@@ -7,8 +7,9 @@
7
7
 
8
8
  import { Database } from "bun:sqlite";
9
9
  import * as sqliteVec from "sqlite-vec";
10
+
11
+ import { logDebug } from "./logger.js";
10
12
  import { RLM_VECTOR_DB_PATH, EMBED_DIMENSIONS, type VectorSearchResult } from "./types.js";
11
- import { logDebug, logInfo } from "./logger.js";
12
13
 
13
14
  const HOOK_NAME = "rlm_vector";
14
15
 
@@ -154,7 +155,7 @@ export function deleteSessionChunks(
154
155
  `SELECT rowid FROM chunks WHERE session_id = ? AND project = ?`,
155
156
  ).all(sessionId, project);
156
157
 
157
- const rows = (Array.isArray(rawRows) ? rawRows : []).filter(isRowidResult);
158
+ const rows = (Array.isArray(rawRows) ? rawRows : []).filter((row) => isRowidResult(row));
158
159
 
159
160
  if (rows.length > 0) {
160
161
  const tx = db.transaction(() => {
@@ -237,7 +238,7 @@ export function searchKnn(
237
238
  }
238
239
 
239
240
  const rawRows = db.query(sql).all(...params);
240
- const rows = (Array.isArray(rawRows) ? rawRows : []).filter(isSearchResultRow);
241
+ const rows = (Array.isArray(rawRows) ? rawRows : []).filter((row) => isSearchResultRow(row));
241
242
 
242
243
  return rows.map((r) => ({
243
244
  chunk_id: r.rowid,
@@ -5,18 +5,17 @@
5
5
 
6
6
  import * as path from "node:path";
7
7
 
8
- import { logInfo } from "../../_shared/lib-ts/base/logger.js";
9
8
 
9
+ import { aggregateAgents } from "./aggregate-agents.js";
10
+ import { loadConfig, getDisplaySettings } from "./config.js";
11
+ import { DEFAULT_REVIEW_ITERATIONS } from "./state.js";
10
12
  import type {
11
13
  AgentConfig,
12
- OrchestratorConfig,
13
14
  ProviderConfig,
14
15
  ModelsConfig,
15
16
  } from "./types.js";
16
17
  import { DEFAULT_DISPLAY, DEFAULT_SANITIZATION } from "./types.js";
17
- import { loadConfig, getDisplaySettings } from "./config.js";
18
- import { aggregateAgents } from "./aggregate-agents.js";
19
- import { DEFAULT_REVIEW_ITERATIONS } from "./state.js";
18
+ import { logInfo } from "../../_shared/lib-ts/base/logger.js";
20
19
 
21
20
  const HOOK = "settings";
22
21
 
@@ -125,11 +124,11 @@ export function loadSettings(projDir: string): Record<string, unknown> {
125
124
  }
126
125
  mergedAgent.display = getDisplaySettings(config, "agentReview");
127
126
  const configRecord = config as Record<string, unknown>;
128
- mergedAgent.agentSelection = { ...DEFAULT_AGENT_SELECTION, ...((configRecord.agentSelection as Record<string, unknown>) ?? {}) };
129
- mergedAgent.agentDefaults = { model: DEFAULT_AGENT_MODEL, ...((configRecord.agentDefaults as Record<string, unknown>) ?? {}) };
127
+ mergedAgent.agentSelection = { ...DEFAULT_AGENT_SELECTION, ...(configRecord.agentSelection as Record<string, unknown>) };
128
+ mergedAgent.agentDefaults = { model: DEFAULT_AGENT_MODEL, ...(configRecord.agentDefaults as Record<string, unknown>) };
130
129
  mergedAgent.complexityCategories = (configRecord.complexityCategories as string[]) ?? [...DEFAULT_COMPLEXITY_CATEGORIES];
131
- mergedAgent.sanitization = { ...DEFAULT_SANITIZATION, ...((configRecord.sanitization as Record<string, unknown>) ?? {}) };
132
- mergedAgent.reviewIterations = { ...DEFAULT_REVIEW_ITERATIONS, ...agentReview.reviewIterations ?? {} };
130
+ mergedAgent.sanitization = { ...DEFAULT_SANITIZATION, ...(configRecord.sanitization as Record<string, unknown>) };
131
+ mergedAgent.reviewIterations = { ...DEFAULT_REVIEW_ITERATIONS, ...agentReview.reviewIterations };
133
132
 
134
133
  const modelsRaw = (config as Record<string, unknown>).models ?? {};
135
134
  return { planReview: mergedPlan, agentReview: mergedAgent, models: modelsRaw };
@@ -6,11 +6,12 @@
6
6
 
7
7
  import * as fs from "node:fs";
8
8
  import * as path from "node:path";
9
+
10
+ import { validatePlanPath } from "./constants.js";
11
+ import type { IterationState, IterationEntry } from "./types.js";
9
12
  import { atomicWrite } from "../../_shared/lib-ts/base/atomic-write.js";
10
13
  import { logInfo, logWarn, logError } from "../../_shared/lib-ts/base/logger.js";
11
14
  import { nowIso } from "../../_shared/lib-ts/base/utils.js";
12
- import { validatePlanPath } from "./constants.js";
13
- import type { IterationState, IterationEntry } from "./types.js";
14
15
 
15
16
  // ---------------------------------------------------------------------------
16
17
  // Constants
@@ -72,11 +73,11 @@ export function loadState(planPath: string): Record<string, unknown> | null {
72
73
  }
73
74
 
74
75
  return state;
75
- } catch (e: unknown) {
76
- if (e instanceof Error && e.message.includes("Invalid plan path")) {
77
- logError("state", `SECURITY: Invalid plan path: ${e}`);
76
+ } catch (error: unknown) {
77
+ if (error instanceof Error && error.message.includes("Invalid plan path")) {
78
+ logError("state", `SECURITY: Invalid plan path: ${error}`);
78
79
  } else {
79
- logError("state", `Failed to load state: ${e}`);
80
+ logError("state", `Failed to load state: ${error}`);
80
81
  }
81
82
  return null;
82
83
  }
@@ -109,11 +110,11 @@ export function saveStateToPlan(
109
110
  }
110
111
 
111
112
  return true;
112
- } catch (e: unknown) {
113
- if (e instanceof Error && e.message.includes("Invalid plan path")) {
114
- logError("state", `SECURITY: Invalid plan path: ${e}`);
113
+ } catch (error: unknown) {
114
+ if (error instanceof Error && error.message.includes("Invalid plan path")) {
115
+ logError("state", `SECURITY: Invalid plan path: ${error}`);
115
116
  } else {
116
- logError("state", String(e));
117
+ logError("state", String(error));
117
118
  }
118
119
  return false;
119
120
  }
@@ -131,12 +132,12 @@ export function deleteState(planPath: string): boolean {
131
132
  logInfo("state", `Deleted state file: ${stateFile}`);
132
133
  }
133
134
  return true;
134
- } catch (e: unknown) {
135
- if (e instanceof Error && e.message.includes("Invalid plan path")) {
136
- logError("state", `SECURITY: Invalid plan path in delete: ${e}`);
135
+ } catch (error: unknown) {
136
+ if (error instanceof Error && error.message.includes("Invalid plan path")) {
137
+ logError("state", `SECURITY: Invalid plan path in delete: ${error}`);
137
138
  return false;
138
139
  }
139
- logWarn("state", `Failed to delete state file: ${e}`);
140
+ logWarn("state", `Failed to delete state file: ${error}`);
140
141
  return false;
141
142
  }
142
143
  }
@@ -208,7 +209,7 @@ export function shouldContinueIterating(
208
209
  verdict: string,
209
210
  config?: Record<string, unknown>,
210
211
  ): boolean {
211
- const current = iteration.current;
212
+ const {current} = iteration;
212
213
  const maxIter = iteration.max;
213
214
 
214
215
  // At or past max iterations
@@ -252,8 +253,8 @@ export function loadIterationState(reviewsDir: string): IterationState | null {
252
253
  if (!fs.existsSync(iterationFile)) return null;
253
254
  try {
254
255
  return JSON.parse(fs.readFileSync(iterationFile, "utf-8")) as IterationState;
255
- } catch (e) {
256
- logError("state", `Failed to load iteration state: ${e}`);
256
+ } catch (error) {
257
+ logError("state", `Failed to load iteration state: ${error}`);
257
258
  return null;
258
259
  }
259
260
  }
@@ -268,8 +269,8 @@ export function saveIterationState(reviewsDir: string, state: IterationState): b
268
269
  const toWrite = { ...state, schema_version: "1.0.0" };
269
270
  fs.writeFileSync(iterationFile, JSON.stringify(toWrite, null, 2), "utf-8");
270
271
  return true;
271
- } catch (e) {
272
- logError("state", `Failed to save iteration state: ${e}`);
272
+ } catch (error) {
273
+ logError("state", `Failed to save iteration state: ${error}`);
273
274
  return false;
274
275
  }
275
276
  }