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.
- package/dist/commands/clean.d.ts +7 -0
- package/dist/commands/clean.js +17 -8
- package/dist/commands/clear.d.ts +85 -0
- package/dist/commands/clear.js +455 -347
- package/dist/commands/init/index.d.ts +15 -0
- package/dist/commands/init/index.js +79 -38
- package/dist/lib/gitignore-manager.js +12 -13
- package/dist/lib/settings-hierarchy.d.ts +13 -1
- package/dist/lib/settings-hierarchy.js +1 -1
- package/dist/lib/template-linter.d.ts +4 -0
- package/dist/lib/template-linter.js +1 -1
- package/dist/lib/tty-detection.d.ts +1 -0
- package/dist/lib/tty-detection.js +1 -0
- package/dist/templates/CLAUDE.md +1 -1
- package/dist/templates/_shared/.claude/settings.json +64 -9
- package/dist/templates/_shared/.claude/skills/handoff/SKILL.md +1 -1
- package/dist/templates/_shared/.claude/skills/handoff-resume/SKILL.md +1 -1
- package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +43 -0
- package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
- package/dist/templates/_shared/.codex/workflows/meta-plan.md +347 -0
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +4 -221
- package/dist/templates/_shared/.windsurf/workflows/meta-plan.md +11 -0
- package/dist/templates/_shared/hooks-ts/context_monitor.ts +2 -2
- package/dist/templates/_shared/hooks-ts/lint_after_edit.ts +59 -0
- package/dist/templates/_shared/hooks-ts/session_end.ts +11 -10
- package/dist/templates/_shared/hooks-ts/session_start.ts +15 -12
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -12
- package/dist/templates/_shared/lib-ts/CLAUDE.md +27 -2
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +26 -7
- package/dist/templates/_shared/lib-ts/base/inference.ts +16 -16
- package/dist/templates/_shared/lib-ts/base/lint-dispatch.ts +339 -0
- package/dist/templates/_shared/lib-ts/base/state-io.ts +4 -3
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +3 -3
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +16 -15
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +16 -16
- package/dist/templates/_shared/lib-ts/context/context-store.ts +15 -14
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +2 -2
- package/dist/templates/_shared/scripts/resolve-run.ts +62 -0
- package/dist/templates/_shared/scripts/resolve_context.ts +1 -1
- package/dist/templates/_shared/scripts/status_line.ts +74 -65
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/CLAUDE.md +14 -14
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/document-generator.ts +10 -9
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/handoff-reader.ts +5 -4
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/resume_handoff.ts +6 -6
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/save_handoff.ts +19 -20
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff-resume.md +2 -2
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff.md +5 -5
- package/dist/templates/_shared/skills/meta-plan/CLAUDE.md +46 -0
- package/dist/templates/_shared/skills/meta-plan/workflows/meta-plan.md +277 -0
- package/dist/templates/cc-native/.claude/settings.json +13 -111
- package/dist/templates/cc-native/_cc-native/artifacts/lib/format.ts +22 -20
- package/dist/templates/cc-native/_cc-native/artifacts/lib/index.ts +11 -11
- package/dist/templates/cc-native/_cc-native/artifacts/lib/tracker.ts +7 -6
- package/dist/templates/cc-native/_cc-native/artifacts/lib/write.ts +17 -16
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +32 -2
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +9 -7
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +25 -0
- package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +2 -2
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +15 -16
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +19 -19
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +3 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +6 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +16 -12
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +2 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +7 -6
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +9 -7
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +17 -14
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +41 -37
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +43 -33
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +9 -8
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +4 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +8 -9
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +20 -19
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +1 -0
- package/dist/templates/cc-native/_cc-native/plan-review/CODING-STANDARDS-CHECKLIST.md +75 -0
- package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +2 -3
- package/dist/templates/cc-native/_cc-native/plan-review/lib/corroboration.ts +69 -16
- package/dist/templates/cc-native/_cc-native/plan-review/lib/graduation.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/orchestrator.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/output-builder.ts +12 -21
- package/dist/templates/cc-native/_cc-native/plan-review/lib/plan-questions.ts +3 -4
- package/dist/templates/cc-native/_cc-native/plan-review/lib/review-pipeline.ts +35 -39
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/agent.ts +2 -3
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/codex-agent.ts +1 -1
- package/oclif.manifest.json +1 -1
- 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
|
-
|
|
82
|
-
|
|
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 (
|
|
131
|
-
logWarn(HOOK_NAME, `HyDE failed: ${
|
|
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 =
|
|
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 (
|
|
260
|
+
} catch (error) {
|
|
258
261
|
logWarn(
|
|
259
262
|
HOOK_NAME,
|
|
260
|
-
`Summarize failed for ${session.result.session_id}: ${
|
|
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 (
|
|
401
|
-
logWarn(HOOK_NAME, `Rank parse failed: ${
|
|
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 {
|
|
16
|
-
import {
|
|
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
|
-
|
|
43
|
-
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
101
|
-
|
|
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 (
|
|
159
|
+
} catch (error) {
|
|
156
160
|
errors++;
|
|
157
|
-
logError(HOOK_NAME, `Error indexing ${session.sessionId}: ${
|
|
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
|
|
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>)
|
|
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.
|
|
259
|
-
const last = parts
|
|
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
|
|
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
|
-
"
|
|
344
|
-
"
|
|
345
|
-
"
|
|
346
|
-
"
|
|
347
|
-
"
|
|
348
|
-
"
|
|
349
|
-
"
|
|
350
|
-
"
|
|
351
|
-
"
|
|
352
|
-
"
|
|
353
|
-
"
|
|
354
|
-
"
|
|
355
|
-
"
|
|
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.
|
|
398
|
+
const normalized = filePath.replaceAll('\\', "/");
|
|
395
399
|
const parts = normalized.split("/");
|
|
396
|
-
const fileName = parts
|
|
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,
|
|
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 {
|
|
16
|
-
import {
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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.
|
|
138
|
+
const pathParts = filePath.replaceAll('\\', "/").split("/");
|
|
139
139
|
const projectsIdx = pathParts.indexOf("projects");
|
|
140
|
-
if (projectsIdx
|
|
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
|
|
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
|
|
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 "
|
|
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
|
-
|
|
224
|
+
}
|
|
225
|
+
case "Edit": {
|
|
226
|
+
return input.file_path ? `${input.file_path}` : "";
|
|
227
|
+
}
|
|
228
|
+
case "Glob": {
|
|
231
229
|
return input.pattern ? `${input.pattern}` : "";
|
|
232
|
-
|
|
230
|
+
}
|
|
231
|
+
case "Grep": {
|
|
233
232
|
return input.pattern ? `/${input.pattern}/` : "";
|
|
234
|
-
|
|
233
|
+
}
|
|
234
|
+
case "Read": {
|
|
235
|
+
return input.file_path ? `${input.file_path}` : "";
|
|
236
|
+
}
|
|
237
|
+
case "Task": {
|
|
235
238
|
return input.description ? `${input.description}` : "";
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
case "WebFetch":
|
|
239
|
+
}
|
|
240
|
+
case "WebFetch": {
|
|
239
241
|
return input.url ? `${input.url}` : "";
|
|
240
|
-
|
|
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 {
|
|
15
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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.
|
|
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 {
|
|
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
|
|
38
|
-
segmentTopic: 3
|
|
39
|
-
keywords: 2
|
|
40
|
-
filesTouched: 2
|
|
38
|
+
summary: 3,
|
|
39
|
+
segmentTopic: 3,
|
|
40
|
+
keywords: 2,
|
|
41
|
+
filesTouched: 2,
|
|
41
42
|
commandsRun: 1.5,
|
|
42
|
-
toolCalls: 1
|
|
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 ??
|
|
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 {
|
|
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, ...(
|
|
129
|
-
mergedAgent.agentDefaults = { model: DEFAULT_AGENT_MODEL, ...(
|
|
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, ...(
|
|
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 (
|
|
76
|
-
if (
|
|
77
|
-
logError("state", `SECURITY: Invalid plan path: ${
|
|
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: ${
|
|
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 (
|
|
113
|
-
if (
|
|
114
|
-
logError("state", `SECURITY: Invalid plan path: ${
|
|
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(
|
|
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 (
|
|
135
|
-
if (
|
|
136
|
-
logError("state", `SECURITY: Invalid plan path in delete: ${
|
|
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: ${
|
|
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
|
|
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 (
|
|
256
|
-
logError("state", `Failed to load iteration state: ${
|
|
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 (
|
|
272
|
-
logError("state", `Failed to save iteration state: ${
|
|
272
|
+
} catch (error) {
|
|
273
|
+
logError("state", `Failed to save iteration state: ${error}`);
|
|
273
274
|
return false;
|
|
274
275
|
}
|
|
275
276
|
}
|