@ordewell/core 0.4.6 → 0.4.8
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 +219 -3
- package/dist/index.d.ts +219 -3
- package/dist/index.js +619 -124
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +594 -126
- 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,
|
|
@@ -156,6 +173,7 @@ __export(index_exports, {
|
|
|
156
173
|
extractObjectWithBalance: () => extractObjectWithBalance,
|
|
157
174
|
extractObjectsWithKey: () => extractObjectsWithKey,
|
|
158
175
|
extractPrdBlock: () => extractPrdBlock,
|
|
176
|
+
extractPresentedToken: () => extractPresentedToken,
|
|
159
177
|
fetchAllProviderModels: () => fetchAllProviderModels,
|
|
160
178
|
filterFallbackByAnchoredInclude: () => filterFallbackByAnchoredInclude,
|
|
161
179
|
filterModelsForPrompt: () => filterModelsForPrompt,
|
|
@@ -173,6 +191,9 @@ __export(index_exports, {
|
|
|
173
191
|
isCliProvider: () => isCliProvider,
|
|
174
192
|
isExecutableResolved: () => isExecutableResolved,
|
|
175
193
|
isOpenAiProvider: () => isOpenAiProvider,
|
|
194
|
+
isPlainPluginName: () => isPlainPluginName,
|
|
195
|
+
isReservedRunnerName: () => isReservedRunnerName,
|
|
196
|
+
isValidManifest: () => isValidManifest,
|
|
176
197
|
killTree: () => killTree,
|
|
177
198
|
knownModelId: () => knownModelId,
|
|
178
199
|
languageForId: () => languageForId,
|
|
@@ -185,6 +206,8 @@ __export(index_exports, {
|
|
|
185
206
|
migrateLegacyPlan: () => migrateLegacyPlan,
|
|
186
207
|
migratePlanState: () => migratePlanState,
|
|
187
208
|
migrateTask: () => migrateTask,
|
|
209
|
+
mintDaemonToken: () => mintDaemonToken,
|
|
210
|
+
mintSessionId: () => mintSessionId,
|
|
188
211
|
modelContextBlock: () => modelContextBlock,
|
|
189
212
|
modifyValidationFeedback: () => modifyValidationFeedback,
|
|
190
213
|
normalizeAgentArgs: () => normalizeAgentArgs,
|
|
@@ -200,6 +223,7 @@ __export(index_exports, {
|
|
|
200
223
|
providerForRunner: () => providerForRunner,
|
|
201
224
|
reEmitPlanPrompt: () => reEmitPlanPrompt,
|
|
202
225
|
reEmitTaskOpsPrompt: () => reEmitTaskOpsPrompt,
|
|
226
|
+
readDaemonToken: () => readDaemonToken,
|
|
203
227
|
referencePattern: () => referencePattern,
|
|
204
228
|
removeTaskFromPlan: () => removeTaskFromPlan,
|
|
205
229
|
renderPlanMap: () => renderPlanMap,
|
|
@@ -211,6 +235,7 @@ __export(index_exports, {
|
|
|
211
235
|
resolveArgs: () => resolveArgs,
|
|
212
236
|
resolveDefaultMode: () => resolveDefaultMode,
|
|
213
237
|
resolveModelShortcut: () => resolveModelShortcut,
|
|
238
|
+
resolvePluginInstallDir: () => resolvePluginInstallDir,
|
|
214
239
|
resolveProvider: () => resolveProvider,
|
|
215
240
|
resolveProviderFromPrefix: () => resolveProviderFromPrefix,
|
|
216
241
|
resolveResearchShell: () => resolveResearchShell,
|
|
@@ -241,6 +266,8 @@ __export(index_exports, {
|
|
|
241
266
|
tmuxSocketName: () => tmuxSocketName,
|
|
242
267
|
tmuxWindowName: () => tmuxWindowName,
|
|
243
268
|
toOrchestratorOptions: () => toOrchestratorOptions,
|
|
269
|
+
tokenSubprotocols: () => tokenSubprotocols,
|
|
270
|
+
tokensMatch: () => tokensMatch,
|
|
244
271
|
truncatedPlanReEmitPrompt: () => truncatedPlanReEmitPrompt,
|
|
245
272
|
updateTaskInPlan: () => updateTaskInPlan,
|
|
246
273
|
validateModifiedPlan: () => validateModifiedPlan,
|
|
@@ -605,7 +632,6 @@ var AUTO_COMMANDS = [
|
|
|
605
632
|
"pwd",
|
|
606
633
|
"which",
|
|
607
634
|
"type",
|
|
608
|
-
"env",
|
|
609
635
|
"uname",
|
|
610
636
|
"whoami",
|
|
611
637
|
"cut",
|
|
@@ -806,6 +832,52 @@ var MULTIPLEXERS = [
|
|
|
806
832
|
"flutter",
|
|
807
833
|
"dart"
|
|
808
834
|
];
|
|
835
|
+
var HELP_FLAGS = ["--help", "--version"];
|
|
836
|
+
var WRAPPER_FAMILY = {
|
|
837
|
+
env: {
|
|
838
|
+
valueFlags: ["-u", "--unset", "-C", "--chdir"],
|
|
839
|
+
booleanFlags: [
|
|
840
|
+
"-i",
|
|
841
|
+
"--ignore-environment",
|
|
842
|
+
"-0",
|
|
843
|
+
"--null",
|
|
844
|
+
"-v",
|
|
845
|
+
"--debug",
|
|
846
|
+
// Optional-value flags: see WrapperSpec.booleanFlags.
|
|
847
|
+
"--block-signal",
|
|
848
|
+
"--default-signal",
|
|
849
|
+
"--ignore-signal",
|
|
850
|
+
"--list-signal-handling",
|
|
851
|
+
...HELP_FLAGS
|
|
852
|
+
],
|
|
853
|
+
stringFlags: ["-S", "--split-string"],
|
|
854
|
+
acceptsAssignments: true
|
|
855
|
+
},
|
|
856
|
+
nice: {
|
|
857
|
+
valueFlags: ["-n", "--adjustment"],
|
|
858
|
+
booleanFlags: HELP_FLAGS,
|
|
859
|
+
booleanPattern: /^-\d+$/
|
|
860
|
+
},
|
|
861
|
+
timeout: {
|
|
862
|
+
valueFlags: ["-s", "--signal", "-k", "--kill-after"],
|
|
863
|
+
booleanFlags: ["--preserve-status", "--foreground", "-v", "--verbose", ...HELP_FLAGS],
|
|
864
|
+
positionals: 1
|
|
865
|
+
},
|
|
866
|
+
nohup: { booleanFlags: HELP_FLAGS },
|
|
867
|
+
setsid: { booleanFlags: ["-c", "--ctty", "-f", "--fork", "-w", "--wait", "-h", "-V", ...HELP_FLAGS] },
|
|
868
|
+
stdbuf: {
|
|
869
|
+
valueFlags: ["-i", "--input", "-o", "--output", "-e", "--error"],
|
|
870
|
+
booleanFlags: HELP_FLAGS
|
|
871
|
+
},
|
|
872
|
+
ionice: {
|
|
873
|
+
valueFlags: ["-c", "--class", "-n", "--classdata", "-p", "--pid", "-P", "--pgid", "-u", "--uid"],
|
|
874
|
+
booleanFlags: ["-t", "--ignore", "-h", "-V", ...HELP_FLAGS]
|
|
875
|
+
},
|
|
876
|
+
// The multi-call binary ships its own `rm`, `mv` and `sh`, so the refused
|
|
877
|
+
// name arrives as its first argument.
|
|
878
|
+
busybox: { booleanFlags: ["--list", "--install", ...HELP_FLAGS] },
|
|
879
|
+
command: { booleanFlags: ["-p"], noExecFlags: ["-v", "-V"] }
|
|
880
|
+
};
|
|
809
881
|
var POSIX_DIALECT = {
|
|
810
882
|
escape: "\\",
|
|
811
883
|
escapeInQuotes: true,
|
|
@@ -1020,10 +1092,92 @@ function binaryName(token, dialect) {
|
|
|
1020
1092
|
if (dot <= 0) return base;
|
|
1021
1093
|
return dialect.strippedExtensions.includes(base.slice(dot).toLowerCase()) ? base.slice(0, dot) : base;
|
|
1022
1094
|
}
|
|
1095
|
+
var ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
1023
1096
|
function toSegment(tokens, piped, dialect) {
|
|
1024
1097
|
const rest = [...tokens];
|
|
1025
|
-
|
|
1026
|
-
|
|
1098
|
+
const assignments = [];
|
|
1099
|
+
while (rest.length > 0 && ASSIGNMENT.test(rest[0])) assignments.push(rest.shift());
|
|
1100
|
+
return {
|
|
1101
|
+
binary: rest.length > 0 ? binaryName(rest[0], dialect) : "",
|
|
1102
|
+
args: rest.slice(1),
|
|
1103
|
+
assignments,
|
|
1104
|
+
piped,
|
|
1105
|
+
expandable: false
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
function joinedShortFlag(list, token) {
|
|
1109
|
+
if (token.length <= 2) return void 0;
|
|
1110
|
+
return list.find((f) => f.length === 2 && token.startsWith(f));
|
|
1111
|
+
}
|
|
1112
|
+
function scanWrapperArgs(binary, spec, args) {
|
|
1113
|
+
const valueFlags = spec.valueFlags ?? [];
|
|
1114
|
+
const stringFlags = spec.stringFlags ?? [];
|
|
1115
|
+
const assignments = [];
|
|
1116
|
+
let positionals = spec.positionals ?? 0;
|
|
1117
|
+
let i = 0;
|
|
1118
|
+
while (i < args.length) {
|
|
1119
|
+
const token = args[i];
|
|
1120
|
+
if (token === "--") {
|
|
1121
|
+
i++;
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
if (/^-./.test(token)) {
|
|
1125
|
+
const eq = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
1126
|
+
const name = eq > 0 ? token.slice(0, eq) : token;
|
|
1127
|
+
const selfContained = eq > 0;
|
|
1128
|
+
if ((spec.noExecFlags ?? []).includes(name)) return { kind: "no-exec" };
|
|
1129
|
+
if (stringFlags.includes(name) || joinedShortFlag(stringFlags, token)) {
|
|
1130
|
+
return {
|
|
1131
|
+
kind: "refuse",
|
|
1132
|
+
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.`
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
if ((spec.booleanFlags ?? []).includes(name) || spec.booleanPattern?.test(token)) {
|
|
1136
|
+
i++;
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
if (valueFlags.includes(name)) {
|
|
1140
|
+
i += selfContained ? 1 : 2;
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
if (joinedShortFlag(valueFlags, token)) {
|
|
1144
|
+
i++;
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
return {
|
|
1148
|
+
kind: "refuse",
|
|
1149
|
+
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.`
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
if (spec.acceptsAssignments && ASSIGNMENT.test(token)) {
|
|
1153
|
+
assignments.push(token);
|
|
1154
|
+
i++;
|
|
1155
|
+
continue;
|
|
1156
|
+
}
|
|
1157
|
+
if (positionals > 0) {
|
|
1158
|
+
positionals--;
|
|
1159
|
+
i++;
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
break;
|
|
1163
|
+
}
|
|
1164
|
+
return { kind: "command", tokens: args.slice(i), assignments };
|
|
1165
|
+
}
|
|
1166
|
+
function unwrap(seg, dialect) {
|
|
1167
|
+
const wrappers = [];
|
|
1168
|
+
const assignments = [...seg.assignments];
|
|
1169
|
+
let current = seg;
|
|
1170
|
+
while (WRAPPER_FAMILY[current.binary]) {
|
|
1171
|
+
const scan = scanWrapperArgs(current.binary, WRAPPER_FAMILY[current.binary], current.args);
|
|
1172
|
+
if (scan.kind === "refuse") return { seg: { ...current, assignments }, wrappers, reason: scan.reason };
|
|
1173
|
+
if (scan.kind === "no-exec" || scan.tokens.length === 0) break;
|
|
1174
|
+
assignments.push(...scan.assignments);
|
|
1175
|
+
wrappers.push(current.binary);
|
|
1176
|
+
const inner = toSegment(scan.tokens, current.piped, dialect);
|
|
1177
|
+
assignments.push(...inner.assignments);
|
|
1178
|
+
current = { ...inner, assignments: [], expandable: current.expandable };
|
|
1179
|
+
}
|
|
1180
|
+
return { seg: { ...current, assignments }, wrappers };
|
|
1027
1181
|
}
|
|
1028
1182
|
function lexAll(command, dialect) {
|
|
1029
1183
|
const queue = [];
|
|
@@ -1086,6 +1240,16 @@ function refusalFor(seg) {
|
|
|
1086
1240
|
return `"git ${sub} ${flag}" mutates refs. You are a read-only planner \u2014 describe the change as a task instead.`;
|
|
1087
1241
|
}
|
|
1088
1242
|
}
|
|
1243
|
+
const execPathFlag = seg.args.find((a) => a === "--exec-path" || a.startsWith("--exec-path="));
|
|
1244
|
+
if (execPathFlag) {
|
|
1245
|
+
return `"git ${execPathFlag}" redirects where git looks for its helper programs, and can make it run an arbitrary one. Use the read-only research tools, or describe the change as a task.`;
|
|
1246
|
+
}
|
|
1247
|
+
if (sub === "grep") {
|
|
1248
|
+
const pagerFlag = seg.args.find((a) => a === "-O" || a === "--open-files-in-pager" || a.startsWith("--open-files-in-pager="));
|
|
1249
|
+
if (pagerFlag) {
|
|
1250
|
+
return `"git grep ${pagerFlag}" opens the results in an arbitrary named program. Use the read-only research tools, or describe the change as a task.`;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1089
1253
|
}
|
|
1090
1254
|
if (seg.binary === "find") {
|
|
1091
1255
|
const flag = seg.args.find((a) => ["-exec", "-execdir", "-ok", "-okdir", "-delete"].includes(a));
|
|
@@ -1108,8 +1272,17 @@ function refusalFor(seg) {
|
|
|
1108
1272
|
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
1273
|
}
|
|
1110
1274
|
}
|
|
1275
|
+
if (seg.assignments.length > 0) {
|
|
1276
|
+
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.`;
|
|
1277
|
+
}
|
|
1111
1278
|
return void 0;
|
|
1112
1279
|
}
|
|
1280
|
+
function withWrapperNote(reason, wrappers) {
|
|
1281
|
+
if (wrappers.length === 0) return reason;
|
|
1282
|
+
const quoted = wrappers.map((w) => `"${w}"`);
|
|
1283
|
+
const names = quoted.length > 1 ? `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}` : quoted[0];
|
|
1284
|
+
return `${reason} Wrapping it in ${names} does not change what runs.`;
|
|
1285
|
+
}
|
|
1113
1286
|
function classifyCommand(command, opts = {}) {
|
|
1114
1287
|
const trimmed = command.trim();
|
|
1115
1288
|
if (!trimmed) return { tier: "refuse", scope: "", reason: "Empty command." };
|
|
@@ -1138,11 +1311,13 @@ function classifyCommand(command, opts = {}) {
|
|
|
1138
1311
|
};
|
|
1139
1312
|
}
|
|
1140
1313
|
if (segments.length === 0) return { tier: "refuse", scope: "", reason: "No command found." };
|
|
1141
|
-
|
|
1314
|
+
const unwrapped = segments.map((seg) => unwrap(seg, dialect));
|
|
1315
|
+
for (const { seg, wrappers, reason: wrapperReason } of unwrapped) {
|
|
1316
|
+
if (wrapperReason) return { tier: "refuse", scope: "", reason: wrapperReason };
|
|
1142
1317
|
const reason = refusalFor(seg);
|
|
1143
|
-
if (reason) return { tier: "refuse", scope: "", reason };
|
|
1318
|
+
if (reason) return { tier: "refuse", scope: "", reason: withWrapperNote(reason, wrappers) };
|
|
1144
1319
|
}
|
|
1145
|
-
const nonAuto =
|
|
1320
|
+
const nonAuto = unwrapped.map((u) => u.seg).filter((s) => !isAuto(s));
|
|
1146
1321
|
if (nonAuto.length === 0) return { tier: "auto", scope: "" };
|
|
1147
1322
|
const scope = [...new Set(nonAuto.map(scopeFor))].sort().join(" + ");
|
|
1148
1323
|
return { tier: "ask", scope };
|
|
@@ -1641,14 +1816,14 @@ var PendingApprovals = class {
|
|
|
1641
1816
|
ask(request) {
|
|
1642
1817
|
const id = `ap-${Date.now()}-${counter++}`;
|
|
1643
1818
|
const pending = { id, request, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1644
|
-
return new Promise((
|
|
1819
|
+
return new Promise((resolve4) => {
|
|
1645
1820
|
const settle = (granted) => {
|
|
1646
1821
|
const entry = this.entries.get(id);
|
|
1647
1822
|
if (!entry) return;
|
|
1648
1823
|
clearTimeout(entry.timer);
|
|
1649
1824
|
this.entries.delete(id);
|
|
1650
1825
|
this.opts.onSettled?.(id, granted);
|
|
1651
|
-
|
|
1826
|
+
resolve4(granted);
|
|
1652
1827
|
};
|
|
1653
1828
|
const timer = setTimeout(() => settle(false), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
1654
1829
|
timer.unref?.();
|
|
@@ -4558,9 +4733,9 @@ function summarizeToolCall(tool, argsJson, toolLabel) {
|
|
|
4558
4733
|
const scope = args.include ? ` in ${args.include}` : "";
|
|
4559
4734
|
return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;
|
|
4560
4735
|
}
|
|
4561
|
-
const
|
|
4562
|
-
if (
|
|
4563
|
-
const basename = String(
|
|
4736
|
+
const path17 = args.filePath || args.file_path || args.path;
|
|
4737
|
+
if (path17) {
|
|
4738
|
+
const basename = String(path17).split("/").pop() || String(path17);
|
|
4564
4739
|
return `${display} ${basename}`;
|
|
4565
4740
|
}
|
|
4566
4741
|
if (args.pattern) {
|
|
@@ -7221,28 +7396,28 @@ function posixBinDirs() {
|
|
|
7221
7396
|
];
|
|
7222
7397
|
}
|
|
7223
7398
|
function windowsBinDirs(env, home) {
|
|
7224
|
-
const
|
|
7225
|
-
const under = (base, ...parts) => base ? [
|
|
7399
|
+
const join16 = (...parts) => path5.win32.join(...parts);
|
|
7400
|
+
const under = (base, ...parts) => base ? [join16(base, ...parts)] : [];
|
|
7226
7401
|
const appData = env.APPDATA;
|
|
7227
7402
|
const localAppData = env.LOCALAPPDATA;
|
|
7228
7403
|
const programData = env.ProgramData;
|
|
7229
7404
|
return [
|
|
7230
7405
|
// Native per-user installers, PowerShell-driven and otherwise.
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7406
|
+
join16(home, ".local", "bin"),
|
|
7407
|
+
join16(home, ".opencode", "bin"),
|
|
7408
|
+
join16(home, ".claude", "bin"),
|
|
7409
|
+
join16(home, ".codex", "bin"),
|
|
7235
7410
|
...under(localAppData, "Programs", "claude"),
|
|
7236
7411
|
// Node package managers. npm's global prefix is `%APPDATA%\npm`; the
|
|
7237
7412
|
// literal spelling is kept as a fallback for a host that does not export
|
|
7238
7413
|
// APPDATA (a service account, a stripped CI container).
|
|
7239
7414
|
...under(appData, "npm"),
|
|
7240
|
-
|
|
7415
|
+
join16(home, "AppData", "Roaming", "npm"),
|
|
7241
7416
|
...under(localAppData, "pnpm"),
|
|
7242
7417
|
...under(localAppData, "Yarn", "bin"),
|
|
7243
|
-
|
|
7418
|
+
join16(home, ".bun", "bin"),
|
|
7244
7419
|
// Windows package managers.
|
|
7245
|
-
|
|
7420
|
+
join16(home, "scoop", "shims"),
|
|
7246
7421
|
...under(env.SCOOP, "shims"),
|
|
7247
7422
|
...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
|
|
7248
7423
|
...under(programData, "chocolatey", "bin"),
|
|
@@ -7252,7 +7427,7 @@ function windowsBinDirs(env, home) {
|
|
|
7252
7427
|
...under(localAppData, "Microsoft", "WindowsApps"),
|
|
7253
7428
|
// Version managers. Volta's Windows home is not the POSIX `~/.volta`.
|
|
7254
7429
|
...under(localAppData, "Volta", "bin"),
|
|
7255
|
-
|
|
7430
|
+
join16(home, ".volta", "bin")
|
|
7256
7431
|
];
|
|
7257
7432
|
}
|
|
7258
7433
|
function wellKnownBinDirs(deps = {}) {
|
|
@@ -7553,7 +7728,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
7553
7728
|
const PATH = await augmentedPath();
|
|
7554
7729
|
const launch = await planDirectLaunch(command, args).catch(() => null);
|
|
7555
7730
|
if (!launch) return null;
|
|
7556
|
-
return new Promise((
|
|
7731
|
+
return new Promise((resolve4) => {
|
|
7557
7732
|
let child;
|
|
7558
7733
|
try {
|
|
7559
7734
|
child = (0, import_child_process3.spawn)(launch.file, launch.args, {
|
|
@@ -7562,7 +7737,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
7562
7737
|
windowsVerbatimArguments: launch.verbatim
|
|
7563
7738
|
});
|
|
7564
7739
|
} catch {
|
|
7565
|
-
|
|
7740
|
+
resolve4(null);
|
|
7566
7741
|
return;
|
|
7567
7742
|
}
|
|
7568
7743
|
let settled = false;
|
|
@@ -7571,7 +7746,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
7571
7746
|
settled = true;
|
|
7572
7747
|
clearTimeout(timer);
|
|
7573
7748
|
killTree(child);
|
|
7574
|
-
|
|
7749
|
+
resolve4(value);
|
|
7575
7750
|
};
|
|
7576
7751
|
const timer = setTimeout(() => finish(null), options?.timeout ?? 2e4);
|
|
7577
7752
|
child.on("error", () => finish(null));
|
|
@@ -8611,11 +8786,71 @@ var RunnerInstallation = class {
|
|
|
8611
8786
|
}
|
|
8612
8787
|
};
|
|
8613
8788
|
|
|
8789
|
+
// src/services/settingsEnvAllowlist.ts
|
|
8790
|
+
var ORDEWELL_SETTABLE_ENV = [
|
|
8791
|
+
"AI_PROVIDER",
|
|
8792
|
+
"ORCHESTRATOR_MODEL",
|
|
8793
|
+
"ORDEWELL_SUBAGENT_MODEL",
|
|
8794
|
+
"ORDEWELL_PLANNER_EFFORT",
|
|
8795
|
+
"ORDEWELL_RESEARCH_ENABLED",
|
|
8796
|
+
"ORDEWELL_MAX_PARALLEL"
|
|
8797
|
+
];
|
|
8798
|
+
var SETTINGS_ENV_REFUSED = [
|
|
8799
|
+
// Approval posture and pre-approved scope.
|
|
8800
|
+
"ORDEWELL_AUTONOMOUS_MODE",
|
|
8801
|
+
"ORDEWELL_APPROVAL_MODE",
|
|
8802
|
+
"ORDEWELL_APPROVAL_ALLOW",
|
|
8803
|
+
// Where settings are persisted.
|
|
8804
|
+
"ORDEWELL_SETTINGS_PATH",
|
|
8805
|
+
// Runtime options and dynamic loaders.
|
|
8806
|
+
"NODE_OPTIONS",
|
|
8807
|
+
"NODE_REPL_EXTERNAL_MODULE",
|
|
8808
|
+
"NODE_PATH",
|
|
8809
|
+
"ELECTRON_RUN_AS_NODE",
|
|
8810
|
+
"LD_PRELOAD",
|
|
8811
|
+
"LD_LIBRARY_PATH",
|
|
8812
|
+
"LD_AUDIT",
|
|
8813
|
+
"DYLD_INSERT_LIBRARIES",
|
|
8814
|
+
"DYLD_LIBRARY_PATH",
|
|
8815
|
+
"DYLD_FRAMEWORK_PATH",
|
|
8816
|
+
// Executable resolution.
|
|
8817
|
+
"PATH",
|
|
8818
|
+
"PATHEXT",
|
|
8819
|
+
"NODE"
|
|
8820
|
+
];
|
|
8821
|
+
var REFUSED = new Set(SETTINGS_ENV_REFUSED);
|
|
8822
|
+
function providerEnvKeys() {
|
|
8823
|
+
const keys = [];
|
|
8824
|
+
for (const meta of Object.values(ALL_PROVIDERS)) {
|
|
8825
|
+
if (meta.apiKeyEnvVar) keys.push(meta.apiKeyEnvVar);
|
|
8826
|
+
if (meta.baseUrlEnvVar) keys.push(meta.baseUrlEnvVar);
|
|
8827
|
+
for (const detect of meta.detectEnvVars) keys.push(detect);
|
|
8828
|
+
}
|
|
8829
|
+
return keys;
|
|
8830
|
+
}
|
|
8831
|
+
var PROVIDER_CREDENTIAL_ENV = new Set(providerEnvKeys());
|
|
8832
|
+
var SETTINGS_ENV_ALLOWLIST = new Set(
|
|
8833
|
+
[...providerEnvKeys(), ...ORDEWELL_SETTABLE_ENV].filter((key) => !REFUSED.has(key))
|
|
8834
|
+
);
|
|
8835
|
+
function admitSettingsEnv(env) {
|
|
8836
|
+
const accepted = {};
|
|
8837
|
+
const rejected = [];
|
|
8838
|
+
for (const [key, value] of Object.entries(env)) {
|
|
8839
|
+
if (REFUSED.has(key) || !SETTINGS_ENV_ALLOWLIST.has(key) || typeof value !== "string") {
|
|
8840
|
+
rejected.push(key);
|
|
8841
|
+
continue;
|
|
8842
|
+
}
|
|
8843
|
+
accepted[key] = value;
|
|
8844
|
+
}
|
|
8845
|
+
return { accepted, rejected };
|
|
8846
|
+
}
|
|
8847
|
+
|
|
8614
8848
|
// src/services/harness/CliAgentAiService.ts
|
|
8615
8849
|
var import_child_process5 = require("child_process");
|
|
8616
8850
|
|
|
8617
8851
|
// src/utils/workspace.ts
|
|
8618
8852
|
var fs3 = __toESM(require("fs"));
|
|
8853
|
+
var path9 = __toESM(require("path"));
|
|
8619
8854
|
var WorkspaceNotFoundError = class extends Error {
|
|
8620
8855
|
constructor(workspace) {
|
|
8621
8856
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -8635,6 +8870,46 @@ function assertWorkspaceExists(workspace, deps = {}) {
|
|
|
8635
8870
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
8636
8871
|
if (!isDirectory(workspace)) throw new WorkspaceNotFoundError(workspace);
|
|
8637
8872
|
}
|
|
8873
|
+
var WorkspaceNotAProjectError = class extends Error {
|
|
8874
|
+
constructor(workspace) {
|
|
8875
|
+
super(`Workspace "${workspace}" is not a project directory (no .ordewell state, version control, or recognized manifest found).`);
|
|
8876
|
+
this.workspace = workspace;
|
|
8877
|
+
this.name = "WorkspaceNotAProjectError";
|
|
8878
|
+
}
|
|
8879
|
+
workspace;
|
|
8880
|
+
};
|
|
8881
|
+
var PROJECT_MARKER_DIRS = [".ordewell", ".git", ".hg", ".svn", ".bzr"];
|
|
8882
|
+
var PROJECT_MARKER_FILES = [
|
|
8883
|
+
"package.json",
|
|
8884
|
+
"Cargo.toml",
|
|
8885
|
+
"go.mod",
|
|
8886
|
+
"pyproject.toml",
|
|
8887
|
+
"setup.py",
|
|
8888
|
+
"requirements.txt",
|
|
8889
|
+
"Pipfile",
|
|
8890
|
+
"pom.xml",
|
|
8891
|
+
"build.gradle",
|
|
8892
|
+
"build.gradle.kts",
|
|
8893
|
+
"Gemfile",
|
|
8894
|
+
"composer.json",
|
|
8895
|
+
"pubspec.yaml",
|
|
8896
|
+
"mix.exs",
|
|
8897
|
+
"CMakeLists.txt"
|
|
8898
|
+
];
|
|
8899
|
+
function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
8900
|
+
const realpath = deps.realpath ?? ((candidate) => fs3.realpathSync(candidate));
|
|
8901
|
+
const exists = deps.exists ?? ((candidate) => fs3.existsSync(candidate));
|
|
8902
|
+
let resolved;
|
|
8903
|
+
try {
|
|
8904
|
+
resolved = realpath(workspace);
|
|
8905
|
+
} catch {
|
|
8906
|
+
throw new WorkspaceNotAProjectError(workspace);
|
|
8907
|
+
}
|
|
8908
|
+
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
8909
|
+
(marker) => exists(path9.join(resolved, marker))
|
|
8910
|
+
);
|
|
8911
|
+
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
8912
|
+
}
|
|
8638
8913
|
|
|
8639
8914
|
// src/services/harness/AgentAdapter.ts
|
|
8640
8915
|
var LineBuffer = class {
|
|
@@ -8690,8 +8965,8 @@ var StdioAgentAdapter = class {
|
|
|
8690
8965
|
}
|
|
8691
8966
|
async start(opts) {
|
|
8692
8967
|
assertWorkspaceExists(opts.cwd, { isDirectory: this.deps.isDirectory });
|
|
8693
|
-
this.processEnded = new Promise((
|
|
8694
|
-
this.markEnded =
|
|
8968
|
+
this.processEnded = new Promise((resolve4) => {
|
|
8969
|
+
this.markEnded = resolve4;
|
|
8695
8970
|
});
|
|
8696
8971
|
const spec = this.spawnSpec(opts);
|
|
8697
8972
|
const resolvePath = this.deps.resolvePath ?? augmentedPath;
|
|
@@ -8739,7 +9014,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
8739
9014
|
onEvent({ type: "error", message: this.exitMessage() });
|
|
8740
9015
|
return;
|
|
8741
9016
|
}
|
|
8742
|
-
await new Promise((
|
|
9017
|
+
await new Promise((resolve4) => {
|
|
8743
9018
|
let settled = false;
|
|
8744
9019
|
const finish = () => {
|
|
8745
9020
|
if (settled) return;
|
|
@@ -8748,7 +9023,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
8748
9023
|
signal?.removeEventListener("abort", onAbort);
|
|
8749
9024
|
this.process?.removeListener("exit", onExit);
|
|
8750
9025
|
this.process?.removeListener("error", onExit);
|
|
8751
|
-
|
|
9026
|
+
resolve4();
|
|
8752
9027
|
};
|
|
8753
9028
|
const emit = (event) => {
|
|
8754
9029
|
onEvent(event);
|
|
@@ -8949,14 +9224,14 @@ function codexSandboxUnavailableMessage() {
|
|
|
8949
9224
|
].join("\n");
|
|
8950
9225
|
}
|
|
8951
9226
|
function runProbe(deps, cwd, env, flags) {
|
|
8952
|
-
return new Promise((
|
|
9227
|
+
return new Promise((resolve4) => {
|
|
8953
9228
|
let output = "";
|
|
8954
9229
|
let settled = false;
|
|
8955
9230
|
const finish = (code) => {
|
|
8956
9231
|
if (settled) return;
|
|
8957
9232
|
settled = true;
|
|
8958
9233
|
clearTimeout(timer);
|
|
8959
|
-
|
|
9234
|
+
resolve4({ code, output });
|
|
8960
9235
|
};
|
|
8961
9236
|
const timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);
|
|
8962
9237
|
timer.unref?.();
|
|
@@ -9039,8 +9314,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
9039
9314
|
async handshake(opts) {
|
|
9040
9315
|
this.sandbox = await probeCodexSandbox(this.deps, opts.cwd, this.spawnEnv);
|
|
9041
9316
|
if (this.sandbox === "unavailable") throw new Error(codexSandboxUnavailableMessage());
|
|
9042
|
-
const ready = new Promise((
|
|
9043
|
-
this.settleHandshake =
|
|
9317
|
+
const ready = new Promise((resolve4) => {
|
|
9318
|
+
this.settleHandshake = resolve4;
|
|
9044
9319
|
});
|
|
9045
9320
|
this.writeLine({
|
|
9046
9321
|
jsonrpc: "2.0",
|
|
@@ -9053,8 +9328,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
9053
9328
|
// A binary that rejects `app-server` outright dies immediately; waiting
|
|
9054
9329
|
// out the timeout would turn a one-line diagnostic into a 30s stall.
|
|
9055
9330
|
this.processEnded.then(() => false),
|
|
9056
|
-
new Promise((
|
|
9057
|
-
const t = setTimeout(() =>
|
|
9331
|
+
new Promise((resolve4) => {
|
|
9332
|
+
const t = setTimeout(() => resolve4(false), HANDSHAKE_TIMEOUT_MS);
|
|
9058
9333
|
t.unref?.();
|
|
9059
9334
|
})
|
|
9060
9335
|
]);
|
|
@@ -9342,12 +9617,12 @@ var OpenCodeAdapter = class {
|
|
|
9342
9617
|
cwd: opts.cwd,
|
|
9343
9618
|
windowsVerbatimArguments: launch.verbatim
|
|
9344
9619
|
});
|
|
9345
|
-
const banner = new Promise((
|
|
9620
|
+
const banner = new Promise((resolve4) => {
|
|
9346
9621
|
let seen = "";
|
|
9347
9622
|
const scan = (chunk) => {
|
|
9348
9623
|
seen += chunk.toString();
|
|
9349
9624
|
const match = seen.match(/https?:\/\/[^\s]+/);
|
|
9350
|
-
if (match)
|
|
9625
|
+
if (match) resolve4(match[0].replace(/[.,)]$/, ""));
|
|
9351
9626
|
};
|
|
9352
9627
|
this.process.stdout?.on("data", scan);
|
|
9353
9628
|
this.process.stderr?.on("data", (chunk) => {
|
|
@@ -9356,15 +9631,15 @@ var OpenCodeAdapter = class {
|
|
|
9356
9631
|
});
|
|
9357
9632
|
this.process.on("exit", () => {
|
|
9358
9633
|
this.exited = true;
|
|
9359
|
-
|
|
9634
|
+
resolve4(null);
|
|
9360
9635
|
});
|
|
9361
9636
|
this.process.on("error", (err) => {
|
|
9362
9637
|
this.exited = true;
|
|
9363
9638
|
this.stderrTail = (this.stderrTail + `
|
|
9364
9639
|
${err.message}`).slice(-STDERR_TAIL_CHARS2);
|
|
9365
|
-
|
|
9640
|
+
resolve4(null);
|
|
9366
9641
|
});
|
|
9367
|
-
const timer = setTimeout(() =>
|
|
9642
|
+
const timer = setTimeout(() => resolve4(null), SERVER_READY_TIMEOUT_MS);
|
|
9368
9643
|
timer.unref?.();
|
|
9369
9644
|
});
|
|
9370
9645
|
this.baseUrl = await banner;
|
|
@@ -9394,8 +9669,8 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
9394
9669
|
const streamAbort = new AbortController();
|
|
9395
9670
|
let connected = () => {
|
|
9396
9671
|
};
|
|
9397
|
-
const streamReady = new Promise((
|
|
9398
|
-
connected =
|
|
9672
|
+
const streamReady = new Promise((resolve4) => {
|
|
9673
|
+
connected = resolve4;
|
|
9399
9674
|
});
|
|
9400
9675
|
const live = this.streamEvents(
|
|
9401
9676
|
streamAbort.signal,
|
|
@@ -9547,14 +9822,14 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
9547
9822
|
}
|
|
9548
9823
|
}
|
|
9549
9824
|
}
|
|
9550
|
-
async json(method,
|
|
9551
|
-
const response = await this.deps.fetch(`${this.baseUrl}${
|
|
9825
|
+
async json(method, path17, body, signal) {
|
|
9826
|
+
const response = await this.deps.fetch(`${this.baseUrl}${path17}`, {
|
|
9552
9827
|
method,
|
|
9553
9828
|
headers: { "content-type": "application/json" },
|
|
9554
9829
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
9555
9830
|
...signal ? { signal } : {}
|
|
9556
9831
|
});
|
|
9557
|
-
if (!response.ok) throw new Error(`${method} ${
|
|
9832
|
+
if (!response.ok) throw new Error(`${method} ${path17} failed: ${response.status} ${response.statusText}`);
|
|
9558
9833
|
return await response.json().catch(() => null);
|
|
9559
9834
|
}
|
|
9560
9835
|
nativeSessionId() {
|
|
@@ -10368,11 +10643,11 @@ function executionSummary(tasks) {
|
|
|
10368
10643
|
|
|
10369
10644
|
// src/utils/sessionStore.ts
|
|
10370
10645
|
var fs5 = __toESM(require("fs"));
|
|
10371
|
-
var
|
|
10646
|
+
var path11 = __toESM(require("path"));
|
|
10372
10647
|
|
|
10373
10648
|
// src/utils/fsHelpers.ts
|
|
10374
10649
|
var fs4 = __toESM(require("fs"));
|
|
10375
|
-
var
|
|
10650
|
+
var path10 = __toESM(require("path"));
|
|
10376
10651
|
var STATE_DIR = ".ordewell";
|
|
10377
10652
|
function ensureDir(dir) {
|
|
10378
10653
|
if (!fs4.existsSync(dir)) {
|
|
@@ -10380,13 +10655,19 @@ function ensureDir(dir) {
|
|
|
10380
10655
|
}
|
|
10381
10656
|
}
|
|
10382
10657
|
function getStateDir(baseDir) {
|
|
10383
|
-
return
|
|
10658
|
+
return path10.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
10659
|
+
}
|
|
10660
|
+
|
|
10661
|
+
// src/utils/sessionId.ts
|
|
10662
|
+
var import_crypto = require("crypto");
|
|
10663
|
+
function mintSessionId() {
|
|
10664
|
+
return `session-${(0, import_crypto.randomBytes)(16).toString("hex")}`;
|
|
10384
10665
|
}
|
|
10385
10666
|
|
|
10386
10667
|
// src/utils/sessionStore.ts
|
|
10387
10668
|
var SESSIONS_SUBDIR = "sessions";
|
|
10388
10669
|
function getSessionsDir(baseDir) {
|
|
10389
|
-
return
|
|
10670
|
+
return path11.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
10390
10671
|
}
|
|
10391
10672
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
10392
10673
|
function hasScalarRunner(parsed) {
|
|
@@ -10407,7 +10688,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
10407
10688
|
ensureDir(sessionsDir);
|
|
10408
10689
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10409
10690
|
const meta = {
|
|
10410
|
-
id: id ||
|
|
10691
|
+
id: id || mintSessionId(),
|
|
10411
10692
|
goal: goal || "(untitled)",
|
|
10412
10693
|
runners: plan.runners,
|
|
10413
10694
|
taskCount: plan.tasks.flatMap((t) => [t, ...t.subtasks || []]).length,
|
|
@@ -10420,7 +10701,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
10420
10701
|
plan: JSON.parse(JSON.stringify(plan))
|
|
10421
10702
|
};
|
|
10422
10703
|
const filename = sessionFilename(meta);
|
|
10423
|
-
const filePath =
|
|
10704
|
+
const filePath = path11.join(sessionsDir, filename);
|
|
10424
10705
|
fs5.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
10425
10706
|
return meta;
|
|
10426
10707
|
}
|
|
@@ -10430,7 +10711,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
10430
10711
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
10431
10712
|
return files.map((f) => {
|
|
10432
10713
|
try {
|
|
10433
|
-
const raw = fs5.readFileSync(
|
|
10714
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
10434
10715
|
const parsed = JSON.parse(raw);
|
|
10435
10716
|
if (hasScalarRunner(parsed)) {
|
|
10436
10717
|
logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
|
|
@@ -10448,7 +10729,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
10448
10729
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
10449
10730
|
for (const f of files) {
|
|
10450
10731
|
try {
|
|
10451
|
-
const raw = fs5.readFileSync(
|
|
10732
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
10452
10733
|
const session = JSON.parse(raw);
|
|
10453
10734
|
if (session.meta.id === sessionId) return f;
|
|
10454
10735
|
} catch (err) {
|
|
@@ -10463,7 +10744,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
10463
10744
|
try {
|
|
10464
10745
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
10465
10746
|
if (file) {
|
|
10466
|
-
const raw = fs5.readFileSync(
|
|
10747
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, file), "utf-8");
|
|
10467
10748
|
const parsed = JSON.parse(raw);
|
|
10468
10749
|
if (hasScalarRunner(parsed)) {
|
|
10469
10750
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -10497,7 +10778,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
10497
10778
|
try {
|
|
10498
10779
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
10499
10780
|
if (file) {
|
|
10500
|
-
fs5.unlinkSync(
|
|
10781
|
+
fs5.unlinkSync(path11.join(sessionsDir, file));
|
|
10501
10782
|
return true;
|
|
10502
10783
|
}
|
|
10503
10784
|
} catch (err) {
|
|
@@ -10516,11 +10797,6 @@ var PlanEditError = class extends Error {
|
|
|
10516
10797
|
function sessionRuntimeSettings(settings) {
|
|
10517
10798
|
return { ...plannerRuntimeToggles(settings), modelAllowlist: settings.modelAllowlist };
|
|
10518
10799
|
}
|
|
10519
|
-
var lastMintedAt = 0;
|
|
10520
|
-
function mintSessionId() {
|
|
10521
|
-
lastMintedAt = Math.max(Date.now(), lastMintedAt + 1);
|
|
10522
|
-
return `session-${lastMintedAt}`;
|
|
10523
|
-
}
|
|
10524
10800
|
var Session = class {
|
|
10525
10801
|
/** Injected by a test; when present it is the service, forever. */
|
|
10526
10802
|
pinnedAiService;
|
|
@@ -12318,26 +12594,128 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
12318
12594
|
}
|
|
12319
12595
|
};
|
|
12320
12596
|
|
|
12597
|
+
// src/utils/daemonToken.ts
|
|
12598
|
+
var import_crypto2 = require("crypto");
|
|
12599
|
+
var import_fs2 = require("fs");
|
|
12600
|
+
var import_os2 = require("os");
|
|
12601
|
+
var import_path2 = require("path");
|
|
12602
|
+
var BEARER_PREFIX = "bearer ";
|
|
12603
|
+
var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
|
|
12604
|
+
var DAEMON_SUBPROTOCOL = "ordewell.v1";
|
|
12605
|
+
function configDir() {
|
|
12606
|
+
return (0, import_path2.join)((0, import_os2.homedir)(), ".config", "ordewell");
|
|
12607
|
+
}
|
|
12608
|
+
function daemonTokenPath(port) {
|
|
12609
|
+
return (0, import_path2.join)(configDir(), `server-${port}.token`);
|
|
12610
|
+
}
|
|
12611
|
+
function mintDaemonToken(port) {
|
|
12612
|
+
const token = (0, import_crypto2.randomBytes)(32).toString("base64url");
|
|
12613
|
+
const file = daemonTokenPath(port);
|
|
12614
|
+
(0, import_fs2.mkdirSync)(configDir(), { recursive: true });
|
|
12615
|
+
try {
|
|
12616
|
+
(0, import_fs2.unlinkSync)(file);
|
|
12617
|
+
} catch {
|
|
12618
|
+
}
|
|
12619
|
+
const fd = (0, import_fs2.openSync)(file, "wx", 384);
|
|
12620
|
+
try {
|
|
12621
|
+
(0, import_fs2.writeSync)(fd, token);
|
|
12622
|
+
} finally {
|
|
12623
|
+
(0, import_fs2.closeSync)(fd);
|
|
12624
|
+
}
|
|
12625
|
+
return { token, file };
|
|
12626
|
+
}
|
|
12627
|
+
function readDaemonToken(port) {
|
|
12628
|
+
try {
|
|
12629
|
+
const token = (0, import_fs2.readFileSync)(daemonTokenPath(port), "utf8").trim();
|
|
12630
|
+
return token === "" ? void 0 : token;
|
|
12631
|
+
} catch {
|
|
12632
|
+
return void 0;
|
|
12633
|
+
}
|
|
12634
|
+
}
|
|
12635
|
+
function clearDaemonToken(port) {
|
|
12636
|
+
try {
|
|
12637
|
+
(0, import_fs2.unlinkSync)(daemonTokenPath(port));
|
|
12638
|
+
} catch {
|
|
12639
|
+
}
|
|
12640
|
+
}
|
|
12641
|
+
function bearerHeaderValue(token) {
|
|
12642
|
+
return `Bearer ${token}`;
|
|
12643
|
+
}
|
|
12644
|
+
function tokenSubprotocols(token) {
|
|
12645
|
+
return [DAEMON_SUBPROTOCOL, `${DAEMON_TOKEN_SUBPROTOCOL_PREFIX}${token}`];
|
|
12646
|
+
}
|
|
12647
|
+
function extractPresentedToken(carriers) {
|
|
12648
|
+
const authorization = carriers.authorization;
|
|
12649
|
+
if (authorization && authorization.toLowerCase().startsWith(BEARER_PREFIX)) {
|
|
12650
|
+
const value = authorization.slice(BEARER_PREFIX.length).trim();
|
|
12651
|
+
if (value !== "") return value;
|
|
12652
|
+
}
|
|
12653
|
+
for (const offered of (carriers.secWebSocketProtocol ?? "").split(",")) {
|
|
12654
|
+
const value = offered.trim();
|
|
12655
|
+
if (!value.startsWith(DAEMON_TOKEN_SUBPROTOCOL_PREFIX)) continue;
|
|
12656
|
+
const token = value.slice(DAEMON_TOKEN_SUBPROTOCOL_PREFIX.length);
|
|
12657
|
+
if (token !== "") return token;
|
|
12658
|
+
}
|
|
12659
|
+
return void 0;
|
|
12660
|
+
}
|
|
12661
|
+
function tokensMatch(presented, expected) {
|
|
12662
|
+
if (presented === void 0) return false;
|
|
12663
|
+
const a = Buffer.from(presented, "utf8");
|
|
12664
|
+
const b = Buffer.from(expected, "utf8");
|
|
12665
|
+
if (a.length !== b.length) return false;
|
|
12666
|
+
return (0, import_crypto2.timingSafeEqual)(a, b);
|
|
12667
|
+
}
|
|
12668
|
+
|
|
12321
12669
|
// src/plugins/RunnerRegistry.ts
|
|
12322
12670
|
var fs7 = __toESM(require("fs"));
|
|
12323
|
-
var
|
|
12671
|
+
var path14 = __toESM(require("path"));
|
|
12324
12672
|
var os5 = __toESM(require("os"));
|
|
12325
12673
|
var import_child_process9 = require("child_process");
|
|
12674
|
+
var import_crypto3 = require("crypto");
|
|
12326
12675
|
|
|
12327
12676
|
// src/plugins/FsPluginStore.ts
|
|
12328
12677
|
var fs6 = __toESM(require("fs"));
|
|
12329
|
-
var
|
|
12678
|
+
var path13 = __toESM(require("path"));
|
|
12330
12679
|
var os4 = __toESM(require("os"));
|
|
12331
|
-
|
|
12332
|
-
|
|
12680
|
+
|
|
12681
|
+
// src/plugins/pluginNames.ts
|
|
12682
|
+
var path12 = __toESM(require("path"));
|
|
12683
|
+
var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
12684
|
+
var MAX_PLUGIN_NAME_LENGTH = 64;
|
|
12685
|
+
function isPlainPluginName(name) {
|
|
12686
|
+
return typeof name === "string" && name.length <= MAX_PLUGIN_NAME_LENGTH && PLUGIN_NAME_PATTERN.test(name);
|
|
12687
|
+
}
|
|
12688
|
+
function assertPlainPluginName(name) {
|
|
12689
|
+
if (!isPlainPluginName(name)) {
|
|
12690
|
+
throw new Error(
|
|
12691
|
+
`Invalid plugin name: ${JSON.stringify(name)}. Names must be a single plain segment of letters, digits, '.', '-' or '_' (max ${MAX_PLUGIN_NAME_LENGTH} characters).`
|
|
12692
|
+
);
|
|
12693
|
+
}
|
|
12333
12694
|
}
|
|
12695
|
+
function resolvePluginInstallDir(pluginsDir, name) {
|
|
12696
|
+
assertPlainPluginName(name);
|
|
12697
|
+
const root = path12.resolve(pluginsDir);
|
|
12698
|
+
const dest = path12.resolve(root, name);
|
|
12699
|
+
const relative3 = path12.relative(root, dest);
|
|
12700
|
+
if (relative3 !== name || relative3 === "" || path12.isAbsolute(relative3)) {
|
|
12701
|
+
throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
|
|
12702
|
+
}
|
|
12703
|
+
return dest;
|
|
12704
|
+
}
|
|
12705
|
+
|
|
12706
|
+
// src/plugins/manifestValidation.ts
|
|
12334
12707
|
function isValidManifest(obj) {
|
|
12335
12708
|
if (!obj || typeof obj !== "object") return false;
|
|
12336
12709
|
const m = obj;
|
|
12337
|
-
return
|
|
12710
|
+
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;
|
|
12711
|
+
}
|
|
12712
|
+
|
|
12713
|
+
// src/plugins/FsPluginStore.ts
|
|
12714
|
+
function userPluginsDir() {
|
|
12715
|
+
return path13.join(os4.homedir(), ".config", "ordewell", "plugins");
|
|
12338
12716
|
}
|
|
12339
12717
|
function loadManifestFromDir(dir) {
|
|
12340
|
-
const manifestPath =
|
|
12718
|
+
const manifestPath = path13.join(dir, "manifest.json");
|
|
12341
12719
|
if (!fs6.existsSync(manifestPath)) return null;
|
|
12342
12720
|
try {
|
|
12343
12721
|
const raw = fs6.readFileSync(manifestPath, "utf8");
|
|
@@ -12352,8 +12730,8 @@ function copyDirSync(src, dest) {
|
|
|
12352
12730
|
ensureDir(dest);
|
|
12353
12731
|
const entries = fs6.readdirSync(src, { withFileTypes: true });
|
|
12354
12732
|
for (const entry of entries) {
|
|
12355
|
-
const srcPath =
|
|
12356
|
-
const destPath =
|
|
12733
|
+
const srcPath = path13.join(src, entry.name);
|
|
12734
|
+
const destPath = path13.join(dest, entry.name);
|
|
12357
12735
|
if (entry.isDirectory()) {
|
|
12358
12736
|
copyDirSync(srcPath, destPath);
|
|
12359
12737
|
} else {
|
|
@@ -12365,7 +12743,7 @@ function rmDirSync(dir) {
|
|
|
12365
12743
|
if (!fs6.existsSync(dir)) return;
|
|
12366
12744
|
const entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
12367
12745
|
for (const entry of entries) {
|
|
12368
|
-
const p =
|
|
12746
|
+
const p = path13.join(dir, entry.name);
|
|
12369
12747
|
if (entry.isDirectory()) {
|
|
12370
12748
|
rmDirSync(p);
|
|
12371
12749
|
} else {
|
|
@@ -12389,6 +12767,13 @@ var FsPluginStore = class {
|
|
|
12389
12767
|
}
|
|
12390
12768
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12391
12769
|
}
|
|
12770
|
+
listDir(dir) {
|
|
12771
|
+
try {
|
|
12772
|
+
return fs6.readdirSync(dir);
|
|
12773
|
+
} catch {
|
|
12774
|
+
return [];
|
|
12775
|
+
}
|
|
12776
|
+
}
|
|
12392
12777
|
loadManifest(pluginDir) {
|
|
12393
12778
|
return loadManifestFromDir(pluginDir);
|
|
12394
12779
|
}
|
|
@@ -12411,11 +12796,11 @@ var FsPluginStore = class {
|
|
|
12411
12796
|
return null;
|
|
12412
12797
|
}
|
|
12413
12798
|
}
|
|
12414
|
-
dirExists(
|
|
12415
|
-
return fs6.existsSync(
|
|
12799
|
+
dirExists(path17) {
|
|
12800
|
+
return fs6.existsSync(path17) && fs6.statSync(path17).isDirectory();
|
|
12416
12801
|
}
|
|
12417
|
-
exists(
|
|
12418
|
-
return fs6.existsSync(
|
|
12802
|
+
exists(path17) {
|
|
12803
|
+
return fs6.existsSync(path17);
|
|
12419
12804
|
}
|
|
12420
12805
|
};
|
|
12421
12806
|
|
|
@@ -12703,17 +13088,98 @@ var OPENCODE_MANIFEST = {
|
|
|
12703
13088
|
]
|
|
12704
13089
|
};
|
|
12705
13090
|
|
|
13091
|
+
// src/plugins/pluginSource.ts
|
|
13092
|
+
var ALLOWED_PLUGIN_HOSTS = [
|
|
13093
|
+
"github.com",
|
|
13094
|
+
"gitlab.com",
|
|
13095
|
+
"bitbucket.org",
|
|
13096
|
+
"codeberg.org"
|
|
13097
|
+
];
|
|
13098
|
+
var SAFE_REPO_PATH = /^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/;
|
|
13099
|
+
var HAS_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]+:/;
|
|
13100
|
+
var SCP_LIKE_REMOTE = /^[^/\\]+@[^/\\]+:/;
|
|
13101
|
+
function hasControlCharacter(value) {
|
|
13102
|
+
for (let i = 0; i < value.length; i++) {
|
|
13103
|
+
const code = value.charCodeAt(i);
|
|
13104
|
+
if (code < 32 || code === 127) return true;
|
|
13105
|
+
}
|
|
13106
|
+
return false;
|
|
13107
|
+
}
|
|
13108
|
+
function assertInstallablePluginUrl(url) {
|
|
13109
|
+
if (typeof url !== "string" || url.trim() === "") {
|
|
13110
|
+
throw new Error("A plugin repository URL is required.");
|
|
13111
|
+
}
|
|
13112
|
+
if (hasControlCharacter(url)) {
|
|
13113
|
+
throw new Error("Plugin URL contains control characters.");
|
|
13114
|
+
}
|
|
13115
|
+
let parsed;
|
|
13116
|
+
try {
|
|
13117
|
+
parsed = new URL(url.trim());
|
|
13118
|
+
} catch {
|
|
13119
|
+
throw new Error(`Not a valid plugin repository URL: ${url}`);
|
|
13120
|
+
}
|
|
13121
|
+
if (parsed.protocol !== "https:") {
|
|
13122
|
+
throw new Error(
|
|
13123
|
+
`Plugin repositories must be cloned over https (got "${parsed.protocol}//"). git transport helpers and non-https schemes are not accepted.`
|
|
13124
|
+
);
|
|
13125
|
+
}
|
|
13126
|
+
if (parsed.username || parsed.password) {
|
|
13127
|
+
throw new Error("Plugin URL must not embed credentials.");
|
|
13128
|
+
}
|
|
13129
|
+
if (parsed.port) {
|
|
13130
|
+
throw new Error("Plugin URL must not specify a port.");
|
|
13131
|
+
}
|
|
13132
|
+
if (parsed.search || parsed.hash) {
|
|
13133
|
+
throw new Error("Plugin URL must not carry a query string or fragment.");
|
|
13134
|
+
}
|
|
13135
|
+
const host = parsed.hostname.toLowerCase();
|
|
13136
|
+
if (!ALLOWED_PLUGIN_HOSTS.includes(host)) {
|
|
13137
|
+
throw new Error(
|
|
13138
|
+
`Plugin host not allowed: ${host}. Allowed hosts: ${ALLOWED_PLUGIN_HOSTS.join(", ")}.`
|
|
13139
|
+
);
|
|
13140
|
+
}
|
|
13141
|
+
if (!SAFE_REPO_PATH.test(parsed.pathname)) {
|
|
13142
|
+
throw new Error(`Not a plain repository path: ${parsed.pathname}`);
|
|
13143
|
+
}
|
|
13144
|
+
return parsed;
|
|
13145
|
+
}
|
|
13146
|
+
function classifyPluginSource(source) {
|
|
13147
|
+
const trimmed = source.trim();
|
|
13148
|
+
if (trimmed.startsWith("github:")) {
|
|
13149
|
+
const repo = trimmed.slice("github:".length).replace(/\.git$/, "");
|
|
13150
|
+
return { kind: "git", url: `https://github.com/${repo}.git` };
|
|
13151
|
+
}
|
|
13152
|
+
if (HAS_SCHEME.test(trimmed) || SCP_LIKE_REMOTE.test(trimmed)) {
|
|
13153
|
+
return { kind: "git", url: trimmed };
|
|
13154
|
+
}
|
|
13155
|
+
return { kind: "path", path: source };
|
|
13156
|
+
}
|
|
13157
|
+
|
|
12706
13158
|
// src/plugins/RunnerRegistry.ts
|
|
12707
13159
|
var BUILTIN_MANIFESTS = [
|
|
12708
13160
|
CLAUDE_CODE_MANIFEST,
|
|
12709
13161
|
CODEX_MANIFEST,
|
|
12710
13162
|
OPENCODE_MANIFEST
|
|
12711
13163
|
];
|
|
13164
|
+
var RESERVED_RUNNER_NAMES = new Set(BUILTIN_MANIFESTS.map((m) => m.name.toLowerCase()));
|
|
13165
|
+
function isReservedRunnerName(name) {
|
|
13166
|
+
return RESERVED_RUNNER_NAMES.has(name.toLowerCase());
|
|
13167
|
+
}
|
|
13168
|
+
function gitClone(url, destDir) {
|
|
13169
|
+
(0, import_child_process9.execFileSync)("git", ["clone", "--depth", "1", "--", url, destDir], {
|
|
13170
|
+
stdio: "pipe",
|
|
13171
|
+
timeout: 3e4,
|
|
13172
|
+
// A repository that demands credentials should fail, not hang on a prompt.
|
|
13173
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
13174
|
+
});
|
|
13175
|
+
}
|
|
12712
13176
|
var RunnerRegistry = class {
|
|
12713
13177
|
plugins = /* @__PURE__ */ new Map();
|
|
12714
13178
|
store;
|
|
12715
|
-
|
|
13179
|
+
clone;
|
|
13180
|
+
constructor(store, clone) {
|
|
12716
13181
|
this.store = store ?? new FsPluginStore();
|
|
13182
|
+
this.clone = clone ?? gitClone;
|
|
12717
13183
|
this.loadBuiltins();
|
|
12718
13184
|
}
|
|
12719
13185
|
loadBuiltins() {
|
|
@@ -12724,9 +13190,15 @@ var RunnerRegistry = class {
|
|
|
12724
13190
|
loadUserPlugins() {
|
|
12725
13191
|
const names = this.store.listUserPluginDirs();
|
|
12726
13192
|
for (const name of names) {
|
|
12727
|
-
|
|
13193
|
+
let pluginDir;
|
|
13194
|
+
try {
|
|
13195
|
+
pluginDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), name);
|
|
13196
|
+
} catch {
|
|
13197
|
+
continue;
|
|
13198
|
+
}
|
|
12728
13199
|
const manifest = this.store.loadManifest(pluginDir);
|
|
12729
|
-
if (!manifest) continue;
|
|
13200
|
+
if (!manifest || !isPlainPluginName(manifest.name)) continue;
|
|
13201
|
+
if (isReservedRunnerName(manifest.name)) continue;
|
|
12730
13202
|
this.plugins.set(manifest.name, {
|
|
12731
13203
|
manifest,
|
|
12732
13204
|
source: "user",
|
|
@@ -12755,7 +13227,7 @@ var RunnerRegistry = class {
|
|
|
12755
13227
|
return entry?.source === "builtin";
|
|
12756
13228
|
}
|
|
12757
13229
|
installFromPath(sourcePath) {
|
|
12758
|
-
const absPath =
|
|
13230
|
+
const absPath = path14.resolve(sourcePath);
|
|
12759
13231
|
if (!this.store.dirExists(absPath)) {
|
|
12760
13232
|
throw new Error(`Plugin source must be a directory: ${absPath}`);
|
|
12761
13233
|
}
|
|
@@ -12763,48 +13235,50 @@ var RunnerRegistry = class {
|
|
|
12763
13235
|
if (!manifest) {
|
|
12764
13236
|
throw new Error(`No valid manifest.json found in: ${absPath}`);
|
|
12765
13237
|
}
|
|
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;
|
|
13238
|
+
return this.registerInstalled(manifest, absPath);
|
|
12775
13239
|
}
|
|
12776
13240
|
installFromGit(url) {
|
|
12777
|
-
const
|
|
12778
|
-
const tmpDir =
|
|
13241
|
+
const validated = assertInstallablePluginUrl(url);
|
|
13242
|
+
const tmpDir = path14.join(os5.tmpdir(), `ordewell-plugin-${(0, import_crypto3.randomBytes)(12).toString("hex")}`);
|
|
12779
13243
|
this.store.ensureDir(tmpDir);
|
|
12780
13244
|
try {
|
|
12781
|
-
|
|
12782
|
-
|
|
12783
|
-
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
13245
|
+
try {
|
|
13246
|
+
this.clone(validated.toString(), tmpDir);
|
|
13247
|
+
} catch (err) {
|
|
13248
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13249
|
+
throw new Error(`Failed to clone repository: ${message}`);
|
|
13250
|
+
}
|
|
13251
|
+
const contents = this.store.listDir(tmpDir);
|
|
13252
|
+
const hasManifest = contents.some((f) => f === "manifest.json");
|
|
13253
|
+
let sourceDir = tmpDir;
|
|
13254
|
+
if (!hasManifest) {
|
|
13255
|
+
const onlyEntry = contents.length === 1 ? path14.join(tmpDir, contents[0]) : void 0;
|
|
13256
|
+
if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
|
|
13257
|
+
throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
|
|
13258
|
+
}
|
|
13259
|
+
sourceDir = onlyEntry;
|
|
13260
|
+
}
|
|
13261
|
+
const manifest = this.store.loadManifest(sourceDir);
|
|
13262
|
+
if (!manifest) {
|
|
13263
|
+
throw new Error("No valid manifest.json found in cloned repository");
|
|
13264
|
+
}
|
|
13265
|
+
return this.registerInstalled(manifest, sourceDir);
|
|
13266
|
+
} finally {
|
|
12793
13267
|
this.store.removeDir(tmpDir);
|
|
12794
|
-
throw new Error(`No manifest.json found in repository: ${url}`);
|
|
12795
13268
|
}
|
|
12796
|
-
return this.finishInstall(tmpDir, repoName, tmpDir);
|
|
12797
13269
|
}
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
13270
|
+
/**
|
|
13271
|
+
* The single destination-building step both install routes share: the name is
|
|
13272
|
+
* constrained to a plain segment and the resolved destination is asserted to
|
|
13273
|
+
* be inside the plugins directory before anything is copied.
|
|
13274
|
+
*/
|
|
13275
|
+
registerInstalled(manifest, sourceDir) {
|
|
13276
|
+
if (isReservedRunnerName(manifest.name)) {
|
|
13277
|
+
throw new Error(`Cannot install a plugin named after a built-in runner: ${manifest.name}`);
|
|
12803
13278
|
}
|
|
12804
|
-
const destDir =
|
|
13279
|
+
const destDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), manifest.name);
|
|
12805
13280
|
this.store.ensureDir(destDir);
|
|
12806
13281
|
this.store.copyDir(sourceDir, destDir);
|
|
12807
|
-
this.store.removeDir(tmpDir);
|
|
12808
13282
|
this.plugins.set(manifest.name, {
|
|
12809
13283
|
manifest,
|
|
12810
13284
|
source: "user",
|
|
@@ -12825,7 +13299,8 @@ var RunnerRegistry = class {
|
|
|
12825
13299
|
this.plugins.delete(name);
|
|
12826
13300
|
}
|
|
12827
13301
|
createSkeleton(name, outputDir) {
|
|
12828
|
-
|
|
13302
|
+
assertPlainPluginName(name);
|
|
13303
|
+
const dir = path14.resolve(outputDir, name);
|
|
12829
13304
|
this.store.ensureDir(dir);
|
|
12830
13305
|
const manifest = {
|
|
12831
13306
|
name,
|
|
@@ -12857,8 +13332,8 @@ var RunnerRegistry = class {
|
|
|
12857
13332
|
]
|
|
12858
13333
|
}
|
|
12859
13334
|
};
|
|
12860
|
-
this.store.writeFile(
|
|
12861
|
-
const runSh =
|
|
13335
|
+
this.store.writeFile(path14.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
13336
|
+
const runSh = path14.join(dir, "run.sh");
|
|
12862
13337
|
const scriptContent = `#!/usr/bin/env bash
|
|
12863
13338
|
# Custom runner script for ${name}
|
|
12864
13339
|
# Receives:
|
|
@@ -12882,13 +13357,6 @@ echo "Running ${name} with prompt: $prompt"
|
|
|
12882
13357
|
return dir;
|
|
12883
13358
|
}
|
|
12884
13359
|
};
|
|
12885
|
-
function fsReaddirSync(dir) {
|
|
12886
|
-
try {
|
|
12887
|
-
return fs7.readdirSync(dir);
|
|
12888
|
-
} catch {
|
|
12889
|
-
return [];
|
|
12890
|
-
}
|
|
12891
|
-
}
|
|
12892
13360
|
function fsChmodSync(fpath, mode) {
|
|
12893
13361
|
try {
|
|
12894
13362
|
fs7.chmodSync(fpath, mode);
|
|
@@ -12898,14 +13366,14 @@ function fsChmodSync(fpath, mode) {
|
|
|
12898
13366
|
|
|
12899
13367
|
// src/utils/stateStore.ts
|
|
12900
13368
|
var fs8 = __toESM(require("fs"));
|
|
12901
|
-
var
|
|
13369
|
+
var path15 = __toESM(require("path"));
|
|
12902
13370
|
var STATE_FILE = "state.json";
|
|
12903
13371
|
function getStatePath(baseDir) {
|
|
12904
|
-
return
|
|
13372
|
+
return path15.join(getStateDir(baseDir), STATE_FILE);
|
|
12905
13373
|
}
|
|
12906
13374
|
function saveState(plan, baseDir) {
|
|
12907
13375
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
12908
|
-
ensureDir(
|
|
13376
|
+
ensureDir(path15.dirname(statePath));
|
|
12909
13377
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
12910
13378
|
fs8.writeFileSync(statePath, JSON.stringify(plan, null, 2));
|
|
12911
13379
|
}
|
|
@@ -12938,7 +13406,7 @@ function stateExists(baseDir) {
|
|
|
12938
13406
|
|
|
12939
13407
|
// src/services/SettingsService.ts
|
|
12940
13408
|
var fs9 = __toESM(require("fs"));
|
|
12941
|
-
var
|
|
13409
|
+
var path16 = __toESM(require("path"));
|
|
12942
13410
|
var os6 = __toESM(require("os"));
|
|
12943
13411
|
var DEFAULTS = {
|
|
12944
13412
|
grillMe: { enabled: false },
|
|
@@ -12951,7 +13419,7 @@ var DEFAULTS = {
|
|
|
12951
13419
|
function getSettingsPath() {
|
|
12952
13420
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
12953
13421
|
if (override && override.trim()) return override.trim();
|
|
12954
|
-
return
|
|
13422
|
+
return path16.join(os6.homedir(), ".config", "ordewell", "settings.json");
|
|
12955
13423
|
}
|
|
12956
13424
|
function readPlannerModels(raw) {
|
|
12957
13425
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -13116,7 +13584,7 @@ var SettingsService = class {
|
|
|
13116
13584
|
return { ...DEFAULTS, grillMe: { ...DEFAULTS.grillMe }, tdd: { ...DEFAULTS.tdd }, prd: { ...DEFAULTS.prd }, review: { ...DEFAULTS.review }, verification: { ...DEFAULTS.verification }, researchSubagents: { ...DEFAULTS.researchSubagents } };
|
|
13117
13585
|
}
|
|
13118
13586
|
persist() {
|
|
13119
|
-
const dir =
|
|
13587
|
+
const dir = path16.dirname(this.filePath);
|
|
13120
13588
|
if (!fs9.existsSync(dir)) {
|
|
13121
13589
|
fs9.mkdirSync(dir, { recursive: true });
|
|
13122
13590
|
}
|
|
@@ -13161,6 +13629,7 @@ var PlannerModelMemory = class {
|
|
|
13161
13629
|
};
|
|
13162
13630
|
// Annotate the CommonJS export names for ESM import in node:
|
|
13163
13631
|
0 && (module.exports = {
|
|
13632
|
+
ALLOWED_PLUGIN_HOSTS,
|
|
13164
13633
|
ALL_PROVIDERS,
|
|
13165
13634
|
AUTO_COMMANDS,
|
|
13166
13635
|
AbstractRunner,
|
|
@@ -13179,6 +13648,8 @@ var PlannerModelMemory = class {
|
|
|
13179
13648
|
CommandLineTooLongError,
|
|
13180
13649
|
ConsoleLogger,
|
|
13181
13650
|
ContextCollector,
|
|
13651
|
+
DAEMON_SUBPROTOCOL,
|
|
13652
|
+
DAEMON_TOKEN_SUBPROTOCOL_PREFIX,
|
|
13182
13653
|
DENY_ALL,
|
|
13183
13654
|
EmbeddedNewlineError,
|
|
13184
13655
|
EnvConfig,
|
|
@@ -13195,9 +13666,12 @@ var PlannerModelMemory = class {
|
|
|
13195
13666
|
ModelResolver,
|
|
13196
13667
|
OPENCODE_MANIFEST,
|
|
13197
13668
|
ORCHESTRATOR_SHORTCUTS,
|
|
13669
|
+
ORDEWELL_SETTABLE_ENV,
|
|
13198
13670
|
OpenAiService,
|
|
13199
13671
|
OpenCodeAdapter,
|
|
13200
13672
|
PLAN_ENVELOPE_KEY,
|
|
13673
|
+
PLUGIN_NAME_PATTERN,
|
|
13674
|
+
PROVIDER_CREDENTIAL_ENV,
|
|
13201
13675
|
PROVIDER_DETECT_PRIORITY,
|
|
13202
13676
|
PROVIDER_LABEL,
|
|
13203
13677
|
PROVIDER_PRIORITY,
|
|
@@ -13212,6 +13686,8 @@ var PlannerModelMemory = class {
|
|
|
13212
13686
|
RunnerInstallation,
|
|
13213
13687
|
RunnerRegistry,
|
|
13214
13688
|
SEARCH_EXCLUSIONS,
|
|
13689
|
+
SETTINGS_ENV_ALLOWLIST,
|
|
13690
|
+
SETTINGS_ENV_REFUSED,
|
|
13215
13691
|
STATE_DIR,
|
|
13216
13692
|
STOPPED_TOOL_RESULT,
|
|
13217
13693
|
SYMBOL_LANGUAGES,
|
|
@@ -13224,13 +13700,19 @@ var PlannerModelMemory = class {
|
|
|
13224
13700
|
TmuxRunner,
|
|
13225
13701
|
VerdictEngine,
|
|
13226
13702
|
WINDOWS_MAX_COMMAND_LINE,
|
|
13703
|
+
WorkspaceNotAProjectError,
|
|
13227
13704
|
WorkspaceNotFoundError,
|
|
13228
13705
|
addTaskToPlan,
|
|
13706
|
+
admitSettingsEnv,
|
|
13229
13707
|
applyHeadLimit,
|
|
13230
13708
|
applyTaskOps,
|
|
13709
|
+
assertInstallablePluginUrl,
|
|
13710
|
+
assertPlainPluginName,
|
|
13231
13711
|
assertWorkspaceExists,
|
|
13712
|
+
assertWorkspaceIsProject,
|
|
13232
13713
|
augmentPromptWithPriorOutputs,
|
|
13233
13714
|
augmentedPath,
|
|
13715
|
+
bearerHeaderValue,
|
|
13234
13716
|
buildConversationSystemPrompt,
|
|
13235
13717
|
buildFallbackGrepArgs,
|
|
13236
13718
|
buildGlobArgs,
|
|
@@ -13258,7 +13740,9 @@ var PlannerModelMemory = class {
|
|
|
13258
13740
|
classifyCommand,
|
|
13259
13741
|
classifyOutcome,
|
|
13260
13742
|
classifyPlannerReply,
|
|
13743
|
+
classifyPluginSource,
|
|
13261
13744
|
clearAugmentedPathCache,
|
|
13745
|
+
clearDaemonToken,
|
|
13262
13746
|
clearResearchShellCache,
|
|
13263
13747
|
clearState,
|
|
13264
13748
|
clipboardCopyCommand,
|
|
@@ -13270,6 +13754,7 @@ var PlannerModelMemory = class {
|
|
|
13270
13754
|
createAiService,
|
|
13271
13755
|
createEmptyPlan,
|
|
13272
13756
|
createTask,
|
|
13757
|
+
daemonTokenPath,
|
|
13273
13758
|
defaultLogger,
|
|
13274
13759
|
definitionPattern,
|
|
13275
13760
|
deleteSession,
|
|
@@ -13287,6 +13772,7 @@ var PlannerModelMemory = class {
|
|
|
13287
13772
|
extractObjectWithBalance,
|
|
13288
13773
|
extractObjectsWithKey,
|
|
13289
13774
|
extractPrdBlock,
|
|
13775
|
+
extractPresentedToken,
|
|
13290
13776
|
fetchAllProviderModels,
|
|
13291
13777
|
filterFallbackByAnchoredInclude,
|
|
13292
13778
|
filterModelsForPrompt,
|
|
@@ -13304,6 +13790,9 @@ var PlannerModelMemory = class {
|
|
|
13304
13790
|
isCliProvider,
|
|
13305
13791
|
isExecutableResolved,
|
|
13306
13792
|
isOpenAiProvider,
|
|
13793
|
+
isPlainPluginName,
|
|
13794
|
+
isReservedRunnerName,
|
|
13795
|
+
isValidManifest,
|
|
13307
13796
|
killTree,
|
|
13308
13797
|
knownModelId,
|
|
13309
13798
|
languageForId,
|
|
@@ -13316,6 +13805,8 @@ var PlannerModelMemory = class {
|
|
|
13316
13805
|
migrateLegacyPlan,
|
|
13317
13806
|
migratePlanState,
|
|
13318
13807
|
migrateTask,
|
|
13808
|
+
mintDaemonToken,
|
|
13809
|
+
mintSessionId,
|
|
13319
13810
|
modelContextBlock,
|
|
13320
13811
|
modifyValidationFeedback,
|
|
13321
13812
|
normalizeAgentArgs,
|
|
@@ -13331,6 +13822,7 @@ var PlannerModelMemory = class {
|
|
|
13331
13822
|
providerForRunner,
|
|
13332
13823
|
reEmitPlanPrompt,
|
|
13333
13824
|
reEmitTaskOpsPrompt,
|
|
13825
|
+
readDaemonToken,
|
|
13334
13826
|
referencePattern,
|
|
13335
13827
|
removeTaskFromPlan,
|
|
13336
13828
|
renderPlanMap,
|
|
@@ -13342,6 +13834,7 @@ var PlannerModelMemory = class {
|
|
|
13342
13834
|
resolveArgs,
|
|
13343
13835
|
resolveDefaultMode,
|
|
13344
13836
|
resolveModelShortcut,
|
|
13837
|
+
resolvePluginInstallDir,
|
|
13345
13838
|
resolveProvider,
|
|
13346
13839
|
resolveProviderFromPrefix,
|
|
13347
13840
|
resolveResearchShell,
|
|
@@ -13372,6 +13865,8 @@ var PlannerModelMemory = class {
|
|
|
13372
13865
|
tmuxSocketName,
|
|
13373
13866
|
tmuxWindowName,
|
|
13374
13867
|
toOrchestratorOptions,
|
|
13868
|
+
tokenSubprotocols,
|
|
13869
|
+
tokensMatch,
|
|
13375
13870
|
truncatedPlanReEmitPrompt,
|
|
13376
13871
|
updateTaskInPlan,
|
|
13377
13872
|
validateModifiedPlan,
|