instar 0.28.85 → 0.28.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/InitiativeTracker.d.ts +177 -1
- package/dist/core/InitiativeTracker.d.ts.map +1 -1
- package/dist/core/InitiativeTracker.js +341 -13
- package/dist/core/InitiativeTracker.js.map +1 -1
- package/dist/core/PlanDocParser.d.ts +62 -0
- package/dist/core/PlanDocParser.d.ts.map +1 -0
- package/dist/core/PlanDocParser.js +328 -0
- package/dist/core/PlanDocParser.js.map +1 -0
- package/dist/core/SafeYaml.d.ts +45 -0
- package/dist/core/SafeYaml.d.ts.map +1 -0
- package/dist/core/SafeYaml.js +230 -0
- package/dist/core/SafeYaml.js.map +1 -0
- package/dist/core/SessionManager.d.ts +12 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +60 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/StageTransitionValidator.d.ts +97 -0
- package/dist/core/StageTransitionValidator.d.ts.map +1 -0
- package/dist/core/StageTransitionValidator.js +338 -0
- package/dist/core/StageTransitionValidator.js.map +1 -0
- package/dist/monitoring/StallTriageNurse.d.ts +11 -0
- package/dist/monitoring/StallTriageNurse.d.ts.map +1 -1
- package/dist/monitoring/StallTriageNurse.js +66 -0
- package/dist/monitoring/StallTriageNurse.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +312 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/0.28.86.md +86 -0
- package/upgrades/0.28.87.md +153 -0
- package/upgrades/side-effects/0.28.86.md +13 -0
- package/upgrades/side-effects/project-scope-phase1a-pr1.md +232 -0
- package/upgrades/side-effects/project-scope-phase1a-pr2.md +377 -0
- package/upgrades/side-effects/verify-injection-stuck-input.md +107 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PlanDocParser — turn a markdown plan doc into a project seed plus child
|
|
3
|
+
* seeds for the InitiativeTracker.
|
|
4
|
+
*
|
|
5
|
+
* Spec: docs/specs/PROJECT-SCOPE-SPEC.md Phase 1.6.
|
|
6
|
+
*
|
|
7
|
+
* Frontmatter schema (validated; unknown keys rejected):
|
|
8
|
+
* kind: project (required)
|
|
9
|
+
* id: <slug> (required; ^[a-z0-9][a-z0-9-]{0,63}$)
|
|
10
|
+
* title: <string> (required)
|
|
11
|
+
* status: active (required)
|
|
12
|
+
* owner: <string> (required)
|
|
13
|
+
* target_repo_path: <absolute path> (required; must exist as a directory)
|
|
14
|
+
* source_docs: [<rel path>, ...] (required; each jailed under target_repo_path)
|
|
15
|
+
* goal: <string> (required)
|
|
16
|
+
* auto_advance: true|false (optional, default true)
|
|
17
|
+
* telegram_topic_id: <string> (optional)
|
|
18
|
+
* defers: [<slug>, ...] (optional)
|
|
19
|
+
*
|
|
20
|
+
* Body schema: tables under `### Tier N …` headers with columns
|
|
21
|
+
* | # | Item | Source | Effort |
|
|
22
|
+
* |---|------|--------|--------|
|
|
23
|
+
* | 1 | foo | bar | s |
|
|
24
|
+
*
|
|
25
|
+
* Each row becomes a child seed at `pipelineStage: 'outline'` carrying
|
|
26
|
+
* `parentProjectId`, `sourceTag`, `effortTag`, and `roundName` (the tier
|
|
27
|
+
* header, e.g. "Tier 1 — first three").
|
|
28
|
+
*
|
|
29
|
+
* `parsePlanDoc` returns `errors[]` rather than throwing. The caller
|
|
30
|
+
* decides whether to persist on partial errors. The HTTP layer maps any
|
|
31
|
+
* non-empty `errors[]` from `POST /projects` to 400.
|
|
32
|
+
*/
|
|
33
|
+
import fs from 'node:fs';
|
|
34
|
+
import path from 'node:path';
|
|
35
|
+
import { extractFrontmatter } from './SafeYaml.js';
|
|
36
|
+
import { jailPath } from './StageTransitionValidator.js';
|
|
37
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
38
|
+
const ALLOWED_FRONTMATTER_KEYS = new Set([
|
|
39
|
+
'kind',
|
|
40
|
+
'id',
|
|
41
|
+
'title',
|
|
42
|
+
'status',
|
|
43
|
+
'owner',
|
|
44
|
+
'target_repo_path',
|
|
45
|
+
'source_docs',
|
|
46
|
+
'goal',
|
|
47
|
+
'auto_advance',
|
|
48
|
+
'telegram_topic_id',
|
|
49
|
+
'defers',
|
|
50
|
+
// Allow the unarchive flag from spec Phase 1.6 (slug-reuse path).
|
|
51
|
+
'unarchive',
|
|
52
|
+
]);
|
|
53
|
+
export async function parsePlanDoc(absPath) {
|
|
54
|
+
const errors = [];
|
|
55
|
+
if (!path.isAbsolute(absPath)) {
|
|
56
|
+
return { project: null, children: [], errors: [`planDocPath must be absolute, got "${absPath}"`] };
|
|
57
|
+
}
|
|
58
|
+
let raw;
|
|
59
|
+
try {
|
|
60
|
+
raw = fs.readFileSync(absPath, 'utf-8');
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
return {
|
|
64
|
+
project: null,
|
|
65
|
+
children: [],
|
|
66
|
+
errors: [`could not read plan doc: ${err instanceof Error ? err.message : String(err)}`],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (raw.length > 256 * 1024) {
|
|
70
|
+
return { project: null, children: [], errors: ['plan doc exceeds 256 KB cap'] };
|
|
71
|
+
}
|
|
72
|
+
const fm = extractFrontmatter(raw);
|
|
73
|
+
if (fm.error)
|
|
74
|
+
errors.push(`frontmatter error: ${fm.error}`);
|
|
75
|
+
if (!fm.frontmatter) {
|
|
76
|
+
errors.push('plan doc is missing a YAML frontmatter block');
|
|
77
|
+
return { project: null, children: [], errors };
|
|
78
|
+
}
|
|
79
|
+
const project = validateProjectFrontmatter(fm.frontmatter, errors);
|
|
80
|
+
if (!project) {
|
|
81
|
+
return { project: null, children: [], errors };
|
|
82
|
+
}
|
|
83
|
+
// Walk the body for tier sections.
|
|
84
|
+
const children = parseTierTables(fm.body, project.id, errors);
|
|
85
|
+
// Append children to round names (sourced from tier headers).
|
|
86
|
+
return { project, children, errors };
|
|
87
|
+
}
|
|
88
|
+
function validateProjectFrontmatter(data, errors) {
|
|
89
|
+
// Unknown keys?
|
|
90
|
+
for (const key of Object.keys(data)) {
|
|
91
|
+
if (!ALLOWED_FRONTMATTER_KEYS.has(key)) {
|
|
92
|
+
errors.push(`unknown frontmatter key "${key}"`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const must = (k, type) => {
|
|
96
|
+
const v = data[k];
|
|
97
|
+
if (v === undefined || v === null || v === '') {
|
|
98
|
+
errors.push(`"${k}" is required`);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (type === 'string' && typeof v !== 'string') {
|
|
102
|
+
errors.push(`"${k}" must be a string`);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (type === 'boolean' && typeof v !== 'boolean') {
|
|
106
|
+
errors.push(`"${k}" must be a boolean`);
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (type === 'array' && !Array.isArray(v)) {
|
|
110
|
+
errors.push(`"${k}" must be an array`);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
};
|
|
115
|
+
if (data.kind !== 'project') {
|
|
116
|
+
errors.push(`"kind" must be "project", got "${String(data.kind)}"`);
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (!must('id', 'string'))
|
|
120
|
+
return null;
|
|
121
|
+
if (!SLUG_RE.test(data.id)) {
|
|
122
|
+
errors.push(`"id" must match ${SLUG_RE.source}`);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
if (!must('title', 'string'))
|
|
126
|
+
return null;
|
|
127
|
+
if (data.title.length > 200) {
|
|
128
|
+
errors.push('"title" must be ≤ 200 chars');
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
if (data.status !== 'active') {
|
|
132
|
+
errors.push('"status" must be "active"');
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
if (!must('owner', 'string'))
|
|
136
|
+
return null;
|
|
137
|
+
if (!must('target_repo_path', 'string'))
|
|
138
|
+
return null;
|
|
139
|
+
const targetRepoPath = data.target_repo_path;
|
|
140
|
+
if (!path.isAbsolute(targetRepoPath)) {
|
|
141
|
+
errors.push('"target_repo_path" must be an absolute path');
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
if (!fs.existsSync(targetRepoPath) || !fs.statSync(targetRepoPath).isDirectory()) {
|
|
145
|
+
errors.push(`"target_repo_path" does not exist or is not a directory: ${targetRepoPath}`);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (!must('source_docs', 'array'))
|
|
149
|
+
return null;
|
|
150
|
+
const sourceDocs = [];
|
|
151
|
+
for (const sd of data.source_docs) {
|
|
152
|
+
if (typeof sd !== 'string' || !sd.trim()) {
|
|
153
|
+
errors.push('"source_docs" entries must be non-empty strings');
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const jailed = jailPath(targetRepoPath, sd);
|
|
157
|
+
if (!jailed.ok) {
|
|
158
|
+
errors.push(`source_docs entry "${sd}" escapes target_repo_path: ${jailed.reason}`);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
sourceDocs.push(sd);
|
|
162
|
+
}
|
|
163
|
+
if (sourceDocs.length === 0) {
|
|
164
|
+
errors.push('"source_docs" must contain at least one valid path');
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (!must('goal', 'string'))
|
|
168
|
+
return null;
|
|
169
|
+
const goal = data.goal;
|
|
170
|
+
if (goal.length > 4000) {
|
|
171
|
+
errors.push('"goal" must be ≤ 4000 chars');
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
let autoAdvance;
|
|
175
|
+
if (data.auto_advance !== undefined) {
|
|
176
|
+
if (typeof data.auto_advance !== 'boolean') {
|
|
177
|
+
errors.push('"auto_advance" must be a boolean');
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
autoAdvance = data.auto_advance;
|
|
181
|
+
}
|
|
182
|
+
let telegramTopicId;
|
|
183
|
+
if (data.telegram_topic_id !== undefined) {
|
|
184
|
+
if (typeof data.telegram_topic_id !== 'string') {
|
|
185
|
+
errors.push('"telegram_topic_id" must be a string');
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
telegramTopicId = data.telegram_topic_id;
|
|
189
|
+
}
|
|
190
|
+
let defers;
|
|
191
|
+
if (data.defers !== undefined) {
|
|
192
|
+
if (!Array.isArray(data.defers)) {
|
|
193
|
+
errors.push('"defers" must be an array');
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const arr = [];
|
|
197
|
+
for (const d of data.defers) {
|
|
198
|
+
if (typeof d !== 'string' || !SLUG_RE.test(d)) {
|
|
199
|
+
errors.push(`"defers" entries must match slug regex; got "${String(d)}"`);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
arr.push(d);
|
|
203
|
+
}
|
|
204
|
+
defers = arr;
|
|
205
|
+
}
|
|
206
|
+
let unarchive;
|
|
207
|
+
if (data.unarchive !== undefined) {
|
|
208
|
+
if (typeof data.unarchive !== 'boolean') {
|
|
209
|
+
errors.push('"unarchive" must be a boolean');
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
unarchive = data.unarchive;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
id: data.id,
|
|
216
|
+
title: data.title,
|
|
217
|
+
status: 'active',
|
|
218
|
+
owner: data.owner,
|
|
219
|
+
targetRepoPath,
|
|
220
|
+
sourceDocs,
|
|
221
|
+
description: goal,
|
|
222
|
+
autoAdvance,
|
|
223
|
+
telegramTopicId,
|
|
224
|
+
defers,
|
|
225
|
+
unarchive,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const TIER_HEADER_RE = /^###\s+(Tier\s+\d+[^\n]*)$/;
|
|
229
|
+
const SLUG_FROM_TITLE_RE = /[^a-z0-9]+/g;
|
|
230
|
+
function parseTierTables(body, projectId, errors) {
|
|
231
|
+
const children = [];
|
|
232
|
+
const seenIds = new Set();
|
|
233
|
+
const lines = body.split(/\r?\n/);
|
|
234
|
+
let i = 0;
|
|
235
|
+
let currentTier = null;
|
|
236
|
+
while (i < lines.length) {
|
|
237
|
+
const line = lines[i];
|
|
238
|
+
const headerMatch = line.match(TIER_HEADER_RE);
|
|
239
|
+
if (headerMatch) {
|
|
240
|
+
currentTier = headerMatch[1].trim();
|
|
241
|
+
i++;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
// Detect a table: a header row starting with `|` followed by a separator row.
|
|
245
|
+
if (currentTier && line.trim().startsWith('|')) {
|
|
246
|
+
const headerCells = splitRow(line);
|
|
247
|
+
const sepIdx = i + 1;
|
|
248
|
+
if (sepIdx < lines.length && /^\s*\|?\s*[-: ]+/.test(lines[sepIdx])) {
|
|
249
|
+
// Validate column layout.
|
|
250
|
+
const colMap = mapColumns(headerCells);
|
|
251
|
+
if (!colMap) {
|
|
252
|
+
errors.push(`tier "${currentTier}" has a table but column headers don't match "# | Item | Source | Effort"`);
|
|
253
|
+
// Skip the malformed table.
|
|
254
|
+
i = sepIdx + 1;
|
|
255
|
+
while (i < lines.length && lines[i].trim().startsWith('|'))
|
|
256
|
+
i++;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
let r = sepIdx + 1;
|
|
260
|
+
while (r < lines.length && lines[r].trim().startsWith('|')) {
|
|
261
|
+
const row = splitRow(lines[r]);
|
|
262
|
+
const numCell = row[colMap.numIdx] ?? '';
|
|
263
|
+
const itemCell = row[colMap.itemIdx] ?? '';
|
|
264
|
+
const sourceCell = row[colMap.sourceIdx] ?? '';
|
|
265
|
+
const effortCell = row[colMap.effortIdx] ?? '';
|
|
266
|
+
if (!itemCell.trim()) {
|
|
267
|
+
r++;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const derivedId = deriveChildId(projectId, numCell, itemCell);
|
|
271
|
+
if (!SLUG_RE.test(derivedId)) {
|
|
272
|
+
errors.push(`derived child id "${derivedId}" is not a valid slug (from row "${itemCell}")`);
|
|
273
|
+
r++;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (seenIds.has(derivedId)) {
|
|
277
|
+
errors.push(`duplicate child id "${derivedId}" in plan doc`);
|
|
278
|
+
r++;
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
seenIds.add(derivedId);
|
|
282
|
+
children.push({
|
|
283
|
+
id: derivedId,
|
|
284
|
+
title: itemCell.trim().slice(0, 200),
|
|
285
|
+
sourceTag: sourceCell.trim(),
|
|
286
|
+
effortTag: effortCell.trim(),
|
|
287
|
+
pipelineStage: 'outline',
|
|
288
|
+
parentProjectId: projectId,
|
|
289
|
+
roundName: currentTier,
|
|
290
|
+
});
|
|
291
|
+
r++;
|
|
292
|
+
}
|
|
293
|
+
i = r;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
i++;
|
|
298
|
+
}
|
|
299
|
+
return children;
|
|
300
|
+
}
|
|
301
|
+
function splitRow(row) {
|
|
302
|
+
const trimmed = row.trim().replace(/^\|/, '').replace(/\|$/, '');
|
|
303
|
+
return trimmed.split('|').map((c) => c.trim());
|
|
304
|
+
}
|
|
305
|
+
function mapColumns(cells) {
|
|
306
|
+
const lower = cells.map((c) => c.toLowerCase());
|
|
307
|
+
const numIdx = lower.findIndex((c) => c === '#' || c === 'no' || c === 'num');
|
|
308
|
+
const itemIdx = lower.findIndex((c) => c === 'item' || c === 'name' || c === 'feature');
|
|
309
|
+
const sourceIdx = lower.findIndex((c) => c === 'source' || c === 'origin');
|
|
310
|
+
const effortIdx = lower.findIndex((c) => c === 'effort' || c === 'size');
|
|
311
|
+
if (numIdx === -1 || itemIdx === -1 || sourceIdx === -1 || effortIdx === -1)
|
|
312
|
+
return null;
|
|
313
|
+
return { numIdx, itemIdx, sourceIdx, effortIdx };
|
|
314
|
+
}
|
|
315
|
+
function deriveChildId(projectId, numCell, itemCell) {
|
|
316
|
+
const numTrim = numCell.trim();
|
|
317
|
+
// Prefer explicit slug-like numbering ("1", "2a"); otherwise use slugified title.
|
|
318
|
+
if (numTrim && /^[a-z0-9][a-z0-9-]{0,16}$/.test(numTrim.toLowerCase())) {
|
|
319
|
+
return `${projectId}-${numTrim.toLowerCase()}`;
|
|
320
|
+
}
|
|
321
|
+
const slugified = itemCell
|
|
322
|
+
.toLowerCase()
|
|
323
|
+
.replace(SLUG_FROM_TITLE_RE, '-')
|
|
324
|
+
.replace(/^-+|-+$/g, '')
|
|
325
|
+
.slice(0, 48);
|
|
326
|
+
return `${projectId}-${slugified}`;
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=PlanDocParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlanDocParser.js","sourceRoot":"","sources":["../../src/core/PlanDocParser.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.
|