tim-hooks 0.1.0-beta.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 (73) hide show
  1. package/README.md +31 -0
  2. package/dist/cadence-runner.d.ts +11 -0
  3. package/dist/cadence-runner.d.ts.map +1 -0
  4. package/dist/cadence-runner.js +30 -0
  5. package/dist/cadence-runner.js.map +1 -0
  6. package/dist/cadence.d.ts +10 -0
  7. package/dist/cadence.d.ts.map +1 -0
  8. package/dist/cadence.js +36 -0
  9. package/dist/cadence.js.map +1 -0
  10. package/dist/checkpoint.d.ts +56 -0
  11. package/dist/checkpoint.d.ts.map +1 -0
  12. package/dist/checkpoint.js +232 -0
  13. package/dist/checkpoint.js.map +1 -0
  14. package/dist/claude-stop.d.ts +32 -0
  15. package/dist/claude-stop.d.ts.map +1 -0
  16. package/dist/claude-stop.js +213 -0
  17. package/dist/claude-stop.js.map +1 -0
  18. package/dist/constants.d.ts +5 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +8 -0
  21. package/dist/constants.js.map +1 -0
  22. package/dist/delta.d.ts +7 -0
  23. package/dist/delta.d.ts.map +1 -0
  24. package/dist/delta.js +53 -0
  25. package/dist/delta.js.map +1 -0
  26. package/dist/hooks.d.ts +39 -0
  27. package/dist/hooks.d.ts.map +1 -0
  28. package/dist/hooks.js +136 -0
  29. package/dist/hooks.js.map +1 -0
  30. package/dist/index.d.ts +13 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +88 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/marker.d.ts +179 -0
  35. package/dist/marker.d.ts.map +1 -0
  36. package/dist/marker.js +590 -0
  37. package/dist/marker.js.map +1 -0
  38. package/dist/phantom-recovery.d.ts +13 -0
  39. package/dist/phantom-recovery.d.ts.map +1 -0
  40. package/dist/phantom-recovery.js +113 -0
  41. package/dist/phantom-recovery.js.map +1 -0
  42. package/dist/project-creation.d.ts +48 -0
  43. package/dist/project-creation.d.ts.map +1 -0
  44. package/dist/project-creation.js +265 -0
  45. package/dist/project-creation.js.map +1 -0
  46. package/dist/prompt-submit.d.ts +16 -0
  47. package/dist/prompt-submit.d.ts.map +1 -0
  48. package/dist/prompt-submit.js +69 -0
  49. package/dist/prompt-submit.js.map +1 -0
  50. package/dist/rebalance.d.ts +17 -0
  51. package/dist/rebalance.d.ts.map +1 -0
  52. package/dist/rebalance.js +91 -0
  53. package/dist/rebalance.js.map +1 -0
  54. package/dist/session-hooks.d.ts +53 -0
  55. package/dist/session-hooks.d.ts.map +1 -0
  56. package/dist/session-hooks.js +167 -0
  57. package/dist/session-hooks.js.map +1 -0
  58. package/dist/update-check.d.ts +5 -0
  59. package/dist/update-check.d.ts.map +1 -0
  60. package/dist/update-check.js +66 -0
  61. package/dist/update-check.js.map +1 -0
  62. package/package.json +24 -0
  63. package/scripts/README-hermes-statusline.md +47 -0
  64. package/scripts/hermes-cli-tim-statusline.patch +75 -0
  65. package/scripts/lib/resolve-tim-cli.sh +30 -0
  66. package/scripts/post-commit.sh +30 -0
  67. package/scripts/tim-claude-session-start.sh +26 -0
  68. package/scripts/tim-cursor-inject.sh +17 -0
  69. package/scripts/tim-hermes-session-cache.sh +32 -0
  70. package/scripts/tim-hermes-statusline.sh +28 -0
  71. package/scripts/tim-post-commit.sh +14 -0
  72. package/scripts/tim-session-start.sh +104 -0
  73. package/scripts/tim-statusline.sh +16 -0
package/dist/marker.js ADDED
@@ -0,0 +1,590 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.CWD_ONLY_MARKER_DISCOVERY_POLICY = exports.DEFAULT_MARKER_DISCOVERY_POLICY = exports.LOCK_TTL_MS = exports.ExclusiveMarkerConflictError = exports.INBOX_LABEL = exports.MARKER_VERSION = exports.CANONICAL_PROJECT_FILENAME = exports.MARKER_LOCK = exports.MARKER_FILENAME = void 0;
37
+ exports.markerPath = markerPath;
38
+ exports.canonicalProjectPath = canonicalProjectPath;
39
+ exports.validateProjectLabel = validateProjectLabel;
40
+ exports.readMarker = readMarker;
41
+ exports.validateMarkerAgainstStore = validateMarkerAgainstStore;
42
+ exports.isUnsafeMarkerDir = isUnsafeMarkerDir;
43
+ exports.writeMarkerAtomic = writeMarkerAtomic;
44
+ exports.writeMarkerExclusive = writeMarkerExclusive;
45
+ exports.writeMarker = writeMarker;
46
+ exports.rotateMarkerSession = rotateMarkerSession;
47
+ exports.syncNearestProjectMarker = syncNearestProjectMarker;
48
+ exports.detectProject = detectProject;
49
+ exports.reconcileMarker = reconcileMarker;
50
+ exports.acquireLock = acquireLock;
51
+ exports.isSessionLocked = isSessionLocked;
52
+ exports.releaseLock = releaseLock;
53
+ exports.findMarkerOptionsFromEnv = findMarkerOptionsFromEnv;
54
+ exports.discoverMarker = discoverMarker;
55
+ exports.findMarker = findMarker;
56
+ exports.buildLoadDirective = buildLoadDirective;
57
+ exports.buildSessionDirective = buildSessionDirective;
58
+ const fs = __importStar(require("fs"));
59
+ const os = __importStar(require("os"));
60
+ const path = __importStar(require("path"));
61
+ const crypto = __importStar(require("node:crypto"));
62
+ const constants_js_1 = require("./constants.js");
63
+ const tim_store_1 = require("tim-store");
64
+ exports.MARKER_FILENAME = '.tim-project';
65
+ exports.MARKER_LOCK = '.tim-project.lock';
66
+ /**
67
+ * Committed default project label for repos that gitignore `.tim-project`.
68
+ * Contains only the stable `project` field; runtime counters live in the
69
+ * local `.tim-project` file created on session start. Override per-machine
70
+ * by creating `.tim-project` in the repo root (it wins over tim.json).
71
+ */
72
+ exports.CANONICAL_PROJECT_FILENAME = 'tim.json';
73
+ /**
74
+ * Current marker schema version. Bump this when the on-disk shape changes;
75
+ * readers detect older files by the missing/unknown `version` field and
76
+ * normalize to the current shape.
77
+ */
78
+ exports.MARKER_VERSION = 2;
79
+ function markerPath(cwd) {
80
+ return path.join(cwd, exports.MARKER_FILENAME);
81
+ }
82
+ function canonicalProjectPath(cwd) {
83
+ return path.join(cwd, exports.CANONICAL_PROJECT_FILENAME);
84
+ }
85
+ /** Valid project labels: P/L/E/N + 4 digits (P0062, L0042, …). */
86
+ const PROJECT_LABEL_PATTERN = /^[PLEN]\d{4}$/;
87
+ /**
88
+ * Shape-valid label that must never be written to `.tim-project`.
89
+ * Used as a vitest fixture / corruption sentinel (see P9999 bug); DB
90
+ * validation also rejects it when the project does not exist.
91
+ */
92
+ const DENIED_MARKER_LABELS = new Set(['P9999']);
93
+ function validateProjectLabel(label) {
94
+ if (DENIED_MARKER_LABELS.has(label))
95
+ return false;
96
+ return PROJECT_LABEL_PATTERN.test(label);
97
+ }
98
+ /**
99
+ * Sentinel label for the Inbox project (P0000). Always treated as
100
+ * valid even when not present in the DB — the Inbox is a system
101
+ * project that tim-store.ensureInboxProject() materializes lazily.
102
+ */
103
+ exports.INBOX_LABEL = 'P0000';
104
+ /**
105
+ * Read a marker and normalize it to the current schema version.
106
+ *
107
+ * - Missing file → null
108
+ * - Corrupt JSON → null
109
+ * - v1 file (no `version` field) → strips `route_exchanges_to` + `sessions`
110
+ * map, sets `version: 2`, returns the upgraded object. The file itself
111
+ * is NOT rewritten here — the next `writeMarker` call upgrades it.
112
+ * - v2 file → returned as-is.
113
+ *
114
+ * Callers always see a v2-conformant `ProjectMarker` regardless of what's
115
+ * on disk. This is the only safe way to evolve the schema without forcing
116
+ * a one-shot migration.
117
+ *
118
+ * When no `.tim-project` exists, falls back to `tim.json` (committed
119
+ * canonical default). A real `.tim-project` always wins — even when
120
+ * corrupt (returns null rather than silently using tim.json).
121
+ */
122
+ function readMarker(cwd) {
123
+ const p = markerPath(cwd);
124
+ if (fs.existsSync(p)) {
125
+ let raw;
126
+ try {
127
+ raw = JSON.parse(fs.readFileSync(p, 'utf8'));
128
+ }
129
+ catch {
130
+ return null;
131
+ }
132
+ return normalizeMarker(raw);
133
+ }
134
+ return readCanonicalProject(cwd);
135
+ }
136
+ /**
137
+ * Read the committed default project from tim.json. Runtime fields use
138
+ * neutral defaults — session start overwrites them into `.tim-project`.
139
+ */
140
+ function readCanonicalProject(cwd) {
141
+ const p = canonicalProjectPath(cwd);
142
+ if (!fs.existsSync(p))
143
+ return null;
144
+ let raw;
145
+ try {
146
+ raw = JSON.parse(fs.readFileSync(p, 'utf8'));
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ if (!raw || typeof raw !== 'object')
152
+ return null;
153
+ const obj = raw;
154
+ if (typeof obj.project !== 'string' || !PROJECT_LABEL_PATTERN.test(obj.project)) {
155
+ console.warn(`[tim-hooks] ${exports.CANONICAL_PROJECT_FILENAME} has malformed project label ` +
156
+ `"${String(obj.project)}" — expected ^[PLEN]\\d{4}$. Ignoring.`);
157
+ return null;
158
+ }
159
+ return {
160
+ version: exports.MARKER_VERSION,
161
+ project: obj.project,
162
+ session: '',
163
+ exchanges: 0,
164
+ batch_size: 5,
165
+ batches_summarized: 0,
166
+ };
167
+ }
168
+ /**
169
+ * Coerce an unknown JSON value into a v2 ProjectMarker. Strips legacy
170
+ * fields. Returns null if the value isn't a usable marker (missing
171
+ * project/session, wrong types, or malformed project label).
172
+ *
173
+ * NOTE: This is the pure-FS reader. The DB-existence check
174
+ * (project label must resolve to a real entry in the TIM DB) lives
175
+ * in `validateMarkerAgainstStore` — called from the two write-side
176
+ * paths (runSessionStart, syncNearestProjectMarker) before they
177
+ * persist anything. We deliberately keep the disk reader free of
178
+ * DB dependencies so hooks under a tight timeout can still parse
179
+ * the marker without paying for an SQLite roundtrip.
180
+ */
181
+ function normalizeMarker(raw) {
182
+ if (!raw || typeof raw !== 'object')
183
+ return null;
184
+ const obj = raw;
185
+ if (typeof obj.project !== 'string' || obj.project.length === 0)
186
+ return null;
187
+ if (!PROJECT_LABEL_PATTERN.test(obj.project)) {
188
+ console.warn(`[tim-hooks] .tim-project has malformed project label "${obj.project}" — ` +
189
+ `expected ^[PLEN]\\d{4}$ (P0062, L0042, …). Ignoring marker.`);
190
+ return null;
191
+ }
192
+ if (typeof obj.session !== 'string')
193
+ return null;
194
+ if (typeof obj.exchanges !== 'number' || !Number.isFinite(obj.exchanges))
195
+ return null;
196
+ if (typeof obj.batch_size !== 'number' || !Number.isFinite(obj.batch_size))
197
+ return null;
198
+ if (typeof obj.batches_summarized !== 'number' || !Number.isFinite(obj.batches_summarized)) {
199
+ return null;
200
+ }
201
+ return {
202
+ version: exports.MARKER_VERSION,
203
+ project: obj.project,
204
+ session: obj.session,
205
+ exchanges: obj.exchanges,
206
+ batch_size: obj.batch_size,
207
+ batches_summarized: obj.batches_summarized,
208
+ };
209
+ }
210
+ /**
211
+ * Defense-in-depth check: a project label that matches the
212
+ * pattern but is semantically bogus (e.g. `P9999` — a label that
213
+ * was never issued by TIM, often the residue of a hand-edit or a
214
+ * botched commit) must NOT be persisted into `.tim-project`. The
215
+ * original P9999 bug bound the statusline to a non-existent
216
+ * project because the file was trusted blindly.
217
+ *
218
+ * Resolution: pattern-match (already enforced by normalizeMarker)
219
+ * AND the project must exist as a `kind=project` entry in the DB.
220
+ * The Inbox (P0000) is exempt — it's a system project that
221
+ * tim-store creates on first use via `ensureInboxProject`.
222
+ *
223
+ * Returns the marker on success, null on rejection. On DB error
224
+ * (store unavailable, DB locked, etc.) we FAIL OPEN: a corrupted
225
+ * DB is not a license to corrupt the marker, but a transient
226
+ * read failure shouldn't brick the session-start hook. The
227
+ * pattern check in normalizeMarker still ran, so we never accept
228
+ * malformed labels — we just skip the existence confirmation.
229
+ */
230
+ async function validateMarkerAgainstStore(marker, store) {
231
+ if (marker.project === exports.INBOX_LABEL)
232
+ return marker;
233
+ let resolved;
234
+ try {
235
+ resolved = await store.resolveProjectLabel(marker.project);
236
+ }
237
+ catch (err) {
238
+ console.warn(`[tim-hooks] .tim-project validation: DB lookup for "${marker.project}" ` +
239
+ `failed (${err.message ?? err}) — accepting on pattern match only.`);
240
+ return marker;
241
+ }
242
+ if (resolved.status === 'found') {
243
+ return { ...marker, project: resolved.label };
244
+ }
245
+ console.warn(`[tim-hooks] .tim-project has pattern-valid project label "${marker.project}" ` +
246
+ `but no matching entry exists in the DB. Treating as corrupt.`);
247
+ return null;
248
+ }
249
+ /**
250
+ * Shared/system directories where a `.tim-project` must never live: every
251
+ * process can have them as cwd, so a marker there leaks into unrelated
252
+ * sessions via walk-up (observed: a cron with cwd=/tmp wrote /tmp/.tim-project
253
+ * and every process under /tmp inherited it). v1 unsafe set — deliberately
254
+ * minimal and explicit: os.tmpdir() itself and the filesystem root.
255
+ * Subdirectories of tmpdir (mkdtemp scratch dirs) are private and stay legal.
256
+ */
257
+ function isUnsafeMarkerDir(dir) {
258
+ let resolved = path.resolve(dir);
259
+ try {
260
+ resolved = fs.realpathSync(resolved);
261
+ }
262
+ catch { /* nonexistent — compare as-is */ }
263
+ let tmp = path.resolve(os.tmpdir());
264
+ try {
265
+ tmp = fs.realpathSync(tmp);
266
+ }
267
+ catch { /* keep resolved */ }
268
+ return resolved === tmp || resolved === path.parse(resolved).root;
269
+ }
270
+ /** Atomically write JSON to `filePath` (tmp + rename — no torn reads on POSIX). */
271
+ function writeMarkerAtomic(filePath, content) {
272
+ const tmp = `${filePath}.tmp.${process.pid}`;
273
+ fs.writeFileSync(tmp, content);
274
+ fs.renameSync(tmp, filePath);
275
+ }
276
+ class ExclusiveMarkerConflictError extends Error {
277
+ filePath;
278
+ constructor(filePath) {
279
+ super(`Local marker already exists: ${filePath}`);
280
+ this.filePath = filePath;
281
+ this.name = 'ExclusiveMarkerConflictError';
282
+ }
283
+ }
284
+ exports.ExclusiveMarkerConflictError = ExclusiveMarkerConflictError;
285
+ /** Publish a marker only when no local marker exists already. */
286
+ function writeMarkerExclusive(cwd, marker) {
287
+ if (!validateProjectLabel(marker.project)) {
288
+ throw new Error(`[tim-hooks] writeMarkerExclusive: refusing to write invalid project label "${marker.project}" — ` +
289
+ `expected ^[PLEN]\\d{4}$ (P0062, L0042, …). Marker not written.`);
290
+ }
291
+ const filePath = markerPath(cwd);
292
+ const tmp = `${filePath}.tmp.${process.pid}.${crypto.randomUUID()}`;
293
+ const complete = { ...marker, version: exports.MARKER_VERSION };
294
+ let ownsTemp = false;
295
+ try {
296
+ fs.writeFileSync(tmp, JSON.stringify(complete, null, 2), { flag: 'wx' });
297
+ ownsTemp = true;
298
+ try {
299
+ fs.linkSync(tmp, filePath);
300
+ }
301
+ catch (err) {
302
+ if (err.code === 'EEXIST') {
303
+ throw new ExclusiveMarkerConflictError(filePath);
304
+ }
305
+ throw err;
306
+ }
307
+ return complete;
308
+ }
309
+ finally {
310
+ if (ownsTemp) {
311
+ try {
312
+ fs.rmSync(tmp, { force: true });
313
+ }
314
+ catch {
315
+ // Publication success or failure is authoritative; cleanup is best-effort.
316
+ }
317
+ }
318
+ }
319
+ }
320
+ /** Write a project marker file. Always emits the current schema version:
321
+ * the on-disk file becomes v2 on first write, regardless of the caller's
322
+ * input. This is the auto-upgrade path for v1 files. */
323
+ function writeMarker(cwd, marker) {
324
+ if (isUnsafeMarkerDir(cwd)) {
325
+ console.warn(`[tim-hooks] writeMarker: refusing to write ${exports.MARKER_FILENAME} in shared directory ` +
326
+ `"${cwd}" (tmpdir / filesystem root). Marker not written — running markerless.`);
327
+ return;
328
+ }
329
+ if (!validateProjectLabel(marker.project)) {
330
+ console.warn(`[tim-hooks] writeMarker: refusing to write invalid project label "${marker.project}" — ` +
331
+ `expected ^[PLEN]\\d{4}$ (P0062, L0042, …). Marker not written.`);
332
+ return;
333
+ }
334
+ const p = markerPath(cwd);
335
+ const upgraded = { ...marker, version: exports.MARKER_VERSION };
336
+ writeMarkerAtomic(p, JSON.stringify(upgraded, null, 2));
337
+ }
338
+ /**
339
+ * Rotate the session id in cwd's `.tim-project` when the harness supplies a new one.
340
+ * Used by tim-session-start.sh — must not interpolate paths into JS source.
341
+ */
342
+ function rotateMarkerSession(cwd, sessionId) {
343
+ if (isUnsafeMarkerDir(cwd)) {
344
+ console.warn(`[tim-hooks] rotateMarkerSession: refusing to touch ${exports.MARKER_FILENAME} in shared ` +
345
+ `directory "${cwd}" (tmpdir / filesystem root). Running markerless.`);
346
+ return;
347
+ }
348
+ const p = markerPath(cwd);
349
+ if (!fs.existsSync(p))
350
+ return;
351
+ try {
352
+ const raw = JSON.parse(fs.readFileSync(p, 'utf8'));
353
+ if (raw.session === sessionId)
354
+ return;
355
+ raw.session = sessionId;
356
+ writeMarkerAtomic(p, JSON.stringify(raw, null, 2));
357
+ }
358
+ catch {
359
+ /* corrupt marker — leave untouched */
360
+ }
361
+ }
362
+ /**
363
+ * Update the nearest `.tim-project` (walk-up from cwd) after tim_load_project.
364
+ * Statusline and hooks read this marker — must match the loaded project label.
365
+ */
366
+ function syncNearestProjectMarker(startCwd, projectLabel, options) {
367
+ if (!validateProjectLabel(projectLabel)) {
368
+ console.warn(`[tim-hooks] syncNearestProjectMarker: refusing to sync invalid project label ` +
369
+ `"${projectLabel}" — expected ^[PLEN]\\d{4}$. Returning false.`);
370
+ return false;
371
+ }
372
+ const located = discoverMarker(startCwd, {
373
+ ...exports.DEFAULT_MARKER_DISCOVERY_POLICY,
374
+ ...options?.findOptions,
375
+ });
376
+ if (!located)
377
+ return false;
378
+ const sessionId = options?.sessionId?.trim();
379
+ const { version: _v, ...rest } = located.marker;
380
+ writeMarker(located.dir, {
381
+ ...rest,
382
+ project: projectLabel,
383
+ ...(sessionId ? { session: sessionId } : {}),
384
+ });
385
+ return true;
386
+ }
387
+ /** Project detection — cwd-only marker (no walk-up). */
388
+ function detectProject(cwd) {
389
+ return discoverMarker(cwd, exports.CWD_ONLY_MARKER_DISCOVERY_POLICY)?.marker ?? null;
390
+ }
391
+ /** Re-derive counters from the DB and persist them into the marker. */
392
+ async function reconcileMarker(store, cwd) {
393
+ const marker = readMarker(cwd);
394
+ if (!marker)
395
+ throw new Error(`No ${exports.MARKER_FILENAME} in ${cwd}`);
396
+ const { exchangeCount, batchesSummarized } = await (0, tim_store_1.deriveCounters)(store, marker.session);
397
+ const reconciled = {
398
+ ...marker,
399
+ exchanges: exchangeCount,
400
+ batches_summarized: batchesSummarized,
401
+ };
402
+ writeMarker(cwd, reconciled);
403
+ // Read back to return the canonical v2 shape (writeMarker upgraded the file).
404
+ return readMarker(cwd) ?? reconciled;
405
+ }
406
+ var constants_js_2 = require("./constants.js");
407
+ Object.defineProperty(exports, "LOCK_TTL_MS", { enumerable: true, get: function () { return constants_js_2.LOCK_TTL_MS; } });
408
+ function acquireLock(cwd) {
409
+ const lock = path.join(cwd, exports.MARKER_LOCK);
410
+ try {
411
+ fs.writeFileSync(lock, JSON.stringify({ pid: process.pid, ts: Date.now() }), { flag: 'wx' });
412
+ return true;
413
+ }
414
+ catch {
415
+ try {
416
+ const raw = JSON.parse(fs.readFileSync(lock, 'utf8'));
417
+ if (Date.now() - raw.ts > constants_js_1.LOCK_TTL_MS) {
418
+ fs.writeFileSync(lock, JSON.stringify({ pid: process.pid, ts: Date.now() }));
419
+ return true;
420
+ }
421
+ }
422
+ catch {
423
+ /* unreadable lock → treat as held */
424
+ }
425
+ return false;
426
+ }
427
+ }
428
+ /** True when an active (non-stale) summarizer/session lock is held. */
429
+ function isSessionLocked(cwd) {
430
+ const lock = path.join(cwd, exports.MARKER_LOCK);
431
+ if (!fs.existsSync(lock))
432
+ return false;
433
+ try {
434
+ const raw = JSON.parse(fs.readFileSync(lock, 'utf8'));
435
+ return Date.now() - raw.ts <= constants_js_1.LOCK_TTL_MS;
436
+ }
437
+ catch {
438
+ return true;
439
+ }
440
+ }
441
+ function releaseLock(cwd) {
442
+ try {
443
+ fs.rmSync(path.join(cwd, exports.MARKER_LOCK), { force: true });
444
+ }
445
+ catch {
446
+ /* ignore */
447
+ }
448
+ }
449
+ /** Production default: walk-up from cwd, home ancestors allowed (statusline / sync paths). */
450
+ exports.DEFAULT_MARKER_DISCOVERY_POLICY = {
451
+ walkUp: true,
452
+ allowHome: true,
453
+ };
454
+ /** Cwd-only binding (session-start hook, checkpoint auto-load). */
455
+ exports.CWD_ONLY_MARKER_DISCOVERY_POLICY = {
456
+ walkUp: false,
457
+ allowHome: false,
458
+ };
459
+ function isInsideRoot(dir, root) {
460
+ const d = path.resolve(dir);
461
+ const r = path.resolve(root);
462
+ return d === r || d.startsWith(r + path.sep);
463
+ }
464
+ /** Test helper: env vars override findMarker scope for spawned CLI. */
465
+ function findMarkerOptionsFromEnv() {
466
+ const maxRoot = process.env.TIM_MARKER_MAX_ROOT?.trim();
467
+ const walkUp = process.env.TIM_MARKER_WALK_UP === '1';
468
+ const allowHome = process.env.TIM_MARKER_ALLOW_HOME === '1';
469
+ if (!maxRoot && !walkUp && !allowHome)
470
+ return undefined;
471
+ return {
472
+ ...(maxRoot ? { maxRoot } : {}),
473
+ ...(walkUp ? { walkUp: true } : {}),
474
+ ...(allowHome ? { allowHome: true } : {}),
475
+ };
476
+ }
477
+ function isHomePath(dir) {
478
+ return path.resolve(dir) === path.resolve(os.homedir());
479
+ }
480
+ function pickMarkerLocation(candidates) {
481
+ return candidates.reduce((best, cur) => path.resolve(cur.dir).length > path.resolve(best.dir).length ? cur : best);
482
+ }
483
+ function scanDirForMarker(dir) {
484
+ // Markers in shared directories (tmpdir, /) are never trusted — treat the
485
+ // dir as marker-free and keep walking, same as any dir without a marker.
486
+ if (isUnsafeMarkerDir(dir))
487
+ return null;
488
+ if (fs.existsSync(markerPath(dir))) {
489
+ const marker = readMarker(dir);
490
+ if (!marker)
491
+ return 'corrupt';
492
+ return { marker, dir };
493
+ }
494
+ const canonical = readCanonicalProject(dir);
495
+ if (canonical)
496
+ return { marker: canonical, dir };
497
+ return null;
498
+ }
499
+ /**
500
+ * Find a project marker from `startCwd` — the single discovery implementation.
501
+ *
502
+ * Policy defaults (when fields omitted): walkUp=true, allowHome=true.
503
+ * Pass `CWD_ONLY_MARKER_DISCOVERY_POLICY` for harness cwd binding.
504
+ */
505
+ function discoverMarker(startCwd, policy = exports.DEFAULT_MARKER_DISCOVERY_POLICY) {
506
+ const walkUp = policy.walkUp ?? true;
507
+ const allowHome = policy.allowHome ?? true;
508
+ const startResolved = path.resolve(startCwd);
509
+ if (!walkUp) {
510
+ const result = scanDirForMarker(startResolved);
511
+ if (result === 'corrupt')
512
+ return null;
513
+ return result;
514
+ }
515
+ const maxRoot = policy.maxRoot ? path.resolve(policy.maxRoot) : null;
516
+ let dir = startResolved;
517
+ const found = [];
518
+ for (let i = 0; i < 256; i++) {
519
+ const result = scanDirForMarker(dir);
520
+ if (result === 'corrupt')
521
+ return null;
522
+ if (result)
523
+ found.push(result);
524
+ const parent = path.dirname(dir);
525
+ if (parent === dir)
526
+ break;
527
+ if (maxRoot && isInsideRoot(dir, maxRoot) && !isInsideRoot(parent, maxRoot))
528
+ break;
529
+ dir = parent;
530
+ }
531
+ if (found.length === 0)
532
+ return null;
533
+ const filtered = found.filter((loc) => {
534
+ if (allowHome)
535
+ return true;
536
+ if (!isHomePath(loc.dir))
537
+ return true;
538
+ return path.resolve(loc.dir) === startResolved;
539
+ });
540
+ if (filtered.length === 0)
541
+ return null;
542
+ return pickMarkerLocation(filtered);
543
+ }
544
+ /**
545
+ * Back-compat wrapper: when `options` is omitted, cwd-only (historical default).
546
+ * Prefer `discoverMarker` with an explicit policy for new code.
547
+ */
548
+ function findMarker(startCwd, options) {
549
+ if (!options) {
550
+ return discoverMarker(startCwd, exports.CWD_ONLY_MARKER_DISCOVERY_POLICY);
551
+ }
552
+ return discoverMarker(startCwd, {
553
+ walkUp: options.walkUp ?? false,
554
+ allowHome: options.allowHome ?? false,
555
+ ...(options.maxRoot ? { maxRoot: options.maxRoot } : {}),
556
+ });
557
+ }
558
+ /**
559
+ * Shared, harness-agnostic directive text. Every start hook (Hermes,
560
+ * Claude Code, Cursor) emits exactly this so wording stays DRY. The TIM
561
+ * marker is authoritative for project binding this turn (see plan §end-state).
562
+ */
563
+ function buildLoadDirective(projectLabel, markerDir, bindingLabel) {
564
+ const display = bindingLabel?.trim() || projectLabel;
565
+ return [
566
+ `📍 TIM project marker detected (.tim-project in ${markerDir}).`,
567
+ `This session is bound to TIM project ${display}.`,
568
+ ``,
569
+ `ACTION: call tim_load_project(label="${projectLabel}") now to load the project ` +
570
+ `brief from the TIM store, then run the tim-session-start skill. STEP 1 ` +
571
+ `(project binding) is already decided by this marker — do NOT ask which ` +
572
+ `project, and do NOT run any hmem/active-project cwd→project resolution. ` +
573
+ `The TIM marker is authoritative for this turn.`,
574
+ ].join('\n');
575
+ }
576
+ /** Directive when project comes from TIM session metadata (no local .tim-project). */
577
+ function buildSessionDirective(projectLabel, cwd, bindingLabel) {
578
+ const display = bindingLabel?.trim() || projectLabel;
579
+ return [
580
+ `📍 TIM session bound to project ${display} (TIM store, cwd ${cwd}).`,
581
+ `This session is bound to TIM project ${display}.`,
582
+ ``,
583
+ `ACTION: call tim_load_project(label="${projectLabel}") now to load the project ` +
584
+ `brief from the TIM store, then run the tim-session-start skill. STEP 1 ` +
585
+ `is already decided by this TIM session — do NOT ask which project, and do NOT ` +
586
+ `run any hmem/active-project cwd→project resolution. The TIM binding is authoritative ` +
587
+ `for this turn.`,
588
+ ].join('\n');
589
+ }
590
+ //# sourceMappingURL=marker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.js","sourceRoot":"","sources":["../src/marker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { TimStore } from 'tim-store';
2
+ import { type ProjectMarker } from './marker.js';
3
+ /**
4
+ * Attempt to recover a real project label when `.tim-project` points at a
5
+ * phantom (pattern-valid label missing from the DB).
6
+ */
7
+ export declare function repairPhantomProjectBinding(store: TimStore, dir: string): Promise<string | null>;
8
+ /** Strip trailing `?` from statusline unbound display labels. */
9
+ export declare function stripUnboundProjectSuffix(label: string): string;
10
+ export declare function formatUnboundProjectLabel(label: string): string;
11
+ export declare function isUnboundProjectLabel(label: string): boolean;
12
+ export declare function markerWithRepairedProject(marker: ProjectMarker, recoveredLabel: string): ProjectMarker;
13
+ //# sourceMappingURL=phantom-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phantom-recovery.d.ts","sourceRoot":"","sources":["../src/phantom-recovery.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAgCrB;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,QAAQ,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BxB;AAED,iEAAiE;AACjE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,aAAa,EACrB,cAAc,EAAE,MAAM,GACrB,aAAa,CAEf"}