nolo-cli 0.1.32 → 0.1.34
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/README.md +4 -10
- package/agent-runtime/agentRecordConfig.ts +10 -0
- package/agent-runtime/hostAdapter.ts +10 -1
- package/agent-runtime/index.ts +9 -20
- package/agent-runtime/localLoop.ts +49 -2
- package/agent-runtime/localToolPolicy.ts +76 -34
- package/agent-runtime/localWorkspaceTools.ts +30 -333
- package/agent-runtime/openAiCompatibleProvider.ts +7 -3
- package/agent-runtime/openAiCompatibleProviderConfig.ts +15 -26
- package/agent-runtime/platformChatProvider.ts +47 -73
- package/agent-runtime/providerResolution.ts +244 -0
- package/agent-runtime/runtimeToolPolicy.ts +77 -29
- package/agent-runtime/shellCommandPolicy.ts +120 -0
- package/agentAliases.ts +14 -83
- package/agentCommandSupport.ts +3 -6
- package/agentInternalCommandEntries.ts +4 -13
- package/agentListCommands.ts +18 -27
- package/agentMachineCommands.ts +40 -336
- package/agentPullCommand.ts +30 -55
- package/agentRecordCommands.ts +84 -1
- package/agentRecordHelpers.ts +102 -186
- package/agentRunCommand.ts +438 -107
- package/agentRuntimeLocal.ts +2 -9
- package/ai/agent/cliExecutor.ts +19 -323
- package/ai/tools/toolNameAliases.ts +70 -0
- package/authCommands.ts +2 -36
- package/cli/agentAliases.ts +14 -83
- package/cli/agentCommandSupport.ts +3 -6
- package/cli/agentInternalCommandEntries.ts +4 -13
- package/cli/agentListCommands.ts +18 -27
- package/cli/agentMachineCommands.ts +40 -336
- package/cli/agentPullCommand.ts +30 -55
- package/cli/agentRecordCommands.ts +84 -1
- package/cli/agentRecordHelpers.ts +102 -186
- package/cli/agentRunCommand.ts +438 -107
- package/cli/agentRuntimeLocal.ts +2 -9
- package/cli/authCommands.ts +2 -36
- package/cli/cliCommandDispatch.ts +2 -2
- package/cli/cliEnvHelpers.ts +34 -107
- package/cli/client/agentRun.ts +854 -57
- package/cli/client/localRuntimeAdapter.ts +59 -159
- package/cli/client/streamingOutput.ts +3 -1
- package/cli/client/taskRunPrompt.ts +24 -7
- package/cli/commandRegistry.ts +4 -5
- package/cli/connectorRunArtifact.ts +10 -34
- package/cli/connectorWebSocketTarget.ts +6 -10
- package/cli/internalCommandEntries.ts +0 -8
- package/cli/localRuntimeDb.ts +2 -39
- package/cli/machineCommands.ts +189 -190
- package/cli/machineDaemonCommands.ts +165 -9
- package/cli/machineHeartbeatCommands.ts +2 -1
- package/cli/machineStatusCommands.ts +13 -5
- package/cli/machineWatchCommands.ts +1 -1
- package/cli/machineWsRunDispatch.ts +30 -44
- package/cli/machineWsSession.ts +0 -2
- package/cli/offlineMarxistsAgentCommand.ts +314 -0
- package/cli/runtimeDoctorCommands.ts +72 -15
- package/cli/scriptCommandEntries.ts +45 -5
- package/cli/tableCommands.ts +133 -33
- package/cli/taskRunCommand.ts +211 -16
- package/cli/tui/session.ts +372 -43
- package/cli/workflowInternalCommandEntries.ts +0 -20
- package/cliCommandDispatch.ts +2 -2
- package/cliEnvHelpers.ts +34 -107
- package/client/agentConfigResolver.test.ts +2 -0
- package/client/agentRun.test.ts +12 -208
- package/client/agentRun.ts +854 -57
- package/client/localProviderResolver.test.ts +26 -2
- package/client/localRuntimeAdapter.test.ts +296 -171
- package/client/localRuntimeAdapter.ts +59 -159
- package/client/localToolPolicy.test.ts +4 -28
- package/client/streamingOutput.ts +3 -1
- package/client/taskRunPrompt.ts +24 -7
- package/commandRegistry.ts +4 -5
- package/connectorRunArtifact.ts +10 -34
- package/connectorWebSocketTarget.ts +6 -10
- package/database/server/serverStoreFactory.ts +2 -8
- package/internalCommandEntries.ts +0 -8
- package/localRuntimeDb.ts +2 -39
- package/machineCommands.ts +189 -190
- package/machineDaemonCommands.ts +165 -9
- package/machineHeartbeatCommands.ts +2 -1
- package/machineStatusCommands.ts +13 -5
- package/machineWatchCommands.ts +1 -1
- package/machineWsRunDispatch.ts +30 -44
- package/machineWsSession.ts +0 -2
- package/offlineMarxistsAgentCommand.ts +314 -0
- package/package.json +52 -188
- package/runtimeDoctorCommands.ts +72 -15
- package/scriptCommandEntries.ts +45 -5
- package/tableCommands.ts +133 -33
- package/taskRunCommand.ts +211 -16
- package/tui/session.ts +372 -43
- package/workflowInternalCommandEntries.ts +0 -20
- package/agent-runtime/dialogStatus.ts +0 -139
- package/agent-runtime/hostRuntimeConfig.ts +0 -86
- package/agentCreateCustomCommands.ts +0 -278
- package/agentDialogsCommands.ts +0 -227
- package/agentDoctorCommands.ts +0 -203
- package/agentRunLocalWorkspace.ts +0 -182
- package/agentRunParsing.ts +0 -298
- package/agentSuperviseCommands.ts +0 -8
- package/agentUnpublishCommands.ts +0 -113
- package/ai/agent/agentRunDialogLineage.ts +0 -56
- package/ai/policy/types.ts +0 -64
- package/ai/skills/skillSummaryMarker.ts +0 -26
- package/app/types.ts +0 -358
- package/build.ts +0 -16
- package/buildPublish.ts +0 -138
- package/buildPublishArtifactAssembly.ts +0 -724
- package/buildPublishImportAnalysis.ts +0 -242
- package/chat/messages/fetchMessages.ts +0 -84
- package/chat/messages/types.ts +0 -185
- package/cli/agentCreateCustomCommands.ts +0 -278
- package/cli/agentDialogsCommands.ts +0 -227
- package/cli/agentDoctorCommands.ts +0 -203
- package/cli/agentRunLocalWorkspace.ts +0 -182
- package/cli/agentRunParsing.ts +0 -298
- package/cli/agentSuperviseCommands.ts +0 -8
- package/cli/agentUnpublishCommands.ts +0 -113
- package/cli/buildPublish.ts +0 -138
- package/cli/buildPublishArtifactAssembly.ts +0 -724
- package/cli/buildPublishImportAnalysis.ts +0 -242
- package/cli/cliIoTypes.ts +0 -3
- package/cli/cliRuntimeDoctorReport.ts +0 -193
- package/cli/client/agentRunInput.ts +0 -10
- package/cli/client/agentRunLocalExecution.ts +0 -124
- package/cli/client/agentRunLocalExecutor.ts +0 -179
- package/cli/client/agentRunRuntimeSelection.ts +0 -145
- package/cli/client/agentRunServerTransport.ts +0 -397
- package/cli/client/agentRunTaskRunRecorder.ts +0 -176
- package/cli/customCodingAgentFlow.ts +0 -208
- package/cli/customCodingAgentRecord.ts +0 -179
- package/cli/dialogDataAccess.ts +0 -186
- package/cli/dialogInternalCommandEntries.ts +0 -11
- package/cli/dialogReadCommands.ts +0 -180
- package/cli/dialogReadHelpers.ts +0 -226
- package/cli/dialogStatusCommands.ts +0 -123
- package/cli/docInternalCommandEntries.ts +0 -20
- package/cli/hybridReadHelpers.ts +0 -109
- package/cli/machineCommandPrompts.ts +0 -79
- package/cli/machineCommandResolution.ts +0 -43
- package/cli/noloReadBridgePrompt.ts +0 -16
- package/cli/pageCreateCommands.ts +0 -219
- package/cli/pageDeleteCommands.ts +0 -167
- package/cli/pageReadCommands.ts +0 -151
- package/cli/pageUpdateCommands.ts +0 -249
- package/cli/pageWriteHelpers.ts +0 -209
- package/cli/publishPackage.ts +0 -36
- package/cli/runtimeInternalCommandEntries.ts +0 -15
- package/cli/runtimePassthroughCommands.ts +0 -22
- package/cli/scriptPassthroughHelpers.ts +0 -28
- package/cli/secretScanHelpers.ts +0 -31
- package/cli/spaceAttachCommands.ts +0 -134
- package/cli/spaceCategoryCommands.ts +0 -263
- package/cli/spaceCommands.ts +0 -295
- package/cli/spaceDeleteCommands.ts +0 -312
- package/cli/spaceInternalCommandEntries.ts +0 -21
- package/cli/spaceMutationHelpers.ts +0 -135
- package/cli/spaceReadCommands.ts +0 -323
- package/cli/tableDataOutput.ts +0 -41
- package/cli/tableDataSafety.ts +0 -26
- package/cli/tableMetaCommands.ts +0 -307
- package/cli/tableMutationCommands.ts +0 -266
- package/cli/tableQueryParsing.ts +0 -90
- package/cli/tableQueryRequest.ts +0 -53
- package/cli/taskRunActions.ts +0 -122
- package/cli/taskRunParsing.ts +0 -86
- package/cli/taskRunPromptShared.ts +0 -55
- package/cli/tui/tuiCatalog.ts +0 -22
- package/cli/tui/tuiCommandInterpreter.ts +0 -253
- package/cli/tui/tuiPresentation.ts +0 -146
- package/cliIoTypes.ts +0 -3
- package/cliRuntimeDoctorReport.ts +0 -193
- package/client/agentRunInput.ts +0 -10
- package/client/agentRunLocalExecution.test.ts +0 -123
- package/client/agentRunLocalExecution.ts +0 -124
- package/client/agentRunLocalExecutor.ts +0 -179
- package/client/agentRunRuntimeSelection.test.ts +0 -159
- package/client/agentRunRuntimeSelection.ts +0 -145
- package/client/agentRunServerTransport.ts +0 -397
- package/client/agentRunTaskRunRecorder.ts +0 -176
- package/connector-experimental/daemonLauncher.ts +0 -223
- package/create/space/spaceKeys.ts +0 -65
- package/create/types.ts +0 -21
- package/customCodingAgentFlow.ts +0 -208
- package/customCodingAgentRecord.ts +0 -179
- package/database/keys.ts +0 -765
- package/database/tombstones.ts +0 -52
- package/database/utils/ulid.ts +0 -1
- package/dialogDataAccess.ts +0 -186
- package/dialogInternalCommandEntries.ts +0 -11
- package/dialogReadCommands.ts +0 -180
- package/dialogReadHelpers.ts +0 -226
- package/dialogStatusCommands.ts +0 -123
- package/docInternalCommandEntries.ts +0 -20
- package/hybridReadHelpers.ts +0 -109
- package/machineCommandPrompts.ts +0 -79
- package/machineCommandResolution.ts +0 -43
- package/noloReadBridgePrompt.ts +0 -16
- package/pageCreateCommands.ts +0 -219
- package/pageDeleteCommands.ts +0 -167
- package/pageReadCommands.ts +0 -151
- package/pageUpdateCommands.ts +0 -249
- package/pageWriteHelpers.ts +0 -209
- package/publishPackage.ts +0 -36
- package/runtimeInternalCommandEntries.ts +0 -15
- package/runtimePassthroughCommands.ts +0 -22
- package/scriptPassthroughHelpers.ts +0 -28
- package/secretScanHelpers.ts +0 -31
- package/share/helpers.ts +0 -302
- package/share/keys.ts +0 -243
- package/share/types.ts +0 -100
- package/spaceAttachCommands.ts +0 -134
- package/spaceCategoryCommands.ts +0 -263
- package/spaceCommands.ts +0 -295
- package/spaceDeleteCommands.ts +0 -312
- package/spaceInternalCommandEntries.ts +0 -21
- package/spaceMutationHelpers.ts +0 -135
- package/spaceReadCommands.ts +0 -323
- package/tableDataOutput.ts +0 -41
- package/tableDataSafety.ts +0 -26
- package/tableMetaCommands.ts +0 -307
- package/tableMutationCommands.ts +0 -266
- package/tableQueryParsing.ts +0 -90
- package/tableQueryRequest.ts +0 -53
- package/taskRunActions.ts +0 -122
- package/taskRunParsing.ts +0 -86
- package/taskRunPromptShared.ts +0 -55
- package/tui/tuiCatalog.ts +0 -22
- package/tui/tuiCommandInterpreter.test.ts +0 -169
- package/tui/tuiCommandInterpreter.ts +0 -253
- package/tui/tuiPresentation.test.ts +0 -154
- package/tui/tuiPresentation.ts +0 -146
package/ai/agent/cliExecutor.ts
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { exec, execSync, spawn } from "child_process";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { randomUUID } from "node:crypto";
|
|
18
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
import { tmpdir } from "node:os";
|
|
21
21
|
import { resolveLaunchableCodexCommand } from "../../connector-experimental/codexBinary";
|
|
@@ -50,25 +50,6 @@ export interface CliExecuteResult {
|
|
|
50
50
|
warnings?: string[];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
type AgyDebugArtifact = {
|
|
54
|
-
dir: string;
|
|
55
|
-
promptHash: string;
|
|
56
|
-
promptBytes: number;
|
|
57
|
-
writeResult: (args: {
|
|
58
|
-
startedAt: string;
|
|
59
|
-
finishedAt: string;
|
|
60
|
-
elapsedMs: number;
|
|
61
|
-
cwd: string;
|
|
62
|
-
timeoutMs: number;
|
|
63
|
-
args: string[];
|
|
64
|
-
stdout: string;
|
|
65
|
-
stderr: string;
|
|
66
|
-
exitCode: number | null;
|
|
67
|
-
outcome: "succeeded" | "timed_out" | "spawn_error" | "failed";
|
|
68
|
-
errorMessage?: string;
|
|
69
|
-
}) => void;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
53
|
type CliSessionMessage = {
|
|
73
54
|
role: "user" | "assistant";
|
|
74
55
|
content: string;
|
|
@@ -190,18 +171,15 @@ function supportsNativeSystemPrompt(provider: CliProvider): boolean {
|
|
|
190
171
|
}
|
|
191
172
|
|
|
192
173
|
function supportsModel(provider: CliProvider): boolean {
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
return provider !== "agy";
|
|
174
|
+
// Codex accepts --model syntactically, but real desktop/subscription installs
|
|
175
|
+
// can fail with plan-gating errors. Keep model routing out of Codex CLI.
|
|
176
|
+
return provider !== "agy" && provider !== "codex";
|
|
196
177
|
}
|
|
197
178
|
|
|
198
179
|
function supportsReasoningEffort(provider: CliProvider): boolean {
|
|
199
180
|
return provider === "claude" || provider === "copilot";
|
|
200
181
|
}
|
|
201
182
|
|
|
202
|
-
function shouldPassCodexModel(options: CliExecuteOptions): boolean {
|
|
203
|
-
return (options.env?.NOLO_CODEX_CLI_ALLOW_MODEL ?? process.env.NOLO_CODEX_CLI_ALLOW_MODEL) === "1";
|
|
204
|
-
}
|
|
205
183
|
function shouldPassClaudeModel(options: CliExecuteOptions): boolean {
|
|
206
184
|
return (options.env?.NOLO_CLAUDE_CLI_ALLOW_MODEL ?? process.env.NOLO_CLAUDE_CLI_ALLOW_MODEL) === "1";
|
|
207
185
|
}
|
|
@@ -217,11 +195,7 @@ function collectCliCapabilityWarnings(
|
|
|
217
195
|
warnings.push(`${label} does not support reasoning_effort; ignored.`);
|
|
218
196
|
}
|
|
219
197
|
|
|
220
|
-
if (provider === "
|
|
221
|
-
warnings.push(
|
|
222
|
-
"Codex CLI model selection is disabled by default because real Codex installs can reject --model with subscription/plan errors; set NOLO_CODEX_CLI_ALLOW_MODEL=1 to pass it through."
|
|
223
|
-
);
|
|
224
|
-
} else if (provider === "claude" && options.model !== undefined && !shouldPassClaudeModel(options)) {
|
|
198
|
+
if (provider === "claude" && options.model !== undefined && !shouldPassClaudeModel(options)) {
|
|
225
199
|
warnings.push(
|
|
226
200
|
"Claude CLI model selection is disabled by default because current installs can reject --model; set NOLO_CLAUDE_CLI_ALLOW_MODEL=1 to pass it through."
|
|
227
201
|
);
|
|
@@ -254,121 +228,16 @@ function resolveCliExecution(
|
|
|
254
228
|
options: CliExecuteOptions
|
|
255
229
|
): { prompt: string; options: CliExecuteOptions; warnings: string[] } {
|
|
256
230
|
const warnings = collectCliCapabilityWarnings(provider, options);
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
? prompt
|
|
260
|
-
: buildCliPrompt(options.systemPrompt, prompt);
|
|
261
|
-
const resolvedOptions =
|
|
262
|
-
supportsNativeSystemPrompt(provider) || !options.systemPrompt?.trim()
|
|
263
|
-
? options
|
|
264
|
-
: {
|
|
265
|
-
...options,
|
|
266
|
-
systemPrompt: undefined,
|
|
267
|
-
};
|
|
268
|
-
const agyPrompt = provider === "agy" ? compactAgyPrompt(resolvedPrompt) : null;
|
|
269
|
-
return {
|
|
270
|
-
prompt: agyPrompt?.prompt ?? resolvedPrompt,
|
|
271
|
-
options: resolvedOptions,
|
|
272
|
-
warnings: [...warnings, ...(agyPrompt?.warnings ?? [])],
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const AGY_PRESERVED_PROMPT_BLOCK_HEADERS = [
|
|
277
|
-
"--- Nolo read-only CLI bridge ---",
|
|
278
|
-
"--- Nolo task-run tool bridge ---",
|
|
279
|
-
] as const;
|
|
280
|
-
const AGY_OPTIONAL_TASKRUN_GUIDANCE_HEADERS = [
|
|
281
|
-
"## TaskRun tool guidance (2026-05-17)",
|
|
282
|
-
"## TaskRun tool strictness (2026-05-17)",
|
|
283
|
-
"## TaskRun delegation boundary (2026-05-17)",
|
|
284
|
-
] as const;
|
|
285
|
-
|
|
286
|
-
function escapeRegExp(value: string) {
|
|
287
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function extractPromptBlock(source: string, header: string) {
|
|
291
|
-
const pattern = new RegExp(
|
|
292
|
-
`(?:^|\\n)(${escapeRegExp(header)}\\n[\\s\\S]*?)(?=\\n{2,}--- [^\\n]+ ---|\\n{2,}User task:|\\n{2,}--- User task ---|$)`,
|
|
293
|
-
);
|
|
294
|
-
const match = source.match(pattern);
|
|
295
|
-
if (!match) return null;
|
|
296
|
-
return {
|
|
297
|
-
block: match[1].trim(),
|
|
298
|
-
remaining: source.replace(pattern, "\n\n"),
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function stripMarkdownSection(source: string, header: string) {
|
|
303
|
-
const pattern = new RegExp(
|
|
304
|
-
`(?:^|\\n)${escapeRegExp(header)}\\n[\\s\\S]*?(?=\\n{2,}## [^\\n]+|\\n{2,}--- [^\\n]+ ---|\\n{2,}User task:|\\n{2,}--- User task ---|$)`,
|
|
305
|
-
);
|
|
306
|
-
return source.replace(pattern, "\n\n");
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function compactAgyPrompt(prompt: string): { prompt: string; warnings: string[] } {
|
|
310
|
-
let next = prompt;
|
|
311
|
-
let changed = false;
|
|
312
|
-
const preservedBlocks: string[] = [];
|
|
313
|
-
|
|
314
|
-
const stripBlock = (pattern: RegExp) => {
|
|
315
|
-
const updated = next.replace(pattern, "\n\n");
|
|
316
|
-
if (updated !== next) {
|
|
317
|
-
next = updated;
|
|
318
|
-
changed = true;
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
for (const header of AGY_PRESERVED_PROMPT_BLOCK_HEADERS) {
|
|
323
|
-
const extracted = extractPromptBlock(next, header);
|
|
324
|
-
if (!extracted) continue;
|
|
325
|
-
next = extracted.remaining;
|
|
326
|
-
preservedBlocks.push(extracted.block);
|
|
327
|
-
changed = true;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Antigravity intermittently stalls on long runtime metadata tails. The
|
|
331
|
-
// connector already enforces permissions and owns dialog context, so trim
|
|
332
|
-
// these blocks before handing the prompt to agy.
|
|
333
|
-
stripBlock(/(?:^|\n)Conversation Reference:\n[\s\S]*?(?=\n{2,}--- Machine permission policy ---|\n{2,}--- User task ---|\n{2,}User task:|$)/);
|
|
334
|
-
stripBlock(/(?:^|\n)--- Machine permission policy ---\n[\s\S]*?(?=\n{2,}--- User task ---|\n{2,}User task:|$)/);
|
|
335
|
-
if (!preservedBlocks.some((block) => block.startsWith("--- Nolo task-run tool bridge ---"))) {
|
|
336
|
-
for (const header of AGY_OPTIONAL_TASKRUN_GUIDANCE_HEADERS) {
|
|
337
|
-
const updated = stripMarkdownSection(next, header);
|
|
338
|
-
if (updated !== next) {
|
|
339
|
-
next = updated;
|
|
340
|
-
changed = true;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
231
|
+
if (supportsNativeSystemPrompt(provider) || !options.systemPrompt?.trim()) {
|
|
232
|
+
return { prompt, options, warnings };
|
|
343
233
|
}
|
|
344
|
-
|
|
345
|
-
let normalized = next
|
|
346
|
-
.replace(/\n\n--- User task ---\n/g, "\n\nUser task:\n")
|
|
347
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
348
|
-
.trim();
|
|
349
|
-
if (preservedBlocks.length > 0) {
|
|
350
|
-
const reinjected = preservedBlocks.join("\n\n");
|
|
351
|
-
if (/^User task:\n/.test(normalized)) {
|
|
352
|
-
normalized = `${reinjected}\n\n${normalized}`;
|
|
353
|
-
} else if (/\n\nUser task:\n/.test(normalized)) {
|
|
354
|
-
normalized = normalized.replace(/\n\nUser task:\n/, `\n\n${reinjected}\n\nUser task:\n`);
|
|
355
|
-
} else {
|
|
356
|
-
normalized = `${normalized}\n\n${reinjected}`.trim();
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
if (normalized !== prompt) {
|
|
360
|
-
changed = true;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (!changed) {
|
|
364
|
-
return { prompt, warnings: [] };
|
|
365
|
-
}
|
|
366
|
-
|
|
367
234
|
return {
|
|
368
|
-
prompt:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
235
|
+
prompt: buildCliPrompt(options.systemPrompt, prompt),
|
|
236
|
+
options: {
|
|
237
|
+
...options,
|
|
238
|
+
systemPrompt: undefined,
|
|
239
|
+
},
|
|
240
|
+
warnings,
|
|
372
241
|
};
|
|
373
242
|
}
|
|
374
243
|
|
|
@@ -536,7 +405,6 @@ function executeCodex(
|
|
|
536
405
|
options: CliExecuteOptions
|
|
537
406
|
): Promise<CliExecuteResult> {
|
|
538
407
|
const {
|
|
539
|
-
model,
|
|
540
408
|
timeout = 120_000,
|
|
541
409
|
cwd = process.cwd(),
|
|
542
410
|
yolo = true,
|
|
@@ -557,12 +425,6 @@ function executeCodex(
|
|
|
557
425
|
"--cd",
|
|
558
426
|
cwd,
|
|
559
427
|
];
|
|
560
|
-
// Codex CLI accepts --model syntactically, but real desktop/subscription
|
|
561
|
-
// installs can fail with plan-gating errors. Keep default execution stable.
|
|
562
|
-
if (model && shouldPassCodexModel(options)) {
|
|
563
|
-
args.push("--model");
|
|
564
|
-
args.push(model);
|
|
565
|
-
}
|
|
566
428
|
if (yolo) {
|
|
567
429
|
args.push("--sandbox");
|
|
568
430
|
args.push("danger-full-access");
|
|
@@ -707,82 +569,9 @@ function formatCliTimeout(timeoutMs: number) {
|
|
|
707
569
|
return `${Math.max(1, Math.ceil(timeoutMs / 1000))}s`;
|
|
708
570
|
}
|
|
709
571
|
|
|
710
|
-
function
|
|
711
|
-
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
function resolveAgyDebugDir(env?: Record<string, string | undefined>) {
|
|
715
|
-
const raw = env?.NOLO_AGY_DEBUG_DIR ?? process.env.NOLO_AGY_DEBUG_DIR ?? "";
|
|
716
|
-
return raw.trim();
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
function createAgyDebugArtifact(args: {
|
|
720
|
-
prompt: string;
|
|
721
|
-
attempt: number;
|
|
722
|
-
timeoutMs: number;
|
|
723
|
-
cwd: string;
|
|
724
|
-
env?: Record<string, string | undefined>;
|
|
725
|
-
}): AgyDebugArtifact | null {
|
|
726
|
-
const debugRoot = resolveAgyDebugDir(args.env);
|
|
727
|
-
if (!debugRoot) return null;
|
|
728
|
-
|
|
729
|
-
const promptHash = shortHash(args.prompt);
|
|
730
|
-
const promptBytes = Buffer.byteLength(args.prompt, "utf8");
|
|
731
|
-
const dir = join(debugRoot, `${Date.now()}-agy-${promptHash}-attempt-${args.attempt + 1}`);
|
|
732
|
-
mkdirSync(dir, { recursive: true });
|
|
733
|
-
writeFileSync(join(dir, "prompt.txt"), args.prompt, "utf8");
|
|
734
|
-
|
|
735
|
-
return {
|
|
736
|
-
dir,
|
|
737
|
-
promptHash,
|
|
738
|
-
promptBytes,
|
|
739
|
-
writeResult: (result) => {
|
|
740
|
-
writeFileSync(join(dir, "stdout.txt"), result.stdout, "utf8");
|
|
741
|
-
writeFileSync(join(dir, "stderr.txt"), result.stderr, "utf8");
|
|
742
|
-
writeFileSync(
|
|
743
|
-
join(dir, "meta.json"),
|
|
744
|
-
`${JSON.stringify({
|
|
745
|
-
promptHash,
|
|
746
|
-
promptBytes,
|
|
747
|
-
attempt: args.attempt + 1,
|
|
748
|
-
startedAt: result.startedAt,
|
|
749
|
-
finishedAt: result.finishedAt,
|
|
750
|
-
elapsedMs: result.elapsedMs,
|
|
751
|
-
cwd: result.cwd,
|
|
752
|
-
timeoutMs: result.timeoutMs,
|
|
753
|
-
args: result.args,
|
|
754
|
-
exitCode: result.exitCode,
|
|
755
|
-
outcome: result.outcome,
|
|
756
|
-
errorMessage: result.errorMessage ?? null,
|
|
757
|
-
stdoutBytes: Buffer.byteLength(result.stdout, "utf8"),
|
|
758
|
-
stderrBytes: Buffer.byteLength(result.stderr, "utf8"),
|
|
759
|
-
}, null, 2)}\n`,
|
|
760
|
-
"utf8"
|
|
761
|
-
);
|
|
762
|
-
},
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
function isAgyTimeoutError(error: unknown) {
|
|
767
|
-
return error instanceof Error && /Antigravity CLI timed out after \d+ms/.test(error.message);
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
function resolveAgyTimeoutRetryCount(env?: Record<string, string | undefined>) {
|
|
771
|
-
const raw = env?.NOLO_AGY_TIMEOUT_RETRIES ?? process.env.NOLO_AGY_TIMEOUT_RETRIES ?? "2";
|
|
772
|
-
const parsed = Number.parseInt(raw, 10);
|
|
773
|
-
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 2;
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
const AGY_PROCESS_TIMEOUT_BUFFER_MS = 10_000;
|
|
777
|
-
|
|
778
|
-
function isAgyUpstreamTimeoutText(stdout: string) {
|
|
779
|
-
return /^Error:\s+timed out waiting for response\b/i.test(stdout.trim());
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
function executeAgyOnce(
|
|
572
|
+
function executeAgy(
|
|
783
573
|
prompt: string,
|
|
784
|
-
options: CliExecuteOptions
|
|
785
|
-
attempt = 0
|
|
574
|
+
options: CliExecuteOptions
|
|
786
575
|
): Promise<CliExecuteResult> {
|
|
787
576
|
const {
|
|
788
577
|
timeout = 120_000,
|
|
@@ -804,14 +593,6 @@ function executeAgyOnce(
|
|
|
804
593
|
}
|
|
805
594
|
|
|
806
595
|
const start = Date.now();
|
|
807
|
-
const startedAt = new Date(start).toISOString();
|
|
808
|
-
const debugArtifact = createAgyDebugArtifact({
|
|
809
|
-
prompt,
|
|
810
|
-
attempt,
|
|
811
|
-
timeoutMs: timeout,
|
|
812
|
-
cwd,
|
|
813
|
-
env: options.env,
|
|
814
|
-
});
|
|
815
596
|
const proc = spawn("agy", args, {
|
|
816
597
|
cwd,
|
|
817
598
|
env: buildCliProcessEnv(options.env),
|
|
@@ -820,40 +601,12 @@ function executeAgyOnce(
|
|
|
820
601
|
let stdout = "";
|
|
821
602
|
let stderr = "";
|
|
822
603
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
823
|
-
let timedOut = false;
|
|
824
|
-
|
|
825
|
-
const flushDebug = (result: {
|
|
826
|
-
exitCode: number | null;
|
|
827
|
-
outcome: "succeeded" | "timed_out" | "spawn_error" | "failed";
|
|
828
|
-
errorMessage?: string;
|
|
829
|
-
}) => {
|
|
830
|
-
debugArtifact?.writeResult({
|
|
831
|
-
startedAt,
|
|
832
|
-
finishedAt: new Date().toISOString(),
|
|
833
|
-
elapsedMs: Date.now() - start,
|
|
834
|
-
cwd,
|
|
835
|
-
timeoutMs: timeout,
|
|
836
|
-
args,
|
|
837
|
-
stdout,
|
|
838
|
-
stderr,
|
|
839
|
-
exitCode: result.exitCode,
|
|
840
|
-
outcome: result.outcome,
|
|
841
|
-
...(result.errorMessage ? { errorMessage: result.errorMessage } : {}),
|
|
842
|
-
});
|
|
843
|
-
};
|
|
844
604
|
|
|
845
605
|
if (timeout > 0) {
|
|
846
606
|
timer = setTimeout(() => {
|
|
847
|
-
timedOut = true;
|
|
848
607
|
proc.kill("SIGTERM");
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
exitCode: null,
|
|
852
|
-
outcome: "timed_out",
|
|
853
|
-
errorMessage: error.message,
|
|
854
|
-
});
|
|
855
|
-
reject(error);
|
|
856
|
-
}, timeout + AGY_PROCESS_TIMEOUT_BUFFER_MS);
|
|
608
|
+
reject(new Error(`Antigravity CLI timed out after ${timeout}ms`));
|
|
609
|
+
}, timeout + 1_000);
|
|
857
610
|
}
|
|
858
611
|
|
|
859
612
|
proc.stdout.on("data", (data: Buffer) => {
|
|
@@ -866,32 +619,11 @@ function executeAgyOnce(
|
|
|
866
619
|
|
|
867
620
|
proc.on("close", (code) => {
|
|
868
621
|
if (timer) clearTimeout(timer);
|
|
869
|
-
if (timedOut) return;
|
|
870
622
|
if (code !== 0 && code !== null) {
|
|
871
|
-
|
|
872
|
-
flushDebug({
|
|
873
|
-
exitCode: code,
|
|
874
|
-
outcome: "failed",
|
|
875
|
-
errorMessage: error.message,
|
|
876
|
-
});
|
|
877
|
-
reject(error);
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
880
|
-
if (isAgyUpstreamTimeoutText(stdout)) {
|
|
881
|
-
const error = new Error(`Antigravity CLI timed out after ${timeout}ms`);
|
|
882
|
-
flushDebug({
|
|
883
|
-
exitCode: code,
|
|
884
|
-
outcome: "timed_out",
|
|
885
|
-
errorMessage: error.message,
|
|
886
|
-
});
|
|
887
|
-
reject(error);
|
|
623
|
+
reject(new Error(`Antigravity CLI exited with code ${code}\nstderr: ${stderr}`));
|
|
888
624
|
return;
|
|
889
625
|
}
|
|
890
626
|
|
|
891
|
-
flushDebug({
|
|
892
|
-
exitCode: code,
|
|
893
|
-
outcome: "succeeded",
|
|
894
|
-
});
|
|
895
627
|
resolve({
|
|
896
628
|
text: stdout.trim(),
|
|
897
629
|
raw: stdout,
|
|
@@ -901,47 +633,11 @@ function executeAgyOnce(
|
|
|
901
633
|
|
|
902
634
|
proc.on("error", (err) => {
|
|
903
635
|
if (timer) clearTimeout(timer);
|
|
904
|
-
flushDebug({
|
|
905
|
-
exitCode: null,
|
|
906
|
-
outcome: "spawn_error",
|
|
907
|
-
errorMessage: err instanceof Error ? err.message : String(err),
|
|
908
|
-
});
|
|
909
636
|
reject(err);
|
|
910
637
|
});
|
|
911
638
|
});
|
|
912
639
|
}
|
|
913
640
|
|
|
914
|
-
async function executeAgy(
|
|
915
|
-
prompt: string,
|
|
916
|
-
options: CliExecuteOptions
|
|
917
|
-
): Promise<CliExecuteResult> {
|
|
918
|
-
const maxRetries = resolveAgyTimeoutRetryCount(options.env);
|
|
919
|
-
let attempt = 0;
|
|
920
|
-
let lastError: unknown;
|
|
921
|
-
|
|
922
|
-
while (attempt <= maxRetries) {
|
|
923
|
-
try {
|
|
924
|
-
const result = await executeAgyOnce(prompt, options, attempt);
|
|
925
|
-
if (attempt === 0) return result;
|
|
926
|
-
return {
|
|
927
|
-
...result,
|
|
928
|
-
warnings: [
|
|
929
|
-
...(result.warnings ?? []),
|
|
930
|
-
`Antigravity CLI succeeded after ${attempt} timeout retr${attempt === 1 ? "y" : "ies"}.`,
|
|
931
|
-
],
|
|
932
|
-
};
|
|
933
|
-
} catch (error) {
|
|
934
|
-
lastError = error;
|
|
935
|
-
if (!isAgyTimeoutError(error) || attempt >= maxRetries) {
|
|
936
|
-
throw error;
|
|
937
|
-
}
|
|
938
|
-
attempt += 1;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
943
|
-
}
|
|
944
|
-
|
|
945
641
|
// ── 注册表(新增 CLI 工具时在这里加) ────────────────────────────────────────
|
|
946
642
|
|
|
947
643
|
const EXECUTORS: Record<
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const LEGACY_TOOL_NAME_ALIASES: Record<string, string> = {
|
|
2
|
+
createPage: "createDoc",
|
|
3
|
+
updatePage: "updateDoc",
|
|
4
|
+
update_page: "updateDoc",
|
|
5
|
+
create_page: "createDoc",
|
|
6
|
+
fetchwebpage: "fetchWebpage",
|
|
7
|
+
fetch_webpage: "fetchWebpage",
|
|
8
|
+
"fetch-page": "fetchWebpage",
|
|
9
|
+
exasearch: "exa_search",
|
|
10
|
+
"exa-search": "exa_search",
|
|
11
|
+
exa_search: "exa_search",
|
|
12
|
+
readDoc: "readDoc",
|
|
13
|
+
readpage: "readDoc",
|
|
14
|
+
read_page: "readDoc",
|
|
15
|
+
read_doc: "readDoc",
|
|
16
|
+
createdoc: "createDoc",
|
|
17
|
+
updateDocTool: "updateDoc",
|
|
18
|
+
readLocal: "readLocalFile",
|
|
19
|
+
read_local: "readLocalFile",
|
|
20
|
+
readLocalTool: "readLocalFile",
|
|
21
|
+
listLocal: "listLocalFiles",
|
|
22
|
+
list_local: "listLocalFiles",
|
|
23
|
+
terminalCommand: "execShell",
|
|
24
|
+
terminal_command: "execShell",
|
|
25
|
+
runCommand: "execShell",
|
|
26
|
+
run_command: "execShell",
|
|
27
|
+
runInBash: "execShell",
|
|
28
|
+
run_in_bash: "execShell",
|
|
29
|
+
executeCommand: "execShell",
|
|
30
|
+
execute_command: "execShell",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const normalizeToolName = (name: string): string =>
|
|
34
|
+
name.replace(/[-_]/g, "").toLowerCase();
|
|
35
|
+
|
|
36
|
+
export const canonicalizeToolName = (rawName: string): string => {
|
|
37
|
+
const trimmedName = rawName.trim();
|
|
38
|
+
if (!trimmedName) return rawName;
|
|
39
|
+
|
|
40
|
+
if (LEGACY_TOOL_NAME_ALIASES[trimmedName]) {
|
|
41
|
+
return LEGACY_TOOL_NAME_ALIASES[trimmedName];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const normalizedRawName = normalizeToolName(trimmedName);
|
|
45
|
+
const matchedAlias = Object.entries(LEGACY_TOOL_NAME_ALIASES).find(
|
|
46
|
+
([alias]) => normalizeToolName(alias) === normalizedRawName,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return matchedAlias?.[1] ?? trimmedName;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const canonicalizeToolNames = (toolNames: string[]): string[] =>
|
|
53
|
+
Array.from(
|
|
54
|
+
new Set(
|
|
55
|
+
toolNames
|
|
56
|
+
.filter((toolName): toolName is string => typeof toolName === "string")
|
|
57
|
+
.map(canonicalizeToolName),
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export const prioritizeToolNames = (
|
|
62
|
+
toolNames: string[],
|
|
63
|
+
preferredToolNames: string[],
|
|
64
|
+
): string[] => {
|
|
65
|
+
const canonicalTools = canonicalizeToolNames(toolNames);
|
|
66
|
+
const preferred = new Set(canonicalizeToolNames(preferredToolNames));
|
|
67
|
+
const prioritized = canonicalTools.filter((toolName) => preferred.has(toolName));
|
|
68
|
+
const remaining = canonicalTools.filter((toolName) => !preferred.has(toolName));
|
|
69
|
+
return [...prioritized, ...remaining];
|
|
70
|
+
};
|
package/authCommands.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
loadProfileConfig,
|
|
10
10
|
saveDefaultProfile,
|
|
11
11
|
} from "./client/profileConfig";
|
|
12
|
-
import { parseUserIdFromAuthToken } from "./cliEnvHelpers";
|
|
13
12
|
import { DEFAULT_NOLO_SERVER_URL } from "./defaultServer";
|
|
14
13
|
|
|
15
14
|
function getArg(args: string[], flag: string) {
|
|
@@ -68,47 +67,17 @@ async function saveTokenLogin(args: {
|
|
|
68
67
|
configPath: string;
|
|
69
68
|
serverUrl: string;
|
|
70
69
|
authToken: string;
|
|
71
|
-
fetchImpl: typeof fetch;
|
|
72
70
|
output: Pick<Console, "log">;
|
|
73
71
|
error: Pick<Console, "error">;
|
|
74
72
|
}) {
|
|
75
|
-
|
|
76
|
-
if (!authToken) {
|
|
73
|
+
if (!args.authToken.trim()) {
|
|
77
74
|
args.error.error("No auth token provided.");
|
|
78
75
|
return 1;
|
|
79
76
|
}
|
|
80
77
|
|
|
81
|
-
const userId = parseUserIdFromAuthToken(authToken);
|
|
82
|
-
if (!userId) {
|
|
83
|
-
args.error.error("Auth token payload is missing userId.");
|
|
84
|
-
return 1;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const res = await args.fetchImpl(
|
|
89
|
-
`${args.serverUrl}/api/v1/db/query/${encodeURIComponent(userId)}?limit=1`,
|
|
90
|
-
{
|
|
91
|
-
method: "POST",
|
|
92
|
-
headers: {
|
|
93
|
-
Authorization: `Bearer ${authToken}`,
|
|
94
|
-
"Content-Type": "application/json",
|
|
95
|
-
},
|
|
96
|
-
body: JSON.stringify({ type: "agent" }),
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
if (res.status === 401 || res.status === 403) {
|
|
100
|
-
args.error.error(
|
|
101
|
-
`Auth token is not valid for ${args.serverUrl}. Log in against the matching server or use a token issued by that server.`
|
|
102
|
-
);
|
|
103
|
-
return 1;
|
|
104
|
-
}
|
|
105
|
-
} catch {
|
|
106
|
-
// Allow saving when the server is temporarily unreachable.
|
|
107
|
-
}
|
|
108
|
-
|
|
109
78
|
saveDefaultProfile(args.configPath, {
|
|
110
79
|
serverUrl: args.serverUrl,
|
|
111
|
-
authToken,
|
|
80
|
+
authToken: args.authToken.trim(),
|
|
112
81
|
});
|
|
113
82
|
args.output.log(`Saved profile default -> ${args.serverUrl}`);
|
|
114
83
|
return 0;
|
|
@@ -175,7 +144,6 @@ async function runWebLogin(args: {
|
|
|
175
144
|
configPath: args.configPath,
|
|
176
145
|
serverUrl: approvedServer,
|
|
177
146
|
authToken: poll.token,
|
|
178
|
-
fetchImpl: args.fetchImpl,
|
|
179
147
|
output: args.output,
|
|
180
148
|
error: args.error,
|
|
181
149
|
});
|
|
@@ -205,7 +173,6 @@ export async function runLoginCommand(args: string[], deps: LoginCommandDeps = {
|
|
|
205
173
|
configPath,
|
|
206
174
|
serverUrl,
|
|
207
175
|
authToken: tokenArg,
|
|
208
|
-
fetchImpl: deps.fetchImpl ?? fetch,
|
|
209
176
|
output: outputTarget,
|
|
210
177
|
error: errorTarget,
|
|
211
178
|
});
|
|
@@ -220,7 +187,6 @@ export async function runLoginCommand(args: string[], deps: LoginCommandDeps = {
|
|
|
220
187
|
configPath,
|
|
221
188
|
serverUrl,
|
|
222
189
|
authToken,
|
|
223
|
-
fetchImpl: deps.fetchImpl ?? fetch,
|
|
224
190
|
output: outputTarget,
|
|
225
191
|
error: errorTarget,
|
|
226
192
|
});
|