@kenkaiiii/ggcoder 5.73.0 → 5.74.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 (69) hide show
  1. package/assets/skills/refactoring/SKILL.md +3 -1
  2. package/dist/app-error.d.ts +21 -0
  3. package/dist/app-error.js +39 -0
  4. package/dist/app-error.js.map +1 -0
  5. package/dist/app-sidecar.js +39 -35
  6. package/dist/app-sidecar.js.map +1 -1
  7. package/dist/core/agent-session.d.ts +2 -2
  8. package/dist/core/agent-session.js +10 -2
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/checklist-detection.d.ts +11 -0
  11. package/dist/core/checklist-detection.js +238 -0
  12. package/dist/core/checklist-detection.js.map +1 -0
  13. package/dist/core/checklist-items.d.ts +180 -0
  14. package/dist/core/checklist-items.js +204 -0
  15. package/dist/core/checklist-items.js.map +1 -0
  16. package/dist/core/checklist-prompt.d.ts +3 -0
  17. package/dist/core/checklist-prompt.js +34 -0
  18. package/dist/core/checklist-prompt.js.map +1 -0
  19. package/dist/core/checklist-snapshot.d.ts +13 -0
  20. package/dist/core/checklist-snapshot.js +29 -0
  21. package/dist/core/checklist-snapshot.js.map +1 -0
  22. package/dist/core/checklist-store.d.ts +59 -0
  23. package/dist/core/checklist-store.js +242 -0
  24. package/dist/core/checklist-store.js.map +1 -0
  25. package/dist/core/lsp/client.d.ts +4 -0
  26. package/dist/core/lsp/client.js +71 -3
  27. package/dist/core/lsp/client.js.map +1 -1
  28. package/dist/core/lsp/manager.d.ts +1 -0
  29. package/dist/core/lsp/manager.js +9 -3
  30. package/dist/core/lsp/manager.js.map +1 -1
  31. package/dist/core/lsp/project-root.d.ts +9 -0
  32. package/dist/core/lsp/project-root.js +75 -0
  33. package/dist/core/lsp/project-root.js.map +1 -0
  34. package/dist/core/lsp/reference-project.d.ts +6 -0
  35. package/dist/core/lsp/reference-project.js +110 -0
  36. package/dist/core/lsp/reference-project.js.map +1 -0
  37. package/dist/core/lsp/servers.js +1 -0
  38. package/dist/core/lsp/servers.js.map +1 -1
  39. package/dist/modes/acp-mode.d.ts +2 -1
  40. package/dist/modes/acp-mode.js +4 -1
  41. package/dist/modes/acp-mode.js.map +1 -1
  42. package/dist/system-prompt.js +4 -4
  43. package/dist/tools/bash.d.ts +4 -1
  44. package/dist/tools/bash.js +32 -7
  45. package/dist/tools/bash.js.map +1 -1
  46. package/dist/tools/checklist.d.ts +56 -0
  47. package/dist/tools/checklist.js +178 -0
  48. package/dist/tools/checklist.js.map +1 -0
  49. package/dist/tools/code-nav.d.ts +1 -1
  50. package/dist/tools/code-nav.js +3 -2
  51. package/dist/tools/code-nav.js.map +1 -1
  52. package/dist/tools/exit-plan.d.ts +2 -2
  53. package/dist/tools/exit-plan.js +7 -1
  54. package/dist/tools/exit-plan.js.map +1 -1
  55. package/dist/tools/index.d.ts +3 -2
  56. package/dist/tools/index.js +3 -0
  57. package/dist/tools/index.js.map +1 -1
  58. package/dist/tools/prompt-hints.js +2 -0
  59. package/dist/tools/prompt-hints.js.map +1 -1
  60. package/dist/tools/tool-tiers.js +1 -0
  61. package/dist/tools/tool-tiers.js.map +1 -1
  62. package/dist/tools/verification-review.d.ts +2 -0
  63. package/dist/tools/verification-review.js +41 -0
  64. package/dist/tools/verification-review.js.map +1 -0
  65. package/dist/ui/tool-line-summary.js +11 -1
  66. package/dist/ui/tool-line-summary.js.map +1 -1
  67. package/dist/ui/transcript/tool-presentation.js +1 -1
  68. package/dist/ui/transcript/tool-presentation.js.map +1 -1
  69. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist-items.js","sourceRoot":"","sources":["../../src/core/checklist-items.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type ChecklistItem } from "./checklist-items.js";
2
+ /** Instructions for checking one checklist item, report-only, recorded through the `checklist` tool. */
3
+ export declare function checklistRunPrompt(item: ChecklistItem): string;
@@ -0,0 +1,34 @@
1
+ // The prompt the app's Checklist screen sends when the user checks one item.
2
+ // Generated from the item definition so it can't drift from the list.
3
+ import { CHECKLIST_FILE, CHECKLIST_STALE_DAYS } from "./checklist-items.js";
4
+ /** Instructions for checking one checklist item, report-only, recorded through the `checklist` tool. */
5
+ export function checklistRunPrompt(item) {
6
+ const skillStep = item.skill
7
+ ? `Load the \`${item.skill}\` skill with the \`skill\` tool and follow its method in report-only mode.`
8
+ : "No skill applies; use your own judgment.";
9
+ const setupNote = item.setupCommand
10
+ ? ` Say that \`/${item.setupCommand}\` would fix most gaps.`
11
+ : "";
12
+ return `# Checklist: ${item.title}
13
+
14
+ Check this project for one item of its health checklist and report in plain words. Results are stored in \`${CHECKLIST_FILE}\` at the project root and become due again after ${CHECKLIST_STALE_DAYS} days.
15
+
16
+ **Check and report only. Do not edit, create, delete, install or commit any project file. Only the \`checklist\` tool writes the record.**
17
+
18
+ ## The item
19
+
20
+ - id: \`${item.id}\`
21
+ - group: ${item.group}
22
+ - what to check: ${item.check}
23
+
24
+ ## Steps
25
+
26
+ 1. The \`checklist\` tool is loaded on demand. Call \`tool_search\` with the query "checklist" first.
27
+ 2. Profile the project briefly: what it is, its stack, whether it has a UI, a deployment, user data.
28
+ 3. Decide whether the item applies. If it clearly doesn't (for example design items for a project with no UI), record \`not-applicable\` with a one-line reason and stop.
29
+ 4. ${skillStep}
30
+ 5. Inspect the code and config, and run the project's real checks where relevant (lint, typecheck, tests, audits). Don't guess what a command would print: run it. Configuration being present is not a passing check. Do not run fix/write flags or checks that would alter project files.
31
+ 6. Report in plain words: a bold verdict limited to the reviewed scope, then each finding with file:line, severity and a suggested fix.${setupNote} State what you checked and what you did not check. Never describe a project as safe or fully covered merely because this review found no issues.
32
+ 7. Call \`checklist\` with \`action: "record"\`, \`id: "${item.id}"\`, \`result\` (\`pass\`, \`issues\` or \`not-applicable\`), a one-line \`summary\`, the \`findings\` (required for \`issues\`, empty for \`pass\`) and \`evidence\`: the commands you ran with their outcome, the files you read, and the skill you loaded. Include one evidence line beginning \`Scope:\` and another beginning \`Not checked:\` describing exclusions or missing access. Loading a skill alone is not review evidence. Keep any limited scope explicit in the summary; a narrow check must not claim to resolve unrelated findings from an earlier review. The tool stamps the date and commit itself.`;
33
+ }
34
+ //# sourceMappingURL=checklist-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist-prompt.js","sourceRoot":"","sources":["../../src/core/checklist-prompt.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,sEAAsE;AAEtE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAsB,MAAM,sBAAsB,CAAC;AAEhG,wGAAwG;AACxG,MAAM,UAAU,kBAAkB,CAAC,IAAmB;IACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK;QAC1B,CAAC,CAAC,cAAc,IAAI,CAAC,KAAK,6EAA6E;QACvG,CAAC,CAAC,0CAA0C,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY;QACjC,CAAC,CAAC,gBAAgB,IAAI,CAAC,YAAY,yBAAyB;QAC5D,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,gBAAgB,IAAI,CAAC,KAAK;;6GAE0E,cAAc,qDAAqD,oBAAoB;;;;;;UAM1L,IAAI,CAAC,EAAE;WACN,IAAI,CAAC,KAAK;mBACF,IAAI,CAAC,KAAK;;;;;;;KAOxB,SAAS;;yIAE2H,SAAS;0DACxF,IAAI,CAAC,EAAE,4lBAA4lB,CAAC;AAC9pB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type ChecklistDetection } from "./checklist-detection.js";
2
+ import { type ChecklistRow, type Result } from "./checklist-store.js";
3
+ export interface ChecklistSnapshotRow extends ChecklistRow {
4
+ readonly detection: ChecklistDetection | null;
5
+ readonly runPrompt: string | null;
6
+ }
7
+ export interface ChecklistSnapshot {
8
+ readonly staleAfterDays: number;
9
+ readonly detectionWarnings: readonly string[];
10
+ readonly items: readonly ChecklistSnapshotRow[];
11
+ }
12
+ /** Read-only snapshot shared by the app and the agent tool. */
13
+ export declare function readChecklistSnapshot(cwd: string, now: Date, signal?: AbortSignal): Promise<Result<ChecklistSnapshot>>;
@@ -0,0 +1,29 @@
1
+ import { CHECKLIST_ITEMS, CHECKLIST_STALE_DAYS, getChecklistItem } from "./checklist-items.js";
2
+ import { detectChecklist } from "./checklist-detection.js";
3
+ import { checklistRunPrompt } from "./checklist-prompt.js";
4
+ import { checklistView, readChecklist } from "./checklist-store.js";
5
+ /** Read-only snapshot shared by the app and the agent tool. */
6
+ export async function readChecklistSnapshot(cwd, now, signal) {
7
+ const [record, detection] = await Promise.all([
8
+ readChecklist(cwd, now, signal),
9
+ detectChecklist(cwd, signal),
10
+ ]);
11
+ if (!record.ok)
12
+ return record;
13
+ return {
14
+ ok: true,
15
+ value: {
16
+ staleAfterDays: CHECKLIST_STALE_DAYS,
17
+ detectionWarnings: detection.warnings,
18
+ items: checklistView(CHECKLIST_ITEMS, record.value, now).map((row) => {
19
+ const item = getChecklistItem(row.id);
20
+ return {
21
+ ...row,
22
+ detection: detection.items[row.id] ?? null,
23
+ runPrompt: item ? checklistRunPrompt(item) : null,
24
+ };
25
+ }),
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=checklist-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist-snapshot.js","sourceRoot":"","sources":["../../src/core/checklist-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAkC,MAAM,sBAAsB,CAAC;AAYpG,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAW,EACX,GAAS,EACT,MAAoB;IAEpB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC5C,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC;QAC/B,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC;KAC7B,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAC9B,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,cAAc,EAAE,oBAAoB;YACpC,iBAAiB,EAAE,SAAS,CAAC,QAAQ;YACrC,KAAK,EAAE,aAAa,CAAC,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;gBACnE,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACtC,OAAO;oBACL,GAAG,GAAG;oBACN,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI;oBAC1C,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;iBAClD,CAAC;YACJ,CAAC,CAAC;SACH;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { type ChecklistItem } from "./checklist-items.js";
2
+ export declare const CHECKLIST_RESULTS: readonly ["pass", "issues", "not-applicable"];
3
+ export type ChecklistResult = (typeof CHECKLIST_RESULTS)[number];
4
+ export type ChecklistStatus = "not-run" | "not-applicable" | "due" | "passed" | "needs-work";
5
+ export declare const SUMMARY_MAX = 300;
6
+ export declare const FINDING_MAX = 300;
7
+ export declare const EVIDENCE_MAX = 200;
8
+ export declare const LIST_MAX = 10;
9
+ export interface ChecklistEntry {
10
+ readonly checkedAt: string;
11
+ readonly commit: string | null;
12
+ readonly uncommittedChanges: boolean;
13
+ readonly result: ChecklistResult;
14
+ readonly summary: string;
15
+ readonly findings: readonly string[];
16
+ readonly evidence: readonly string[];
17
+ }
18
+ export interface ChecklistRecord {
19
+ readonly version: 1;
20
+ readonly items: Readonly<Record<string, ChecklistEntry>>;
21
+ }
22
+ export type Result<T, E = string> = {
23
+ ok: true;
24
+ value: T;
25
+ } | {
26
+ ok: false;
27
+ error: E;
28
+ };
29
+ export declare function checklistPath(cwd: string): string;
30
+ /**
31
+ * Read and validate the record. A missing file is an empty record; a file that
32
+ * is not valid JSON (or not a version-1 record) is an error, so a write never
33
+ * silently replaces a teammate's data. Invalid entries are dropped, not fatal.
34
+ */
35
+ export declare function readChecklist(cwd: string, now: Date, signal?: AbortSignal): Promise<Result<ChecklistRecord>>;
36
+ /** Canonical JSON: ids sorted, fixed key order, 2-space indent, trailing newline. */
37
+ export declare function serializeChecklist(record: ChecklistRecord): string;
38
+ /** Lock the whole read/merge/write transaction, then replace the record atomically. */
39
+ export declare function writeChecklistEntry(cwd: string, id: string, entry: ChecklistEntry, now: Date, signal?: AbortSignal): Promise<Result<ChecklistRecord>>;
40
+ export declare function checklistStatus(entry: ChecklistEntry | undefined, now: Date): ChecklistStatus;
41
+ export interface ChecklistRow {
42
+ readonly id: string;
43
+ readonly group: ChecklistItem["group"];
44
+ readonly title: string;
45
+ readonly description: string;
46
+ readonly check: string;
47
+ readonly skill: string | null;
48
+ readonly setupCommand: string | null;
49
+ readonly status: ChecklistStatus;
50
+ readonly checkedAt: string | null;
51
+ readonly commit: string | null;
52
+ readonly uncommittedChanges: boolean;
53
+ readonly result: ChecklistResult | null;
54
+ readonly summary: string | null;
55
+ readonly findings: readonly string[];
56
+ readonly evidence: readonly string[];
57
+ }
58
+ /** Every item in list order, joined with its recorded entry and current status. */
59
+ export declare function checklistView(items: readonly ChecklistItem[], record: ChecklistRecord, now: Date): ChecklistRow[];
@@ -0,0 +1,242 @@
1
+ // Read/write the project health checklist record (`<project>/.gg-checklist.json`).
2
+ // The file is shared through Git, so it is treated as untrusted on the way in:
3
+ // every entry is validated, unknown ids and bad dates are dropped, long text is
4
+ // clipped. Writes are atomic (temp file + rename) and canonical (sorted ids,
5
+ // fixed key order) so diffs between teammates stay small.
6
+ import { randomUUID } from "node:crypto";
7
+ import { constants } from "node:fs";
8
+ import fs, {} from "node:fs/promises";
9
+ import path from "node:path";
10
+ import { setTimeout as delay } from "node:timers/promises";
11
+ import { z } from "zod";
12
+ import { CHECKLIST_FILE, CHECKLIST_STALE_DAYS, getChecklistItem, } from "./checklist-items.js";
13
+ export const CHECKLIST_RESULTS = ["pass", "issues", "not-applicable"];
14
+ export const SUMMARY_MAX = 300;
15
+ export const FINDING_MAX = 300;
16
+ export const EVIDENCE_MAX = 200;
17
+ export const LIST_MAX = 10;
18
+ /** Accept teammates' clocks running a little ahead; anything further is bogus. */
19
+ const FUTURE_SLACK_MS = 24 * 60 * 60 * 1000;
20
+ const STALE_MS = CHECKLIST_STALE_DAYS * 24 * 60 * 60 * 1000;
21
+ const MAX_FILE_BYTES = 1024 * 1024;
22
+ const clip = (max) => z.string().transform((s) => (s.length > max ? s.slice(0, max) : s));
23
+ const clippedList = (max) => z
24
+ .array(z.unknown())
25
+ .catch([])
26
+ .transform((list) => list
27
+ .filter((v) => typeof v === "string" && v.trim() !== "")
28
+ .slice(0, LIST_MAX)
29
+ .map((s) => (s.length > max ? s.slice(0, max) : s)));
30
+ const StoredEntry = z.object({
31
+ checkedAt: z.string().refine((s) => Number.isFinite(Date.parse(s))),
32
+ commit: z
33
+ .string()
34
+ .regex(/^[0-9a-f]{4,64}$/)
35
+ .nullable()
36
+ .catch(null),
37
+ uncommittedChanges: z.boolean().catch(false),
38
+ result: z.enum(CHECKLIST_RESULTS),
39
+ summary: clip(SUMMARY_MAX).catch(""),
40
+ findings: clippedList(FINDING_MAX),
41
+ evidence: clippedList(EVIDENCE_MAX),
42
+ });
43
+ const StoredFile = z.object({
44
+ version: z.literal(1),
45
+ items: z.record(z.string(), z.unknown()),
46
+ });
47
+ export function checklistPath(cwd) {
48
+ return path.join(cwd, CHECKLIST_FILE);
49
+ }
50
+ const EMPTY = { version: 1, items: {} };
51
+ /**
52
+ * Read and validate the record. A missing file is an empty record; a file that
53
+ * is not valid JSON (or not a version-1 record) is an error, so a write never
54
+ * silently replaces a teammate's data. Invalid entries are dropped, not fatal.
55
+ */
56
+ export async function readChecklist(cwd, now, signal) {
57
+ let raw;
58
+ let handle;
59
+ try {
60
+ if (signal?.aborted)
61
+ return { ok: false, error: "Checklist read cancelled" };
62
+ const file = checklistPath(cwd);
63
+ const link = await fs.lstat(file);
64
+ if (link.isSymbolicLink() || !link.isFile()) {
65
+ return { ok: false, error: `${CHECKLIST_FILE} must be a regular file, not a link` };
66
+ }
67
+ handle = await fs.open(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
68
+ const stat = await handle.stat();
69
+ if (!stat.isFile())
70
+ return { ok: false, error: `${CHECKLIST_FILE} must be a regular file` };
71
+ if (stat.size > MAX_FILE_BYTES) {
72
+ return { ok: false, error: `${CHECKLIST_FILE} is larger than 1 MB` };
73
+ }
74
+ const buffer = Buffer.alloc(MAX_FILE_BYTES + 1);
75
+ let length = 0;
76
+ while (length < buffer.length) {
77
+ if (signal?.aborted)
78
+ return { ok: false, error: "Checklist read cancelled" };
79
+ const { bytesRead } = await handle.read(buffer, length, buffer.length - length, null);
80
+ if (bytesRead === 0)
81
+ break;
82
+ length += bytesRead;
83
+ }
84
+ if (length > MAX_FILE_BYTES)
85
+ return { ok: false, error: `${CHECKLIST_FILE} is larger than 1 MB` };
86
+ raw = buffer.subarray(0, length).toString("utf-8");
87
+ }
88
+ catch (err) {
89
+ if (err.code === "ENOENT")
90
+ return { ok: true, value: EMPTY };
91
+ return { ok: false, error: `Could not read ${CHECKLIST_FILE}: ${err.message}` };
92
+ }
93
+ finally {
94
+ await handle?.close();
95
+ }
96
+ let json;
97
+ try {
98
+ json = JSON.parse(raw);
99
+ }
100
+ catch {
101
+ return { ok: false, error: `${CHECKLIST_FILE} is not valid JSON` };
102
+ }
103
+ const file = StoredFile.safeParse(json);
104
+ if (!file.success) {
105
+ return { ok: false, error: `${CHECKLIST_FILE} is not a version 1 checklist record` };
106
+ }
107
+ const items = {};
108
+ const latest = now.getTime() + FUTURE_SLACK_MS;
109
+ for (const [id, value] of Object.entries(file.data.items)) {
110
+ if (!getChecklistItem(id))
111
+ continue;
112
+ const entry = StoredEntry.safeParse(value);
113
+ if (!entry.success)
114
+ continue;
115
+ const checked = Date.parse(entry.data.checkedAt);
116
+ if (checked > latest)
117
+ continue;
118
+ items[id] = { ...entry.data, checkedAt: new Date(checked).toISOString() };
119
+ }
120
+ return { ok: true, value: { version: 1, items } };
121
+ }
122
+ /** Canonical JSON: ids sorted, fixed key order, 2-space indent, trailing newline. */
123
+ export function serializeChecklist(record) {
124
+ const items = {};
125
+ for (const id of Object.keys(record.items).sort()) {
126
+ const e = record.items[id];
127
+ if (!e)
128
+ continue;
129
+ items[id] = {
130
+ checkedAt: e.checkedAt,
131
+ commit: e.commit,
132
+ uncommittedChanges: e.uncommittedChanges,
133
+ result: e.result,
134
+ summary: e.summary,
135
+ findings: [...e.findings],
136
+ evidence: [...e.evidence],
137
+ };
138
+ }
139
+ return JSON.stringify({ version: 1, items }, null, 2) + "\n";
140
+ }
141
+ /** Atomic directory creation serializes distinct tools/processes, not just one session.
142
+ * Fail closed on a busy/interrupted writer; never steal a live lock after a timeout. */
143
+ async function acquireWriteLock(lockPath, signal) {
144
+ const started = performance.now();
145
+ while (true) {
146
+ if (signal?.aborted)
147
+ return { ok: false, error: "Checklist recording cancelled" };
148
+ try {
149
+ await fs.mkdir(lockPath);
150
+ return { ok: true, value: undefined };
151
+ }
152
+ catch (error) {
153
+ if (error.code !== "EEXIST") {
154
+ return {
155
+ ok: false,
156
+ error: `Could not lock ${CHECKLIST_FILE}: ${error.message}`,
157
+ };
158
+ }
159
+ }
160
+ if (performance.now() - started >= 2500) {
161
+ return {
162
+ ok: false,
163
+ error: `${CHECKLIST_FILE} is locked by another or interrupted write. Retry after it finishes; an interrupted write may require removing ${CHECKLIST_FILE}.lock when no checks are running.`,
164
+ };
165
+ }
166
+ try {
167
+ await delay(25, undefined, signal ? { signal } : undefined);
168
+ }
169
+ catch {
170
+ return { ok: false, error: "Checklist recording cancelled" };
171
+ }
172
+ }
173
+ }
174
+ /** Lock the whole read/merge/write transaction, then replace the record atomically. */
175
+ export async function writeChecklistEntry(cwd, id, entry, now, signal) {
176
+ if (!getChecklistItem(id))
177
+ return { ok: false, error: `Unknown checklist item: ${id}` };
178
+ const target = checklistPath(cwd);
179
+ const lockPath = `${target}.lock`;
180
+ const locked = await acquireWriteLock(lockPath, signal);
181
+ if (!locked.ok)
182
+ return locked;
183
+ const temp = `${target}.${process.pid}.${randomUUID()}.tmp`;
184
+ try {
185
+ const current = await readChecklist(cwd, now, signal);
186
+ if (!current.ok)
187
+ return current;
188
+ const next = { version: 1, items: { ...current.value.items, [id]: entry } };
189
+ await fs.writeFile(temp, serializeChecklist(next), {
190
+ encoding: "utf-8",
191
+ flag: "wx",
192
+ ...(signal ? { signal } : {}),
193
+ });
194
+ if (signal?.aborted)
195
+ return { ok: false, error: "Checklist recording cancelled" };
196
+ await fs.rename(temp, target);
197
+ return { ok: true, value: next };
198
+ }
199
+ catch (err) {
200
+ return { ok: false, error: `Could not write ${CHECKLIST_FILE}: ${err.message}` };
201
+ }
202
+ finally {
203
+ await fs.rm(temp, { force: true }).catch(() => { });
204
+ await fs.rmdir(lockPath);
205
+ }
206
+ }
207
+ export function checklistStatus(entry, now) {
208
+ if (!entry)
209
+ return "not-run";
210
+ const checked = Date.parse(entry.checkedAt);
211
+ if (!Number.isFinite(checked) || checked > now.getTime() + FUTURE_SLACK_MS)
212
+ return "not-run";
213
+ if (entry.result === "not-applicable")
214
+ return "not-applicable";
215
+ if (now.getTime() - checked > STALE_MS)
216
+ return "due";
217
+ return entry.result === "pass" ? "passed" : "needs-work";
218
+ }
219
+ /** Every item in list order, joined with its recorded entry and current status. */
220
+ export function checklistView(items, record, now) {
221
+ return items.map((item) => {
222
+ const entry = record.items[item.id];
223
+ return {
224
+ id: item.id,
225
+ group: item.group,
226
+ title: item.title,
227
+ description: item.description,
228
+ check: item.check,
229
+ skill: item.skill ?? null,
230
+ setupCommand: item.setupCommand ?? null,
231
+ status: checklistStatus(entry, now),
232
+ checkedAt: entry?.checkedAt ?? null,
233
+ commit: entry?.commit ?? null,
234
+ uncommittedChanges: entry?.uncommittedChanges ?? false,
235
+ result: entry?.result ?? null,
236
+ summary: entry?.summary ?? null,
237
+ findings: entry?.findings ?? [],
238
+ evidence: entry?.evidence ?? [],
239
+ };
240
+ });
241
+ }
242
+ //# sourceMappingURL=checklist-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist-store.js","sourceRoot":"","sources":["../../src/core/checklist-store.ts"],"names":[],"mappings":"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"}
@@ -55,6 +55,7 @@ export interface LspSymbolEntry {
55
55
  export type LspRequestOutcome<T> = {
56
56
  status: "ok";
57
57
  value: T;
58
+ warning?: string;
58
59
  } | {
59
60
  status: "unsupported";
60
61
  } | {
@@ -115,6 +116,7 @@ export declare class LspClient {
115
116
  private alive;
116
117
  private readonly initializationOptions;
117
118
  private stderrBuffer;
119
+ private referenceProjectFiles;
118
120
  constructor(spec: LspServerSpec, rootPath: string, command: ResolvedCommand);
119
121
  get isAlive(): boolean;
120
122
  /** True while the server reports indexing/analysis through LSP work progress. */
@@ -158,6 +160,8 @@ export declare class LspClient {
158
160
  definition(uri: string, position: LspPosition, timeoutMs: number): Promise<LspRequestOutcome<LspLocation[]>>;
159
161
  /** Every reference to the symbol at `position`, declaration included. */
160
162
  references(uri: string, position: LspPosition, timeoutMs: number, includeDeclaration?: boolean): Promise<LspRequestOutcome<LspLocation[]>>;
163
+ /** Include unopened callers without creating configs or opening stale editor buffers. */
164
+ private prepareReferenceProject;
161
165
  /** Flattened symbol outline for a whole document. */
162
166
  documentSymbols(uri: string, timeoutMs: number): Promise<LspRequestOutcome<LspSymbolEntry[]>>;
163
167
  /** Type/signature summary at `position`, as plain text. */
@@ -1,5 +1,8 @@
1
1
  import { spawn } from "node:child_process";
2
- import { pathToFileURL } from "node:url";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import path from "node:path";
4
+ import { z } from "zod";
5
+ import { collectReferenceProjectFiles } from "./reference-project.js";
3
6
  import { JsonRpcConnection, JsonRpcRequestError } from "./jsonrpc.js";
4
7
  import { getSafeToolEnv } from "../../tools/safe-env.js";
5
8
  import { killProcessTree } from "../../utils/process.js";
@@ -14,6 +17,11 @@ const REQUEST_TIMED_OUT = -32803;
14
17
  const PULL_POLL_INTERVAL_MS = 300;
15
18
  /** Bounded stderr retained per server for failure diagnostics. */
16
19
  const STDERR_TAIL_BYTES = 4000;
20
+ const ProjectInfoReply = z.object({
21
+ success: z.literal(true),
22
+ body: z.object({ configFileName: z.string(), languageServiceDisabled: z.boolean().optional() }),
23
+ });
24
+ const PARTIAL_REFERENCE_COVERAGE = "Reference coverage is partial: the configless project exceeded its indexing budget or could not be fully read. Use grep to check additional callers.";
17
25
  const SHUTDOWN_TIMEOUT_MS = 2000;
18
26
  const KILL_GRACE_MS = 1500;
19
27
  /**
@@ -202,6 +210,7 @@ export class LspClient {
202
210
  alive = true;
203
211
  initializationOptions;
204
212
  stderrBuffer = "";
213
+ referenceProjectFiles;
205
214
  constructor(spec, rootPath, command) {
206
215
  this.spec = spec;
207
216
  this.rootPath = rootPath;
@@ -400,8 +409,67 @@ export class LspClient {
400
409
  return this.navigate("textDocument/definition", { textDocument: { uri }, position }, timeoutMs, "definitionProvider", parseLocations);
401
410
  }
402
411
  /** Every reference to the symbol at `position`, declaration included. */
403
- references(uri, position, timeoutMs, includeDeclaration = true) {
404
- return this.navigate("textDocument/references", { textDocument: { uri }, position, context: { includeDeclaration } }, timeoutMs, "referencesProvider", parseLocations);
412
+ async references(uri, position, timeoutMs, includeDeclaration = true) {
413
+ const started = Date.now();
414
+ const warning = this.spec.id === "typescript"
415
+ ? await this.prepareReferenceProject(uri, timeoutMs)
416
+ : undefined;
417
+ const outcome = await this.navigate("textDocument/references", { textDocument: { uri }, position, context: { includeDeclaration } }, Math.max(1, timeoutMs - (Date.now() - started)), "referencesProvider", parseLocations);
418
+ return outcome.status === "ok" && warning ? { ...outcome, warning } : outcome;
419
+ }
420
+ /** Include unopened callers without creating configs or opening stale editor buffers. */
421
+ async prepareReferenceProject(uri, timeoutMs) {
422
+ const started = Date.now();
423
+ const remaining = () => Math.max(1, timeoutMs - (Date.now() - started));
424
+ const projectFileName = path.join(this.rootPath, ".gg-lsp-reference-project");
425
+ try {
426
+ const reply = await this.conn.request("workspace/executeCommand", {
427
+ command: "typescript.tsserverRequest",
428
+ arguments: [
429
+ "projectInfo",
430
+ { file: fileURLToPath(uri), needFileNameList: false },
431
+ { executionTarget: 0 },
432
+ ],
433
+ }, remaining());
434
+ const parsed = ProjectInfoReply.safeParse(reply);
435
+ if (!parsed.success || parsed.data.body.languageServiceDisabled)
436
+ return PARTIAL_REFERENCE_COVERAGE;
437
+ const config = parsed.data.body.configFileName;
438
+ if (!/[\\/]inferredProject\d+\*$/.test(config) &&
439
+ path.normalize(config) !== path.normalize(projectFileName))
440
+ return undefined;
441
+ const scan = await collectReferenceProjectFiles(this.rootPath, AbortSignal.timeout(Math.min(1000, remaining())));
442
+ const files = [...new Set([...scan.files, fileURLToPath(uri)])].sort();
443
+ const signature = JSON.stringify(files);
444
+ if (signature !== this.referenceProjectFiles) {
445
+ const opened = await this.conn.request("workspace/executeCommand", {
446
+ command: "typescript.tsserverRequest",
447
+ arguments: [
448
+ "openExternalProject",
449
+ {
450
+ projectFileName,
451
+ rootFiles: files.map((fileName) => ({ fileName })),
452
+ options: { allowJs: true, checkJs: false, noEmit: true },
453
+ },
454
+ { executionTarget: 0 },
455
+ ],
456
+ }, remaining());
457
+ if (!z.object({ success: z.literal(true) }).safeParse(opened).success)
458
+ return PARTIAL_REFERENCE_COVERAGE;
459
+ this.referenceProjectFiles = signature;
460
+ log("DEBUG", "lsp", "Prepared configless reference project", {
461
+ server: this.spec.id,
462
+ root: this.rootPath,
463
+ files: files.length,
464
+ complete: scan.complete,
465
+ durationMs: Date.now() - started,
466
+ });
467
+ }
468
+ return scan.complete ? undefined : PARTIAL_REFERENCE_COVERAGE;
469
+ }
470
+ catch {
471
+ return PARTIAL_REFERENCE_COVERAGE;
472
+ }
405
473
  }
406
474
  /** Flattened symbol outline for a whole document. */
407
475
  documentSymbols(uri, timeoutMs) {