poe-code 3.0.187 → 3.0.189

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 (95) hide show
  1. package/dist/cli/commands/experiment.js +1 -1
  2. package/dist/cli/commands/experiment.js.map +1 -1
  3. package/dist/cli/commands/pipeline-init.js +1 -1
  4. package/dist/cli/commands/pipeline-init.js.map +1 -1
  5. package/dist/cli/commands/pipeline.js +1 -1
  6. package/dist/cli/commands/pipeline.js.map +1 -1
  7. package/dist/cli/commands/spawn.js +2 -1
  8. package/dist/cli/commands/spawn.js.map +1 -1
  9. package/dist/cli/program.js +6 -6
  10. package/dist/cli/program.js.map +1 -1
  11. package/dist/index.js +122 -225
  12. package/dist/index.js.map +4 -4
  13. package/dist/prompts/github-issue-comment-created.md +1 -0
  14. package/dist/prompts/github-issue-opened.md +1 -0
  15. package/dist/prompts/github-pull-request-comment-created.md +1 -0
  16. package/dist/prompts/github-pull-request-opened.md +1 -0
  17. package/dist/prompts/github-pull-request-synchronized.md +1 -0
  18. package/dist/providers/claude-code.js +2 -76
  19. package/dist/providers/claude-code.js.map +4 -4
  20. package/dist/providers/codex.js +2 -76
  21. package/dist/providers/codex.js.map +4 -4
  22. package/dist/providers/goose.js +2 -76
  23. package/dist/providers/goose.js.map +4 -4
  24. package/dist/providers/kimi.js +2 -76
  25. package/dist/providers/kimi.js.map +4 -4
  26. package/dist/providers/opencode.js +2 -76
  27. package/dist/providers/opencode.js.map +4 -4
  28. package/dist/providers/poe-agent.js +23 -107
  29. package/dist/providers/poe-agent.js.map +4 -4
  30. package/dist/sdk/experiment.js +1 -1
  31. package/dist/sdk/experiment.js.map +1 -1
  32. package/package.json +10 -30
  33. package/packages/design-system/dist/prompts/primitives/cancel.d.ts +1 -1
  34. package/packages/design-system/dist/prompts/primitives/cancel.js +1 -1
  35. package/packages/cmdkit/dist/cli.compile-check.d.ts +0 -1
  36. package/packages/cmdkit/dist/cli.compile-check.js +0 -26
  37. package/packages/cmdkit/dist/cli.d.ts +0 -12
  38. package/packages/cmdkit/dist/cli.js +0 -2331
  39. package/packages/cmdkit/dist/cli.js.map +0 -7
  40. package/packages/cmdkit/dist/index.compile-check.d.ts +0 -1
  41. package/packages/cmdkit/dist/index.compile-check.js +0 -50
  42. package/packages/cmdkit/dist/index.d.ts +0 -164
  43. package/packages/cmdkit/dist/index.js +0 -561
  44. package/packages/cmdkit/dist/index.js.map +0 -7
  45. package/packages/cmdkit/dist/mcp.compile-check.d.ts +0 -1
  46. package/packages/cmdkit/dist/mcp.compile-check.js +0 -26
  47. package/packages/cmdkit/dist/mcp.d.ts +0 -31
  48. package/packages/cmdkit/dist/mcp.js +0 -1254
  49. package/packages/cmdkit/dist/mcp.js.map +0 -7
  50. package/packages/cmdkit/dist/number-schema.d.ts +0 -3
  51. package/packages/cmdkit/dist/number-schema.js +0 -8
  52. package/packages/cmdkit/dist/renderer.d.ts +0 -5
  53. package/packages/cmdkit/dist/renderer.js +0 -164
  54. package/packages/cmdkit/dist/renderer.js.map +0 -7
  55. package/packages/cmdkit/dist/schema-scope.d.ts +0 -4
  56. package/packages/cmdkit/dist/schema-scope.js +0 -34
  57. package/packages/cmdkit/dist/sdk.compile-check.d.ts +0 -1
  58. package/packages/cmdkit/dist/sdk.compile-check.js +0 -79
  59. package/packages/cmdkit/dist/sdk.d.ts +0 -63
  60. package/packages/cmdkit/dist/sdk.js +0 -369
  61. package/packages/cmdkit/dist/sdk.js.map +0 -7
  62. package/packages/cmdkit-openapi/dist/api-command.d.ts +0 -7
  63. package/packages/cmdkit-openapi/dist/api-command.js +0 -4
  64. package/packages/cmdkit-openapi/dist/auth/bearer-token-auth.d.ts +0 -8
  65. package/packages/cmdkit-openapi/dist/auth/bearer-token-auth.js +0 -216
  66. package/packages/cmdkit-openapi/dist/auth/types.d.ts +0 -9
  67. package/packages/cmdkit-openapi/dist/auth/types.js +0 -1
  68. package/packages/cmdkit-openapi/dist/bin/generate.d.ts +0 -40
  69. package/packages/cmdkit-openapi/dist/bin/generate.js +0 -248
  70. package/packages/cmdkit-openapi/dist/define-client.d.ts +0 -20
  71. package/packages/cmdkit-openapi/dist/define-client.js +0 -148
  72. package/packages/cmdkit-openapi/dist/generate.d.ts +0 -210
  73. package/packages/cmdkit-openapi/dist/generate.js +0 -1131
  74. package/packages/cmdkit-openapi/dist/group-by-noun.d.ts +0 -6
  75. package/packages/cmdkit-openapi/dist/group-by-noun.js +0 -17
  76. package/packages/cmdkit-openapi/dist/http.d.ts +0 -26
  77. package/packages/cmdkit-openapi/dist/http.js +0 -123
  78. package/packages/cmdkit-openapi/dist/index.d.ts +0 -12
  79. package/packages/cmdkit-openapi/dist/index.js +0 -6
  80. package/packages/cmdkit-openapi/dist/interpreter.d.ts +0 -6
  81. package/packages/cmdkit-openapi/dist/interpreter.js +0 -289
  82. package/packages/cmdkit-openapi/dist/lock.d.ts +0 -14
  83. package/packages/cmdkit-openapi/dist/lock.js +0 -48
  84. package/packages/cmdkit-openapi/dist/naming.d.ts +0 -24
  85. package/packages/cmdkit-openapi/dist/naming.js +0 -218
  86. package/packages/cmdkit-openapi/dist/request-shape.d.ts +0 -15
  87. package/packages/cmdkit-openapi/dist/request-shape.js +0 -5
  88. package/packages/cmdkit-openapi/dist/runtime.d.ts +0 -13
  89. package/packages/cmdkit-openapi/dist/runtime.js +0 -94
  90. package/packages/cmdkit-openapi/dist/spec-source.d.ts +0 -11
  91. package/packages/cmdkit-openapi/dist/spec-source.js +0 -63
  92. package/packages/cmdkit-schema/dist/index.compile-check.d.ts +0 -1
  93. package/packages/cmdkit-schema/dist/index.compile-check.js +0 -12
  94. package/packages/cmdkit-schema/dist/index.d.ts +0 -124
  95. package/packages/cmdkit-schema/dist/index.js +0 -175
@@ -1,216 +0,0 @@
1
- import { defineCommand, defineGroup, S, UserError } from "@poe-code/cmdkit";
2
- import { isCancel, password } from "@poe-code/design-system";
3
- import { createSecretStore } from "auth-store";
4
- import { requestJson } from "../http.js";
5
- const DEFAULT_COMMAND_PREFIX = "auth";
6
- const loginParams = S.Object({
7
- token: S.Optional(S.String({ description: "Bearer token to store." })),
8
- tokenStdin: S.Optional(S.Boolean({ description: "Read the token from stdin instead of prompting." })),
9
- });
10
- const emptyParams = S.Object({});
11
- const KEYCHAIN_ACCOUNT = "token";
12
- const DEFAULT_STORE_DIRECTORY = ".cmdkit-openapi";
13
- const DEFAULT_STORE_VERSION = "v1";
14
- export function bearerTokenAuth(options) {
15
- const commandPrefix = options.commandPrefix ?? DEFAULT_COMMAND_PREFIX;
16
- const { store, backend } = createSecretStore({
17
- fileStore: {
18
- salt: `${options.serviceName}:cmdkit-openapi:${DEFAULT_STORE_VERSION}`,
19
- defaultDirectory: DEFAULT_STORE_DIRECTORY,
20
- defaultFileName: `${options.serviceName}.enc`,
21
- },
22
- keychainStore: {
23
- service: options.serviceName,
24
- account: KEYCHAIN_ACCOUNT,
25
- },
26
- });
27
- async function resolveToken() {
28
- const envToken = normalizeToken(process.env[options.envVar]);
29
- if (envToken) {
30
- return {
31
- token: envToken,
32
- tokenSource: `env (${options.envVar})`,
33
- };
34
- }
35
- const storedToken = normalizeToken(await store.get());
36
- if (!storedToken) {
37
- return null;
38
- }
39
- return {
40
- token: storedToken,
41
- tokenSource: backend,
42
- };
43
- }
44
- const loginCommand = defineCommand({
45
- name: "login",
46
- description: "Store a bearer token for future requests.",
47
- params: loginParams,
48
- handler: async (ctx) => {
49
- const token = await resolveLoginToken(ctx.params, ctx.readStdin);
50
- const identity = await resolveIdentity(token, ctx, options.whoamiPath);
51
- if (options.whoamiPath !== undefined && identity.isEmployee !== true) {
52
- throw new UserError("Authenticated account is not an employee.");
53
- }
54
- await store.set(token);
55
- return {
56
- email: identity.email,
57
- isEmployee: identity.isEmployee,
58
- storageBackend: backend,
59
- };
60
- },
61
- render: {
62
- rich: (result, { logger }) => {
63
- logger.success(formatLoginMessage(result));
64
- logger.message(result.storageBackend === "keychain"
65
- ? "Stored in macOS Keychain."
66
- : "Stored in encrypted file store.");
67
- },
68
- json: (result) => result,
69
- },
70
- });
71
- const logoutCommand = defineCommand({
72
- name: "logout",
73
- description: "Remove the stored bearer token.",
74
- params: emptyParams,
75
- handler: async () => {
76
- await store.delete();
77
- return {
78
- storageBackend: backend,
79
- };
80
- },
81
- render: {
82
- rich: (_result, { logger }) => {
83
- logger.success("Removed stored credential.");
84
- },
85
- json: (result) => result,
86
- },
87
- });
88
- const statusCommand = defineCommand({
89
- name: "status",
90
- description: "Show where the current bearer token resolves from.",
91
- params: emptyParams,
92
- handler: async (ctx) => {
93
- const resolvedToken = await resolveToken();
94
- if (!resolvedToken) {
95
- return { loggedIn: false };
96
- }
97
- const identity = await resolveIdentity(resolvedToken.token, ctx, options.whoamiPath);
98
- return {
99
- loggedIn: true,
100
- tokenSource: resolvedToken.tokenSource,
101
- email: identity.email,
102
- isEmployee: identity.isEmployee,
103
- };
104
- },
105
- render: {
106
- rich: (result, { logger }) => {
107
- if (!result.loggedIn) {
108
- logger.message("Not logged in.");
109
- return;
110
- }
111
- logger.success(result.email ? `Logged in as ${result.email}` : "Logged in.");
112
- logger.message(`Token source: ${result.tokenSource}`);
113
- },
114
- json: (result) => result,
115
- },
116
- });
117
- return {
118
- async getToken() {
119
- const resolvedToken = await resolveToken();
120
- if (resolvedToken) {
121
- return resolvedToken.token;
122
- }
123
- throw new UserError(`Run '${commandPrefix} login' first.`);
124
- },
125
- async invalidate() {
126
- await store.delete();
127
- },
128
- commands: [defineGroup({
129
- name: commandPrefix,
130
- description: "Manage stored bearer-token authentication.",
131
- scope: ["cli"],
132
- children: [loginCommand, logoutCommand, statusCommand],
133
- })],
134
- };
135
- }
136
- async function resolveLoginToken(params, readStdin) {
137
- const providedToken = normalizeToken(params.token);
138
- if (providedToken && params.tokenStdin) {
139
- throw new UserError("Pass either --token or --token-stdin, not both.");
140
- }
141
- if (providedToken) {
142
- return providedToken;
143
- }
144
- if (params.tokenStdin) {
145
- const stdinToken = normalizeToken(await (readStdin?.() ?? readAllFromStdin()));
146
- if (!stdinToken) {
147
- throw new UserError("Received an empty token from stdin.");
148
- }
149
- return stdinToken;
150
- }
151
- const promptedToken = await password({
152
- message: "Paste your API key:",
153
- });
154
- if (isCancel(promptedToken)) {
155
- throw new UserError("Authentication cancelled.");
156
- }
157
- const normalizedPromptedToken = normalizeToken(promptedToken);
158
- if (!normalizedPromptedToken) {
159
- throw new UserError("Token cannot be empty.");
160
- }
161
- return normalizedPromptedToken;
162
- }
163
- async function resolveIdentity(token, services, whoamiPath) {
164
- if (whoamiPath === undefined) {
165
- return {};
166
- }
167
- if (!services.baseUrl) {
168
- throw new UserError("Auth verification requires a baseUrl service.");
169
- }
170
- const response = await requestJson({
171
- baseUrl: services.baseUrl,
172
- path: whoamiPath,
173
- method: "GET",
174
- auth: "required",
175
- tokenSource: {
176
- getToken: async () => token,
177
- },
178
- fetch: services.fetch,
179
- });
180
- return parseIdentity(response);
181
- }
182
- function parseIdentity(response) {
183
- if (!isRecord(response)) {
184
- return {};
185
- }
186
- return {
187
- email: typeof response.email === "string" ? response.email : undefined,
188
- isEmployee: typeof response.is_employee === "boolean" ? response.is_employee : undefined,
189
- };
190
- }
191
- async function readAllFromStdin() {
192
- const chunks = [];
193
- for await (const chunk of process.stdin) {
194
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
195
- }
196
- return Buffer.concat(chunks).toString("utf8");
197
- }
198
- function normalizeToken(value) {
199
- if (typeof value !== "string") {
200
- return null;
201
- }
202
- const trimmed = value.trim();
203
- return trimmed.length > 0 ? trimmed : null;
204
- }
205
- function formatLoginMessage(result) {
206
- if (!result.email) {
207
- return "Authenticated.";
208
- }
209
- if (result.isEmployee === true) {
210
- return `Authenticated as ${result.email} (employee confirmed).`;
211
- }
212
- return `Authenticated as ${result.email}.`;
213
- }
214
- function isRecord(value) {
215
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
216
- }
@@ -1,9 +0,0 @@
1
- import type { CommandNode } from "@poe-code/cmdkit";
2
- export interface TokenSource {
3
- getToken(): Promise<string>;
4
- invalidate?(): Promise<void>;
5
- }
6
- export interface CommandContributor {
7
- commands: CommandNode<any>[];
8
- }
9
- export type AuthProvider = TokenSource & CommandContributor;
@@ -1 +0,0 @@
1
- export {};
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env node
2
- interface GenerateCliFileSystem {
3
- mkdir(directoryPath: string, options?: {
4
- recursive?: boolean;
5
- }): Promise<unknown>;
6
- readFile(filePath: string, encoding: BufferEncoding): Promise<string>;
7
- readdir(directoryPath: string): Promise<string[]>;
8
- rm(targetPath: string, options?: {
9
- force?: boolean;
10
- }): Promise<void>;
11
- stat(targetPath: string): Promise<{
12
- isDirectory(): boolean;
13
- }>;
14
- writeFile(filePath: string, contents: string, encoding: BufferEncoding): Promise<void>;
15
- }
16
- interface GenerateCliWriter {
17
- write(chunk: string | Uint8Array): boolean;
18
- }
19
- interface GenerateCliServices {
20
- cwd: string;
21
- fetch: typeof globalThis.fetch;
22
- fs: GenerateCliFileSystem;
23
- stderr: GenerateCliWriter;
24
- stdout: GenerateCliWriter;
25
- }
26
- interface GenerateCliOptions {
27
- check: boolean;
28
- input: string;
29
- lockPath: string;
30
- outputDir: string;
31
- }
32
- interface SyncGeneratedClientResult {
33
- deletedFileCount: number;
34
- drifted: boolean;
35
- specSha: string;
36
- updatedFileCount: number;
37
- }
38
- export declare function runGenerateCli(argv?: string[], services?: GenerateCliServices): Promise<number>;
39
- export declare function syncGeneratedClient(options: GenerateCliOptions, services: Pick<GenerateCliServices, "cwd" | "fetch" | "fs">): Promise<SyncGeneratedClientResult>;
40
- export {};
@@ -1,248 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createHash } from "node:crypto";
3
- import fs from "node:fs/promises";
4
- import { realpathSync } from "node:fs";
5
- import path from "node:path";
6
- import { fileURLToPath } from "node:url";
7
- import { UserError } from "@poe-code/cmdkit";
8
- import { generate } from "../generate.js";
9
- import { readOpenApiLock, writeOpenApiLock } from "../lock.js";
10
- import { parseOpenApiDocument, readOpenApiSourceText } from "../spec-source.js";
11
- const DEFAULT_OPTIONS = {
12
- check: false,
13
- input: "openapi.json",
14
- lockPath: "openapi.lock",
15
- outputDir: "src/generated"
16
- };
17
- const HELP_TEXT = `Usage: cmdkit-openapi-generate [options]
18
-
19
- Options:
20
- --input <path-or-url> OpenAPI document to read (default: openapi.json)
21
- --output <dir> Directory for generated command files (default: src/generated)
22
- --lock <path> Lock file path (default: openapi.lock)
23
- --check Exit non-zero if generated output or lock file would change
24
- -h, --help Show this help text
25
- `;
26
- export async function runGenerateCli(argv = process.argv, services = {
27
- cwd: process.cwd(),
28
- fetch: globalThis.fetch,
29
- fs,
30
- stderr: process.stderr,
31
- stdout: process.stdout
32
- }) {
33
- try {
34
- const parsed = parseGenerateCliArgs(argv.slice(2));
35
- if (parsed === "help") {
36
- services.stdout.write(HELP_TEXT);
37
- return 0;
38
- }
39
- const result = await syncGeneratedClient(parsed, services);
40
- if (parsed.check) {
41
- if (result.drifted) {
42
- services.stderr.write(`OpenAPI output is out of date for ${parsed.outputDir}. Run the generator without --check to update it.\n`);
43
- return 1;
44
- }
45
- services.stdout.write(`OpenAPI output is up to date (${result.specSha}).\n`);
46
- return 0;
47
- }
48
- if (result.drifted) {
49
- services.stdout.write(`Updated OpenAPI output (${result.updatedFileCount} written, ${result.deletedFileCount} deleted).\n`);
50
- return 0;
51
- }
52
- services.stdout.write(`OpenAPI output is up to date (${result.specSha}).\n`);
53
- return 0;
54
- }
55
- catch (error) {
56
- if (error instanceof UserError) {
57
- services.stderr.write(`${error.message}\n`);
58
- return 1;
59
- }
60
- throw error;
61
- }
62
- }
63
- export async function syncGeneratedClient(options, services) {
64
- const sourceText = await readOpenApiSourceText(options.input, services);
65
- const specSha = createSpecSha(sourceText);
66
- const document = parseOpenApiDocument(sourceText, options.input);
67
- const generatedFiles = generate(document, { specSha });
68
- const outputDir = path.resolve(services.cwd, options.outputDir);
69
- const lockPath = path.resolve(services.cwd, options.lockPath);
70
- const currentLock = await readOpenApiLock(services.fs, lockPath);
71
- const currentFiles = await readGeneratedFiles(services.fs, outputDir);
72
- const desiredFiles = new Map([
73
- ...generatedFiles.map((file) => [path.resolve(outputDir, file.path), file.contents]),
74
- ...createDownloadedSpecFiles(options.input, sourceText).map((file) => [path.resolve(outputDir, file.path), file.contents])
75
- ]);
76
- const updatedFiles = collectUpdatedFiles(currentFiles, desiredFiles);
77
- const deletedFiles = collectDeletedFiles(currentFiles, desiredFiles);
78
- const drifted = currentLock?.specSha !== specSha || updatedFiles.length > 0 || deletedFiles.length > 0;
79
- if (!options.check && drifted) {
80
- await writeGeneratedFiles(services.fs, updatedFiles);
81
- await deleteGeneratedFiles(services.fs, deletedFiles);
82
- await writeOpenApiLock(services.fs, lockPath, { specSha });
83
- }
84
- return {
85
- drifted,
86
- specSha,
87
- updatedFileCount: updatedFiles.length,
88
- deletedFileCount: deletedFiles.length
89
- };
90
- }
91
- function parseGenerateCliArgs(argv) {
92
- const options = { ...DEFAULT_OPTIONS };
93
- for (let index = 0; index < argv.length; index += 1) {
94
- const argument = argv[index] ?? "";
95
- if (argument === "-h" || argument === "--help") {
96
- return "help";
97
- }
98
- if (argument === "--check") {
99
- options.check = true;
100
- continue;
101
- }
102
- if (argument === "--input" || argument === "--output" || argument === "--lock") {
103
- const value = argv[index + 1];
104
- if (value === undefined) {
105
- throw new UserError(`Missing value for ${JSON.stringify(argument)}.`);
106
- }
107
- assignOptionValue(options, argument, value);
108
- index += 1;
109
- continue;
110
- }
111
- if (argument.startsWith("--input=")) {
112
- assignOptionValue(options, "--input", argument.slice("--input=".length));
113
- continue;
114
- }
115
- if (argument.startsWith("--output=")) {
116
- assignOptionValue(options, "--output", argument.slice("--output=".length));
117
- continue;
118
- }
119
- if (argument.startsWith("--lock=")) {
120
- assignOptionValue(options, "--lock", argument.slice("--lock=".length));
121
- continue;
122
- }
123
- throw new UserError(`Unknown argument ${JSON.stringify(argument)}.`);
124
- }
125
- return options;
126
- }
127
- function assignOptionValue(options, argument, value) {
128
- if (value.length === 0) {
129
- throw new UserError(`Missing value for ${JSON.stringify(argument)}.`);
130
- }
131
- if (argument === "--input") {
132
- options.input = value;
133
- return;
134
- }
135
- if (argument === "--output") {
136
- options.outputDir = value;
137
- return;
138
- }
139
- options.lockPath = value;
140
- }
141
- function createSpecSha(sourceText) {
142
- return `sha256:${createHash("sha256").update(sourceText).digest("hex")}`;
143
- }
144
- function createDownloadedSpecFiles(input, sourceText) {
145
- const inputUrl = tryParseUrl(input);
146
- if (inputUrl === null || (inputUrl.protocol !== "http:" && inputUrl.protocol !== "https:")) {
147
- return [];
148
- }
149
- return [
150
- {
151
- path: getDownloadedSpecFileName(inputUrl),
152
- contents: sourceText
153
- }
154
- ];
155
- }
156
- function getDownloadedSpecFileName(inputUrl) {
157
- const basename = path.posix.basename(inputUrl.pathname);
158
- return basename.length > 0 ? basename : "openapi.json";
159
- }
160
- function tryParseUrl(input) {
161
- if (input instanceof URL) {
162
- return input;
163
- }
164
- try {
165
- return new URL(input);
166
- }
167
- catch {
168
- return null;
169
- }
170
- }
171
- async function readGeneratedFiles(fs, directoryPath) {
172
- const files = new Map();
173
- try {
174
- const entries = await fs.readdir(directoryPath);
175
- for (const entry of entries) {
176
- const entryPath = path.resolve(directoryPath, entry);
177
- const stats = await fs.stat(entryPath);
178
- if (stats.isDirectory()) {
179
- for (const [nestedPath, nestedContents] of await readGeneratedFiles(fs, entryPath)) {
180
- files.set(nestedPath, nestedContents);
181
- }
182
- continue;
183
- }
184
- files.set(entryPath, await fs.readFile(entryPath, "utf8"));
185
- }
186
- }
187
- catch (error) {
188
- if (!isNotFoundError(error)) {
189
- throw error;
190
- }
191
- }
192
- return files;
193
- }
194
- function collectUpdatedFiles(currentFiles, desiredFiles) {
195
- const updatedFiles = [];
196
- for (const [filePath, contents] of desiredFiles) {
197
- if (currentFiles.get(filePath) === contents) {
198
- continue;
199
- }
200
- updatedFiles.push({ path: filePath, contents });
201
- }
202
- return updatedFiles;
203
- }
204
- function collectDeletedFiles(currentFiles, desiredFiles) {
205
- const deletedFiles = [];
206
- for (const filePath of currentFiles.keys()) {
207
- if (desiredFiles.has(filePath)) {
208
- continue;
209
- }
210
- deletedFiles.push(filePath);
211
- }
212
- return deletedFiles;
213
- }
214
- async function writeGeneratedFiles(fs, filesToWrite) {
215
- for (const file of filesToWrite) {
216
- await fs.mkdir(path.dirname(file.path), { recursive: true });
217
- await fs.writeFile(file.path, file.contents, "utf8");
218
- }
219
- }
220
- async function deleteGeneratedFiles(fs, filePaths) {
221
- for (const filePath of filePaths) {
222
- await fs.rm(filePath, { force: true });
223
- }
224
- }
225
- function isNotFoundError(error) {
226
- return (typeof error === "object" &&
227
- error !== null &&
228
- "code" in error &&
229
- error.code === "ENOENT");
230
- }
231
- function isDirectExecution(moduleUrl, argv) {
232
- const entryPoint = argv[1];
233
- if (entryPoint === undefined) {
234
- return false;
235
- }
236
- try {
237
- return path.resolve(fileURLToPath(moduleUrl)) === realpathSync(path.resolve(entryPoint));
238
- }
239
- catch {
240
- return false;
241
- }
242
- }
243
- if (isDirectExecution(import.meta.url, process.argv)) {
244
- const exitCode = await runGenerateCli();
245
- if (exitCode !== 0) {
246
- process.exit(exitCode);
247
- }
248
- }
@@ -1,20 +0,0 @@
1
- import type { CommandNode, Group } from "@poe-code/cmdkit";
2
- import type { AuthProvider, TokenSource } from "./auth/types.js";
3
- export interface OpenApiClientServices {
4
- baseUrl: string;
5
- tokenSource: TokenSource;
6
- }
7
- export interface DefineClientOptions<TServices extends object = Record<string, never>> {
8
- name: string;
9
- baseUrl: string;
10
- auth: AuthProvider;
11
- commands: CommandNode<OpenApiClientServices & TServices>[];
12
- handwrittenCommands?: CommandNode<OpenApiClientServices & TServices>[];
13
- }
14
- export interface DefinedClient<TServices extends object = Record<string, never>> {
15
- name: string;
16
- mcpPrefix: string;
17
- root: Group<OpenApiClientServices & TServices>;
18
- services: OpenApiClientServices;
19
- }
20
- export declare function defineClient<TServices extends object = Record<string, never>>(options: DefineClientOptions<TServices>): DefinedClient<TServices>;
@@ -1,148 +0,0 @@
1
- import { defineCommand, defineGroup, UserError } from "@poe-code/cmdkit";
2
- import { toMcpPrefix } from "./naming.js";
3
- const CLI_SCOPE = ["cli"];
4
- export function defineClient(options) {
5
- validateClientName(options.name);
6
- if (options.auth === undefined) {
7
- throw new UserError("defineClient requires an auth provider.");
8
- }
9
- const mergedChildren = mergeChildren([
10
- { nodes: options.commands, source: "generated" },
11
- { nodes: options.handwrittenCommands ?? [], source: "handwritten" },
12
- { nodes: options.auth.commands.map((command) => cloneNode(command, CLI_SCOPE)), source: "auth" }
13
- ]);
14
- return {
15
- name: options.name,
16
- mcpPrefix: toMcpPrefix(options.name),
17
- root: defineGroup({
18
- name: options.name,
19
- children: mergedChildren
20
- }),
21
- services: {
22
- baseUrl: options.baseUrl,
23
- tokenSource: options.auth
24
- }
25
- };
26
- }
27
- function mergeChildren(entries) {
28
- const nodeSources = new Map();
29
- const merged = [];
30
- for (const entry of entries) {
31
- mergeInto(merged, entry.nodes, [], entry.source, nodeSources);
32
- }
33
- // defineGroup snapshots its children at construction time, while mergeInto mutates an
34
- // existing group's children after that snapshot. Re-cloning here re-materializes each
35
- // merged group so nesting client.root under another group preserves the merged children.
36
- return merged.map((node) => cloneNode(node));
37
- }
38
- function mergeInto(target, incoming, path, source, nodeSources) {
39
- for (const candidate of incoming) {
40
- const nextNode = cloneNode(candidate);
41
- registerSource(nextNode, source, nodeSources);
42
- const existing = target.find((node) => node.name === nextNode.name);
43
- if (existing === undefined) {
44
- target.push(nextNode);
45
- continue;
46
- }
47
- if (existing.kind !== "group" || nextNode.kind !== "group") {
48
- throw createCollisionError([...path, nextNode.name], getRegisteredSource(nodeSources, existing), source);
49
- }
50
- mergeInto(existing.children, nextNode.children, [...path, nextNode.name], source, nodeSources);
51
- }
52
- }
53
- function registerSource(node, source, nodeSources) {
54
- nodeSources.set(node, source);
55
- if (node.kind === "group") {
56
- for (const child of node.children) {
57
- registerSource(child, source, nodeSources);
58
- }
59
- }
60
- }
61
- function getRegisteredSource(nodeSources, node) {
62
- const source = nodeSources.get(node);
63
- if (source === undefined) {
64
- throw new Error("Bug: merged command node is missing source metadata.");
65
- }
66
- return source;
67
- }
68
- function createCollisionError(path, left, right) {
69
- return new UserError(`Command path ${JSON.stringify(path.join(" "))} is defined more than once (${left} and ${right}).`);
70
- }
71
- function cloneNode(node, scopeOverride) {
72
- if (node.kind === "command") {
73
- return cloneCommand(node, scopeOverride);
74
- }
75
- return cloneGroup(node, scopeOverride);
76
- }
77
- function cloneCommand(command, scopeOverride) {
78
- return defineCommand({
79
- name: command.name,
80
- description: command.description,
81
- aliases: [...command.aliases],
82
- positional: [...command.positional],
83
- params: command.params,
84
- secrets: { ...command.secrets },
85
- scope: [...(scopeOverride ?? command.scope)],
86
- confirm: command.confirm,
87
- requires: command.requires,
88
- handler: command.handler,
89
- render: command.render
90
- });
91
- }
92
- function cloneGroup(group, scopeOverride) {
93
- const children = group.children.map((child) => cloneNode(child, scopeOverride));
94
- const defaultCommand = findCommand(children, group.default?.name);
95
- return defineGroup({
96
- name: group.name,
97
- description: group.description,
98
- aliases: [...group.aliases],
99
- scope: cloneScope(group.scope, scopeOverride),
100
- secrets: { ...group.secrets },
101
- requires: group.requires,
102
- children,
103
- default: defaultCommand
104
- });
105
- }
106
- function validateClientName(name) {
107
- if (!isValidClientName(name)) {
108
- throw new UserError(`Client name ${JSON.stringify(name)} must use lowercase letters, numbers, and hyphens only.`);
109
- }
110
- }
111
- function isValidClientName(name) {
112
- if (name.length === 0 || name.startsWith("-") || name.endsWith("-")) {
113
- return false;
114
- }
115
- for (const character of name) {
116
- if (character === "-") {
117
- continue;
118
- }
119
- if (character >= "a" && character <= "z") {
120
- continue;
121
- }
122
- if (character >= "0" && character <= "9") {
123
- continue;
124
- }
125
- return false;
126
- }
127
- return true;
128
- }
129
- function cloneScope(scope, scopeOverride) {
130
- if (scopeOverride !== undefined) {
131
- return [...scopeOverride];
132
- }
133
- if (scope === undefined) {
134
- return undefined;
135
- }
136
- return [...scope];
137
- }
138
- function findCommand(nodes, name) {
139
- if (name === undefined) {
140
- return undefined;
141
- }
142
- for (const node of nodes) {
143
- if (node.kind === "command" && node.name === name) {
144
- return node;
145
- }
146
- }
147
- return undefined;
148
- }