@sema-agent/core 7.27.0 → 7.28.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 (35) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agents/builtin-agents.d.ts +6 -15
  3. package/dist/agents/cascade.d.ts +29 -33
  4. package/dist/agents/observer.d.ts +18 -20
  5. package/dist/agents/subagent.d.ts +58 -70
  6. package/dist/agents/tool-filter.d.ts +10 -12
  7. package/dist/agents/verify.d.ts +44 -49
  8. package/dist/brain/input-too-long.d.ts +10 -12
  9. package/dist/brain/media-degrade.d.ts +4 -5
  10. package/dist/brain/reasoning.d.ts +10 -12
  11. package/dist/brain/repetition.d.ts +7 -9
  12. package/dist/brain/request-params.d.ts +20 -25
  13. package/dist/brain/route-adjudicator.d.ts +4 -4
  14. package/dist/brain/route-conformance.d.ts +2 -2
  15. package/dist/brain/status-sink.d.ts +12 -14
  16. package/dist/brain/terminal-cause.d.ts +12 -15
  17. package/dist/brain/timeout.d.ts +17 -19
  18. package/dist/core/memory-engine/consolidation.d.ts +11 -15
  19. package/dist/core/memory-engine/engine.d.ts +45 -54
  20. package/dist/core/memory-engine/tools.d.ts +17 -23
  21. package/dist/core/permission-rule-model.js +5 -3
  22. package/dist/shell/lex.d.ts +279 -0
  23. package/dist/shell/lex.js +1253 -0
  24. package/dist/tools/fs/bash-program-position.d.ts +2 -4
  25. package/dist/tools/fs/bash-program-position.js +2 -1
  26. package/dist/tools/fs/bash-readonly-classifier.d.ts +2 -2
  27. package/dist/tools/fs/bash-readonly-classifier.js +1 -1
  28. package/dist/tools/fs/shell-read-check.js +1 -1
  29. package/dist/tools/fs/shell-read-establish.js +11 -1
  30. package/dist/tools/fs/shell-read-plan.d.ts +7 -2
  31. package/dist/tools/fs/shell-read-plan.js +48 -10
  32. package/package.json +2 -2
  33. package/wire-changes/core@7.28.0.json +594 -0
  34. package/dist/tools/fs/bash-lexer.d.ts +0 -152
  35. package/dist/tools/fs/bash-lexer.js +0 -627
@@ -1,627 +0,0 @@
1
- export const SUBSTITUTION_PLACEHOLDER = " subst";
2
- function quoteStep(open, ch) {
3
- if (open === undefined)
4
- return ch === '"' || ch === "'" ? ch : undefined;
5
- return open === ch ? undefined : open;
6
- }
7
- export function dollarOpensQuote(text, at) {
8
- const next = text[at + 1];
9
- if (next !== "'" && next !== '"')
10
- return false;
11
- let run = 0;
12
- for (let k = at - 1; k >= 0 && text[k] === "\\"; k--)
13
- run += 1;
14
- return run % 2 === 0;
15
- }
16
- export function ansiCQuoteClose(source, open) {
17
- for (let i = open + 1; i < source.length; i++) {
18
- if (source[i] === "\\") {
19
- i += 1;
20
- continue;
21
- }
22
- if (source[i] === "'")
23
- return i;
24
- }
25
- return undefined;
26
- }
27
- export function quoteMask(s) {
28
- const openedBy = new Array(s.length).fill(undefined);
29
- const quoted = new Array(s.length).fill(false);
30
- let open;
31
- for (let i = 0; i < s.length; i++) {
32
- if (open === undefined && s[i] === "$" && s[i + 1] === "'") {
33
- const close = ansiCQuoteClose(s, i + 1);
34
- for (let k = i; k <= (close ?? s.length - 1); k++) {
35
- openedBy[k] = "'";
36
- quoted[k] = true;
37
- }
38
- if (close === undefined) {
39
- open = "'";
40
- break;
41
- }
42
- i = close;
43
- continue;
44
- }
45
- const before = open;
46
- open = quoteStep(open, s[i]);
47
- const holds = before ?? open;
48
- openedBy[i] = holds;
49
- quoted[i] = holds !== undefined;
50
- }
51
- return { openedBy, quoted, balanced: open === undefined };
52
- }
53
- export function literalTildeSpelling(word) {
54
- return word.startsWith("~") ? `./${word}` : word;
55
- }
56
- function tildeIsLiteral(raw) {
57
- if (!raw.startsWith("~"))
58
- return true;
59
- for (let i = 1; i < raw.length; i++) {
60
- const ch = raw[i];
61
- if (ch === '"' || ch === "'")
62
- return true;
63
- if (ch === "/")
64
- return false;
65
- }
66
- return false;
67
- }
68
- function ansiCBody(source, open) {
69
- const close = ansiCQuoteClose(source, open);
70
- if (close === undefined)
71
- return undefined;
72
- const body = source.slice(open + 1, close);
73
- return body.includes("\\") ? { unreadable: true, close } : { text: body, close };
74
- }
75
- export function wordsOf(segment) {
76
- const folded = [];
77
- const raw = [];
78
- for (const t of segment.tokens) {
79
- if (t.kind !== "word")
80
- continue;
81
- folded.push(t.folded);
82
- raw.push(t.raw);
83
- }
84
- return { folded, raw };
85
- }
86
- function past(text, j) {
87
- let k = j;
88
- while (text[k] === "\\" && text[k + 1] === "\n")
89
- k += 2;
90
- return k;
91
- }
92
- function parenBodyEnd(text, open) {
93
- let depth = 0;
94
- let quoted;
95
- let wordStart = true;
96
- let word = "";
97
- for (let j = open; j < text.length; j++) {
98
- const c = text[j];
99
- if (quoted !== undefined) {
100
- if (c === "\\" && quoted === '"')
101
- j++;
102
- else if (c === quoted)
103
- quoted = undefined;
104
- wordStart = false;
105
- continue;
106
- }
107
- if (c === "\\") {
108
- if (text[j + 1] === "\n") {
109
- j++;
110
- continue;
111
- }
112
- j++;
113
- wordStart = false;
114
- word = "";
115
- continue;
116
- }
117
- if (c === "#" && wordStart) {
118
- const nl = text.indexOf("\n", j);
119
- if (nl < 0)
120
- return undefined;
121
- j = nl;
122
- wordStart = true;
123
- word = "";
124
- continue;
125
- }
126
- if (c === "'" || c === '"') {
127
- quoted = c;
128
- wordStart = false;
129
- word = "";
130
- continue;
131
- }
132
- if (c === "$" && text[past(text, j + 1)] === "{") {
133
- const open2 = past(text, j + 1);
134
- const close = braceExpansionEnd(text, open2);
135
- if (close === undefined)
136
- return undefined;
137
- if (UNREADABLE_EXPANSION_TEXT.test(text.slice(open2 + 1, close - 1)))
138
- return "unreadable";
139
- j = close - 1;
140
- wordStart = false;
141
- word = "";
142
- continue;
143
- }
144
- if (c === "<" && text[past(text, j + 1)] === "<" && text[past(text, past(text, j + 1) + 1)] !== "<")
145
- return "unreadable";
146
- if (c === "(")
147
- depth++;
148
- else if (c === ")") {
149
- depth--;
150
- if (depth === 0)
151
- return j + 1;
152
- }
153
- const boundary = /[\s;|&()]/.test(c);
154
- if (boundary && word === "case")
155
- return "unreadable";
156
- word = boundary ? "" : word + c;
157
- wordStart = boundary;
158
- }
159
- return undefined;
160
- }
161
- function braceExpansionEnd(text, open) {
162
- let quoted;
163
- for (let j = open + 1; j < text.length; j++) {
164
- const c = text[j];
165
- if (quoted !== undefined) {
166
- if (c === "\\" && quoted === '"')
167
- j++;
168
- else if (c === quoted)
169
- quoted = undefined;
170
- continue;
171
- }
172
- if (c === "\\") {
173
- j++;
174
- continue;
175
- }
176
- if (c === "'" || c === '"') {
177
- quoted = c;
178
- continue;
179
- }
180
- if (c === "}")
181
- return j + 1;
182
- }
183
- return undefined;
184
- }
185
- const UNREADABLE_EXPANSION_TEXT = /[$`()<>{\\]/;
186
- function backtickBody(source, open) {
187
- let body = "";
188
- for (let j = open + 1; j < source.length; j++) {
189
- const c = source[j];
190
- if (c === "\\" && j + 1 < source.length) {
191
- const next = source[j + 1];
192
- if (next === "\n") {
193
- j++;
194
- continue;
195
- }
196
- body += next === "$" || next === "`" || next === "\\" ? next : c + next;
197
- j++;
198
- continue;
199
- }
200
- if (c === "`")
201
- return { body, close: j };
202
- body += c;
203
- }
204
- return undefined;
205
- }
206
- export function substitutionsInHeredocBody(body) {
207
- const out = [];
208
- for (let i = 0; i < body.length; i++) {
209
- const ch = body[i];
210
- if (ch === "\\") {
211
- i++;
212
- continue;
213
- }
214
- if (ch === "`") {
215
- const tick = backtickBody(body, i);
216
- if (tick === undefined)
217
- return undefined;
218
- out.push(tick.body);
219
- i = tick.close;
220
- continue;
221
- }
222
- if (ch === "$" && body[i + 1] === "(") {
223
- const end = parenBodyEnd(body, i + 1);
224
- if (typeof end !== "number")
225
- return undefined;
226
- out.push(body.slice(i + 2, end - 1));
227
- i = end - 1;
228
- }
229
- }
230
- return out;
231
- }
232
- const UNDELIMITED_SUBSTITUTION = "a command substitution carries a construct this lexer cannot delimit";
233
- const WHITESPACE = /\s/;
234
- const BLANK = /[ \t]/;
235
- const UNTERMINATED_HEREDOC = "a here-document body never terminates";
236
- function scan(source, opts, quotesLiteral) {
237
- const lenient = opts.mode === "lenient";
238
- const split = opts.connectors !== "text";
239
- const segments = [{ start: 0, end: source.length, connector: "start", tokens: [], substitutions: [] }];
240
- const current = () => segments[segments.length - 1];
241
- const pendingHeredocs = [];
242
- let pendingRedirect;
243
- let pendingHeredoc;
244
- let inSingle = false;
245
- let inDouble = false;
246
- let raw = "";
247
- let folded = "";
248
- let started = false;
249
- let foldOpen;
250
- const next = (j) => (lenient ? past(source, j + 1) : j + 1);
251
- const foldChar = (ch) => {
252
- if (ch === '"' || ch === "'") {
253
- if (foldOpen === undefined) {
254
- foldOpen = ch;
255
- return;
256
- }
257
- if (foldOpen === ch) {
258
- foldOpen = undefined;
259
- return;
260
- }
261
- }
262
- folded += ch;
263
- };
264
- const take = (ch) => { raw += ch; foldChar(ch); started = true; };
265
- const endWord = () => {
266
- if (!started)
267
- return undefined;
268
- const word = { raw, folded, tilde: tildeIsLiteral(raw) ? literalTildeSpelling(folded) : folded };
269
- raw = "";
270
- folded = "";
271
- started = false;
272
- foldOpen = undefined;
273
- if (pendingHeredoc !== undefined) {
274
- const header = pendingHeredoc;
275
- pendingHeredoc = undefined;
276
- if (word.folded === "" || /[$`]/.test(word.raw))
277
- return "a here-document delimiter is not a plain word";
278
- const token = { kind: "heredoc", delimiter: word.folded, quoted: /["'\\]/.test(word.raw), body: "" };
279
- current().tokens.push(token);
280
- pendingHeredocs.push({ delimiter: word.folded, quoted: token.quoted, dash: header.dash, token });
281
- return undefined;
282
- }
283
- if (pendingRedirect !== undefined) {
284
- const op = pendingRedirect;
285
- pendingRedirect = undefined;
286
- if (op === ">&" || op === "<&") {
287
- if (word.raw === word.folded && /^(?:\d+-?|-)$/.test(word.folded)) {
288
- current().tokens.push({ kind: "redirect", op });
289
- return undefined;
290
- }
291
- current().tokens.push({ kind: "redirect", op: op === ">&" ? "&>" : "<", target: { kind: "word", raw: word.raw, folded: word.tilde } });
292
- return undefined;
293
- }
294
- current().tokens.push({ kind: "redirect", op, target: { kind: "word", raw: word.raw, folded: word.tilde } });
295
- return undefined;
296
- }
297
- current().tokens.push({ kind: "word", raw: word.raw, folded: word.tilde });
298
- return undefined;
299
- };
300
- const operandOwed = () => pendingRedirect !== undefined ? "a redirection names no target" : pendingHeredoc !== undefined ? "a here-document operator names no delimiter" : undefined;
301
- const closeSegment = (connector, at, from) => {
302
- const refusal = endWord() ?? operandOwed();
303
- if (refusal !== undefined)
304
- return refusal;
305
- current().end = at;
306
- segments.push({ start: from, end: source.length, connector, tokens: [], substitutions: [] });
307
- return undefined;
308
- };
309
- const substitution = (from, to, body) => {
310
- raw += source.slice(from, to);
311
- folded += SUBSTITUTION_PLACEHOLDER;
312
- started = true;
313
- current().substitutions.push(body);
314
- };
315
- const readHeredocBodies = (from) => {
316
- let p = from;
317
- for (const h of pendingHeredocs) {
318
- const lines = [];
319
- for (;;) {
320
- if (p > source.length)
321
- return { reject: UNTERMINATED_HEREDOC };
322
- let nl = source.indexOf("\n", p);
323
- let line = nl < 0 ? source.slice(p) : source.slice(p, nl);
324
- if (!h.quoted) {
325
- while (nl >= 0 && /(?<!\\)(?:\\\\)*\\$/.test(line)) {
326
- const after = source.indexOf("\n", nl + 1);
327
- line = line.slice(0, -1) + (after < 0 ? source.slice(nl + 1) : source.slice(nl + 1, after));
328
- nl = after;
329
- }
330
- }
331
- if ((h.dash ? line.replace(/^\t+/, "") : line) === h.delimiter) {
332
- p = nl < 0 ? source.length + 1 : nl + 1;
333
- break;
334
- }
335
- if (nl < 0)
336
- return { reject: UNTERMINATED_HEREDOC };
337
- lines.push(line);
338
- p = nl + 1;
339
- }
340
- h.token.body = lines.join("\n");
341
- }
342
- pendingHeredocs.length = 0;
343
- return Math.min(p, source.length);
344
- };
345
- for (let i = 0; i < source.length; i++) {
346
- if (lenient && !inSingle) {
347
- const j = past(source, i);
348
- if (j >= source.length)
349
- break;
350
- i = j;
351
- }
352
- const ch = source[i];
353
- if (!quotesLiteral && ch === "$" && !inSingle && !inDouble && dollarOpensQuote(source, i)) {
354
- const q = next(i);
355
- if (source[q] === '"') {
356
- raw += ch;
357
- started = true;
358
- i = q - 1;
359
- continue;
360
- }
361
- if (source[q] === "'") {
362
- const ansi = ansiCBody(source, q);
363
- if (ansi === undefined)
364
- return { reject: "an ANSI-C quoted word never closes" };
365
- if ("unreadable" in ansi)
366
- return { reject: "an ANSI-C quoted word carries an escape this lexer does not fold" };
367
- raw += source.slice(i, ansi.close + 1);
368
- folded += ansi.text;
369
- started = true;
370
- i = ansi.close;
371
- continue;
372
- }
373
- }
374
- if (!quotesLiteral) {
375
- if (ch === "'" && !inDouble) {
376
- inSingle = !inSingle;
377
- take(ch);
378
- continue;
379
- }
380
- if (ch === '"' && !inSingle) {
381
- inDouble = !inDouble;
382
- take(ch);
383
- continue;
384
- }
385
- }
386
- if (inSingle) {
387
- take(ch);
388
- continue;
389
- }
390
- if (lenient) {
391
- const n1 = next(i);
392
- if (ch === "\\") {
393
- const escaped = source[i + 1];
394
- if (escaped === undefined) {
395
- take(ch);
396
- continue;
397
- }
398
- raw += ch + escaped;
399
- folded += inDouble && !"$`\"\\".includes(escaped) ? ch + escaped : escaped;
400
- started = true;
401
- i++;
402
- continue;
403
- }
404
- if (ch === "`") {
405
- const tick = backtickBody(source, i);
406
- if (tick === undefined)
407
- return { reject: "a command substitution never terminates" };
408
- substitution(i, tick.close + 1, tick.body);
409
- i = tick.close;
410
- continue;
411
- }
412
- if (ch === "$" && source[n1] === "(") {
413
- const end = parenBodyEnd(source, n1);
414
- if (end === undefined)
415
- return { reject: "a command substitution never terminates" };
416
- if (end === "unreadable")
417
- return { reject: UNDELIMITED_SUBSTITUTION };
418
- substitution(i, end, source.slice(n1 + 1, end - 1));
419
- i = end - 1;
420
- continue;
421
- }
422
- if (ch === "$" && source[n1] === "{") {
423
- const end = braceExpansionEnd(source, n1);
424
- if (end === undefined)
425
- return { reject: "a parameter expansion never terminates" };
426
- if (UNREADABLE_EXPANSION_TEXT.test(source.slice(n1 + 1, end - 1)))
427
- return { reject: "a parameter expansion carries text this lexer does not read" };
428
- const text = source.slice(i, end);
429
- raw += text;
430
- folded += text;
431
- started = true;
432
- i = end - 1;
433
- continue;
434
- }
435
- if (inDouble) {
436
- take(ch);
437
- continue;
438
- }
439
- if ((ch === "<" || ch === ">") && source[n1] === "(") {
440
- const end = parenBodyEnd(source, n1);
441
- if (end === undefined)
442
- return { reject: "a process substitution never terminates" };
443
- if (end === "unreadable")
444
- return { reject: UNDELIMITED_SUBSTITUTION };
445
- substitution(i, end, source.slice(n1 + 1, end - 1));
446
- i = end - 1;
447
- continue;
448
- }
449
- if (ch === "#" && !started) {
450
- const nl = source.indexOf("\n", i);
451
- i = nl < 0 ? source.length : nl - 1;
452
- continue;
453
- }
454
- if (ch === "\n") {
455
- if (!split) {
456
- const r = endWord();
457
- if (r !== undefined)
458
- return { reject: r };
459
- continue;
460
- }
461
- const refusal = closeSegment("\n", i, i + 1);
462
- if (refusal !== undefined)
463
- return { reject: refusal };
464
- if (pendingHeredocs.length > 0) {
465
- const resume = readHeredocBodies(i + 1);
466
- if (typeof resume !== "number")
467
- return resume;
468
- current().start = resume;
469
- i = resume - 1;
470
- }
471
- continue;
472
- }
473
- if (ch === "(" || ch === ")") {
474
- const r = endWord() ?? operandOwed();
475
- if (r !== undefined)
476
- return { reject: r };
477
- current().tokens.push({ kind: "group", op: ch });
478
- continue;
479
- }
480
- if (ch === "<" || ch === ">" || (ch === "&" && source[n1] === ">")) {
481
- if (ch !== "&" && started && raw === folded && /^\d+$/.test(raw)) {
482
- raw = "";
483
- folded = "";
484
- started = false;
485
- }
486
- else {
487
- const r = endWord() ?? operandOwed();
488
- if (r !== undefined)
489
- return { reject: r };
490
- }
491
- const n2 = next(n1);
492
- if (ch === "&") {
493
- if (source[n2] === ">") {
494
- pendingRedirect = "&>>";
495
- i = n2;
496
- }
497
- else {
498
- pendingRedirect = "&>";
499
- i = n1;
500
- }
501
- continue;
502
- }
503
- if (ch === "<" && source[n1] === "<") {
504
- if (source[n2] === "<") {
505
- pendingRedirect = "<<<";
506
- i = n2;
507
- continue;
508
- }
509
- const dash = source[n2] === "-";
510
- pendingHeredoc = { dash };
511
- i = dash ? n2 : n1;
512
- continue;
513
- }
514
- if (source[n1] === "&") {
515
- pendingRedirect = ch === ">" ? ">&" : "<&";
516
- i = n1;
517
- continue;
518
- }
519
- if (ch === ">" && (source[n1] === ">" || source[n1] === "|")) {
520
- pendingRedirect = source[n1] === ">" ? ">>" : ">";
521
- i = n1;
522
- continue;
523
- }
524
- pendingRedirect = ch;
525
- continue;
526
- }
527
- if (split) {
528
- let refusal;
529
- if (ch === ";")
530
- refusal = closeSegment(";", i, i + 1);
531
- else if (ch === "&") {
532
- if (source[n1] === "&") {
533
- refusal = closeSegment("&&", i, n1 + 1);
534
- i = n1;
535
- }
536
- else
537
- refusal = closeSegment("&", i, i + 1);
538
- }
539
- else if (ch === "|") {
540
- if (source[n1] === "|" || source[n1] === "&") {
541
- refusal = closeSegment(source[n1] === "|" ? "||" : "|", i, n1 + 1);
542
- i = n1;
543
- }
544
- else
545
- refusal = closeSegment("|", i, i + 1);
546
- }
547
- else if (BLANK.test(ch)) {
548
- refusal = endWord();
549
- }
550
- else {
551
- take(ch);
552
- continue;
553
- }
554
- if (refusal !== undefined)
555
- return { reject: refusal };
556
- continue;
557
- }
558
- if (BLANK.test(ch)) {
559
- const r = endWord();
560
- if (r !== undefined)
561
- return { reject: r };
562
- continue;
563
- }
564
- take(ch);
565
- continue;
566
- }
567
- if (!inDouble && split) {
568
- if (ch === "&") {
569
- if (source[i + 1] === "&") {
570
- closeSegment("&&", i, i + 2);
571
- i++;
572
- continue;
573
- }
574
- return { reject: "`&` backgrounding is not allowed — a backgrounded process outlives the command" };
575
- }
576
- if (ch === "|") {
577
- if (source[i + 1] === "|") {
578
- closeSegment("||", i, i + 2);
579
- i++;
580
- }
581
- else
582
- closeSegment("|", i, i + 1);
583
- continue;
584
- }
585
- if (ch === ";") {
586
- closeSegment(";", i, i + 1);
587
- continue;
588
- }
589
- }
590
- if (!inDouble && WHITESPACE.test(ch)) {
591
- endWord();
592
- continue;
593
- }
594
- take(ch);
595
- }
596
- const tail = endWord() ?? operandOwed();
597
- if (tail !== undefined)
598
- return { reject: tail };
599
- if (pendingHeredocs.length > 0)
600
- return { reject: UNTERMINATED_HEREDOC };
601
- const out = segments.map((s) => ({
602
- text: source.slice(s.start, s.end),
603
- connector: s.connector,
604
- tokens: s.tokens,
605
- substitutions: s.substitutions,
606
- }));
607
- return { balanced: !inSingle && !inDouble, command: { segments: out, substitutions: out.flatMap((s) => s.substitutions) } };
608
- }
609
- export function lexShellText(source, opts) {
610
- const honoured = scan(source, opts, false);
611
- if ("reject" in honoured)
612
- return honoured;
613
- if (honoured.balanced)
614
- return honoured.command;
615
- const blind = scan(source, opts, true);
616
- if ("reject" in blind)
617
- return blind;
618
- if (opts.mode === "lenient" || opts.connectors === "text")
619
- return blind.command;
620
- const segments = blind.command.segments.map((segment) => {
621
- const own = scan(segment.text, { mode: "strict", connectors: "text" }, false);
622
- if ("reject" in own || !own.balanced)
623
- return segment;
624
- return { ...segment, tokens: own.command.segments[0].tokens };
625
- });
626
- return { segments, substitutions: [] };
627
- }