@ordewell/core 0.4.7 → 0.4.9
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/{ITerminalRunner-fynILAiR.d.mts → ITerminalRunner-1NAv8wCC.d.mts} +15 -3
- package/dist/{ITerminalRunner-Cpyzyrnl.d.ts → ITerminalRunner-CbE6gKLI.d.ts} +15 -3
- package/dist/index.d.mts +251 -3
- package/dist/index.d.ts +251 -3
- package/dist/index.js +2092 -134
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2067 -137
- package/dist/index.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -108,7 +108,6 @@ var AUTO_COMMANDS = [
|
|
|
108
108
|
"pwd",
|
|
109
109
|
"which",
|
|
110
110
|
"type",
|
|
111
|
-
"env",
|
|
112
111
|
"uname",
|
|
113
112
|
"whoami",
|
|
114
113
|
"cut",
|
|
@@ -119,13 +118,1233 @@ var AUTO_COMMANDS = [
|
|
|
119
118
|
"jq",
|
|
120
119
|
"yq"
|
|
121
120
|
];
|
|
121
|
+
var UNIVERSAL_FLAGS = ["--help", "--version"];
|
|
122
|
+
var COUNT_FLAG = /^-\d+$/;
|
|
123
|
+
var FLAG_POLICY = {
|
|
124
|
+
ls: {
|
|
125
|
+
cluster: true,
|
|
126
|
+
booleans: [
|
|
127
|
+
"-1",
|
|
128
|
+
"-a",
|
|
129
|
+
"-A",
|
|
130
|
+
"-b",
|
|
131
|
+
"-c",
|
|
132
|
+
"-C",
|
|
133
|
+
"-d",
|
|
134
|
+
"-D",
|
|
135
|
+
"-f",
|
|
136
|
+
"-F",
|
|
137
|
+
"-g",
|
|
138
|
+
"-G",
|
|
139
|
+
"-h",
|
|
140
|
+
"-H",
|
|
141
|
+
"-i",
|
|
142
|
+
"-k",
|
|
143
|
+
"-l",
|
|
144
|
+
"-L",
|
|
145
|
+
"-m",
|
|
146
|
+
"-n",
|
|
147
|
+
"-N",
|
|
148
|
+
"-o",
|
|
149
|
+
"-p",
|
|
150
|
+
"-q",
|
|
151
|
+
"-Q",
|
|
152
|
+
"-r",
|
|
153
|
+
"-R",
|
|
154
|
+
"-s",
|
|
155
|
+
"-S",
|
|
156
|
+
"-t",
|
|
157
|
+
"-u",
|
|
158
|
+
"-U",
|
|
159
|
+
"-v",
|
|
160
|
+
"-x",
|
|
161
|
+
"-X",
|
|
162
|
+
"-Z",
|
|
163
|
+
"--all",
|
|
164
|
+
"--almost-all",
|
|
165
|
+
"--author",
|
|
166
|
+
"--escape",
|
|
167
|
+
"--classify",
|
|
168
|
+
"--file-type",
|
|
169
|
+
"--full-time",
|
|
170
|
+
"--no-group",
|
|
171
|
+
"--human-readable",
|
|
172
|
+
"--si",
|
|
173
|
+
"--dereference-command-line",
|
|
174
|
+
"--inode",
|
|
175
|
+
"--kibibytes",
|
|
176
|
+
"--dereference",
|
|
177
|
+
"--numeric-uid-gid",
|
|
178
|
+
"--literal",
|
|
179
|
+
"--hide-control-chars",
|
|
180
|
+
"--show-control-chars",
|
|
181
|
+
"--quote-name",
|
|
182
|
+
"--reverse",
|
|
183
|
+
"--recursive",
|
|
184
|
+
"--size",
|
|
185
|
+
"--directory",
|
|
186
|
+
"--group-directories-first",
|
|
187
|
+
"--context",
|
|
188
|
+
"--zero"
|
|
189
|
+
],
|
|
190
|
+
values: [
|
|
191
|
+
"-w",
|
|
192
|
+
"-I",
|
|
193
|
+
"-T",
|
|
194
|
+
"--width",
|
|
195
|
+
"--ignore",
|
|
196
|
+
"--hide",
|
|
197
|
+
"--block-size",
|
|
198
|
+
"--color",
|
|
199
|
+
"--format",
|
|
200
|
+
"--sort",
|
|
201
|
+
"--time",
|
|
202
|
+
"--time-style",
|
|
203
|
+
"--indicator-style",
|
|
204
|
+
"--quoting-style",
|
|
205
|
+
"--tabsize"
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
tree: {
|
|
209
|
+
cluster: true,
|
|
210
|
+
// `-o` is absent on purpose: it is tree's write-to-a-file flag, which the
|
|
211
|
+
// redirect check never sees because there is no redirect.
|
|
212
|
+
booleans: [
|
|
213
|
+
"-a",
|
|
214
|
+
"-d",
|
|
215
|
+
"-f",
|
|
216
|
+
"-i",
|
|
217
|
+
"-l",
|
|
218
|
+
"-x",
|
|
219
|
+
"-C",
|
|
220
|
+
"-n",
|
|
221
|
+
"-p",
|
|
222
|
+
"-s",
|
|
223
|
+
"-h",
|
|
224
|
+
"-u",
|
|
225
|
+
"-g",
|
|
226
|
+
"-D",
|
|
227
|
+
"-t",
|
|
228
|
+
"-c",
|
|
229
|
+
"-r",
|
|
230
|
+
"-F",
|
|
231
|
+
"-q",
|
|
232
|
+
"-N",
|
|
233
|
+
"-Q",
|
|
234
|
+
"-v",
|
|
235
|
+
"-J",
|
|
236
|
+
"-X",
|
|
237
|
+
"-Z",
|
|
238
|
+
"--noreport",
|
|
239
|
+
"--dirsfirst",
|
|
240
|
+
"--du",
|
|
241
|
+
"--prune",
|
|
242
|
+
"--matchdirs",
|
|
243
|
+
"--inodes",
|
|
244
|
+
"--device",
|
|
245
|
+
"--si",
|
|
246
|
+
"--gitignore",
|
|
247
|
+
"--ignore-case",
|
|
248
|
+
"--filesfirst",
|
|
249
|
+
"--nolinks",
|
|
250
|
+
"--hintro"
|
|
251
|
+
],
|
|
252
|
+
values: [
|
|
253
|
+
"-L",
|
|
254
|
+
"-P",
|
|
255
|
+
"-I",
|
|
256
|
+
"-H",
|
|
257
|
+
"--filelimit",
|
|
258
|
+
"--timefmt",
|
|
259
|
+
"--charset",
|
|
260
|
+
"--sort",
|
|
261
|
+
"--gitfile",
|
|
262
|
+
"--info",
|
|
263
|
+
"--prefix"
|
|
264
|
+
]
|
|
265
|
+
},
|
|
266
|
+
git: {
|
|
267
|
+
cluster: true,
|
|
268
|
+
// Absent on purpose, and each for a reason that was demonstrated rather than
|
|
269
|
+
// guessed at:
|
|
270
|
+
// -c, --config-env set configuration inline, and several configuration
|
|
271
|
+
// keys name a program to run (`core.pager`, `core.editor`,
|
|
272
|
+
// `diff.external`), so this is an execution flag with one
|
|
273
|
+
// indirection in front of it.
|
|
274
|
+
// --exec-path redirects where git finds its helper programs; a
|
|
275
|
+
// fabricated helper ran during an ordinary remote listing.
|
|
276
|
+
// -O, --open-files-in-pager runs an arbitrary named program over search hits.
|
|
277
|
+
// --upload-pack, --receive-pack name the program run on the other end.
|
|
278
|
+
// --textconv, --ext-diff run filters the repository itself configures.
|
|
279
|
+
// --git-dir, --work-tree repoint git at a tree whose configuration is not
|
|
280
|
+
// the one the developer is looking at.
|
|
281
|
+
// -o, --output write a file. `git ls-files -o` is a legitimate spelling
|
|
282
|
+
// of `--others`, but `git archive -o` writes, and the
|
|
283
|
+
// long spelling stays available for the read.
|
|
284
|
+
booleans: [
|
|
285
|
+
"-a",
|
|
286
|
+
"-b",
|
|
287
|
+
"-E",
|
|
288
|
+
"-F",
|
|
289
|
+
"-h",
|
|
290
|
+
"-H",
|
|
291
|
+
"-i",
|
|
292
|
+
"-I",
|
|
293
|
+
"-l",
|
|
294
|
+
"-p",
|
|
295
|
+
"-P",
|
|
296
|
+
"-q",
|
|
297
|
+
"-r",
|
|
298
|
+
"-R",
|
|
299
|
+
"-s",
|
|
300
|
+
"-t",
|
|
301
|
+
"-u",
|
|
302
|
+
"-v",
|
|
303
|
+
"-w",
|
|
304
|
+
"-z",
|
|
305
|
+
"--oneline",
|
|
306
|
+
"--graph",
|
|
307
|
+
"--stat",
|
|
308
|
+
"--shortstat",
|
|
309
|
+
"--numstat",
|
|
310
|
+
"--dirstat",
|
|
311
|
+
"--summary",
|
|
312
|
+
"--name-only",
|
|
313
|
+
"--name-status",
|
|
314
|
+
"--raw",
|
|
315
|
+
"--patch",
|
|
316
|
+
"--no-patch",
|
|
317
|
+
"--patch-with-stat",
|
|
318
|
+
"--cached",
|
|
319
|
+
"--staged",
|
|
320
|
+
"--porcelain",
|
|
321
|
+
"--short",
|
|
322
|
+
"--long",
|
|
323
|
+
"--branch",
|
|
324
|
+
"--show-stash",
|
|
325
|
+
"--show-current",
|
|
326
|
+
"--all",
|
|
327
|
+
"--tags",
|
|
328
|
+
"--heads",
|
|
329
|
+
"--remotes",
|
|
330
|
+
"--list",
|
|
331
|
+
"--verbose",
|
|
332
|
+
"--quiet",
|
|
333
|
+
"--abbrev-ref",
|
|
334
|
+
"--count",
|
|
335
|
+
"--reverse",
|
|
336
|
+
"--first-parent",
|
|
337
|
+
"--no-merges",
|
|
338
|
+
"--merges",
|
|
339
|
+
"--follow",
|
|
340
|
+
"--full-history",
|
|
341
|
+
"--simplify-merges",
|
|
342
|
+
"--sparse",
|
|
343
|
+
"--dense",
|
|
344
|
+
"--ancestry-path",
|
|
345
|
+
"--left-right",
|
|
346
|
+
"--cherry",
|
|
347
|
+
"--cherry-pick",
|
|
348
|
+
"--cherry-mark",
|
|
349
|
+
"--boundary",
|
|
350
|
+
"--topo-order",
|
|
351
|
+
"--date-order",
|
|
352
|
+
"--author-date-order",
|
|
353
|
+
"--relative-date",
|
|
354
|
+
"--parents",
|
|
355
|
+
"--children",
|
|
356
|
+
"--timestamp",
|
|
357
|
+
"--no-walk",
|
|
358
|
+
"--do-walk",
|
|
359
|
+
"--decorate",
|
|
360
|
+
"--no-decorate",
|
|
361
|
+
"--abbrev-commit",
|
|
362
|
+
"--no-abbrev-commit",
|
|
363
|
+
"--abbrev",
|
|
364
|
+
"--no-abbrev",
|
|
365
|
+
"--color",
|
|
366
|
+
"--no-color",
|
|
367
|
+
"--pretty",
|
|
368
|
+
"--format",
|
|
369
|
+
"--expand-tabs",
|
|
370
|
+
"--no-expand-tabs",
|
|
371
|
+
"--numbered",
|
|
372
|
+
"--email",
|
|
373
|
+
"--no-notes",
|
|
374
|
+
"--notes",
|
|
375
|
+
"--show-signature",
|
|
376
|
+
"--find-renames",
|
|
377
|
+
"--find-copies",
|
|
378
|
+
"--find-copies-harder",
|
|
379
|
+
"--break-rewrites",
|
|
380
|
+
"--no-renames",
|
|
381
|
+
"--irreversible-delete",
|
|
382
|
+
"--full-index",
|
|
383
|
+
"--binary",
|
|
384
|
+
"--text",
|
|
385
|
+
"--check",
|
|
386
|
+
"--exit-code",
|
|
387
|
+
"--word-diff",
|
|
388
|
+
"--function-context",
|
|
389
|
+
"--ignore-all-space",
|
|
390
|
+
"--ignore-space-change",
|
|
391
|
+
"--ignore-space-at-eol",
|
|
392
|
+
"--ignore-blank-lines",
|
|
393
|
+
"--ignore-cr-at-eol",
|
|
394
|
+
"--no-prefix",
|
|
395
|
+
"--default-prefix",
|
|
396
|
+
"--no-textconv",
|
|
397
|
+
"--no-ext-diff",
|
|
398
|
+
"--submodule",
|
|
399
|
+
"--ignore-submodules",
|
|
400
|
+
"--recurse-submodules",
|
|
401
|
+
"--no-recurse-submodules",
|
|
402
|
+
"--others",
|
|
403
|
+
"--deleted",
|
|
404
|
+
"--modified",
|
|
405
|
+
"--unmerged",
|
|
406
|
+
"--stage",
|
|
407
|
+
"--killed",
|
|
408
|
+
"--ignored",
|
|
409
|
+
"--exclude-standard",
|
|
410
|
+
"--error-unmatch",
|
|
411
|
+
"--full-name",
|
|
412
|
+
"--directory",
|
|
413
|
+
"--no-empty-directory",
|
|
414
|
+
"--untracked-files",
|
|
415
|
+
"--no-optional-locks",
|
|
416
|
+
"--no-pager",
|
|
417
|
+
"--paginate",
|
|
418
|
+
"--bare",
|
|
419
|
+
"--literal-pathspecs",
|
|
420
|
+
"--glob-pathspecs",
|
|
421
|
+
"--noglob-pathspecs",
|
|
422
|
+
"--icase-pathspecs",
|
|
423
|
+
"--line-number",
|
|
424
|
+
"--column",
|
|
425
|
+
"--heading",
|
|
426
|
+
"--no-index",
|
|
427
|
+
"--untracked",
|
|
428
|
+
"--no-recursive",
|
|
429
|
+
"--name-rev",
|
|
430
|
+
"--root",
|
|
431
|
+
"--dirty",
|
|
432
|
+
"--broken",
|
|
433
|
+
"--always",
|
|
434
|
+
"--merged",
|
|
435
|
+
"--no-merged",
|
|
436
|
+
"--show-toplevel",
|
|
437
|
+
"--show-cdup",
|
|
438
|
+
"--git-common-dir",
|
|
439
|
+
"--absolute-git-dir",
|
|
440
|
+
"--is-inside-work-tree",
|
|
441
|
+
"--is-inside-git-dir",
|
|
442
|
+
"--is-bare-repository",
|
|
443
|
+
"--symbolic",
|
|
444
|
+
"--symbolic-full-name",
|
|
445
|
+
"--verify",
|
|
446
|
+
"--short-hash",
|
|
447
|
+
"--textual",
|
|
448
|
+
"--batch",
|
|
449
|
+
"--batch-check",
|
|
450
|
+
"--batch-all-objects",
|
|
451
|
+
"--buffer",
|
|
452
|
+
"--follow-symlinks",
|
|
453
|
+
"--use-mailmap"
|
|
454
|
+
],
|
|
455
|
+
values: [
|
|
456
|
+
"-n",
|
|
457
|
+
"-C",
|
|
458
|
+
"-B",
|
|
459
|
+
"-M",
|
|
460
|
+
"-L",
|
|
461
|
+
"-S",
|
|
462
|
+
"-G",
|
|
463
|
+
"-U",
|
|
464
|
+
"-e",
|
|
465
|
+
"-m",
|
|
466
|
+
"-f",
|
|
467
|
+
"-g",
|
|
468
|
+
"-x",
|
|
469
|
+
"-X",
|
|
470
|
+
"-W",
|
|
471
|
+
"--max-count",
|
|
472
|
+
"--skip",
|
|
473
|
+
"--since",
|
|
474
|
+
"--after",
|
|
475
|
+
"--until",
|
|
476
|
+
"--before",
|
|
477
|
+
"--author",
|
|
478
|
+
"--grep",
|
|
479
|
+
"--grep-reflog",
|
|
480
|
+
"--committer",
|
|
481
|
+
"--date",
|
|
482
|
+
"--diff-filter",
|
|
483
|
+
"--unified",
|
|
484
|
+
"--stat-width",
|
|
485
|
+
"--stat-name-width",
|
|
486
|
+
"--stat-count",
|
|
487
|
+
"--word-diff-regex",
|
|
488
|
+
"--line-prefix",
|
|
489
|
+
"--src-prefix",
|
|
490
|
+
"--dst-prefix",
|
|
491
|
+
"--pickaxe-regex",
|
|
492
|
+
"--anchored",
|
|
493
|
+
"--color-moved",
|
|
494
|
+
"--color-words",
|
|
495
|
+
"--inter-hunk-context",
|
|
496
|
+
"--max-parents",
|
|
497
|
+
"--min-parents",
|
|
498
|
+
"--simplify-by-decoration",
|
|
499
|
+
"--glob",
|
|
500
|
+
"--exclude",
|
|
501
|
+
"--sort",
|
|
502
|
+
"--contains",
|
|
503
|
+
"--points-at",
|
|
504
|
+
"--decorate-refs",
|
|
505
|
+
"--decorate-refs-exclude",
|
|
506
|
+
"--encoding",
|
|
507
|
+
"--context",
|
|
508
|
+
"--max-depth",
|
|
509
|
+
// `--filters` is absent from this list on purpose: it runs the clean and
|
|
510
|
+
// smudge filters the repository under research configures, which is the
|
|
511
|
+
// same execution vector as the configuration flag above with a different
|
|
512
|
+
// spelling.
|
|
513
|
+
"--and",
|
|
514
|
+
"--or",
|
|
515
|
+
"--not",
|
|
516
|
+
"--all-match",
|
|
517
|
+
"--threads",
|
|
518
|
+
"--path"
|
|
519
|
+
],
|
|
520
|
+
patterns: [COUNT_FLAG]
|
|
521
|
+
},
|
|
522
|
+
wc: {
|
|
523
|
+
cluster: true,
|
|
524
|
+
booleans: [
|
|
525
|
+
"-c",
|
|
526
|
+
"-l",
|
|
527
|
+
"-m",
|
|
528
|
+
"-w",
|
|
529
|
+
"-L",
|
|
530
|
+
"--bytes",
|
|
531
|
+
"--chars",
|
|
532
|
+
"--lines",
|
|
533
|
+
"--words",
|
|
534
|
+
"--max-line-length",
|
|
535
|
+
"--total"
|
|
536
|
+
]
|
|
537
|
+
},
|
|
538
|
+
du: {
|
|
539
|
+
cluster: true,
|
|
540
|
+
booleans: [
|
|
541
|
+
"-0",
|
|
542
|
+
"-a",
|
|
543
|
+
"-b",
|
|
544
|
+
"-c",
|
|
545
|
+
"-D",
|
|
546
|
+
"-h",
|
|
547
|
+
"-H",
|
|
548
|
+
"-k",
|
|
549
|
+
"-l",
|
|
550
|
+
"-L",
|
|
551
|
+
"-m",
|
|
552
|
+
"-P",
|
|
553
|
+
"-s",
|
|
554
|
+
"-S",
|
|
555
|
+
"-x",
|
|
556
|
+
"--all",
|
|
557
|
+
"--apparent-size",
|
|
558
|
+
"--bytes",
|
|
559
|
+
"--total",
|
|
560
|
+
"--dereference-args",
|
|
561
|
+
"--human-readable",
|
|
562
|
+
"--si",
|
|
563
|
+
"--inodes",
|
|
564
|
+
"--count-links",
|
|
565
|
+
"--dereference",
|
|
566
|
+
"--no-dereference",
|
|
567
|
+
"--separate-dirs",
|
|
568
|
+
"--summarize",
|
|
569
|
+
"--one-file-system",
|
|
570
|
+
"--null"
|
|
571
|
+
],
|
|
572
|
+
values: [
|
|
573
|
+
"-d",
|
|
574
|
+
"-t",
|
|
575
|
+
"-B",
|
|
576
|
+
"-X",
|
|
577
|
+
"--max-depth",
|
|
578
|
+
"--threshold",
|
|
579
|
+
"--block-size",
|
|
580
|
+
"--exclude",
|
|
581
|
+
"--exclude-from",
|
|
582
|
+
"--time",
|
|
583
|
+
"--time-style",
|
|
584
|
+
"--files0-from"
|
|
585
|
+
]
|
|
586
|
+
},
|
|
587
|
+
df: {
|
|
588
|
+
cluster: true,
|
|
589
|
+
booleans: [
|
|
590
|
+
"-a",
|
|
591
|
+
"-h",
|
|
592
|
+
"-H",
|
|
593
|
+
"-i",
|
|
594
|
+
"-k",
|
|
595
|
+
"-l",
|
|
596
|
+
"-m",
|
|
597
|
+
"-P",
|
|
598
|
+
"-T",
|
|
599
|
+
"-v",
|
|
600
|
+
"--all",
|
|
601
|
+
"--human-readable",
|
|
602
|
+
"--si",
|
|
603
|
+
"--inodes",
|
|
604
|
+
"--local",
|
|
605
|
+
"--portability",
|
|
606
|
+
"--print-type",
|
|
607
|
+
"--total",
|
|
608
|
+
"--sync",
|
|
609
|
+
"--no-sync"
|
|
610
|
+
],
|
|
611
|
+
values: ["-B", "-t", "-x", "--block-size", "--type", "--exclude-type"]
|
|
612
|
+
},
|
|
613
|
+
file: {
|
|
614
|
+
cluster: true,
|
|
615
|
+
// `-C`/`--compile` is absent: it writes a compiled magic file.
|
|
616
|
+
booleans: [
|
|
617
|
+
"-b",
|
|
618
|
+
"-c",
|
|
619
|
+
"-h",
|
|
620
|
+
"-i",
|
|
621
|
+
"-k",
|
|
622
|
+
"-L",
|
|
623
|
+
"-n",
|
|
624
|
+
"-N",
|
|
625
|
+
"-p",
|
|
626
|
+
"-r",
|
|
627
|
+
"-s",
|
|
628
|
+
"-S",
|
|
629
|
+
"-v",
|
|
630
|
+
"-z",
|
|
631
|
+
"-0",
|
|
632
|
+
"--brief",
|
|
633
|
+
"--mime",
|
|
634
|
+
"--mime-type",
|
|
635
|
+
"--mime-encoding",
|
|
636
|
+
"--dereference",
|
|
637
|
+
"--no-dereference",
|
|
638
|
+
"--keep-going",
|
|
639
|
+
"--no-buffer",
|
|
640
|
+
"--no-pad",
|
|
641
|
+
"--raw",
|
|
642
|
+
"--special-files",
|
|
643
|
+
"--uncompress",
|
|
644
|
+
"--print0",
|
|
645
|
+
"--checking-printout"
|
|
646
|
+
],
|
|
647
|
+
values: [
|
|
648
|
+
"-e",
|
|
649
|
+
"-m",
|
|
650
|
+
"-P",
|
|
651
|
+
"-F",
|
|
652
|
+
"--exclude",
|
|
653
|
+
"--magic-file",
|
|
654
|
+
"--separator",
|
|
655
|
+
"--parameter",
|
|
656
|
+
"--extension",
|
|
657
|
+
"--files-from"
|
|
658
|
+
]
|
|
659
|
+
},
|
|
660
|
+
head: {
|
|
661
|
+
cluster: true,
|
|
662
|
+
booleans: ["-q", "-v", "-z", "--quiet", "--silent", "--verbose", "--zero-terminated"],
|
|
663
|
+
values: ["-c", "-n", "--bytes", "--lines"],
|
|
664
|
+
patterns: [COUNT_FLAG]
|
|
665
|
+
},
|
|
666
|
+
tail: {
|
|
667
|
+
cluster: true,
|
|
668
|
+
booleans: [
|
|
669
|
+
"-f",
|
|
670
|
+
"-F",
|
|
671
|
+
"-q",
|
|
672
|
+
"-v",
|
|
673
|
+
"-z",
|
|
674
|
+
"--follow",
|
|
675
|
+
"--retry",
|
|
676
|
+
"--quiet",
|
|
677
|
+
"--silent",
|
|
678
|
+
"--verbose",
|
|
679
|
+
"--zero-terminated"
|
|
680
|
+
],
|
|
681
|
+
values: [
|
|
682
|
+
"-c",
|
|
683
|
+
"-n",
|
|
684
|
+
"-s",
|
|
685
|
+
"--bytes",
|
|
686
|
+
"--lines",
|
|
687
|
+
"--sleep-interval",
|
|
688
|
+
"--pid",
|
|
689
|
+
"--max-unchanged-stats"
|
|
690
|
+
],
|
|
691
|
+
patterns: [COUNT_FLAG]
|
|
692
|
+
},
|
|
693
|
+
cat: {
|
|
694
|
+
cluster: true,
|
|
695
|
+
booleans: [
|
|
696
|
+
"-A",
|
|
697
|
+
"-b",
|
|
698
|
+
"-e",
|
|
699
|
+
"-E",
|
|
700
|
+
"-n",
|
|
701
|
+
"-s",
|
|
702
|
+
"-t",
|
|
703
|
+
"-T",
|
|
704
|
+
"-u",
|
|
705
|
+
"-v",
|
|
706
|
+
"--show-all",
|
|
707
|
+
"--number-nonblank",
|
|
708
|
+
"--show-ends",
|
|
709
|
+
"--number",
|
|
710
|
+
"--squeeze-blank",
|
|
711
|
+
"--show-tabs",
|
|
712
|
+
"--show-nonprinting"
|
|
713
|
+
]
|
|
714
|
+
},
|
|
715
|
+
sort: {
|
|
716
|
+
cluster: true,
|
|
717
|
+
// Absent on purpose: `-o`/`--output` writes a file with no redirect for the
|
|
718
|
+
// redirect check to see, and `--compress-program` names a program that sort
|
|
719
|
+
// runs over its own temporary files — a permitted binary as an interpreter.
|
|
720
|
+
booleans: [
|
|
721
|
+
"-b",
|
|
722
|
+
"-c",
|
|
723
|
+
"-C",
|
|
724
|
+
"-d",
|
|
725
|
+
"-f",
|
|
726
|
+
"-g",
|
|
727
|
+
"-h",
|
|
728
|
+
"-i",
|
|
729
|
+
"-M",
|
|
730
|
+
"-n",
|
|
731
|
+
"-r",
|
|
732
|
+
"-R",
|
|
733
|
+
"-s",
|
|
734
|
+
"-u",
|
|
735
|
+
"-V",
|
|
736
|
+
"-z",
|
|
737
|
+
"--ignore-leading-blanks",
|
|
738
|
+
"--check",
|
|
739
|
+
"--dictionary-order",
|
|
740
|
+
"--ignore-case",
|
|
741
|
+
"--general-numeric-sort",
|
|
742
|
+
"--human-numeric-sort",
|
|
743
|
+
"--ignore-nonprinting",
|
|
744
|
+
"--month-sort",
|
|
745
|
+
"--numeric-sort",
|
|
746
|
+
"--random-sort",
|
|
747
|
+
"--reverse",
|
|
748
|
+
"--stable",
|
|
749
|
+
"--unique",
|
|
750
|
+
"--version-sort",
|
|
751
|
+
"--zero-terminated",
|
|
752
|
+
"--debug"
|
|
753
|
+
],
|
|
754
|
+
values: [
|
|
755
|
+
"-k",
|
|
756
|
+
"-t",
|
|
757
|
+
"-S",
|
|
758
|
+
"-T",
|
|
759
|
+
"--key",
|
|
760
|
+
"--field-separator",
|
|
761
|
+
"--buffer-size",
|
|
762
|
+
"--temporary-directory",
|
|
763
|
+
"--random-source",
|
|
764
|
+
"--batch-size",
|
|
765
|
+
"--parallel",
|
|
766
|
+
"--sort"
|
|
767
|
+
]
|
|
768
|
+
},
|
|
769
|
+
uniq: {
|
|
770
|
+
cluster: true,
|
|
771
|
+
booleans: [
|
|
772
|
+
"-c",
|
|
773
|
+
"-d",
|
|
774
|
+
"-D",
|
|
775
|
+
"-i",
|
|
776
|
+
"-u",
|
|
777
|
+
"-z",
|
|
778
|
+
"--count",
|
|
779
|
+
"--repeated",
|
|
780
|
+
"--all-repeated",
|
|
781
|
+
"--ignore-case",
|
|
782
|
+
"--unique",
|
|
783
|
+
"--zero-terminated"
|
|
784
|
+
],
|
|
785
|
+
values: ["-f", "-s", "-w", "--skip-fields", "--skip-chars", "--check-chars", "--group"]
|
|
786
|
+
},
|
|
787
|
+
// No flag on either runs a program or writes a file, and the planner's
|
|
788
|
+
// commonest use of `echo` is a section marker — `echo --- files changed ---`
|
|
789
|
+
// is three tokens that all begin with a dash and none of them is a flag.
|
|
790
|
+
echo: { freeform: true },
|
|
791
|
+
printf: { freeform: true },
|
|
792
|
+
date: {
|
|
793
|
+
cluster: true,
|
|
794
|
+
// `-s`/`--set` is absent: it sets the system clock.
|
|
795
|
+
booleans: [
|
|
796
|
+
"-u",
|
|
797
|
+
"-R",
|
|
798
|
+
"-I",
|
|
799
|
+
"--utc",
|
|
800
|
+
"--universal",
|
|
801
|
+
"--rfc-email",
|
|
802
|
+
"--rfc-3339",
|
|
803
|
+
"--iso-8601",
|
|
804
|
+
"--debug"
|
|
805
|
+
],
|
|
806
|
+
values: ["-d", "-f", "-r", "--date", "--file", "--reference"]
|
|
807
|
+
},
|
|
808
|
+
stat: {
|
|
809
|
+
cluster: true,
|
|
810
|
+
booleans: ["-f", "-L", "-t", "--file-system", "--terse", "--dereference"],
|
|
811
|
+
values: ["-c", "--format", "--printf", "--cached"]
|
|
812
|
+
},
|
|
813
|
+
basename: {
|
|
814
|
+
cluster: true,
|
|
815
|
+
booleans: ["-a", "-z", "--multiple", "--zero"],
|
|
816
|
+
values: ["-s", "--suffix"]
|
|
817
|
+
},
|
|
818
|
+
dirname: {
|
|
819
|
+
cluster: true,
|
|
820
|
+
booleans: ["-z", "--zero"]
|
|
821
|
+
},
|
|
822
|
+
realpath: {
|
|
823
|
+
cluster: true,
|
|
824
|
+
booleans: [
|
|
825
|
+
"-e",
|
|
826
|
+
"-m",
|
|
827
|
+
"-L",
|
|
828
|
+
"-P",
|
|
829
|
+
"-q",
|
|
830
|
+
"-s",
|
|
831
|
+
"-z",
|
|
832
|
+
"--canonicalize-existing",
|
|
833
|
+
"--canonicalize-missing",
|
|
834
|
+
"--logical",
|
|
835
|
+
"--physical",
|
|
836
|
+
"--quiet",
|
|
837
|
+
"--strip",
|
|
838
|
+
"--no-symlinks",
|
|
839
|
+
"--zero"
|
|
840
|
+
],
|
|
841
|
+
values: ["--relative-to", "--relative-base"]
|
|
842
|
+
},
|
|
843
|
+
pwd: { cluster: true, booleans: ["-L", "-P", "--logical", "--physical"] },
|
|
844
|
+
which: { cluster: true, booleans: ["-a", "-s", "--all"] },
|
|
845
|
+
type: { cluster: true, booleans: ["-a", "-f", "-p", "-P", "-t"] },
|
|
846
|
+
uname: {
|
|
847
|
+
cluster: true,
|
|
848
|
+
booleans: [
|
|
849
|
+
"-a",
|
|
850
|
+
"-i",
|
|
851
|
+
"-m",
|
|
852
|
+
"-n",
|
|
853
|
+
"-o",
|
|
854
|
+
"-p",
|
|
855
|
+
"-r",
|
|
856
|
+
"-s",
|
|
857
|
+
"-v",
|
|
858
|
+
"--all",
|
|
859
|
+
"--kernel-name",
|
|
860
|
+
"--nodename",
|
|
861
|
+
"--kernel-release",
|
|
862
|
+
"--kernel-version",
|
|
863
|
+
"--machine",
|
|
864
|
+
"--processor",
|
|
865
|
+
"--hardware-platform",
|
|
866
|
+
"--operating-system"
|
|
867
|
+
]
|
|
868
|
+
},
|
|
869
|
+
whoami: {},
|
|
870
|
+
cut: {
|
|
871
|
+
cluster: true,
|
|
872
|
+
// `--output-delimiter` names a separator string, not a file.
|
|
873
|
+
booleans: ["-n", "-s", "-z", "--only-delimited", "--complement", "--zero-terminated"],
|
|
874
|
+
values: [
|
|
875
|
+
"-b",
|
|
876
|
+
"-c",
|
|
877
|
+
"-d",
|
|
878
|
+
"-f",
|
|
879
|
+
"--bytes",
|
|
880
|
+
"--characters",
|
|
881
|
+
"--delimiter",
|
|
882
|
+
"--fields",
|
|
883
|
+
"--output-delimiter"
|
|
884
|
+
]
|
|
885
|
+
},
|
|
886
|
+
nl: {
|
|
887
|
+
cluster: true,
|
|
888
|
+
booleans: ["-p", "--no-renumber"],
|
|
889
|
+
values: [
|
|
890
|
+
"-b",
|
|
891
|
+
"-d",
|
|
892
|
+
"-f",
|
|
893
|
+
"-h",
|
|
894
|
+
"-i",
|
|
895
|
+
"-l",
|
|
896
|
+
"-n",
|
|
897
|
+
"-s",
|
|
898
|
+
"-v",
|
|
899
|
+
"-w",
|
|
900
|
+
"--body-numbering",
|
|
901
|
+
"--section-delimiter",
|
|
902
|
+
"--footer-numbering",
|
|
903
|
+
"--header-numbering",
|
|
904
|
+
"--join-blank-lines",
|
|
905
|
+
"--line-increment",
|
|
906
|
+
"--number-format",
|
|
907
|
+
"--number-separator",
|
|
908
|
+
"--starting-line-number",
|
|
909
|
+
"--number-width"
|
|
910
|
+
]
|
|
911
|
+
},
|
|
912
|
+
rg: {
|
|
913
|
+
cluster: true,
|
|
914
|
+
// `--pre` runs a named preprocessor over every file searched and
|
|
915
|
+
// `--hostname-bin` runs a named program to resolve the hostname; both are
|
|
916
|
+
// absent, and `--pre-glob` with them.
|
|
917
|
+
booleans: [
|
|
918
|
+
"-a",
|
|
919
|
+
"-c",
|
|
920
|
+
"-F",
|
|
921
|
+
"-h",
|
|
922
|
+
"-H",
|
|
923
|
+
"-i",
|
|
924
|
+
"-I",
|
|
925
|
+
"-l",
|
|
926
|
+
"-L",
|
|
927
|
+
"-n",
|
|
928
|
+
"-N",
|
|
929
|
+
"-o",
|
|
930
|
+
"-p",
|
|
931
|
+
"-P",
|
|
932
|
+
"-q",
|
|
933
|
+
"-s",
|
|
934
|
+
"-S",
|
|
935
|
+
"-u",
|
|
936
|
+
"-uu",
|
|
937
|
+
"-uuu",
|
|
938
|
+
"-U",
|
|
939
|
+
"-v",
|
|
940
|
+
"-V",
|
|
941
|
+
"-w",
|
|
942
|
+
"-x",
|
|
943
|
+
"-z",
|
|
944
|
+
"--text",
|
|
945
|
+
"--count",
|
|
946
|
+
"--count-matches",
|
|
947
|
+
"--fixed-strings",
|
|
948
|
+
"--files",
|
|
949
|
+
"--files-with-matches",
|
|
950
|
+
"--files-without-match",
|
|
951
|
+
"--follow",
|
|
952
|
+
"--hidden",
|
|
953
|
+
"--no-hidden",
|
|
954
|
+
"--ignore-case",
|
|
955
|
+
"--case-sensitive",
|
|
956
|
+
"--smart-case",
|
|
957
|
+
"--invert-match",
|
|
958
|
+
"--line-number",
|
|
959
|
+
"--no-line-number",
|
|
960
|
+
"--with-filename",
|
|
961
|
+
"--no-filename",
|
|
962
|
+
"--heading",
|
|
963
|
+
"--no-heading",
|
|
964
|
+
"--column",
|
|
965
|
+
"--no-column",
|
|
966
|
+
"--byte-offset",
|
|
967
|
+
"--vimgrep",
|
|
968
|
+
"--json",
|
|
969
|
+
"--stats",
|
|
970
|
+
"--trim",
|
|
971
|
+
"--pretty",
|
|
972
|
+
"--passthru",
|
|
973
|
+
"--word-regexp",
|
|
974
|
+
"--line-regexp",
|
|
975
|
+
"--multiline",
|
|
976
|
+
"--multiline-dotall",
|
|
977
|
+
"--no-multiline",
|
|
978
|
+
"--crlf",
|
|
979
|
+
"--null",
|
|
980
|
+
"--null-data",
|
|
981
|
+
"--binary",
|
|
982
|
+
"--search-zip",
|
|
983
|
+
"--no-ignore",
|
|
984
|
+
"--no-ignore-dot",
|
|
985
|
+
"--no-ignore-exclude",
|
|
986
|
+
"--no-ignore-files",
|
|
987
|
+
"--no-ignore-global",
|
|
988
|
+
"--no-ignore-parent",
|
|
989
|
+
"--no-ignore-vcs",
|
|
990
|
+
"--no-ignore-messages",
|
|
991
|
+
"--no-messages",
|
|
992
|
+
"--no-require-git",
|
|
993
|
+
"--require-git",
|
|
994
|
+
"--one-file-system",
|
|
995
|
+
"--pcre2",
|
|
996
|
+
"--no-pcre2",
|
|
997
|
+
"--auto-hybrid-regex",
|
|
998
|
+
"--line-buffered",
|
|
999
|
+
"--block-buffered",
|
|
1000
|
+
"--unicode",
|
|
1001
|
+
"--no-unicode",
|
|
1002
|
+
"--unrestricted",
|
|
1003
|
+
"--type-list",
|
|
1004
|
+
"--debug",
|
|
1005
|
+
"--trace",
|
|
1006
|
+
"--include-zero",
|
|
1007
|
+
"--no-context-separator",
|
|
1008
|
+
"--stop-on-nonmatch",
|
|
1009
|
+
"--quiet",
|
|
1010
|
+
"--no-binary"
|
|
1011
|
+
],
|
|
1012
|
+
values: [
|
|
1013
|
+
"-A",
|
|
1014
|
+
"-B",
|
|
1015
|
+
"-C",
|
|
1016
|
+
"-d",
|
|
1017
|
+
"-e",
|
|
1018
|
+
"-E",
|
|
1019
|
+
"-f",
|
|
1020
|
+
"-g",
|
|
1021
|
+
"-j",
|
|
1022
|
+
"-m",
|
|
1023
|
+
"-M",
|
|
1024
|
+
"-r",
|
|
1025
|
+
"-t",
|
|
1026
|
+
"-T",
|
|
1027
|
+
"--after-context",
|
|
1028
|
+
"--before-context",
|
|
1029
|
+
"--context",
|
|
1030
|
+
"--context-separator",
|
|
1031
|
+
"--field-context-separator",
|
|
1032
|
+
"--field-match-separator",
|
|
1033
|
+
"--regexp",
|
|
1034
|
+
"--file",
|
|
1035
|
+
"--glob",
|
|
1036
|
+
"--iglob",
|
|
1037
|
+
"--glob-case-insensitive",
|
|
1038
|
+
"--type",
|
|
1039
|
+
"--type-not",
|
|
1040
|
+
"--type-add",
|
|
1041
|
+
"--type-clear",
|
|
1042
|
+
"--max-count",
|
|
1043
|
+
"--max-columns",
|
|
1044
|
+
"--max-depth",
|
|
1045
|
+
"--maxdepth",
|
|
1046
|
+
"--max-filesize",
|
|
1047
|
+
"--replace",
|
|
1048
|
+
"--threads",
|
|
1049
|
+
"--encoding",
|
|
1050
|
+
"--engine",
|
|
1051
|
+
"--sort",
|
|
1052
|
+
"--sortr",
|
|
1053
|
+
"--color",
|
|
1054
|
+
"--colors",
|
|
1055
|
+
"--path-separator",
|
|
1056
|
+
"--ignore-file",
|
|
1057
|
+
"--dfa-size-limit",
|
|
1058
|
+
"--regex-size-limit",
|
|
1059
|
+
"--binary-files",
|
|
1060
|
+
"--max-columns-preview"
|
|
1061
|
+
]
|
|
1062
|
+
},
|
|
1063
|
+
grep: {
|
|
1064
|
+
cluster: true,
|
|
1065
|
+
// `-o` here is `--only-matching`, which writes nothing. It is the same two
|
|
1066
|
+
// characters as `sort -o`, which writes a file — the reason these sets are
|
|
1067
|
+
// per-binary rather than one shared list.
|
|
1068
|
+
booleans: [
|
|
1069
|
+
"-a",
|
|
1070
|
+
"-b",
|
|
1071
|
+
"-c",
|
|
1072
|
+
"-E",
|
|
1073
|
+
"-F",
|
|
1074
|
+
"-G",
|
|
1075
|
+
"-H",
|
|
1076
|
+
"-h",
|
|
1077
|
+
"-i",
|
|
1078
|
+
"-I",
|
|
1079
|
+
"-l",
|
|
1080
|
+
"-L",
|
|
1081
|
+
"-n",
|
|
1082
|
+
"-o",
|
|
1083
|
+
"-P",
|
|
1084
|
+
"-q",
|
|
1085
|
+
"-r",
|
|
1086
|
+
"-R",
|
|
1087
|
+
"-s",
|
|
1088
|
+
"-T",
|
|
1089
|
+
"-U",
|
|
1090
|
+
"-v",
|
|
1091
|
+
"-w",
|
|
1092
|
+
"-x",
|
|
1093
|
+
"-y",
|
|
1094
|
+
"-z",
|
|
1095
|
+
"-Z",
|
|
1096
|
+
"--extended-regexp",
|
|
1097
|
+
"--fixed-strings",
|
|
1098
|
+
"--basic-regexp",
|
|
1099
|
+
"--perl-regexp",
|
|
1100
|
+
"--ignore-case",
|
|
1101
|
+
"--no-ignore-case",
|
|
1102
|
+
"--invert-match",
|
|
1103
|
+
"--word-regexp",
|
|
1104
|
+
"--line-regexp",
|
|
1105
|
+
"--count",
|
|
1106
|
+
"--files-with-matches",
|
|
1107
|
+
"--files-without-match",
|
|
1108
|
+
"--line-number",
|
|
1109
|
+
"--with-filename",
|
|
1110
|
+
"--no-filename",
|
|
1111
|
+
"--only-matching",
|
|
1112
|
+
"--quiet",
|
|
1113
|
+
"--silent",
|
|
1114
|
+
"--no-messages",
|
|
1115
|
+
"--text",
|
|
1116
|
+
"--binary",
|
|
1117
|
+
"--line-buffered",
|
|
1118
|
+
"--null",
|
|
1119
|
+
"--null-data",
|
|
1120
|
+
"--byte-offset",
|
|
1121
|
+
"--recursive",
|
|
1122
|
+
"--dereference-recursive",
|
|
1123
|
+
"--initial-tab",
|
|
1124
|
+
"--unix-byte-offsets",
|
|
1125
|
+
"--no-group-separator",
|
|
1126
|
+
"--color",
|
|
1127
|
+
"--colour"
|
|
1128
|
+
],
|
|
1129
|
+
values: [
|
|
1130
|
+
"-A",
|
|
1131
|
+
"-B",
|
|
1132
|
+
"-C",
|
|
1133
|
+
"-d",
|
|
1134
|
+
"-D",
|
|
1135
|
+
"-e",
|
|
1136
|
+
"-f",
|
|
1137
|
+
"-m",
|
|
1138
|
+
"--after-context",
|
|
1139
|
+
"--before-context",
|
|
1140
|
+
"--context",
|
|
1141
|
+
"--regexp",
|
|
1142
|
+
"--file",
|
|
1143
|
+
"--max-count",
|
|
1144
|
+
"--devices",
|
|
1145
|
+
"--directories",
|
|
1146
|
+
"--binary-files",
|
|
1147
|
+
"--include",
|
|
1148
|
+
"--exclude",
|
|
1149
|
+
"--exclude-dir",
|
|
1150
|
+
"--exclude-from",
|
|
1151
|
+
"--label",
|
|
1152
|
+
"--group-separator"
|
|
1153
|
+
]
|
|
1154
|
+
},
|
|
1155
|
+
find: {
|
|
1156
|
+
// No clustering: find spells its flags as single-dash words, so walking the
|
|
1157
|
+
// characters of `-name` would read it as five short flags. And its arguments
|
|
1158
|
+
// are an expression, so `--` does not end them.
|
|
1159
|
+
expressionArgs: true,
|
|
1160
|
+
// Absent on purpose: `-exec`, `-execdir`, `-ok` and `-okdir` run an inner
|
|
1161
|
+
// command (also caught by the named guard below, which says so more
|
|
1162
|
+
// precisely), `-delete` removes files, and `-fprint`, `-fprint0`, `-fprintf`
|
|
1163
|
+
// and `-fls` are find's write family — the same write as `> file` with no
|
|
1164
|
+
// redirect for the redirect check to see.
|
|
1165
|
+
booleans: [
|
|
1166
|
+
"-H",
|
|
1167
|
+
"-L",
|
|
1168
|
+
"-P",
|
|
1169
|
+
"-a",
|
|
1170
|
+
"-and",
|
|
1171
|
+
"-o",
|
|
1172
|
+
"-or",
|
|
1173
|
+
"-not",
|
|
1174
|
+
"-d",
|
|
1175
|
+
"-depth",
|
|
1176
|
+
"-daystart",
|
|
1177
|
+
"-empty",
|
|
1178
|
+
"-executable",
|
|
1179
|
+
"-false",
|
|
1180
|
+
"-follow",
|
|
1181
|
+
"-help",
|
|
1182
|
+
"--help",
|
|
1183
|
+
"-ignore_readdir_race",
|
|
1184
|
+
"-noignore_readdir_race",
|
|
1185
|
+
"-ls",
|
|
1186
|
+
"-mount",
|
|
1187
|
+
"-nogroup",
|
|
1188
|
+
"-noleaf",
|
|
1189
|
+
"-nouser",
|
|
1190
|
+
"-print",
|
|
1191
|
+
"-print0",
|
|
1192
|
+
"-prune",
|
|
1193
|
+
"-quit",
|
|
1194
|
+
"-readable",
|
|
1195
|
+
"-true",
|
|
1196
|
+
"-version",
|
|
1197
|
+
"-writable",
|
|
1198
|
+
"-xdev"
|
|
1199
|
+
],
|
|
1200
|
+
values: [
|
|
1201
|
+
"-maxdepth",
|
|
1202
|
+
"-mindepth",
|
|
1203
|
+
"-name",
|
|
1204
|
+
"-iname",
|
|
1205
|
+
"-path",
|
|
1206
|
+
"-ipath",
|
|
1207
|
+
"-wholename",
|
|
1208
|
+
"-iwholename",
|
|
1209
|
+
"-regex",
|
|
1210
|
+
"-iregex",
|
|
1211
|
+
"-lname",
|
|
1212
|
+
"-ilname",
|
|
1213
|
+
"-type",
|
|
1214
|
+
"-xtype",
|
|
1215
|
+
"-size",
|
|
1216
|
+
"-newer",
|
|
1217
|
+
"-anewer",
|
|
1218
|
+
"-cnewer",
|
|
1219
|
+
"-mtime",
|
|
1220
|
+
"-mmin",
|
|
1221
|
+
"-ctime",
|
|
1222
|
+
"-cmin",
|
|
1223
|
+
"-atime",
|
|
1224
|
+
"-amin",
|
|
1225
|
+
"-used",
|
|
1226
|
+
"-uid",
|
|
1227
|
+
"-gid",
|
|
1228
|
+
"-user",
|
|
1229
|
+
"-group",
|
|
1230
|
+
"-perm",
|
|
1231
|
+
"-links",
|
|
1232
|
+
"-inum",
|
|
1233
|
+
"-samefile",
|
|
1234
|
+
"-fstype",
|
|
1235
|
+
"-regextype",
|
|
1236
|
+
"-files0-from",
|
|
1237
|
+
"-printf",
|
|
1238
|
+
"-context",
|
|
1239
|
+
"-D"
|
|
1240
|
+
],
|
|
1241
|
+
// `find -O2` glues the optimisation level on, and `-newermt`/`-newerat` and
|
|
1242
|
+
// friends spell the two comparison fields into the flag name.
|
|
1243
|
+
patterns: [/^-O\d$/, /^-newer[acmBt][acmBt]$/]
|
|
1244
|
+
},
|
|
1245
|
+
jq: {
|
|
1246
|
+
cluster: true,
|
|
1247
|
+
booleans: [
|
|
1248
|
+
"-a",
|
|
1249
|
+
"-c",
|
|
1250
|
+
"-C",
|
|
1251
|
+
"-e",
|
|
1252
|
+
"-h",
|
|
1253
|
+
"-j",
|
|
1254
|
+
"-M",
|
|
1255
|
+
"-n",
|
|
1256
|
+
"-r",
|
|
1257
|
+
"-R",
|
|
1258
|
+
"-s",
|
|
1259
|
+
"-S",
|
|
1260
|
+
"--ascii-output",
|
|
1261
|
+
"--compact-output",
|
|
1262
|
+
"--color-output",
|
|
1263
|
+
"--monochrome-output",
|
|
1264
|
+
"--exit-status",
|
|
1265
|
+
"--join-output",
|
|
1266
|
+
"--null-input",
|
|
1267
|
+
"--raw-input",
|
|
1268
|
+
"--raw-output",
|
|
1269
|
+
"--raw-output0",
|
|
1270
|
+
"--slurp",
|
|
1271
|
+
"--sort-keys",
|
|
1272
|
+
"--seq",
|
|
1273
|
+
"--stream",
|
|
1274
|
+
"--stream-errors",
|
|
1275
|
+
"--tab",
|
|
1276
|
+
"--unbuffered",
|
|
1277
|
+
"--args",
|
|
1278
|
+
"--jsonargs"
|
|
1279
|
+
],
|
|
1280
|
+
values: [
|
|
1281
|
+
"-f",
|
|
1282
|
+
"-L",
|
|
1283
|
+
"--arg",
|
|
1284
|
+
"--argjson",
|
|
1285
|
+
"--slurpfile",
|
|
1286
|
+
"--rawfile",
|
|
1287
|
+
"--indent",
|
|
1288
|
+
"--from-file"
|
|
1289
|
+
]
|
|
1290
|
+
},
|
|
1291
|
+
yq: {
|
|
1292
|
+
cluster: true,
|
|
1293
|
+
// `-i`/`--inplace`/`--in-place` rewrite the file, and `-s`/`--split-exp`
|
|
1294
|
+
// writes one file per document. All absent — and all bare or near-bare
|
|
1295
|
+
// booleans, which is why exempting booleans was not an option.
|
|
1296
|
+
booleans: [
|
|
1297
|
+
"-C",
|
|
1298
|
+
"-e",
|
|
1299
|
+
"-h",
|
|
1300
|
+
"-j",
|
|
1301
|
+
"-M",
|
|
1302
|
+
"-n",
|
|
1303
|
+
"-N",
|
|
1304
|
+
"-P",
|
|
1305
|
+
"-r",
|
|
1306
|
+
"-S",
|
|
1307
|
+
"-v",
|
|
1308
|
+
"-y",
|
|
1309
|
+
"-Y",
|
|
1310
|
+
"--colors",
|
|
1311
|
+
"--no-colors",
|
|
1312
|
+
"--exit-status",
|
|
1313
|
+
"--no-doc",
|
|
1314
|
+
"--null-input",
|
|
1315
|
+
"--prettyPrint",
|
|
1316
|
+
"--raw-output",
|
|
1317
|
+
"--sort-keys",
|
|
1318
|
+
"--tojson",
|
|
1319
|
+
"--yaml-output",
|
|
1320
|
+
"--yaml-roundtrip",
|
|
1321
|
+
"--unwrapScalar",
|
|
1322
|
+
"--header-preprocess",
|
|
1323
|
+
"--no-exit-status",
|
|
1324
|
+
"--verbose",
|
|
1325
|
+
"--xml-strict-mode"
|
|
1326
|
+
],
|
|
1327
|
+
values: [
|
|
1328
|
+
"-I",
|
|
1329
|
+
"-o",
|
|
1330
|
+
"-p",
|
|
1331
|
+
"-L",
|
|
1332
|
+
"--indent",
|
|
1333
|
+
"--output-format",
|
|
1334
|
+
"--input-format",
|
|
1335
|
+
"--expression",
|
|
1336
|
+
"--width",
|
|
1337
|
+
"--xml-attribute-prefix",
|
|
1338
|
+
"--xml-content-name"
|
|
1339
|
+
]
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
122
1342
|
var GIT_READONLY_SUBCOMMANDS = [
|
|
123
1343
|
"log",
|
|
124
1344
|
"status",
|
|
125
1345
|
"diff",
|
|
126
1346
|
"show",
|
|
127
1347
|
"ls-files",
|
|
128
|
-
"ls-remote",
|
|
129
1348
|
"ls-tree",
|
|
130
1349
|
"branch",
|
|
131
1350
|
"tag",
|
|
@@ -240,6 +1459,26 @@ var REFUSED_SUBCOMMANDS = {
|
|
|
240
1459
|
az: ["login", "logout"],
|
|
241
1460
|
terraform: ["apply", "destroy"]
|
|
242
1461
|
};
|
|
1462
|
+
var SHELL_KEYWORDS = [
|
|
1463
|
+
"{",
|
|
1464
|
+
"}",
|
|
1465
|
+
"if",
|
|
1466
|
+
"then",
|
|
1467
|
+
"elif",
|
|
1468
|
+
"else",
|
|
1469
|
+
"fi",
|
|
1470
|
+
"for",
|
|
1471
|
+
"while",
|
|
1472
|
+
"until",
|
|
1473
|
+
"do",
|
|
1474
|
+
"done",
|
|
1475
|
+
"case",
|
|
1476
|
+
"esac",
|
|
1477
|
+
"select",
|
|
1478
|
+
"function",
|
|
1479
|
+
"time",
|
|
1480
|
+
"export"
|
|
1481
|
+
];
|
|
243
1482
|
var INTERPRETERS = [
|
|
244
1483
|
"sh",
|
|
245
1484
|
"bash",
|
|
@@ -309,6 +1548,52 @@ var MULTIPLEXERS = [
|
|
|
309
1548
|
"flutter",
|
|
310
1549
|
"dart"
|
|
311
1550
|
];
|
|
1551
|
+
var HELP_FLAGS = ["--help", "--version"];
|
|
1552
|
+
var WRAPPER_FAMILY = {
|
|
1553
|
+
env: {
|
|
1554
|
+
valueFlags: ["-u", "--unset", "-C", "--chdir"],
|
|
1555
|
+
booleanFlags: [
|
|
1556
|
+
"-i",
|
|
1557
|
+
"--ignore-environment",
|
|
1558
|
+
"-0",
|
|
1559
|
+
"--null",
|
|
1560
|
+
"-v",
|
|
1561
|
+
"--debug",
|
|
1562
|
+
// Optional-value flags: see WrapperSpec.booleanFlags.
|
|
1563
|
+
"--block-signal",
|
|
1564
|
+
"--default-signal",
|
|
1565
|
+
"--ignore-signal",
|
|
1566
|
+
"--list-signal-handling",
|
|
1567
|
+
...HELP_FLAGS
|
|
1568
|
+
],
|
|
1569
|
+
stringFlags: ["-S", "--split-string"],
|
|
1570
|
+
acceptsAssignments: true
|
|
1571
|
+
},
|
|
1572
|
+
nice: {
|
|
1573
|
+
valueFlags: ["-n", "--adjustment"],
|
|
1574
|
+
booleanFlags: HELP_FLAGS,
|
|
1575
|
+
booleanPattern: /^-\d+$/
|
|
1576
|
+
},
|
|
1577
|
+
timeout: {
|
|
1578
|
+
valueFlags: ["-s", "--signal", "-k", "--kill-after"],
|
|
1579
|
+
booleanFlags: ["--preserve-status", "--foreground", "-v", "--verbose", ...HELP_FLAGS],
|
|
1580
|
+
positionals: 1
|
|
1581
|
+
},
|
|
1582
|
+
nohup: { booleanFlags: HELP_FLAGS },
|
|
1583
|
+
setsid: { booleanFlags: ["-c", "--ctty", "-f", "--fork", "-w", "--wait", "-h", "-V", ...HELP_FLAGS] },
|
|
1584
|
+
stdbuf: {
|
|
1585
|
+
valueFlags: ["-i", "--input", "-o", "--output", "-e", "--error"],
|
|
1586
|
+
booleanFlags: HELP_FLAGS
|
|
1587
|
+
},
|
|
1588
|
+
ionice: {
|
|
1589
|
+
valueFlags: ["-c", "--class", "-n", "--classdata", "-p", "--pid", "-P", "--pgid", "-u", "--uid"],
|
|
1590
|
+
booleanFlags: ["-t", "--ignore", "-h", "-V", ...HELP_FLAGS]
|
|
1591
|
+
},
|
|
1592
|
+
// The multi-call binary ships its own `rm`, `mv` and `sh`, so the refused
|
|
1593
|
+
// name arrives as its first argument.
|
|
1594
|
+
busybox: { booleanFlags: ["--list", "--install", ...HELP_FLAGS] },
|
|
1595
|
+
command: { booleanFlags: ["-p"], noExecFlags: ["-v", "-V"] }
|
|
1596
|
+
};
|
|
312
1597
|
var POSIX_DIALECT = {
|
|
313
1598
|
escape: "\\",
|
|
314
1599
|
escapeInQuotes: true,
|
|
@@ -523,10 +1808,92 @@ function binaryName(token, dialect) {
|
|
|
523
1808
|
if (dot <= 0) return base;
|
|
524
1809
|
return dialect.strippedExtensions.includes(base.slice(dot).toLowerCase()) ? base.slice(0, dot) : base;
|
|
525
1810
|
}
|
|
1811
|
+
var ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
526
1812
|
function toSegment(tokens, piped, dialect) {
|
|
527
1813
|
const rest = [...tokens];
|
|
528
|
-
|
|
529
|
-
|
|
1814
|
+
const assignments = [];
|
|
1815
|
+
while (rest.length > 0 && ASSIGNMENT.test(rest[0])) assignments.push(rest.shift());
|
|
1816
|
+
return {
|
|
1817
|
+
binary: rest.length > 0 ? binaryName(rest[0], dialect) : "",
|
|
1818
|
+
args: rest.slice(1),
|
|
1819
|
+
assignments,
|
|
1820
|
+
piped,
|
|
1821
|
+
expandable: false
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
function joinedShortFlag(list, token) {
|
|
1825
|
+
if (token.length <= 2) return void 0;
|
|
1826
|
+
return list.find((f) => f.length === 2 && token.startsWith(f));
|
|
1827
|
+
}
|
|
1828
|
+
function scanWrapperArgs(binary, spec, args) {
|
|
1829
|
+
const valueFlags = spec.valueFlags ?? [];
|
|
1830
|
+
const stringFlags = spec.stringFlags ?? [];
|
|
1831
|
+
const assignments = [];
|
|
1832
|
+
let positionals = spec.positionals ?? 0;
|
|
1833
|
+
let i = 0;
|
|
1834
|
+
while (i < args.length) {
|
|
1835
|
+
const token = args[i];
|
|
1836
|
+
if (token === "--") {
|
|
1837
|
+
i++;
|
|
1838
|
+
break;
|
|
1839
|
+
}
|
|
1840
|
+
if (/^-./.test(token)) {
|
|
1841
|
+
const eq = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
1842
|
+
const name = eq > 0 ? token.slice(0, eq) : token;
|
|
1843
|
+
const selfContained = eq > 0;
|
|
1844
|
+
if ((spec.noExecFlags ?? []).includes(name)) return { kind: "no-exec" };
|
|
1845
|
+
if (stringFlags.includes(name) || joinedShortFlag(stringFlags, token)) {
|
|
1846
|
+
return {
|
|
1847
|
+
kind: "refuse",
|
|
1848
|
+
reason: `"${binary} ${name}" splits a string into a command, which this classifier cannot inspect. Use the read-only research tools, or describe it as a task.`
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
if ((spec.booleanFlags ?? []).includes(name) || spec.booleanPattern?.test(token)) {
|
|
1852
|
+
i++;
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
if (valueFlags.includes(name)) {
|
|
1856
|
+
i += selfContained ? 1 : 2;
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
if (joinedShortFlag(valueFlags, token)) {
|
|
1860
|
+
i++;
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1863
|
+
return {
|
|
1864
|
+
kind: "refuse",
|
|
1865
|
+
reason: `"${token}" is not a flag this classifier knows on the wrapper "${binary}", so it cannot tell which command "${binary}" would actually run. Re-run without it.`
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
if (spec.acceptsAssignments && ASSIGNMENT.test(token)) {
|
|
1869
|
+
assignments.push(token);
|
|
1870
|
+
i++;
|
|
1871
|
+
continue;
|
|
1872
|
+
}
|
|
1873
|
+
if (positionals > 0) {
|
|
1874
|
+
positionals--;
|
|
1875
|
+
i++;
|
|
1876
|
+
continue;
|
|
1877
|
+
}
|
|
1878
|
+
break;
|
|
1879
|
+
}
|
|
1880
|
+
return { kind: "command", tokens: args.slice(i), assignments };
|
|
1881
|
+
}
|
|
1882
|
+
function unwrap(seg, dialect) {
|
|
1883
|
+
const wrappers = [];
|
|
1884
|
+
const assignments = [...seg.assignments];
|
|
1885
|
+
let current = seg;
|
|
1886
|
+
while (WRAPPER_FAMILY[current.binary]) {
|
|
1887
|
+
const scan = scanWrapperArgs(current.binary, WRAPPER_FAMILY[current.binary], current.args);
|
|
1888
|
+
if (scan.kind === "refuse") return { seg: { ...current, assignments }, wrappers, reason: scan.reason };
|
|
1889
|
+
if (scan.kind === "no-exec" || scan.tokens.length === 0) break;
|
|
1890
|
+
assignments.push(...scan.assignments);
|
|
1891
|
+
wrappers.push(current.binary);
|
|
1892
|
+
const inner = toSegment(scan.tokens, current.piped, dialect);
|
|
1893
|
+
assignments.push(...inner.assignments);
|
|
1894
|
+
current = { ...inner, assignments: [], expandable: current.expandable };
|
|
1895
|
+
}
|
|
1896
|
+
return { seg: { ...current, assignments }, wrappers };
|
|
530
1897
|
}
|
|
531
1898
|
function lexAll(command, dialect) {
|
|
532
1899
|
const queue = [];
|
|
@@ -555,16 +1922,79 @@ function pathLikeArgs(command, opts = {}) {
|
|
|
555
1922
|
return !a.startsWith("-") && looksLikePath(a) ? [a] : [];
|
|
556
1923
|
}));
|
|
557
1924
|
}
|
|
1925
|
+
function matchFlag(spec, booleans, values, token) {
|
|
1926
|
+
if (token.startsWith("--")) {
|
|
1927
|
+
const eq = token.indexOf("=");
|
|
1928
|
+
const name = eq > 0 ? token.slice(0, eq) : token;
|
|
1929
|
+
if (booleans.has(name)) return "boolean";
|
|
1930
|
+
if (values.has(name)) return eq > 0 ? "boolean" : "value";
|
|
1931
|
+
return void 0;
|
|
1932
|
+
}
|
|
1933
|
+
if (booleans.has(token)) return "boolean";
|
|
1934
|
+
if (values.has(token)) return "value";
|
|
1935
|
+
if (spec.patterns?.some((p) => p.test(token))) return "boolean";
|
|
1936
|
+
if (!spec.cluster) return void 0;
|
|
1937
|
+
for (let i = 1; i < token.length; i++) {
|
|
1938
|
+
const short = `-${token[i]}`;
|
|
1939
|
+
if (booleans.has(short)) continue;
|
|
1940
|
+
if (values.has(short)) return i === token.length - 1 ? "value" : "boolean";
|
|
1941
|
+
return void 0;
|
|
1942
|
+
}
|
|
1943
|
+
return "boolean";
|
|
1944
|
+
}
|
|
1945
|
+
function takesNextToken(next) {
|
|
1946
|
+
if (next === void 0) return false;
|
|
1947
|
+
return !/^-./.test(next) || /^-\d/.test(next);
|
|
1948
|
+
}
|
|
1949
|
+
function flagLabel(token) {
|
|
1950
|
+
const eq = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
1951
|
+
return eq > 0 ? token.slice(0, eq) : token;
|
|
1952
|
+
}
|
|
1953
|
+
function scanFlags(seg) {
|
|
1954
|
+
const spec = FLAG_POLICY[seg.binary];
|
|
1955
|
+
if (!spec || spec.freeform) return void 0;
|
|
1956
|
+
const booleans = /* @__PURE__ */ new Set([...spec.booleans ?? [], ...UNIVERSAL_FLAGS]);
|
|
1957
|
+
const values = new Set(spec.values ?? []);
|
|
1958
|
+
const operands = [];
|
|
1959
|
+
let i = 0;
|
|
1960
|
+
while (i < seg.args.length) {
|
|
1961
|
+
const token = seg.args[i];
|
|
1962
|
+
if (token === "--" && !spec.expressionArgs) {
|
|
1963
|
+
operands.push(...seg.args.slice(i + 1));
|
|
1964
|
+
break;
|
|
1965
|
+
}
|
|
1966
|
+
if (!/^-./.test(token)) {
|
|
1967
|
+
operands.push(token);
|
|
1968
|
+
i++;
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
const shape = matchFlag(spec, booleans, values, token);
|
|
1972
|
+
if (shape === void 0) return { unknown: flagLabel(token), operands };
|
|
1973
|
+
i += shape === "value" && takesNextToken(seg.args[i + 1]) ? 2 : 1;
|
|
1974
|
+
}
|
|
1975
|
+
return { operands };
|
|
1976
|
+
}
|
|
1977
|
+
function subcommandOf(seg) {
|
|
1978
|
+
const scan = scanFlags(seg);
|
|
1979
|
+
if (scan) return scan.operands[0];
|
|
1980
|
+
return seg.args.find((a) => !a.startsWith("-"));
|
|
1981
|
+
}
|
|
1982
|
+
var SCOPE_LEAD_ARGS = 2;
|
|
558
1983
|
function scopeFor(seg) {
|
|
559
1984
|
if (!MULTIPLEXERS.includes(seg.binary)) return seg.binary;
|
|
560
|
-
const
|
|
561
|
-
|
|
1985
|
+
const lead = [];
|
|
1986
|
+
for (const arg of seg.args) {
|
|
1987
|
+
if (arg.startsWith("-")) break;
|
|
1988
|
+
lead.push(arg);
|
|
1989
|
+
if (lead.length === SCOPE_LEAD_ARGS) break;
|
|
1990
|
+
}
|
|
1991
|
+
return [seg.binary, ...lead].join(" ");
|
|
562
1992
|
}
|
|
563
1993
|
function isAuto(seg) {
|
|
564
1994
|
if (!AUTO_COMMANDS.includes(seg.binary)) return false;
|
|
565
1995
|
if (seg.expandable) return false;
|
|
566
1996
|
if (seg.binary !== "git") return true;
|
|
567
|
-
const sub = seg
|
|
1997
|
+
const sub = subcommandOf(seg);
|
|
568
1998
|
return sub !== void 0 && GIT_READONLY_SUBCOMMANDS.includes(sub);
|
|
569
1999
|
}
|
|
570
2000
|
function refusalFor(seg) {
|
|
@@ -574,20 +2004,32 @@ function refusalFor(seg) {
|
|
|
574
2004
|
if (seg.binary === "eval" || seg.binary === "exec") {
|
|
575
2005
|
return `"${seg.binary}" runs a string as a command, which this classifier cannot inspect. Use the read-only research tools, or describe it as a task.`;
|
|
576
2006
|
}
|
|
2007
|
+
if (seg.binary === "source" || seg.binary === ".") {
|
|
2008
|
+
return `"${seg.binary}" runs a file's contents as commands, which this classifier cannot inspect. Use the read-only research tools, or describe it as a task.`;
|
|
2009
|
+
}
|
|
2010
|
+
if (SHELL_KEYWORDS.includes(seg.binary)) {
|
|
2011
|
+
return `"${seg.binary}" is a shell keyword or compound-command opener. This classifier only inspects the command that runs first, and a keyword hides the real one from it. Run the inner command directly, or describe it as a task.`;
|
|
2012
|
+
}
|
|
577
2013
|
const subs = REFUSED_SUBCOMMANDS[seg.binary];
|
|
578
2014
|
if (subs) {
|
|
579
|
-
const sub = seg
|
|
2015
|
+
const sub = subcommandOf(seg);
|
|
580
2016
|
if (sub && subs.includes(sub)) {
|
|
581
2017
|
return `"${seg.binary} ${sub}" changes state or reaches outward. You are a read-only planner \u2014 put it in the plan and let the runner do it.`;
|
|
582
2018
|
}
|
|
583
2019
|
}
|
|
584
2020
|
if (seg.binary === "git") {
|
|
585
|
-
const sub = seg
|
|
2021
|
+
const sub = subcommandOf(seg);
|
|
586
2022
|
if (sub === "branch" || sub === "tag") {
|
|
587
2023
|
const flag = seg.args.find((a) => ["-D", "-d", "-m", "-M", "--delete", "--move"].includes(a));
|
|
588
2024
|
if (flag) {
|
|
589
2025
|
return `"git ${sub} ${flag}" mutates refs. You are a read-only planner \u2014 describe the change as a task instead.`;
|
|
590
2026
|
}
|
|
2027
|
+
const listing = seg.args.includes("-l") || seg.args.includes("--list");
|
|
2028
|
+
const scan2 = scanFlags(seg);
|
|
2029
|
+
const target = scan2?.operands[1];
|
|
2030
|
+
if (!listing && target) {
|
|
2031
|
+
return `"git ${sub} ${target}" creates or moves a ref. You are a read-only planner \u2014 describe the change as a task instead.`;
|
|
2032
|
+
}
|
|
591
2033
|
}
|
|
592
2034
|
}
|
|
593
2035
|
if (seg.binary === "find") {
|
|
@@ -611,8 +2053,24 @@ function refusalFor(seg) {
|
|
|
611
2053
|
return `Inline code via "${seg.binary} ${seg.args.find(isInlineCodeFlag)}" is not available to the planner. Use the read-only research tools, or describe it as a task.`;
|
|
612
2054
|
}
|
|
613
2055
|
}
|
|
2056
|
+
if (seg.assignments.length > 0) {
|
|
2057
|
+
return `The environment assignment "${seg.assignments[0]}" decides what "${seg.binary}" actually does, and this classifier cannot judge the value. Re-run the command without the assignment.`;
|
|
2058
|
+
}
|
|
2059
|
+
const scan = scanFlags(seg);
|
|
2060
|
+
if (scan?.unknown) {
|
|
2061
|
+
return `"${scan.unknown}" is not a flag this classifier knows to be read-only on "${seg.binary}", and flags on otherwise read-only binaries can run a helper program or write a file. Re-run with read-only flags only, or describe the work as a task.`;
|
|
2062
|
+
}
|
|
2063
|
+
if (seg.binary === "uniq" && scan && scan.operands.length > 1) {
|
|
2064
|
+
return `"uniq" writes to its second file argument ("${scan.operands[1]}"). You are a read-only planner \u2014 pipe the output instead of naming an output file, or describe the write as a task.`;
|
|
2065
|
+
}
|
|
614
2066
|
return void 0;
|
|
615
2067
|
}
|
|
2068
|
+
function withWrapperNote(reason, wrappers) {
|
|
2069
|
+
if (wrappers.length === 0) return reason;
|
|
2070
|
+
const quoted = wrappers.map((w) => `"${w}"`);
|
|
2071
|
+
const names = quoted.length > 1 ? `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}` : quoted[0];
|
|
2072
|
+
return `${reason} Wrapping it in ${names} does not change what runs.`;
|
|
2073
|
+
}
|
|
616
2074
|
function classifyCommand(command, opts = {}) {
|
|
617
2075
|
const trimmed = command.trim();
|
|
618
2076
|
if (!trimmed) return { tier: "refuse", scope: "", reason: "Empty command." };
|
|
@@ -641,11 +2099,13 @@ function classifyCommand(command, opts = {}) {
|
|
|
641
2099
|
};
|
|
642
2100
|
}
|
|
643
2101
|
if (segments.length === 0) return { tier: "refuse", scope: "", reason: "No command found." };
|
|
644
|
-
|
|
2102
|
+
const unwrapped = segments.map((seg) => unwrap(seg, dialect));
|
|
2103
|
+
for (const { seg, wrappers, reason: wrapperReason } of unwrapped) {
|
|
2104
|
+
if (wrapperReason) return { tier: "refuse", scope: "", reason: wrapperReason };
|
|
645
2105
|
const reason = refusalFor(seg);
|
|
646
|
-
if (reason) return { tier: "refuse", scope: "", reason };
|
|
2106
|
+
if (reason) return { tier: "refuse", scope: "", reason: withWrapperNote(reason, wrappers) };
|
|
647
2107
|
}
|
|
648
|
-
const nonAuto =
|
|
2108
|
+
const nonAuto = unwrapped.map((u) => u.seg).filter((s) => !isAuto(s));
|
|
649
2109
|
if (nonAuto.length === 0) return { tier: "auto", scope: "" };
|
|
650
2110
|
const scope = [...new Set(nonAuto.map(scopeFor))].sort().join(" + ");
|
|
651
2111
|
return { tier: "ask", scope };
|
|
@@ -989,6 +2449,139 @@ It is outside the auto-allowed read-only set (${scope}). Continue with the read-
|
|
|
989
2449
|
}
|
|
990
2450
|
};
|
|
991
2451
|
|
|
2452
|
+
// src/utils/redactSecrets.ts
|
|
2453
|
+
var REDACTION_MARKER = "REDACTED";
|
|
2454
|
+
function marker(kind, length) {
|
|
2455
|
+
return `[${REDACTION_MARKER} ${kind}: ${length} chars]`;
|
|
2456
|
+
}
|
|
2457
|
+
var LINE_PREFIX = String.raw`(?:[ \t]*\d+\||[^\s:]*:\d+:|)[ \t]*`;
|
|
2458
|
+
var LINE_PREFIX_ANCHORED = new RegExp("^" + LINE_PREFIX);
|
|
2459
|
+
var CREDENTIAL_WORD = String.raw`(?:api[_-]?keys?|secrets?|passwords?|passwd|passphrase|tokens?|access[_-]?keys?|private[_-]?keys?|client[_-]?secrets?|credentials?|auth)(?![a-z])`;
|
|
2460
|
+
var NAMED_CREDENTIAL = new RegExp(
|
|
2461
|
+
String.raw`((?:^|[^A-Za-z0-9_])["']?[A-Za-z0-9_.\-]*` + CREDENTIAL_WORD + String.raw`[A-Za-z0-9_.\-]*["']?[ \t]*(?:=>|[:=])[ \t]*)(["'\x60]?)([A-Za-z0-9_\-./+=:~!@#%^&*]{8,})\2`,
|
|
2462
|
+
"gi"
|
|
2463
|
+
);
|
|
2464
|
+
var DOTENV_CREDENTIAL = new RegExp(
|
|
2465
|
+
String.raw`^(` + LINE_PREFIX + String.raw`(?:export[ \t]+)?[A-Z0-9_]*` + CREDENTIAL_WORD.toUpperCase() + String.raw`[A-Z0-9_]*[ \t]*=[ \t]*)(["'\x60]?)([^\s"'\x60]{3,})\2[ \t]*$`,
|
|
2466
|
+
"gm"
|
|
2467
|
+
);
|
|
2468
|
+
var PROVIDER_KEY_PATTERNS = [
|
|
2469
|
+
// OpenAI / Anthropic / OpenRouter and the many `sk-` derivatives
|
|
2470
|
+
/(?<![A-Za-z0-9])sk-(?:ant-|proj-|or-v1-|live-|test-)?[A-Za-z0-9_-]{20,}/g,
|
|
2471
|
+
// GitHub personal-access, OAuth, app and refresh tokens
|
|
2472
|
+
/(?<![A-Za-z0-9])(?:gh[pousr]|github_pat)_[A-Za-z0-9_]{22,}/g,
|
|
2473
|
+
// Slack bot / user / app tokens
|
|
2474
|
+
/(?<![A-Za-z0-9])xox[abprse]-[A-Za-z0-9-]{10,}/g,
|
|
2475
|
+
// Stripe secret and restricted keys
|
|
2476
|
+
/(?<![A-Za-z0-9])[sr]k_(?:live|test)_[A-Za-z0-9]{16,}/g,
|
|
2477
|
+
// Google API keys and OAuth access tokens
|
|
2478
|
+
/(?<![A-Za-z0-9])AIza[A-Za-z0-9_-]{30,}/g,
|
|
2479
|
+
/(?<![A-Za-z0-9])ya29\.[A-Za-z0-9_-]{20,}/g,
|
|
2480
|
+
// npm, Hugging Face, Groq, GitLab, DigitalOcean, Shopify
|
|
2481
|
+
/(?<![A-Za-z0-9])(?:npm|hf|gsk|glpat|dop_v1|shpat|shpss)[_-][A-Za-z0-9]{20,}/g,
|
|
2482
|
+
/(?<![A-Za-z0-9])xai-[A-Za-z0-9]{20,}/g,
|
|
2483
|
+
// Three-segment JWTs, whose payload segment is base64 for `{"`
|
|
2484
|
+
/(?<![A-Za-z0-9])eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g
|
|
2485
|
+
];
|
|
2486
|
+
var CLOUD_ACCESS_KEY_ID = /(?<![A-Za-z0-9])(?:A3T[A-Z0-9]{2}|AKIA|ASIA|ABIA|ACCA|AGPA|AIDA|AIPA|ANPA|ANVA|AROA)[A-Z0-9]{16}(?![A-Za-z0-9])/g;
|
|
2487
|
+
var PEM_BEGIN = /-----BEGIN ((?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?)-----/;
|
|
2488
|
+
var PEM_BODY_LINE = /^[A-Za-z0-9+/=:,.\- \t]*$/;
|
|
2489
|
+
function redactPrivateKeyBlocks(text) {
|
|
2490
|
+
if (!PEM_BEGIN.test(text)) return text;
|
|
2491
|
+
const out = [];
|
|
2492
|
+
let label = null;
|
|
2493
|
+
let bodyChars = 0;
|
|
2494
|
+
const closeBlock = () => {
|
|
2495
|
+
if (label === null) return;
|
|
2496
|
+
out.push(marker("private key", bodyChars));
|
|
2497
|
+
label = null;
|
|
2498
|
+
bodyChars = 0;
|
|
2499
|
+
};
|
|
2500
|
+
for (const line of text.split("\n")) {
|
|
2501
|
+
if (label === null) {
|
|
2502
|
+
out.push(line);
|
|
2503
|
+
const begun = PEM_BEGIN.exec(line);
|
|
2504
|
+
if (begun) label = begun[1];
|
|
2505
|
+
continue;
|
|
2506
|
+
}
|
|
2507
|
+
const content = line.replace(LINE_PREFIX_ANCHORED, "");
|
|
2508
|
+
if (content.includes(`-----END ${label}-----`)) {
|
|
2509
|
+
closeBlock();
|
|
2510
|
+
out.push(line);
|
|
2511
|
+
} else if (PEM_BODY_LINE.test(content)) {
|
|
2512
|
+
bodyChars += content.trim().length;
|
|
2513
|
+
} else {
|
|
2514
|
+
closeBlock();
|
|
2515
|
+
out.push(line);
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
closeBlock();
|
|
2519
|
+
return out.join("\n");
|
|
2520
|
+
}
|
|
2521
|
+
var NUMERIC = /^[-+]?\d+(?:\.\d+)?$/;
|
|
2522
|
+
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2523
|
+
var MEMBER_EXPRESSION = /^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)+$/;
|
|
2524
|
+
var SLUG = /^[a-z]+(?:[-_][a-z]+)+$/;
|
|
2525
|
+
var PATHISH = /^(?:\.{0,2}\/|~\/)/;
|
|
2526
|
+
var URLISH = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
2527
|
+
var CODE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2528
|
+
"true",
|
|
2529
|
+
"false",
|
|
2530
|
+
"null",
|
|
2531
|
+
"none",
|
|
2532
|
+
"nil",
|
|
2533
|
+
"undefined",
|
|
2534
|
+
"void",
|
|
2535
|
+
"string",
|
|
2536
|
+
"number",
|
|
2537
|
+
"boolean",
|
|
2538
|
+
"object",
|
|
2539
|
+
"any",
|
|
2540
|
+
"unknown",
|
|
2541
|
+
"bool",
|
|
2542
|
+
"str",
|
|
2543
|
+
"int"
|
|
2544
|
+
]);
|
|
2545
|
+
var UNAMBIGUOUS_CREDENTIAL_NAME = /(?:password|passwd|passphrase|secret|credentials?|private[_-]?key)/i;
|
|
2546
|
+
function looksLikeKeyMaterial(value) {
|
|
2547
|
+
const hasDigit = /\d/.test(value);
|
|
2548
|
+
const hasAlpha = /[A-Za-z]/.test(value);
|
|
2549
|
+
const mixedCase = /[a-z]/.test(value) && /[A-Z]/.test(value);
|
|
2550
|
+
return hasDigit && hasAlpha || mixedCase || value.length >= 24;
|
|
2551
|
+
}
|
|
2552
|
+
function looksLikeCode(value) {
|
|
2553
|
+
return NUMERIC.test(value) || CODE_KEYWORDS.has(value.toLowerCase()) || MEMBER_EXPRESSION.test(value) || PATHISH.test(value) || URLISH.test(value);
|
|
2554
|
+
}
|
|
2555
|
+
function trimTrailingPunctuation(value) {
|
|
2556
|
+
const match = /[.:!]+$/.exec(value);
|
|
2557
|
+
if (!match || match.index === 0) return { value, tail: "" };
|
|
2558
|
+
return { value: value.slice(0, match.index), tail: match[0] };
|
|
2559
|
+
}
|
|
2560
|
+
function redactSecrets(text) {
|
|
2561
|
+
if (!text) return text;
|
|
2562
|
+
let out = redactPrivateKeyBlocks(text);
|
|
2563
|
+
out = out.replace(DOTENV_CREDENTIAL, (full, head, quote, value) => {
|
|
2564
|
+
if (looksLikeCode(value) || value.startsWith("$")) return full;
|
|
2565
|
+
return `${head}${quote}${marker("credential", value.length)}${quote}`;
|
|
2566
|
+
});
|
|
2567
|
+
out = out.replace(NAMED_CREDENTIAL, (full, head, quote, raw) => {
|
|
2568
|
+
const { value, tail } = trimTrailingPunctuation(raw);
|
|
2569
|
+
if (value.length < 8) return full;
|
|
2570
|
+
if (looksLikeCode(value) || value.startsWith("$")) return full;
|
|
2571
|
+
if (UNAMBIGUOUS_CREDENTIAL_NAME.test(head) && /\d/.test(value)) {
|
|
2572
|
+
return `${head}${quote}${marker("credential", value.length)}${quote}${tail}`;
|
|
2573
|
+
}
|
|
2574
|
+
if (IDENTIFIER.test(value) || SLUG.test(value)) return full;
|
|
2575
|
+
if (!UNAMBIGUOUS_CREDENTIAL_NAME.test(head) && !looksLikeKeyMaterial(value)) return full;
|
|
2576
|
+
return `${head}${quote}${marker("credential", value.length)}${quote}${tail}`;
|
|
2577
|
+
});
|
|
2578
|
+
for (const pattern of PROVIDER_KEY_PATTERNS) {
|
|
2579
|
+
out = out.replace(pattern, (hit) => marker("api key", hit.length));
|
|
2580
|
+
}
|
|
2581
|
+
out = out.replace(CLOUD_ACCESS_KEY_ID, (hit) => marker("access key id", hit.length));
|
|
2582
|
+
return out;
|
|
2583
|
+
}
|
|
2584
|
+
|
|
992
2585
|
// src/services/executeTool.ts
|
|
993
2586
|
var GREP_OUTPUT_MODES = ["content", "files", "count"];
|
|
994
2587
|
function num(value) {
|
|
@@ -1015,6 +2608,10 @@ function grepOptions(args) {
|
|
|
1015
2608
|
}
|
|
1016
2609
|
var STOPPED_TOOL_RESULT = "Stopped by the user \u2014 this call was not executed, and no further tool calls will run this turn.";
|
|
1017
2610
|
async function executeTool(name, args, fs10, fetcher, signal) {
|
|
2611
|
+
const outcome = await runTool(name, args, fs10, fetcher, signal);
|
|
2612
|
+
return { ...outcome, output: redactSecrets(outcome.output) };
|
|
2613
|
+
}
|
|
2614
|
+
async function runTool(name, args, fs10, fetcher, signal) {
|
|
1018
2615
|
if (signal?.aborted) return { success: false, output: STOPPED_TOOL_RESULT, truncated: false };
|
|
1019
2616
|
switch (name) {
|
|
1020
2617
|
case "read_file": {
|
|
@@ -1144,14 +2741,14 @@ var PendingApprovals = class {
|
|
|
1144
2741
|
ask(request) {
|
|
1145
2742
|
const id = `ap-${Date.now()}-${counter++}`;
|
|
1146
2743
|
const pending = { id, request, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1147
|
-
return new Promise((
|
|
2744
|
+
return new Promise((resolve4) => {
|
|
1148
2745
|
const settle = (granted) => {
|
|
1149
2746
|
const entry = this.entries.get(id);
|
|
1150
2747
|
if (!entry) return;
|
|
1151
2748
|
clearTimeout(entry.timer);
|
|
1152
2749
|
this.entries.delete(id);
|
|
1153
2750
|
this.opts.onSettled?.(id, granted);
|
|
1154
|
-
|
|
2751
|
+
resolve4(granted);
|
|
1155
2752
|
};
|
|
1156
2753
|
const timer = setTimeout(() => settle(false), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
1157
2754
|
timer.unref?.();
|
|
@@ -4350,11 +5947,11 @@ function composeAugmentedPrompt(task, allTasks, opts) {
|
|
|
4350
5947
|
if (isHitlTask(task)) {
|
|
4351
5948
|
blocks.push(renderCheckpointInstruction());
|
|
4352
5949
|
}
|
|
4353
|
-
const
|
|
4354
|
-
if (blocks.length === 0) return basePrompt +
|
|
5950
|
+
const marker2 = renderCompletionMarker(task);
|
|
5951
|
+
if (blocks.length === 0) return basePrompt + marker2;
|
|
4355
5952
|
return `${blocks.join("\n\n")}
|
|
4356
5953
|
|
|
4357
|
-
${basePrompt}${
|
|
5954
|
+
${basePrompt}${marker2}`;
|
|
4358
5955
|
}
|
|
4359
5956
|
|
|
4360
5957
|
// src/services/VerdictEngine.ts
|
|
@@ -5791,28 +7388,28 @@ function posixBinDirs() {
|
|
|
5791
7388
|
];
|
|
5792
7389
|
}
|
|
5793
7390
|
function windowsBinDirs(env, home) {
|
|
5794
|
-
const
|
|
5795
|
-
const under = (base, ...parts) => base ? [
|
|
7391
|
+
const join16 = (...parts) => path5.win32.join(...parts);
|
|
7392
|
+
const under = (base, ...parts) => base ? [join16(base, ...parts)] : [];
|
|
5796
7393
|
const appData = env.APPDATA;
|
|
5797
7394
|
const localAppData = env.LOCALAPPDATA;
|
|
5798
7395
|
const programData = env.ProgramData;
|
|
5799
7396
|
return [
|
|
5800
7397
|
// Native per-user installers, PowerShell-driven and otherwise.
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
7398
|
+
join16(home, ".local", "bin"),
|
|
7399
|
+
join16(home, ".opencode", "bin"),
|
|
7400
|
+
join16(home, ".claude", "bin"),
|
|
7401
|
+
join16(home, ".codex", "bin"),
|
|
5805
7402
|
...under(localAppData, "Programs", "claude"),
|
|
5806
7403
|
// Node package managers. npm's global prefix is `%APPDATA%\npm`; the
|
|
5807
7404
|
// literal spelling is kept as a fallback for a host that does not export
|
|
5808
7405
|
// APPDATA (a service account, a stripped CI container).
|
|
5809
7406
|
...under(appData, "npm"),
|
|
5810
|
-
|
|
7407
|
+
join16(home, "AppData", "Roaming", "npm"),
|
|
5811
7408
|
...under(localAppData, "pnpm"),
|
|
5812
7409
|
...under(localAppData, "Yarn", "bin"),
|
|
5813
|
-
|
|
7410
|
+
join16(home, ".bun", "bin"),
|
|
5814
7411
|
// Windows package managers.
|
|
5815
|
-
|
|
7412
|
+
join16(home, "scoop", "shims"),
|
|
5816
7413
|
...under(env.SCOOP, "shims"),
|
|
5817
7414
|
...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
|
|
5818
7415
|
...under(programData, "chocolatey", "bin"),
|
|
@@ -5822,7 +7419,7 @@ function windowsBinDirs(env, home) {
|
|
|
5822
7419
|
...under(localAppData, "Microsoft", "WindowsApps"),
|
|
5823
7420
|
// Version managers. Volta's Windows home is not the POSIX `~/.volta`.
|
|
5824
7421
|
...under(localAppData, "Volta", "bin"),
|
|
5825
|
-
|
|
7422
|
+
join16(home, ".volta", "bin")
|
|
5826
7423
|
];
|
|
5827
7424
|
}
|
|
5828
7425
|
function wellKnownBinDirs(deps = {}) {
|
|
@@ -6123,7 +7720,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
6123
7720
|
const PATH = await augmentedPath();
|
|
6124
7721
|
const launch = await planDirectLaunch(command, args).catch(() => null);
|
|
6125
7722
|
if (!launch) return null;
|
|
6126
|
-
return new Promise((
|
|
7723
|
+
return new Promise((resolve4) => {
|
|
6127
7724
|
let child;
|
|
6128
7725
|
try {
|
|
6129
7726
|
child = spawn(launch.file, launch.args, {
|
|
@@ -6132,7 +7729,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
6132
7729
|
windowsVerbatimArguments: launch.verbatim
|
|
6133
7730
|
});
|
|
6134
7731
|
} catch {
|
|
6135
|
-
|
|
7732
|
+
resolve4(null);
|
|
6136
7733
|
return;
|
|
6137
7734
|
}
|
|
6138
7735
|
let settled = false;
|
|
@@ -6141,7 +7738,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
6141
7738
|
settled = true;
|
|
6142
7739
|
clearTimeout(timer);
|
|
6143
7740
|
killTree(child);
|
|
6144
|
-
|
|
7741
|
+
resolve4(value);
|
|
6145
7742
|
};
|
|
6146
7743
|
const timer = setTimeout(() => finish(null), options?.timeout ?? 2e4);
|
|
6147
7744
|
child.on("error", () => finish(null));
|
|
@@ -7181,11 +8778,71 @@ var RunnerInstallation = class {
|
|
|
7181
8778
|
}
|
|
7182
8779
|
};
|
|
7183
8780
|
|
|
8781
|
+
// src/services/settingsEnvAllowlist.ts
|
|
8782
|
+
var ORDEWELL_SETTABLE_ENV = [
|
|
8783
|
+
"AI_PROVIDER",
|
|
8784
|
+
"ORCHESTRATOR_MODEL",
|
|
8785
|
+
"ORDEWELL_SUBAGENT_MODEL",
|
|
8786
|
+
"ORDEWELL_PLANNER_EFFORT",
|
|
8787
|
+
"ORDEWELL_RESEARCH_ENABLED",
|
|
8788
|
+
"ORDEWELL_MAX_PARALLEL"
|
|
8789
|
+
];
|
|
8790
|
+
var SETTINGS_ENV_REFUSED = [
|
|
8791
|
+
// Approval posture and pre-approved scope.
|
|
8792
|
+
"ORDEWELL_AUTONOMOUS_MODE",
|
|
8793
|
+
"ORDEWELL_APPROVAL_MODE",
|
|
8794
|
+
"ORDEWELL_APPROVAL_ALLOW",
|
|
8795
|
+
// Where settings are persisted.
|
|
8796
|
+
"ORDEWELL_SETTINGS_PATH",
|
|
8797
|
+
// Runtime options and dynamic loaders.
|
|
8798
|
+
"NODE_OPTIONS",
|
|
8799
|
+
"NODE_REPL_EXTERNAL_MODULE",
|
|
8800
|
+
"NODE_PATH",
|
|
8801
|
+
"ELECTRON_RUN_AS_NODE",
|
|
8802
|
+
"LD_PRELOAD",
|
|
8803
|
+
"LD_LIBRARY_PATH",
|
|
8804
|
+
"LD_AUDIT",
|
|
8805
|
+
"DYLD_INSERT_LIBRARIES",
|
|
8806
|
+
"DYLD_LIBRARY_PATH",
|
|
8807
|
+
"DYLD_FRAMEWORK_PATH",
|
|
8808
|
+
// Executable resolution.
|
|
8809
|
+
"PATH",
|
|
8810
|
+
"PATHEXT",
|
|
8811
|
+
"NODE"
|
|
8812
|
+
];
|
|
8813
|
+
var REFUSED = new Set(SETTINGS_ENV_REFUSED);
|
|
8814
|
+
function providerEnvKeys() {
|
|
8815
|
+
const keys = [];
|
|
8816
|
+
for (const meta of Object.values(ALL_PROVIDERS)) {
|
|
8817
|
+
if (meta.apiKeyEnvVar) keys.push(meta.apiKeyEnvVar);
|
|
8818
|
+
if (meta.baseUrlEnvVar) keys.push(meta.baseUrlEnvVar);
|
|
8819
|
+
for (const detect of meta.detectEnvVars) keys.push(detect);
|
|
8820
|
+
}
|
|
8821
|
+
return keys;
|
|
8822
|
+
}
|
|
8823
|
+
var PROVIDER_CREDENTIAL_ENV = new Set(providerEnvKeys());
|
|
8824
|
+
var SETTINGS_ENV_ALLOWLIST = new Set(
|
|
8825
|
+
[...providerEnvKeys(), ...ORDEWELL_SETTABLE_ENV].filter((key) => !REFUSED.has(key))
|
|
8826
|
+
);
|
|
8827
|
+
function admitSettingsEnv(env) {
|
|
8828
|
+
const accepted = {};
|
|
8829
|
+
const rejected = [];
|
|
8830
|
+
for (const [key, value] of Object.entries(env)) {
|
|
8831
|
+
if (REFUSED.has(key) || !SETTINGS_ENV_ALLOWLIST.has(key) || typeof value !== "string") {
|
|
8832
|
+
rejected.push(key);
|
|
8833
|
+
continue;
|
|
8834
|
+
}
|
|
8835
|
+
accepted[key] = value;
|
|
8836
|
+
}
|
|
8837
|
+
return { accepted, rejected };
|
|
8838
|
+
}
|
|
8839
|
+
|
|
7184
8840
|
// src/services/harness/CliAgentAiService.ts
|
|
7185
8841
|
import { spawn as nodeSpawn } from "child_process";
|
|
7186
8842
|
|
|
7187
8843
|
// src/utils/workspace.ts
|
|
7188
8844
|
import * as fs3 from "fs";
|
|
8845
|
+
import * as path9 from "path";
|
|
7189
8846
|
var WorkspaceNotFoundError = class extends Error {
|
|
7190
8847
|
constructor(workspace) {
|
|
7191
8848
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -7205,6 +8862,46 @@ function assertWorkspaceExists(workspace, deps = {}) {
|
|
|
7205
8862
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
7206
8863
|
if (!isDirectory(workspace)) throw new WorkspaceNotFoundError(workspace);
|
|
7207
8864
|
}
|
|
8865
|
+
var WorkspaceNotAProjectError = class extends Error {
|
|
8866
|
+
constructor(workspace) {
|
|
8867
|
+
super(`Workspace "${workspace}" is not a project directory (no .ordewell state, version control, or recognized manifest found).`);
|
|
8868
|
+
this.workspace = workspace;
|
|
8869
|
+
this.name = "WorkspaceNotAProjectError";
|
|
8870
|
+
}
|
|
8871
|
+
workspace;
|
|
8872
|
+
};
|
|
8873
|
+
var PROJECT_MARKER_DIRS = [".ordewell", ".git", ".hg", ".svn", ".bzr"];
|
|
8874
|
+
var PROJECT_MARKER_FILES = [
|
|
8875
|
+
"package.json",
|
|
8876
|
+
"Cargo.toml",
|
|
8877
|
+
"go.mod",
|
|
8878
|
+
"pyproject.toml",
|
|
8879
|
+
"setup.py",
|
|
8880
|
+
"requirements.txt",
|
|
8881
|
+
"Pipfile",
|
|
8882
|
+
"pom.xml",
|
|
8883
|
+
"build.gradle",
|
|
8884
|
+
"build.gradle.kts",
|
|
8885
|
+
"Gemfile",
|
|
8886
|
+
"composer.json",
|
|
8887
|
+
"pubspec.yaml",
|
|
8888
|
+
"mix.exs",
|
|
8889
|
+
"CMakeLists.txt"
|
|
8890
|
+
];
|
|
8891
|
+
function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
8892
|
+
const realpath = deps.realpath ?? ((candidate) => fs3.realpathSync(candidate));
|
|
8893
|
+
const exists = deps.exists ?? ((candidate) => fs3.existsSync(candidate));
|
|
8894
|
+
let resolved;
|
|
8895
|
+
try {
|
|
8896
|
+
resolved = realpath(workspace);
|
|
8897
|
+
} catch {
|
|
8898
|
+
throw new WorkspaceNotAProjectError(workspace);
|
|
8899
|
+
}
|
|
8900
|
+
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
8901
|
+
(marker2) => exists(path9.join(resolved, marker2))
|
|
8902
|
+
);
|
|
8903
|
+
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
8904
|
+
}
|
|
7208
8905
|
|
|
7209
8906
|
// src/services/harness/AgentAdapter.ts
|
|
7210
8907
|
var LineBuffer = class {
|
|
@@ -7260,8 +8957,8 @@ var StdioAgentAdapter = class {
|
|
|
7260
8957
|
}
|
|
7261
8958
|
async start(opts) {
|
|
7262
8959
|
assertWorkspaceExists(opts.cwd, { isDirectory: this.deps.isDirectory });
|
|
7263
|
-
this.processEnded = new Promise((
|
|
7264
|
-
this.markEnded =
|
|
8960
|
+
this.processEnded = new Promise((resolve4) => {
|
|
8961
|
+
this.markEnded = resolve4;
|
|
7265
8962
|
});
|
|
7266
8963
|
const spec = this.spawnSpec(opts);
|
|
7267
8964
|
const resolvePath = this.deps.resolvePath ?? augmentedPath;
|
|
@@ -7309,7 +9006,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
7309
9006
|
onEvent({ type: "error", message: this.exitMessage() });
|
|
7310
9007
|
return;
|
|
7311
9008
|
}
|
|
7312
|
-
await new Promise((
|
|
9009
|
+
await new Promise((resolve4) => {
|
|
7313
9010
|
let settled = false;
|
|
7314
9011
|
const finish = () => {
|
|
7315
9012
|
if (settled) return;
|
|
@@ -7318,7 +9015,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
7318
9015
|
signal?.removeEventListener("abort", onAbort);
|
|
7319
9016
|
this.process?.removeListener("exit", onExit);
|
|
7320
9017
|
this.process?.removeListener("error", onExit);
|
|
7321
|
-
|
|
9018
|
+
resolve4();
|
|
7322
9019
|
};
|
|
7323
9020
|
const emit = (event) => {
|
|
7324
9021
|
onEvent(event);
|
|
@@ -7519,14 +9216,14 @@ function codexSandboxUnavailableMessage() {
|
|
|
7519
9216
|
].join("\n");
|
|
7520
9217
|
}
|
|
7521
9218
|
function runProbe(deps, cwd, env, flags) {
|
|
7522
|
-
return new Promise((
|
|
9219
|
+
return new Promise((resolve4) => {
|
|
7523
9220
|
let output = "";
|
|
7524
9221
|
let settled = false;
|
|
7525
9222
|
const finish = (code) => {
|
|
7526
9223
|
if (settled) return;
|
|
7527
9224
|
settled = true;
|
|
7528
9225
|
clearTimeout(timer);
|
|
7529
|
-
|
|
9226
|
+
resolve4({ code, output });
|
|
7530
9227
|
};
|
|
7531
9228
|
const timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);
|
|
7532
9229
|
timer.unref?.();
|
|
@@ -7609,8 +9306,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
7609
9306
|
async handshake(opts) {
|
|
7610
9307
|
this.sandbox = await probeCodexSandbox(this.deps, opts.cwd, this.spawnEnv);
|
|
7611
9308
|
if (this.sandbox === "unavailable") throw new Error(codexSandboxUnavailableMessage());
|
|
7612
|
-
const ready = new Promise((
|
|
7613
|
-
this.settleHandshake =
|
|
9309
|
+
const ready = new Promise((resolve4) => {
|
|
9310
|
+
this.settleHandshake = resolve4;
|
|
7614
9311
|
});
|
|
7615
9312
|
this.writeLine({
|
|
7616
9313
|
jsonrpc: "2.0",
|
|
@@ -7623,8 +9320,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
7623
9320
|
// A binary that rejects `app-server` outright dies immediately; waiting
|
|
7624
9321
|
// out the timeout would turn a one-line diagnostic into a 30s stall.
|
|
7625
9322
|
this.processEnded.then(() => false),
|
|
7626
|
-
new Promise((
|
|
7627
|
-
const t = setTimeout(() =>
|
|
9323
|
+
new Promise((resolve4) => {
|
|
9324
|
+
const t = setTimeout(() => resolve4(false), HANDSHAKE_TIMEOUT_MS);
|
|
7628
9325
|
t.unref?.();
|
|
7629
9326
|
})
|
|
7630
9327
|
]);
|
|
@@ -7912,12 +9609,12 @@ var OpenCodeAdapter = class {
|
|
|
7912
9609
|
cwd: opts.cwd,
|
|
7913
9610
|
windowsVerbatimArguments: launch.verbatim
|
|
7914
9611
|
});
|
|
7915
|
-
const banner = new Promise((
|
|
9612
|
+
const banner = new Promise((resolve4) => {
|
|
7916
9613
|
let seen = "";
|
|
7917
9614
|
const scan = (chunk) => {
|
|
7918
9615
|
seen += chunk.toString();
|
|
7919
9616
|
const match = seen.match(/https?:\/\/[^\s]+/);
|
|
7920
|
-
if (match)
|
|
9617
|
+
if (match) resolve4(match[0].replace(/[.,)]$/, ""));
|
|
7921
9618
|
};
|
|
7922
9619
|
this.process.stdout?.on("data", scan);
|
|
7923
9620
|
this.process.stderr?.on("data", (chunk) => {
|
|
@@ -7926,15 +9623,15 @@ var OpenCodeAdapter = class {
|
|
|
7926
9623
|
});
|
|
7927
9624
|
this.process.on("exit", () => {
|
|
7928
9625
|
this.exited = true;
|
|
7929
|
-
|
|
9626
|
+
resolve4(null);
|
|
7930
9627
|
});
|
|
7931
9628
|
this.process.on("error", (err) => {
|
|
7932
9629
|
this.exited = true;
|
|
7933
9630
|
this.stderrTail = (this.stderrTail + `
|
|
7934
9631
|
${err.message}`).slice(-STDERR_TAIL_CHARS2);
|
|
7935
|
-
|
|
9632
|
+
resolve4(null);
|
|
7936
9633
|
});
|
|
7937
|
-
const timer = setTimeout(() =>
|
|
9634
|
+
const timer = setTimeout(() => resolve4(null), SERVER_READY_TIMEOUT_MS);
|
|
7938
9635
|
timer.unref?.();
|
|
7939
9636
|
});
|
|
7940
9637
|
this.baseUrl = await banner;
|
|
@@ -7964,8 +9661,8 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
7964
9661
|
const streamAbort = new AbortController();
|
|
7965
9662
|
let connected = () => {
|
|
7966
9663
|
};
|
|
7967
|
-
const streamReady = new Promise((
|
|
7968
|
-
connected =
|
|
9664
|
+
const streamReady = new Promise((resolve4) => {
|
|
9665
|
+
connected = resolve4;
|
|
7969
9666
|
});
|
|
7970
9667
|
const live = this.streamEvents(
|
|
7971
9668
|
streamAbort.signal,
|
|
@@ -8117,14 +9814,14 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
8117
9814
|
}
|
|
8118
9815
|
}
|
|
8119
9816
|
}
|
|
8120
|
-
async json(method,
|
|
8121
|
-
const response = await this.deps.fetch(`${this.baseUrl}${
|
|
9817
|
+
async json(method, path17, body, signal) {
|
|
9818
|
+
const response = await this.deps.fetch(`${this.baseUrl}${path17}`, {
|
|
8122
9819
|
method,
|
|
8123
9820
|
headers: { "content-type": "application/json" },
|
|
8124
9821
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
8125
9822
|
...signal ? { signal } : {}
|
|
8126
9823
|
});
|
|
8127
|
-
if (!response.ok) throw new Error(`${method} ${
|
|
9824
|
+
if (!response.ok) throw new Error(`${method} ${path17} failed: ${response.status} ${response.statusText}`);
|
|
8128
9825
|
return await response.json().catch(() => null);
|
|
8129
9826
|
}
|
|
8130
9827
|
nativeSessionId() {
|
|
@@ -8421,7 +10118,8 @@ var CliAgentAiService = class {
|
|
|
8421
10118
|
let stepIndex = 0;
|
|
8422
10119
|
const truncate = (value) => value.length > LOG_MAX_CHARS ? `${value.slice(0, LOG_MAX_CHARS)}
|
|
8423
10120
|
[... truncated, total ${value.length} chars]` : value;
|
|
8424
|
-
const settle = (id,
|
|
10121
|
+
const settle = (id, rawOutput, success, outcome) => {
|
|
10122
|
+
const output = redactSecrets(rawOutput);
|
|
8425
10123
|
const call = pendingCalls.get(id);
|
|
8426
10124
|
pendingCalls.delete(id);
|
|
8427
10125
|
const step = {
|
|
@@ -8938,11 +10636,11 @@ function executionSummary(tasks) {
|
|
|
8938
10636
|
|
|
8939
10637
|
// src/utils/sessionStore.ts
|
|
8940
10638
|
import * as fs5 from "fs";
|
|
8941
|
-
import * as
|
|
10639
|
+
import * as path11 from "path";
|
|
8942
10640
|
|
|
8943
10641
|
// src/utils/fsHelpers.ts
|
|
8944
10642
|
import * as fs4 from "fs";
|
|
8945
|
-
import * as
|
|
10643
|
+
import * as path10 from "path";
|
|
8946
10644
|
var STATE_DIR = ".ordewell";
|
|
8947
10645
|
function ensureDir(dir) {
|
|
8948
10646
|
if (!fs4.existsSync(dir)) {
|
|
@@ -8950,13 +10648,29 @@ function ensureDir(dir) {
|
|
|
8950
10648
|
}
|
|
8951
10649
|
}
|
|
8952
10650
|
function getStateDir(baseDir) {
|
|
8953
|
-
return
|
|
10651
|
+
return path10.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
10652
|
+
}
|
|
10653
|
+
var IGNORE_FILE = ".gitignore";
|
|
10654
|
+
function ensureStateDirIgnored(baseDir) {
|
|
10655
|
+
const dir = getStateDir(baseDir);
|
|
10656
|
+
ensureDir(dir);
|
|
10657
|
+
try {
|
|
10658
|
+
fs4.writeFileSync(path10.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
|
|
10659
|
+
} catch (err) {
|
|
10660
|
+
if (err.code !== "EEXIST") throw err;
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
|
|
10664
|
+
// src/utils/sessionId.ts
|
|
10665
|
+
import { randomBytes } from "crypto";
|
|
10666
|
+
function mintSessionId() {
|
|
10667
|
+
return `session-${randomBytes(16).toString("hex")}`;
|
|
8954
10668
|
}
|
|
8955
10669
|
|
|
8956
10670
|
// src/utils/sessionStore.ts
|
|
8957
10671
|
var SESSIONS_SUBDIR = "sessions";
|
|
8958
10672
|
function getSessionsDir(baseDir) {
|
|
8959
|
-
return
|
|
10673
|
+
return path11.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
8960
10674
|
}
|
|
8961
10675
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
8962
10676
|
function hasScalarRunner(parsed) {
|
|
@@ -8975,9 +10689,10 @@ function sessionFilename(session) {
|
|
|
8975
10689
|
function saveSession(plan, goal, baseDir, id) {
|
|
8976
10690
|
const sessionsDir = getSessionsDir(baseDir);
|
|
8977
10691
|
ensureDir(sessionsDir);
|
|
10692
|
+
ensureStateDirIgnored(baseDir);
|
|
8978
10693
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8979
10694
|
const meta = {
|
|
8980
|
-
id: id ||
|
|
10695
|
+
id: id || mintSessionId(),
|
|
8981
10696
|
goal: goal || "(untitled)",
|
|
8982
10697
|
runners: plan.runners,
|
|
8983
10698
|
taskCount: plan.tasks.flatMap((t) => [t, ...t.subtasks || []]).length,
|
|
@@ -8990,7 +10705,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
8990
10705
|
plan: JSON.parse(JSON.stringify(plan))
|
|
8991
10706
|
};
|
|
8992
10707
|
const filename = sessionFilename(meta);
|
|
8993
|
-
const filePath =
|
|
10708
|
+
const filePath = path11.join(sessionsDir, filename);
|
|
8994
10709
|
fs5.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
8995
10710
|
return meta;
|
|
8996
10711
|
}
|
|
@@ -9000,7 +10715,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
9000
10715
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
9001
10716
|
return files.map((f) => {
|
|
9002
10717
|
try {
|
|
9003
|
-
const raw = fs5.readFileSync(
|
|
10718
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
9004
10719
|
const parsed = JSON.parse(raw);
|
|
9005
10720
|
if (hasScalarRunner(parsed)) {
|
|
9006
10721
|
logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
|
|
@@ -9018,7 +10733,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
9018
10733
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
9019
10734
|
for (const f of files) {
|
|
9020
10735
|
try {
|
|
9021
|
-
const raw = fs5.readFileSync(
|
|
10736
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
9022
10737
|
const session = JSON.parse(raw);
|
|
9023
10738
|
if (session.meta.id === sessionId) return f;
|
|
9024
10739
|
} catch (err) {
|
|
@@ -9033,7 +10748,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
9033
10748
|
try {
|
|
9034
10749
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
9035
10750
|
if (file) {
|
|
9036
|
-
const raw = fs5.readFileSync(
|
|
10751
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, file), "utf-8");
|
|
9037
10752
|
const parsed = JSON.parse(raw);
|
|
9038
10753
|
if (hasScalarRunner(parsed)) {
|
|
9039
10754
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -9067,7 +10782,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
9067
10782
|
try {
|
|
9068
10783
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
9069
10784
|
if (file) {
|
|
9070
|
-
fs5.unlinkSync(
|
|
10785
|
+
fs5.unlinkSync(path11.join(sessionsDir, file));
|
|
9071
10786
|
return true;
|
|
9072
10787
|
}
|
|
9073
10788
|
} catch (err) {
|
|
@@ -9086,11 +10801,6 @@ var PlanEditError = class extends Error {
|
|
|
9086
10801
|
function sessionRuntimeSettings(settings) {
|
|
9087
10802
|
return { ...plannerRuntimeToggles(settings), modelAllowlist: settings.modelAllowlist };
|
|
9088
10803
|
}
|
|
9089
|
-
var lastMintedAt = 0;
|
|
9090
|
-
function mintSessionId() {
|
|
9091
|
-
lastMintedAt = Math.max(Date.now(), lastMintedAt + 1);
|
|
9092
|
-
return `session-${lastMintedAt}`;
|
|
9093
|
-
}
|
|
9094
10804
|
var Session = class {
|
|
9095
10805
|
/** Injected by a test; when present it is the service, forever. */
|
|
9096
10806
|
pinnedAiService;
|
|
@@ -10531,8 +12241,8 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
10531
12241
|
import { execFile as execFile2 } from "child_process";
|
|
10532
12242
|
import { promisify as promisify4 } from "util";
|
|
10533
12243
|
import { tmpdir } from "os";
|
|
10534
|
-
import { join as
|
|
10535
|
-
import { existsSync as
|
|
12244
|
+
import { join as join10 } from "path";
|
|
12245
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
10536
12246
|
|
|
10537
12247
|
// src/utils/tmux.ts
|
|
10538
12248
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -10623,7 +12333,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
10623
12333
|
* lets the user keep poking at a finished task's terminal.
|
|
10624
12334
|
*/
|
|
10625
12335
|
async start(command, args, cwd, env) {
|
|
10626
|
-
|
|
12336
|
+
writeFileSync6(this.logPath, "");
|
|
10627
12337
|
const envAssignments = Object.entries(env ?? {}).map(([k, v]) => `${k}=${posixShellQuote(v)}`).join(" ");
|
|
10628
12338
|
const inner = [command, ...args].map(posixShellQuote).join(" ");
|
|
10629
12339
|
const prefix = envAssignments ? `env ${envAssignments} ` : "";
|
|
@@ -10637,7 +12347,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
10637
12347
|
if (this.exited) return;
|
|
10638
12348
|
let content;
|
|
10639
12349
|
try {
|
|
10640
|
-
content =
|
|
12350
|
+
content = existsSync6(this.logPath) ? readFileSync4(this.logPath, "utf8") : "";
|
|
10641
12351
|
} catch {
|
|
10642
12352
|
return;
|
|
10643
12353
|
}
|
|
@@ -10816,7 +12526,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10816
12526
|
windowName,
|
|
10817
12527
|
this.execFileImpl,
|
|
10818
12528
|
this.pollIntervalMs,
|
|
10819
|
-
|
|
12529
|
+
join10(this.logDir, `${id}.log`),
|
|
10820
12530
|
this.socket
|
|
10821
12531
|
);
|
|
10822
12532
|
invocation.env = { ...invocation.env, PATH: await this.resolvePath() };
|
|
@@ -10826,26 +12536,128 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10826
12536
|
}
|
|
10827
12537
|
};
|
|
10828
12538
|
|
|
12539
|
+
// src/utils/daemonToken.ts
|
|
12540
|
+
import { randomBytes as randomBytes2, timingSafeEqual } from "crypto";
|
|
12541
|
+
import { closeSync, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeSync } from "fs";
|
|
12542
|
+
import { homedir as homedir5 } from "os";
|
|
12543
|
+
import { join as join11 } from "path";
|
|
12544
|
+
var BEARER_PREFIX = "bearer ";
|
|
12545
|
+
var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
|
|
12546
|
+
var DAEMON_SUBPROTOCOL = "ordewell.v1";
|
|
12547
|
+
function configDir() {
|
|
12548
|
+
return join11(homedir5(), ".config", "ordewell");
|
|
12549
|
+
}
|
|
12550
|
+
function daemonTokenPath(port) {
|
|
12551
|
+
return join11(configDir(), `server-${port}.token`);
|
|
12552
|
+
}
|
|
12553
|
+
function mintDaemonToken(port) {
|
|
12554
|
+
const token = randomBytes2(32).toString("base64url");
|
|
12555
|
+
const file = daemonTokenPath(port);
|
|
12556
|
+
mkdirSync5(configDir(), { recursive: true });
|
|
12557
|
+
try {
|
|
12558
|
+
unlinkSync3(file);
|
|
12559
|
+
} catch {
|
|
12560
|
+
}
|
|
12561
|
+
const fd = openSync(file, "wx", 384);
|
|
12562
|
+
try {
|
|
12563
|
+
writeSync(fd, token);
|
|
12564
|
+
} finally {
|
|
12565
|
+
closeSync(fd);
|
|
12566
|
+
}
|
|
12567
|
+
return { token, file };
|
|
12568
|
+
}
|
|
12569
|
+
function readDaemonToken(port) {
|
|
12570
|
+
try {
|
|
12571
|
+
const token = readFileSync5(daemonTokenPath(port), "utf8").trim();
|
|
12572
|
+
return token === "" ? void 0 : token;
|
|
12573
|
+
} catch {
|
|
12574
|
+
return void 0;
|
|
12575
|
+
}
|
|
12576
|
+
}
|
|
12577
|
+
function clearDaemonToken(port) {
|
|
12578
|
+
try {
|
|
12579
|
+
unlinkSync3(daemonTokenPath(port));
|
|
12580
|
+
} catch {
|
|
12581
|
+
}
|
|
12582
|
+
}
|
|
12583
|
+
function bearerHeaderValue(token) {
|
|
12584
|
+
return `Bearer ${token}`;
|
|
12585
|
+
}
|
|
12586
|
+
function tokenSubprotocols(token) {
|
|
12587
|
+
return [DAEMON_SUBPROTOCOL, `${DAEMON_TOKEN_SUBPROTOCOL_PREFIX}${token}`];
|
|
12588
|
+
}
|
|
12589
|
+
function extractPresentedToken(carriers) {
|
|
12590
|
+
const authorization = carriers.authorization;
|
|
12591
|
+
if (authorization && authorization.toLowerCase().startsWith(BEARER_PREFIX)) {
|
|
12592
|
+
const value = authorization.slice(BEARER_PREFIX.length).trim();
|
|
12593
|
+
if (value !== "") return value;
|
|
12594
|
+
}
|
|
12595
|
+
for (const offered of (carriers.secWebSocketProtocol ?? "").split(",")) {
|
|
12596
|
+
const value = offered.trim();
|
|
12597
|
+
if (!value.startsWith(DAEMON_TOKEN_SUBPROTOCOL_PREFIX)) continue;
|
|
12598
|
+
const token = value.slice(DAEMON_TOKEN_SUBPROTOCOL_PREFIX.length);
|
|
12599
|
+
if (token !== "") return token;
|
|
12600
|
+
}
|
|
12601
|
+
return void 0;
|
|
12602
|
+
}
|
|
12603
|
+
function tokensMatch(presented, expected) {
|
|
12604
|
+
if (presented === void 0) return false;
|
|
12605
|
+
const a = Buffer.from(presented, "utf8");
|
|
12606
|
+
const b = Buffer.from(expected, "utf8");
|
|
12607
|
+
if (a.length !== b.length) return false;
|
|
12608
|
+
return timingSafeEqual(a, b);
|
|
12609
|
+
}
|
|
12610
|
+
|
|
10829
12611
|
// src/plugins/RunnerRegistry.ts
|
|
10830
12612
|
import * as fs7 from "fs";
|
|
10831
|
-
import * as
|
|
12613
|
+
import * as path14 from "path";
|
|
10832
12614
|
import * as os5 from "os";
|
|
10833
|
-
import {
|
|
12615
|
+
import { execFileSync } from "child_process";
|
|
12616
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
10834
12617
|
|
|
10835
12618
|
// src/plugins/FsPluginStore.ts
|
|
10836
12619
|
import * as fs6 from "fs";
|
|
10837
|
-
import * as
|
|
12620
|
+
import * as path13 from "path";
|
|
10838
12621
|
import * as os4 from "os";
|
|
10839
|
-
|
|
10840
|
-
|
|
12622
|
+
|
|
12623
|
+
// src/plugins/pluginNames.ts
|
|
12624
|
+
import * as path12 from "path";
|
|
12625
|
+
var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
12626
|
+
var MAX_PLUGIN_NAME_LENGTH = 64;
|
|
12627
|
+
function isPlainPluginName(name) {
|
|
12628
|
+
return typeof name === "string" && name.length <= MAX_PLUGIN_NAME_LENGTH && PLUGIN_NAME_PATTERN.test(name);
|
|
12629
|
+
}
|
|
12630
|
+
function assertPlainPluginName(name) {
|
|
12631
|
+
if (!isPlainPluginName(name)) {
|
|
12632
|
+
throw new Error(
|
|
12633
|
+
`Invalid plugin name: ${JSON.stringify(name)}. Names must be a single plain segment of letters, digits, '.', '-' or '_' (max ${MAX_PLUGIN_NAME_LENGTH} characters).`
|
|
12634
|
+
);
|
|
12635
|
+
}
|
|
10841
12636
|
}
|
|
12637
|
+
function resolvePluginInstallDir(pluginsDir, name) {
|
|
12638
|
+
assertPlainPluginName(name);
|
|
12639
|
+
const root = path12.resolve(pluginsDir);
|
|
12640
|
+
const dest = path12.resolve(root, name);
|
|
12641
|
+
const relative3 = path12.relative(root, dest);
|
|
12642
|
+
if (relative3 !== name || relative3 === "" || path12.isAbsolute(relative3)) {
|
|
12643
|
+
throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
|
|
12644
|
+
}
|
|
12645
|
+
return dest;
|
|
12646
|
+
}
|
|
12647
|
+
|
|
12648
|
+
// src/plugins/manifestValidation.ts
|
|
10842
12649
|
function isValidManifest(obj) {
|
|
10843
12650
|
if (!obj || typeof obj !== "object") return false;
|
|
10844
12651
|
const m = obj;
|
|
10845
|
-
return
|
|
12652
|
+
return isPlainPluginName(m.name) && typeof m.displayName === "string" && typeof m.description === "string" && typeof m.version === "string" && typeof m.runner === "object" && m.runner !== null && typeof m.runner.command === "string" && Array.isArray(m.runner.argsTemplate) && typeof m.features === "object" && m.features !== null && typeof m.modelDiscovery === "object" && m.modelDiscovery !== null;
|
|
12653
|
+
}
|
|
12654
|
+
|
|
12655
|
+
// src/plugins/FsPluginStore.ts
|
|
12656
|
+
function userPluginsDir() {
|
|
12657
|
+
return path13.join(os4.homedir(), ".config", "ordewell", "plugins");
|
|
10846
12658
|
}
|
|
10847
12659
|
function loadManifestFromDir(dir) {
|
|
10848
|
-
const manifestPath =
|
|
12660
|
+
const manifestPath = path13.join(dir, "manifest.json");
|
|
10849
12661
|
if (!fs6.existsSync(manifestPath)) return null;
|
|
10850
12662
|
try {
|
|
10851
12663
|
const raw = fs6.readFileSync(manifestPath, "utf8");
|
|
@@ -10860,8 +12672,8 @@ function copyDirSync(src, dest) {
|
|
|
10860
12672
|
ensureDir(dest);
|
|
10861
12673
|
const entries = fs6.readdirSync(src, { withFileTypes: true });
|
|
10862
12674
|
for (const entry of entries) {
|
|
10863
|
-
const srcPath =
|
|
10864
|
-
const destPath =
|
|
12675
|
+
const srcPath = path13.join(src, entry.name);
|
|
12676
|
+
const destPath = path13.join(dest, entry.name);
|
|
10865
12677
|
if (entry.isDirectory()) {
|
|
10866
12678
|
copyDirSync(srcPath, destPath);
|
|
10867
12679
|
} else {
|
|
@@ -10873,7 +12685,7 @@ function rmDirSync(dir) {
|
|
|
10873
12685
|
if (!fs6.existsSync(dir)) return;
|
|
10874
12686
|
const entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
10875
12687
|
for (const entry of entries) {
|
|
10876
|
-
const p =
|
|
12688
|
+
const p = path13.join(dir, entry.name);
|
|
10877
12689
|
if (entry.isDirectory()) {
|
|
10878
12690
|
rmDirSync(p);
|
|
10879
12691
|
} else {
|
|
@@ -10897,6 +12709,13 @@ var FsPluginStore = class {
|
|
|
10897
12709
|
}
|
|
10898
12710
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
10899
12711
|
}
|
|
12712
|
+
listDir(dir) {
|
|
12713
|
+
try {
|
|
12714
|
+
return fs6.readdirSync(dir);
|
|
12715
|
+
} catch {
|
|
12716
|
+
return [];
|
|
12717
|
+
}
|
|
12718
|
+
}
|
|
10900
12719
|
loadManifest(pluginDir) {
|
|
10901
12720
|
return loadManifestFromDir(pluginDir);
|
|
10902
12721
|
}
|
|
@@ -10919,11 +12738,11 @@ var FsPluginStore = class {
|
|
|
10919
12738
|
return null;
|
|
10920
12739
|
}
|
|
10921
12740
|
}
|
|
10922
|
-
dirExists(
|
|
10923
|
-
return fs6.existsSync(
|
|
12741
|
+
dirExists(path17) {
|
|
12742
|
+
return fs6.existsSync(path17) && fs6.statSync(path17).isDirectory();
|
|
10924
12743
|
}
|
|
10925
|
-
exists(
|
|
10926
|
-
return fs6.existsSync(
|
|
12744
|
+
exists(path17) {
|
|
12745
|
+
return fs6.existsSync(path17);
|
|
10927
12746
|
}
|
|
10928
12747
|
};
|
|
10929
12748
|
|
|
@@ -11211,17 +13030,98 @@ var OPENCODE_MANIFEST = {
|
|
|
11211
13030
|
]
|
|
11212
13031
|
};
|
|
11213
13032
|
|
|
13033
|
+
// src/plugins/pluginSource.ts
|
|
13034
|
+
var ALLOWED_PLUGIN_HOSTS = [
|
|
13035
|
+
"github.com",
|
|
13036
|
+
"gitlab.com",
|
|
13037
|
+
"bitbucket.org",
|
|
13038
|
+
"codeberg.org"
|
|
13039
|
+
];
|
|
13040
|
+
var SAFE_REPO_PATH = /^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/;
|
|
13041
|
+
var HAS_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]+:/;
|
|
13042
|
+
var SCP_LIKE_REMOTE = /^[^/\\]+@[^/\\]+:/;
|
|
13043
|
+
function hasControlCharacter(value) {
|
|
13044
|
+
for (let i = 0; i < value.length; i++) {
|
|
13045
|
+
const code = value.charCodeAt(i);
|
|
13046
|
+
if (code < 32 || code === 127) return true;
|
|
13047
|
+
}
|
|
13048
|
+
return false;
|
|
13049
|
+
}
|
|
13050
|
+
function assertInstallablePluginUrl(url) {
|
|
13051
|
+
if (typeof url !== "string" || url.trim() === "") {
|
|
13052
|
+
throw new Error("A plugin repository URL is required.");
|
|
13053
|
+
}
|
|
13054
|
+
if (hasControlCharacter(url)) {
|
|
13055
|
+
throw new Error("Plugin URL contains control characters.");
|
|
13056
|
+
}
|
|
13057
|
+
let parsed;
|
|
13058
|
+
try {
|
|
13059
|
+
parsed = new URL(url.trim());
|
|
13060
|
+
} catch {
|
|
13061
|
+
throw new Error(`Not a valid plugin repository URL: ${url}`);
|
|
13062
|
+
}
|
|
13063
|
+
if (parsed.protocol !== "https:") {
|
|
13064
|
+
throw new Error(
|
|
13065
|
+
`Plugin repositories must be cloned over https (got "${parsed.protocol}//"). git transport helpers and non-https schemes are not accepted.`
|
|
13066
|
+
);
|
|
13067
|
+
}
|
|
13068
|
+
if (parsed.username || parsed.password) {
|
|
13069
|
+
throw new Error("Plugin URL must not embed credentials.");
|
|
13070
|
+
}
|
|
13071
|
+
if (parsed.port) {
|
|
13072
|
+
throw new Error("Plugin URL must not specify a port.");
|
|
13073
|
+
}
|
|
13074
|
+
if (parsed.search || parsed.hash) {
|
|
13075
|
+
throw new Error("Plugin URL must not carry a query string or fragment.");
|
|
13076
|
+
}
|
|
13077
|
+
const host = parsed.hostname.toLowerCase();
|
|
13078
|
+
if (!ALLOWED_PLUGIN_HOSTS.includes(host)) {
|
|
13079
|
+
throw new Error(
|
|
13080
|
+
`Plugin host not allowed: ${host}. Allowed hosts: ${ALLOWED_PLUGIN_HOSTS.join(", ")}.`
|
|
13081
|
+
);
|
|
13082
|
+
}
|
|
13083
|
+
if (!SAFE_REPO_PATH.test(parsed.pathname)) {
|
|
13084
|
+
throw new Error(`Not a plain repository path: ${parsed.pathname}`);
|
|
13085
|
+
}
|
|
13086
|
+
return parsed;
|
|
13087
|
+
}
|
|
13088
|
+
function classifyPluginSource(source) {
|
|
13089
|
+
const trimmed = source.trim();
|
|
13090
|
+
if (trimmed.startsWith("github:")) {
|
|
13091
|
+
const repo = trimmed.slice("github:".length).replace(/\.git$/, "");
|
|
13092
|
+
return { kind: "git", url: `https://github.com/${repo}.git` };
|
|
13093
|
+
}
|
|
13094
|
+
if (HAS_SCHEME.test(trimmed) || SCP_LIKE_REMOTE.test(trimmed)) {
|
|
13095
|
+
return { kind: "git", url: trimmed };
|
|
13096
|
+
}
|
|
13097
|
+
return { kind: "path", path: source };
|
|
13098
|
+
}
|
|
13099
|
+
|
|
11214
13100
|
// src/plugins/RunnerRegistry.ts
|
|
11215
13101
|
var BUILTIN_MANIFESTS = [
|
|
11216
13102
|
CLAUDE_CODE_MANIFEST,
|
|
11217
13103
|
CODEX_MANIFEST,
|
|
11218
13104
|
OPENCODE_MANIFEST
|
|
11219
13105
|
];
|
|
13106
|
+
var RESERVED_RUNNER_NAMES = new Set(BUILTIN_MANIFESTS.map((m) => m.name.toLowerCase()));
|
|
13107
|
+
function isReservedRunnerName(name) {
|
|
13108
|
+
return RESERVED_RUNNER_NAMES.has(name.toLowerCase());
|
|
13109
|
+
}
|
|
13110
|
+
function gitClone(url, destDir) {
|
|
13111
|
+
execFileSync("git", ["clone", "--depth", "1", "--", url, destDir], {
|
|
13112
|
+
stdio: "pipe",
|
|
13113
|
+
timeout: 3e4,
|
|
13114
|
+
// A repository that demands credentials should fail, not hang on a prompt.
|
|
13115
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
13116
|
+
});
|
|
13117
|
+
}
|
|
11220
13118
|
var RunnerRegistry = class {
|
|
11221
13119
|
plugins = /* @__PURE__ */ new Map();
|
|
11222
13120
|
store;
|
|
11223
|
-
|
|
13121
|
+
clone;
|
|
13122
|
+
constructor(store, clone) {
|
|
11224
13123
|
this.store = store ?? new FsPluginStore();
|
|
13124
|
+
this.clone = clone ?? gitClone;
|
|
11225
13125
|
this.loadBuiltins();
|
|
11226
13126
|
}
|
|
11227
13127
|
loadBuiltins() {
|
|
@@ -11232,9 +13132,15 @@ var RunnerRegistry = class {
|
|
|
11232
13132
|
loadUserPlugins() {
|
|
11233
13133
|
const names = this.store.listUserPluginDirs();
|
|
11234
13134
|
for (const name of names) {
|
|
11235
|
-
|
|
13135
|
+
let pluginDir;
|
|
13136
|
+
try {
|
|
13137
|
+
pluginDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), name);
|
|
13138
|
+
} catch {
|
|
13139
|
+
continue;
|
|
13140
|
+
}
|
|
11236
13141
|
const manifest = this.store.loadManifest(pluginDir);
|
|
11237
|
-
if (!manifest) continue;
|
|
13142
|
+
if (!manifest || !isPlainPluginName(manifest.name)) continue;
|
|
13143
|
+
if (isReservedRunnerName(manifest.name)) continue;
|
|
11238
13144
|
this.plugins.set(manifest.name, {
|
|
11239
13145
|
manifest,
|
|
11240
13146
|
source: "user",
|
|
@@ -11263,7 +13169,7 @@ var RunnerRegistry = class {
|
|
|
11263
13169
|
return entry?.source === "builtin";
|
|
11264
13170
|
}
|
|
11265
13171
|
installFromPath(sourcePath) {
|
|
11266
|
-
const absPath =
|
|
13172
|
+
const absPath = path14.resolve(sourcePath);
|
|
11267
13173
|
if (!this.store.dirExists(absPath)) {
|
|
11268
13174
|
throw new Error(`Plugin source must be a directory: ${absPath}`);
|
|
11269
13175
|
}
|
|
@@ -11271,48 +13177,50 @@ var RunnerRegistry = class {
|
|
|
11271
13177
|
if (!manifest) {
|
|
11272
13178
|
throw new Error(`No valid manifest.json found in: ${absPath}`);
|
|
11273
13179
|
}
|
|
11274
|
-
|
|
11275
|
-
this.store.ensureDir(destDir);
|
|
11276
|
-
this.store.copyDir(absPath, destDir);
|
|
11277
|
-
this.plugins.set(manifest.name, {
|
|
11278
|
-
manifest,
|
|
11279
|
-
source: "user",
|
|
11280
|
-
installPath: destDir
|
|
11281
|
-
});
|
|
11282
|
-
return manifest;
|
|
13180
|
+
return this.registerInstalled(manifest, absPath);
|
|
11283
13181
|
}
|
|
11284
13182
|
installFromGit(url) {
|
|
11285
|
-
const
|
|
11286
|
-
const tmpDir =
|
|
13183
|
+
const validated = assertInstallablePluginUrl(url);
|
|
13184
|
+
const tmpDir = path14.join(os5.tmpdir(), `ordewell-plugin-${randomBytes3(12).toString("hex")}`);
|
|
11287
13185
|
this.store.ensureDir(tmpDir);
|
|
11288
13186
|
try {
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
13187
|
+
try {
|
|
13188
|
+
this.clone(validated.toString(), tmpDir);
|
|
13189
|
+
} catch (err) {
|
|
13190
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13191
|
+
throw new Error(`Failed to clone repository: ${message}`);
|
|
13192
|
+
}
|
|
13193
|
+
const contents = this.store.listDir(tmpDir);
|
|
13194
|
+
const hasManifest = contents.some((f) => f === "manifest.json");
|
|
13195
|
+
let sourceDir = tmpDir;
|
|
13196
|
+
if (!hasManifest) {
|
|
13197
|
+
const onlyEntry = contents.length === 1 ? path14.join(tmpDir, contents[0]) : void 0;
|
|
13198
|
+
if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
|
|
13199
|
+
throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
|
|
13200
|
+
}
|
|
13201
|
+
sourceDir = onlyEntry;
|
|
13202
|
+
}
|
|
13203
|
+
const manifest = this.store.loadManifest(sourceDir);
|
|
13204
|
+
if (!manifest) {
|
|
13205
|
+
throw new Error("No valid manifest.json found in cloned repository");
|
|
13206
|
+
}
|
|
13207
|
+
return this.registerInstalled(manifest, sourceDir);
|
|
13208
|
+
} finally {
|
|
11301
13209
|
this.store.removeDir(tmpDir);
|
|
11302
|
-
throw new Error(`No manifest.json found in repository: ${url}`);
|
|
11303
13210
|
}
|
|
11304
|
-
return this.finishInstall(tmpDir, repoName, tmpDir);
|
|
11305
13211
|
}
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
13212
|
+
/**
|
|
13213
|
+
* The single destination-building step both install routes share: the name is
|
|
13214
|
+
* constrained to a plain segment and the resolved destination is asserted to
|
|
13215
|
+
* be inside the plugins directory before anything is copied.
|
|
13216
|
+
*/
|
|
13217
|
+
registerInstalled(manifest, sourceDir) {
|
|
13218
|
+
if (isReservedRunnerName(manifest.name)) {
|
|
13219
|
+
throw new Error(`Cannot install a plugin named after a built-in runner: ${manifest.name}`);
|
|
11311
13220
|
}
|
|
11312
|
-
const destDir =
|
|
13221
|
+
const destDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), manifest.name);
|
|
11313
13222
|
this.store.ensureDir(destDir);
|
|
11314
13223
|
this.store.copyDir(sourceDir, destDir);
|
|
11315
|
-
this.store.removeDir(tmpDir);
|
|
11316
13224
|
this.plugins.set(manifest.name, {
|
|
11317
13225
|
manifest,
|
|
11318
13226
|
source: "user",
|
|
@@ -11333,7 +13241,8 @@ var RunnerRegistry = class {
|
|
|
11333
13241
|
this.plugins.delete(name);
|
|
11334
13242
|
}
|
|
11335
13243
|
createSkeleton(name, outputDir) {
|
|
11336
|
-
|
|
13244
|
+
assertPlainPluginName(name);
|
|
13245
|
+
const dir = path14.resolve(outputDir, name);
|
|
11337
13246
|
this.store.ensureDir(dir);
|
|
11338
13247
|
const manifest = {
|
|
11339
13248
|
name,
|
|
@@ -11365,8 +13274,8 @@ var RunnerRegistry = class {
|
|
|
11365
13274
|
]
|
|
11366
13275
|
}
|
|
11367
13276
|
};
|
|
11368
|
-
this.store.writeFile(
|
|
11369
|
-
const runSh =
|
|
13277
|
+
this.store.writeFile(path14.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
13278
|
+
const runSh = path14.join(dir, "run.sh");
|
|
11370
13279
|
const scriptContent = `#!/usr/bin/env bash
|
|
11371
13280
|
# Custom runner script for ${name}
|
|
11372
13281
|
# Receives:
|
|
@@ -11390,13 +13299,6 @@ echo "Running ${name} with prompt: $prompt"
|
|
|
11390
13299
|
return dir;
|
|
11391
13300
|
}
|
|
11392
13301
|
};
|
|
11393
|
-
function fsReaddirSync(dir) {
|
|
11394
|
-
try {
|
|
11395
|
-
return fs7.readdirSync(dir);
|
|
11396
|
-
} catch {
|
|
11397
|
-
return [];
|
|
11398
|
-
}
|
|
11399
|
-
}
|
|
11400
13302
|
function fsChmodSync(fpath, mode) {
|
|
11401
13303
|
try {
|
|
11402
13304
|
fs7.chmodSync(fpath, mode);
|
|
@@ -11406,14 +13308,14 @@ function fsChmodSync(fpath, mode) {
|
|
|
11406
13308
|
|
|
11407
13309
|
// src/utils/stateStore.ts
|
|
11408
13310
|
import * as fs8 from "fs";
|
|
11409
|
-
import * as
|
|
13311
|
+
import * as path15 from "path";
|
|
11410
13312
|
var STATE_FILE = "state.json";
|
|
11411
13313
|
function getStatePath(baseDir) {
|
|
11412
|
-
return
|
|
13314
|
+
return path15.join(getStateDir(baseDir), STATE_FILE);
|
|
11413
13315
|
}
|
|
11414
13316
|
function saveState(plan, baseDir) {
|
|
11415
13317
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
11416
|
-
ensureDir(
|
|
13318
|
+
ensureDir(path15.dirname(statePath));
|
|
11417
13319
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
11418
13320
|
fs8.writeFileSync(statePath, JSON.stringify(plan, null, 2));
|
|
11419
13321
|
}
|
|
@@ -11446,7 +13348,7 @@ function stateExists(baseDir) {
|
|
|
11446
13348
|
|
|
11447
13349
|
// src/services/SettingsService.ts
|
|
11448
13350
|
import * as fs9 from "fs";
|
|
11449
|
-
import * as
|
|
13351
|
+
import * as path16 from "path";
|
|
11450
13352
|
import * as os6 from "os";
|
|
11451
13353
|
var DEFAULTS = {
|
|
11452
13354
|
grillMe: { enabled: false },
|
|
@@ -11459,7 +13361,7 @@ var DEFAULTS = {
|
|
|
11459
13361
|
function getSettingsPath() {
|
|
11460
13362
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
11461
13363
|
if (override && override.trim()) return override.trim();
|
|
11462
|
-
return
|
|
13364
|
+
return path16.join(os6.homedir(), ".config", "ordewell", "settings.json");
|
|
11463
13365
|
}
|
|
11464
13366
|
function readPlannerModels(raw) {
|
|
11465
13367
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -11624,7 +13526,7 @@ var SettingsService = class {
|
|
|
11624
13526
|
return { ...DEFAULTS, grillMe: { ...DEFAULTS.grillMe }, tdd: { ...DEFAULTS.tdd }, prd: { ...DEFAULTS.prd }, review: { ...DEFAULTS.review }, verification: { ...DEFAULTS.verification }, researchSubagents: { ...DEFAULTS.researchSubagents } };
|
|
11625
13527
|
}
|
|
11626
13528
|
persist() {
|
|
11627
|
-
const dir =
|
|
13529
|
+
const dir = path16.dirname(this.filePath);
|
|
11628
13530
|
if (!fs9.existsSync(dir)) {
|
|
11629
13531
|
fs9.mkdirSync(dir, { recursive: true });
|
|
11630
13532
|
}
|
|
@@ -11668,6 +13570,7 @@ var PlannerModelMemory = class {
|
|
|
11668
13570
|
}
|
|
11669
13571
|
};
|
|
11670
13572
|
export {
|
|
13573
|
+
ALLOWED_PLUGIN_HOSTS,
|
|
11671
13574
|
ALL_PROVIDERS,
|
|
11672
13575
|
AUTO_COMMANDS,
|
|
11673
13576
|
AbstractRunner,
|
|
@@ -11686,6 +13589,8 @@ export {
|
|
|
11686
13589
|
CommandLineTooLongError,
|
|
11687
13590
|
ConsoleLogger,
|
|
11688
13591
|
ContextCollector,
|
|
13592
|
+
DAEMON_SUBPROTOCOL,
|
|
13593
|
+
DAEMON_TOKEN_SUBPROTOCOL_PREFIX,
|
|
11689
13594
|
DENY_ALL,
|
|
11690
13595
|
EmbeddedNewlineError,
|
|
11691
13596
|
EnvConfig,
|
|
@@ -11702,9 +13607,12 @@ export {
|
|
|
11702
13607
|
ModelResolver,
|
|
11703
13608
|
OPENCODE_MANIFEST,
|
|
11704
13609
|
ORCHESTRATOR_SHORTCUTS,
|
|
13610
|
+
ORDEWELL_SETTABLE_ENV,
|
|
11705
13611
|
OpenAiService,
|
|
11706
13612
|
OpenCodeAdapter,
|
|
11707
13613
|
PLAN_ENVELOPE_KEY,
|
|
13614
|
+
PLUGIN_NAME_PATTERN,
|
|
13615
|
+
PROVIDER_CREDENTIAL_ENV,
|
|
11708
13616
|
PROVIDER_DETECT_PRIORITY,
|
|
11709
13617
|
PROVIDER_LABEL,
|
|
11710
13618
|
PROVIDER_PRIORITY,
|
|
@@ -11719,6 +13627,8 @@ export {
|
|
|
11719
13627
|
RunnerInstallation,
|
|
11720
13628
|
RunnerRegistry,
|
|
11721
13629
|
SEARCH_EXCLUSIONS,
|
|
13630
|
+
SETTINGS_ENV_ALLOWLIST,
|
|
13631
|
+
SETTINGS_ENV_REFUSED,
|
|
11722
13632
|
STATE_DIR,
|
|
11723
13633
|
STOPPED_TOOL_RESULT,
|
|
11724
13634
|
SYMBOL_LANGUAGES,
|
|
@@ -11731,13 +13641,19 @@ export {
|
|
|
11731
13641
|
TmuxRunner,
|
|
11732
13642
|
VerdictEngine,
|
|
11733
13643
|
WINDOWS_MAX_COMMAND_LINE,
|
|
13644
|
+
WorkspaceNotAProjectError,
|
|
11734
13645
|
WorkspaceNotFoundError,
|
|
11735
13646
|
addTaskToPlan,
|
|
13647
|
+
admitSettingsEnv,
|
|
11736
13648
|
applyHeadLimit,
|
|
11737
13649
|
applyTaskOps,
|
|
13650
|
+
assertInstallablePluginUrl,
|
|
13651
|
+
assertPlainPluginName,
|
|
11738
13652
|
assertWorkspaceExists,
|
|
13653
|
+
assertWorkspaceIsProject,
|
|
11739
13654
|
augmentPromptWithPriorOutputs,
|
|
11740
13655
|
augmentedPath,
|
|
13656
|
+
bearerHeaderValue,
|
|
11741
13657
|
buildConversationSystemPrompt,
|
|
11742
13658
|
buildFallbackGrepArgs,
|
|
11743
13659
|
buildGlobArgs,
|
|
@@ -11765,7 +13681,9 @@ export {
|
|
|
11765
13681
|
classifyCommand,
|
|
11766
13682
|
classifyOutcome,
|
|
11767
13683
|
classifyPlannerReply,
|
|
13684
|
+
classifyPluginSource,
|
|
11768
13685
|
clearAugmentedPathCache,
|
|
13686
|
+
clearDaemonToken,
|
|
11769
13687
|
clearResearchShellCache,
|
|
11770
13688
|
clearState,
|
|
11771
13689
|
clipboardCopyCommand,
|
|
@@ -11777,6 +13695,7 @@ export {
|
|
|
11777
13695
|
createAiService,
|
|
11778
13696
|
createEmptyPlan,
|
|
11779
13697
|
createTask,
|
|
13698
|
+
daemonTokenPath,
|
|
11780
13699
|
defaultLogger,
|
|
11781
13700
|
definitionPattern,
|
|
11782
13701
|
deleteSession,
|
|
@@ -11787,6 +13706,7 @@ export {
|
|
|
11787
13706
|
emptyWarnings,
|
|
11788
13707
|
enabledRunners,
|
|
11789
13708
|
ensureDir,
|
|
13709
|
+
ensureStateDirIgnored,
|
|
11790
13710
|
escapeControlCharsInStrings,
|
|
11791
13711
|
executionLogBlock,
|
|
11792
13712
|
executionSummary,
|
|
@@ -11794,6 +13714,7 @@ export {
|
|
|
11794
13714
|
extractObjectWithBalance,
|
|
11795
13715
|
extractObjectsWithKey,
|
|
11796
13716
|
extractPrdBlock,
|
|
13717
|
+
extractPresentedToken,
|
|
11797
13718
|
fetchAllProviderModels,
|
|
11798
13719
|
filterFallbackByAnchoredInclude,
|
|
11799
13720
|
filterModelsForPrompt,
|
|
@@ -11811,6 +13732,9 @@ export {
|
|
|
11811
13732
|
isCliProvider,
|
|
11812
13733
|
isExecutableResolved,
|
|
11813
13734
|
isOpenAiProvider,
|
|
13735
|
+
isPlainPluginName,
|
|
13736
|
+
isReservedRunnerName,
|
|
13737
|
+
isValidManifest,
|
|
11814
13738
|
killTree,
|
|
11815
13739
|
knownModelId,
|
|
11816
13740
|
languageForId,
|
|
@@ -11823,6 +13747,8 @@ export {
|
|
|
11823
13747
|
migrateLegacyPlan,
|
|
11824
13748
|
migratePlanState,
|
|
11825
13749
|
migrateTask,
|
|
13750
|
+
mintDaemonToken,
|
|
13751
|
+
mintSessionId,
|
|
11826
13752
|
modelContextBlock,
|
|
11827
13753
|
modifyValidationFeedback,
|
|
11828
13754
|
normalizeAgentArgs,
|
|
@@ -11838,6 +13764,7 @@ export {
|
|
|
11838
13764
|
providerForRunner,
|
|
11839
13765
|
reEmitPlanPrompt,
|
|
11840
13766
|
reEmitTaskOpsPrompt,
|
|
13767
|
+
readDaemonToken,
|
|
11841
13768
|
referencePattern,
|
|
11842
13769
|
removeTaskFromPlan,
|
|
11843
13770
|
renderPlanMap,
|
|
@@ -11849,6 +13776,7 @@ export {
|
|
|
11849
13776
|
resolveArgs,
|
|
11850
13777
|
resolveDefaultMode,
|
|
11851
13778
|
resolveModelShortcut,
|
|
13779
|
+
resolvePluginInstallDir,
|
|
11852
13780
|
resolveProvider,
|
|
11853
13781
|
resolveProviderFromPrefix,
|
|
11854
13782
|
resolveResearchShell,
|
|
@@ -11879,6 +13807,8 @@ export {
|
|
|
11879
13807
|
tmuxSocketName,
|
|
11880
13808
|
tmuxWindowName,
|
|
11881
13809
|
toOrchestratorOptions,
|
|
13810
|
+
tokenSubprotocols,
|
|
13811
|
+
tokensMatch,
|
|
11882
13812
|
truncatedPlanReEmitPrompt,
|
|
11883
13813
|
updateTaskInPlan,
|
|
11884
13814
|
validateModifiedPlan,
|