litmus-cli 1.4.40 → 1.4.42

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 (48) hide show
  1. package/README.md +7 -0
  2. package/dist/commands/connect.d.ts +2 -0
  3. package/dist/commands/connect.d.ts.map +1 -1
  4. package/dist/commands/connect.js +27 -8
  5. package/dist/commands/connect.js.map +1 -1
  6. package/dist/commands/doctor.d.ts +20 -2
  7. package/dist/commands/doctor.d.ts.map +1 -1
  8. package/dist/commands/doctor.js +29 -5
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/submit.d.ts.map +1 -1
  11. package/dist/commands/submit.js +1 -42
  12. package/dist/commands/submit.js.map +1 -1
  13. package/dist/index.js +3 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/lib/ai-tracking.d.ts +13 -0
  16. package/dist/lib/ai-tracking.d.ts.map +1 -1
  17. package/dist/lib/ai-tracking.js +71 -0
  18. package/dist/lib/ai-tracking.js.map +1 -1
  19. package/dist/lib/api.d.ts +28 -0
  20. package/dist/lib/api.d.ts.map +1 -1
  21. package/dist/lib/api.js +74 -0
  22. package/dist/lib/api.js.map +1 -1
  23. package/dist/lib/connect-skills.d.ts +40 -0
  24. package/dist/lib/connect-skills.d.ts.map +1 -0
  25. package/dist/lib/connect-skills.js +150 -0
  26. package/dist/lib/connect-skills.js.map +1 -0
  27. package/dist/lib/errors.d.ts.map +1 -1
  28. package/dist/lib/errors.js +4 -0
  29. package/dist/lib/errors.js.map +1 -1
  30. package/dist/lib/hook-logger.cjs +137 -7
  31. package/dist/lib/session-over.d.ts +32 -0
  32. package/dist/lib/session-over.d.ts.map +1 -0
  33. package/dist/lib/session-over.js +99 -0
  34. package/dist/lib/session-over.js.map +1 -0
  35. package/dist/lib/skill-import.d.ts +82 -0
  36. package/dist/lib/skill-import.d.ts.map +1 -0
  37. package/dist/lib/skill-import.js +228 -0
  38. package/dist/lib/skill-import.js.map +1 -0
  39. package/dist/lib/skill-picker.d.ts +28 -0
  40. package/dist/lib/skill-picker.d.ts.map +1 -0
  41. package/dist/lib/skill-picker.js +100 -0
  42. package/dist/lib/skill-picker.js.map +1 -0
  43. package/dist/lib/tracker.d.ts.map +1 -1
  44. package/dist/lib/tracker.js +10 -0
  45. package/dist/lib/tracker.js.map +1 -1
  46. package/dist/lib/watcher.js +8 -0
  47. package/dist/lib/watcher.js.map +1 -1
  48. package/package.json +1 -1
@@ -0,0 +1,228 @@
1
+ import os from "os";
2
+ import path from "path";
3
+ import { createHash } from "crypto";
4
+ import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, statSync, writeFileSync } from "fs";
5
+ /**
6
+ * ENG-2814 — find the candidate's own AI tool skills on THIS machine, for `litmus
7
+ * connect` to offer to import into their workspace.
8
+ *
9
+ * Runs on the laptop because that is the only place the skills are: the workspace
10
+ * cannot see the candidate's home. The upload goes to the same `/workspace/skills`
11
+ * routes the assessment page's Import skills dialog uses, and NOTHING about which
12
+ * files are skills is decided here: `POST /workspace/skills/plan` runs the upload's
13
+ * own parser over the paths and SKILL.md heads and answers with the files to send
14
+ * (`backend/services/candidate_skills.py`). One parser cannot disagree with itself.
15
+ *
16
+ * Every folder an AI tool reads Agent Skills (`<name>/SKILL.md`) from is looked in.
17
+ * A folder that does not exist costs nothing; a skill found in two of them (a
18
+ * `.claude/skills` copy of an `.agents/skills` one, say) is imported once, and the
19
+ * server reports the other as a duplicate.
20
+ */
21
+ export const SKILL_SOURCES = [
22
+ { dir: ".claude/skills", tools: "Claude Code" },
23
+ { dir: ".agents/skills", tools: "Codex, Copilot" },
24
+ { dir: ".codex/skills", tools: "Codex" },
25
+ { dir: ".copilot/skills", tools: "Copilot" },
26
+ { dir: ".cursor/skills", tools: "Cursor" },
27
+ { dir: ".gemini/skills", tools: "Gemini CLI" },
28
+ ];
29
+ const SKILL_FILE = "SKILL.md";
30
+ // Never part of a skill, and big enough to swamp the path list if walked.
31
+ const SKIP_DIRS = new Set(["node_modules", ".git", "__pycache__", ".venv", "__MACOSX"]);
32
+ const MAX_DEPTH = 8;
33
+ // The plan route refuses more than 10x the upload's 1000-file cap.
34
+ const MAX_PATHS = 10000;
35
+ // The browser sends the same head: enough for any frontmatter, and the plan body cap
36
+ // is sized for it.
37
+ export const PLAN_HEAD_CHARS = 16 * 1024;
38
+ /** Is `target` the folder `root` or inside it? Both are real paths. */
39
+ function within(root, target) {
40
+ const rel = path.relative(root, target);
41
+ return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
42
+ }
43
+ /**
44
+ * Every file under each skills folder that exists.
45
+ *
46
+ * A link is followed only where it stays inside what the candidate agreed to share.
47
+ * An entry directly under a skills folder may be a link (a skill kept in dotfiles and
48
+ * linked in is common), and it sets the boundary: below it, a file or folder whose
49
+ * real path leaves that entry is not collected, so a link in a skill cannot carry an
50
+ * unrelated file off the laptop under the skill's name.
51
+ */
52
+ export function collectSkillFiles(home = os.homedir()) {
53
+ const out = [];
54
+ const walk = (abs, rel, depth, boundary, seen) => {
55
+ if (out.length >= MAX_PATHS || depth > MAX_DEPTH)
56
+ return;
57
+ let names;
58
+ try {
59
+ names = readdirSync(abs).sort();
60
+ }
61
+ catch {
62
+ return;
63
+ }
64
+ for (const name of names) {
65
+ if (out.length >= MAX_PATHS)
66
+ return;
67
+ const childAbs = path.join(abs, name);
68
+ const childRel = `${rel}/${name}`;
69
+ let real;
70
+ let st;
71
+ try {
72
+ real = realpathSync(childAbs);
73
+ st = statSync(real);
74
+ }
75
+ catch {
76
+ continue;
77
+ }
78
+ // A folder directly under a skills folder is its own boundary. Everything else,
79
+ // a loose file beside the skills included, must stay inside its boundary.
80
+ const linkedSkill = depth === 0 && st.isDirectory();
81
+ if (!linkedSkill && !within(boundary, real))
82
+ continue;
83
+ const bound = linkedSkill ? real : boundary;
84
+ if (st.isDirectory()) {
85
+ // Hidden folders (`.trash`) are skipped by the server anyway; not walking them
86
+ // keeps a big one from eating the path budget.
87
+ if (name.startsWith(".") || SKIP_DIRS.has(name) || seen.has(real))
88
+ continue;
89
+ walk(childAbs, childRel, depth + 1, bound, new Set(seen).add(real));
90
+ }
91
+ else if (st.isFile()) {
92
+ out.push({ path: childRel, abs: real, size: st.size, mtimeMs: st.mtimeMs });
93
+ }
94
+ }
95
+ };
96
+ for (const { dir } of SKILL_SOURCES) {
97
+ const abs = path.join(home, dir);
98
+ if (!existsSync(abs))
99
+ continue;
100
+ let rootReal;
101
+ try {
102
+ rootReal = realpathSync(abs);
103
+ }
104
+ catch {
105
+ continue;
106
+ }
107
+ walk(abs, dir.replace(/^\./, ""), 0, rootReal, new Set([rootReal]));
108
+ }
109
+ return out;
110
+ }
111
+ // The upload's own caps (`candidate_skills.MAX_UPLOAD_BYTES`, `MAX_FILES`). Checked
112
+ // before the offer so a candidate is never asked about an import that cannot succeed.
113
+ export const MAX_UPLOAD_BYTES = 10 * 1024 * 1024;
114
+ export const MAX_UPLOAD_FILES = 1000;
115
+ /** Why these files cannot be uploaded in one import, or null when they fit. */
116
+ export function overUploadCaps(files) {
117
+ const bytes = files.reduce((n, f) => n + f.size, 0);
118
+ if (files.length > MAX_UPLOAD_FILES)
119
+ return `more than ${MAX_UPLOAD_FILES} files`;
120
+ if (bytes > MAX_UPLOAD_BYTES)
121
+ return `over ${MAX_UPLOAD_BYTES / (1024 * 1024)} MB`;
122
+ return null;
123
+ }
124
+ /** The plan route's body: every path, and the head of each SKILL.md. */
125
+ export function planRequest(files) {
126
+ const body = { skipInvalid: true, paths: [], skillFiles: {}, unreadable: [], truncated: [] };
127
+ for (const f of files) {
128
+ body.paths.push(f.path);
129
+ if (path.posix.basename(f.path) !== SKILL_FILE)
130
+ continue;
131
+ let text;
132
+ try {
133
+ text = readFileSync(f.abs, "utf8");
134
+ }
135
+ catch {
136
+ body.unreadable.push(f.path);
137
+ continue;
138
+ }
139
+ let head = text.slice(0, PLAN_HEAD_CHARS);
140
+ if (/[\uD800-\uDBFF]$/.test(head))
141
+ head = head.slice(0, -1);
142
+ body.skillFiles[f.path] = head;
143
+ if (text.length > PLAN_HEAD_CHARS)
144
+ body.truncated.push(f.path);
145
+ }
146
+ return body;
147
+ }
148
+ /** The skill folder names among the paths the server said to send, for the prompt. */
149
+ export function skillNames(kept) {
150
+ const names = new Set();
151
+ for (const p of kept) {
152
+ const parts = p.split("/");
153
+ if (parts[parts.length - 1] === SKILL_FILE && parts.length >= 2)
154
+ names.add(parts[parts.length - 2]);
155
+ }
156
+ return [...names].sort();
157
+ }
158
+ /**
159
+ * What the candidate was last asked about, per assessment, so a candidate who
160
+ * reconnects every day of a work trial is asked again only when their skills changed.
161
+ * A digest of the kept files' paths, sizes and modification times: cheap, and any
162
+ * edit to a skill changes it.
163
+ */
164
+ export function skillSetDigest(files) {
165
+ const h = createHash("sha256");
166
+ for (const f of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
167
+ h.update(`${f.path}\0${f.size}\0${Math.trunc(f.mtimeMs)}\n`);
168
+ }
169
+ return h.digest("hex");
170
+ }
171
+ function stateFile(home) {
172
+ return path.join(home, ".litmus", "skill-imports.json");
173
+ }
174
+ export function lastAnswered(assessmentId, home = os.homedir()) {
175
+ try {
176
+ const state = JSON.parse(readFileSync(stateFile(home), "utf8"));
177
+ const v = state[assessmentId];
178
+ return typeof v === "string" ? v : null;
179
+ }
180
+ catch {
181
+ return null;
182
+ }
183
+ }
184
+ /** Best effort: failing to remember only means being asked again next time. */
185
+ export function rememberAnswered(assessmentId, digest, home = os.homedir()) {
186
+ const file = stateFile(home);
187
+ let state = {};
188
+ try {
189
+ state = JSON.parse(readFileSync(file, "utf8"));
190
+ }
191
+ catch {
192
+ // first write
193
+ }
194
+ state[assessmentId] = digest;
195
+ try {
196
+ mkdirSync(path.dirname(file), { recursive: true });
197
+ writeFileSync(file, JSON.stringify(state, null, 2) + "\n");
198
+ }
199
+ catch {
200
+ // see above
201
+ }
202
+ }
203
+ const DEST_LABEL = {
204
+ claude: "Claude Code",
205
+ agents: "Codex and Copilot",
206
+ continue: "Continue",
207
+ };
208
+ /** What the import did, in the same words the assessment page's dialog used. */
209
+ export function importSummaryLines(result) {
210
+ const lines = [];
211
+ const n = result.installed.length;
212
+ if (n > 0)
213
+ lines.push(`Imported ${n} skill${n === 1 ? "" : "s"}: ${result.installed.join(", ")}.`);
214
+ for (const s of result.skipped) {
215
+ if (s.reason === "agents_skipped")
216
+ continue;
217
+ const why = s.reason === "modified"
218
+ ? "you changed it after importing, so your version was kept"
219
+ : "a skill with that name is already in your workspace";
220
+ lines.push(`Skipped ${s.name} for ${DEST_LABEL[s.dest] ?? s.dest}: ${why}.`);
221
+ }
222
+ if (result.aider === "exists") {
223
+ lines.push("Aider: your ~/.aider.conf.yml was left as is. Run /read ~/.litmus/skills-index.md in Aider.");
224
+ }
225
+ return lines;
226
+ }
227
+ export const SKILLS_PICKUP = "In Copilot, run /skills reload.";
228
+ //# sourceMappingURL=skill-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-import.js","sourceRoot":"","sources":["../../src/lib/skill-import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AAE5G;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,aAAa,GAAkD;IAC1E,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE;IAC/C,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,EAAE;IAClD,EAAE,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE;IACxC,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE;IAC5C,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC1C,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,YAAY,EAAE;CAC/C,CAAA;AAED,MAAM,UAAU,GAAG,UAAU,CAAA;AAC7B,0EAA0E;AAC1E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;AACvF,MAAM,SAAS,GAAG,CAAC,CAAA;AACnB,mEAAmE;AACnE,MAAM,SAAS,GAAG,KAAM,CAAA;AACxB,qFAAqF;AACrF,mBAAmB;AACnB,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,CAAA;AAYxC,uEAAuE;AACvE,SAAS,MAAM,CAAC,IAAY,EAAE,MAAc;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACvC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;AACvE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,CAAC,OAAO,EAAE;IAC3D,MAAM,GAAG,GAAqB,EAAE,CAAA;IAChC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,KAAa,EAAE,QAAgB,EAAE,IAAiB,EAAE,EAAE;QAC5F,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS,IAAI,KAAK,GAAG,SAAS;YAAE,OAAM;QACxD,IAAI,KAAe,CAAA;QACnB,IAAI,CAAC;YACH,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAM;QACR,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS;gBAAE,OAAM;YACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;YACrC,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;YACjC,IAAI,IAAY,CAAA;YAChB,IAAI,EAAE,CAAA;YACN,IAAI,CAAC;gBACH,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;gBAC7B,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;YACrB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAQ;YACV,CAAC;YACD,gFAAgF;YAChF,0EAA0E;YAC1E,MAAM,WAAW,GAAG,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;YACnD,IAAI,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC;gBAAE,SAAQ;YACrD,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAA;YAC3C,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;gBACrB,+EAA+E;gBAC/E,+CAA+C;gBAC/C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAQ;gBAC3E,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YACrE,CAAC;iBAAM,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;gBACvB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAA;YAC7E,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IACD,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,aAAa,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC9B,IAAI,QAAgB,CAAA;QACpB,IAAI,CAAC;YACH,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,oFAAoF;AACpF,sFAAsF;AACtF,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;AAChD,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAA;AAEpC,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,KAAuB;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACnD,IAAI,KAAK,CAAC,MAAM,GAAG,gBAAgB;QAAE,OAAO,aAAa,gBAAgB,QAAQ,CAAA;IACjF,IAAI,KAAK,GAAG,gBAAgB;QAAE,OAAO,QAAQ,gBAAgB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAA;IAClF,OAAO,IAAI,CAAA;AACb,CAAC;AAYD,wEAAwE;AACxE,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,IAAI,GAAqB,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;IAC9G,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACvB,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,UAAU;YAAE,SAAQ;QACxD,IAAI,IAAY,CAAA;QAChB,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAC5B,SAAQ;QACV,CAAC;QACD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAA;QACzC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC3D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;QAC9B,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe;YAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC1B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;IACrG,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAA;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAuB;IACpD,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IAC9B,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACxE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,oBAAoB,CAAC,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,YAAoB,EAAE,OAAe,EAAE,CAAC,OAAO,EAAE;IAC5E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAA;QAC1F,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,CAAA;QAC7B,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,YAAoB,EAAE,MAAc,EAAE,OAAe,EAAE,CAAC,OAAO,EAAE;IAChG,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC5B,IAAI,KAAK,GAA4B,EAAE,CAAA;IACvC,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAA;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,GAAG,MAAM,CAAA;IAC5B,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC;AAUD,MAAM,UAAU,GAA2B;IACzC,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,mBAAmB;IAC3B,QAAQ,EAAE,UAAU;CACrB,CAAA;AAED,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAAC,MAAyB;IAC1D,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAA;IACjC,IAAI,CAAC,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClG,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,gBAAgB;YAAE,SAAQ;QAC3C,MAAM,GAAG,GACP,CAAC,CAAC,MAAM,KAAK,UAAU;YACrB,CAAC,CAAC,0DAA0D;YAC5D,CAAC,CAAC,qDAAqD,CAAA;QAC3D,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,QAAQ,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC,CAAA;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,6FAA6F,CAAC,CAAA;IAC3G,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,iCAAiC,CAAA"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ENG-2814 — the per-skill choice in `litmus connect`: one row per skill with a green
3
+ * ✔ or red ✘ beside it, ↑/↓ to move, Enter to switch a row, and Enter on the last
4
+ * row to finish. Every skill starts kept, since the candidate already said yes.
5
+ *
6
+ * The state and the drawing are plain functions so they are tested without a terminal;
7
+ * `pickSkills` is only the raw-mode loop around them.
8
+ */
9
+ export interface PickerState {
10
+ names: string[];
11
+ kept: boolean[];
12
+ /** 0..names.length; names.length is the Import row. */
13
+ cursor: number;
14
+ }
15
+ export type PickerKey = "up" | "down" | "enter" | "cancel";
16
+ export type PickerStep = {
17
+ state: PickerState;
18
+ } | {
19
+ done: string[] | null;
20
+ };
21
+ export declare function initialPicker(names: string[]): PickerState;
22
+ export declare function pickerStep(s: PickerState, key: PickerKey): PickerStep;
23
+ /** The rows to draw, at most `height` of them around the cursor, plus the hint. */
24
+ export declare function renderPicker(s: PickerState, height?: number): string[];
25
+ /** The names the candidate kept, or null on Esc. The list is cleared once answered:
26
+ * the import summary names what went. */
27
+ export declare function pickSkills(names: string[]): Promise<string[] | null>;
28
+ //# sourceMappingURL=skill-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-picker.d.ts","sourceRoot":"","sources":["../../src/lib/skill-picker.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE1D,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,CAAA;AAE3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,WAAW,CAE1D;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAG,UAAU,CASrE;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAE,MAAiB,GAAG,MAAM,EAAE,CAehF;AAYD;0CAC0C;AAC1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA0CpE"}
@@ -0,0 +1,100 @@
1
+ import readline from "readline";
2
+ import chalk from "chalk";
3
+ export function initialPicker(names) {
4
+ return { names, kept: names.map(() => true), cursor: 0 };
5
+ }
6
+ export function pickerStep(s, key) {
7
+ const last = s.names.length;
8
+ if (key === "cancel")
9
+ return { done: null };
10
+ if (key === "up")
11
+ return { state: { ...s, cursor: s.cursor === 0 ? last : s.cursor - 1 } };
12
+ if (key === "down")
13
+ return { state: { ...s, cursor: s.cursor === last ? 0 : s.cursor + 1 } };
14
+ if (s.cursor === last)
15
+ return { done: s.names.filter((_, i) => s.kept[i]) };
16
+ const kept = [...s.kept];
17
+ kept[s.cursor] = !kept[s.cursor];
18
+ return { state: { ...s, kept } };
19
+ }
20
+ /** The rows to draw, at most `height` of them around the cursor, plus the hint. */
21
+ export function renderPicker(s, height = Infinity) {
22
+ const width = Math.max(...s.names.map((n) => n.length));
23
+ const rows = s.names.map((name, i) => {
24
+ const mark = s.kept[i] ? chalk.green("✔") : chalk.red("✘");
25
+ return `${i === s.cursor ? chalk.cyan("❯") : " "} ${name.padEnd(width)} ${mark}`;
26
+ });
27
+ const n = s.kept.filter(Boolean).length;
28
+ const label = n === 0 ? "Import none" : `Import ${n} skill${n === 1 ? "" : "s"}`;
29
+ rows.push(`${s.cursor === s.names.length ? chalk.cyan("❯") : " "} ${chalk.bold(label)}`);
30
+ const shown = Math.max(1, Math.min(rows.length, height));
31
+ const start = Math.min(Math.max(0, s.cursor - shown + 1), rows.length - shown);
32
+ return [
33
+ chalk.dim(" ↑/↓ to move, Enter to switch ✔/✘, Enter on Import to finish"),
34
+ ...rows.slice(start, start + shown),
35
+ ];
36
+ }
37
+ function toKey(key) {
38
+ if (!key)
39
+ return null;
40
+ if (key.ctrl && key.name === "c")
41
+ return "interrupt";
42
+ if (key.name === "up" || key.name === "k")
43
+ return "up";
44
+ if (key.name === "down" || key.name === "j")
45
+ return "down";
46
+ if (key.name === "return" || key.name === "enter" || key.name === "space")
47
+ return "enter";
48
+ if (key.name === "escape")
49
+ return "cancel";
50
+ return null;
51
+ }
52
+ /** The names the candidate kept, or null on Esc. The list is cleared once answered:
53
+ * the import summary names what went. */
54
+ export function pickSkills(names) {
55
+ const input = process.stdin;
56
+ const out = process.stdout;
57
+ let state = initialPicker(names);
58
+ let drawn = 0;
59
+ const draw = () => {
60
+ if (drawn > 0)
61
+ out.write(`\x1b[${drawn}A`);
62
+ out.write("\x1b[0J");
63
+ const lines = renderPicker(state, Math.max(3, (out.rows || 24) - 4));
64
+ out.write(lines.join("\n") + "\n");
65
+ drawn = lines.length;
66
+ };
67
+ return new Promise((resolve) => {
68
+ readline.emitKeypressEvents(input);
69
+ const wasRaw = input.isRaw;
70
+ input.setRawMode?.(true);
71
+ input.resume();
72
+ out.write("\x1b[?25l");
73
+ const finish = (result) => {
74
+ input.removeListener("keypress", onKey);
75
+ input.setRawMode?.(wasRaw ?? false);
76
+ input.pause();
77
+ out.write(`\x1b[${drawn}A\x1b[0J\x1b[?25h`);
78
+ resolve(result);
79
+ };
80
+ const onKey = (_str, key) => {
81
+ const k = toKey(key);
82
+ if (k === null)
83
+ return;
84
+ // Raw mode swallows Ctrl+C's signal; give it back so connect stops as it would anywhere else.
85
+ if (k === "interrupt") {
86
+ finish(null);
87
+ process.kill(process.pid, "SIGINT");
88
+ return;
89
+ }
90
+ const next = pickerStep(state, k);
91
+ if ("done" in next)
92
+ return finish(next.done);
93
+ state = next.state;
94
+ draw();
95
+ };
96
+ input.on("keypress", onKey);
97
+ draw();
98
+ });
99
+ }
100
+ //# sourceMappingURL=skill-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-picker.js","sourceRoot":"","sources":["../../src/lib/skill-picker.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AA6FA;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAM5D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,oFAAoF;IACpF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,kBAAkB,CA4ChG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CA0FrD"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AA+FA;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAM5D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,oFAAoF;IACpF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,kBAAkB,CA4ChG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAmGrD"}
@@ -2,6 +2,8 @@ import { spawn } from "child_process";
2
2
  import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync, statSync, unlinkSync, closeSync } from "fs";
3
3
  import path from "path";
4
4
  import { fileURLToPath } from "url";
5
+ import { refreshInstalledLoggers } from "./ai-tracking.js";
6
+ import { sessionOverMarked } from "./session-over.js";
5
7
  import { readShadowTrackerFile, shadowTrackerFileMtime, shadowLogPath, writeShadowReviveInfo } from "./shadow.js";
6
8
  const __filename = fileURLToPath(import.meta.url);
7
9
  const __dirname = path.dirname(__filename);
@@ -185,6 +187,14 @@ export function startTracker(projectDir) {
185
187
  const reason = e instanceof Error ? e.message : String(e);
186
188
  throw new Error(`Tracker cannot start: failed to create ${litmusDir} (${reason}).`);
187
189
  }
190
+ // ENG-2768: an assessment initialised by an older CLI runs the logger it was
191
+ // given then; sync any existing copy to this build's before anything else.
192
+ refreshInstalledLoggers(projectDir, path.join(__dirname, "hook-logger.cjs"));
193
+ // ENG-2768: the server has said this session is over. A watcher here would
194
+ // only reinstall the hooks and registry entry the last one released (its
195
+ // first heartbeat self-heals them) and then be told the same thing again.
196
+ if (sessionOverMarked(projectDir))
197
+ return;
188
198
  // Skip respawn only when the existing PID is alive AND the watcher's nonce
189
199
  // is recent — guards against PID reuse leaving us thinking a random shell
190
200
  // is our watcher and silently disabling tracking.
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AAClH,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AACnC,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEjH,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACjD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;AAE1C,MAAM,UAAU,GAAG,eAAe,CAAA;AAClC,gFAAgF;AAChF,0EAA0E;AAC1E,gFAAgF;AAChF,+DAA+D;AAC/D,EAAE;AACF,yEAAyE;AACzE,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,iFAAiF;AACjF,6EAA6E;AAC7E,gFAAgF;AAChF,6EAA6E;AAC7E,uDAAuD;AACvD,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,wCAAwC;AAEhF,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA,CAAC,qCAAqC;QAC1D,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe,EAAE,SAAiB;IAC/D,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IACpD,4EAA4E;IAC5E,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,kBAAkB;IAClB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAA;QACtD,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,gBAAgB,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,eAAe,GAAG,oBAAoB,CAAA;AAC5C,0EAA0E;AAC1E,6EAA6E;AAC7E,6DAA6D;AAC7D,MAAM,mBAAmB,GAAG,KAAM,CAAA;AAElC;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,sEAAsE;YACtE,IAAI,CAAC;gBACH,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,GAAG,mBAAmB,EAAE,CAAC;oBAClE,UAAU,CAAC,QAAQ,CAAC,CAAA;oBACpB,SAAQ,CAAC,uCAAuC;gBAClD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAQ,CAAC,4DAA4D;YACvE,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAClD,OAAO,qBAAqB,CAC1B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,EACnC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CACjC,CAAA;AACH,CAAC;AAkBD,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,YAAqB;IAC1E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;IAElD,IAAI,GAAG,GAAkB,IAAI,CAAA;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;QACjE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,GAAG,GAAG,MAAM,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAE7B,IAAI,UAAU,GAAkB,IAAI,CAAA;IACpC,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAA;IACvD,CAAC;IAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAE1B,uEAAuE;IACvE,2EAA2E;IAC3E,sEAAsE;IACtE,mCAAmC;IACnC,IAAI,GAAG,KAAK,IAAI,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,YAAY,EAAE,aAAa,CAAC,CAAA;QACnE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;YAC5C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBAAE,GAAG,GAAG,MAAM,CAAA;QAClC,CAAC;IACH,CAAC;IACD,IAAI,UAAU,KAAK,IAAI,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,sBAAsB,CAAC,YAAY,EAAE,eAAe,CAAC,CAAA;QACnE,IAAI,KAAK,KAAK,IAAI;YAAE,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;IACrD,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,IAAI,cAAc,CAAC,GAAG,CAAC,CAAA;IACpD,OAAO;QACL,GAAG;QACH,QAAQ;QACR,UAAU;QACV,0EAA0E;QAC1E,wEAAwE;QACxE,sEAAsE;QACtE,yEAAyE;QACzE,8DAA8D;QAC9D,OAAO,EAAE,QAAQ,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,GAAG,CAAC,IAAI,IAAI,UAAU,IAAI,gBAAgB;KACjG,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;IAClD,yEAAyE;IACzE,0EAA0E;IAC1E,uEAAuE;IACvE,uEAAuE;IACvE,+DAA+D;IAC/D,IAAI,YAAY,GAAkB,IAAI,CAAA;IACtC,IAAI,CAAC;QACH,YAAY,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAA+B,CAAC,YAAY,IAAI,IAAI,CAAA;IAC1I,CAAC;IAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACzG,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACtD,CAAC;IAAC,MAAM,CAAC,CAAC,oCAAoC,CAAC,CAAC;IAEhD,0EAA0E;IAC1E,wEAAwE;IACxE,8EAA8E;IAC9E,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACzD,MAAM,IAAI,KAAK,CAAC,0CAA0C,SAAS,KAAK,MAAM,IAAI,CAAC,CAAA;IACrF,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,uBAAuB,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAA;IAE5E,2EAA2E;IAC3E,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,iBAAiB,CAAC,UAAU,CAAC;QAAE,OAAM;IAEzC,2EAA2E;IAC3E,0EAA0E;IAC1E,kDAAkD;IAClD,IAAI,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC;QAAE,OAAM;IAErD,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,uEAAuE;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;IACtD,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IACzC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAM,CAAC,2CAA2C;IAEvE,IAAI,CAAC;QACH,2EAA2E;QAC3E,sDAAsD;QACtD,IAAI,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC;YAAE,OAAM;QAErD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAA;QAEzD,qEAAqE;QACrE,uEAAuE;QACvE,yEAAyE;QACzE,sEAAsE;QACtE,0CAA0C;QAC1C,IAAI,YAAY,EAAE,CAAC;YACjB,qBAAqB,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAA;QACtG,CAAC;QAED,0EAA0E;QAC1E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE;YACnG,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;SACnC,CAAC,CAAA;QAEF,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,IAAI,CAAC;gBACH,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;gBACjD,qEAAqE;gBACrE,qEAAqE;gBACrE,sEAAsE;gBACtE,kEAAkE;gBAClE,sEAAsE;gBACtE,uEAAuE;gBACvE,kEAAkE;gBAClE,sEAAsE;gBACtE,6DAA6D;gBAC7D,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAA;YACtD,CAAC;YAAC,MAAM,CAAC;gBACP,eAAe;YACjB,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;QACxD,IAAI,CAAC;YAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC;IAChE,CAAC;AACH,CAAC"}
@@ -31,6 +31,7 @@ import { fetchInitMetadata, ServerError } from "./api.js";
31
31
  import { resolveBackendBase } from "./api-base.js";
32
32
  import { ServerTimesSchema } from "./schemas.js";
33
33
  import { detectInstalledHooks } from "./ai-tracking.js";
34
+ import { retireAiCaptureForEndedSession, sessionOverMarked } from "./session-over.js";
34
35
  import { readActivityLogTail } from "./activity-tail.js";
35
36
  import { setupAiTracking } from "../commands/init.js";
36
37
  import { writeShadowChainCursor, readShadowChainCursor, writeShadowTrackerFile, writeShadowReviveInfo, readShadowConfigById, findShadowConfigForDir, deleteShadowForAssessment, writeRepairFile, removeRepairFile, REPAIR_FILE_NAME, } from "./shadow.js";
@@ -345,6 +346,9 @@ function uploadEvents() {
345
346
  deleteShadowForAssessment(litmusConfig.assessmentId);
346
347
  removeRepairFile(projectDir);
347
348
  removeOwnedAiNotice(); // ENG-1857: session over — the nudge goes with it
349
+ // ENG-2768: and the AI hooks stop too, or every prompt typed in
350
+ // this folder keeps uploading to be refused.
351
+ retireAiCaptureForEndedSession(projectDir, litmusConfig?.token);
348
352
  shutdown();
349
353
  }
350
354
  }
@@ -889,6 +893,10 @@ function checkHooksPresence() {
889
893
  // Hooks capture nothing without credentials — let the config heal first.
890
894
  if (!configWasPresent)
891
895
  return;
896
+ // ENG-2768: an ended session's hooks were released on purpose; never put
897
+ // them back.
898
+ if (sessionOverMarked(projectDir))
899
+ return;
892
900
  let legs;
893
901
  try {
894
902
  legs = missingHookLegs();