argsbarg 6.1.2 → 6.1.3
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/CHANGELOG.md +65 -1
- package/README.md +17 -19
- package/bin/argsbarg +10 -0
- package/docs/README.md +4 -3
- package/docs/ai-skills.md +4 -2
- package/docs/bundled-docs.md +50 -25
- package/docs/cli-program.md +52 -10
- package/docs/config-schema.md +10 -11
- package/docs/configure.md +2 -0
- package/docs/decisions.md +40 -0
- package/docs/developing.md +43 -5
- package/docs/http-server.md +171 -0
- package/docs/json-schema-subset.md +51 -0
- package/docs/mcp.md +4 -2
- package/docs/output-schema.md +55 -62
- package/examples/formats.ts +6 -6
- package/examples/full-example/Formula/full-example.rb +35 -0
- package/examples/full-example/README.md +20 -21
- package/examples/full-example/docs/README.md +1 -1
- package/examples/full-example/docs/cli-schema.json +1790 -98
- package/examples/full-example/docs/cli.md +1990 -0
- package/examples/full-example/docs/http.md +28 -29
- package/examples/full-example/docs/mcp.md +8 -22
- package/examples/full-example/docs/openapi.json +783 -50
- package/examples/full-example/docs/skill.md +10 -10
- package/examples/full-example/justfile +11 -1
- package/examples/full-example/src/commands/render-json/__generated__/RenderJsonInputSchema.json +15 -0
- package/examples/full-example/src/commands/render-json/__generated__/index.ts +5 -0
- package/examples/full-example/src/commands/render-json/command.test.ts +46 -0
- package/examples/full-example/src/commands/render-json/command.ts +30 -0
- package/examples/full-example/src/commands/render-json/types.ts +9 -0
- package/examples/full-example/src/commands/status/__generated__/StatusJsonOutputSchema.json +15 -0
- package/examples/full-example/src/commands/status/__generated__/index.ts +2 -2
- package/examples/full-example/src/commands/status/command.ts +5 -13
- package/examples/full-example/src/commands/status/types.ts +1 -14
- package/examples/full-example/src/commands/workspaces/__generated__/WorkspaceNameInputSchema.json +15 -0
- package/examples/full-example/src/commands/workspaces/__generated__/index.ts +5 -0
- package/examples/full-example/src/commands/workspaces/command.test.ts +58 -0
- package/examples/full-example/src/commands/workspaces/command.ts +94 -0
- package/examples/full-example/src/commands/workspaces/types.ts +6 -0
- package/examples/full-example/src/db/index.test.ts +86 -0
- package/examples/full-example/src/db/index.ts +101 -0
- package/examples/full-example/src/db/migrate.test.ts +35 -0
- package/examples/full-example/src/db/migrate.ts +69 -0
- package/examples/full-example/src/db/migrations/001_workspaces.sql +6 -0
- package/examples/full-example/src/db/tables/workspaces.ts +66 -0
- package/examples/full-example/src/program.ts +11 -36
- package/examples/full-example/src/types/argsbarg.d.ts +11 -0
- package/examples/full-example/src/types/md.d.ts +4 -0
- package/examples/full-example/tsconfig.json +5 -2
- package/examples/mcp-test.ts +1 -2
- package/examples/minimal.ts +1 -7
- package/examples/nested.ts +1 -2
- package/examples/option-required.ts +1 -1
- package/examples/servers.ts +4 -5
- package/index.d.ts +431 -136
- package/package.json +19 -2
- package/src/builtins/builtins.test.ts +7 -7
- package/src/builtins/completion-bash.ts +1 -1
- package/src/builtins/completion-fish.ts +1 -1
- package/src/builtins/completion-group.ts +4 -4
- package/src/builtins/completion-simulate-shared.ts +9 -0
- package/src/builtins/completion-zsh.ts +1 -1
- package/src/builtins/config.test.ts +3 -3
- package/src/builtins/config.ts +9 -9
- package/src/builtins/configure-copy.ts +2 -2
- package/src/builtins/configure.ts +4 -4
- package/src/builtins/dispatch.ts +19 -18
- package/src/builtins/export.ts +7 -5
- package/src/builtins/http.ts +68 -0
- package/src/builtins/mcp.ts +28 -4
- package/src/builtins/presentation.ts +6 -6
- package/src/builtins/registry.ts +6 -6
- package/src/builtins/scopes.ts +2 -2
- package/src/builtins/version.ts +1 -1
- package/src/cli-tool/full-example-capabilities.test.ts +10 -15
- package/src/cli-tool/main.ts +1 -1
- package/src/cli-tool/program.ts +3 -2
- package/src/cli-tool/prompt.ts +1 -1
- package/src/cli-tool/run-schemagen.ts +1 -3
- package/src/cli-tool/schemagen/cleanup.ts +6 -7
- package/src/cli-tool/schemagen/discover-schema-roots.ts +66 -120
- package/src/cli-tool/schemagen/index.ts +2 -2
- package/src/cli-tool/schemagen/names.ts +8 -13
- package/src/cli-tool/schemagen/run.ts +21 -28
- package/src/cli-tool/schemagen/schemagen.test.ts +136 -46
- package/src/config/bindings.test.ts +1 -1
- package/src/config/bindings.ts +1 -1
- package/src/config/bootstrap.test.ts +1 -1
- package/src/config/bootstrap.ts +36 -4
- package/src/config/context.test.ts +1 -1
- package/src/config/context.ts +1 -1
- package/src/config/entry.ts +1 -1
- package/src/config/file.test.ts +1 -1
- package/src/config/file.ts +3 -3
- package/src/config/manifest.ts +1 -1
- package/src/config/resolve.test.ts +1 -1
- package/src/config/resolve.ts +1 -1
- package/src/config/schema.ts +1 -1
- package/src/config/validate.ts +1 -1
- package/src/{install → configure/artifacts}/binary-placement.test.ts +1 -1
- package/src/{install → configure/artifacts}/binary-placement.ts +1 -1
- package/src/{install → configure/artifacts}/gh-release-update.ts +1 -1
- package/src/{install → configure/artifacts}/install-validate.test.ts +3 -3
- package/src/{install → configure/artifacts}/mcp-config.ts +1 -1
- package/src/{install → configure/artifacts}/mcp-opencode.test.ts +1 -1
- package/src/{install → configure/artifacts}/mcp-opencode.ts +1 -1
- package/src/{install → configure/artifacts}/paths.ts +5 -5
- package/src/configure/artifacts/plan.ts +24 -0
- package/src/{install → configure/artifacts}/status.test.ts +1 -1
- package/src/{install → configure/artifacts}/status.ts +2 -2
- package/src/{install → configure/artifacts}/target-base.ts +1 -1
- package/src/{install → configure/artifacts}/target-detect.ts +1 -1
- package/src/{install → configure/artifacts}/target-effective.ts +3 -9
- package/src/{install → configure/artifacts}/target-mcp-cli.ts +1 -1
- package/src/{install → configure/artifacts}/target-mcp-json.ts +1 -1
- package/src/{install → configure/artifacts}/target-plan-build.ts +2 -2
- package/src/{install → configure/artifacts}/target-registry.ts +2 -2
- package/src/{install → configure/artifacts}/target-scope.ts +3 -3
- package/src/{install → configure/artifacts}/target-skill.ts +1 -1
- package/src/{install → configure/artifacts}/target-types.ts +2 -2
- package/src/{install → configure/artifacts}/targets/app.ts +5 -5
- package/src/{install → configure/artifacts}/targets/chatgpt-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/claude-code-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/claude-desktop-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/claude-skill.ts +2 -2
- package/src/{install → configure/artifacts}/targets/codex-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/codex-skill.ts +2 -2
- package/src/{install → configure/artifacts}/targets/configure.ts +5 -5
- package/src/{install → configure/artifacts}/targets/cursor-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/cursor-skill.ts +2 -2
- package/src/{install → configure/artifacts}/targets/index.ts +1 -1
- package/src/{install → configure/artifacts}/targets/openclaw-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/openclaw-skill.ts +3 -3
- package/src/{install → configure/artifacts}/targets/opencode-mcp.ts +5 -5
- package/src/{install → configure/artifacts}/targets/opencode-skill.ts +3 -3
- package/src/{install → configure/artifacts}/targets.test.ts +1 -1
- package/src/{install → configure/artifacts}/uninstall.ts +1 -1
- package/src/configure/configure.test.ts +11 -11
- package/src/configure/index.ts +14 -14
- package/src/configure/prompt.ts +2 -2
- package/src/{context.ts → core/context.ts} +26 -20
- package/src/{json-leaf.test.ts → core/json-leaf.test.ts} +4 -4
- package/src/{leaf-inputs.test.ts → core/leaf-inputs.test.ts} +7 -7
- package/src/{leaf-inputs.ts → core/leaf-inputs.ts} +16 -12
- package/src/{parse.test.ts → core/parse.test.ts} +97 -109
- package/src/{parse.ts → core/parse.ts} +129 -31
- package/src/{schema.ts → core/schema.ts} +25 -13
- package/src/{types.ts → core/types.ts} +225 -35
- package/src/{validate.ts → core/validate.ts} +39 -29
- package/src/docs/builtin.ts +8 -19
- package/src/docs/{api-guide.test.ts → cli-guide.test.ts} +21 -21
- package/src/docs/{api-guide.ts → cli-guide.ts} +45 -16
- package/src/docs/docs.test.ts +76 -41
- package/src/docs/http-guide.ts +37 -34
- package/src/docs/mcp-guide.ts +12 -14
- package/src/docs/mcp-resources.test.ts +2 -3
- package/src/docs/mcp-resources.ts +6 -11
- package/src/docs/resolve.ts +22 -30
- package/src/docs/save.ts +3 -3
- package/src/exports/cli.ts +47 -0
- package/src/exports/headless.ts +13 -0
- package/src/exports/http.ts +6 -0
- package/src/exports/mcp.ts +6 -0
- package/src/{headless.test.ts → headless/routing.test.ts} +3 -3
- package/src/{headless.ts → headless/routing.ts} +3 -3
- package/src/headless/tool-call.ts +114 -46
- package/src/help.test.ts +152 -0
- package/src/help.ts +3 -3
- package/src/hooks/builtin.ts +20 -0
- package/src/hooks/run.ts +142 -0
- package/src/http/openapi.ts +182 -0
- package/src/http/readiness.ts +78 -0
- package/src/{api → http}/result.ts +16 -5
- package/src/http/routes.ts +329 -0
- package/src/http/server.ts +225 -0
- package/src/index.ts +36 -25
- package/src/log/ecs.test.ts +43 -0
- package/src/log/ecs.ts +59 -0
- package/src/log/emitter.ts +166 -0
- package/src/mcp/bundle.ts +2 -2
- package/src/mcp/claude.test.ts +1 -1
- package/src/mcp/claude.ts +4 -4
- package/src/{hidden-mcpb.test.ts → mcp/hidden-mcpb.test.ts} +10 -9
- package/src/mcp/result.ts +2 -2
- package/src/mcp/server.ts +54 -6
- package/src/mcp/tools.ts +9 -20
- package/src/{capabilities.ts → runtime/capabilities.ts} +11 -11
- package/src/{cli-errors.ts → runtime/cli-errors.ts} +4 -4
- package/src/{cli.ts → runtime/cli.ts} +159 -49
- package/src/runtime/exposure.ts +102 -0
- package/src/{invoke.test.ts → runtime/invoke.test.ts} +31 -7
- package/src/server/context.ts +25 -0
- package/src/server/overrides.ts +112 -0
- package/src/skill/generate.ts +8 -8
- package/src/skill/hint.ts +1 -1
- package/src/skill/install.ts +2 -2
- package/src/skill/naming.ts +1 -1
- package/src/{test-fixtures.ts → test/fixtures.ts} +3 -2
- package/src/{config.integration.test.ts → test/integration/config.test.ts} +8 -8
- package/src/{api.integration.test.ts → test/integration/http.test.ts} +170 -67
- package/src/{mcp.integration.test.ts → test/integration/mcp.test.ts} +11 -57
- package/docs/api-server.md +0 -141
- package/examples/full-example/docs/api.md +0 -511
- package/examples/full-example/src/commands/status/__generated__/outputSchema.json +0 -28
- package/examples/full-example/src/config/__generated__/configSchema.json +0 -40
- package/examples/full-example/src/config/__generated__/index.ts +0 -5
- package/examples/full-example/src/config/types.ts +0 -24
- package/src/api/openapi.ts +0 -117
- package/src/api/server.ts +0 -120
- package/src/builtins/api.ts +0 -38
- package/src/hidden.ts +0 -30
- package/src/install/plan.ts +0 -53
- /package/src/{install → configure/artifacts}/detect-installed.ts +0 -0
- /package/src/{install → configure/artifacts}/gh-release-update.test.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-codex.test.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-codex.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-openclaw.test.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-openclaw.ts +0 -0
- /package/src/{install → configure/artifacts}/normalize-uninstall.ts +0 -0
- /package/src/{install → configure/artifacts}/normalize.ts +0 -0
- /package/src/{install → configure/artifacts}/opts.ts +0 -0
- /package/src/{install → configure/artifacts}/shell.ts +0 -0
- /package/src/{formats.test.ts → core/formats.test.ts} +0 -0
- /package/src/{formats.ts → core/formats.ts} +0 -0
- /package/src/{respond.ts → core/respond.ts} +0 -0
- /package/src/{types.test.ts → core/types.test.ts} +0 -0
- /package/src/{api → http}/schema-deref.test.ts +0 -0
- /package/src/{api → http}/schema-deref.ts +0 -0
|
@@ -3,7 +3,7 @@ Tests for docs/mcp-resources module behavior.
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { expect, test } from "bun:test";
|
|
6
|
-
import type { CliProgram } from "
|
|
6
|
+
import type { CliProgram } from "~/core/types.ts";
|
|
7
7
|
import {
|
|
8
8
|
defaultDocsTopicResourceUri,
|
|
9
9
|
docsMcpResources,
|
|
@@ -21,14 +21,13 @@ function fixture(opts?: { docs?: boolean; mcp?: boolean }): CliProgram {
|
|
|
21
21
|
...(docs
|
|
22
22
|
? {
|
|
23
23
|
docs: {
|
|
24
|
-
enabled: true,
|
|
25
24
|
topics: {
|
|
26
25
|
readme: { text: "# Readme\n", description: "User guide." },
|
|
27
26
|
arch: { text: "# Arch\n" },
|
|
28
27
|
},
|
|
29
28
|
},
|
|
30
29
|
}
|
|
31
|
-
: {}),
|
|
30
|
+
: { docs: { enabled: false } }),
|
|
32
31
|
...(mcp ? { mcpServer: { enabled: true } } : {}),
|
|
33
32
|
handler: () => {},
|
|
34
33
|
};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Auto MCP resources for user docs.topics when docs and MCP are both enabled.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { CliProgram } from "
|
|
6
|
-
import { docsEnabled, docsTopicDescription, docsTopicText, docsUserTopicKeys } from "./resolve.ts";
|
|
5
|
+
import type { CliProgram } from "~/core/types.ts";
|
|
6
|
+
import { docsEnabled, docsTopicDescription, docsTopicText, docsUserTopicKeys, resolveDocsConfig } from "./resolve.ts";
|
|
7
7
|
|
|
8
8
|
/** Default URI pattern for a docs topic MCP resource (`<mcpId>://docs/<topicKey>`). */
|
|
9
9
|
export function defaultDocsTopicResourceUri(mcpId: string, topicKey: string): string {
|
|
@@ -31,12 +31,10 @@ export function docsMcpResources(program: CliProgram): {
|
|
|
31
31
|
if (!docsEnabled(program) || program.mcpServer?.enabled !== true) {
|
|
32
32
|
return [];
|
|
33
33
|
}
|
|
34
|
-
const docs = program
|
|
35
|
-
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
34
|
+
const docs = resolveDocsConfig(program);
|
|
35
|
+
const topics = docs.topics ?? {};
|
|
38
36
|
return docsUserTopicKeys(docs).map((key) => {
|
|
39
|
-
const topic =
|
|
37
|
+
const topic = topics[key];
|
|
40
38
|
if (!topic) {
|
|
41
39
|
throw new Error(`docs topic missing: ${key}`);
|
|
42
40
|
}
|
|
@@ -58,9 +56,6 @@ export function reservedDocsTopicResourceUris(program: CliProgram): string[] {
|
|
|
58
56
|
if (!docsEnabled(program) || program.mcpServer?.enabled !== true) {
|
|
59
57
|
return [];
|
|
60
58
|
}
|
|
61
|
-
const docs = program
|
|
62
|
-
if (!docs) {
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
59
|
+
const docs = resolveDocsConfig(program);
|
|
65
60
|
return docsUserTopicKeys(docs).map((key) => resolveDocsTopicResourceUri(program, key));
|
|
66
61
|
}
|
package/src/docs/resolve.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import { cliSchemaJson } from "~/core/schema.ts";
|
|
2
|
+
import type { CliDocsConfig, CliProgram } from "~/core/types.ts";
|
|
3
|
+
import { openApiJson } from "~/http/openapi.ts";
|
|
4
|
+
import { generateSkillBundle } from "~/skill/generate.ts";
|
|
5
|
+
import { generateCliGuide } from "./cli-guide.ts";
|
|
6
6
|
import { generateHttpGuide } from "./http-guide.ts";
|
|
7
7
|
import { generateMcpGuide } from "./mcp-guide.ts";
|
|
8
8
|
|
|
9
9
|
/** Built-in docs subcommand keys not allowed in `docs.topics`. */
|
|
10
|
-
export const DOCS_BUILTIN_TOPIC_KEYS = ["http", "mcp", "all", "cli-schema", "
|
|
10
|
+
export const DOCS_BUILTIN_TOPIC_KEYS = ["http", "mcp", "all", "cli-schema", "cli", "skill", "openapi"] as const;
|
|
11
11
|
|
|
12
12
|
export type DocsBuiltinTopicKey = (typeof DOCS_BUILTIN_TOPIC_KEYS)[number];
|
|
13
13
|
|
|
@@ -16,28 +16,20 @@ export const DOCS_ROUTER_DESCRIPTION = "Print bundled CLI documentation.";
|
|
|
16
16
|
|
|
17
17
|
/** Returns whether bundled docs are enabled on the program root. */
|
|
18
18
|
export function docsEnabled(program: CliProgram): boolean {
|
|
19
|
-
return program.docs?.enabled
|
|
19
|
+
return program.docs?.enabled !== false;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
export function
|
|
24
|
-
return
|
|
22
|
+
/** Normalized docs config with defaults applied. */
|
|
23
|
+
export function resolveDocsConfig(program: CliProgram): CliDocsConfig {
|
|
24
|
+
return {
|
|
25
|
+
description: program.docs?.description,
|
|
26
|
+
topics: program.docs?.topics ?? {},
|
|
27
|
+
};
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
/**
|
|
28
|
-
export function
|
|
29
|
-
|
|
30
|
-
return docs.defaultTopic;
|
|
31
|
-
}
|
|
32
|
-
const keys = docsUserTopicKeys(docs);
|
|
33
|
-
if (keys.length === 0) {
|
|
34
|
-
throw new Error("docs.topics must be non-empty");
|
|
35
|
-
}
|
|
36
|
-
const first = keys[0];
|
|
37
|
-
if (first === undefined) {
|
|
38
|
-
throw new Error("docs.topics must be non-empty");
|
|
39
|
-
}
|
|
40
|
-
return first;
|
|
30
|
+
/** User topic keys in declaration order. */
|
|
31
|
+
export function docsUserTopicKeys(docs: CliDocsConfig): string[] {
|
|
32
|
+
return Object.keys(docs.topics ?? {});
|
|
41
33
|
}
|
|
42
34
|
|
|
43
35
|
/** Whether MCP auto-guide topic is included. */
|
|
@@ -47,7 +39,7 @@ export function docsIncludesMcpTopic(program: CliProgram): boolean {
|
|
|
47
39
|
|
|
48
40
|
/** Whether HTTP auto-guide topic is included. */
|
|
49
41
|
export function docsIncludesHttpTopic(program: CliProgram): boolean {
|
|
50
|
-
return docsEnabled(program) && program.
|
|
42
|
+
return docsEnabled(program) && program.httpServer?.enabled === true;
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
/** Whether OpenAPI export topic is included. */
|
|
@@ -69,8 +61,7 @@ export function docsTopicDescription(key: string, custom?: string): string {
|
|
|
69
61
|
|
|
70
62
|
/** Markdown body for one docs topic key. */
|
|
71
63
|
export function docsTopicText(program: CliProgram, topic: string): string {
|
|
72
|
-
|
|
73
|
-
if (!docs) {
|
|
64
|
+
if (!docsEnabled(program)) {
|
|
74
65
|
throw new Error("docs not enabled");
|
|
75
66
|
}
|
|
76
67
|
if (topic === "mcp") {
|
|
@@ -85,7 +76,8 @@ export function docsTopicText(program: CliProgram, topic: string): string {
|
|
|
85
76
|
}
|
|
86
77
|
return generateHttpGuide(program);
|
|
87
78
|
}
|
|
88
|
-
const
|
|
79
|
+
const topics = program.docs?.topics ?? {};
|
|
80
|
+
const entry = topics[topic];
|
|
89
81
|
if (!entry) {
|
|
90
82
|
throw new Error(`Unknown docs topic '${topic}'.`);
|
|
91
83
|
}
|
|
@@ -103,8 +95,8 @@ export function docsTopicContent(program: CliProgram, topic: string): string {
|
|
|
103
95
|
}
|
|
104
96
|
return openApiJson(program);
|
|
105
97
|
}
|
|
106
|
-
if (topic === "
|
|
107
|
-
return
|
|
98
|
+
if (topic === "cli") {
|
|
99
|
+
return generateCliGuide(program);
|
|
108
100
|
}
|
|
109
101
|
if (topic === "skill") {
|
|
110
102
|
return `${generateSkillBundle(program, "cursor").skillMd}\n`;
|
package/src/docs/save.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import type { CliProgram } from "~/core/types.ts";
|
|
4
|
+
import { generatedFileHtmlComment, insertGeneratedHint } from "~/skill/hint.ts";
|
|
5
5
|
import { docsTopicContent } from "./resolve.ts";
|
|
6
6
|
|
|
7
7
|
/** Relative output directory for `docs --save`. */
|
|
8
8
|
export const DOCS_SAVE_DIR = "docs";
|
|
9
9
|
|
|
10
10
|
/** Builtin docs topics generated by argsbarg (not consumer `docs.topics`). */
|
|
11
|
-
export const DOCS_GENERATED_SAVE_TOPICS = ["mcp", "
|
|
11
|
+
export const DOCS_GENERATED_SAVE_TOPICS = ["mcp", "cli", "skill"] as const;
|
|
12
12
|
|
|
13
13
|
/** Whether `--save` should prepend a generated-file hint (argsbarg writers only). */
|
|
14
14
|
export function docsTopicIsGeneratedByArgsbarg(topic: string): boolean {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Public CLI runtime export (`argsbarg/cli`).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { displayAppConfigPath, resolveAppConfigPath } from "~/config/file.ts";
|
|
6
|
+
export type { CliLeafInputs } from "~/core/context.ts";
|
|
7
|
+
export { CliContext } from "~/core/context.ts";
|
|
8
|
+
export {
|
|
9
|
+
parseCommaList,
|
|
10
|
+
parseDate,
|
|
11
|
+
parseDateTime,
|
|
12
|
+
parseDurationMs,
|
|
13
|
+
} from "~/core/formats.ts";
|
|
14
|
+
export type {
|
|
15
|
+
CliAppConfig,
|
|
16
|
+
CliAppConfigEntry,
|
|
17
|
+
CliConfigureConfig,
|
|
18
|
+
CliConfigureTargets,
|
|
19
|
+
CliDocsConfig,
|
|
20
|
+
CliDocsTopic,
|
|
21
|
+
CliFallbackMode,
|
|
22
|
+
CliHandler,
|
|
23
|
+
CliHttpResponseConfig,
|
|
24
|
+
CliHttpServerConfig,
|
|
25
|
+
CliInvocation,
|
|
26
|
+
CliLeafKind,
|
|
27
|
+
CliMcpResource,
|
|
28
|
+
CliMcpServerConfig,
|
|
29
|
+
CliMcpToolConfig,
|
|
30
|
+
CliOption,
|
|
31
|
+
CliPositional,
|
|
32
|
+
CliProgram,
|
|
33
|
+
CliRespondBody,
|
|
34
|
+
CliRespondOptions,
|
|
35
|
+
InstallAgentIntegration,
|
|
36
|
+
InstallTargetSpec,
|
|
37
|
+
ResolvedInstallTarget,
|
|
38
|
+
} from "~/core/types.ts";
|
|
39
|
+
export {
|
|
40
|
+
CliOptionKind,
|
|
41
|
+
CliSchemaValidationError,
|
|
42
|
+
CliValueFormat,
|
|
43
|
+
isJsonLeaf,
|
|
44
|
+
} from "~/core/types.ts";
|
|
45
|
+
export { Cli, type CliInvokeKind, type CliInvokeResult } from "~/runtime/cli.ts";
|
|
46
|
+
export { cliErrWithHelp } from "~/runtime/cli-errors.ts";
|
|
47
|
+
export { isInteractiveTty } from "~/utils.ts";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Headless routing helpers (`argsbarg/headless`).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type { HeadlessContext } from "~/headless/routing.ts";
|
|
6
|
+
export {
|
|
7
|
+
formatDryRunMessage,
|
|
8
|
+
requireYesInNonTty,
|
|
9
|
+
shouldRunHeadless,
|
|
10
|
+
shouldRunHeadlessWithPositionals,
|
|
11
|
+
shouldRunHeadlessWithYes,
|
|
12
|
+
wantsExplicitJson,
|
|
13
|
+
} from "~/headless/routing.ts";
|
|
@@ -10,18 +10,18 @@ import {
|
|
|
10
10
|
shouldRunHeadlessWithPositionals,
|
|
11
11
|
shouldRunHeadlessWithYes,
|
|
12
12
|
wantsExplicitJson,
|
|
13
|
-
} from "./
|
|
13
|
+
} from "./routing.ts";
|
|
14
14
|
|
|
15
15
|
test("wantsExplicitJson includes MCP and API invocation", () => {
|
|
16
16
|
expect(wantsExplicitJson({ invocation: "cli" }, false)).toBe(false);
|
|
17
17
|
expect(wantsExplicitJson({ invocation: "mcp" }, false)).toBe(true);
|
|
18
|
-
expect(wantsExplicitJson({ invocation: "
|
|
18
|
+
expect(wantsExplicitJson({ invocation: "http" }, false)).toBe(true);
|
|
19
19
|
expect(wantsExplicitJson({ invocation: "cli" }, true)).toBe(true);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
test("shouldRunHeadless is true for MCP, API, and json", () => {
|
|
23
23
|
expect(shouldRunHeadless({ invocation: "mcp" }, false)).toBe(true);
|
|
24
|
-
expect(shouldRunHeadless({ invocation: "
|
|
24
|
+
expect(shouldRunHeadless({ invocation: "http" }, false)).toBe(true);
|
|
25
25
|
expect(shouldRunHeadless({ invocation: "cli" }, true)).toBe(true);
|
|
26
26
|
expect(shouldRunHeadless({ invocation: "cli" }, false, true)).toBe(true);
|
|
27
27
|
expect(shouldRunHeadless({ invocation: "cli" }, false, false, false)).toBe(true);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { CliContext } from "
|
|
2
|
-
import { isInteractiveTty } from "
|
|
1
|
+
import type { CliContext } from "~/core/context.ts";
|
|
2
|
+
import { isInteractiveTty } from "~/utils.ts";
|
|
3
3
|
|
|
4
4
|
/** Minimal context for headless routing helpers. */
|
|
5
5
|
export type HeadlessContext = Pick<CliContext, "invocation">;
|
|
6
6
|
|
|
7
7
|
/** True when the handler was invoked via MCP or HTTP API. */
|
|
8
8
|
function isToolInvocation(invocation: CliContext["invocation"]): boolean {
|
|
9
|
-
return invocation === "mcp" || invocation === "
|
|
9
|
+
return invocation === "mcp" || invocation === "http";
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/** True when `--json` was passed or the handler was invoked headlessly over MCP/HTTP. */
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
Shared headless tool dispatch for MCP and HTTP: config bootstrap, argv conversion, and invoke.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
5
|
+
import { bootstrapAppConfig } from "~/config/bootstrap.ts";
|
|
6
|
+
import { formatMcpMissingConfigMessage, missingRequiredConfig } from "~/config/resolve.ts";
|
|
7
|
+
import type { CliInvocation, CliProgram, InvokeFailureKind } from "~/core/types.ts";
|
|
8
|
+
import { failureKindHttpStatus } from "~/hooks/run.ts";
|
|
9
|
+
import { apiErrorResponse, apiSuccessResponse, firstErrorLine } from "~/http/result.ts";
|
|
10
|
+
import { type HttpRouteDef, httpRequestToArgv } from "~/http/routes.ts";
|
|
11
|
+
import { obscureUnexpectedClientMessage } from "~/log/emitter.ts";
|
|
12
|
+
import { buildToolCallSuccessFromResponse } from "~/mcp/result.ts";
|
|
13
|
+
import { collectMcpTools, type McpToolDef, mcpToolCallToArgv } from "~/mcp/tools.ts";
|
|
14
|
+
import type { Cli, CliInvokeResult } from "~/runtime/cli.ts";
|
|
12
15
|
|
|
13
16
|
/** Outcome of resolving a tool name against the program schema. */
|
|
14
17
|
export type ToolLookupResult =
|
|
@@ -31,20 +34,16 @@ export interface HeadlessToolCallFailure {
|
|
|
31
34
|
exitCode: number;
|
|
32
35
|
stdout: string;
|
|
33
36
|
stderr: string;
|
|
37
|
+
failureKind?: InvokeFailureKind;
|
|
34
38
|
invokeResult?: CliInvokeResult;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
export type HeadlessToolCallResult = HeadlessToolCallSuccess | HeadlessToolCallFailure;
|
|
38
42
|
|
|
39
|
-
/** Finds an exposed tool by
|
|
40
|
-
export function lookupHeadlessTool(
|
|
41
|
-
program: CliProgram,
|
|
42
|
-
toolName: string,
|
|
43
|
-
invocation: CliInvocation = "mcp",
|
|
44
|
-
): ToolLookupResult {
|
|
43
|
+
/** Finds an exposed MCP tool by name. */
|
|
44
|
+
export function lookupHeadlessTool(program: CliProgram, toolName: string): ToolLookupResult {
|
|
45
45
|
const tools = collectMcpTools(program);
|
|
46
|
-
const tool =
|
|
47
|
-
invocation === "api" ? tools.find((t) => t.apiName === toolName) : tools.find((t) => t.name === toolName);
|
|
46
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
48
47
|
if (!tool) {
|
|
49
48
|
return { ok: false, kind: "unknown", message: `Unknown tool: ${toolName}` };
|
|
50
49
|
}
|
|
@@ -60,6 +59,33 @@ export function lookupHeadlessTool(
|
|
|
60
59
|
return { ok: true, tool };
|
|
61
60
|
}
|
|
62
61
|
|
|
62
|
+
function invokeFailure(result: CliInvokeResult): HeadlessToolCallFailure {
|
|
63
|
+
const message = result.errorMsg ?? (result.stderr.trim() || `Exit code ${result.exitCode}`);
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
kind: result.kind === "help" ? "help" : "invoke",
|
|
67
|
+
message,
|
|
68
|
+
exitCode: result.exitCode,
|
|
69
|
+
stdout: result.stdout,
|
|
70
|
+
stderr: result.stderr,
|
|
71
|
+
failureKind: result.failureKind,
|
|
72
|
+
invokeResult: result,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function noResponseFailure(result: CliInvokeResult): HeadlessToolCallFailure {
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
kind: "invoke",
|
|
80
|
+
message: "Handler did not call ctx.respond() or return a value",
|
|
81
|
+
exitCode: 1,
|
|
82
|
+
stdout: result.stdout,
|
|
83
|
+
stderr: result.stderr,
|
|
84
|
+
failureKind: "unexpected",
|
|
85
|
+
invokeResult: result,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
/**
|
|
64
90
|
* Converts flat tool arguments to argv and invokes the leaf handler headlessly.
|
|
65
91
|
*/
|
|
@@ -68,6 +94,7 @@ export async function executeHeadlessToolCall(
|
|
|
68
94
|
tool: McpToolDef,
|
|
69
95
|
args: Record<string, unknown>,
|
|
70
96
|
invocation: CliInvocation,
|
|
97
|
+
mcp?: { rpcMethod: string; toolName?: string; requestId: string },
|
|
71
98
|
): Promise<HeadlessToolCallResult> {
|
|
72
99
|
const argvResult = mcpToolCallToArgv(cli.program, tool, args);
|
|
73
100
|
if ("error" in argvResult) {
|
|
@@ -78,20 +105,13 @@ export async function executeHeadlessToolCall(
|
|
|
78
105
|
exitCode: 1,
|
|
79
106
|
stdout: "",
|
|
80
107
|
stderr: "",
|
|
108
|
+
failureKind: "validation",
|
|
81
109
|
};
|
|
82
110
|
}
|
|
83
111
|
|
|
84
|
-
const invokeResult = await cli.invoke(argvResult, { invocation, toolArgs: args });
|
|
112
|
+
const invokeResult = await cli.invoke(argvResult, { invocation, toolArgs: args, mcp });
|
|
85
113
|
if (invokeResult.kind === "help") {
|
|
86
|
-
return
|
|
87
|
-
ok: false,
|
|
88
|
-
kind: "help",
|
|
89
|
-
message: invokeResult.errorMsg ?? "Help is not available via tool calls.",
|
|
90
|
-
exitCode: invokeResult.exitCode,
|
|
91
|
-
stdout: invokeResult.stdout,
|
|
92
|
-
stderr: invokeResult.stderr,
|
|
93
|
-
invokeResult,
|
|
94
|
-
};
|
|
114
|
+
return invokeFailure(invokeResult);
|
|
95
115
|
}
|
|
96
116
|
|
|
97
117
|
if (invokeResult.kind === "ok" && invokeResult.exitCode === 0 && invokeResult.response) {
|
|
@@ -104,46 +124,81 @@ export async function executeHeadlessToolCall(
|
|
|
104
124
|
}
|
|
105
125
|
|
|
106
126
|
if (invokeResult.kind === "ok" && invokeResult.exitCode === 0) {
|
|
127
|
+
return noResponseFailure(invokeResult);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return invokeFailure(invokeResult);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Invokes a matched HTTP REST route headlessly (query + body → argv → invoke).
|
|
135
|
+
*/
|
|
136
|
+
export async function executeHttpRouteCall(
|
|
137
|
+
cli: Cli,
|
|
138
|
+
route: HttpRouteDef,
|
|
139
|
+
pathParams: Record<string, string>,
|
|
140
|
+
query: Record<string, string>,
|
|
141
|
+
body: Record<string, unknown>,
|
|
142
|
+
http?: { request: Request; clientIp: string; requestId: string },
|
|
143
|
+
): Promise<HeadlessToolCallResult> {
|
|
144
|
+
const argvResult = httpRequestToArgv(cli.program, route, pathParams, query, body);
|
|
145
|
+
if ("error" in argvResult) {
|
|
107
146
|
return {
|
|
108
147
|
ok: false,
|
|
109
|
-
kind: "
|
|
110
|
-
message:
|
|
148
|
+
kind: "argv",
|
|
149
|
+
message: argvResult.error,
|
|
111
150
|
exitCode: 1,
|
|
112
|
-
stdout:
|
|
113
|
-
stderr:
|
|
114
|
-
|
|
151
|
+
stdout: "",
|
|
152
|
+
stderr: "",
|
|
153
|
+
failureKind: "validation",
|
|
115
154
|
};
|
|
116
155
|
}
|
|
117
156
|
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
157
|
+
const toolArgs = { ...body, ...query, ...pathParams };
|
|
158
|
+
const invokeResult = await cli.invoke(argvResult, { invocation: "http", toolArgs, http });
|
|
159
|
+
if (invokeResult.kind === "help") {
|
|
160
|
+
return invokeFailure(invokeResult);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (invokeResult.kind === "ok" && invokeResult.exitCode === 0 && invokeResult.response) {
|
|
164
|
+
const mcpResult = buildToolCallSuccessFromResponse(invokeResult.response);
|
|
165
|
+
return {
|
|
166
|
+
ok: true,
|
|
167
|
+
response: invokeResult.response,
|
|
168
|
+
mcpResult,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (invokeResult.kind === "ok" && invokeResult.exitCode === 0) {
|
|
173
|
+
return noResponseFailure(invokeResult);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return invokeFailure(invokeResult);
|
|
128
177
|
}
|
|
129
178
|
|
|
130
179
|
/** Maps a headless success result to an HTTP Response. */
|
|
131
180
|
export function headlessSuccessToHttpResponse(
|
|
132
181
|
result: HeadlessToolCallSuccess,
|
|
133
|
-
leafApiResponse?: import("
|
|
182
|
+
leafApiResponse?: import("~/core/types.ts").CliHttpResponseConfig,
|
|
183
|
+
defaultStatus?: number,
|
|
134
184
|
): Response {
|
|
135
|
-
return apiSuccessResponse(result.response, leafApiResponse);
|
|
185
|
+
return apiSuccessResponse(result.response, leafApiResponse, defaultStatus);
|
|
136
186
|
}
|
|
137
187
|
|
|
138
188
|
/** Maps a headless failure result to a JSON HTTP error Response. */
|
|
139
|
-
export function headlessFailureToHttpResponse(result: HeadlessToolCallFailure): Response {
|
|
189
|
+
export function headlessFailureToHttpResponse(result: HeadlessToolCallFailure, obscureUnexpected = false): Response {
|
|
140
190
|
const status = resolveHttpErrorStatus(result);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
191
|
+
let message = firstErrorLine(result.message);
|
|
192
|
+
if (obscureUnexpected && result.failureKind === "unexpected") {
|
|
193
|
+
message = obscureUnexpectedClientMessage();
|
|
194
|
+
}
|
|
195
|
+
return apiErrorResponse(status, { error: message });
|
|
144
196
|
}
|
|
145
197
|
|
|
146
198
|
function resolveHttpErrorStatus(result: HeadlessToolCallFailure): number {
|
|
199
|
+
if (result.failureKind) {
|
|
200
|
+
return failureKindHttpStatus(result.failureKind);
|
|
201
|
+
}
|
|
147
202
|
if (result.kind === "argv" || result.kind === "help") {
|
|
148
203
|
return 400;
|
|
149
204
|
}
|
|
@@ -155,3 +210,16 @@ function resolveHttpErrorStatus(result: HeadlessToolCallFailure): number {
|
|
|
155
210
|
}
|
|
156
211
|
return 500;
|
|
157
212
|
}
|
|
213
|
+
|
|
214
|
+
/** Maps invoke failure kind to MCP tools/call error text (respects obscureUnexpected). */
|
|
215
|
+
export function headlessFailureMcpMessage(result: HeadlessToolCallFailure, obscureUnexpected = false): string {
|
|
216
|
+
if (obscureUnexpected && result.failureKind === "unexpected") {
|
|
217
|
+
return obscureUnexpectedClientMessage();
|
|
218
|
+
}
|
|
219
|
+
return firstErrorLine(result.message);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Missing-config lookup failures as MCP/HTTP pre-invoke errors. */
|
|
223
|
+
export function missingConfigFailureKind(): InvokeFailureKind {
|
|
224
|
+
return "missing_config";
|
|
225
|
+
}
|