instar 0.28.86 → 0.28.88

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 (45) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +9 -0
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/InitiativeTracker.d.ts +1 -0
  5. package/dist/core/InitiativeTracker.d.ts.map +1 -1
  6. package/dist/core/InitiativeTracker.js +8 -1
  7. package/dist/core/InitiativeTracker.js.map +1 -1
  8. package/dist/core/PlanDocParser.d.ts +62 -0
  9. package/dist/core/PlanDocParser.d.ts.map +1 -0
  10. package/dist/core/PlanDocParser.js +328 -0
  11. package/dist/core/PlanDocParser.js.map +1 -0
  12. package/dist/core/ProjectDigestCache.d.ts +58 -0
  13. package/dist/core/ProjectDigestCache.d.ts.map +1 -0
  14. package/dist/core/ProjectDigestCache.js +146 -0
  15. package/dist/core/ProjectDigestCache.js.map +1 -0
  16. package/dist/core/SafeYaml.d.ts +45 -0
  17. package/dist/core/SafeYaml.d.ts.map +1 -0
  18. package/dist/core/SafeYaml.js +230 -0
  19. package/dist/core/SafeYaml.js.map +1 -0
  20. package/dist/core/SessionManager.d.ts +12 -0
  21. package/dist/core/SessionManager.d.ts.map +1 -1
  22. package/dist/core/SessionManager.js +60 -0
  23. package/dist/core/SessionManager.js.map +1 -1
  24. package/dist/core/StageTransitionValidator.d.ts +97 -0
  25. package/dist/core/StageTransitionValidator.d.ts.map +1 -0
  26. package/dist/core/StageTransitionValidator.js +338 -0
  27. package/dist/core/StageTransitionValidator.js.map +1 -0
  28. package/dist/monitoring/StallTriageNurse.d.ts +11 -0
  29. package/dist/monitoring/StallTriageNurse.d.ts.map +1 -1
  30. package/dist/monitoring/StallTriageNurse.js +66 -0
  31. package/dist/monitoring/StallTriageNurse.js.map +1 -1
  32. package/dist/server/routes.d.ts.map +1 -1
  33. package/dist/server/routes.js +312 -0
  34. package/dist/server/routes.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/data/builtin-manifest.json +58 -50
  37. package/src/templates/hooks/compaction-recovery.sh +50 -0
  38. package/src/templates/hooks/session-start.sh +50 -0
  39. package/upgrades/0.28.87.md +153 -0
  40. package/upgrades/0.28.88.md +91 -0
  41. package/upgrades/side-effects/0.28.86.md +13 -0
  42. package/upgrades/side-effects/0.28.87.md +13 -0
  43. package/upgrades/side-effects/project-scope-phase1a-pr2.md +377 -0
  44. package/upgrades/side-effects/project-scope-phase1a-pr3.md +477 -0
  45. package/upgrades/side-effects/verify-injection-stuck-input.md +107 -0
@@ -0,0 +1,58 @@
1
+ import type { InitiativeTracker, Initiative } from './InitiativeTracker.js';
2
+ /** Where the digest lands. Hooks read this exact path. */
3
+ export declare const DIGEST_CACHE_FILENAME = "projects-digest.cache";
4
+ /** Max projects rendered into `digestLines`. Top-N by `lastTouchedAt`. */
5
+ export declare const MAX_PROJECTS_IN_DIGEST = 5;
6
+ /** Max characters per sanitized string (titles, round names). */
7
+ export declare const MAX_STRING_LENGTH = 80;
8
+ /** JSON shape that the hooks deserialize. */
9
+ export interface ProjectDigestCacheFile {
10
+ /** ISO timestamp when this snapshot was written. */
11
+ generatedAt: string;
12
+ /** One sanitized one-liner per active project, top-N by `lastTouchedAt`. */
13
+ digestLines: string[];
14
+ /** Total active projects in the tracker (independent of truncation). */
15
+ totalActiveProjects: number;
16
+ /** True iff `totalActiveProjects > MAX_PROJECTS_IN_DIGEST`. */
17
+ truncated: boolean;
18
+ }
19
+ /**
20
+ * Strip control chars (incl. \n, \r, \t), then collapse runs of internal
21
+ * whitespace to single spaces and cap at `cap` chars.
22
+ *
23
+ * Exported so the hooks (well, their JS-side helpers) and tests can apply
24
+ * the same rule on read. The bash hooks themselves use a `tr`-based
25
+ * equivalent — the literal regex below is the canonical implementation.
26
+ */
27
+ export declare function sanitizeDigestString(input: unknown, cap?: number): string;
28
+ /**
29
+ * Render one digest line for a single project. Pure function — caller
30
+ * provides the project; sanitization happens inside.
31
+ */
32
+ export declare function formatProjectDigestLine(project: Initiative): string;
33
+ /**
34
+ * ProjectDigestCache — single-responsibility writer. Construct once at
35
+ * server boot; pass `writeDigestCache.bind(this)` as the invalidator on
36
+ * `InitiativeTracker.setDigestCacheInvalidator(fn)`.
37
+ */
38
+ export declare class ProjectDigestCache {
39
+ private readonly filePath;
40
+ private readonly tracker;
41
+ /** Bound to `process.pid` so concurrent writers (test sandbox + main
42
+ * process) don't trample one another's temp files. */
43
+ private readonly tmpSuffix;
44
+ constructor(stateDir: string, tracker: InitiativeTracker);
45
+ /** Absolute path to the cache file. Exposed for diagnostics. */
46
+ getCachePath(): string;
47
+ /**
48
+ * Snapshot all active projects, render the top-N digest lines, and write
49
+ * the result atomically. Synchronous on purpose — runs in the
50
+ * invalidator hot path (every project mutation calls it once).
51
+ *
52
+ * Best-effort: any thrown error is swallowed after logging, so a hiccup
53
+ * writing the cache never blocks a successful mutation.
54
+ */
55
+ writeDigestCache(): void;
56
+ private atomicWrite;
57
+ }
58
+ //# sourceMappingURL=ProjectDigestCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectDigestCache.d.ts","sourceRoot":"","sources":["../../src/core/ProjectDigestCache.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE5E,0DAA0D;AAC1D,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,6CAA6C;AAC7C,MAAM,WAAW,sBAAsB;IACrC,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wEAAwE;IACxE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAoB,GAAG,MAAM,CAUpF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAsBnE;AAaD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C;2DACuD;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB;IAMxD,gEAAgE;IAChE,YAAY,IAAI,MAAM;IAItB;;;;;;;OAOG;IACH,gBAAgB,IAAI,IAAI;IA4BxB,OAAO,CAAC,WAAW;CAOpB"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * ProjectDigestCache — writes a sanitized JSON snapshot of active projects
3
+ * to `.instar/projects-digest.cache` for cheap, no-HTTP consumption by
4
+ * session-start and compaction-recovery hooks.
5
+ *
6
+ * Spec source: PROJECT-SCOPE-SPEC.md § Phase 1.9 (session-start + compaction
7
+ * recovery hooks). The hooks have a ≤50ms budget — pure file read, no HTTP.
8
+ *
9
+ * Invariants:
10
+ * - Top 5 active projects by `lastTouchedAt` (desc) are included; the
11
+ * `truncated` flag + `totalActiveProjects` count make over-limit visible.
12
+ * - Every string field that lands in the cache is sanitized at write time:
13
+ * control chars (incl. newline + CR) stripped, and the result capped at
14
+ * 80 characters. The hooks ALSO sanitize on read (defense in depth),
15
+ * so direct cache-file poisoning can't smuggle an unprintable string
16
+ * into orientation output.
17
+ * - Atomic on-disk write (temp file + rename) — readers never observe a
18
+ * partial file. Matches the pattern `InitiativeTracker.saveToDisk()`
19
+ * uses for its own persistence.
20
+ *
21
+ * This module is the **read side** of the invalidator hook PR 1 added on
22
+ * InitiativeTracker (`setDigestCacheInvalidator`). The server wires
23
+ * `writeDigestCache()` as the invalidator at boot, so every successful
24
+ * project mutation re-renders the file. Mutations on `kind:'task'`
25
+ * initiatives also trigger a rewrite — the function filters internally to
26
+ * `kind:'project' && status:'active'`, so the side effect is a no-op when
27
+ * no project state changed.
28
+ */
29
+ import fs from 'node:fs';
30
+ import path from 'node:path';
31
+ /** Where the digest lands. Hooks read this exact path. */
32
+ export const DIGEST_CACHE_FILENAME = 'projects-digest.cache';
33
+ /** Max projects rendered into `digestLines`. Top-N by `lastTouchedAt`. */
34
+ export const MAX_PROJECTS_IN_DIGEST = 5;
35
+ /** Max characters per sanitized string (titles, round names). */
36
+ export const MAX_STRING_LENGTH = 80;
37
+ /**
38
+ * Strip control chars (incl. \n, \r, \t), then collapse runs of internal
39
+ * whitespace to single spaces and cap at `cap` chars.
40
+ *
41
+ * Exported so the hooks (well, their JS-side helpers) and tests can apply
42
+ * the same rule on read. The bash hooks themselves use a `tr`-based
43
+ * equivalent — the literal regex below is the canonical implementation.
44
+ */
45
+ export function sanitizeDigestString(input, cap = MAX_STRING_LENGTH) {
46
+ const raw = typeof input === 'string' ? input : input == null ? '' : String(input);
47
+ // Strip ASCII control chars (0x00-0x1F) and DEL (0x7F).
48
+ // Replaces with a single space so words don't collide.
49
+ // eslint-disable-next-line no-control-regex
50
+ const stripped = raw.replace(/[\x00-\x1F\x7F]/g, ' ');
51
+ // Collapse internal whitespace runs, trim ends.
52
+ const collapsed = stripped.replace(/\s+/g, ' ').trim();
53
+ if (collapsed.length <= cap)
54
+ return collapsed;
55
+ return collapsed.slice(0, cap);
56
+ }
57
+ /**
58
+ * Render one digest line for a single project. Pure function — caller
59
+ * provides the project; sanitization happens inside.
60
+ */
61
+ export function formatProjectDigestLine(project) {
62
+ const id = sanitizeDigestString(project.id, MAX_STRING_LENGTH);
63
+ const rounds = Array.isArray(project.rounds) ? project.rounds : [];
64
+ const total = rounds.length;
65
+ const done = rounds.filter((r) => r && (r.status === 'complete' || r.status === 'complete-with-skips')).length;
66
+ // Next round: first non-complete round in order. Falls through to "(none)"
67
+ // when every round is done.
68
+ const next = rounds.find((r) => r &&
69
+ r.status !== 'complete' &&
70
+ r.status !== 'complete-with-skips' &&
71
+ r.status !== 'failed');
72
+ const nextLabel = next
73
+ ? sanitizeDigestString(next.name || '(unnamed round)', MAX_STRING_LENGTH)
74
+ : '(none — all rounds complete)';
75
+ return `Project [${id}]: ${done} of ${total} done. Next round: ${nextLabel}.`;
76
+ }
77
+ /**
78
+ * Sort projects by `lastTouchedAt` descending. Ties broken by `id` ascending
79
+ * so the output is stable.
80
+ */
81
+ function sortByLastTouched(a, b) {
82
+ const at = a.lastTouchedAt ?? '';
83
+ const bt = b.lastTouchedAt ?? '';
84
+ if (at === bt)
85
+ return a.id.localeCompare(b.id);
86
+ return bt.localeCompare(at);
87
+ }
88
+ /**
89
+ * ProjectDigestCache — single-responsibility writer. Construct once at
90
+ * server boot; pass `writeDigestCache.bind(this)` as the invalidator on
91
+ * `InitiativeTracker.setDigestCacheInvalidator(fn)`.
92
+ */
93
+ export class ProjectDigestCache {
94
+ filePath;
95
+ tracker;
96
+ /** Bound to `process.pid` so concurrent writers (test sandbox + main
97
+ * process) don't trample one another's temp files. */
98
+ tmpSuffix;
99
+ constructor(stateDir, tracker) {
100
+ this.filePath = path.join(stateDir, DIGEST_CACHE_FILENAME);
101
+ this.tracker = tracker;
102
+ this.tmpSuffix = `.${process.pid}.tmp`;
103
+ }
104
+ /** Absolute path to the cache file. Exposed for diagnostics. */
105
+ getCachePath() {
106
+ return this.filePath;
107
+ }
108
+ /**
109
+ * Snapshot all active projects, render the top-N digest lines, and write
110
+ * the result atomically. Synchronous on purpose — runs in the
111
+ * invalidator hot path (every project mutation calls it once).
112
+ *
113
+ * Best-effort: any thrown error is swallowed after logging, so a hiccup
114
+ * writing the cache never blocks a successful mutation.
115
+ */
116
+ writeDigestCache() {
117
+ try {
118
+ const all = this.tracker.list({ kind: 'project', status: 'active' });
119
+ // `list()` already sorts by `lastTouchedAt` desc; re-sort defensively
120
+ // in case the contract changes underneath us.
121
+ const sorted = [...all].sort(sortByLastTouched);
122
+ const total = sorted.length;
123
+ const truncated = total > MAX_PROJECTS_IN_DIGEST;
124
+ const top = sorted.slice(0, MAX_PROJECTS_IN_DIGEST);
125
+ const digestLines = top.map((p) => formatProjectDigestLine(p));
126
+ const payload = {
127
+ generatedAt: new Date().toISOString(),
128
+ digestLines,
129
+ totalActiveProjects: total,
130
+ truncated,
131
+ };
132
+ this.atomicWrite(JSON.stringify(payload, null, 2));
133
+ }
134
+ catch (err) {
135
+ console.warn(`[ProjectDigestCache] writeDigestCache failed (non-fatal): ${err instanceof Error ? err.message : err}`);
136
+ }
137
+ }
138
+ atomicWrite(contents) {
139
+ const dir = path.dirname(this.filePath);
140
+ fs.mkdirSync(dir, { recursive: true });
141
+ const tmp = `${this.filePath}${this.tmpSuffix}`;
142
+ fs.writeFileSync(tmp, contents);
143
+ fs.renameSync(tmp, this.filePath);
144
+ }
145
+ }
146
+ //# sourceMappingURL=ProjectDigestCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectDigestCache.js","sourceRoot":"","sources":["../../src/core/ProjectDigestCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Tiny YAML frontmatter parser used by project-scope.
3
+ *
4
+ * Scope is deliberately narrow:
5
+ * - top-level scalar keys (`key: value`)
6
+ * - top-level boolean (`true` / `false`) and numeric scalars
7
+ * - top-level string scalars (with optional double-quoting)
8
+ * - top-level string arrays via `- item` block sequences OR `[a, b, c]`
9
+ * flow sequences
10
+ * - no nested maps, no anchors, no multi-document streams
11
+ *
12
+ * Why not js-yaml: that dep isn't in the current package.json and the spec
13
+ * (Phase 1.6) only asks for safe-load semantics over a constrained schema.
14
+ * Adding a new runtime dep for ~40 lines of work isn't worth the supply-chain
15
+ * surface. If the schema grows beyond block scalars we add js-yaml then.
16
+ *
17
+ * Hardening:
18
+ * - Tag-like values starting with `!` are rejected (no `!!python/object`).
19
+ * - Anchor / alias tokens (`&` / `*` at the start of a value) are rejected.
20
+ * - Aborts after 1000 lines to bound CPU on adversarial input.
21
+ *
22
+ * All callers wrap the output in their own schema validator — this returns
23
+ * `unknown` shaped as `Record<string, unknown>` and never throws on missing
24
+ * keys.
25
+ */
26
+ export interface FrontmatterResult {
27
+ ok: true;
28
+ data: Record<string, unknown>;
29
+ }
30
+ export interface FrontmatterError {
31
+ ok: false;
32
+ error: string;
33
+ }
34
+ /**
35
+ * Extract the YAML frontmatter from a markdown string. Returns the parsed
36
+ * frontmatter and the body (everything after the second `---`). If no
37
+ * frontmatter is present, `data` is `{}` and body is the entire input.
38
+ */
39
+ export declare function extractFrontmatter(source: string): {
40
+ frontmatter: Record<string, unknown> | null;
41
+ body: string;
42
+ error?: string;
43
+ };
44
+ export declare function parseSafeYaml(input: string): FrontmatterResult | FrontmatterError;
45
+ //# sourceMappingURL=SafeYaml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SafeYaml.d.ts","sourceRoot":"","sources":["../../src/core/SafeYaml.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GACb;IAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA8B/E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,gBAAgB,CA2EjF"}
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Tiny YAML frontmatter parser used by project-scope.
3
+ *
4
+ * Scope is deliberately narrow:
5
+ * - top-level scalar keys (`key: value`)
6
+ * - top-level boolean (`true` / `false`) and numeric scalars
7
+ * - top-level string scalars (with optional double-quoting)
8
+ * - top-level string arrays via `- item` block sequences OR `[a, b, c]`
9
+ * flow sequences
10
+ * - no nested maps, no anchors, no multi-document streams
11
+ *
12
+ * Why not js-yaml: that dep isn't in the current package.json and the spec
13
+ * (Phase 1.6) only asks for safe-load semantics over a constrained schema.
14
+ * Adding a new runtime dep for ~40 lines of work isn't worth the supply-chain
15
+ * surface. If the schema grows beyond block scalars we add js-yaml then.
16
+ *
17
+ * Hardening:
18
+ * - Tag-like values starting with `!` are rejected (no `!!python/object`).
19
+ * - Anchor / alias tokens (`&` / `*` at the start of a value) are rejected.
20
+ * - Aborts after 1000 lines to bound CPU on adversarial input.
21
+ *
22
+ * All callers wrap the output in their own schema validator — this returns
23
+ * `unknown` shaped as `Record<string, unknown>` and never throws on missing
24
+ * keys.
25
+ */
26
+ const MAX_LINES = 1000;
27
+ /**
28
+ * Extract the YAML frontmatter from a markdown string. Returns the parsed
29
+ * frontmatter and the body (everything after the second `---`). If no
30
+ * frontmatter is present, `data` is `{}` and body is the entire input.
31
+ */
32
+ export function extractFrontmatter(source) {
33
+ const trimmedHead = source.startsWith('') ? source.slice(1) : source;
34
+ if (!trimmedHead.startsWith('---')) {
35
+ return { frontmatter: null, body: source };
36
+ }
37
+ const lines = trimmedHead.split(/\r?\n/);
38
+ if (lines.length > MAX_LINES) {
39
+ return { frontmatter: null, body: source, error: 'document exceeds 1000-line cap' };
40
+ }
41
+ // First line should be the opening `---` (possibly with trailing spaces).
42
+ if (lines[0].trim() !== '---') {
43
+ return { frontmatter: null, body: source };
44
+ }
45
+ let endIdx = -1;
46
+ for (let i = 1; i < lines.length; i++) {
47
+ if (lines[i].trim() === '---' || lines[i].trim() === '...') {
48
+ endIdx = i;
49
+ break;
50
+ }
51
+ }
52
+ if (endIdx === -1) {
53
+ return { frontmatter: null, body: source, error: 'unterminated frontmatter block' };
54
+ }
55
+ const yamlBody = lines.slice(1, endIdx).join('\n');
56
+ const body = lines.slice(endIdx + 1).join('\n');
57
+ const parsed = parseSafeYaml(yamlBody);
58
+ if (!parsed.ok) {
59
+ return { frontmatter: null, body, error: parsed.error };
60
+ }
61
+ return { frontmatter: parsed.data, body };
62
+ }
63
+ export function parseSafeYaml(input) {
64
+ const lines = input.split(/\r?\n/);
65
+ if (lines.length > MAX_LINES) {
66
+ return { ok: false, error: 'yaml exceeds 1000-line cap' };
67
+ }
68
+ const data = {};
69
+ let i = 0;
70
+ while (i < lines.length) {
71
+ const rawLine = lines[i];
72
+ const line = rawLine.replace(/\s+$/, '');
73
+ if (!line.trim() || line.trim().startsWith('#')) {
74
+ i++;
75
+ continue;
76
+ }
77
+ // Top-level: must start at column 0 with `key:` (no leading whitespace).
78
+ if (/^\s/.test(line)) {
79
+ return { ok: false, error: `unexpected indentation at line ${i + 1}` };
80
+ }
81
+ const colonIdx = line.indexOf(':');
82
+ if (colonIdx === -1) {
83
+ return { ok: false, error: `expected "key:" at line ${i + 1}` };
84
+ }
85
+ const key = line.slice(0, colonIdx).trim();
86
+ if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(key)) {
87
+ return { ok: false, error: `invalid key "${key}" at line ${i + 1}` };
88
+ }
89
+ const rest = line.slice(colonIdx + 1).trim();
90
+ if (rest === '' || rest === '|' || rest === '>') {
91
+ // Block sequence or block scalar follows on indented lines.
92
+ const childLines = [];
93
+ let j = i + 1;
94
+ while (j < lines.length) {
95
+ const next = lines[j];
96
+ if (next.trim() === '' || next.startsWith(' ') || next.startsWith('\t') || next.startsWith('-')) {
97
+ childLines.push(next);
98
+ j++;
99
+ }
100
+ else {
101
+ break;
102
+ }
103
+ }
104
+ // Detect block sequence by leading `-` (with optional indent).
105
+ const seqLines = childLines.filter((l) => /^\s*-\s+/.test(l));
106
+ if (seqLines.length > 0 && seqLines.length === childLines.filter((l) => l.trim()).length) {
107
+ const arr = [];
108
+ for (const sl of seqLines) {
109
+ const item = sl.replace(/^\s*-\s+/, '').trim();
110
+ const v = parseScalar(item);
111
+ if (typeof v !== 'string' && typeof v !== 'number' && typeof v !== 'boolean') {
112
+ return { ok: false, error: `unsupported sequence item at "${key}"` };
113
+ }
114
+ arr.push(String(v));
115
+ }
116
+ data[key] = arr;
117
+ }
118
+ else if (rest === '|' || rest === '>') {
119
+ // Block scalar: dedent shortest common leading whitespace.
120
+ const nonEmpty = childLines.filter((l) => l.trim().length > 0);
121
+ const indents = nonEmpty.map((l) => (l.match(/^\s*/)?.[0].length ?? 0));
122
+ const minIndent = indents.length > 0 ? Math.min(...indents) : 0;
123
+ const joined = nonEmpty.map((l) => l.slice(minIndent)).join(rest === '|' ? '\n' : ' ');
124
+ data[key] = joined;
125
+ }
126
+ else {
127
+ // No children → empty string / undefined behaviour: treat as empty string.
128
+ data[key] = '';
129
+ }
130
+ i = j;
131
+ continue;
132
+ }
133
+ const valueResult = parseInlineValue(rest);
134
+ if (!valueResult.ok) {
135
+ return { ok: false, error: `${valueResult.error} at line ${i + 1}` };
136
+ }
137
+ data[key] = valueResult.value;
138
+ i++;
139
+ }
140
+ return { ok: true, data };
141
+ }
142
+ function parseInlineValue(raw) {
143
+ const trimmed = raw.trim();
144
+ if (trimmed.startsWith('!')) {
145
+ return { ok: false, error: 'YAML tags are not permitted' };
146
+ }
147
+ if (trimmed.startsWith('&') || trimmed.startsWith('*')) {
148
+ return { ok: false, error: 'YAML anchors and aliases are not permitted' };
149
+ }
150
+ // Flow sequence [a, b, c]
151
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
152
+ const inner = trimmed.slice(1, -1).trim();
153
+ if (inner === '')
154
+ return { ok: true, value: [] };
155
+ const parts = splitFlowList(inner);
156
+ const arr = [];
157
+ for (const p of parts) {
158
+ const v = parseScalar(p.trim());
159
+ arr.push(v);
160
+ }
161
+ return { ok: true, value: arr };
162
+ }
163
+ // Flow mapping {k: v} is not supported in our schema; reject to fail loud.
164
+ if (trimmed.startsWith('{')) {
165
+ return { ok: false, error: 'inline maps are not permitted' };
166
+ }
167
+ return { ok: true, value: parseScalar(trimmed) };
168
+ }
169
+ function splitFlowList(s) {
170
+ const out = [];
171
+ let depth = 0;
172
+ let inStr = null;
173
+ let cur = '';
174
+ for (const ch of s) {
175
+ if (inStr) {
176
+ cur += ch;
177
+ if (ch === inStr)
178
+ inStr = null;
179
+ continue;
180
+ }
181
+ if (ch === '"' || ch === "'") {
182
+ inStr = ch;
183
+ cur += ch;
184
+ continue;
185
+ }
186
+ if (ch === '[' || ch === '{')
187
+ depth++;
188
+ else if (ch === ']' || ch === '}')
189
+ depth--;
190
+ if (ch === ',' && depth === 0) {
191
+ out.push(cur);
192
+ cur = '';
193
+ }
194
+ else {
195
+ cur += ch;
196
+ }
197
+ }
198
+ if (cur.trim().length > 0)
199
+ out.push(cur);
200
+ return out;
201
+ }
202
+ function parseScalar(raw) {
203
+ const s = raw.trim();
204
+ if (s === '')
205
+ return '';
206
+ if (s === 'null' || s === '~')
207
+ return null;
208
+ if (s === 'true' || s === 'True' || s === 'TRUE')
209
+ return true;
210
+ if (s === 'false' || s === 'False' || s === 'FALSE')
211
+ return false;
212
+ // Quoted strings (return raw, no escape processing — we don't need it for
213
+ // the project-scope schema).
214
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
215
+ return s.slice(1, -1);
216
+ }
217
+ // Number?
218
+ if (/^-?\d+$/.test(s)) {
219
+ const n = parseInt(s, 10);
220
+ if (Number.isSafeInteger(n))
221
+ return n;
222
+ }
223
+ if (/^-?\d+\.\d+$/.test(s)) {
224
+ const f = parseFloat(s);
225
+ if (Number.isFinite(f))
226
+ return f;
227
+ }
228
+ return s;
229
+ }
230
+ //# sourceMappingURL=SafeYaml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SafeYaml.js","sourceRoot":"","sources":["../../src/core/SafeYaml.ts"],"names":[],"mappings":"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"}
@@ -386,6 +386,18 @@ export declare class SessionManager extends EventEmitter {
386
386
  * Used by injectMessage after provenance checks pass.
387
387
  */
388
388
  private rawInject;
389
+ /**
390
+ * Verify an injection actually submitted by checking for a marker snippet
391
+ * still present at the ❯ prompt. On Claude Code v2.1.105+ fresh spawns, the
392
+ * Enter after bracketed-paste-end is occasionally eaten by a race with the
393
+ * paste-end sequence and the text sits unsubmitted forever. This guard
394
+ * sends one extra Enter if we detect the stuck state; single-shot, safe
395
+ * when the text did submit normally (no-op).
396
+ *
397
+ * Runs asynchronously — fires a background check after markerCheckMs and
398
+ * does not block the caller. Called from rawInject after Enter is sent.
399
+ */
400
+ private verifyInjection;
389
401
  /**
390
402
  * Wait for Claude to be ready in a tmux session by polling output.
391
403
  * Looks for Claude Code's prompt character (❯) which appears when ready for input.
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../src/core/SessionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../src/core/SessionManager.ts"],"names":[],"mappings":"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"}
@@ -1713,6 +1713,12 @@ rm() { "${shimRunner}" rm "$@"; }
1713
1713
  encoding: 'utf-8', timeout: 5000,
1714
1714
  });
1715
1715
  }
1716
+ // Verify Enter actually submitted — on fresh Claude Code TUIs (v2.1.105+)
1717
+ // the Enter after bracketed-paste-end is occasionally eaten, leaving the
1718
+ // text sitting in the input box unsubmitted. verifyInjection captures the
1719
+ // pane after a short delay and sends one extra Enter if the marker text
1720
+ // is still visible at the ❯ prompt.
1721
+ this.verifyInjection(tmuxSession, text);
1716
1722
  return true;
1717
1723
  }
1718
1724
  catch (err) {
@@ -1743,6 +1749,60 @@ rm() { "${shimRunner}" rm "$@"; }
1743
1749
  }
1744
1750
  return false;
1745
1751
  }
1752
+ /**
1753
+ * Verify an injection actually submitted by checking for a marker snippet
1754
+ * still present at the ❯ prompt. On Claude Code v2.1.105+ fresh spawns, the
1755
+ * Enter after bracketed-paste-end is occasionally eaten by a race with the
1756
+ * paste-end sequence and the text sits unsubmitted forever. This guard
1757
+ * sends one extra Enter if we detect the stuck state; single-shot, safe
1758
+ * when the text did submit normally (no-op).
1759
+ *
1760
+ * Runs asynchronously — fires a background check after markerCheckMs and
1761
+ * does not block the caller. Called from rawInject after Enter is sent.
1762
+ */
1763
+ verifyInjection(tmuxSession, injectedText) {
1764
+ const markerCheckMs = 1500;
1765
+ // Extract a distinguishing first-40-chars marker from the injected text.
1766
+ // Strip leading whitespace/newlines so we match what's visible at the prompt.
1767
+ const marker = injectedText.replace(/^\s+/, '').slice(0, 40).trim();
1768
+ if (!marker || marker.length < 8)
1769
+ return; // too short to be a reliable marker
1770
+ setTimeout(() => {
1771
+ try {
1772
+ if (!this.tmuxSessionExists(tmuxSession))
1773
+ return;
1774
+ const pane = this.captureOutput(tmuxSession, 20) || '';
1775
+ // If the marker is still at a ❯ prompt line, Enter was eaten.
1776
+ // Check the pane has BOTH ❯ and the marker on the same line (or within 2 lines).
1777
+ const lines = pane.split('\n');
1778
+ let stuck = false;
1779
+ for (let i = 0; i < lines.length; i++) {
1780
+ const line = lines[i];
1781
+ if (line.includes('❯') && (line.includes(marker) || (lines[i + 1] && lines[i + 1].includes(marker.slice(0, 30))))) {
1782
+ stuck = true;
1783
+ break;
1784
+ }
1785
+ }
1786
+ if (stuck) {
1787
+ console.warn(`[SessionManager] Injection stuck in "${tmuxSession}" — marker "${marker.slice(0, 30)}…" still at prompt. Resending Enter.`);
1788
+ execFileSync(this.config.tmuxPath, ['send-keys', '-t', `=${tmuxSession}:`, 'Enter'], {
1789
+ encoding: 'utf-8', timeout: 5000,
1790
+ });
1791
+ DegradationReporter.getInstance().report({
1792
+ feature: 'SessionManager.verifyInjection',
1793
+ primary: 'Bracketed paste + Enter submits injected message',
1794
+ fallback: 'Auto-resent Enter after detecting stuck input',
1795
+ reason: 'Enter eaten by paste-end race on fresh Claude Code TUI',
1796
+ impact: 'Recovered without user intervention',
1797
+ });
1798
+ }
1799
+ }
1800
+ catch (err) {
1801
+ // Best-effort — never throw from a background verification
1802
+ console.error(`[SessionManager] verifyInjection error for "${tmuxSession}": ${err instanceof Error ? err.message : err}`);
1803
+ }
1804
+ }, markerCheckMs);
1805
+ }
1746
1806
  /**
1747
1807
  * Wait for Claude to be ready in a tmux session by polling output.
1748
1808
  * Looks for Claude Code's prompt character (❯) which appears when ready for input.