toolcraft 0.0.136 → 0.0.138
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/composition.json +7 -2
- package/dist/cli.js +55 -34
- package/dist/composition.json +7 -2
- package/dist/human-in-loop/approvals-commands.js +18 -28
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/renderer.js +4 -1
- package/dist/user-error.d.ts +8 -0
- package/dist/user-error.js +10 -0
- package/node_modules/@poe-code/agent-defs/README.md +14 -1
- package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/codex.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/cursor.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/goose.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/kimi.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/opencode.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/pi.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/capabilities.d.ts +14 -0
- package/node_modules/@poe-code/agent-defs/dist/capabilities.js +63 -0
- package/node_modules/@poe-code/agent-defs/dist/index.d.ts +2 -1
- package/node_modules/@poe-code/agent-defs/dist/index.js +1 -0
- package/node_modules/@poe-code/agent-defs/dist/registry.js +3 -0
- package/node_modules/@poe-code/agent-defs/dist/types.d.ts +7 -0
- package/node_modules/@poe-code/frontmatter/README.md +3 -0
- package/node_modules/@poe-code/frontmatter/dist/index.d.ts +1 -1
- package/node_modules/@poe-code/frontmatter/dist/index.js +1 -1
- package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +9 -0
- package/node_modules/@poe-code/frontmatter/dist/parse.js +16 -0
- package/node_modules/@poe-code/process-runner/dist/docker/docker-execution-env.js +20 -8
- package/node_modules/@poe-code/process-runner/dist/host/host-execution-env.js +1 -0
- package/node_modules/@poe-code/process-runner/dist/types.d.ts +2 -0
- package/node_modules/@poe-code/task-list/dist/backends/gh-issues-client.js +4 -0
- package/node_modules/@poe-code/user-error/README.md +56 -0
- package/node_modules/@poe-code/user-error/dist/index.d.ts +17 -0
- package/node_modules/@poe-code/user-error/dist/index.js +21 -0
- package/node_modules/@poe-code/user-error/package.json +24 -0
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-design/dist/acp/components.d.ts +8 -1
- package/node_modules/toolcraft-design/dist/acp/components.js +11 -6
- package/node_modules/toolcraft-design/dist/acp/index.d.ts +1 -0
- package/node_modules/toolcraft-design/dist/components/command-errors.d.ts +2 -0
- package/node_modules/toolcraft-design/dist/components/command-errors.js +8 -2
- package/node_modules/toolcraft-design/dist/components/index.d.ts +1 -1
- package/node_modules/toolcraft-design/dist/components/index.js +1 -1
- package/node_modules/toolcraft-design/dist/components/table.d.ts +1 -0
- package/node_modules/toolcraft-design/dist/components/table.js +52 -5
- package/node_modules/toolcraft-design/dist/components/template.d.ts +9 -0
- package/node_modules/toolcraft-design/dist/components/template.js +27 -2
- package/node_modules/toolcraft-design/dist/index.d.ts +2 -2
- package/node_modules/toolcraft-design/dist/index.js +2 -2
- package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +5 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +15 -1
- package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +1 -1
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +6 -4
package/composition.json
CHANGED
|
@@ -36,6 +36,11 @@
|
|
|
36
36
|
"version": "0.0.1",
|
|
37
37
|
"license": "MIT"
|
|
38
38
|
},
|
|
39
|
+
{
|
|
40
|
+
"name": "@poe-code/user-error",
|
|
41
|
+
"version": "0.0.1",
|
|
42
|
+
"license": "MIT"
|
|
43
|
+
},
|
|
39
44
|
{
|
|
40
45
|
"name": "auth-store",
|
|
41
46
|
"version": "0.0.1",
|
|
@@ -108,7 +113,7 @@
|
|
|
108
113
|
},
|
|
109
114
|
{
|
|
110
115
|
"name": "toolcraft",
|
|
111
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.138",
|
|
112
117
|
"license": "MIT"
|
|
113
118
|
},
|
|
114
119
|
{
|
|
@@ -118,7 +123,7 @@
|
|
|
118
123
|
},
|
|
119
124
|
{
|
|
120
125
|
"name": "toolcraft-schema",
|
|
121
|
-
"version": "0.0.
|
|
126
|
+
"version": "0.0.138",
|
|
122
127
|
"license": "MIT"
|
|
123
128
|
},
|
|
124
129
|
{
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { Command as CommanderCommand, CommanderError, InvalidArgumentError, Option } from "commander";
|
|
5
5
|
import { validate as validateSchema } from "toolcraft-schema";
|
|
6
6
|
import { cancel, configureTheme, confirm, createLogger, formatCommandList, formatOptionList, getTheme, helpFormatterPlain, isCancel, note, promptText, renderHelpTokens, renderTable, resetOutputFormatCache, select, text } from "toolcraft-design";
|
|
7
|
-
import { ApprovalDeclinedError, ToolcraftBugError, UserError, assertCommandRequirements, getCommandSourcePath, hasMcpProxyConfig, resolveCommandSecrets } from "./index.js";
|
|
7
|
+
import { ApprovalDeclinedError, ToolcraftBugError, UserError, assertCommandRequirements, getCommandSourcePath, hasMcpProxyConfig, isUserError, resolveCommandSecrets } from "./index.js";
|
|
8
8
|
import { hasOwnErrorCode } from "./error-codes.js";
|
|
9
9
|
import { writeErrorReport } from "./error-report.js";
|
|
10
10
|
import { assertHumanInLoopWired, mergeApprovalsRoot } from "./human-in-loop/wiring.js";
|
|
@@ -396,6 +396,13 @@ function formatOptionFlags(field, globalLongOptionFlags) {
|
|
|
396
396
|
}
|
|
397
397
|
return [`-${field.shortFlag}`, field.optionFlag, ...field.longAliases].join(", ");
|
|
398
398
|
}
|
|
399
|
+
function formatMissingParameterMessage(field) {
|
|
400
|
+
const message = `Missing required parameter "${field.displayPath}".`;
|
|
401
|
+
if (field.schema.kind !== "enum") {
|
|
402
|
+
return message;
|
|
403
|
+
}
|
|
404
|
+
return `${message} Expected one of: ${field.schema.values.map((value) => String(value)).join(", ")}.`;
|
|
405
|
+
}
|
|
399
406
|
function formatPositionalToken(field) {
|
|
400
407
|
const optionalPositional = field.optional || field.hasDefault;
|
|
401
408
|
if (field.variadicPosition === true) {
|
|
@@ -1132,6 +1139,8 @@ function formatExampleRows(examples, breadcrumb, rootUsageName) {
|
|
|
1132
1139
|
return examples.map((example) => `${example.title}\n ${formatExampleCommand(breadcrumb, rootUsageName, example.params)}`);
|
|
1133
1140
|
}
|
|
1134
1141
|
const MAX_INLINE_OPTIONAL_PARAMETER_TOKENS = 8;
|
|
1142
|
+
/** Mirrors the fallback width used by the design system's column layout. */
|
|
1143
|
+
const DEFAULT_HELP_TOTAL_WIDTH = 100;
|
|
1135
1144
|
function tokenizeHelpFlags(flags) {
|
|
1136
1145
|
const tokens = [];
|
|
1137
1146
|
let index = 0;
|
|
@@ -1208,9 +1217,13 @@ function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
|
|
|
1208
1217
|
.map((field) => createCommandParameterToken(formatCommandParameterFieldFlags(field, globalLongOptionFlags), field.positionalIndex === undefined && (field.optional || field.hasDefault)))
|
|
1209
1218
|
.concat(collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing)));
|
|
1210
1219
|
}
|
|
1211
|
-
function collapseOptionalParameterTokens(parameterTokens) {
|
|
1220
|
+
function collapseOptionalParameterTokens(parameterTokens, inlineWidthBudget = Number.POSITIVE_INFINITY) {
|
|
1212
1221
|
const optionalCount = parameterTokens.filter((token) => token.optional).length;
|
|
1213
|
-
if (optionalCount
|
|
1222
|
+
if (optionalCount === 0) {
|
|
1223
|
+
return parameterTokens;
|
|
1224
|
+
}
|
|
1225
|
+
const inlineWidth = parameterTokens.reduce((total, token) => total + token.text.length + 1, 0);
|
|
1226
|
+
if (optionalCount <= MAX_INLINE_OPTIONAL_PARAMETER_TOKENS && inlineWidth <= inlineWidthBudget) {
|
|
1214
1227
|
return parameterTokens;
|
|
1215
1228
|
}
|
|
1216
1229
|
const required = parameterTokens.filter((token) => !token.optional);
|
|
@@ -1231,8 +1244,11 @@ function collapseOptionalParameterTokens(parameterTokens) {
|
|
|
1231
1244
|
function formatCommandRowNameTokens(node, casing, globalLongOptionFlags) {
|
|
1232
1245
|
const baseName = node.aliases.length === 0 ? node.name : `${node.name} (${node.aliases.join(", ")})`;
|
|
1233
1246
|
const nameTokens = [{ text: baseName, role: "command" }];
|
|
1247
|
+
// formatCommandList indents rows by two columns, so anything wider than the rest of the
|
|
1248
|
+
// terminal wraps onto continuation lines and makes the command list unreadable.
|
|
1249
|
+
const inlineWidthBudget = Math.max(0, (process.stdout.columns ?? DEFAULT_HELP_TOTAL_WIDTH) - 2 - baseName.length);
|
|
1234
1250
|
const parameterTokens = node.kind === "command"
|
|
1235
|
-
? collapseOptionalParameterTokens(formatCommandParameterTokens(node, casing, globalLongOptionFlags))
|
|
1251
|
+
? collapseOptionalParameterTokens(formatCommandParameterTokens(node, casing, globalLongOptionFlags), inlineWidthBudget)
|
|
1236
1252
|
: [];
|
|
1237
1253
|
for (const token of parameterTokens) {
|
|
1238
1254
|
nameTokens.push({ text: " ", role: "literal" }, ...token.tokens);
|
|
@@ -1285,10 +1301,10 @@ function formatGlobalOptionsLine(ctx) {
|
|
|
1285
1301
|
if (ctx.showVersion) {
|
|
1286
1302
|
flags.push("--version");
|
|
1287
1303
|
}
|
|
1288
|
-
return flags.length > 0 ? `${text.section("Options:")} ${flags.join(" ")}` : "";
|
|
1304
|
+
return flags.length > 0 ? `${text.section("Global Options:")} ${flags.join(" ")}` : "";
|
|
1289
1305
|
}
|
|
1290
1306
|
function formatLeafGlobalOptionsLine(ctx) {
|
|
1291
|
-
return ctx.controls.verbose ? `${text.section("Options:")} -v, --verbose` : "";
|
|
1307
|
+
return ctx.controls.verbose ? `${text.section("Global Options:")} -v, --verbose` : "";
|
|
1292
1308
|
}
|
|
1293
1309
|
function collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlags) {
|
|
1294
1310
|
const seen = new Map();
|
|
@@ -1331,21 +1347,16 @@ function formatHelpOptionList(rows) {
|
|
|
1331
1347
|
: formatOptionList(rows);
|
|
1332
1348
|
}
|
|
1333
1349
|
function sortLeafHelpOptionFields(fields) {
|
|
1334
|
-
const positionals = [];
|
|
1335
1350
|
const required = [];
|
|
1336
1351
|
const optional = [];
|
|
1337
1352
|
for (const field of fields) {
|
|
1338
|
-
if (field.positionalIndex !== undefined) {
|
|
1339
|
-
positionals.push(field);
|
|
1340
|
-
continue;
|
|
1341
|
-
}
|
|
1342
1353
|
if (!field.optional && !field.hasDefault) {
|
|
1343
1354
|
required.push(field);
|
|
1344
1355
|
continue;
|
|
1345
1356
|
}
|
|
1346
1357
|
optional.push(field);
|
|
1347
1358
|
}
|
|
1348
|
-
return [...
|
|
1359
|
+
return [...required, ...optional];
|
|
1349
1360
|
}
|
|
1350
1361
|
function buildUsageLine(breadcrumb, rootUsageName, suffix) {
|
|
1351
1362
|
const visibleBreadcrumb = breadcrumb.filter((segment) => segment.length > 0);
|
|
@@ -1388,13 +1399,13 @@ function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUs
|
|
|
1388
1399
|
const globalLongOptionFlags = getGlobalLongOptionFlags(globalOptions.presetsEnabled, globalOptions.showVersion, globalOptions.controls);
|
|
1389
1400
|
const commandRows = formatCommandRows(group, scope, casing, globalLongOptionFlags, globalOptions.controls.help);
|
|
1390
1401
|
if (commandRows.length > 0) {
|
|
1391
|
-
sections.push(`${text.
|
|
1402
|
+
sections.push(`${text.section("Commands:")}\n${formatHelpCommandList(commandRows)}`);
|
|
1392
1403
|
}
|
|
1393
1404
|
if (isRoot) {
|
|
1394
1405
|
const schemaGlobalRows = collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlags);
|
|
1395
1406
|
const builtInLine = formatGlobalOptionsLine(globalOptions);
|
|
1396
1407
|
if (schemaGlobalRows.length > 0) {
|
|
1397
|
-
sections.push(`${text.
|
|
1408
|
+
sections.push(`${text.section("Options:")}\n${formatHelpOptionList(schemaGlobalRows)}\n${builtInLine}`);
|
|
1398
1409
|
}
|
|
1399
1410
|
else {
|
|
1400
1411
|
sections.push(builtInLine);
|
|
@@ -1417,11 +1428,19 @@ function renderLeafHelp(command, breadcrumb, casing, globalOptions, rootUsageNam
|
|
|
1417
1428
|
const globalLongOptionFlags = getGlobalLongOptionFlags(globalOptions.presetsEnabled, globalOptions.showVersion, globalOptions.controls);
|
|
1418
1429
|
const collected = collectFields(command.params, casing, globalLongOptionFlags);
|
|
1419
1430
|
const fields = assignPositionals(collected.fields, command.positional);
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1431
|
+
const localFields = fields.filter((field) => field.global !== true);
|
|
1432
|
+
const toHelpRow = (field) => createHelpOptionRow(formatHelpFieldFlags(field, globalLongOptionFlags), formatHelpFieldDescription(field));
|
|
1433
|
+
const argumentRows = localFields
|
|
1434
|
+
.filter((field) => field.positionalIndex !== undefined)
|
|
1435
|
+
.map(toHelpRow);
|
|
1436
|
+
const optionRows = sortLeafHelpOptionFields(localFields.filter((field) => field.positionalIndex === undefined))
|
|
1437
|
+
.map(toHelpRow)
|
|
1422
1438
|
.concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
|
|
1439
|
+
if (argumentRows.length > 0) {
|
|
1440
|
+
sections.push(`${text.section("Arguments:")}\n${formatHelpOptionList(argumentRows)}`);
|
|
1441
|
+
}
|
|
1423
1442
|
if (optionRows.length > 0) {
|
|
1424
|
-
sections.push(`${text.
|
|
1443
|
+
sections.push(`${text.section("Options:")}\n${formatHelpOptionList(optionRows)}`);
|
|
1425
1444
|
}
|
|
1426
1445
|
const builtInLine = formatLeafGlobalOptionsLine(globalOptions);
|
|
1427
1446
|
if (builtInLine.length > 0) {
|
|
@@ -1429,10 +1448,10 @@ function renderLeafHelp(command, breadcrumb, casing, globalOptions, rootUsageNam
|
|
|
1429
1448
|
}
|
|
1430
1449
|
const secretRows = formatSecretRows(command.secrets);
|
|
1431
1450
|
if (secretRows.length > 0) {
|
|
1432
|
-
sections.push(`${text.
|
|
1451
|
+
sections.push(`${text.section("Secrets (environment):")}\n${formatHelpOptionList(secretRows)}`);
|
|
1433
1452
|
}
|
|
1434
1453
|
if (command.examples.length > 0) {
|
|
1435
|
-
sections.push(`${text.
|
|
1454
|
+
sections.push(`${text.section("Examples:")}\n${formatExampleRows(command.examples, breadcrumb, rootUsageName).join("\n")}`);
|
|
1436
1455
|
}
|
|
1437
1456
|
const positionalFields = fields.filter((f) => f.positionalIndex !== undefined);
|
|
1438
1457
|
const usageSuffix = positionalFields.length > 0
|
|
@@ -1599,7 +1618,12 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
|
|
|
1599
1618
|
}
|
|
1600
1619
|
for (const field of fields) {
|
|
1601
1620
|
if (field.positionalIndex !== undefined) {
|
|
1602
|
-
|
|
1621
|
+
// Positionals are declared optional so resolveParams stays the single owner of argument
|
|
1622
|
+
// validation: Commander would otherwise report a missing positional in its own words
|
|
1623
|
+
// before prompts, defaults, and presets have had a chance to supply the value.
|
|
1624
|
+
command.argument(field.variadicPosition === true
|
|
1625
|
+
? `[${field.displayPath}...]`
|
|
1626
|
+
: `[${field.displayPath}]`);
|
|
1603
1627
|
continue;
|
|
1604
1628
|
}
|
|
1605
1629
|
for (const option of createOption(field, globalLongOptionFlags)) {
|
|
@@ -2540,10 +2564,10 @@ function isHumanInLoopPending(result) {
|
|
|
2540
2564
|
typeof result.message === "string" &&
|
|
2541
2565
|
typeof result.enqueuedAt === "string");
|
|
2542
2566
|
}
|
|
2543
|
-
function renderHumanInLoopPending(pending) {
|
|
2567
|
+
function renderHumanInLoopPending(pending, rootUsageName) {
|
|
2544
2568
|
process.stdout.write(`✓ Queued for human approval (id: ${pending.approvalId})\n` +
|
|
2545
2569
|
` Message: ${pending.message}\n` +
|
|
2546
|
-
` Track:
|
|
2570
|
+
` Track: ${rootUsageName} approvals show --approval-id ${pending.approvalId}\n`);
|
|
2547
2571
|
}
|
|
2548
2572
|
function renderApprovalDeclined(error) {
|
|
2549
2573
|
const logger = createLogger();
|
|
@@ -2638,7 +2662,7 @@ function parseOptionFieldValue(field, value, errors) {
|
|
|
2638
2662
|
return { ok: true, value: parsedValue };
|
|
2639
2663
|
}
|
|
2640
2664
|
catch (error) {
|
|
2641
|
-
if (error
|
|
2665
|
+
if (isUserError(error) || error instanceof InvalidArgumentError) {
|
|
2642
2666
|
errors.push({
|
|
2643
2667
|
path: field.displayPath,
|
|
2644
2668
|
message: error.message
|
|
@@ -3150,7 +3174,7 @@ async function resolveParams(fields, dynamicFields, variants, positionalValues,
|
|
|
3150
3174
|
}
|
|
3151
3175
|
errors.push({
|
|
3152
3176
|
path: field.displayPath,
|
|
3153
|
-
message:
|
|
3177
|
+
message: formatMissingParameterMessage(field)
|
|
3154
3178
|
});
|
|
3155
3179
|
continue;
|
|
3156
3180
|
}
|
|
@@ -3193,7 +3217,7 @@ function getResolvedFlags(command) {
|
|
|
3193
3217
|
const flags = command.optsWithGlobals();
|
|
3194
3218
|
return flags;
|
|
3195
3219
|
}
|
|
3196
|
-
async function executeCommand(state, services, requirementOptions, runtimeFetch, humanInLoop, runtimeEnv, runtimeFs, outputEmitter, outputFormats, promptStreams, diagnosticsOptions, onErrorReportContext) {
|
|
3220
|
+
async function executeCommand(state, rootUsageName, services, requirementOptions, runtimeFetch, humanInLoop, runtimeEnv, runtimeFs, outputEmitter, outputFormats, promptStreams, diagnosticsOptions, onErrorReportContext) {
|
|
3197
3221
|
const logger = createLogger(outputEmitter);
|
|
3198
3222
|
const optionValues = state.actionCommand.optsWithGlobals();
|
|
3199
3223
|
const resolvedFlags = optionValues;
|
|
@@ -3334,7 +3358,7 @@ async function executeCommand(state, services, requirementOptions, runtimeFetch,
|
|
|
3334
3358
|
writeRichHeader(`${state.command.name} (fixture)`);
|
|
3335
3359
|
}
|
|
3336
3360
|
if (isHumanInLoopPending(result)) {
|
|
3337
|
-
renderHumanInLoopPending(result);
|
|
3361
|
+
renderHumanInLoopPending(result, rootUsageName);
|
|
3338
3362
|
return;
|
|
3339
3363
|
}
|
|
3340
3364
|
const renderStatus = renderCLIResult(state.command, state.commandPath, result, output, primitives, outputFormats, outputEmitter === undefined
|
|
@@ -3571,7 +3595,7 @@ function renderHttpError(error, options) {
|
|
|
3571
3595
|
async function handleRunError(error, options) {
|
|
3572
3596
|
const logger = createLogger(options.outputEmitter);
|
|
3573
3597
|
await withOutputFormat(options.output, async () => {
|
|
3574
|
-
if (error
|
|
3598
|
+
if (isUserError(error)) {
|
|
3575
3599
|
renderCliErrorPattern(options.userErrorPattern === "definition"
|
|
3576
3600
|
? {
|
|
3577
3601
|
kind: "definition",
|
|
@@ -3870,12 +3894,9 @@ function getDefaultCommanderCommandName(command) {
|
|
|
3870
3894
|
function configureCommanderSuggestionOutput(command) {
|
|
3871
3895
|
command.exitOverride();
|
|
3872
3896
|
command.configureOutput({
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
}
|
|
3877
|
-
write(message);
|
|
3878
|
-
}
|
|
3897
|
+
// Every Commander error throws through exitOverride and is rendered once by handleRunError
|
|
3898
|
+
// in the design-system error pattern; writing it here as well double-reports one mistake.
|
|
3899
|
+
outputError: () => { }
|
|
3879
3900
|
});
|
|
3880
3901
|
command.commands.forEach((child) => configureCommanderSuggestionOutput(child));
|
|
3881
3902
|
}
|
|
@@ -3941,7 +3962,7 @@ export async function runCLI(roots, options = {}) {
|
|
|
3941
3962
|
const execute = async (state) => {
|
|
3942
3963
|
lastActionCommand = state.actionCommand;
|
|
3943
3964
|
resolvedCommandPath = formatCliCommandPath(state.commandPath);
|
|
3944
|
-
await executeCommand(state, servicesWithBuiltIns, requirementOptions, runtimeFetch, humanInLoop, options.env, options.fs, options.outputEmitter, controls.outputFormats, {
|
|
3965
|
+
await executeCommand(state, rootUsageName, servicesWithBuiltIns, requirementOptions, runtimeFetch, humanInLoop, options.env, options.fs, options.outputEmitter, controls.outputFormats, {
|
|
3945
3966
|
input: options.promptInput,
|
|
3946
3967
|
output: options.promptOutput
|
|
3947
3968
|
}, {
|
package/dist/composition.json
CHANGED
|
@@ -36,6 +36,11 @@
|
|
|
36
36
|
"version": "0.0.1",
|
|
37
37
|
"license": "MIT"
|
|
38
38
|
},
|
|
39
|
+
{
|
|
40
|
+
"name": "@poe-code/user-error",
|
|
41
|
+
"version": "0.0.1",
|
|
42
|
+
"license": "MIT"
|
|
43
|
+
},
|
|
39
44
|
{
|
|
40
45
|
"name": "auth-store",
|
|
41
46
|
"version": "0.0.1",
|
|
@@ -108,7 +113,7 @@
|
|
|
108
113
|
},
|
|
109
114
|
{
|
|
110
115
|
"name": "toolcraft",
|
|
111
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.138",
|
|
112
117
|
"license": "MIT"
|
|
113
118
|
},
|
|
114
119
|
{
|
|
@@ -118,7 +123,7 @@
|
|
|
118
123
|
},
|
|
119
124
|
{
|
|
120
125
|
"name": "toolcraft-schema",
|
|
121
|
-
"version": "0.0.
|
|
126
|
+
"version": "0.0.138",
|
|
122
127
|
"license": "MIT"
|
|
123
128
|
},
|
|
124
129
|
{
|
|
@@ -3,12 +3,14 @@ import { S } from "toolcraft-schema";
|
|
|
3
3
|
import { hasOwnErrorCode } from "../error-codes.js";
|
|
4
4
|
import { UserError, defineCommand, defineGroup } from "../index.js";
|
|
5
5
|
import { ensureApprovalList } from "./approval-tasks.js";
|
|
6
|
+
import { approvalStateMachine } from "./state-machine.js";
|
|
6
7
|
import { runApproval } from "./runner.js";
|
|
7
8
|
const approvalsGroupSymbol = Symbol("toolcraft.humanInLoop.approvalsBuiltIn");
|
|
8
9
|
const listScope = ["cli", "mcp", "sdk"];
|
|
9
10
|
const runScope = ["cli"];
|
|
11
|
+
const approvalStateValues = approvalStateMachine.states;
|
|
10
12
|
const listParams = S.Object({
|
|
11
|
-
state: S.Optional(S.
|
|
13
|
+
state: S.Optional(S.Array(S.Enum(approvalStateValues)))
|
|
12
14
|
});
|
|
13
15
|
const showParams = S.Object({
|
|
14
16
|
approvalId: S.String()
|
|
@@ -51,18 +53,12 @@ export const approvalsGroup = markApprovalsBuiltIn(defineGroup({
|
|
|
51
53
|
scope: listScope,
|
|
52
54
|
params: showParams,
|
|
53
55
|
handler: async ({ params, humanInLoop }) => {
|
|
54
|
-
|
|
56
|
+
return withMissingApprovalError(params.approvalId, async () => {
|
|
55
57
|
const { tasks } = await ensureApprovalList(humanInLoop.runtimeOptions, {
|
|
56
58
|
create: false
|
|
57
59
|
});
|
|
58
60
|
return tasks.get(params.approvalId);
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
if (isMissingStateError(error)) {
|
|
62
|
-
throw new TaskNotFoundError(`Task "approvals/${params.approvalId}" not found.`);
|
|
63
|
-
}
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
61
|
+
});
|
|
66
62
|
},
|
|
67
63
|
render: {
|
|
68
64
|
rich: (result, primitives) => renderApprovalDetails(result, primitives),
|
|
@@ -76,7 +72,7 @@ export const approvalsGroup = markApprovalsBuiltIn(defineGroup({
|
|
|
76
72
|
scope: runScope,
|
|
77
73
|
params: runParams,
|
|
78
74
|
handler: async ({ params, humanInLoop, root }) => {
|
|
79
|
-
return runApproval(params.approvalId, humanInLoop.runtimeOptions, root);
|
|
75
|
+
return withMissingApprovalError(params.approvalId, async () => runApproval(params.approvalId, humanInLoop.runtimeOptions, root));
|
|
80
76
|
},
|
|
81
77
|
render: {
|
|
82
78
|
rich: (result, primitives) => {
|
|
@@ -115,8 +111,7 @@ function isApprovalsBuiltIn(node) {
|
|
|
115
111
|
return (node.kind === "group" &&
|
|
116
112
|
node[approvalsGroupSymbol] === true);
|
|
117
113
|
}
|
|
118
|
-
async function loadApprovals(tasks,
|
|
119
|
-
const states = splitStateFilter(stateFilter);
|
|
114
|
+
async function loadApprovals(tasks, states = []) {
|
|
120
115
|
if (states.length === 0) {
|
|
121
116
|
return tasks.all();
|
|
122
117
|
}
|
|
@@ -136,22 +131,6 @@ async function loadApprovals(tasks, stateFilter) {
|
|
|
136
131
|
}
|
|
137
132
|
return approvals;
|
|
138
133
|
}
|
|
139
|
-
function splitStateFilter(stateFilter) {
|
|
140
|
-
if (stateFilter === undefined) {
|
|
141
|
-
return [];
|
|
142
|
-
}
|
|
143
|
-
const seen = new Set();
|
|
144
|
-
const states = [];
|
|
145
|
-
for (const value of stateFilter.split(",")) {
|
|
146
|
-
const trimmed = value.trim();
|
|
147
|
-
if (trimmed.length === 0 || seen.has(trimmed)) {
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
seen.add(trimmed);
|
|
151
|
-
states.push(trimmed);
|
|
152
|
-
}
|
|
153
|
-
return states;
|
|
154
|
-
}
|
|
155
134
|
function renderApprovalList(result, { logger, renderTable, getTheme }) {
|
|
156
135
|
if (result.length === 0) {
|
|
157
136
|
logger.message("No approvals found.");
|
|
@@ -227,6 +206,17 @@ function stringifyValue(value) {
|
|
|
227
206
|
function escapeMarkdownCell(value) {
|
|
228
207
|
return value.replaceAll("|", "\\|");
|
|
229
208
|
}
|
|
209
|
+
async function withMissingApprovalError(approvalId, run) {
|
|
210
|
+
try {
|
|
211
|
+
return await run();
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
if (error instanceof TaskNotFoundError || isMissingStateError(error)) {
|
|
215
|
+
throw new UserError(`Approval "${approvalId}" not found. Run approvals list to see queued approvals.`);
|
|
216
|
+
}
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
230
220
|
function isMissingStateError(error) {
|
|
231
221
|
return hasOwnErrorCode(error, "ENOENT");
|
|
232
222
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { AnySchema, ObjectSchema, Static } from "toolcraft-schema";
|
|
|
3
3
|
import type { LoggerOutput, RenderTableOptions, ThemePalette } from "toolcraft-design";
|
|
4
4
|
import { ApprovalDeclinedError } from "./human-in-loop/types.js";
|
|
5
5
|
import type { HumanInLoopConfig, HumanInLoopPending, HumanInLoopRuntime } from "./human-in-loop/types.js";
|
|
6
|
-
import { ToolcraftBugError, UserError } from "./user-error.js";
|
|
6
|
+
import { ToolcraftBugError, UserError, isUserError } from "./user-error.js";
|
|
7
7
|
import type { RuntimeLogger } from "./runtime-logging.js";
|
|
8
8
|
import type { StreamStatusEvent, ToolcraftStream } from "./stream.js";
|
|
9
9
|
export { createManagedStream } from "./stream.js";
|
|
@@ -227,7 +227,8 @@ export declare function hasMcpProxyConfig(group: Group<any>): boolean;
|
|
|
227
227
|
export { S, toJsonSchema } from "./schema.js";
|
|
228
228
|
export { AuthenticationError, BadRequestError, ClientError, ConflictError, HttpError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, ServerError, ServiceUnavailableError, UnprocessableEntityError, createHttpError } from "./http-errors.js";
|
|
229
229
|
export type { HttpErrorRequest, HttpErrorResponse } from "./http-errors.js";
|
|
230
|
-
export { ApprovalDeclinedError, ToolcraftBugError, UserError };
|
|
230
|
+
export { ApprovalDeclinedError, ToolcraftBugError, UserError, isUserError };
|
|
231
|
+
export { suggest } from "./suggest.js";
|
|
231
232
|
export { createRuntimeLogger, isLogLevel, shouldEmitDiagnostic } from "./runtime-logging.js";
|
|
232
233
|
export { findPackageMetadata, packageMetadata } from "./package-metadata.js";
|
|
233
234
|
export type { PackageMetadata } from "./package-metadata.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import { ApprovalDeclinedError } from "./human-in-loop/types.js";
|
|
3
3
|
import { mergeHumanInLoopFromGroup, validateHumanInLoopOnDefine } from "./human-in-loop/config.js";
|
|
4
|
-
import { ToolcraftBugError, UserError } from "./user-error.js";
|
|
4
|
+
import { ToolcraftBugError, UserError, isUserError } from "./user-error.js";
|
|
5
5
|
import { suggest } from "./suggest.js";
|
|
6
6
|
export { createManagedStream } from "./stream.js";
|
|
7
7
|
const commandConfigSymbol = Symbol("toolcraft.command.config");
|
|
@@ -500,6 +500,7 @@ export function hasMcpProxyConfig(group) {
|
|
|
500
500
|
}
|
|
501
501
|
export { S, toJsonSchema } from "./schema.js";
|
|
502
502
|
export { AuthenticationError, BadRequestError, ClientError, ConflictError, HttpError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, ServerError, ServiceUnavailableError, UnprocessableEntityError, createHttpError } from "./http-errors.js";
|
|
503
|
-
export { ApprovalDeclinedError, ToolcraftBugError, UserError };
|
|
503
|
+
export { ApprovalDeclinedError, ToolcraftBugError, UserError, isUserError };
|
|
504
|
+
export { suggest } from "./suggest.js";
|
|
504
505
|
export { createRuntimeLogger, isLogLevel, shouldEmitDiagnostic } from "./runtime-logging.js";
|
|
505
506
|
export { findPackageMetadata, packageMetadata } from "./package-metadata.js";
|
package/dist/renderer.js
CHANGED
|
@@ -142,6 +142,9 @@ function compactUrl(value) {
|
|
|
142
142
|
return value;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
function stackedList(value) {
|
|
146
|
+
return value.map((entry) => displayScalar(entry)).join("\n") || "—";
|
|
147
|
+
}
|
|
145
148
|
function displayRowValue(value) {
|
|
146
149
|
return isUrl(value) ? compactUrl(value) : displayScalar(value);
|
|
147
150
|
}
|
|
@@ -176,7 +179,7 @@ function renderObjectCard(result, primitives, title) {
|
|
|
176
179
|
const arrayObjectSections = directArrayObjectSections(result);
|
|
177
180
|
const listRows = Object.entries(result)
|
|
178
181
|
.filter(([, value]) => Array.isArray(value) && !isNonEmptyArrayOfObjects(value))
|
|
179
|
-
.map(([key, value]) => ({ label: humanizeKey(key), value:
|
|
182
|
+
.map(([key, value]) => ({ label: humanizeKey(key), value: stackedList(value) }));
|
|
180
183
|
return renderDetailCard({
|
|
181
184
|
theme: primitives.getTheme(),
|
|
182
185
|
title,
|
package/dist/user-error.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
export declare class UserError extends Error {
|
|
2
2
|
constructor(message: string, options?: ErrorOptions);
|
|
3
3
|
}
|
|
4
|
+
/**
|
|
5
|
+
* Detects user errors by name as well as identity, so an instance created in
|
|
6
|
+
* another bundle (for example `@poe-code/user-error`, thrown by packages that do
|
|
7
|
+
* not depend on toolcraft) is still rendered as guidance where `instanceof`
|
|
8
|
+
* would fail - while a genuine `UserError` stays one even if its name was
|
|
9
|
+
* overwritten.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isUserError(error: unknown): error is Error;
|
|
4
12
|
export declare class ToolcraftBugError extends Error {
|
|
5
13
|
constructor(message: string);
|
|
6
14
|
}
|
package/dist/user-error.js
CHANGED
|
@@ -4,6 +4,16 @@ export class UserError extends Error {
|
|
|
4
4
|
this.name = "UserError";
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Detects user errors by name as well as identity, so an instance created in
|
|
9
|
+
* another bundle (for example `@poe-code/user-error`, thrown by packages that do
|
|
10
|
+
* not depend on toolcraft) is still rendered as guidance where `instanceof`
|
|
11
|
+
* would fail - while a genuine `UserError` stays one even if its name was
|
|
12
|
+
* overwritten.
|
|
13
|
+
*/
|
|
14
|
+
export function isUserError(error) {
|
|
15
|
+
return error instanceof UserError || (error instanceof Error && error.name === "UserError");
|
|
16
|
+
}
|
|
7
17
|
export class ToolcraftBugError extends Error {
|
|
8
18
|
constructor(message) {
|
|
9
19
|
super(message);
|
|
@@ -4,7 +4,8 @@ Shared catalog of supported coding-agent definitions.
|
|
|
4
4
|
|
|
5
5
|
This package owns the declarative agent metadata used by CLI, SDK, spawn,
|
|
6
6
|
configuration, and UI surfaces: stable ids, labels, aliases, config paths,
|
|
7
|
-
binary names, API-shape support, OTEL capture wiring,
|
|
7
|
+
binary names, API-shape support, OTEL capture wiring, brand colors, and the
|
|
8
|
+
capability matrix that says which commands accept each agent.
|
|
8
9
|
|
|
9
10
|
## Usage
|
|
10
11
|
|
|
@@ -24,6 +25,18 @@ const codex = allAgents.find((agent) => agent.id === "codex");
|
|
|
24
25
|
- `formatAgentSpecifier(specifier)`: formats an agent specifier.
|
|
25
26
|
- `normalizeAgentId(input)`: normalizes the agent part through the registry.
|
|
26
27
|
- Agent definition exports such as `codexAgent`, `claudeCodeAgent`, `geminiCliAgent`, and `piAgent`.
|
|
28
|
+
- `listAgentsWithCapability(capability, options?)`: ids supporting a capability, optionally including aliases.
|
|
29
|
+
- `agentSupportsCapability(input, capability)`: resolves aliases, then checks the matrix.
|
|
30
|
+
- `formatAgentCapabilityError({ agent, capability })`: the shared message for a rejected agent argument.
|
|
31
|
+
|
|
32
|
+
## Capability Matrix
|
|
33
|
+
|
|
34
|
+
Each `AgentDefinition` declares its `capabilities` (`spawn`, `configure`,
|
|
35
|
+
`install`, `test`, `skill`, `mcp`). This is the single published source for every
|
|
36
|
+
command's allow-list, so `spawn`/`configure`/`install`/`test`/`skill` cannot
|
|
37
|
+
drift apart. `src/cli/commands/agent-capability-matrix.test.ts` pins each
|
|
38
|
+
capability to the registry that implements it, and fails if a registry gains or
|
|
39
|
+
loses an agent without the matrix being updated.
|
|
27
40
|
|
|
28
41
|
## Config Options
|
|
29
42
|
|
|
@@ -5,6 +5,7 @@ export const poeAgentAgent = {
|
|
|
5
5
|
summary: "Run one-shot prompts with the built-in Poe agent runtime.",
|
|
6
6
|
apiShapes: ["openai-responses", "openai-chat-completions"],
|
|
7
7
|
configPath: "~/.poe-code/config.json",
|
|
8
|
+
capabilities: ["configure"],
|
|
8
9
|
branding: {
|
|
9
10
|
colors: {
|
|
10
11
|
dark: "#A465F7",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentCapability } from "./types.js";
|
|
2
|
+
export declare function listAgentsWithCapability(capability: AgentCapability, options?: {
|
|
3
|
+
includeAliases?: boolean;
|
|
4
|
+
}): readonly string[];
|
|
5
|
+
export declare function agentSupportsCapability(input: string, capability: AgentCapability): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* The single message for every agent argument that misses. It distinguishes a
|
|
8
|
+
* typo (unknown id, plus a did-you-mean) from a real capability gap ("pi
|
|
9
|
+
* supports: spawn"), and always names the agents the command does accept.
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatAgentCapabilityError(input: {
|
|
12
|
+
agent: string;
|
|
13
|
+
capability: AgentCapability;
|
|
14
|
+
}): string;
|