toolfactory 0.1.1 → 0.2.0

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.
Files changed (110) hide show
  1. package/README.md +31 -3
  2. package/dist/bindings/python.js +1 -1
  3. package/dist/commands.d.ts +1 -1
  4. package/dist/distribution/native.d.ts +50 -0
  5. package/dist/distribution/native.js +414 -0
  6. package/dist/distribution/native.test.d.ts +1 -0
  7. package/dist/distribution/native.test.js +127 -0
  8. package/dist/distribution/system.d.ts +57 -0
  9. package/dist/distribution/system.js +637 -0
  10. package/dist/distribution/system.test.d.ts +1 -0
  11. package/dist/distribution/system.test.js +116 -0
  12. package/dist/e2e.test.js +7 -1
  13. package/dist/hosts/openclaw.js +6 -2
  14. package/dist/hosts/vscode.d.ts +1 -0
  15. package/dist/hosts/vscode.js +67 -0
  16. package/dist/model.d.ts +63 -2
  17. package/dist/model.js +18 -1
  18. package/dist/ops.d.ts +52 -0
  19. package/dist/project/apply.d.ts +1 -1
  20. package/dist/project/apply.js +194 -17
  21. package/dist/project/apply.test.js +103 -0
  22. package/dist/project/gate.d.ts +17 -2
  23. package/dist/project/gate.js +102 -23
  24. package/dist/project/history.d.ts +30 -1
  25. package/dist/project/lock.d.ts +5 -0
  26. package/dist/project/lock.js +9 -0
  27. package/dist/surfaces/agent-plugins.js +5 -4
  28. package/dist/surfaces/agents.js +27 -3
  29. package/dist/surfaces/agents.test.js +12 -0
  30. package/dist/surfaces/claude.js +8 -3
  31. package/dist/surfaces/codex.js +9 -4
  32. package/dist/surfaces/codex.test.js +16 -6
  33. package/dist/surfaces/cursor.js +2 -2
  34. package/dist/surfaces/distribution.test.js +121 -7
  35. package/dist/surfaces/dsh.js +29 -7
  36. package/dist/surfaces/dsh.test.js +11 -6
  37. package/dist/surfaces/gemini.js +2 -2
  38. package/dist/surfaces/gemini.test.js +4 -4
  39. package/dist/surfaces/hermes-native.js +43 -12
  40. package/dist/surfaces/hermes-native.test.js +53 -11
  41. package/dist/surfaces/mcp-registry.js +59 -7
  42. package/dist/surfaces/mcp-registry.test.js +23 -0
  43. package/dist/surfaces/mcpb.d.ts +1 -0
  44. package/dist/surfaces/mcpb.js +36 -23
  45. package/dist/surfaces/mcpb.test.js +31 -3
  46. package/dist/surfaces/npm.js +45 -14
  47. package/dist/surfaces/openclaw-native.js +10 -8
  48. package/dist/surfaces/openclaw-native.test.js +30 -0
  49. package/dist/surfaces/pypi.js +27 -3
  50. package/dist/surfaces/readme.d.ts +16 -0
  51. package/dist/surfaces/readme.js +17 -7
  52. package/dist/surfaces/registry.js +9 -3
  53. package/dist/surfaces/vscode-extension.d.ts +14 -0
  54. package/dist/surfaces/vscode-extension.js +312 -0
  55. package/dist/surfaces/vscode-extension.test.d.ts +1 -0
  56. package/dist/surfaces/vscode-extension.test.js +81 -0
  57. package/dist/surfaces/vscode-scaffold.d.ts +43 -0
  58. package/dist/surfaces/vscode-scaffold.js +43 -0
  59. package/dist/surfaces/workflows.js +57 -11
  60. package/dist/surfaces/workflows.test.js +71 -3
  61. package/dist/toolfactory/cli.js +1 -1
  62. package/dist/toolfactory/mcp.js +1 -1
  63. package/package.json +2 -1
  64. package/src/bindings/python.ts +1 -1
  65. package/src/distribution/native.test.ts +161 -0
  66. package/src/distribution/native.ts +460 -0
  67. package/src/distribution/system.test.ts +136 -0
  68. package/src/distribution/system.ts +688 -0
  69. package/src/e2e.test.ts +7 -1
  70. package/src/hosts/openclaw.ts +4 -2
  71. package/src/hosts/vscode.ts +79 -0
  72. package/src/model.ts +26 -2
  73. package/src/project/apply.test.ts +120 -0
  74. package/src/project/apply.ts +257 -15
  75. package/src/project/gate.ts +131 -24
  76. package/src/project/lock.ts +12 -0
  77. package/src/surfaces/agent-plugins.ts +5 -4
  78. package/src/surfaces/agents.test.ts +16 -0
  79. package/src/surfaces/agents.ts +38 -3
  80. package/src/surfaces/claude.ts +7 -3
  81. package/src/surfaces/codex.test.ts +15 -5
  82. package/src/surfaces/codex.ts +12 -6
  83. package/src/surfaces/cursor.ts +2 -10
  84. package/src/surfaces/distribution.test.ts +141 -6
  85. package/src/surfaces/dsh.test.ts +11 -5
  86. package/src/surfaces/dsh.ts +30 -7
  87. package/src/surfaces/gemini.test.ts +3 -3
  88. package/src/surfaces/gemini.ts +1 -2
  89. package/src/surfaces/hermes-native.test.ts +61 -10
  90. package/src/surfaces/hermes-native.ts +46 -13
  91. package/src/surfaces/mcp-registry.test.ts +28 -0
  92. package/src/surfaces/mcp-registry.ts +66 -8
  93. package/src/surfaces/mcpb.test.ts +32 -5
  94. package/src/surfaces/mcpb.ts +44 -23
  95. package/src/surfaces/npm.ts +47 -15
  96. package/src/surfaces/openclaw-native.test.ts +37 -0
  97. package/src/surfaces/openclaw-native.ts +49 -47
  98. package/src/surfaces/pypi.ts +27 -3
  99. package/src/surfaces/readme.ts +21 -6
  100. package/src/surfaces/registry.ts +9 -3
  101. package/src/surfaces/vscode-extension.test.ts +89 -0
  102. package/src/surfaces/vscode-extension.ts +345 -0
  103. package/src/surfaces/vscode-scaffold.ts +55 -0
  104. package/src/surfaces/workflows.test.ts +86 -3
  105. package/src/surfaces/workflows.ts +57 -11
  106. package/src/toolfactory/cli.ts +1 -1
  107. package/src/toolfactory/mcp.ts +1 -1
  108. package/web/dist/assets/{index-CCXhQKK3.css → index-BuT2czb2.css} +1 -1
  109. package/web/dist/assets/{index-D1PwZ3qS.js → index-CVm6m4s0.js} +1 -1
  110. package/web/dist/index.html +2 -2
@@ -0,0 +1,116 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { systemPackageConfigSchema, systemPackageJobs, systemPackageSteps, systemPublishJobs, systemRegistryRows, } from "./system.js";
3
+ function project(entries, surfaces = entries.map((entry) => entry.id)) {
4
+ return {
5
+ root: "/local/never-in-output",
6
+ tool: {
7
+ schemaVersion: 1,
8
+ identity: "package.json",
9
+ binding: "typescript",
10
+ surfaces: surfaces,
11
+ bundle: { runtime: "package" },
12
+ tests: { examples: {} },
13
+ systemPackages: entries,
14
+ },
15
+ identity: { name: "tool", version: "1.2.3" },
16
+ identityExtra: {},
17
+ operations: [],
18
+ toolfactoryVersion: "0.1.0",
19
+ };
20
+ }
21
+ const choco = {
22
+ id: "chocolatey",
23
+ path: "packaging/choco",
24
+ identity: "tool.nuspec",
25
+ name: "tool",
26
+ versionCommand: "node -p \"require('./tool.nuspec.version.json').version\"",
27
+ };
28
+ describe("system packages", () => {
29
+ it("requires real catalog/repository configuration", () => {
30
+ expect(() => systemPackageConfigSchema.parse({ ...choco, id: "apt" })).toThrow(/PPA/);
31
+ expect(() => systemPackageConfigSchema.parse({
32
+ id: "scoop",
33
+ path: "packaging/scoop",
34
+ identity: "tool.json",
35
+ name: "tool",
36
+ versionCommand: "Get-Content VERSION",
37
+ buildCommand: "./build.ps1",
38
+ asset: "../tool.zip",
39
+ bucket: "acme/scoop-bucket",
40
+ bucketName: "acme",
41
+ catalogPath: "bucket/tool.json",
42
+ })).toThrow(/path must stay/);
43
+ expect(() => systemPackageSteps(project([], ["chocolatey"]))).toThrow(/exactly one/);
44
+ });
45
+ it("packages with checkout-relative paths", () => {
46
+ const steps = systemPackageSteps(project([choco]), { local: false });
47
+ expect(steps.at(-1)?.run).toContain("choco pack 'packaging/choco/tool.nuspec'");
48
+ expect(steps.at(-1)?.run).not.toContain("/local/never-in-output");
49
+ });
50
+ it("stages a non-root WinGet manifest directory and Debian source changes portably", () => {
51
+ const winget = {
52
+ id: "winget",
53
+ path: "packaging/winget",
54
+ identity: "manifests/a/acme/tool/1.2.3",
55
+ name: "Acme.Tool",
56
+ versionCommand: "cat VERSION",
57
+ buildCommand: "./build-installer.ps1",
58
+ asset: "dist/tool.msi",
59
+ };
60
+ const apt = {
61
+ id: "apt",
62
+ path: "packaging/debian/source",
63
+ identity: "debian/control",
64
+ name: "tool",
65
+ versionCommand: "dpkg-parsechangelog -S Version | cut -d- -f1",
66
+ ppa: "acme/tool",
67
+ buildDependencies: ["debhelper"],
68
+ };
69
+ const steps = systemPackageSteps(project([winget, apt]), { local: false });
70
+ expect(steps.find((step) => step.name === "WinGet catalog submission")?.run).toContain("test -d 'packaging/winget/manifests/a/acme/tool/1.2.3'");
71
+ const debian = steps.find((step) => step.name === "Debian source package")?.run;
72
+ expect(debian).toContain("find 'packaging/debian/source/..'");
73
+ expect(debian).toContain("'dist/release/system/apt'");
74
+ expect(debian).not.toContain("../dist/release");
75
+ });
76
+ it("gates direct jobs and commits author-controlled Homebrew metadata after release", () => {
77
+ const brew = {
78
+ id: "homebrew",
79
+ path: "packaging/brew",
80
+ identity: "tool.rb",
81
+ name: "tool",
82
+ versionCommand: "grep VERSION tool.rb",
83
+ buildCommand: "make release-archive",
84
+ asset: "dist/tool.tar.gz",
85
+ tap: "acme/homebrew-tap",
86
+ catalogPath: "Formula/tool.rb",
87
+ };
88
+ const jobs = systemPublishJobs(project([choco, brew]), "release-assets", "${{ needs.gate.outputs.sha }}");
89
+ expect(jobs["publish-chocolatey"]?.if).toBe("needs.gate.outputs.chocolatey == 'true'");
90
+ expect(jobs["publish-homebrew"]?.needs).toEqual(["gate", "release"]);
91
+ expect(JSON.stringify(jobs["publish-homebrew"])).toContain("git -C .system-catalog push");
92
+ expect(JSON.stringify(jobs["publish-homebrew"])).toContain("system-homebrew");
93
+ expect(JSON.stringify(jobs["publish-homebrew"])).toContain("toolfactory-postrelease/tap");
94
+ expect(JSON.stringify(jobs["publish-chocolatey"])).toContain("system-chocolatey");
95
+ expect(JSON.stringify(jobs)).not.toContain("/local/never-in-output");
96
+ expect(systemRegistryRows(project([choco])).at(0)?.secrets).toEqual(["CHOCOLATEY_API_KEY"]);
97
+ });
98
+ it("uses dedicated native runners and upload names instead of the Ubuntu package job", () => {
99
+ const brew = {
100
+ id: "homebrew",
101
+ path: "packaging/brew",
102
+ identity: "tool.rb",
103
+ name: "tool",
104
+ versionCommand: "grep VERSION tool.rb",
105
+ buildCommand: "make release-archive",
106
+ asset: "dist/tool.tar.gz",
107
+ tap: "acme/homebrew-tap",
108
+ catalogPath: "Formula/tool.rb",
109
+ };
110
+ const jobs = systemPackageJobs(project([choco, brew]), "${{ github.sha }}");
111
+ expect(jobs["system-homebrew"]?.["runs-on"]).toBe("macos-latest");
112
+ expect(jobs["system-chocolatey"]?.["runs-on"]).toBe("windows-latest");
113
+ expect(JSON.stringify(jobs["system-chocolatey"])).toContain("system-chocolatey");
114
+ expect(JSON.stringify(jobs)).not.toContain("/local/never-in-output");
115
+ });
116
+ });
package/dist/e2e.test.js CHANGED
@@ -119,6 +119,12 @@ describe.skipIf(!existsSync(repoNodeModules))("confluence: a walked tree equals
119
119
  await commands.introspect(fresh);
120
120
  authorProse(fresh);
121
121
  commands.build(fresh);
122
- expect(tree(walked)).toEqual(tree(fresh));
122
+ const walkedTree = tree(walked);
123
+ // Deselecting a region surface preserves its author-owned scaffold, including an empty
124
+ // Docker ignore file. All managed bytes still converge with the freshly generated tree.
125
+ expect(walkedTree[".dockerignore"]).toContain("# tf:dockerignore# /tf:dockerignore");
126
+ expect(walkedTree[".dockerignore"]).not.toContain("node_modules/");
127
+ delete walkedTree[".dockerignore"];
128
+ expect(walkedTree).toEqual(tree(fresh));
123
129
  });
124
130
  });
@@ -56,9 +56,13 @@ function missing(scaffold, ours, path, skip) {
56
56
  }
57
57
  function planned(files, path) {
58
58
  const file = files.find((candidate) => candidate.path === `${HOST_DIR}/${path}`);
59
- if (file?.kind !== "file")
59
+ if (!file)
60
60
  throw new Error(`the openclaw surface no longer plans ${path}`);
61
- return file.content;
61
+ if (file.kind === "file")
62
+ return file.content;
63
+ if (file.kind === "merge" && file.format === "json")
64
+ return JSON.stringify(file.patch, null, 2);
65
+ throw new Error(`the openclaw surface no longer plans ${path} as JSON`);
62
66
  }
63
67
  /** Human-readable drift lines; empty means the generator still mirrors upstream. */
64
68
  export function scaffoldDrift(project) {
@@ -0,0 +1 @@
1
+ export declare function scaffoldDrift(): string[];
@@ -0,0 +1,67 @@
1
+ /** Verify the extension scaffold against Microsoft's generator, without touching the checkout. */
2
+ import { execFileSync } from "node:child_process";
3
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { argv } from "node:process";
7
+ import { fileURLToPath } from "node:url";
8
+ import { ESBUILD, ESLINT, GITIGNORE, IGNORE, LAUNCH, TASKS, VSCODE_GENERATOR, VSCODE_SCAFFOLD, } from "../surfaces/vscode-scaffold.js";
9
+ export function scaffoldDrift() {
10
+ const root = mkdtempSync(join(tmpdir(), "toolfactory-vscode-scaffold-"));
11
+ const target = join(root, "probe");
12
+ try {
13
+ execFileSync("npx", [
14
+ "--yes",
15
+ "--package",
16
+ "yo",
17
+ "--package",
18
+ `generator-code@${VSCODE_GENERATOR}`,
19
+ "--",
20
+ "yo",
21
+ "code",
22
+ target,
23
+ "--extensionType",
24
+ "ts",
25
+ "--extensionDisplayName",
26
+ "ToolFactory Probe",
27
+ "--extensionId",
28
+ "tf-probe",
29
+ "--extensionDescription",
30
+ "ToolFactory scaffold probe",
31
+ "--pkgManager",
32
+ "npm",
33
+ "--bundler",
34
+ "esbuild",
35
+ "--gitInit",
36
+ "false",
37
+ "--skip-install",
38
+ "--skipOpen",
39
+ "--quick",
40
+ ], { stdio: "pipe", cwd: root });
41
+ const pkg = JSON.parse(readFileSync(join(target, "package.json"), "utf8"));
42
+ const drift = Object.entries(VSCODE_SCAFFOLD)
43
+ .filter(([key, expected]) => JSON.stringify(pkg[key]) !== JSON.stringify(expected))
44
+ .map(([key]) => `package.json ${key}`);
45
+ for (const [path, expected] of [
46
+ ["esbuild.js", ESBUILD],
47
+ ["eslint.config.mjs", ESLINT],
48
+ [".vscodeignore", IGNORE],
49
+ [".gitignore", GITIGNORE],
50
+ [".vscode/launch.json", LAUNCH],
51
+ [".vscode/tasks.json", TASKS],
52
+ ]) {
53
+ if (readFileSync(join(target, path), "utf8") !== expected)
54
+ drift.push(path);
55
+ }
56
+ return drift;
57
+ }
58
+ finally {
59
+ rmSync(root, { recursive: true, force: true });
60
+ }
61
+ }
62
+ if (argv[1] === fileURLToPath(import.meta.url)) {
63
+ const drift = scaffoldDrift();
64
+ if (drift.length)
65
+ throw new Error(`VS Code scaffold drifted: ${drift.join(", ")}`);
66
+ process.stdout.write("VS Code scaffold matches generator-code.\n");
67
+ }
package/dist/model.d.ts CHANGED
@@ -10,7 +10,7 @@ import { z } from "zod";
10
10
  export declare const CAPABILITIES: readonly ["net", "fs", "shell", "secret", "browser", "model", "user-input", "channel"];
11
11
  export type Capability = (typeof CAPABILITIES)[number];
12
12
  export declare const PORTABLE_CAPABILITIES: ReadonlySet<Capability>;
13
- export declare const SURFACE_IDS: readonly ["skill", "agent-plugins", "claude", "codex", "cursor", "mcp", "mcp-registry", "cli", "npm", "pypi", "openclaw-native", "hermes-native", "clawhub", "web", "dsh", "workflows", "agents", "readme", "gemini", "mcpb", "browser-extension"];
13
+ export declare const SURFACE_IDS: readonly ["skill", "agent-plugins", "claude", "codex", "cursor", "mcp", "mcp-registry", "cli", "npm", "pypi", "openclaw-native", "hermes-native", "clawhub", "web", "dsh", "workflows", "agents", "readme", "gemini", "mcpb", "browser-extension", "vscode-extension", "cargo", "nuget", "maven-central", "rubygems", "packagist", "go-module", "homebrew", "winget", "scoop", "chocolatey", "apt", "rpm"];
14
14
  export type SurfaceId = (typeof SURFACE_IDS)[number];
15
15
  export declare const BINDINGS: readonly ["typescript", "python"];
16
16
  export type Binding = (typeof BINDINGS)[number];
@@ -41,6 +41,12 @@ export declare const ToolConfigSchema: z.ZodObject<{
41
41
  none: "none";
42
42
  }>>;
43
43
  surfaces: z.ZodArray<z.ZodEnum<{
44
+ homebrew: "homebrew";
45
+ winget: "winget";
46
+ scoop: "scoop";
47
+ chocolatey: "chocolatey";
48
+ apt: "apt";
49
+ rpm: "rpm";
44
50
  skill: "skill";
45
51
  "agent-plugins": "agent-plugins";
46
52
  claude: "claude";
@@ -62,6 +68,13 @@ export declare const ToolConfigSchema: z.ZodObject<{
62
68
  gemini: "gemini";
63
69
  mcpb: "mcpb";
64
70
  "browser-extension": "browser-extension";
71
+ "vscode-extension": "vscode-extension";
72
+ cargo: "cargo";
73
+ nuget: "nuget";
74
+ "maven-central": "maven-central";
75
+ rubygems: "rubygems";
76
+ packagist: "packagist";
77
+ "go-module": "go-module";
65
78
  }>>;
66
79
  kernel: z.ZodOptional<z.ZodObject<{
67
80
  command: z.ZodString;
@@ -82,6 +95,7 @@ export declare const ToolConfigSchema: z.ZodObject<{
82
95
  }, z.core.$strip>>;
83
96
  codex: z.ZodOptional<z.ZodObject<{
84
97
  interface: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
98
+ mcp: z.ZodDefault<z.ZodBoolean>;
85
99
  }, z.core.$strip>>;
86
100
  browserExtension: z.ZodOptional<z.ZodObject<{
87
101
  endpoint: z.ZodOptional<z.ZodString>;
@@ -98,6 +112,48 @@ export declare const ToolConfigSchema: z.ZodObject<{
98
112
  hermes: z.ZodOptional<z.ZodObject<{
99
113
  toolset: z.ZodOptional<z.ZodString>;
100
114
  }, z.core.$strip>>;
115
+ vscode: z.ZodOptional<z.ZodObject<{
116
+ publisher: z.ZodOptional<z.ZodString>;
117
+ marketplace: z.ZodDefault<z.ZodBoolean>;
118
+ openvsx: z.ZodDefault<z.ZodBoolean>;
119
+ }, z.core.$strip>>;
120
+ nativePackages: z.ZodOptional<z.ZodArray<z.ZodObject<{
121
+ id: z.ZodEnum<{
122
+ cargo: "cargo";
123
+ nuget: "nuget";
124
+ "maven-central": "maven-central";
125
+ rubygems: "rubygems";
126
+ packagist: "packagist";
127
+ "go-module": "go-module";
128
+ }>;
129
+ path: z.ZodString;
130
+ identity: z.ZodString;
131
+ name: z.ZodString;
132
+ versionCommand: z.ZodOptional<z.ZodString>;
133
+ }, z.core.$strict>>>;
134
+ systemPackages: z.ZodOptional<z.ZodArray<z.ZodObject<{
135
+ id: z.ZodEnum<{
136
+ homebrew: "homebrew";
137
+ winget: "winget";
138
+ scoop: "scoop";
139
+ chocolatey: "chocolatey";
140
+ apt: "apt";
141
+ rpm: "rpm";
142
+ }>;
143
+ path: z.ZodString;
144
+ identity: z.ZodString;
145
+ name: z.ZodString;
146
+ versionCommand: z.ZodString;
147
+ buildCommand: z.ZodOptional<z.ZodString>;
148
+ buildDependencies: z.ZodDefault<z.ZodArray<z.ZodString>>;
149
+ asset: z.ZodOptional<z.ZodString>;
150
+ tap: z.ZodOptional<z.ZodString>;
151
+ bucket: z.ZodOptional<z.ZodString>;
152
+ bucketName: z.ZodOptional<z.ZodString>;
153
+ catalogPath: z.ZodOptional<z.ZodString>;
154
+ ppa: z.ZodOptional<z.ZodString>;
155
+ coprProject: z.ZodOptional<z.ZodString>;
156
+ }, z.core.$strict>>>;
101
157
  openclaw: z.ZodOptional<z.ZodObject<{
102
158
  registers: z.ZodOptional<z.ZodArray<z.ZodObject<{
103
159
  api: z.ZodString;
@@ -182,10 +238,15 @@ export interface RegionFile {
182
238
  export interface MergeFile {
183
239
  kind: "merge";
184
240
  path: string;
185
- format: "json" | "toml";
241
+ format: "json" | "toml" | "yaml";
186
242
  patch: Record<string, unknown>;
187
243
  /** Dotted paths inside `patch` whose object toolfactory owns whole: replaced, never merged. */
188
244
  owned?: string[];
245
+ /**
246
+ * Arrays whose entries are shared by a stable identifier. Toolfactory replaces only entries it
247
+ * previously wrote, preserves the author's other entries, and rejects an id collision.
248
+ */
249
+ keyedArrays?: Record<string, string>;
189
250
  }
190
251
  export type PlannedFile = FullFile | RegionFile | MergeFile;
191
252
  export interface Command {
package/dist/model.js CHANGED
@@ -7,6 +7,9 @@
7
7
  * rest is derived and written in-tree, tracked by a lock file.
8
8
  */
9
9
  import { z } from "zod";
10
+ import { NATIVE_PACKAGE_IDS, nativePackageConfigSchema } from "./distribution/native.js";
11
+ import { SYSTEM_PACKAGE_IDS, systemPackageConfigSchema } from "./distribution/system.js";
12
+ import { vscodeConfigSchema } from "./surfaces/vscode-extension.js";
10
13
  export const CAPABILITIES = [
11
14
  "net",
12
15
  "fs",
@@ -45,6 +48,9 @@ export const SURFACE_IDS = [
45
48
  "gemini",
46
49
  "mcpb",
47
50
  "browser-extension",
51
+ "vscode-extension",
52
+ ...NATIVE_PACKAGE_IDS,
53
+ ...SYSTEM_PACKAGE_IDS,
48
54
  ];
49
55
  export const BINDINGS = ["typescript", "python"];
50
56
  /**
@@ -100,7 +106,15 @@ export const ToolConfigSchema = z
100
106
  .default({ examples: {} })
101
107
  .describe("Example arguments per operation, used by the generated surface-smoke tests."),
102
108
  npm: z.object({ scope: z.string().optional() }).optional(),
103
- codex: z.object({ interface: jsonObject.optional() }).optional(),
109
+ codex: z
110
+ .object({
111
+ interface: jsonObject.optional(),
112
+ mcp: z
113
+ .boolean()
114
+ .default(true)
115
+ .describe("Whether the Codex plugin manifest eagerly configures the generated MCP server."),
116
+ })
117
+ .optional(),
104
118
  browserExtension: z
105
119
  .object({
106
120
  endpoint: z
@@ -138,6 +152,9 @@ export const ToolConfigSchema = z
138
152
  .optional()
139
153
  .describe("Privacy-policy URLs of the services this tool talks to; Anthropic's Connectors Directory submission requires them in the MCPB manifest."),
140
154
  hermes: z.object({ toolset: z.string().optional() }).optional(),
155
+ vscode: vscodeConfigSchema.optional(),
156
+ nativePackages: z.array(nativePackageConfigSchema).optional(),
157
+ systemPackages: z.array(systemPackageConfigSchema).optional(),
141
158
  openclaw: z
142
159
  .object({
143
160
  registers: z
package/dist/ops.d.ts CHANGED
@@ -16,6 +16,12 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
16
16
  none: "none";
17
17
  }>>;
18
18
  surfaces: z.ZodOptional<z.ZodArray<z.ZodEnum<{
19
+ homebrew: "homebrew";
20
+ winget: "winget";
21
+ scoop: "scoop";
22
+ chocolatey: "chocolatey";
23
+ apt: "apt";
24
+ rpm: "rpm";
19
25
  skill: "skill";
20
26
  "agent-plugins": "agent-plugins";
21
27
  claude: "claude";
@@ -37,6 +43,13 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
37
43
  gemini: "gemini";
38
44
  mcpb: "mcpb";
39
45
  "browser-extension": "browser-extension";
46
+ "vscode-extension": "vscode-extension";
47
+ cargo: "cargo";
48
+ nuget: "nuget";
49
+ "maven-central": "maven-central";
50
+ rubygems: "rubygems";
51
+ packagist: "packagist";
52
+ "go-module": "go-module";
40
53
  }>>>;
41
54
  description: z.ZodOptional<z.ZodString>;
42
55
  license: z.ZodOptional<z.ZodString>;
@@ -86,6 +99,12 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
86
99
  }, z.core.$strip>> | import("./toolfactory/types.js").Operation<z.ZodObject<{
87
100
  root: z.ZodDefault<z.ZodString>;
88
101
  surface: z.ZodOptional<z.ZodEnum<{
102
+ homebrew: "homebrew";
103
+ winget: "winget";
104
+ scoop: "scoop";
105
+ chocolatey: "chocolatey";
106
+ apt: "apt";
107
+ rpm: "rpm";
89
108
  skill: "skill";
90
109
  "agent-plugins": "agent-plugins";
91
110
  claude: "claude";
@@ -107,6 +126,13 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
107
126
  gemini: "gemini";
108
127
  mcpb: "mcpb";
109
128
  "browser-extension": "browser-extension";
129
+ "vscode-extension": "vscode-extension";
130
+ cargo: "cargo";
131
+ nuget: "nuget";
132
+ "maven-central": "maven-central";
133
+ rubygems: "rubygems";
134
+ packagist: "packagist";
135
+ "go-module": "go-module";
110
136
  }>>;
111
137
  }, z.core.$strip>, z.ZodObject<{
112
138
  outcomes: z.ZodArray<z.ZodObject<{
@@ -138,6 +164,12 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
138
164
  }, z.core.$strip>> | import("./toolfactory/types.js").Operation<z.ZodObject<{
139
165
  root: z.ZodDefault<z.ZodString>;
140
166
  surface: z.ZodEnum<{
167
+ homebrew: "homebrew";
168
+ winget: "winget";
169
+ scoop: "scoop";
170
+ chocolatey: "chocolatey";
171
+ apt: "apt";
172
+ rpm: "rpm";
141
173
  skill: "skill";
142
174
  "agent-plugins": "agent-plugins";
143
175
  claude: "claude";
@@ -159,6 +191,13 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
159
191
  gemini: "gemini";
160
192
  mcpb: "mcpb";
161
193
  "browser-extension": "browser-extension";
194
+ "vscode-extension": "vscode-extension";
195
+ cargo: "cargo";
196
+ nuget: "nuget";
197
+ "maven-central": "maven-central";
198
+ rubygems: "rubygems";
199
+ packagist: "packagist";
200
+ "go-module": "go-module";
162
201
  }>;
163
202
  }, z.core.$strip>, z.ZodObject<{
164
203
  adopted: z.ZodArray<z.ZodString>;
@@ -209,6 +248,12 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
209
248
  }, z.core.$strip>, z.ZodObject<{
210
249
  from: z.ZodOptional<z.ZodString>;
211
250
  dropped: z.ZodArray<z.ZodEnum<{
251
+ homebrew: "homebrew";
252
+ winget: "winget";
253
+ scoop: "scoop";
254
+ chocolatey: "chocolatey";
255
+ apt: "apt";
256
+ rpm: "rpm";
212
257
  skill: "skill";
213
258
  "agent-plugins": "agent-plugins";
214
259
  claude: "claude";
@@ -230,6 +275,13 @@ export declare const operations: (import("./toolfactory/types.js").Operation<z.Z
230
275
  gemini: "gemini";
231
276
  mcpb: "mcpb";
232
277
  "browser-extension": "browser-extension";
278
+ "vscode-extension": "vscode-extension";
279
+ cargo: "cargo";
280
+ nuget: "nuget";
281
+ "maven-central": "maven-central";
282
+ rubygems: "rubygems";
283
+ packagist: "packagist";
284
+ "go-module": "go-module";
233
285
  }>>;
234
286
  steps: z.ZodArray<z.ZodObject<{
235
287
  name: z.ZodString;
@@ -23,7 +23,7 @@ export declare function deepMerge(base: Record<string, unknown>, patch: Record<s
23
23
  /** The values a merge file owns, read back out of a document; an owned object comes back whole. */
24
24
  export declare function pickPatch(document: Record<string, unknown>, patch: Record<string, unknown>, owned?: string[], prefix?: string): Record<string, unknown>;
25
25
  /** The dotted paths a patch writes: one per leaf value, and one per object it owns whole. */
26
- export declare function patchKeys(patch: Record<string, unknown>, owned?: string[], prefix?: string): string[];
26
+ export declare function patchKeys(patch: Record<string, unknown>, owned?: string[], keyedArrays?: Record<string, string>, prefix?: string): string[];
27
27
  /** Uninstall dotted paths from a document, pruning the objects the removal empties. */
28
28
  export declare function removeKeys(document: Record<string, unknown>, keys: readonly string[]): boolean;
29
29
  /** The content toolfactory manages, as one string for hashing and comparison. */