@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.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
ALLOWED_PLUGIN_HOSTS: () => ALLOWED_PLUGIN_HOSTS,
|
|
33
34
|
ALL_PROVIDERS: () => ALL_PROVIDERS,
|
|
34
35
|
AUTO_COMMANDS: () => AUTO_COMMANDS,
|
|
35
36
|
AbstractRunner: () => AbstractRunner,
|
|
@@ -48,6 +49,8 @@ __export(index_exports, {
|
|
|
48
49
|
CommandLineTooLongError: () => CommandLineTooLongError,
|
|
49
50
|
ConsoleLogger: () => ConsoleLogger,
|
|
50
51
|
ContextCollector: () => ContextCollector,
|
|
52
|
+
DAEMON_SUBPROTOCOL: () => DAEMON_SUBPROTOCOL,
|
|
53
|
+
DAEMON_TOKEN_SUBPROTOCOL_PREFIX: () => DAEMON_TOKEN_SUBPROTOCOL_PREFIX,
|
|
51
54
|
DENY_ALL: () => DENY_ALL,
|
|
52
55
|
EmbeddedNewlineError: () => EmbeddedNewlineError,
|
|
53
56
|
EnvConfig: () => EnvConfig,
|
|
@@ -64,9 +67,12 @@ __export(index_exports, {
|
|
|
64
67
|
ModelResolver: () => ModelResolver,
|
|
65
68
|
OPENCODE_MANIFEST: () => OPENCODE_MANIFEST,
|
|
66
69
|
ORCHESTRATOR_SHORTCUTS: () => ORCHESTRATOR_SHORTCUTS,
|
|
70
|
+
ORDEWELL_SETTABLE_ENV: () => ORDEWELL_SETTABLE_ENV,
|
|
67
71
|
OpenAiService: () => OpenAiService,
|
|
68
72
|
OpenCodeAdapter: () => OpenCodeAdapter,
|
|
69
73
|
PLAN_ENVELOPE_KEY: () => PLAN_ENVELOPE_KEY,
|
|
74
|
+
PLUGIN_NAME_PATTERN: () => PLUGIN_NAME_PATTERN,
|
|
75
|
+
PROVIDER_CREDENTIAL_ENV: () => PROVIDER_CREDENTIAL_ENV,
|
|
70
76
|
PROVIDER_DETECT_PRIORITY: () => PROVIDER_DETECT_PRIORITY,
|
|
71
77
|
PROVIDER_LABEL: () => PROVIDER_LABEL,
|
|
72
78
|
PROVIDER_PRIORITY: () => PROVIDER_PRIORITY,
|
|
@@ -81,6 +87,8 @@ __export(index_exports, {
|
|
|
81
87
|
RunnerInstallation: () => RunnerInstallation,
|
|
82
88
|
RunnerRegistry: () => RunnerRegistry,
|
|
83
89
|
SEARCH_EXCLUSIONS: () => SEARCH_EXCLUSIONS,
|
|
90
|
+
SETTINGS_ENV_ALLOWLIST: () => SETTINGS_ENV_ALLOWLIST,
|
|
91
|
+
SETTINGS_ENV_REFUSED: () => SETTINGS_ENV_REFUSED,
|
|
84
92
|
STATE_DIR: () => STATE_DIR,
|
|
85
93
|
STOPPED_TOOL_RESULT: () => STOPPED_TOOL_RESULT,
|
|
86
94
|
SYMBOL_LANGUAGES: () => SYMBOL_LANGUAGES,
|
|
@@ -93,13 +101,19 @@ __export(index_exports, {
|
|
|
93
101
|
TmuxRunner: () => TmuxRunner,
|
|
94
102
|
VerdictEngine: () => VerdictEngine,
|
|
95
103
|
WINDOWS_MAX_COMMAND_LINE: () => WINDOWS_MAX_COMMAND_LINE,
|
|
104
|
+
WorkspaceNotAProjectError: () => WorkspaceNotAProjectError,
|
|
96
105
|
WorkspaceNotFoundError: () => WorkspaceNotFoundError,
|
|
97
106
|
addTaskToPlan: () => addTaskToPlan,
|
|
107
|
+
admitSettingsEnv: () => admitSettingsEnv,
|
|
98
108
|
applyHeadLimit: () => applyHeadLimit,
|
|
99
109
|
applyTaskOps: () => applyTaskOps,
|
|
110
|
+
assertInstallablePluginUrl: () => assertInstallablePluginUrl,
|
|
111
|
+
assertPlainPluginName: () => assertPlainPluginName,
|
|
100
112
|
assertWorkspaceExists: () => assertWorkspaceExists,
|
|
113
|
+
assertWorkspaceIsProject: () => assertWorkspaceIsProject,
|
|
101
114
|
augmentPromptWithPriorOutputs: () => augmentPromptWithPriorOutputs,
|
|
102
115
|
augmentedPath: () => augmentedPath,
|
|
116
|
+
bearerHeaderValue: () => bearerHeaderValue,
|
|
103
117
|
buildConversationSystemPrompt: () => buildConversationSystemPrompt,
|
|
104
118
|
buildFallbackGrepArgs: () => buildFallbackGrepArgs,
|
|
105
119
|
buildGlobArgs: () => buildGlobArgs,
|
|
@@ -127,7 +141,9 @@ __export(index_exports, {
|
|
|
127
141
|
classifyCommand: () => classifyCommand,
|
|
128
142
|
classifyOutcome: () => classifyOutcome,
|
|
129
143
|
classifyPlannerReply: () => classifyPlannerReply,
|
|
144
|
+
classifyPluginSource: () => classifyPluginSource,
|
|
130
145
|
clearAugmentedPathCache: () => clearAugmentedPathCache,
|
|
146
|
+
clearDaemonToken: () => clearDaemonToken,
|
|
131
147
|
clearResearchShellCache: () => clearResearchShellCache,
|
|
132
148
|
clearState: () => clearState,
|
|
133
149
|
clipboardCopyCommand: () => clipboardCopyCommand,
|
|
@@ -139,6 +155,7 @@ __export(index_exports, {
|
|
|
139
155
|
createAiService: () => createAiService,
|
|
140
156
|
createEmptyPlan: () => createEmptyPlan,
|
|
141
157
|
createTask: () => createTask,
|
|
158
|
+
daemonTokenPath: () => daemonTokenPath,
|
|
142
159
|
defaultLogger: () => defaultLogger,
|
|
143
160
|
definitionPattern: () => definitionPattern,
|
|
144
161
|
deleteSession: () => deleteSession,
|
|
@@ -149,6 +166,7 @@ __export(index_exports, {
|
|
|
149
166
|
emptyWarnings: () => emptyWarnings,
|
|
150
167
|
enabledRunners: () => enabledRunners,
|
|
151
168
|
ensureDir: () => ensureDir,
|
|
169
|
+
ensureStateDirIgnored: () => ensureStateDirIgnored,
|
|
152
170
|
escapeControlCharsInStrings: () => escapeControlCharsInStrings,
|
|
153
171
|
executionLogBlock: () => executionLogBlock,
|
|
154
172
|
executionSummary: () => executionSummary,
|
|
@@ -156,6 +174,7 @@ __export(index_exports, {
|
|
|
156
174
|
extractObjectWithBalance: () => extractObjectWithBalance,
|
|
157
175
|
extractObjectsWithKey: () => extractObjectsWithKey,
|
|
158
176
|
extractPrdBlock: () => extractPrdBlock,
|
|
177
|
+
extractPresentedToken: () => extractPresentedToken,
|
|
159
178
|
fetchAllProviderModels: () => fetchAllProviderModels,
|
|
160
179
|
filterFallbackByAnchoredInclude: () => filterFallbackByAnchoredInclude,
|
|
161
180
|
filterModelsForPrompt: () => filterModelsForPrompt,
|
|
@@ -173,6 +192,9 @@ __export(index_exports, {
|
|
|
173
192
|
isCliProvider: () => isCliProvider,
|
|
174
193
|
isExecutableResolved: () => isExecutableResolved,
|
|
175
194
|
isOpenAiProvider: () => isOpenAiProvider,
|
|
195
|
+
isPlainPluginName: () => isPlainPluginName,
|
|
196
|
+
isReservedRunnerName: () => isReservedRunnerName,
|
|
197
|
+
isValidManifest: () => isValidManifest,
|
|
176
198
|
killTree: () => killTree,
|
|
177
199
|
knownModelId: () => knownModelId,
|
|
178
200
|
languageForId: () => languageForId,
|
|
@@ -185,6 +207,8 @@ __export(index_exports, {
|
|
|
185
207
|
migrateLegacyPlan: () => migrateLegacyPlan,
|
|
186
208
|
migratePlanState: () => migratePlanState,
|
|
187
209
|
migrateTask: () => migrateTask,
|
|
210
|
+
mintDaemonToken: () => mintDaemonToken,
|
|
211
|
+
mintSessionId: () => mintSessionId,
|
|
188
212
|
modelContextBlock: () => modelContextBlock,
|
|
189
213
|
modifyValidationFeedback: () => modifyValidationFeedback,
|
|
190
214
|
normalizeAgentArgs: () => normalizeAgentArgs,
|
|
@@ -200,6 +224,7 @@ __export(index_exports, {
|
|
|
200
224
|
providerForRunner: () => providerForRunner,
|
|
201
225
|
reEmitPlanPrompt: () => reEmitPlanPrompt,
|
|
202
226
|
reEmitTaskOpsPrompt: () => reEmitTaskOpsPrompt,
|
|
227
|
+
readDaemonToken: () => readDaemonToken,
|
|
203
228
|
referencePattern: () => referencePattern,
|
|
204
229
|
removeTaskFromPlan: () => removeTaskFromPlan,
|
|
205
230
|
renderPlanMap: () => renderPlanMap,
|
|
@@ -211,6 +236,7 @@ __export(index_exports, {
|
|
|
211
236
|
resolveArgs: () => resolveArgs,
|
|
212
237
|
resolveDefaultMode: () => resolveDefaultMode,
|
|
213
238
|
resolveModelShortcut: () => resolveModelShortcut,
|
|
239
|
+
resolvePluginInstallDir: () => resolvePluginInstallDir,
|
|
214
240
|
resolveProvider: () => resolveProvider,
|
|
215
241
|
resolveProviderFromPrefix: () => resolveProviderFromPrefix,
|
|
216
242
|
resolveResearchShell: () => resolveResearchShell,
|
|
@@ -241,6 +267,8 @@ __export(index_exports, {
|
|
|
241
267
|
tmuxSocketName: () => tmuxSocketName,
|
|
242
268
|
tmuxWindowName: () => tmuxWindowName,
|
|
243
269
|
toOrchestratorOptions: () => toOrchestratorOptions,
|
|
270
|
+
tokenSubprotocols: () => tokenSubprotocols,
|
|
271
|
+
tokensMatch: () => tokensMatch,
|
|
244
272
|
truncatedPlanReEmitPrompt: () => truncatedPlanReEmitPrompt,
|
|
245
273
|
updateTaskInPlan: () => updateTaskInPlan,
|
|
246
274
|
validateModifiedPlan: () => validateModifiedPlan,
|
|
@@ -605,7 +633,6 @@ var AUTO_COMMANDS = [
|
|
|
605
633
|
"pwd",
|
|
606
634
|
"which",
|
|
607
635
|
"type",
|
|
608
|
-
"env",
|
|
609
636
|
"uname",
|
|
610
637
|
"whoami",
|
|
611
638
|
"cut",
|
|
@@ -616,13 +643,1233 @@ var AUTO_COMMANDS = [
|
|
|
616
643
|
"jq",
|
|
617
644
|
"yq"
|
|
618
645
|
];
|
|
646
|
+
var UNIVERSAL_FLAGS = ["--help", "--version"];
|
|
647
|
+
var COUNT_FLAG = /^-\d+$/;
|
|
648
|
+
var FLAG_POLICY = {
|
|
649
|
+
ls: {
|
|
650
|
+
cluster: true,
|
|
651
|
+
booleans: [
|
|
652
|
+
"-1",
|
|
653
|
+
"-a",
|
|
654
|
+
"-A",
|
|
655
|
+
"-b",
|
|
656
|
+
"-c",
|
|
657
|
+
"-C",
|
|
658
|
+
"-d",
|
|
659
|
+
"-D",
|
|
660
|
+
"-f",
|
|
661
|
+
"-F",
|
|
662
|
+
"-g",
|
|
663
|
+
"-G",
|
|
664
|
+
"-h",
|
|
665
|
+
"-H",
|
|
666
|
+
"-i",
|
|
667
|
+
"-k",
|
|
668
|
+
"-l",
|
|
669
|
+
"-L",
|
|
670
|
+
"-m",
|
|
671
|
+
"-n",
|
|
672
|
+
"-N",
|
|
673
|
+
"-o",
|
|
674
|
+
"-p",
|
|
675
|
+
"-q",
|
|
676
|
+
"-Q",
|
|
677
|
+
"-r",
|
|
678
|
+
"-R",
|
|
679
|
+
"-s",
|
|
680
|
+
"-S",
|
|
681
|
+
"-t",
|
|
682
|
+
"-u",
|
|
683
|
+
"-U",
|
|
684
|
+
"-v",
|
|
685
|
+
"-x",
|
|
686
|
+
"-X",
|
|
687
|
+
"-Z",
|
|
688
|
+
"--all",
|
|
689
|
+
"--almost-all",
|
|
690
|
+
"--author",
|
|
691
|
+
"--escape",
|
|
692
|
+
"--classify",
|
|
693
|
+
"--file-type",
|
|
694
|
+
"--full-time",
|
|
695
|
+
"--no-group",
|
|
696
|
+
"--human-readable",
|
|
697
|
+
"--si",
|
|
698
|
+
"--dereference-command-line",
|
|
699
|
+
"--inode",
|
|
700
|
+
"--kibibytes",
|
|
701
|
+
"--dereference",
|
|
702
|
+
"--numeric-uid-gid",
|
|
703
|
+
"--literal",
|
|
704
|
+
"--hide-control-chars",
|
|
705
|
+
"--show-control-chars",
|
|
706
|
+
"--quote-name",
|
|
707
|
+
"--reverse",
|
|
708
|
+
"--recursive",
|
|
709
|
+
"--size",
|
|
710
|
+
"--directory",
|
|
711
|
+
"--group-directories-first",
|
|
712
|
+
"--context",
|
|
713
|
+
"--zero"
|
|
714
|
+
],
|
|
715
|
+
values: [
|
|
716
|
+
"-w",
|
|
717
|
+
"-I",
|
|
718
|
+
"-T",
|
|
719
|
+
"--width",
|
|
720
|
+
"--ignore",
|
|
721
|
+
"--hide",
|
|
722
|
+
"--block-size",
|
|
723
|
+
"--color",
|
|
724
|
+
"--format",
|
|
725
|
+
"--sort",
|
|
726
|
+
"--time",
|
|
727
|
+
"--time-style",
|
|
728
|
+
"--indicator-style",
|
|
729
|
+
"--quoting-style",
|
|
730
|
+
"--tabsize"
|
|
731
|
+
]
|
|
732
|
+
},
|
|
733
|
+
tree: {
|
|
734
|
+
cluster: true,
|
|
735
|
+
// `-o` is absent on purpose: it is tree's write-to-a-file flag, which the
|
|
736
|
+
// redirect check never sees because there is no redirect.
|
|
737
|
+
booleans: [
|
|
738
|
+
"-a",
|
|
739
|
+
"-d",
|
|
740
|
+
"-f",
|
|
741
|
+
"-i",
|
|
742
|
+
"-l",
|
|
743
|
+
"-x",
|
|
744
|
+
"-C",
|
|
745
|
+
"-n",
|
|
746
|
+
"-p",
|
|
747
|
+
"-s",
|
|
748
|
+
"-h",
|
|
749
|
+
"-u",
|
|
750
|
+
"-g",
|
|
751
|
+
"-D",
|
|
752
|
+
"-t",
|
|
753
|
+
"-c",
|
|
754
|
+
"-r",
|
|
755
|
+
"-F",
|
|
756
|
+
"-q",
|
|
757
|
+
"-N",
|
|
758
|
+
"-Q",
|
|
759
|
+
"-v",
|
|
760
|
+
"-J",
|
|
761
|
+
"-X",
|
|
762
|
+
"-Z",
|
|
763
|
+
"--noreport",
|
|
764
|
+
"--dirsfirst",
|
|
765
|
+
"--du",
|
|
766
|
+
"--prune",
|
|
767
|
+
"--matchdirs",
|
|
768
|
+
"--inodes",
|
|
769
|
+
"--device",
|
|
770
|
+
"--si",
|
|
771
|
+
"--gitignore",
|
|
772
|
+
"--ignore-case",
|
|
773
|
+
"--filesfirst",
|
|
774
|
+
"--nolinks",
|
|
775
|
+
"--hintro"
|
|
776
|
+
],
|
|
777
|
+
values: [
|
|
778
|
+
"-L",
|
|
779
|
+
"-P",
|
|
780
|
+
"-I",
|
|
781
|
+
"-H",
|
|
782
|
+
"--filelimit",
|
|
783
|
+
"--timefmt",
|
|
784
|
+
"--charset",
|
|
785
|
+
"--sort",
|
|
786
|
+
"--gitfile",
|
|
787
|
+
"--info",
|
|
788
|
+
"--prefix"
|
|
789
|
+
]
|
|
790
|
+
},
|
|
791
|
+
git: {
|
|
792
|
+
cluster: true,
|
|
793
|
+
// Absent on purpose, and each for a reason that was demonstrated rather than
|
|
794
|
+
// guessed at:
|
|
795
|
+
// -c, --config-env set configuration inline, and several configuration
|
|
796
|
+
// keys name a program to run (`core.pager`, `core.editor`,
|
|
797
|
+
// `diff.external`), so this is an execution flag with one
|
|
798
|
+
// indirection in front of it.
|
|
799
|
+
// --exec-path redirects where git finds its helper programs; a
|
|
800
|
+
// fabricated helper ran during an ordinary remote listing.
|
|
801
|
+
// -O, --open-files-in-pager runs an arbitrary named program over search hits.
|
|
802
|
+
// --upload-pack, --receive-pack name the program run on the other end.
|
|
803
|
+
// --textconv, --ext-diff run filters the repository itself configures.
|
|
804
|
+
// --git-dir, --work-tree repoint git at a tree whose configuration is not
|
|
805
|
+
// the one the developer is looking at.
|
|
806
|
+
// -o, --output write a file. `git ls-files -o` is a legitimate spelling
|
|
807
|
+
// of `--others`, but `git archive -o` writes, and the
|
|
808
|
+
// long spelling stays available for the read.
|
|
809
|
+
booleans: [
|
|
810
|
+
"-a",
|
|
811
|
+
"-b",
|
|
812
|
+
"-E",
|
|
813
|
+
"-F",
|
|
814
|
+
"-h",
|
|
815
|
+
"-H",
|
|
816
|
+
"-i",
|
|
817
|
+
"-I",
|
|
818
|
+
"-l",
|
|
819
|
+
"-p",
|
|
820
|
+
"-P",
|
|
821
|
+
"-q",
|
|
822
|
+
"-r",
|
|
823
|
+
"-R",
|
|
824
|
+
"-s",
|
|
825
|
+
"-t",
|
|
826
|
+
"-u",
|
|
827
|
+
"-v",
|
|
828
|
+
"-w",
|
|
829
|
+
"-z",
|
|
830
|
+
"--oneline",
|
|
831
|
+
"--graph",
|
|
832
|
+
"--stat",
|
|
833
|
+
"--shortstat",
|
|
834
|
+
"--numstat",
|
|
835
|
+
"--dirstat",
|
|
836
|
+
"--summary",
|
|
837
|
+
"--name-only",
|
|
838
|
+
"--name-status",
|
|
839
|
+
"--raw",
|
|
840
|
+
"--patch",
|
|
841
|
+
"--no-patch",
|
|
842
|
+
"--patch-with-stat",
|
|
843
|
+
"--cached",
|
|
844
|
+
"--staged",
|
|
845
|
+
"--porcelain",
|
|
846
|
+
"--short",
|
|
847
|
+
"--long",
|
|
848
|
+
"--branch",
|
|
849
|
+
"--show-stash",
|
|
850
|
+
"--show-current",
|
|
851
|
+
"--all",
|
|
852
|
+
"--tags",
|
|
853
|
+
"--heads",
|
|
854
|
+
"--remotes",
|
|
855
|
+
"--list",
|
|
856
|
+
"--verbose",
|
|
857
|
+
"--quiet",
|
|
858
|
+
"--abbrev-ref",
|
|
859
|
+
"--count",
|
|
860
|
+
"--reverse",
|
|
861
|
+
"--first-parent",
|
|
862
|
+
"--no-merges",
|
|
863
|
+
"--merges",
|
|
864
|
+
"--follow",
|
|
865
|
+
"--full-history",
|
|
866
|
+
"--simplify-merges",
|
|
867
|
+
"--sparse",
|
|
868
|
+
"--dense",
|
|
869
|
+
"--ancestry-path",
|
|
870
|
+
"--left-right",
|
|
871
|
+
"--cherry",
|
|
872
|
+
"--cherry-pick",
|
|
873
|
+
"--cherry-mark",
|
|
874
|
+
"--boundary",
|
|
875
|
+
"--topo-order",
|
|
876
|
+
"--date-order",
|
|
877
|
+
"--author-date-order",
|
|
878
|
+
"--relative-date",
|
|
879
|
+
"--parents",
|
|
880
|
+
"--children",
|
|
881
|
+
"--timestamp",
|
|
882
|
+
"--no-walk",
|
|
883
|
+
"--do-walk",
|
|
884
|
+
"--decorate",
|
|
885
|
+
"--no-decorate",
|
|
886
|
+
"--abbrev-commit",
|
|
887
|
+
"--no-abbrev-commit",
|
|
888
|
+
"--abbrev",
|
|
889
|
+
"--no-abbrev",
|
|
890
|
+
"--color",
|
|
891
|
+
"--no-color",
|
|
892
|
+
"--pretty",
|
|
893
|
+
"--format",
|
|
894
|
+
"--expand-tabs",
|
|
895
|
+
"--no-expand-tabs",
|
|
896
|
+
"--numbered",
|
|
897
|
+
"--email",
|
|
898
|
+
"--no-notes",
|
|
899
|
+
"--notes",
|
|
900
|
+
"--show-signature",
|
|
901
|
+
"--find-renames",
|
|
902
|
+
"--find-copies",
|
|
903
|
+
"--find-copies-harder",
|
|
904
|
+
"--break-rewrites",
|
|
905
|
+
"--no-renames",
|
|
906
|
+
"--irreversible-delete",
|
|
907
|
+
"--full-index",
|
|
908
|
+
"--binary",
|
|
909
|
+
"--text",
|
|
910
|
+
"--check",
|
|
911
|
+
"--exit-code",
|
|
912
|
+
"--word-diff",
|
|
913
|
+
"--function-context",
|
|
914
|
+
"--ignore-all-space",
|
|
915
|
+
"--ignore-space-change",
|
|
916
|
+
"--ignore-space-at-eol",
|
|
917
|
+
"--ignore-blank-lines",
|
|
918
|
+
"--ignore-cr-at-eol",
|
|
919
|
+
"--no-prefix",
|
|
920
|
+
"--default-prefix",
|
|
921
|
+
"--no-textconv",
|
|
922
|
+
"--no-ext-diff",
|
|
923
|
+
"--submodule",
|
|
924
|
+
"--ignore-submodules",
|
|
925
|
+
"--recurse-submodules",
|
|
926
|
+
"--no-recurse-submodules",
|
|
927
|
+
"--others",
|
|
928
|
+
"--deleted",
|
|
929
|
+
"--modified",
|
|
930
|
+
"--unmerged",
|
|
931
|
+
"--stage",
|
|
932
|
+
"--killed",
|
|
933
|
+
"--ignored",
|
|
934
|
+
"--exclude-standard",
|
|
935
|
+
"--error-unmatch",
|
|
936
|
+
"--full-name",
|
|
937
|
+
"--directory",
|
|
938
|
+
"--no-empty-directory",
|
|
939
|
+
"--untracked-files",
|
|
940
|
+
"--no-optional-locks",
|
|
941
|
+
"--no-pager",
|
|
942
|
+
"--paginate",
|
|
943
|
+
"--bare",
|
|
944
|
+
"--literal-pathspecs",
|
|
945
|
+
"--glob-pathspecs",
|
|
946
|
+
"--noglob-pathspecs",
|
|
947
|
+
"--icase-pathspecs",
|
|
948
|
+
"--line-number",
|
|
949
|
+
"--column",
|
|
950
|
+
"--heading",
|
|
951
|
+
"--no-index",
|
|
952
|
+
"--untracked",
|
|
953
|
+
"--no-recursive",
|
|
954
|
+
"--name-rev",
|
|
955
|
+
"--root",
|
|
956
|
+
"--dirty",
|
|
957
|
+
"--broken",
|
|
958
|
+
"--always",
|
|
959
|
+
"--merged",
|
|
960
|
+
"--no-merged",
|
|
961
|
+
"--show-toplevel",
|
|
962
|
+
"--show-cdup",
|
|
963
|
+
"--git-common-dir",
|
|
964
|
+
"--absolute-git-dir",
|
|
965
|
+
"--is-inside-work-tree",
|
|
966
|
+
"--is-inside-git-dir",
|
|
967
|
+
"--is-bare-repository",
|
|
968
|
+
"--symbolic",
|
|
969
|
+
"--symbolic-full-name",
|
|
970
|
+
"--verify",
|
|
971
|
+
"--short-hash",
|
|
972
|
+
"--textual",
|
|
973
|
+
"--batch",
|
|
974
|
+
"--batch-check",
|
|
975
|
+
"--batch-all-objects",
|
|
976
|
+
"--buffer",
|
|
977
|
+
"--follow-symlinks",
|
|
978
|
+
"--use-mailmap"
|
|
979
|
+
],
|
|
980
|
+
values: [
|
|
981
|
+
"-n",
|
|
982
|
+
"-C",
|
|
983
|
+
"-B",
|
|
984
|
+
"-M",
|
|
985
|
+
"-L",
|
|
986
|
+
"-S",
|
|
987
|
+
"-G",
|
|
988
|
+
"-U",
|
|
989
|
+
"-e",
|
|
990
|
+
"-m",
|
|
991
|
+
"-f",
|
|
992
|
+
"-g",
|
|
993
|
+
"-x",
|
|
994
|
+
"-X",
|
|
995
|
+
"-W",
|
|
996
|
+
"--max-count",
|
|
997
|
+
"--skip",
|
|
998
|
+
"--since",
|
|
999
|
+
"--after",
|
|
1000
|
+
"--until",
|
|
1001
|
+
"--before",
|
|
1002
|
+
"--author",
|
|
1003
|
+
"--grep",
|
|
1004
|
+
"--grep-reflog",
|
|
1005
|
+
"--committer",
|
|
1006
|
+
"--date",
|
|
1007
|
+
"--diff-filter",
|
|
1008
|
+
"--unified",
|
|
1009
|
+
"--stat-width",
|
|
1010
|
+
"--stat-name-width",
|
|
1011
|
+
"--stat-count",
|
|
1012
|
+
"--word-diff-regex",
|
|
1013
|
+
"--line-prefix",
|
|
1014
|
+
"--src-prefix",
|
|
1015
|
+
"--dst-prefix",
|
|
1016
|
+
"--pickaxe-regex",
|
|
1017
|
+
"--anchored",
|
|
1018
|
+
"--color-moved",
|
|
1019
|
+
"--color-words",
|
|
1020
|
+
"--inter-hunk-context",
|
|
1021
|
+
"--max-parents",
|
|
1022
|
+
"--min-parents",
|
|
1023
|
+
"--simplify-by-decoration",
|
|
1024
|
+
"--glob",
|
|
1025
|
+
"--exclude",
|
|
1026
|
+
"--sort",
|
|
1027
|
+
"--contains",
|
|
1028
|
+
"--points-at",
|
|
1029
|
+
"--decorate-refs",
|
|
1030
|
+
"--decorate-refs-exclude",
|
|
1031
|
+
"--encoding",
|
|
1032
|
+
"--context",
|
|
1033
|
+
"--max-depth",
|
|
1034
|
+
// `--filters` is absent from this list on purpose: it runs the clean and
|
|
1035
|
+
// smudge filters the repository under research configures, which is the
|
|
1036
|
+
// same execution vector as the configuration flag above with a different
|
|
1037
|
+
// spelling.
|
|
1038
|
+
"--and",
|
|
1039
|
+
"--or",
|
|
1040
|
+
"--not",
|
|
1041
|
+
"--all-match",
|
|
1042
|
+
"--threads",
|
|
1043
|
+
"--path"
|
|
1044
|
+
],
|
|
1045
|
+
patterns: [COUNT_FLAG]
|
|
1046
|
+
},
|
|
1047
|
+
wc: {
|
|
1048
|
+
cluster: true,
|
|
1049
|
+
booleans: [
|
|
1050
|
+
"-c",
|
|
1051
|
+
"-l",
|
|
1052
|
+
"-m",
|
|
1053
|
+
"-w",
|
|
1054
|
+
"-L",
|
|
1055
|
+
"--bytes",
|
|
1056
|
+
"--chars",
|
|
1057
|
+
"--lines",
|
|
1058
|
+
"--words",
|
|
1059
|
+
"--max-line-length",
|
|
1060
|
+
"--total"
|
|
1061
|
+
]
|
|
1062
|
+
},
|
|
1063
|
+
du: {
|
|
1064
|
+
cluster: true,
|
|
1065
|
+
booleans: [
|
|
1066
|
+
"-0",
|
|
1067
|
+
"-a",
|
|
1068
|
+
"-b",
|
|
1069
|
+
"-c",
|
|
1070
|
+
"-D",
|
|
1071
|
+
"-h",
|
|
1072
|
+
"-H",
|
|
1073
|
+
"-k",
|
|
1074
|
+
"-l",
|
|
1075
|
+
"-L",
|
|
1076
|
+
"-m",
|
|
1077
|
+
"-P",
|
|
1078
|
+
"-s",
|
|
1079
|
+
"-S",
|
|
1080
|
+
"-x",
|
|
1081
|
+
"--all",
|
|
1082
|
+
"--apparent-size",
|
|
1083
|
+
"--bytes",
|
|
1084
|
+
"--total",
|
|
1085
|
+
"--dereference-args",
|
|
1086
|
+
"--human-readable",
|
|
1087
|
+
"--si",
|
|
1088
|
+
"--inodes",
|
|
1089
|
+
"--count-links",
|
|
1090
|
+
"--dereference",
|
|
1091
|
+
"--no-dereference",
|
|
1092
|
+
"--separate-dirs",
|
|
1093
|
+
"--summarize",
|
|
1094
|
+
"--one-file-system",
|
|
1095
|
+
"--null"
|
|
1096
|
+
],
|
|
1097
|
+
values: [
|
|
1098
|
+
"-d",
|
|
1099
|
+
"-t",
|
|
1100
|
+
"-B",
|
|
1101
|
+
"-X",
|
|
1102
|
+
"--max-depth",
|
|
1103
|
+
"--threshold",
|
|
1104
|
+
"--block-size",
|
|
1105
|
+
"--exclude",
|
|
1106
|
+
"--exclude-from",
|
|
1107
|
+
"--time",
|
|
1108
|
+
"--time-style",
|
|
1109
|
+
"--files0-from"
|
|
1110
|
+
]
|
|
1111
|
+
},
|
|
1112
|
+
df: {
|
|
1113
|
+
cluster: true,
|
|
1114
|
+
booleans: [
|
|
1115
|
+
"-a",
|
|
1116
|
+
"-h",
|
|
1117
|
+
"-H",
|
|
1118
|
+
"-i",
|
|
1119
|
+
"-k",
|
|
1120
|
+
"-l",
|
|
1121
|
+
"-m",
|
|
1122
|
+
"-P",
|
|
1123
|
+
"-T",
|
|
1124
|
+
"-v",
|
|
1125
|
+
"--all",
|
|
1126
|
+
"--human-readable",
|
|
1127
|
+
"--si",
|
|
1128
|
+
"--inodes",
|
|
1129
|
+
"--local",
|
|
1130
|
+
"--portability",
|
|
1131
|
+
"--print-type",
|
|
1132
|
+
"--total",
|
|
1133
|
+
"--sync",
|
|
1134
|
+
"--no-sync"
|
|
1135
|
+
],
|
|
1136
|
+
values: ["-B", "-t", "-x", "--block-size", "--type", "--exclude-type"]
|
|
1137
|
+
},
|
|
1138
|
+
file: {
|
|
1139
|
+
cluster: true,
|
|
1140
|
+
// `-C`/`--compile` is absent: it writes a compiled magic file.
|
|
1141
|
+
booleans: [
|
|
1142
|
+
"-b",
|
|
1143
|
+
"-c",
|
|
1144
|
+
"-h",
|
|
1145
|
+
"-i",
|
|
1146
|
+
"-k",
|
|
1147
|
+
"-L",
|
|
1148
|
+
"-n",
|
|
1149
|
+
"-N",
|
|
1150
|
+
"-p",
|
|
1151
|
+
"-r",
|
|
1152
|
+
"-s",
|
|
1153
|
+
"-S",
|
|
1154
|
+
"-v",
|
|
1155
|
+
"-z",
|
|
1156
|
+
"-0",
|
|
1157
|
+
"--brief",
|
|
1158
|
+
"--mime",
|
|
1159
|
+
"--mime-type",
|
|
1160
|
+
"--mime-encoding",
|
|
1161
|
+
"--dereference",
|
|
1162
|
+
"--no-dereference",
|
|
1163
|
+
"--keep-going",
|
|
1164
|
+
"--no-buffer",
|
|
1165
|
+
"--no-pad",
|
|
1166
|
+
"--raw",
|
|
1167
|
+
"--special-files",
|
|
1168
|
+
"--uncompress",
|
|
1169
|
+
"--print0",
|
|
1170
|
+
"--checking-printout"
|
|
1171
|
+
],
|
|
1172
|
+
values: [
|
|
1173
|
+
"-e",
|
|
1174
|
+
"-m",
|
|
1175
|
+
"-P",
|
|
1176
|
+
"-F",
|
|
1177
|
+
"--exclude",
|
|
1178
|
+
"--magic-file",
|
|
1179
|
+
"--separator",
|
|
1180
|
+
"--parameter",
|
|
1181
|
+
"--extension",
|
|
1182
|
+
"--files-from"
|
|
1183
|
+
]
|
|
1184
|
+
},
|
|
1185
|
+
head: {
|
|
1186
|
+
cluster: true,
|
|
1187
|
+
booleans: ["-q", "-v", "-z", "--quiet", "--silent", "--verbose", "--zero-terminated"],
|
|
1188
|
+
values: ["-c", "-n", "--bytes", "--lines"],
|
|
1189
|
+
patterns: [COUNT_FLAG]
|
|
1190
|
+
},
|
|
1191
|
+
tail: {
|
|
1192
|
+
cluster: true,
|
|
1193
|
+
booleans: [
|
|
1194
|
+
"-f",
|
|
1195
|
+
"-F",
|
|
1196
|
+
"-q",
|
|
1197
|
+
"-v",
|
|
1198
|
+
"-z",
|
|
1199
|
+
"--follow",
|
|
1200
|
+
"--retry",
|
|
1201
|
+
"--quiet",
|
|
1202
|
+
"--silent",
|
|
1203
|
+
"--verbose",
|
|
1204
|
+
"--zero-terminated"
|
|
1205
|
+
],
|
|
1206
|
+
values: [
|
|
1207
|
+
"-c",
|
|
1208
|
+
"-n",
|
|
1209
|
+
"-s",
|
|
1210
|
+
"--bytes",
|
|
1211
|
+
"--lines",
|
|
1212
|
+
"--sleep-interval",
|
|
1213
|
+
"--pid",
|
|
1214
|
+
"--max-unchanged-stats"
|
|
1215
|
+
],
|
|
1216
|
+
patterns: [COUNT_FLAG]
|
|
1217
|
+
},
|
|
1218
|
+
cat: {
|
|
1219
|
+
cluster: true,
|
|
1220
|
+
booleans: [
|
|
1221
|
+
"-A",
|
|
1222
|
+
"-b",
|
|
1223
|
+
"-e",
|
|
1224
|
+
"-E",
|
|
1225
|
+
"-n",
|
|
1226
|
+
"-s",
|
|
1227
|
+
"-t",
|
|
1228
|
+
"-T",
|
|
1229
|
+
"-u",
|
|
1230
|
+
"-v",
|
|
1231
|
+
"--show-all",
|
|
1232
|
+
"--number-nonblank",
|
|
1233
|
+
"--show-ends",
|
|
1234
|
+
"--number",
|
|
1235
|
+
"--squeeze-blank",
|
|
1236
|
+
"--show-tabs",
|
|
1237
|
+
"--show-nonprinting"
|
|
1238
|
+
]
|
|
1239
|
+
},
|
|
1240
|
+
sort: {
|
|
1241
|
+
cluster: true,
|
|
1242
|
+
// Absent on purpose: `-o`/`--output` writes a file with no redirect for the
|
|
1243
|
+
// redirect check to see, and `--compress-program` names a program that sort
|
|
1244
|
+
// runs over its own temporary files — a permitted binary as an interpreter.
|
|
1245
|
+
booleans: [
|
|
1246
|
+
"-b",
|
|
1247
|
+
"-c",
|
|
1248
|
+
"-C",
|
|
1249
|
+
"-d",
|
|
1250
|
+
"-f",
|
|
1251
|
+
"-g",
|
|
1252
|
+
"-h",
|
|
1253
|
+
"-i",
|
|
1254
|
+
"-M",
|
|
1255
|
+
"-n",
|
|
1256
|
+
"-r",
|
|
1257
|
+
"-R",
|
|
1258
|
+
"-s",
|
|
1259
|
+
"-u",
|
|
1260
|
+
"-V",
|
|
1261
|
+
"-z",
|
|
1262
|
+
"--ignore-leading-blanks",
|
|
1263
|
+
"--check",
|
|
1264
|
+
"--dictionary-order",
|
|
1265
|
+
"--ignore-case",
|
|
1266
|
+
"--general-numeric-sort",
|
|
1267
|
+
"--human-numeric-sort",
|
|
1268
|
+
"--ignore-nonprinting",
|
|
1269
|
+
"--month-sort",
|
|
1270
|
+
"--numeric-sort",
|
|
1271
|
+
"--random-sort",
|
|
1272
|
+
"--reverse",
|
|
1273
|
+
"--stable",
|
|
1274
|
+
"--unique",
|
|
1275
|
+
"--version-sort",
|
|
1276
|
+
"--zero-terminated",
|
|
1277
|
+
"--debug"
|
|
1278
|
+
],
|
|
1279
|
+
values: [
|
|
1280
|
+
"-k",
|
|
1281
|
+
"-t",
|
|
1282
|
+
"-S",
|
|
1283
|
+
"-T",
|
|
1284
|
+
"--key",
|
|
1285
|
+
"--field-separator",
|
|
1286
|
+
"--buffer-size",
|
|
1287
|
+
"--temporary-directory",
|
|
1288
|
+
"--random-source",
|
|
1289
|
+
"--batch-size",
|
|
1290
|
+
"--parallel",
|
|
1291
|
+
"--sort"
|
|
1292
|
+
]
|
|
1293
|
+
},
|
|
1294
|
+
uniq: {
|
|
1295
|
+
cluster: true,
|
|
1296
|
+
booleans: [
|
|
1297
|
+
"-c",
|
|
1298
|
+
"-d",
|
|
1299
|
+
"-D",
|
|
1300
|
+
"-i",
|
|
1301
|
+
"-u",
|
|
1302
|
+
"-z",
|
|
1303
|
+
"--count",
|
|
1304
|
+
"--repeated",
|
|
1305
|
+
"--all-repeated",
|
|
1306
|
+
"--ignore-case",
|
|
1307
|
+
"--unique",
|
|
1308
|
+
"--zero-terminated"
|
|
1309
|
+
],
|
|
1310
|
+
values: ["-f", "-s", "-w", "--skip-fields", "--skip-chars", "--check-chars", "--group"]
|
|
1311
|
+
},
|
|
1312
|
+
// No flag on either runs a program or writes a file, and the planner's
|
|
1313
|
+
// commonest use of `echo` is a section marker — `echo --- files changed ---`
|
|
1314
|
+
// is three tokens that all begin with a dash and none of them is a flag.
|
|
1315
|
+
echo: { freeform: true },
|
|
1316
|
+
printf: { freeform: true },
|
|
1317
|
+
date: {
|
|
1318
|
+
cluster: true,
|
|
1319
|
+
// `-s`/`--set` is absent: it sets the system clock.
|
|
1320
|
+
booleans: [
|
|
1321
|
+
"-u",
|
|
1322
|
+
"-R",
|
|
1323
|
+
"-I",
|
|
1324
|
+
"--utc",
|
|
1325
|
+
"--universal",
|
|
1326
|
+
"--rfc-email",
|
|
1327
|
+
"--rfc-3339",
|
|
1328
|
+
"--iso-8601",
|
|
1329
|
+
"--debug"
|
|
1330
|
+
],
|
|
1331
|
+
values: ["-d", "-f", "-r", "--date", "--file", "--reference"]
|
|
1332
|
+
},
|
|
1333
|
+
stat: {
|
|
1334
|
+
cluster: true,
|
|
1335
|
+
booleans: ["-f", "-L", "-t", "--file-system", "--terse", "--dereference"],
|
|
1336
|
+
values: ["-c", "--format", "--printf", "--cached"]
|
|
1337
|
+
},
|
|
1338
|
+
basename: {
|
|
1339
|
+
cluster: true,
|
|
1340
|
+
booleans: ["-a", "-z", "--multiple", "--zero"],
|
|
1341
|
+
values: ["-s", "--suffix"]
|
|
1342
|
+
},
|
|
1343
|
+
dirname: {
|
|
1344
|
+
cluster: true,
|
|
1345
|
+
booleans: ["-z", "--zero"]
|
|
1346
|
+
},
|
|
1347
|
+
realpath: {
|
|
1348
|
+
cluster: true,
|
|
1349
|
+
booleans: [
|
|
1350
|
+
"-e",
|
|
1351
|
+
"-m",
|
|
1352
|
+
"-L",
|
|
1353
|
+
"-P",
|
|
1354
|
+
"-q",
|
|
1355
|
+
"-s",
|
|
1356
|
+
"-z",
|
|
1357
|
+
"--canonicalize-existing",
|
|
1358
|
+
"--canonicalize-missing",
|
|
1359
|
+
"--logical",
|
|
1360
|
+
"--physical",
|
|
1361
|
+
"--quiet",
|
|
1362
|
+
"--strip",
|
|
1363
|
+
"--no-symlinks",
|
|
1364
|
+
"--zero"
|
|
1365
|
+
],
|
|
1366
|
+
values: ["--relative-to", "--relative-base"]
|
|
1367
|
+
},
|
|
1368
|
+
pwd: { cluster: true, booleans: ["-L", "-P", "--logical", "--physical"] },
|
|
1369
|
+
which: { cluster: true, booleans: ["-a", "-s", "--all"] },
|
|
1370
|
+
type: { cluster: true, booleans: ["-a", "-f", "-p", "-P", "-t"] },
|
|
1371
|
+
uname: {
|
|
1372
|
+
cluster: true,
|
|
1373
|
+
booleans: [
|
|
1374
|
+
"-a",
|
|
1375
|
+
"-i",
|
|
1376
|
+
"-m",
|
|
1377
|
+
"-n",
|
|
1378
|
+
"-o",
|
|
1379
|
+
"-p",
|
|
1380
|
+
"-r",
|
|
1381
|
+
"-s",
|
|
1382
|
+
"-v",
|
|
1383
|
+
"--all",
|
|
1384
|
+
"--kernel-name",
|
|
1385
|
+
"--nodename",
|
|
1386
|
+
"--kernel-release",
|
|
1387
|
+
"--kernel-version",
|
|
1388
|
+
"--machine",
|
|
1389
|
+
"--processor",
|
|
1390
|
+
"--hardware-platform",
|
|
1391
|
+
"--operating-system"
|
|
1392
|
+
]
|
|
1393
|
+
},
|
|
1394
|
+
whoami: {},
|
|
1395
|
+
cut: {
|
|
1396
|
+
cluster: true,
|
|
1397
|
+
// `--output-delimiter` names a separator string, not a file.
|
|
1398
|
+
booleans: ["-n", "-s", "-z", "--only-delimited", "--complement", "--zero-terminated"],
|
|
1399
|
+
values: [
|
|
1400
|
+
"-b",
|
|
1401
|
+
"-c",
|
|
1402
|
+
"-d",
|
|
1403
|
+
"-f",
|
|
1404
|
+
"--bytes",
|
|
1405
|
+
"--characters",
|
|
1406
|
+
"--delimiter",
|
|
1407
|
+
"--fields",
|
|
1408
|
+
"--output-delimiter"
|
|
1409
|
+
]
|
|
1410
|
+
},
|
|
1411
|
+
nl: {
|
|
1412
|
+
cluster: true,
|
|
1413
|
+
booleans: ["-p", "--no-renumber"],
|
|
1414
|
+
values: [
|
|
1415
|
+
"-b",
|
|
1416
|
+
"-d",
|
|
1417
|
+
"-f",
|
|
1418
|
+
"-h",
|
|
1419
|
+
"-i",
|
|
1420
|
+
"-l",
|
|
1421
|
+
"-n",
|
|
1422
|
+
"-s",
|
|
1423
|
+
"-v",
|
|
1424
|
+
"-w",
|
|
1425
|
+
"--body-numbering",
|
|
1426
|
+
"--section-delimiter",
|
|
1427
|
+
"--footer-numbering",
|
|
1428
|
+
"--header-numbering",
|
|
1429
|
+
"--join-blank-lines",
|
|
1430
|
+
"--line-increment",
|
|
1431
|
+
"--number-format",
|
|
1432
|
+
"--number-separator",
|
|
1433
|
+
"--starting-line-number",
|
|
1434
|
+
"--number-width"
|
|
1435
|
+
]
|
|
1436
|
+
},
|
|
1437
|
+
rg: {
|
|
1438
|
+
cluster: true,
|
|
1439
|
+
// `--pre` runs a named preprocessor over every file searched and
|
|
1440
|
+
// `--hostname-bin` runs a named program to resolve the hostname; both are
|
|
1441
|
+
// absent, and `--pre-glob` with them.
|
|
1442
|
+
booleans: [
|
|
1443
|
+
"-a",
|
|
1444
|
+
"-c",
|
|
1445
|
+
"-F",
|
|
1446
|
+
"-h",
|
|
1447
|
+
"-H",
|
|
1448
|
+
"-i",
|
|
1449
|
+
"-I",
|
|
1450
|
+
"-l",
|
|
1451
|
+
"-L",
|
|
1452
|
+
"-n",
|
|
1453
|
+
"-N",
|
|
1454
|
+
"-o",
|
|
1455
|
+
"-p",
|
|
1456
|
+
"-P",
|
|
1457
|
+
"-q",
|
|
1458
|
+
"-s",
|
|
1459
|
+
"-S",
|
|
1460
|
+
"-u",
|
|
1461
|
+
"-uu",
|
|
1462
|
+
"-uuu",
|
|
1463
|
+
"-U",
|
|
1464
|
+
"-v",
|
|
1465
|
+
"-V",
|
|
1466
|
+
"-w",
|
|
1467
|
+
"-x",
|
|
1468
|
+
"-z",
|
|
1469
|
+
"--text",
|
|
1470
|
+
"--count",
|
|
1471
|
+
"--count-matches",
|
|
1472
|
+
"--fixed-strings",
|
|
1473
|
+
"--files",
|
|
1474
|
+
"--files-with-matches",
|
|
1475
|
+
"--files-without-match",
|
|
1476
|
+
"--follow",
|
|
1477
|
+
"--hidden",
|
|
1478
|
+
"--no-hidden",
|
|
1479
|
+
"--ignore-case",
|
|
1480
|
+
"--case-sensitive",
|
|
1481
|
+
"--smart-case",
|
|
1482
|
+
"--invert-match",
|
|
1483
|
+
"--line-number",
|
|
1484
|
+
"--no-line-number",
|
|
1485
|
+
"--with-filename",
|
|
1486
|
+
"--no-filename",
|
|
1487
|
+
"--heading",
|
|
1488
|
+
"--no-heading",
|
|
1489
|
+
"--column",
|
|
1490
|
+
"--no-column",
|
|
1491
|
+
"--byte-offset",
|
|
1492
|
+
"--vimgrep",
|
|
1493
|
+
"--json",
|
|
1494
|
+
"--stats",
|
|
1495
|
+
"--trim",
|
|
1496
|
+
"--pretty",
|
|
1497
|
+
"--passthru",
|
|
1498
|
+
"--word-regexp",
|
|
1499
|
+
"--line-regexp",
|
|
1500
|
+
"--multiline",
|
|
1501
|
+
"--multiline-dotall",
|
|
1502
|
+
"--no-multiline",
|
|
1503
|
+
"--crlf",
|
|
1504
|
+
"--null",
|
|
1505
|
+
"--null-data",
|
|
1506
|
+
"--binary",
|
|
1507
|
+
"--search-zip",
|
|
1508
|
+
"--no-ignore",
|
|
1509
|
+
"--no-ignore-dot",
|
|
1510
|
+
"--no-ignore-exclude",
|
|
1511
|
+
"--no-ignore-files",
|
|
1512
|
+
"--no-ignore-global",
|
|
1513
|
+
"--no-ignore-parent",
|
|
1514
|
+
"--no-ignore-vcs",
|
|
1515
|
+
"--no-ignore-messages",
|
|
1516
|
+
"--no-messages",
|
|
1517
|
+
"--no-require-git",
|
|
1518
|
+
"--require-git",
|
|
1519
|
+
"--one-file-system",
|
|
1520
|
+
"--pcre2",
|
|
1521
|
+
"--no-pcre2",
|
|
1522
|
+
"--auto-hybrid-regex",
|
|
1523
|
+
"--line-buffered",
|
|
1524
|
+
"--block-buffered",
|
|
1525
|
+
"--unicode",
|
|
1526
|
+
"--no-unicode",
|
|
1527
|
+
"--unrestricted",
|
|
1528
|
+
"--type-list",
|
|
1529
|
+
"--debug",
|
|
1530
|
+
"--trace",
|
|
1531
|
+
"--include-zero",
|
|
1532
|
+
"--no-context-separator",
|
|
1533
|
+
"--stop-on-nonmatch",
|
|
1534
|
+
"--quiet",
|
|
1535
|
+
"--no-binary"
|
|
1536
|
+
],
|
|
1537
|
+
values: [
|
|
1538
|
+
"-A",
|
|
1539
|
+
"-B",
|
|
1540
|
+
"-C",
|
|
1541
|
+
"-d",
|
|
1542
|
+
"-e",
|
|
1543
|
+
"-E",
|
|
1544
|
+
"-f",
|
|
1545
|
+
"-g",
|
|
1546
|
+
"-j",
|
|
1547
|
+
"-m",
|
|
1548
|
+
"-M",
|
|
1549
|
+
"-r",
|
|
1550
|
+
"-t",
|
|
1551
|
+
"-T",
|
|
1552
|
+
"--after-context",
|
|
1553
|
+
"--before-context",
|
|
1554
|
+
"--context",
|
|
1555
|
+
"--context-separator",
|
|
1556
|
+
"--field-context-separator",
|
|
1557
|
+
"--field-match-separator",
|
|
1558
|
+
"--regexp",
|
|
1559
|
+
"--file",
|
|
1560
|
+
"--glob",
|
|
1561
|
+
"--iglob",
|
|
1562
|
+
"--glob-case-insensitive",
|
|
1563
|
+
"--type",
|
|
1564
|
+
"--type-not",
|
|
1565
|
+
"--type-add",
|
|
1566
|
+
"--type-clear",
|
|
1567
|
+
"--max-count",
|
|
1568
|
+
"--max-columns",
|
|
1569
|
+
"--max-depth",
|
|
1570
|
+
"--maxdepth",
|
|
1571
|
+
"--max-filesize",
|
|
1572
|
+
"--replace",
|
|
1573
|
+
"--threads",
|
|
1574
|
+
"--encoding",
|
|
1575
|
+
"--engine",
|
|
1576
|
+
"--sort",
|
|
1577
|
+
"--sortr",
|
|
1578
|
+
"--color",
|
|
1579
|
+
"--colors",
|
|
1580
|
+
"--path-separator",
|
|
1581
|
+
"--ignore-file",
|
|
1582
|
+
"--dfa-size-limit",
|
|
1583
|
+
"--regex-size-limit",
|
|
1584
|
+
"--binary-files",
|
|
1585
|
+
"--max-columns-preview"
|
|
1586
|
+
]
|
|
1587
|
+
},
|
|
1588
|
+
grep: {
|
|
1589
|
+
cluster: true,
|
|
1590
|
+
// `-o` here is `--only-matching`, which writes nothing. It is the same two
|
|
1591
|
+
// characters as `sort -o`, which writes a file — the reason these sets are
|
|
1592
|
+
// per-binary rather than one shared list.
|
|
1593
|
+
booleans: [
|
|
1594
|
+
"-a",
|
|
1595
|
+
"-b",
|
|
1596
|
+
"-c",
|
|
1597
|
+
"-E",
|
|
1598
|
+
"-F",
|
|
1599
|
+
"-G",
|
|
1600
|
+
"-H",
|
|
1601
|
+
"-h",
|
|
1602
|
+
"-i",
|
|
1603
|
+
"-I",
|
|
1604
|
+
"-l",
|
|
1605
|
+
"-L",
|
|
1606
|
+
"-n",
|
|
1607
|
+
"-o",
|
|
1608
|
+
"-P",
|
|
1609
|
+
"-q",
|
|
1610
|
+
"-r",
|
|
1611
|
+
"-R",
|
|
1612
|
+
"-s",
|
|
1613
|
+
"-T",
|
|
1614
|
+
"-U",
|
|
1615
|
+
"-v",
|
|
1616
|
+
"-w",
|
|
1617
|
+
"-x",
|
|
1618
|
+
"-y",
|
|
1619
|
+
"-z",
|
|
1620
|
+
"-Z",
|
|
1621
|
+
"--extended-regexp",
|
|
1622
|
+
"--fixed-strings",
|
|
1623
|
+
"--basic-regexp",
|
|
1624
|
+
"--perl-regexp",
|
|
1625
|
+
"--ignore-case",
|
|
1626
|
+
"--no-ignore-case",
|
|
1627
|
+
"--invert-match",
|
|
1628
|
+
"--word-regexp",
|
|
1629
|
+
"--line-regexp",
|
|
1630
|
+
"--count",
|
|
1631
|
+
"--files-with-matches",
|
|
1632
|
+
"--files-without-match",
|
|
1633
|
+
"--line-number",
|
|
1634
|
+
"--with-filename",
|
|
1635
|
+
"--no-filename",
|
|
1636
|
+
"--only-matching",
|
|
1637
|
+
"--quiet",
|
|
1638
|
+
"--silent",
|
|
1639
|
+
"--no-messages",
|
|
1640
|
+
"--text",
|
|
1641
|
+
"--binary",
|
|
1642
|
+
"--line-buffered",
|
|
1643
|
+
"--null",
|
|
1644
|
+
"--null-data",
|
|
1645
|
+
"--byte-offset",
|
|
1646
|
+
"--recursive",
|
|
1647
|
+
"--dereference-recursive",
|
|
1648
|
+
"--initial-tab",
|
|
1649
|
+
"--unix-byte-offsets",
|
|
1650
|
+
"--no-group-separator",
|
|
1651
|
+
"--color",
|
|
1652
|
+
"--colour"
|
|
1653
|
+
],
|
|
1654
|
+
values: [
|
|
1655
|
+
"-A",
|
|
1656
|
+
"-B",
|
|
1657
|
+
"-C",
|
|
1658
|
+
"-d",
|
|
1659
|
+
"-D",
|
|
1660
|
+
"-e",
|
|
1661
|
+
"-f",
|
|
1662
|
+
"-m",
|
|
1663
|
+
"--after-context",
|
|
1664
|
+
"--before-context",
|
|
1665
|
+
"--context",
|
|
1666
|
+
"--regexp",
|
|
1667
|
+
"--file",
|
|
1668
|
+
"--max-count",
|
|
1669
|
+
"--devices",
|
|
1670
|
+
"--directories",
|
|
1671
|
+
"--binary-files",
|
|
1672
|
+
"--include",
|
|
1673
|
+
"--exclude",
|
|
1674
|
+
"--exclude-dir",
|
|
1675
|
+
"--exclude-from",
|
|
1676
|
+
"--label",
|
|
1677
|
+
"--group-separator"
|
|
1678
|
+
]
|
|
1679
|
+
},
|
|
1680
|
+
find: {
|
|
1681
|
+
// No clustering: find spells its flags as single-dash words, so walking the
|
|
1682
|
+
// characters of `-name` would read it as five short flags. And its arguments
|
|
1683
|
+
// are an expression, so `--` does not end them.
|
|
1684
|
+
expressionArgs: true,
|
|
1685
|
+
// Absent on purpose: `-exec`, `-execdir`, `-ok` and `-okdir` run an inner
|
|
1686
|
+
// command (also caught by the named guard below, which says so more
|
|
1687
|
+
// precisely), `-delete` removes files, and `-fprint`, `-fprint0`, `-fprintf`
|
|
1688
|
+
// and `-fls` are find's write family — the same write as `> file` with no
|
|
1689
|
+
// redirect for the redirect check to see.
|
|
1690
|
+
booleans: [
|
|
1691
|
+
"-H",
|
|
1692
|
+
"-L",
|
|
1693
|
+
"-P",
|
|
1694
|
+
"-a",
|
|
1695
|
+
"-and",
|
|
1696
|
+
"-o",
|
|
1697
|
+
"-or",
|
|
1698
|
+
"-not",
|
|
1699
|
+
"-d",
|
|
1700
|
+
"-depth",
|
|
1701
|
+
"-daystart",
|
|
1702
|
+
"-empty",
|
|
1703
|
+
"-executable",
|
|
1704
|
+
"-false",
|
|
1705
|
+
"-follow",
|
|
1706
|
+
"-help",
|
|
1707
|
+
"--help",
|
|
1708
|
+
"-ignore_readdir_race",
|
|
1709
|
+
"-noignore_readdir_race",
|
|
1710
|
+
"-ls",
|
|
1711
|
+
"-mount",
|
|
1712
|
+
"-nogroup",
|
|
1713
|
+
"-noleaf",
|
|
1714
|
+
"-nouser",
|
|
1715
|
+
"-print",
|
|
1716
|
+
"-print0",
|
|
1717
|
+
"-prune",
|
|
1718
|
+
"-quit",
|
|
1719
|
+
"-readable",
|
|
1720
|
+
"-true",
|
|
1721
|
+
"-version",
|
|
1722
|
+
"-writable",
|
|
1723
|
+
"-xdev"
|
|
1724
|
+
],
|
|
1725
|
+
values: [
|
|
1726
|
+
"-maxdepth",
|
|
1727
|
+
"-mindepth",
|
|
1728
|
+
"-name",
|
|
1729
|
+
"-iname",
|
|
1730
|
+
"-path",
|
|
1731
|
+
"-ipath",
|
|
1732
|
+
"-wholename",
|
|
1733
|
+
"-iwholename",
|
|
1734
|
+
"-regex",
|
|
1735
|
+
"-iregex",
|
|
1736
|
+
"-lname",
|
|
1737
|
+
"-ilname",
|
|
1738
|
+
"-type",
|
|
1739
|
+
"-xtype",
|
|
1740
|
+
"-size",
|
|
1741
|
+
"-newer",
|
|
1742
|
+
"-anewer",
|
|
1743
|
+
"-cnewer",
|
|
1744
|
+
"-mtime",
|
|
1745
|
+
"-mmin",
|
|
1746
|
+
"-ctime",
|
|
1747
|
+
"-cmin",
|
|
1748
|
+
"-atime",
|
|
1749
|
+
"-amin",
|
|
1750
|
+
"-used",
|
|
1751
|
+
"-uid",
|
|
1752
|
+
"-gid",
|
|
1753
|
+
"-user",
|
|
1754
|
+
"-group",
|
|
1755
|
+
"-perm",
|
|
1756
|
+
"-links",
|
|
1757
|
+
"-inum",
|
|
1758
|
+
"-samefile",
|
|
1759
|
+
"-fstype",
|
|
1760
|
+
"-regextype",
|
|
1761
|
+
"-files0-from",
|
|
1762
|
+
"-printf",
|
|
1763
|
+
"-context",
|
|
1764
|
+
"-D"
|
|
1765
|
+
],
|
|
1766
|
+
// `find -O2` glues the optimisation level on, and `-newermt`/`-newerat` and
|
|
1767
|
+
// friends spell the two comparison fields into the flag name.
|
|
1768
|
+
patterns: [/^-O\d$/, /^-newer[acmBt][acmBt]$/]
|
|
1769
|
+
},
|
|
1770
|
+
jq: {
|
|
1771
|
+
cluster: true,
|
|
1772
|
+
booleans: [
|
|
1773
|
+
"-a",
|
|
1774
|
+
"-c",
|
|
1775
|
+
"-C",
|
|
1776
|
+
"-e",
|
|
1777
|
+
"-h",
|
|
1778
|
+
"-j",
|
|
1779
|
+
"-M",
|
|
1780
|
+
"-n",
|
|
1781
|
+
"-r",
|
|
1782
|
+
"-R",
|
|
1783
|
+
"-s",
|
|
1784
|
+
"-S",
|
|
1785
|
+
"--ascii-output",
|
|
1786
|
+
"--compact-output",
|
|
1787
|
+
"--color-output",
|
|
1788
|
+
"--monochrome-output",
|
|
1789
|
+
"--exit-status",
|
|
1790
|
+
"--join-output",
|
|
1791
|
+
"--null-input",
|
|
1792
|
+
"--raw-input",
|
|
1793
|
+
"--raw-output",
|
|
1794
|
+
"--raw-output0",
|
|
1795
|
+
"--slurp",
|
|
1796
|
+
"--sort-keys",
|
|
1797
|
+
"--seq",
|
|
1798
|
+
"--stream",
|
|
1799
|
+
"--stream-errors",
|
|
1800
|
+
"--tab",
|
|
1801
|
+
"--unbuffered",
|
|
1802
|
+
"--args",
|
|
1803
|
+
"--jsonargs"
|
|
1804
|
+
],
|
|
1805
|
+
values: [
|
|
1806
|
+
"-f",
|
|
1807
|
+
"-L",
|
|
1808
|
+
"--arg",
|
|
1809
|
+
"--argjson",
|
|
1810
|
+
"--slurpfile",
|
|
1811
|
+
"--rawfile",
|
|
1812
|
+
"--indent",
|
|
1813
|
+
"--from-file"
|
|
1814
|
+
]
|
|
1815
|
+
},
|
|
1816
|
+
yq: {
|
|
1817
|
+
cluster: true,
|
|
1818
|
+
// `-i`/`--inplace`/`--in-place` rewrite the file, and `-s`/`--split-exp`
|
|
1819
|
+
// writes one file per document. All absent — and all bare or near-bare
|
|
1820
|
+
// booleans, which is why exempting booleans was not an option.
|
|
1821
|
+
booleans: [
|
|
1822
|
+
"-C",
|
|
1823
|
+
"-e",
|
|
1824
|
+
"-h",
|
|
1825
|
+
"-j",
|
|
1826
|
+
"-M",
|
|
1827
|
+
"-n",
|
|
1828
|
+
"-N",
|
|
1829
|
+
"-P",
|
|
1830
|
+
"-r",
|
|
1831
|
+
"-S",
|
|
1832
|
+
"-v",
|
|
1833
|
+
"-y",
|
|
1834
|
+
"-Y",
|
|
1835
|
+
"--colors",
|
|
1836
|
+
"--no-colors",
|
|
1837
|
+
"--exit-status",
|
|
1838
|
+
"--no-doc",
|
|
1839
|
+
"--null-input",
|
|
1840
|
+
"--prettyPrint",
|
|
1841
|
+
"--raw-output",
|
|
1842
|
+
"--sort-keys",
|
|
1843
|
+
"--tojson",
|
|
1844
|
+
"--yaml-output",
|
|
1845
|
+
"--yaml-roundtrip",
|
|
1846
|
+
"--unwrapScalar",
|
|
1847
|
+
"--header-preprocess",
|
|
1848
|
+
"--no-exit-status",
|
|
1849
|
+
"--verbose",
|
|
1850
|
+
"--xml-strict-mode"
|
|
1851
|
+
],
|
|
1852
|
+
values: [
|
|
1853
|
+
"-I",
|
|
1854
|
+
"-o",
|
|
1855
|
+
"-p",
|
|
1856
|
+
"-L",
|
|
1857
|
+
"--indent",
|
|
1858
|
+
"--output-format",
|
|
1859
|
+
"--input-format",
|
|
1860
|
+
"--expression",
|
|
1861
|
+
"--width",
|
|
1862
|
+
"--xml-attribute-prefix",
|
|
1863
|
+
"--xml-content-name"
|
|
1864
|
+
]
|
|
1865
|
+
}
|
|
1866
|
+
};
|
|
619
1867
|
var GIT_READONLY_SUBCOMMANDS = [
|
|
620
1868
|
"log",
|
|
621
1869
|
"status",
|
|
622
1870
|
"diff",
|
|
623
1871
|
"show",
|
|
624
1872
|
"ls-files",
|
|
625
|
-
"ls-remote",
|
|
626
1873
|
"ls-tree",
|
|
627
1874
|
"branch",
|
|
628
1875
|
"tag",
|
|
@@ -737,6 +1984,26 @@ var REFUSED_SUBCOMMANDS = {
|
|
|
737
1984
|
az: ["login", "logout"],
|
|
738
1985
|
terraform: ["apply", "destroy"]
|
|
739
1986
|
};
|
|
1987
|
+
var SHELL_KEYWORDS = [
|
|
1988
|
+
"{",
|
|
1989
|
+
"}",
|
|
1990
|
+
"if",
|
|
1991
|
+
"then",
|
|
1992
|
+
"elif",
|
|
1993
|
+
"else",
|
|
1994
|
+
"fi",
|
|
1995
|
+
"for",
|
|
1996
|
+
"while",
|
|
1997
|
+
"until",
|
|
1998
|
+
"do",
|
|
1999
|
+
"done",
|
|
2000
|
+
"case",
|
|
2001
|
+
"esac",
|
|
2002
|
+
"select",
|
|
2003
|
+
"function",
|
|
2004
|
+
"time",
|
|
2005
|
+
"export"
|
|
2006
|
+
];
|
|
740
2007
|
var INTERPRETERS = [
|
|
741
2008
|
"sh",
|
|
742
2009
|
"bash",
|
|
@@ -806,6 +2073,52 @@ var MULTIPLEXERS = [
|
|
|
806
2073
|
"flutter",
|
|
807
2074
|
"dart"
|
|
808
2075
|
];
|
|
2076
|
+
var HELP_FLAGS = ["--help", "--version"];
|
|
2077
|
+
var WRAPPER_FAMILY = {
|
|
2078
|
+
env: {
|
|
2079
|
+
valueFlags: ["-u", "--unset", "-C", "--chdir"],
|
|
2080
|
+
booleanFlags: [
|
|
2081
|
+
"-i",
|
|
2082
|
+
"--ignore-environment",
|
|
2083
|
+
"-0",
|
|
2084
|
+
"--null",
|
|
2085
|
+
"-v",
|
|
2086
|
+
"--debug",
|
|
2087
|
+
// Optional-value flags: see WrapperSpec.booleanFlags.
|
|
2088
|
+
"--block-signal",
|
|
2089
|
+
"--default-signal",
|
|
2090
|
+
"--ignore-signal",
|
|
2091
|
+
"--list-signal-handling",
|
|
2092
|
+
...HELP_FLAGS
|
|
2093
|
+
],
|
|
2094
|
+
stringFlags: ["-S", "--split-string"],
|
|
2095
|
+
acceptsAssignments: true
|
|
2096
|
+
},
|
|
2097
|
+
nice: {
|
|
2098
|
+
valueFlags: ["-n", "--adjustment"],
|
|
2099
|
+
booleanFlags: HELP_FLAGS,
|
|
2100
|
+
booleanPattern: /^-\d+$/
|
|
2101
|
+
},
|
|
2102
|
+
timeout: {
|
|
2103
|
+
valueFlags: ["-s", "--signal", "-k", "--kill-after"],
|
|
2104
|
+
booleanFlags: ["--preserve-status", "--foreground", "-v", "--verbose", ...HELP_FLAGS],
|
|
2105
|
+
positionals: 1
|
|
2106
|
+
},
|
|
2107
|
+
nohup: { booleanFlags: HELP_FLAGS },
|
|
2108
|
+
setsid: { booleanFlags: ["-c", "--ctty", "-f", "--fork", "-w", "--wait", "-h", "-V", ...HELP_FLAGS] },
|
|
2109
|
+
stdbuf: {
|
|
2110
|
+
valueFlags: ["-i", "--input", "-o", "--output", "-e", "--error"],
|
|
2111
|
+
booleanFlags: HELP_FLAGS
|
|
2112
|
+
},
|
|
2113
|
+
ionice: {
|
|
2114
|
+
valueFlags: ["-c", "--class", "-n", "--classdata", "-p", "--pid", "-P", "--pgid", "-u", "--uid"],
|
|
2115
|
+
booleanFlags: ["-t", "--ignore", "-h", "-V", ...HELP_FLAGS]
|
|
2116
|
+
},
|
|
2117
|
+
// The multi-call binary ships its own `rm`, `mv` and `sh`, so the refused
|
|
2118
|
+
// name arrives as its first argument.
|
|
2119
|
+
busybox: { booleanFlags: ["--list", "--install", ...HELP_FLAGS] },
|
|
2120
|
+
command: { booleanFlags: ["-p"], noExecFlags: ["-v", "-V"] }
|
|
2121
|
+
};
|
|
809
2122
|
var POSIX_DIALECT = {
|
|
810
2123
|
escape: "\\",
|
|
811
2124
|
escapeInQuotes: true,
|
|
@@ -1020,10 +2333,92 @@ function binaryName(token, dialect) {
|
|
|
1020
2333
|
if (dot <= 0) return base;
|
|
1021
2334
|
return dialect.strippedExtensions.includes(base.slice(dot).toLowerCase()) ? base.slice(0, dot) : base;
|
|
1022
2335
|
}
|
|
2336
|
+
var ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
1023
2337
|
function toSegment(tokens, piped, dialect) {
|
|
1024
2338
|
const rest = [...tokens];
|
|
1025
|
-
|
|
1026
|
-
|
|
2339
|
+
const assignments = [];
|
|
2340
|
+
while (rest.length > 0 && ASSIGNMENT.test(rest[0])) assignments.push(rest.shift());
|
|
2341
|
+
return {
|
|
2342
|
+
binary: rest.length > 0 ? binaryName(rest[0], dialect) : "",
|
|
2343
|
+
args: rest.slice(1),
|
|
2344
|
+
assignments,
|
|
2345
|
+
piped,
|
|
2346
|
+
expandable: false
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
function joinedShortFlag(list, token) {
|
|
2350
|
+
if (token.length <= 2) return void 0;
|
|
2351
|
+
return list.find((f) => f.length === 2 && token.startsWith(f));
|
|
2352
|
+
}
|
|
2353
|
+
function scanWrapperArgs(binary, spec, args) {
|
|
2354
|
+
const valueFlags = spec.valueFlags ?? [];
|
|
2355
|
+
const stringFlags = spec.stringFlags ?? [];
|
|
2356
|
+
const assignments = [];
|
|
2357
|
+
let positionals = spec.positionals ?? 0;
|
|
2358
|
+
let i = 0;
|
|
2359
|
+
while (i < args.length) {
|
|
2360
|
+
const token = args[i];
|
|
2361
|
+
if (token === "--") {
|
|
2362
|
+
i++;
|
|
2363
|
+
break;
|
|
2364
|
+
}
|
|
2365
|
+
if (/^-./.test(token)) {
|
|
2366
|
+
const eq = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
2367
|
+
const name = eq > 0 ? token.slice(0, eq) : token;
|
|
2368
|
+
const selfContained = eq > 0;
|
|
2369
|
+
if ((spec.noExecFlags ?? []).includes(name)) return { kind: "no-exec" };
|
|
2370
|
+
if (stringFlags.includes(name) || joinedShortFlag(stringFlags, token)) {
|
|
2371
|
+
return {
|
|
2372
|
+
kind: "refuse",
|
|
2373
|
+
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.`
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
if ((spec.booleanFlags ?? []).includes(name) || spec.booleanPattern?.test(token)) {
|
|
2377
|
+
i++;
|
|
2378
|
+
continue;
|
|
2379
|
+
}
|
|
2380
|
+
if (valueFlags.includes(name)) {
|
|
2381
|
+
i += selfContained ? 1 : 2;
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
if (joinedShortFlag(valueFlags, token)) {
|
|
2385
|
+
i++;
|
|
2386
|
+
continue;
|
|
2387
|
+
}
|
|
2388
|
+
return {
|
|
2389
|
+
kind: "refuse",
|
|
2390
|
+
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.`
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
if (spec.acceptsAssignments && ASSIGNMENT.test(token)) {
|
|
2394
|
+
assignments.push(token);
|
|
2395
|
+
i++;
|
|
2396
|
+
continue;
|
|
2397
|
+
}
|
|
2398
|
+
if (positionals > 0) {
|
|
2399
|
+
positionals--;
|
|
2400
|
+
i++;
|
|
2401
|
+
continue;
|
|
2402
|
+
}
|
|
2403
|
+
break;
|
|
2404
|
+
}
|
|
2405
|
+
return { kind: "command", tokens: args.slice(i), assignments };
|
|
2406
|
+
}
|
|
2407
|
+
function unwrap(seg, dialect) {
|
|
2408
|
+
const wrappers = [];
|
|
2409
|
+
const assignments = [...seg.assignments];
|
|
2410
|
+
let current = seg;
|
|
2411
|
+
while (WRAPPER_FAMILY[current.binary]) {
|
|
2412
|
+
const scan = scanWrapperArgs(current.binary, WRAPPER_FAMILY[current.binary], current.args);
|
|
2413
|
+
if (scan.kind === "refuse") return { seg: { ...current, assignments }, wrappers, reason: scan.reason };
|
|
2414
|
+
if (scan.kind === "no-exec" || scan.tokens.length === 0) break;
|
|
2415
|
+
assignments.push(...scan.assignments);
|
|
2416
|
+
wrappers.push(current.binary);
|
|
2417
|
+
const inner = toSegment(scan.tokens, current.piped, dialect);
|
|
2418
|
+
assignments.push(...inner.assignments);
|
|
2419
|
+
current = { ...inner, assignments: [], expandable: current.expandable };
|
|
2420
|
+
}
|
|
2421
|
+
return { seg: { ...current, assignments }, wrappers };
|
|
1027
2422
|
}
|
|
1028
2423
|
function lexAll(command, dialect) {
|
|
1029
2424
|
const queue = [];
|
|
@@ -1052,16 +2447,79 @@ function pathLikeArgs(command, opts = {}) {
|
|
|
1052
2447
|
return !a.startsWith("-") && looksLikePath(a) ? [a] : [];
|
|
1053
2448
|
}));
|
|
1054
2449
|
}
|
|
2450
|
+
function matchFlag(spec, booleans, values, token) {
|
|
2451
|
+
if (token.startsWith("--")) {
|
|
2452
|
+
const eq = token.indexOf("=");
|
|
2453
|
+
const name = eq > 0 ? token.slice(0, eq) : token;
|
|
2454
|
+
if (booleans.has(name)) return "boolean";
|
|
2455
|
+
if (values.has(name)) return eq > 0 ? "boolean" : "value";
|
|
2456
|
+
return void 0;
|
|
2457
|
+
}
|
|
2458
|
+
if (booleans.has(token)) return "boolean";
|
|
2459
|
+
if (values.has(token)) return "value";
|
|
2460
|
+
if (spec.patterns?.some((p) => p.test(token))) return "boolean";
|
|
2461
|
+
if (!spec.cluster) return void 0;
|
|
2462
|
+
for (let i = 1; i < token.length; i++) {
|
|
2463
|
+
const short = `-${token[i]}`;
|
|
2464
|
+
if (booleans.has(short)) continue;
|
|
2465
|
+
if (values.has(short)) return i === token.length - 1 ? "value" : "boolean";
|
|
2466
|
+
return void 0;
|
|
2467
|
+
}
|
|
2468
|
+
return "boolean";
|
|
2469
|
+
}
|
|
2470
|
+
function takesNextToken(next) {
|
|
2471
|
+
if (next === void 0) return false;
|
|
2472
|
+
return !/^-./.test(next) || /^-\d/.test(next);
|
|
2473
|
+
}
|
|
2474
|
+
function flagLabel(token) {
|
|
2475
|
+
const eq = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
2476
|
+
return eq > 0 ? token.slice(0, eq) : token;
|
|
2477
|
+
}
|
|
2478
|
+
function scanFlags(seg) {
|
|
2479
|
+
const spec = FLAG_POLICY[seg.binary];
|
|
2480
|
+
if (!spec || spec.freeform) return void 0;
|
|
2481
|
+
const booleans = /* @__PURE__ */ new Set([...spec.booleans ?? [], ...UNIVERSAL_FLAGS]);
|
|
2482
|
+
const values = new Set(spec.values ?? []);
|
|
2483
|
+
const operands = [];
|
|
2484
|
+
let i = 0;
|
|
2485
|
+
while (i < seg.args.length) {
|
|
2486
|
+
const token = seg.args[i];
|
|
2487
|
+
if (token === "--" && !spec.expressionArgs) {
|
|
2488
|
+
operands.push(...seg.args.slice(i + 1));
|
|
2489
|
+
break;
|
|
2490
|
+
}
|
|
2491
|
+
if (!/^-./.test(token)) {
|
|
2492
|
+
operands.push(token);
|
|
2493
|
+
i++;
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
const shape = matchFlag(spec, booleans, values, token);
|
|
2497
|
+
if (shape === void 0) return { unknown: flagLabel(token), operands };
|
|
2498
|
+
i += shape === "value" && takesNextToken(seg.args[i + 1]) ? 2 : 1;
|
|
2499
|
+
}
|
|
2500
|
+
return { operands };
|
|
2501
|
+
}
|
|
2502
|
+
function subcommandOf(seg) {
|
|
2503
|
+
const scan = scanFlags(seg);
|
|
2504
|
+
if (scan) return scan.operands[0];
|
|
2505
|
+
return seg.args.find((a) => !a.startsWith("-"));
|
|
2506
|
+
}
|
|
2507
|
+
var SCOPE_LEAD_ARGS = 2;
|
|
1055
2508
|
function scopeFor(seg) {
|
|
1056
2509
|
if (!MULTIPLEXERS.includes(seg.binary)) return seg.binary;
|
|
1057
|
-
const
|
|
1058
|
-
|
|
2510
|
+
const lead = [];
|
|
2511
|
+
for (const arg of seg.args) {
|
|
2512
|
+
if (arg.startsWith("-")) break;
|
|
2513
|
+
lead.push(arg);
|
|
2514
|
+
if (lead.length === SCOPE_LEAD_ARGS) break;
|
|
2515
|
+
}
|
|
2516
|
+
return [seg.binary, ...lead].join(" ");
|
|
1059
2517
|
}
|
|
1060
2518
|
function isAuto(seg) {
|
|
1061
2519
|
if (!AUTO_COMMANDS.includes(seg.binary)) return false;
|
|
1062
2520
|
if (seg.expandable) return false;
|
|
1063
2521
|
if (seg.binary !== "git") return true;
|
|
1064
|
-
const sub = seg
|
|
2522
|
+
const sub = subcommandOf(seg);
|
|
1065
2523
|
return sub !== void 0 && GIT_READONLY_SUBCOMMANDS.includes(sub);
|
|
1066
2524
|
}
|
|
1067
2525
|
function refusalFor(seg) {
|
|
@@ -1071,20 +2529,32 @@ function refusalFor(seg) {
|
|
|
1071
2529
|
if (seg.binary === "eval" || seg.binary === "exec") {
|
|
1072
2530
|
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.`;
|
|
1073
2531
|
}
|
|
2532
|
+
if (seg.binary === "source" || seg.binary === ".") {
|
|
2533
|
+
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.`;
|
|
2534
|
+
}
|
|
2535
|
+
if (SHELL_KEYWORDS.includes(seg.binary)) {
|
|
2536
|
+
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.`;
|
|
2537
|
+
}
|
|
1074
2538
|
const subs = REFUSED_SUBCOMMANDS[seg.binary];
|
|
1075
2539
|
if (subs) {
|
|
1076
|
-
const sub = seg
|
|
2540
|
+
const sub = subcommandOf(seg);
|
|
1077
2541
|
if (sub && subs.includes(sub)) {
|
|
1078
2542
|
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.`;
|
|
1079
2543
|
}
|
|
1080
2544
|
}
|
|
1081
2545
|
if (seg.binary === "git") {
|
|
1082
|
-
const sub = seg
|
|
2546
|
+
const sub = subcommandOf(seg);
|
|
1083
2547
|
if (sub === "branch" || sub === "tag") {
|
|
1084
2548
|
const flag = seg.args.find((a) => ["-D", "-d", "-m", "-M", "--delete", "--move"].includes(a));
|
|
1085
2549
|
if (flag) {
|
|
1086
2550
|
return `"git ${sub} ${flag}" mutates refs. You are a read-only planner \u2014 describe the change as a task instead.`;
|
|
1087
2551
|
}
|
|
2552
|
+
const listing = seg.args.includes("-l") || seg.args.includes("--list");
|
|
2553
|
+
const scan2 = scanFlags(seg);
|
|
2554
|
+
const target = scan2?.operands[1];
|
|
2555
|
+
if (!listing && target) {
|
|
2556
|
+
return `"git ${sub} ${target}" creates or moves a ref. You are a read-only planner \u2014 describe the change as a task instead.`;
|
|
2557
|
+
}
|
|
1088
2558
|
}
|
|
1089
2559
|
}
|
|
1090
2560
|
if (seg.binary === "find") {
|
|
@@ -1108,8 +2578,24 @@ function refusalFor(seg) {
|
|
|
1108
2578
|
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.`;
|
|
1109
2579
|
}
|
|
1110
2580
|
}
|
|
2581
|
+
if (seg.assignments.length > 0) {
|
|
2582
|
+
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.`;
|
|
2583
|
+
}
|
|
2584
|
+
const scan = scanFlags(seg);
|
|
2585
|
+
if (scan?.unknown) {
|
|
2586
|
+
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.`;
|
|
2587
|
+
}
|
|
2588
|
+
if (seg.binary === "uniq" && scan && scan.operands.length > 1) {
|
|
2589
|
+
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.`;
|
|
2590
|
+
}
|
|
1111
2591
|
return void 0;
|
|
1112
2592
|
}
|
|
2593
|
+
function withWrapperNote(reason, wrappers) {
|
|
2594
|
+
if (wrappers.length === 0) return reason;
|
|
2595
|
+
const quoted = wrappers.map((w) => `"${w}"`);
|
|
2596
|
+
const names = quoted.length > 1 ? `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}` : quoted[0];
|
|
2597
|
+
return `${reason} Wrapping it in ${names} does not change what runs.`;
|
|
2598
|
+
}
|
|
1113
2599
|
function classifyCommand(command, opts = {}) {
|
|
1114
2600
|
const trimmed = command.trim();
|
|
1115
2601
|
if (!trimmed) return { tier: "refuse", scope: "", reason: "Empty command." };
|
|
@@ -1138,11 +2624,13 @@ function classifyCommand(command, opts = {}) {
|
|
|
1138
2624
|
};
|
|
1139
2625
|
}
|
|
1140
2626
|
if (segments.length === 0) return { tier: "refuse", scope: "", reason: "No command found." };
|
|
1141
|
-
|
|
2627
|
+
const unwrapped = segments.map((seg) => unwrap(seg, dialect));
|
|
2628
|
+
for (const { seg, wrappers, reason: wrapperReason } of unwrapped) {
|
|
2629
|
+
if (wrapperReason) return { tier: "refuse", scope: "", reason: wrapperReason };
|
|
1142
2630
|
const reason = refusalFor(seg);
|
|
1143
|
-
if (reason) return { tier: "refuse", scope: "", reason };
|
|
2631
|
+
if (reason) return { tier: "refuse", scope: "", reason: withWrapperNote(reason, wrappers) };
|
|
1144
2632
|
}
|
|
1145
|
-
const nonAuto =
|
|
2633
|
+
const nonAuto = unwrapped.map((u) => u.seg).filter((s) => !isAuto(s));
|
|
1146
2634
|
if (nonAuto.length === 0) return { tier: "auto", scope: "" };
|
|
1147
2635
|
const scope = [...new Set(nonAuto.map(scopeFor))].sort().join(" + ");
|
|
1148
2636
|
return { tier: "ask", scope };
|
|
@@ -1486,6 +2974,139 @@ It is outside the auto-allowed read-only set (${scope}). Continue with the read-
|
|
|
1486
2974
|
}
|
|
1487
2975
|
};
|
|
1488
2976
|
|
|
2977
|
+
// src/utils/redactSecrets.ts
|
|
2978
|
+
var REDACTION_MARKER = "REDACTED";
|
|
2979
|
+
function marker(kind, length) {
|
|
2980
|
+
return `[${REDACTION_MARKER} ${kind}: ${length} chars]`;
|
|
2981
|
+
}
|
|
2982
|
+
var LINE_PREFIX = String.raw`(?:[ \t]*\d+\||[^\s:]*:\d+:|)[ \t]*`;
|
|
2983
|
+
var LINE_PREFIX_ANCHORED = new RegExp("^" + LINE_PREFIX);
|
|
2984
|
+
var CREDENTIAL_WORD = String.raw`(?:api[_-]?keys?|secrets?|passwords?|passwd|passphrase|tokens?|access[_-]?keys?|private[_-]?keys?|client[_-]?secrets?|credentials?|auth)(?![a-z])`;
|
|
2985
|
+
var NAMED_CREDENTIAL = new RegExp(
|
|
2986
|
+
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`,
|
|
2987
|
+
"gi"
|
|
2988
|
+
);
|
|
2989
|
+
var DOTENV_CREDENTIAL = new RegExp(
|
|
2990
|
+
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]*$`,
|
|
2991
|
+
"gm"
|
|
2992
|
+
);
|
|
2993
|
+
var PROVIDER_KEY_PATTERNS = [
|
|
2994
|
+
// OpenAI / Anthropic / OpenRouter and the many `sk-` derivatives
|
|
2995
|
+
/(?<![A-Za-z0-9])sk-(?:ant-|proj-|or-v1-|live-|test-)?[A-Za-z0-9_-]{20,}/g,
|
|
2996
|
+
// GitHub personal-access, OAuth, app and refresh tokens
|
|
2997
|
+
/(?<![A-Za-z0-9])(?:gh[pousr]|github_pat)_[A-Za-z0-9_]{22,}/g,
|
|
2998
|
+
// Slack bot / user / app tokens
|
|
2999
|
+
/(?<![A-Za-z0-9])xox[abprse]-[A-Za-z0-9-]{10,}/g,
|
|
3000
|
+
// Stripe secret and restricted keys
|
|
3001
|
+
/(?<![A-Za-z0-9])[sr]k_(?:live|test)_[A-Za-z0-9]{16,}/g,
|
|
3002
|
+
// Google API keys and OAuth access tokens
|
|
3003
|
+
/(?<![A-Za-z0-9])AIza[A-Za-z0-9_-]{30,}/g,
|
|
3004
|
+
/(?<![A-Za-z0-9])ya29\.[A-Za-z0-9_-]{20,}/g,
|
|
3005
|
+
// npm, Hugging Face, Groq, GitLab, DigitalOcean, Shopify
|
|
3006
|
+
/(?<![A-Za-z0-9])(?:npm|hf|gsk|glpat|dop_v1|shpat|shpss)[_-][A-Za-z0-9]{20,}/g,
|
|
3007
|
+
/(?<![A-Za-z0-9])xai-[A-Za-z0-9]{20,}/g,
|
|
3008
|
+
// Three-segment JWTs, whose payload segment is base64 for `{"`
|
|
3009
|
+
/(?<![A-Za-z0-9])eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g
|
|
3010
|
+
];
|
|
3011
|
+
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;
|
|
3012
|
+
var PEM_BEGIN = /-----BEGIN ((?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?)-----/;
|
|
3013
|
+
var PEM_BODY_LINE = /^[A-Za-z0-9+/=:,.\- \t]*$/;
|
|
3014
|
+
function redactPrivateKeyBlocks(text) {
|
|
3015
|
+
if (!PEM_BEGIN.test(text)) return text;
|
|
3016
|
+
const out = [];
|
|
3017
|
+
let label = null;
|
|
3018
|
+
let bodyChars = 0;
|
|
3019
|
+
const closeBlock = () => {
|
|
3020
|
+
if (label === null) return;
|
|
3021
|
+
out.push(marker("private key", bodyChars));
|
|
3022
|
+
label = null;
|
|
3023
|
+
bodyChars = 0;
|
|
3024
|
+
};
|
|
3025
|
+
for (const line of text.split("\n")) {
|
|
3026
|
+
if (label === null) {
|
|
3027
|
+
out.push(line);
|
|
3028
|
+
const begun = PEM_BEGIN.exec(line);
|
|
3029
|
+
if (begun) label = begun[1];
|
|
3030
|
+
continue;
|
|
3031
|
+
}
|
|
3032
|
+
const content = line.replace(LINE_PREFIX_ANCHORED, "");
|
|
3033
|
+
if (content.includes(`-----END ${label}-----`)) {
|
|
3034
|
+
closeBlock();
|
|
3035
|
+
out.push(line);
|
|
3036
|
+
} else if (PEM_BODY_LINE.test(content)) {
|
|
3037
|
+
bodyChars += content.trim().length;
|
|
3038
|
+
} else {
|
|
3039
|
+
closeBlock();
|
|
3040
|
+
out.push(line);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
closeBlock();
|
|
3044
|
+
return out.join("\n");
|
|
3045
|
+
}
|
|
3046
|
+
var NUMERIC = /^[-+]?\d+(?:\.\d+)?$/;
|
|
3047
|
+
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
3048
|
+
var MEMBER_EXPRESSION = /^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)+$/;
|
|
3049
|
+
var SLUG = /^[a-z]+(?:[-_][a-z]+)+$/;
|
|
3050
|
+
var PATHISH = /^(?:\.{0,2}\/|~\/)/;
|
|
3051
|
+
var URLISH = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
3052
|
+
var CODE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
3053
|
+
"true",
|
|
3054
|
+
"false",
|
|
3055
|
+
"null",
|
|
3056
|
+
"none",
|
|
3057
|
+
"nil",
|
|
3058
|
+
"undefined",
|
|
3059
|
+
"void",
|
|
3060
|
+
"string",
|
|
3061
|
+
"number",
|
|
3062
|
+
"boolean",
|
|
3063
|
+
"object",
|
|
3064
|
+
"any",
|
|
3065
|
+
"unknown",
|
|
3066
|
+
"bool",
|
|
3067
|
+
"str",
|
|
3068
|
+
"int"
|
|
3069
|
+
]);
|
|
3070
|
+
var UNAMBIGUOUS_CREDENTIAL_NAME = /(?:password|passwd|passphrase|secret|credentials?|private[_-]?key)/i;
|
|
3071
|
+
function looksLikeKeyMaterial(value) {
|
|
3072
|
+
const hasDigit = /\d/.test(value);
|
|
3073
|
+
const hasAlpha = /[A-Za-z]/.test(value);
|
|
3074
|
+
const mixedCase = /[a-z]/.test(value) && /[A-Z]/.test(value);
|
|
3075
|
+
return hasDigit && hasAlpha || mixedCase || value.length >= 24;
|
|
3076
|
+
}
|
|
3077
|
+
function looksLikeCode(value) {
|
|
3078
|
+
return NUMERIC.test(value) || CODE_KEYWORDS.has(value.toLowerCase()) || MEMBER_EXPRESSION.test(value) || PATHISH.test(value) || URLISH.test(value);
|
|
3079
|
+
}
|
|
3080
|
+
function trimTrailingPunctuation(value) {
|
|
3081
|
+
const match = /[.:!]+$/.exec(value);
|
|
3082
|
+
if (!match || match.index === 0) return { value, tail: "" };
|
|
3083
|
+
return { value: value.slice(0, match.index), tail: match[0] };
|
|
3084
|
+
}
|
|
3085
|
+
function redactSecrets(text) {
|
|
3086
|
+
if (!text) return text;
|
|
3087
|
+
let out = redactPrivateKeyBlocks(text);
|
|
3088
|
+
out = out.replace(DOTENV_CREDENTIAL, (full, head, quote, value) => {
|
|
3089
|
+
if (looksLikeCode(value) || value.startsWith("$")) return full;
|
|
3090
|
+
return `${head}${quote}${marker("credential", value.length)}${quote}`;
|
|
3091
|
+
});
|
|
3092
|
+
out = out.replace(NAMED_CREDENTIAL, (full, head, quote, raw) => {
|
|
3093
|
+
const { value, tail } = trimTrailingPunctuation(raw);
|
|
3094
|
+
if (value.length < 8) return full;
|
|
3095
|
+
if (looksLikeCode(value) || value.startsWith("$")) return full;
|
|
3096
|
+
if (UNAMBIGUOUS_CREDENTIAL_NAME.test(head) && /\d/.test(value)) {
|
|
3097
|
+
return `${head}${quote}${marker("credential", value.length)}${quote}${tail}`;
|
|
3098
|
+
}
|
|
3099
|
+
if (IDENTIFIER.test(value) || SLUG.test(value)) return full;
|
|
3100
|
+
if (!UNAMBIGUOUS_CREDENTIAL_NAME.test(head) && !looksLikeKeyMaterial(value)) return full;
|
|
3101
|
+
return `${head}${quote}${marker("credential", value.length)}${quote}${tail}`;
|
|
3102
|
+
});
|
|
3103
|
+
for (const pattern of PROVIDER_KEY_PATTERNS) {
|
|
3104
|
+
out = out.replace(pattern, (hit) => marker("api key", hit.length));
|
|
3105
|
+
}
|
|
3106
|
+
out = out.replace(CLOUD_ACCESS_KEY_ID, (hit) => marker("access key id", hit.length));
|
|
3107
|
+
return out;
|
|
3108
|
+
}
|
|
3109
|
+
|
|
1489
3110
|
// src/services/executeTool.ts
|
|
1490
3111
|
var GREP_OUTPUT_MODES = ["content", "files", "count"];
|
|
1491
3112
|
function num(value) {
|
|
@@ -1512,6 +3133,10 @@ function grepOptions(args) {
|
|
|
1512
3133
|
}
|
|
1513
3134
|
var STOPPED_TOOL_RESULT = "Stopped by the user \u2014 this call was not executed, and no further tool calls will run this turn.";
|
|
1514
3135
|
async function executeTool(name, args, fs10, fetcher, signal) {
|
|
3136
|
+
const outcome = await runTool(name, args, fs10, fetcher, signal);
|
|
3137
|
+
return { ...outcome, output: redactSecrets(outcome.output) };
|
|
3138
|
+
}
|
|
3139
|
+
async function runTool(name, args, fs10, fetcher, signal) {
|
|
1515
3140
|
if (signal?.aborted) return { success: false, output: STOPPED_TOOL_RESULT, truncated: false };
|
|
1516
3141
|
switch (name) {
|
|
1517
3142
|
case "read_file": {
|
|
@@ -1641,14 +3266,14 @@ var PendingApprovals = class {
|
|
|
1641
3266
|
ask(request) {
|
|
1642
3267
|
const id = `ap-${Date.now()}-${counter++}`;
|
|
1643
3268
|
const pending = { id, request, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1644
|
-
return new Promise((
|
|
3269
|
+
return new Promise((resolve4) => {
|
|
1645
3270
|
const settle = (granted) => {
|
|
1646
3271
|
const entry = this.entries.get(id);
|
|
1647
3272
|
if (!entry) return;
|
|
1648
3273
|
clearTimeout(entry.timer);
|
|
1649
3274
|
this.entries.delete(id);
|
|
1650
3275
|
this.opts.onSettled?.(id, granted);
|
|
1651
|
-
|
|
3276
|
+
resolve4(granted);
|
|
1652
3277
|
};
|
|
1653
3278
|
const timer = setTimeout(() => settle(false), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
1654
3279
|
timer.unref?.();
|
|
@@ -4558,9 +6183,9 @@ function summarizeToolCall(tool, argsJson, toolLabel) {
|
|
|
4558
6183
|
const scope = args.include ? ` in ${args.include}` : "";
|
|
4559
6184
|
return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;
|
|
4560
6185
|
}
|
|
4561
|
-
const
|
|
4562
|
-
if (
|
|
4563
|
-
const basename = String(
|
|
6186
|
+
const path17 = args.filePath || args.file_path || args.path;
|
|
6187
|
+
if (path17) {
|
|
6188
|
+
const basename = String(path17).split("/").pop() || String(path17);
|
|
4564
6189
|
return `${display} ${basename}`;
|
|
4565
6190
|
}
|
|
4566
6191
|
if (args.pattern) {
|
|
@@ -5780,11 +7405,11 @@ function composeAugmentedPrompt(task, allTasks, opts) {
|
|
|
5780
7405
|
if (isHitlTask(task)) {
|
|
5781
7406
|
blocks.push(renderCheckpointInstruction());
|
|
5782
7407
|
}
|
|
5783
|
-
const
|
|
5784
|
-
if (blocks.length === 0) return basePrompt +
|
|
7408
|
+
const marker2 = renderCompletionMarker(task);
|
|
7409
|
+
if (blocks.length === 0) return basePrompt + marker2;
|
|
5785
7410
|
return `${blocks.join("\n\n")}
|
|
5786
7411
|
|
|
5787
|
-
${basePrompt}${
|
|
7412
|
+
${basePrompt}${marker2}`;
|
|
5788
7413
|
}
|
|
5789
7414
|
|
|
5790
7415
|
// src/services/VerdictEngine.ts
|
|
@@ -7221,28 +8846,28 @@ function posixBinDirs() {
|
|
|
7221
8846
|
];
|
|
7222
8847
|
}
|
|
7223
8848
|
function windowsBinDirs(env, home) {
|
|
7224
|
-
const
|
|
7225
|
-
const under = (base, ...parts) => base ? [
|
|
8849
|
+
const join16 = (...parts) => path5.win32.join(...parts);
|
|
8850
|
+
const under = (base, ...parts) => base ? [join16(base, ...parts)] : [];
|
|
7226
8851
|
const appData = env.APPDATA;
|
|
7227
8852
|
const localAppData = env.LOCALAPPDATA;
|
|
7228
8853
|
const programData = env.ProgramData;
|
|
7229
8854
|
return [
|
|
7230
8855
|
// Native per-user installers, PowerShell-driven and otherwise.
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
8856
|
+
join16(home, ".local", "bin"),
|
|
8857
|
+
join16(home, ".opencode", "bin"),
|
|
8858
|
+
join16(home, ".claude", "bin"),
|
|
8859
|
+
join16(home, ".codex", "bin"),
|
|
7235
8860
|
...under(localAppData, "Programs", "claude"),
|
|
7236
8861
|
// Node package managers. npm's global prefix is `%APPDATA%\npm`; the
|
|
7237
8862
|
// literal spelling is kept as a fallback for a host that does not export
|
|
7238
8863
|
// APPDATA (a service account, a stripped CI container).
|
|
7239
8864
|
...under(appData, "npm"),
|
|
7240
|
-
|
|
8865
|
+
join16(home, "AppData", "Roaming", "npm"),
|
|
7241
8866
|
...under(localAppData, "pnpm"),
|
|
7242
8867
|
...under(localAppData, "Yarn", "bin"),
|
|
7243
|
-
|
|
8868
|
+
join16(home, ".bun", "bin"),
|
|
7244
8869
|
// Windows package managers.
|
|
7245
|
-
|
|
8870
|
+
join16(home, "scoop", "shims"),
|
|
7246
8871
|
...under(env.SCOOP, "shims"),
|
|
7247
8872
|
...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
|
|
7248
8873
|
...under(programData, "chocolatey", "bin"),
|
|
@@ -7252,7 +8877,7 @@ function windowsBinDirs(env, home) {
|
|
|
7252
8877
|
...under(localAppData, "Microsoft", "WindowsApps"),
|
|
7253
8878
|
// Version managers. Volta's Windows home is not the POSIX `~/.volta`.
|
|
7254
8879
|
...under(localAppData, "Volta", "bin"),
|
|
7255
|
-
|
|
8880
|
+
join16(home, ".volta", "bin")
|
|
7256
8881
|
];
|
|
7257
8882
|
}
|
|
7258
8883
|
function wellKnownBinDirs(deps = {}) {
|
|
@@ -7553,7 +9178,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
7553
9178
|
const PATH = await augmentedPath();
|
|
7554
9179
|
const launch = await planDirectLaunch(command, args).catch(() => null);
|
|
7555
9180
|
if (!launch) return null;
|
|
7556
|
-
return new Promise((
|
|
9181
|
+
return new Promise((resolve4) => {
|
|
7557
9182
|
let child;
|
|
7558
9183
|
try {
|
|
7559
9184
|
child = (0, import_child_process3.spawn)(launch.file, launch.args, {
|
|
@@ -7562,7 +9187,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
7562
9187
|
windowsVerbatimArguments: launch.verbatim
|
|
7563
9188
|
});
|
|
7564
9189
|
} catch {
|
|
7565
|
-
|
|
9190
|
+
resolve4(null);
|
|
7566
9191
|
return;
|
|
7567
9192
|
}
|
|
7568
9193
|
let settled = false;
|
|
@@ -7571,7 +9196,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
7571
9196
|
settled = true;
|
|
7572
9197
|
clearTimeout(timer);
|
|
7573
9198
|
killTree(child);
|
|
7574
|
-
|
|
9199
|
+
resolve4(value);
|
|
7575
9200
|
};
|
|
7576
9201
|
const timer = setTimeout(() => finish(null), options?.timeout ?? 2e4);
|
|
7577
9202
|
child.on("error", () => finish(null));
|
|
@@ -8611,11 +10236,71 @@ var RunnerInstallation = class {
|
|
|
8611
10236
|
}
|
|
8612
10237
|
};
|
|
8613
10238
|
|
|
10239
|
+
// src/services/settingsEnvAllowlist.ts
|
|
10240
|
+
var ORDEWELL_SETTABLE_ENV = [
|
|
10241
|
+
"AI_PROVIDER",
|
|
10242
|
+
"ORCHESTRATOR_MODEL",
|
|
10243
|
+
"ORDEWELL_SUBAGENT_MODEL",
|
|
10244
|
+
"ORDEWELL_PLANNER_EFFORT",
|
|
10245
|
+
"ORDEWELL_RESEARCH_ENABLED",
|
|
10246
|
+
"ORDEWELL_MAX_PARALLEL"
|
|
10247
|
+
];
|
|
10248
|
+
var SETTINGS_ENV_REFUSED = [
|
|
10249
|
+
// Approval posture and pre-approved scope.
|
|
10250
|
+
"ORDEWELL_AUTONOMOUS_MODE",
|
|
10251
|
+
"ORDEWELL_APPROVAL_MODE",
|
|
10252
|
+
"ORDEWELL_APPROVAL_ALLOW",
|
|
10253
|
+
// Where settings are persisted.
|
|
10254
|
+
"ORDEWELL_SETTINGS_PATH",
|
|
10255
|
+
// Runtime options and dynamic loaders.
|
|
10256
|
+
"NODE_OPTIONS",
|
|
10257
|
+
"NODE_REPL_EXTERNAL_MODULE",
|
|
10258
|
+
"NODE_PATH",
|
|
10259
|
+
"ELECTRON_RUN_AS_NODE",
|
|
10260
|
+
"LD_PRELOAD",
|
|
10261
|
+
"LD_LIBRARY_PATH",
|
|
10262
|
+
"LD_AUDIT",
|
|
10263
|
+
"DYLD_INSERT_LIBRARIES",
|
|
10264
|
+
"DYLD_LIBRARY_PATH",
|
|
10265
|
+
"DYLD_FRAMEWORK_PATH",
|
|
10266
|
+
// Executable resolution.
|
|
10267
|
+
"PATH",
|
|
10268
|
+
"PATHEXT",
|
|
10269
|
+
"NODE"
|
|
10270
|
+
];
|
|
10271
|
+
var REFUSED = new Set(SETTINGS_ENV_REFUSED);
|
|
10272
|
+
function providerEnvKeys() {
|
|
10273
|
+
const keys = [];
|
|
10274
|
+
for (const meta of Object.values(ALL_PROVIDERS)) {
|
|
10275
|
+
if (meta.apiKeyEnvVar) keys.push(meta.apiKeyEnvVar);
|
|
10276
|
+
if (meta.baseUrlEnvVar) keys.push(meta.baseUrlEnvVar);
|
|
10277
|
+
for (const detect of meta.detectEnvVars) keys.push(detect);
|
|
10278
|
+
}
|
|
10279
|
+
return keys;
|
|
10280
|
+
}
|
|
10281
|
+
var PROVIDER_CREDENTIAL_ENV = new Set(providerEnvKeys());
|
|
10282
|
+
var SETTINGS_ENV_ALLOWLIST = new Set(
|
|
10283
|
+
[...providerEnvKeys(), ...ORDEWELL_SETTABLE_ENV].filter((key) => !REFUSED.has(key))
|
|
10284
|
+
);
|
|
10285
|
+
function admitSettingsEnv(env) {
|
|
10286
|
+
const accepted = {};
|
|
10287
|
+
const rejected = [];
|
|
10288
|
+
for (const [key, value] of Object.entries(env)) {
|
|
10289
|
+
if (REFUSED.has(key) || !SETTINGS_ENV_ALLOWLIST.has(key) || typeof value !== "string") {
|
|
10290
|
+
rejected.push(key);
|
|
10291
|
+
continue;
|
|
10292
|
+
}
|
|
10293
|
+
accepted[key] = value;
|
|
10294
|
+
}
|
|
10295
|
+
return { accepted, rejected };
|
|
10296
|
+
}
|
|
10297
|
+
|
|
8614
10298
|
// src/services/harness/CliAgentAiService.ts
|
|
8615
10299
|
var import_child_process5 = require("child_process");
|
|
8616
10300
|
|
|
8617
10301
|
// src/utils/workspace.ts
|
|
8618
10302
|
var fs3 = __toESM(require("fs"));
|
|
10303
|
+
var path9 = __toESM(require("path"));
|
|
8619
10304
|
var WorkspaceNotFoundError = class extends Error {
|
|
8620
10305
|
constructor(workspace) {
|
|
8621
10306
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -8635,6 +10320,46 @@ function assertWorkspaceExists(workspace, deps = {}) {
|
|
|
8635
10320
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
8636
10321
|
if (!isDirectory(workspace)) throw new WorkspaceNotFoundError(workspace);
|
|
8637
10322
|
}
|
|
10323
|
+
var WorkspaceNotAProjectError = class extends Error {
|
|
10324
|
+
constructor(workspace) {
|
|
10325
|
+
super(`Workspace "${workspace}" is not a project directory (no .ordewell state, version control, or recognized manifest found).`);
|
|
10326
|
+
this.workspace = workspace;
|
|
10327
|
+
this.name = "WorkspaceNotAProjectError";
|
|
10328
|
+
}
|
|
10329
|
+
workspace;
|
|
10330
|
+
};
|
|
10331
|
+
var PROJECT_MARKER_DIRS = [".ordewell", ".git", ".hg", ".svn", ".bzr"];
|
|
10332
|
+
var PROJECT_MARKER_FILES = [
|
|
10333
|
+
"package.json",
|
|
10334
|
+
"Cargo.toml",
|
|
10335
|
+
"go.mod",
|
|
10336
|
+
"pyproject.toml",
|
|
10337
|
+
"setup.py",
|
|
10338
|
+
"requirements.txt",
|
|
10339
|
+
"Pipfile",
|
|
10340
|
+
"pom.xml",
|
|
10341
|
+
"build.gradle",
|
|
10342
|
+
"build.gradle.kts",
|
|
10343
|
+
"Gemfile",
|
|
10344
|
+
"composer.json",
|
|
10345
|
+
"pubspec.yaml",
|
|
10346
|
+
"mix.exs",
|
|
10347
|
+
"CMakeLists.txt"
|
|
10348
|
+
];
|
|
10349
|
+
function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
10350
|
+
const realpath = deps.realpath ?? ((candidate) => fs3.realpathSync(candidate));
|
|
10351
|
+
const exists = deps.exists ?? ((candidate) => fs3.existsSync(candidate));
|
|
10352
|
+
let resolved;
|
|
10353
|
+
try {
|
|
10354
|
+
resolved = realpath(workspace);
|
|
10355
|
+
} catch {
|
|
10356
|
+
throw new WorkspaceNotAProjectError(workspace);
|
|
10357
|
+
}
|
|
10358
|
+
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
10359
|
+
(marker2) => exists(path9.join(resolved, marker2))
|
|
10360
|
+
);
|
|
10361
|
+
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
10362
|
+
}
|
|
8638
10363
|
|
|
8639
10364
|
// src/services/harness/AgentAdapter.ts
|
|
8640
10365
|
var LineBuffer = class {
|
|
@@ -8690,8 +10415,8 @@ var StdioAgentAdapter = class {
|
|
|
8690
10415
|
}
|
|
8691
10416
|
async start(opts) {
|
|
8692
10417
|
assertWorkspaceExists(opts.cwd, { isDirectory: this.deps.isDirectory });
|
|
8693
|
-
this.processEnded = new Promise((
|
|
8694
|
-
this.markEnded =
|
|
10418
|
+
this.processEnded = new Promise((resolve4) => {
|
|
10419
|
+
this.markEnded = resolve4;
|
|
8695
10420
|
});
|
|
8696
10421
|
const spec = this.spawnSpec(opts);
|
|
8697
10422
|
const resolvePath = this.deps.resolvePath ?? augmentedPath;
|
|
@@ -8739,7 +10464,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
8739
10464
|
onEvent({ type: "error", message: this.exitMessage() });
|
|
8740
10465
|
return;
|
|
8741
10466
|
}
|
|
8742
|
-
await new Promise((
|
|
10467
|
+
await new Promise((resolve4) => {
|
|
8743
10468
|
let settled = false;
|
|
8744
10469
|
const finish = () => {
|
|
8745
10470
|
if (settled) return;
|
|
@@ -8748,7 +10473,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
8748
10473
|
signal?.removeEventListener("abort", onAbort);
|
|
8749
10474
|
this.process?.removeListener("exit", onExit);
|
|
8750
10475
|
this.process?.removeListener("error", onExit);
|
|
8751
|
-
|
|
10476
|
+
resolve4();
|
|
8752
10477
|
};
|
|
8753
10478
|
const emit = (event) => {
|
|
8754
10479
|
onEvent(event);
|
|
@@ -8949,14 +10674,14 @@ function codexSandboxUnavailableMessage() {
|
|
|
8949
10674
|
].join("\n");
|
|
8950
10675
|
}
|
|
8951
10676
|
function runProbe(deps, cwd, env, flags) {
|
|
8952
|
-
return new Promise((
|
|
10677
|
+
return new Promise((resolve4) => {
|
|
8953
10678
|
let output = "";
|
|
8954
10679
|
let settled = false;
|
|
8955
10680
|
const finish = (code) => {
|
|
8956
10681
|
if (settled) return;
|
|
8957
10682
|
settled = true;
|
|
8958
10683
|
clearTimeout(timer);
|
|
8959
|
-
|
|
10684
|
+
resolve4({ code, output });
|
|
8960
10685
|
};
|
|
8961
10686
|
const timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);
|
|
8962
10687
|
timer.unref?.();
|
|
@@ -9039,8 +10764,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
9039
10764
|
async handshake(opts) {
|
|
9040
10765
|
this.sandbox = await probeCodexSandbox(this.deps, opts.cwd, this.spawnEnv);
|
|
9041
10766
|
if (this.sandbox === "unavailable") throw new Error(codexSandboxUnavailableMessage());
|
|
9042
|
-
const ready = new Promise((
|
|
9043
|
-
this.settleHandshake =
|
|
10767
|
+
const ready = new Promise((resolve4) => {
|
|
10768
|
+
this.settleHandshake = resolve4;
|
|
9044
10769
|
});
|
|
9045
10770
|
this.writeLine({
|
|
9046
10771
|
jsonrpc: "2.0",
|
|
@@ -9053,8 +10778,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
9053
10778
|
// A binary that rejects `app-server` outright dies immediately; waiting
|
|
9054
10779
|
// out the timeout would turn a one-line diagnostic into a 30s stall.
|
|
9055
10780
|
this.processEnded.then(() => false),
|
|
9056
|
-
new Promise((
|
|
9057
|
-
const t = setTimeout(() =>
|
|
10781
|
+
new Promise((resolve4) => {
|
|
10782
|
+
const t = setTimeout(() => resolve4(false), HANDSHAKE_TIMEOUT_MS);
|
|
9058
10783
|
t.unref?.();
|
|
9059
10784
|
})
|
|
9060
10785
|
]);
|
|
@@ -9342,12 +11067,12 @@ var OpenCodeAdapter = class {
|
|
|
9342
11067
|
cwd: opts.cwd,
|
|
9343
11068
|
windowsVerbatimArguments: launch.verbatim
|
|
9344
11069
|
});
|
|
9345
|
-
const banner = new Promise((
|
|
11070
|
+
const banner = new Promise((resolve4) => {
|
|
9346
11071
|
let seen = "";
|
|
9347
11072
|
const scan = (chunk) => {
|
|
9348
11073
|
seen += chunk.toString();
|
|
9349
11074
|
const match = seen.match(/https?:\/\/[^\s]+/);
|
|
9350
|
-
if (match)
|
|
11075
|
+
if (match) resolve4(match[0].replace(/[.,)]$/, ""));
|
|
9351
11076
|
};
|
|
9352
11077
|
this.process.stdout?.on("data", scan);
|
|
9353
11078
|
this.process.stderr?.on("data", (chunk) => {
|
|
@@ -9356,15 +11081,15 @@ var OpenCodeAdapter = class {
|
|
|
9356
11081
|
});
|
|
9357
11082
|
this.process.on("exit", () => {
|
|
9358
11083
|
this.exited = true;
|
|
9359
|
-
|
|
11084
|
+
resolve4(null);
|
|
9360
11085
|
});
|
|
9361
11086
|
this.process.on("error", (err) => {
|
|
9362
11087
|
this.exited = true;
|
|
9363
11088
|
this.stderrTail = (this.stderrTail + `
|
|
9364
11089
|
${err.message}`).slice(-STDERR_TAIL_CHARS2);
|
|
9365
|
-
|
|
11090
|
+
resolve4(null);
|
|
9366
11091
|
});
|
|
9367
|
-
const timer = setTimeout(() =>
|
|
11092
|
+
const timer = setTimeout(() => resolve4(null), SERVER_READY_TIMEOUT_MS);
|
|
9368
11093
|
timer.unref?.();
|
|
9369
11094
|
});
|
|
9370
11095
|
this.baseUrl = await banner;
|
|
@@ -9394,8 +11119,8 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
9394
11119
|
const streamAbort = new AbortController();
|
|
9395
11120
|
let connected = () => {
|
|
9396
11121
|
};
|
|
9397
|
-
const streamReady = new Promise((
|
|
9398
|
-
connected =
|
|
11122
|
+
const streamReady = new Promise((resolve4) => {
|
|
11123
|
+
connected = resolve4;
|
|
9399
11124
|
});
|
|
9400
11125
|
const live = this.streamEvents(
|
|
9401
11126
|
streamAbort.signal,
|
|
@@ -9547,14 +11272,14 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
9547
11272
|
}
|
|
9548
11273
|
}
|
|
9549
11274
|
}
|
|
9550
|
-
async json(method,
|
|
9551
|
-
const response = await this.deps.fetch(`${this.baseUrl}${
|
|
11275
|
+
async json(method, path17, body, signal) {
|
|
11276
|
+
const response = await this.deps.fetch(`${this.baseUrl}${path17}`, {
|
|
9552
11277
|
method,
|
|
9553
11278
|
headers: { "content-type": "application/json" },
|
|
9554
11279
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
9555
11280
|
...signal ? { signal } : {}
|
|
9556
11281
|
});
|
|
9557
|
-
if (!response.ok) throw new Error(`${method} ${
|
|
11282
|
+
if (!response.ok) throw new Error(`${method} ${path17} failed: ${response.status} ${response.statusText}`);
|
|
9558
11283
|
return await response.json().catch(() => null);
|
|
9559
11284
|
}
|
|
9560
11285
|
nativeSessionId() {
|
|
@@ -9851,7 +11576,8 @@ var CliAgentAiService = class {
|
|
|
9851
11576
|
let stepIndex = 0;
|
|
9852
11577
|
const truncate = (value) => value.length > LOG_MAX_CHARS ? `${value.slice(0, LOG_MAX_CHARS)}
|
|
9853
11578
|
[... truncated, total ${value.length} chars]` : value;
|
|
9854
|
-
const settle = (id,
|
|
11579
|
+
const settle = (id, rawOutput, success, outcome) => {
|
|
11580
|
+
const output = redactSecrets(rawOutput);
|
|
9855
11581
|
const call = pendingCalls.get(id);
|
|
9856
11582
|
pendingCalls.delete(id);
|
|
9857
11583
|
const step = {
|
|
@@ -10368,11 +12094,11 @@ function executionSummary(tasks) {
|
|
|
10368
12094
|
|
|
10369
12095
|
// src/utils/sessionStore.ts
|
|
10370
12096
|
var fs5 = __toESM(require("fs"));
|
|
10371
|
-
var
|
|
12097
|
+
var path11 = __toESM(require("path"));
|
|
10372
12098
|
|
|
10373
12099
|
// src/utils/fsHelpers.ts
|
|
10374
12100
|
var fs4 = __toESM(require("fs"));
|
|
10375
|
-
var
|
|
12101
|
+
var path10 = __toESM(require("path"));
|
|
10376
12102
|
var STATE_DIR = ".ordewell";
|
|
10377
12103
|
function ensureDir(dir) {
|
|
10378
12104
|
if (!fs4.existsSync(dir)) {
|
|
@@ -10380,13 +12106,29 @@ function ensureDir(dir) {
|
|
|
10380
12106
|
}
|
|
10381
12107
|
}
|
|
10382
12108
|
function getStateDir(baseDir) {
|
|
10383
|
-
return
|
|
12109
|
+
return path10.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
12110
|
+
}
|
|
12111
|
+
var IGNORE_FILE = ".gitignore";
|
|
12112
|
+
function ensureStateDirIgnored(baseDir) {
|
|
12113
|
+
const dir = getStateDir(baseDir);
|
|
12114
|
+
ensureDir(dir);
|
|
12115
|
+
try {
|
|
12116
|
+
fs4.writeFileSync(path10.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
|
|
12117
|
+
} catch (err) {
|
|
12118
|
+
if (err.code !== "EEXIST") throw err;
|
|
12119
|
+
}
|
|
12120
|
+
}
|
|
12121
|
+
|
|
12122
|
+
// src/utils/sessionId.ts
|
|
12123
|
+
var import_crypto = require("crypto");
|
|
12124
|
+
function mintSessionId() {
|
|
12125
|
+
return `session-${(0, import_crypto.randomBytes)(16).toString("hex")}`;
|
|
10384
12126
|
}
|
|
10385
12127
|
|
|
10386
12128
|
// src/utils/sessionStore.ts
|
|
10387
12129
|
var SESSIONS_SUBDIR = "sessions";
|
|
10388
12130
|
function getSessionsDir(baseDir) {
|
|
10389
|
-
return
|
|
12131
|
+
return path11.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
10390
12132
|
}
|
|
10391
12133
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
10392
12134
|
function hasScalarRunner(parsed) {
|
|
@@ -10405,9 +12147,10 @@ function sessionFilename(session) {
|
|
|
10405
12147
|
function saveSession(plan, goal, baseDir, id) {
|
|
10406
12148
|
const sessionsDir = getSessionsDir(baseDir);
|
|
10407
12149
|
ensureDir(sessionsDir);
|
|
12150
|
+
ensureStateDirIgnored(baseDir);
|
|
10408
12151
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10409
12152
|
const meta = {
|
|
10410
|
-
id: id ||
|
|
12153
|
+
id: id || mintSessionId(),
|
|
10411
12154
|
goal: goal || "(untitled)",
|
|
10412
12155
|
runners: plan.runners,
|
|
10413
12156
|
taskCount: plan.tasks.flatMap((t) => [t, ...t.subtasks || []]).length,
|
|
@@ -10420,7 +12163,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
10420
12163
|
plan: JSON.parse(JSON.stringify(plan))
|
|
10421
12164
|
};
|
|
10422
12165
|
const filename = sessionFilename(meta);
|
|
10423
|
-
const filePath =
|
|
12166
|
+
const filePath = path11.join(sessionsDir, filename);
|
|
10424
12167
|
fs5.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
10425
12168
|
return meta;
|
|
10426
12169
|
}
|
|
@@ -10430,7 +12173,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
10430
12173
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
10431
12174
|
return files.map((f) => {
|
|
10432
12175
|
try {
|
|
10433
|
-
const raw = fs5.readFileSync(
|
|
12176
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
10434
12177
|
const parsed = JSON.parse(raw);
|
|
10435
12178
|
if (hasScalarRunner(parsed)) {
|
|
10436
12179
|
logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
|
|
@@ -10448,7 +12191,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
10448
12191
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
10449
12192
|
for (const f of files) {
|
|
10450
12193
|
try {
|
|
10451
|
-
const raw = fs5.readFileSync(
|
|
12194
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
10452
12195
|
const session = JSON.parse(raw);
|
|
10453
12196
|
if (session.meta.id === sessionId) return f;
|
|
10454
12197
|
} catch (err) {
|
|
@@ -10463,7 +12206,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
10463
12206
|
try {
|
|
10464
12207
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
10465
12208
|
if (file) {
|
|
10466
|
-
const raw = fs5.readFileSync(
|
|
12209
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, file), "utf-8");
|
|
10467
12210
|
const parsed = JSON.parse(raw);
|
|
10468
12211
|
if (hasScalarRunner(parsed)) {
|
|
10469
12212
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -10497,7 +12240,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
10497
12240
|
try {
|
|
10498
12241
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
10499
12242
|
if (file) {
|
|
10500
|
-
fs5.unlinkSync(
|
|
12243
|
+
fs5.unlinkSync(path11.join(sessionsDir, file));
|
|
10501
12244
|
return true;
|
|
10502
12245
|
}
|
|
10503
12246
|
} catch (err) {
|
|
@@ -10516,11 +12259,6 @@ var PlanEditError = class extends Error {
|
|
|
10516
12259
|
function sessionRuntimeSettings(settings) {
|
|
10517
12260
|
return { ...plannerRuntimeToggles(settings), modelAllowlist: settings.modelAllowlist };
|
|
10518
12261
|
}
|
|
10519
|
-
var lastMintedAt = 0;
|
|
10520
|
-
function mintSessionId() {
|
|
10521
|
-
lastMintedAt = Math.max(Date.now(), lastMintedAt + 1);
|
|
10522
|
-
return `session-${lastMintedAt}`;
|
|
10523
|
-
}
|
|
10524
12262
|
var Session = class {
|
|
10525
12263
|
/** Injected by a test; when present it is the service, forever. */
|
|
10526
12264
|
pinnedAiService;
|
|
@@ -12318,26 +14056,128 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
12318
14056
|
}
|
|
12319
14057
|
};
|
|
12320
14058
|
|
|
14059
|
+
// src/utils/daemonToken.ts
|
|
14060
|
+
var import_crypto2 = require("crypto");
|
|
14061
|
+
var import_fs2 = require("fs");
|
|
14062
|
+
var import_os2 = require("os");
|
|
14063
|
+
var import_path2 = require("path");
|
|
14064
|
+
var BEARER_PREFIX = "bearer ";
|
|
14065
|
+
var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
|
|
14066
|
+
var DAEMON_SUBPROTOCOL = "ordewell.v1";
|
|
14067
|
+
function configDir() {
|
|
14068
|
+
return (0, import_path2.join)((0, import_os2.homedir)(), ".config", "ordewell");
|
|
14069
|
+
}
|
|
14070
|
+
function daemonTokenPath(port) {
|
|
14071
|
+
return (0, import_path2.join)(configDir(), `server-${port}.token`);
|
|
14072
|
+
}
|
|
14073
|
+
function mintDaemonToken(port) {
|
|
14074
|
+
const token = (0, import_crypto2.randomBytes)(32).toString("base64url");
|
|
14075
|
+
const file = daemonTokenPath(port);
|
|
14076
|
+
(0, import_fs2.mkdirSync)(configDir(), { recursive: true });
|
|
14077
|
+
try {
|
|
14078
|
+
(0, import_fs2.unlinkSync)(file);
|
|
14079
|
+
} catch {
|
|
14080
|
+
}
|
|
14081
|
+
const fd = (0, import_fs2.openSync)(file, "wx", 384);
|
|
14082
|
+
try {
|
|
14083
|
+
(0, import_fs2.writeSync)(fd, token);
|
|
14084
|
+
} finally {
|
|
14085
|
+
(0, import_fs2.closeSync)(fd);
|
|
14086
|
+
}
|
|
14087
|
+
return { token, file };
|
|
14088
|
+
}
|
|
14089
|
+
function readDaemonToken(port) {
|
|
14090
|
+
try {
|
|
14091
|
+
const token = (0, import_fs2.readFileSync)(daemonTokenPath(port), "utf8").trim();
|
|
14092
|
+
return token === "" ? void 0 : token;
|
|
14093
|
+
} catch {
|
|
14094
|
+
return void 0;
|
|
14095
|
+
}
|
|
14096
|
+
}
|
|
14097
|
+
function clearDaemonToken(port) {
|
|
14098
|
+
try {
|
|
14099
|
+
(0, import_fs2.unlinkSync)(daemonTokenPath(port));
|
|
14100
|
+
} catch {
|
|
14101
|
+
}
|
|
14102
|
+
}
|
|
14103
|
+
function bearerHeaderValue(token) {
|
|
14104
|
+
return `Bearer ${token}`;
|
|
14105
|
+
}
|
|
14106
|
+
function tokenSubprotocols(token) {
|
|
14107
|
+
return [DAEMON_SUBPROTOCOL, `${DAEMON_TOKEN_SUBPROTOCOL_PREFIX}${token}`];
|
|
14108
|
+
}
|
|
14109
|
+
function extractPresentedToken(carriers) {
|
|
14110
|
+
const authorization = carriers.authorization;
|
|
14111
|
+
if (authorization && authorization.toLowerCase().startsWith(BEARER_PREFIX)) {
|
|
14112
|
+
const value = authorization.slice(BEARER_PREFIX.length).trim();
|
|
14113
|
+
if (value !== "") return value;
|
|
14114
|
+
}
|
|
14115
|
+
for (const offered of (carriers.secWebSocketProtocol ?? "").split(",")) {
|
|
14116
|
+
const value = offered.trim();
|
|
14117
|
+
if (!value.startsWith(DAEMON_TOKEN_SUBPROTOCOL_PREFIX)) continue;
|
|
14118
|
+
const token = value.slice(DAEMON_TOKEN_SUBPROTOCOL_PREFIX.length);
|
|
14119
|
+
if (token !== "") return token;
|
|
14120
|
+
}
|
|
14121
|
+
return void 0;
|
|
14122
|
+
}
|
|
14123
|
+
function tokensMatch(presented, expected) {
|
|
14124
|
+
if (presented === void 0) return false;
|
|
14125
|
+
const a = Buffer.from(presented, "utf8");
|
|
14126
|
+
const b = Buffer.from(expected, "utf8");
|
|
14127
|
+
if (a.length !== b.length) return false;
|
|
14128
|
+
return (0, import_crypto2.timingSafeEqual)(a, b);
|
|
14129
|
+
}
|
|
14130
|
+
|
|
12321
14131
|
// src/plugins/RunnerRegistry.ts
|
|
12322
14132
|
var fs7 = __toESM(require("fs"));
|
|
12323
|
-
var
|
|
14133
|
+
var path14 = __toESM(require("path"));
|
|
12324
14134
|
var os5 = __toESM(require("os"));
|
|
12325
14135
|
var import_child_process9 = require("child_process");
|
|
14136
|
+
var import_crypto3 = require("crypto");
|
|
12326
14137
|
|
|
12327
14138
|
// src/plugins/FsPluginStore.ts
|
|
12328
14139
|
var fs6 = __toESM(require("fs"));
|
|
12329
|
-
var
|
|
14140
|
+
var path13 = __toESM(require("path"));
|
|
12330
14141
|
var os4 = __toESM(require("os"));
|
|
12331
|
-
|
|
12332
|
-
|
|
14142
|
+
|
|
14143
|
+
// src/plugins/pluginNames.ts
|
|
14144
|
+
var path12 = __toESM(require("path"));
|
|
14145
|
+
var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
14146
|
+
var MAX_PLUGIN_NAME_LENGTH = 64;
|
|
14147
|
+
function isPlainPluginName(name) {
|
|
14148
|
+
return typeof name === "string" && name.length <= MAX_PLUGIN_NAME_LENGTH && PLUGIN_NAME_PATTERN.test(name);
|
|
14149
|
+
}
|
|
14150
|
+
function assertPlainPluginName(name) {
|
|
14151
|
+
if (!isPlainPluginName(name)) {
|
|
14152
|
+
throw new Error(
|
|
14153
|
+
`Invalid plugin name: ${JSON.stringify(name)}. Names must be a single plain segment of letters, digits, '.', '-' or '_' (max ${MAX_PLUGIN_NAME_LENGTH} characters).`
|
|
14154
|
+
);
|
|
14155
|
+
}
|
|
12333
14156
|
}
|
|
14157
|
+
function resolvePluginInstallDir(pluginsDir, name) {
|
|
14158
|
+
assertPlainPluginName(name);
|
|
14159
|
+
const root = path12.resolve(pluginsDir);
|
|
14160
|
+
const dest = path12.resolve(root, name);
|
|
14161
|
+
const relative3 = path12.relative(root, dest);
|
|
14162
|
+
if (relative3 !== name || relative3 === "" || path12.isAbsolute(relative3)) {
|
|
14163
|
+
throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
|
|
14164
|
+
}
|
|
14165
|
+
return dest;
|
|
14166
|
+
}
|
|
14167
|
+
|
|
14168
|
+
// src/plugins/manifestValidation.ts
|
|
12334
14169
|
function isValidManifest(obj) {
|
|
12335
14170
|
if (!obj || typeof obj !== "object") return false;
|
|
12336
14171
|
const m = obj;
|
|
12337
|
-
return
|
|
14172
|
+
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;
|
|
14173
|
+
}
|
|
14174
|
+
|
|
14175
|
+
// src/plugins/FsPluginStore.ts
|
|
14176
|
+
function userPluginsDir() {
|
|
14177
|
+
return path13.join(os4.homedir(), ".config", "ordewell", "plugins");
|
|
12338
14178
|
}
|
|
12339
14179
|
function loadManifestFromDir(dir) {
|
|
12340
|
-
const manifestPath =
|
|
14180
|
+
const manifestPath = path13.join(dir, "manifest.json");
|
|
12341
14181
|
if (!fs6.existsSync(manifestPath)) return null;
|
|
12342
14182
|
try {
|
|
12343
14183
|
const raw = fs6.readFileSync(manifestPath, "utf8");
|
|
@@ -12352,8 +14192,8 @@ function copyDirSync(src, dest) {
|
|
|
12352
14192
|
ensureDir(dest);
|
|
12353
14193
|
const entries = fs6.readdirSync(src, { withFileTypes: true });
|
|
12354
14194
|
for (const entry of entries) {
|
|
12355
|
-
const srcPath =
|
|
12356
|
-
const destPath =
|
|
14195
|
+
const srcPath = path13.join(src, entry.name);
|
|
14196
|
+
const destPath = path13.join(dest, entry.name);
|
|
12357
14197
|
if (entry.isDirectory()) {
|
|
12358
14198
|
copyDirSync(srcPath, destPath);
|
|
12359
14199
|
} else {
|
|
@@ -12365,7 +14205,7 @@ function rmDirSync(dir) {
|
|
|
12365
14205
|
if (!fs6.existsSync(dir)) return;
|
|
12366
14206
|
const entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
12367
14207
|
for (const entry of entries) {
|
|
12368
|
-
const p =
|
|
14208
|
+
const p = path13.join(dir, entry.name);
|
|
12369
14209
|
if (entry.isDirectory()) {
|
|
12370
14210
|
rmDirSync(p);
|
|
12371
14211
|
} else {
|
|
@@ -12389,6 +14229,13 @@ var FsPluginStore = class {
|
|
|
12389
14229
|
}
|
|
12390
14230
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12391
14231
|
}
|
|
14232
|
+
listDir(dir) {
|
|
14233
|
+
try {
|
|
14234
|
+
return fs6.readdirSync(dir);
|
|
14235
|
+
} catch {
|
|
14236
|
+
return [];
|
|
14237
|
+
}
|
|
14238
|
+
}
|
|
12392
14239
|
loadManifest(pluginDir) {
|
|
12393
14240
|
return loadManifestFromDir(pluginDir);
|
|
12394
14241
|
}
|
|
@@ -12411,11 +14258,11 @@ var FsPluginStore = class {
|
|
|
12411
14258
|
return null;
|
|
12412
14259
|
}
|
|
12413
14260
|
}
|
|
12414
|
-
dirExists(
|
|
12415
|
-
return fs6.existsSync(
|
|
14261
|
+
dirExists(path17) {
|
|
14262
|
+
return fs6.existsSync(path17) && fs6.statSync(path17).isDirectory();
|
|
12416
14263
|
}
|
|
12417
|
-
exists(
|
|
12418
|
-
return fs6.existsSync(
|
|
14264
|
+
exists(path17) {
|
|
14265
|
+
return fs6.existsSync(path17);
|
|
12419
14266
|
}
|
|
12420
14267
|
};
|
|
12421
14268
|
|
|
@@ -12703,17 +14550,98 @@ var OPENCODE_MANIFEST = {
|
|
|
12703
14550
|
]
|
|
12704
14551
|
};
|
|
12705
14552
|
|
|
14553
|
+
// src/plugins/pluginSource.ts
|
|
14554
|
+
var ALLOWED_PLUGIN_HOSTS = [
|
|
14555
|
+
"github.com",
|
|
14556
|
+
"gitlab.com",
|
|
14557
|
+
"bitbucket.org",
|
|
14558
|
+
"codeberg.org"
|
|
14559
|
+
];
|
|
14560
|
+
var SAFE_REPO_PATH = /^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/;
|
|
14561
|
+
var HAS_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]+:/;
|
|
14562
|
+
var SCP_LIKE_REMOTE = /^[^/\\]+@[^/\\]+:/;
|
|
14563
|
+
function hasControlCharacter(value) {
|
|
14564
|
+
for (let i = 0; i < value.length; i++) {
|
|
14565
|
+
const code = value.charCodeAt(i);
|
|
14566
|
+
if (code < 32 || code === 127) return true;
|
|
14567
|
+
}
|
|
14568
|
+
return false;
|
|
14569
|
+
}
|
|
14570
|
+
function assertInstallablePluginUrl(url) {
|
|
14571
|
+
if (typeof url !== "string" || url.trim() === "") {
|
|
14572
|
+
throw new Error("A plugin repository URL is required.");
|
|
14573
|
+
}
|
|
14574
|
+
if (hasControlCharacter(url)) {
|
|
14575
|
+
throw new Error("Plugin URL contains control characters.");
|
|
14576
|
+
}
|
|
14577
|
+
let parsed;
|
|
14578
|
+
try {
|
|
14579
|
+
parsed = new URL(url.trim());
|
|
14580
|
+
} catch {
|
|
14581
|
+
throw new Error(`Not a valid plugin repository URL: ${url}`);
|
|
14582
|
+
}
|
|
14583
|
+
if (parsed.protocol !== "https:") {
|
|
14584
|
+
throw new Error(
|
|
14585
|
+
`Plugin repositories must be cloned over https (got "${parsed.protocol}//"). git transport helpers and non-https schemes are not accepted.`
|
|
14586
|
+
);
|
|
14587
|
+
}
|
|
14588
|
+
if (parsed.username || parsed.password) {
|
|
14589
|
+
throw new Error("Plugin URL must not embed credentials.");
|
|
14590
|
+
}
|
|
14591
|
+
if (parsed.port) {
|
|
14592
|
+
throw new Error("Plugin URL must not specify a port.");
|
|
14593
|
+
}
|
|
14594
|
+
if (parsed.search || parsed.hash) {
|
|
14595
|
+
throw new Error("Plugin URL must not carry a query string or fragment.");
|
|
14596
|
+
}
|
|
14597
|
+
const host = parsed.hostname.toLowerCase();
|
|
14598
|
+
if (!ALLOWED_PLUGIN_HOSTS.includes(host)) {
|
|
14599
|
+
throw new Error(
|
|
14600
|
+
`Plugin host not allowed: ${host}. Allowed hosts: ${ALLOWED_PLUGIN_HOSTS.join(", ")}.`
|
|
14601
|
+
);
|
|
14602
|
+
}
|
|
14603
|
+
if (!SAFE_REPO_PATH.test(parsed.pathname)) {
|
|
14604
|
+
throw new Error(`Not a plain repository path: ${parsed.pathname}`);
|
|
14605
|
+
}
|
|
14606
|
+
return parsed;
|
|
14607
|
+
}
|
|
14608
|
+
function classifyPluginSource(source) {
|
|
14609
|
+
const trimmed = source.trim();
|
|
14610
|
+
if (trimmed.startsWith("github:")) {
|
|
14611
|
+
const repo = trimmed.slice("github:".length).replace(/\.git$/, "");
|
|
14612
|
+
return { kind: "git", url: `https://github.com/${repo}.git` };
|
|
14613
|
+
}
|
|
14614
|
+
if (HAS_SCHEME.test(trimmed) || SCP_LIKE_REMOTE.test(trimmed)) {
|
|
14615
|
+
return { kind: "git", url: trimmed };
|
|
14616
|
+
}
|
|
14617
|
+
return { kind: "path", path: source };
|
|
14618
|
+
}
|
|
14619
|
+
|
|
12706
14620
|
// src/plugins/RunnerRegistry.ts
|
|
12707
14621
|
var BUILTIN_MANIFESTS = [
|
|
12708
14622
|
CLAUDE_CODE_MANIFEST,
|
|
12709
14623
|
CODEX_MANIFEST,
|
|
12710
14624
|
OPENCODE_MANIFEST
|
|
12711
14625
|
];
|
|
14626
|
+
var RESERVED_RUNNER_NAMES = new Set(BUILTIN_MANIFESTS.map((m) => m.name.toLowerCase()));
|
|
14627
|
+
function isReservedRunnerName(name) {
|
|
14628
|
+
return RESERVED_RUNNER_NAMES.has(name.toLowerCase());
|
|
14629
|
+
}
|
|
14630
|
+
function gitClone(url, destDir) {
|
|
14631
|
+
(0, import_child_process9.execFileSync)("git", ["clone", "--depth", "1", "--", url, destDir], {
|
|
14632
|
+
stdio: "pipe",
|
|
14633
|
+
timeout: 3e4,
|
|
14634
|
+
// A repository that demands credentials should fail, not hang on a prompt.
|
|
14635
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
14636
|
+
});
|
|
14637
|
+
}
|
|
12712
14638
|
var RunnerRegistry = class {
|
|
12713
14639
|
plugins = /* @__PURE__ */ new Map();
|
|
12714
14640
|
store;
|
|
12715
|
-
|
|
14641
|
+
clone;
|
|
14642
|
+
constructor(store, clone) {
|
|
12716
14643
|
this.store = store ?? new FsPluginStore();
|
|
14644
|
+
this.clone = clone ?? gitClone;
|
|
12717
14645
|
this.loadBuiltins();
|
|
12718
14646
|
}
|
|
12719
14647
|
loadBuiltins() {
|
|
@@ -12724,9 +14652,15 @@ var RunnerRegistry = class {
|
|
|
12724
14652
|
loadUserPlugins() {
|
|
12725
14653
|
const names = this.store.listUserPluginDirs();
|
|
12726
14654
|
for (const name of names) {
|
|
12727
|
-
|
|
14655
|
+
let pluginDir;
|
|
14656
|
+
try {
|
|
14657
|
+
pluginDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), name);
|
|
14658
|
+
} catch {
|
|
14659
|
+
continue;
|
|
14660
|
+
}
|
|
12728
14661
|
const manifest = this.store.loadManifest(pluginDir);
|
|
12729
|
-
if (!manifest) continue;
|
|
14662
|
+
if (!manifest || !isPlainPluginName(manifest.name)) continue;
|
|
14663
|
+
if (isReservedRunnerName(manifest.name)) continue;
|
|
12730
14664
|
this.plugins.set(manifest.name, {
|
|
12731
14665
|
manifest,
|
|
12732
14666
|
source: "user",
|
|
@@ -12755,7 +14689,7 @@ var RunnerRegistry = class {
|
|
|
12755
14689
|
return entry?.source === "builtin";
|
|
12756
14690
|
}
|
|
12757
14691
|
installFromPath(sourcePath) {
|
|
12758
|
-
const absPath =
|
|
14692
|
+
const absPath = path14.resolve(sourcePath);
|
|
12759
14693
|
if (!this.store.dirExists(absPath)) {
|
|
12760
14694
|
throw new Error(`Plugin source must be a directory: ${absPath}`);
|
|
12761
14695
|
}
|
|
@@ -12763,48 +14697,50 @@ var RunnerRegistry = class {
|
|
|
12763
14697
|
if (!manifest) {
|
|
12764
14698
|
throw new Error(`No valid manifest.json found in: ${absPath}`);
|
|
12765
14699
|
}
|
|
12766
|
-
|
|
12767
|
-
this.store.ensureDir(destDir);
|
|
12768
|
-
this.store.copyDir(absPath, destDir);
|
|
12769
|
-
this.plugins.set(manifest.name, {
|
|
12770
|
-
manifest,
|
|
12771
|
-
source: "user",
|
|
12772
|
-
installPath: destDir
|
|
12773
|
-
});
|
|
12774
|
-
return manifest;
|
|
14700
|
+
return this.registerInstalled(manifest, absPath);
|
|
12775
14701
|
}
|
|
12776
14702
|
installFromGit(url) {
|
|
12777
|
-
const
|
|
12778
|
-
const tmpDir =
|
|
14703
|
+
const validated = assertInstallablePluginUrl(url);
|
|
14704
|
+
const tmpDir = path14.join(os5.tmpdir(), `ordewell-plugin-${(0, import_crypto3.randomBytes)(12).toString("hex")}`);
|
|
12779
14705
|
this.store.ensureDir(tmpDir);
|
|
12780
14706
|
try {
|
|
12781
|
-
|
|
12782
|
-
|
|
12783
|
-
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
14707
|
+
try {
|
|
14708
|
+
this.clone(validated.toString(), tmpDir);
|
|
14709
|
+
} catch (err) {
|
|
14710
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14711
|
+
throw new Error(`Failed to clone repository: ${message}`);
|
|
14712
|
+
}
|
|
14713
|
+
const contents = this.store.listDir(tmpDir);
|
|
14714
|
+
const hasManifest = contents.some((f) => f === "manifest.json");
|
|
14715
|
+
let sourceDir = tmpDir;
|
|
14716
|
+
if (!hasManifest) {
|
|
14717
|
+
const onlyEntry = contents.length === 1 ? path14.join(tmpDir, contents[0]) : void 0;
|
|
14718
|
+
if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
|
|
14719
|
+
throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
|
|
14720
|
+
}
|
|
14721
|
+
sourceDir = onlyEntry;
|
|
14722
|
+
}
|
|
14723
|
+
const manifest = this.store.loadManifest(sourceDir);
|
|
14724
|
+
if (!manifest) {
|
|
14725
|
+
throw new Error("No valid manifest.json found in cloned repository");
|
|
14726
|
+
}
|
|
14727
|
+
return this.registerInstalled(manifest, sourceDir);
|
|
14728
|
+
} finally {
|
|
12793
14729
|
this.store.removeDir(tmpDir);
|
|
12794
|
-
throw new Error(`No manifest.json found in repository: ${url}`);
|
|
12795
14730
|
}
|
|
12796
|
-
return this.finishInstall(tmpDir, repoName, tmpDir);
|
|
12797
14731
|
}
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
14732
|
+
/**
|
|
14733
|
+
* The single destination-building step both install routes share: the name is
|
|
14734
|
+
* constrained to a plain segment and the resolved destination is asserted to
|
|
14735
|
+
* be inside the plugins directory before anything is copied.
|
|
14736
|
+
*/
|
|
14737
|
+
registerInstalled(manifest, sourceDir) {
|
|
14738
|
+
if (isReservedRunnerName(manifest.name)) {
|
|
14739
|
+
throw new Error(`Cannot install a plugin named after a built-in runner: ${manifest.name}`);
|
|
12803
14740
|
}
|
|
12804
|
-
const destDir =
|
|
14741
|
+
const destDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), manifest.name);
|
|
12805
14742
|
this.store.ensureDir(destDir);
|
|
12806
14743
|
this.store.copyDir(sourceDir, destDir);
|
|
12807
|
-
this.store.removeDir(tmpDir);
|
|
12808
14744
|
this.plugins.set(manifest.name, {
|
|
12809
14745
|
manifest,
|
|
12810
14746
|
source: "user",
|
|
@@ -12825,7 +14761,8 @@ var RunnerRegistry = class {
|
|
|
12825
14761
|
this.plugins.delete(name);
|
|
12826
14762
|
}
|
|
12827
14763
|
createSkeleton(name, outputDir) {
|
|
12828
|
-
|
|
14764
|
+
assertPlainPluginName(name);
|
|
14765
|
+
const dir = path14.resolve(outputDir, name);
|
|
12829
14766
|
this.store.ensureDir(dir);
|
|
12830
14767
|
const manifest = {
|
|
12831
14768
|
name,
|
|
@@ -12857,8 +14794,8 @@ var RunnerRegistry = class {
|
|
|
12857
14794
|
]
|
|
12858
14795
|
}
|
|
12859
14796
|
};
|
|
12860
|
-
this.store.writeFile(
|
|
12861
|
-
const runSh =
|
|
14797
|
+
this.store.writeFile(path14.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
14798
|
+
const runSh = path14.join(dir, "run.sh");
|
|
12862
14799
|
const scriptContent = `#!/usr/bin/env bash
|
|
12863
14800
|
# Custom runner script for ${name}
|
|
12864
14801
|
# Receives:
|
|
@@ -12882,13 +14819,6 @@ echo "Running ${name} with prompt: $prompt"
|
|
|
12882
14819
|
return dir;
|
|
12883
14820
|
}
|
|
12884
14821
|
};
|
|
12885
|
-
function fsReaddirSync(dir) {
|
|
12886
|
-
try {
|
|
12887
|
-
return fs7.readdirSync(dir);
|
|
12888
|
-
} catch {
|
|
12889
|
-
return [];
|
|
12890
|
-
}
|
|
12891
|
-
}
|
|
12892
14822
|
function fsChmodSync(fpath, mode) {
|
|
12893
14823
|
try {
|
|
12894
14824
|
fs7.chmodSync(fpath, mode);
|
|
@@ -12898,14 +14828,14 @@ function fsChmodSync(fpath, mode) {
|
|
|
12898
14828
|
|
|
12899
14829
|
// src/utils/stateStore.ts
|
|
12900
14830
|
var fs8 = __toESM(require("fs"));
|
|
12901
|
-
var
|
|
14831
|
+
var path15 = __toESM(require("path"));
|
|
12902
14832
|
var STATE_FILE = "state.json";
|
|
12903
14833
|
function getStatePath(baseDir) {
|
|
12904
|
-
return
|
|
14834
|
+
return path15.join(getStateDir(baseDir), STATE_FILE);
|
|
12905
14835
|
}
|
|
12906
14836
|
function saveState(plan, baseDir) {
|
|
12907
14837
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
12908
|
-
ensureDir(
|
|
14838
|
+
ensureDir(path15.dirname(statePath));
|
|
12909
14839
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
12910
14840
|
fs8.writeFileSync(statePath, JSON.stringify(plan, null, 2));
|
|
12911
14841
|
}
|
|
@@ -12938,7 +14868,7 @@ function stateExists(baseDir) {
|
|
|
12938
14868
|
|
|
12939
14869
|
// src/services/SettingsService.ts
|
|
12940
14870
|
var fs9 = __toESM(require("fs"));
|
|
12941
|
-
var
|
|
14871
|
+
var path16 = __toESM(require("path"));
|
|
12942
14872
|
var os6 = __toESM(require("os"));
|
|
12943
14873
|
var DEFAULTS = {
|
|
12944
14874
|
grillMe: { enabled: false },
|
|
@@ -12951,7 +14881,7 @@ var DEFAULTS = {
|
|
|
12951
14881
|
function getSettingsPath() {
|
|
12952
14882
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
12953
14883
|
if (override && override.trim()) return override.trim();
|
|
12954
|
-
return
|
|
14884
|
+
return path16.join(os6.homedir(), ".config", "ordewell", "settings.json");
|
|
12955
14885
|
}
|
|
12956
14886
|
function readPlannerModels(raw) {
|
|
12957
14887
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -13116,7 +15046,7 @@ var SettingsService = class {
|
|
|
13116
15046
|
return { ...DEFAULTS, grillMe: { ...DEFAULTS.grillMe }, tdd: { ...DEFAULTS.tdd }, prd: { ...DEFAULTS.prd }, review: { ...DEFAULTS.review }, verification: { ...DEFAULTS.verification }, researchSubagents: { ...DEFAULTS.researchSubagents } };
|
|
13117
15047
|
}
|
|
13118
15048
|
persist() {
|
|
13119
|
-
const dir =
|
|
15049
|
+
const dir = path16.dirname(this.filePath);
|
|
13120
15050
|
if (!fs9.existsSync(dir)) {
|
|
13121
15051
|
fs9.mkdirSync(dir, { recursive: true });
|
|
13122
15052
|
}
|
|
@@ -13161,6 +15091,7 @@ var PlannerModelMemory = class {
|
|
|
13161
15091
|
};
|
|
13162
15092
|
// Annotate the CommonJS export names for ESM import in node:
|
|
13163
15093
|
0 && (module.exports = {
|
|
15094
|
+
ALLOWED_PLUGIN_HOSTS,
|
|
13164
15095
|
ALL_PROVIDERS,
|
|
13165
15096
|
AUTO_COMMANDS,
|
|
13166
15097
|
AbstractRunner,
|
|
@@ -13179,6 +15110,8 @@ var PlannerModelMemory = class {
|
|
|
13179
15110
|
CommandLineTooLongError,
|
|
13180
15111
|
ConsoleLogger,
|
|
13181
15112
|
ContextCollector,
|
|
15113
|
+
DAEMON_SUBPROTOCOL,
|
|
15114
|
+
DAEMON_TOKEN_SUBPROTOCOL_PREFIX,
|
|
13182
15115
|
DENY_ALL,
|
|
13183
15116
|
EmbeddedNewlineError,
|
|
13184
15117
|
EnvConfig,
|
|
@@ -13195,9 +15128,12 @@ var PlannerModelMemory = class {
|
|
|
13195
15128
|
ModelResolver,
|
|
13196
15129
|
OPENCODE_MANIFEST,
|
|
13197
15130
|
ORCHESTRATOR_SHORTCUTS,
|
|
15131
|
+
ORDEWELL_SETTABLE_ENV,
|
|
13198
15132
|
OpenAiService,
|
|
13199
15133
|
OpenCodeAdapter,
|
|
13200
15134
|
PLAN_ENVELOPE_KEY,
|
|
15135
|
+
PLUGIN_NAME_PATTERN,
|
|
15136
|
+
PROVIDER_CREDENTIAL_ENV,
|
|
13201
15137
|
PROVIDER_DETECT_PRIORITY,
|
|
13202
15138
|
PROVIDER_LABEL,
|
|
13203
15139
|
PROVIDER_PRIORITY,
|
|
@@ -13212,6 +15148,8 @@ var PlannerModelMemory = class {
|
|
|
13212
15148
|
RunnerInstallation,
|
|
13213
15149
|
RunnerRegistry,
|
|
13214
15150
|
SEARCH_EXCLUSIONS,
|
|
15151
|
+
SETTINGS_ENV_ALLOWLIST,
|
|
15152
|
+
SETTINGS_ENV_REFUSED,
|
|
13215
15153
|
STATE_DIR,
|
|
13216
15154
|
STOPPED_TOOL_RESULT,
|
|
13217
15155
|
SYMBOL_LANGUAGES,
|
|
@@ -13224,13 +15162,19 @@ var PlannerModelMemory = class {
|
|
|
13224
15162
|
TmuxRunner,
|
|
13225
15163
|
VerdictEngine,
|
|
13226
15164
|
WINDOWS_MAX_COMMAND_LINE,
|
|
15165
|
+
WorkspaceNotAProjectError,
|
|
13227
15166
|
WorkspaceNotFoundError,
|
|
13228
15167
|
addTaskToPlan,
|
|
15168
|
+
admitSettingsEnv,
|
|
13229
15169
|
applyHeadLimit,
|
|
13230
15170
|
applyTaskOps,
|
|
15171
|
+
assertInstallablePluginUrl,
|
|
15172
|
+
assertPlainPluginName,
|
|
13231
15173
|
assertWorkspaceExists,
|
|
15174
|
+
assertWorkspaceIsProject,
|
|
13232
15175
|
augmentPromptWithPriorOutputs,
|
|
13233
15176
|
augmentedPath,
|
|
15177
|
+
bearerHeaderValue,
|
|
13234
15178
|
buildConversationSystemPrompt,
|
|
13235
15179
|
buildFallbackGrepArgs,
|
|
13236
15180
|
buildGlobArgs,
|
|
@@ -13258,7 +15202,9 @@ var PlannerModelMemory = class {
|
|
|
13258
15202
|
classifyCommand,
|
|
13259
15203
|
classifyOutcome,
|
|
13260
15204
|
classifyPlannerReply,
|
|
15205
|
+
classifyPluginSource,
|
|
13261
15206
|
clearAugmentedPathCache,
|
|
15207
|
+
clearDaemonToken,
|
|
13262
15208
|
clearResearchShellCache,
|
|
13263
15209
|
clearState,
|
|
13264
15210
|
clipboardCopyCommand,
|
|
@@ -13270,6 +15216,7 @@ var PlannerModelMemory = class {
|
|
|
13270
15216
|
createAiService,
|
|
13271
15217
|
createEmptyPlan,
|
|
13272
15218
|
createTask,
|
|
15219
|
+
daemonTokenPath,
|
|
13273
15220
|
defaultLogger,
|
|
13274
15221
|
definitionPattern,
|
|
13275
15222
|
deleteSession,
|
|
@@ -13280,6 +15227,7 @@ var PlannerModelMemory = class {
|
|
|
13280
15227
|
emptyWarnings,
|
|
13281
15228
|
enabledRunners,
|
|
13282
15229
|
ensureDir,
|
|
15230
|
+
ensureStateDirIgnored,
|
|
13283
15231
|
escapeControlCharsInStrings,
|
|
13284
15232
|
executionLogBlock,
|
|
13285
15233
|
executionSummary,
|
|
@@ -13287,6 +15235,7 @@ var PlannerModelMemory = class {
|
|
|
13287
15235
|
extractObjectWithBalance,
|
|
13288
15236
|
extractObjectsWithKey,
|
|
13289
15237
|
extractPrdBlock,
|
|
15238
|
+
extractPresentedToken,
|
|
13290
15239
|
fetchAllProviderModels,
|
|
13291
15240
|
filterFallbackByAnchoredInclude,
|
|
13292
15241
|
filterModelsForPrompt,
|
|
@@ -13304,6 +15253,9 @@ var PlannerModelMemory = class {
|
|
|
13304
15253
|
isCliProvider,
|
|
13305
15254
|
isExecutableResolved,
|
|
13306
15255
|
isOpenAiProvider,
|
|
15256
|
+
isPlainPluginName,
|
|
15257
|
+
isReservedRunnerName,
|
|
15258
|
+
isValidManifest,
|
|
13307
15259
|
killTree,
|
|
13308
15260
|
knownModelId,
|
|
13309
15261
|
languageForId,
|
|
@@ -13316,6 +15268,8 @@ var PlannerModelMemory = class {
|
|
|
13316
15268
|
migrateLegacyPlan,
|
|
13317
15269
|
migratePlanState,
|
|
13318
15270
|
migrateTask,
|
|
15271
|
+
mintDaemonToken,
|
|
15272
|
+
mintSessionId,
|
|
13319
15273
|
modelContextBlock,
|
|
13320
15274
|
modifyValidationFeedback,
|
|
13321
15275
|
normalizeAgentArgs,
|
|
@@ -13331,6 +15285,7 @@ var PlannerModelMemory = class {
|
|
|
13331
15285
|
providerForRunner,
|
|
13332
15286
|
reEmitPlanPrompt,
|
|
13333
15287
|
reEmitTaskOpsPrompt,
|
|
15288
|
+
readDaemonToken,
|
|
13334
15289
|
referencePattern,
|
|
13335
15290
|
removeTaskFromPlan,
|
|
13336
15291
|
renderPlanMap,
|
|
@@ -13342,6 +15297,7 @@ var PlannerModelMemory = class {
|
|
|
13342
15297
|
resolveArgs,
|
|
13343
15298
|
resolveDefaultMode,
|
|
13344
15299
|
resolveModelShortcut,
|
|
15300
|
+
resolvePluginInstallDir,
|
|
13345
15301
|
resolveProvider,
|
|
13346
15302
|
resolveProviderFromPrefix,
|
|
13347
15303
|
resolveResearchShell,
|
|
@@ -13372,6 +15328,8 @@ var PlannerModelMemory = class {
|
|
|
13372
15328
|
tmuxSocketName,
|
|
13373
15329
|
tmuxWindowName,
|
|
13374
15330
|
toOrchestratorOptions,
|
|
15331
|
+
tokenSubprotocols,
|
|
15332
|
+
tokensMatch,
|
|
13375
15333
|
truncatedPlanReEmitPrompt,
|
|
13376
15334
|
updateTaskInPlan,
|
|
13377
15335
|
validateModifiedPlan,
|