smartwing_knowflow 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/entry.cjs +60 -25
- package/dist/entry.cjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,8 @@ knowflow publish ./article.md --space team-docs --tags ai
|
|
|
31
31
|
|
|
32
32
|
成功时 stdout 输出绝对 URL,退出码 `0`;用法/配置错误 `2`;API/网络错误 `3`。
|
|
33
33
|
|
|
34
|
+
发布请求单次最多等待 60 秒;请求超时或服务端限流时,CLI 会使用同一个幂等键自动重试最多 2 次。
|
|
35
|
+
|
|
34
36
|
## 参数
|
|
35
37
|
|
|
36
38
|
| 参数 | 说明 |
|
|
@@ -38,9 +40,13 @@ knowflow publish ./article.md --space team-docs --tags ai
|
|
|
38
40
|
| `<file.md>` | 要发布的 Markdown 文件(≤1MB) |
|
|
39
41
|
| `--title` | 覆盖标题,缺省取文件名 |
|
|
40
42
|
| `--space <slug>` | 发布到团队空间 |
|
|
41
|
-
| `--tags <list>` |
|
|
43
|
+
| `--tags <list>` | 逗号分隔标签(最多 5 个去重标签) |
|
|
42
44
|
| `--site <url>` | 覆盖 `KNOWFLOW_SITE` |
|
|
43
|
-
| `--json`
|
|
45
|
+
| `--json` | 输出机器可读 JSON |
|
|
46
|
+
| `--quiet` | 静默成功输出 |
|
|
47
|
+
| `--verbose` | 向 stderr 输出诊断信息 |
|
|
48
|
+
|
|
49
|
+
运行 `knowflow -h` 或 `knowflow publish -h` 查看命令帮助。API Key 只能通过 `KNOWFLOW_API_KEY` 环境变量配置。
|
|
44
50
|
|
|
45
51
|
## 获取 API Key
|
|
46
52
|
|
package/dist/entry.cjs
CHANGED
|
@@ -148,15 +148,19 @@ var CliOutput = class {
|
|
|
148
148
|
var import_node_crypto = require("crypto");
|
|
149
149
|
var import_node_path = require("path");
|
|
150
150
|
var FILE_TIMEOUT_MS = 5e3;
|
|
151
|
-
var HTTP_TIMEOUT_MS =
|
|
151
|
+
var HTTP_TIMEOUT_MS = 6e4;
|
|
152
|
+
var MAX_HTTP_RETRIES = 2;
|
|
153
|
+
var RETRY_DELAYS_MS = [1e3, 2e3];
|
|
152
154
|
var MAX_MARKDOWN_BYTES = 1024 * 1024;
|
|
153
155
|
var PublishService = class {
|
|
154
|
-
constructor(fileAdapter, httpAdapter) {
|
|
156
|
+
constructor(fileAdapter, httpAdapter, options = {}) {
|
|
155
157
|
this.fileAdapter = fileAdapter;
|
|
156
158
|
this.httpAdapter = httpAdapter;
|
|
159
|
+
this.options = options;
|
|
157
160
|
}
|
|
158
161
|
fileAdapter;
|
|
159
162
|
httpAdapter;
|
|
163
|
+
options;
|
|
160
164
|
async publish(options, apiKey) {
|
|
161
165
|
let markdown;
|
|
162
166
|
try {
|
|
@@ -187,30 +191,55 @@ var PublishService = class {
|
|
|
187
191
|
};
|
|
188
192
|
const digest = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(body)).digest("hex").slice(0, 32);
|
|
189
193
|
const idempotencyKey = `cli-${digest}`;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
194
|
+
const sleep = this.options.sleep ?? ((delayMs) => new Promise((resolve) => {
|
|
195
|
+
setTimeout(resolve, delayMs);
|
|
196
|
+
}));
|
|
197
|
+
const maxRetries = this.options.maxHttpRetries ?? MAX_HTTP_RETRIES;
|
|
198
|
+
const timeoutMs = this.options.httpTimeoutMs ?? HTTP_TIMEOUT_MS;
|
|
199
|
+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
200
|
+
try {
|
|
201
|
+
const result = await this.httpAdapter.publish(
|
|
202
|
+
body,
|
|
203
|
+
apiKey,
|
|
204
|
+
idempotencyKey,
|
|
205
|
+
AbortSignal.timeout(timeoutMs)
|
|
206
|
+
);
|
|
207
|
+
if (result.ok) {
|
|
208
|
+
if (!result.post.url) {
|
|
209
|
+
throw new CliError(
|
|
210
|
+
"INVALID_RESPONSE",
|
|
211
|
+
"API response did not include a post URL.",
|
|
212
|
+
EXIT_API
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
return result.post.url;
|
|
216
|
+
}
|
|
217
|
+
if (!isRetryableFailure(result.error) || attempt === maxRetries) {
|
|
218
|
+
throw new CliError(result.error.code, result.error.message, EXIT_API);
|
|
219
|
+
}
|
|
220
|
+
} catch (error) {
|
|
221
|
+
if (error instanceof CliError) {
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
if (!isRetryableNetworkError(error) || attempt === maxRetries) {
|
|
225
|
+
throw new CliError(
|
|
226
|
+
"NETWORK_ERROR",
|
|
227
|
+
error instanceof Error ? error.message : "Network request failed.",
|
|
228
|
+
EXIT_API
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
await sleep(RETRY_DELAYS_MS[Math.min(attempt, RETRY_DELAYS_MS.length - 1)]);
|
|
210
233
|
}
|
|
211
|
-
|
|
234
|
+
throw new CliError("NETWORK_ERROR", "Network request failed.", EXIT_API);
|
|
212
235
|
}
|
|
213
236
|
};
|
|
237
|
+
function isRetryableFailure(error) {
|
|
238
|
+
return error.status === 429 || error.code === "RATE_LIMITED";
|
|
239
|
+
}
|
|
240
|
+
function isRetryableNetworkError(error) {
|
|
241
|
+
return error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
242
|
+
}
|
|
214
243
|
|
|
215
244
|
// src/features/cli/cli.ts
|
|
216
245
|
function parseTags(value) {
|
|
@@ -218,11 +247,17 @@ function parseTags(value) {
|
|
|
218
247
|
}
|
|
219
248
|
async function runCli(argv, runtime = { env: process.env, stdout: process.stdout, stderr: process.stderr }) {
|
|
220
249
|
let exitCode = EXIT_SUCCESS;
|
|
221
|
-
const program = new import_commander.Command().name("knowflow").description("Publish Markdown to KnowFlow").version("0.1.
|
|
250
|
+
const program = new import_commander.Command().name("knowflow").description("Publish Markdown to KnowFlow").version("0.1.1").showHelpAfterError().addHelpText(
|
|
251
|
+
"after",
|
|
252
|
+
"\nOptions are configured with KNOWFLOW_SITE and KNOWFLOW_API_KEY. HTTP requests wait up to 60 seconds and retry timeouts or rate limits up to 2 times.\nExit codes: 0 success, 1 internal, 2 usage/config, 3 API/network\n"
|
|
253
|
+
).exitOverride().configureOutput({
|
|
222
254
|
writeOut: (text) => runtime.stdout.write(text),
|
|
223
255
|
writeErr: (text) => runtime.stderr.write(text)
|
|
224
256
|
});
|
|
225
|
-
program.command("publish").description("Publish a Markdown file and print its URL").argument("<file.md>", "Markdown file to publish").option("--space <slug>", "Publish to a team space").option("--tags <list>", "Comma-separated tags").option("--title <title>", "Override the file name
|
|
257
|
+
program.command("publish").description("Publish a Markdown file and print its URL").argument("<file.md>", "Markdown file to publish").option("--space <slug>", "Publish to a team space by slug").option("--tags <list>", "Comma-separated tags (up to 5 unique tags)").option("--title <title>", "Override the title derived from the file name").option("--site <url>", "Override the KNOWFLOW_SITE environment variable").option("--json", "Print a machine-readable JSON result").option("--quiet", "Suppress successful output").option("--verbose", "Print request diagnostics to stderr").addHelpText(
|
|
258
|
+
"after",
|
|
259
|
+
"\nKNOWFLOW_API_KEY is read from the environment and is never accepted as a command-line option.\nHTTP requests wait up to 60 seconds and retry timeouts or rate limits up to 2 times.\nExit codes: 0 success, 1 internal, 2 usage/config, 3 API/network\n"
|
|
260
|
+
).action(async (file, flags) => {
|
|
226
261
|
const output = new CliOutput(runtime.stdout, runtime.stderr, flags.quiet, flags.json);
|
|
227
262
|
try {
|
|
228
263
|
const config = resolveCliConfig(flags, runtime.env);
|
package/dist/entry.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/features/cli/cli.ts","../../src/features/cli/adapters/node-file.adapter.ts","../../src/features/cli/adapters/fetch-http.adapter.ts","../../src/features/cli/core/config.ts","../../src/features/cli/core/errors.ts","../../src/features/cli/io/output.ts","../../src/features/cli/publish.service.ts","../../src/features/cli/entry.ts"],"sourcesContent":["import type { Writable } from \"node:stream\";\nimport { Command, CommanderError } from \"commander\";\nimport { NodeFileAdapter } from \"./adapters/node-file.adapter\";\nimport { FetchKnowFlowHttpAdapter } from \"./adapters/fetch-http.adapter\";\nimport { resolveCliConfig } from \"./core/config\";\nimport { CliError, EXIT_GENERIC, EXIT_SUCCESS, EXIT_USAGE } from \"./core/errors\";\nimport { CliOutput } from \"./io/output\";\nimport { PublishService } from \"./publish.service\";\n\ninterface CliRuntime {\n env: Record<string, string | undefined>;\n stdout: Writable;\n stderr: Writable;\n}\n\ninterface PublishFlags {\n json?: boolean;\n quiet?: boolean;\n site?: string;\n space?: string;\n tags?: string;\n title?: string;\n verbose?: boolean;\n}\n\nfunction parseTags(value: string | undefined): string[] {\n return value\n ? Array.from(new Set(value.split(\",\").map((tag) => tag.trim()).filter(Boolean))).slice(0, 5)\n : [];\n}\n\nexport async function runCli(\n argv: string[],\n runtime: CliRuntime = { env: process.env, stdout: process.stdout, stderr: process.stderr },\n): Promise<number> {\n let exitCode = EXIT_SUCCESS;\n const program = new Command()\n .name(\"knowflow\")\n .description(\"Publish Markdown to KnowFlow\")\n .version(\"0.1.0\")\n .showHelpAfterError()\n .exitOverride()\n .configureOutput({\n writeOut: (text) => runtime.stdout.write(text),\n writeErr: (text) => runtime.stderr.write(text),\n });\n\n program\n .command(\"publish\")\n .description(\"Publish a Markdown file and print its URL\")\n .argument(\"<file.md>\", \"Markdown file to publish\")\n .option(\"--space <slug>\", \"Publish to a team space\")\n .option(\"--tags <list>\", \"Comma-separated tags\")\n .option(\"--title <title>\", \"Override the file name as title\")\n .option(\"--site <url>\", \"KnowFlow site (overrides KNOWFLOW_SITE)\")\n .option(\"--json\", \"Print machine-readable JSON\")\n .option(\"--quiet\", \"Suppress successful output\")\n .option(\"--verbose\", \"Print diagnostics to stderr\")\n .addHelpText(\"after\", \"\\nExit codes: 0 success, 1 internal, 2 usage/config, 3 API/network\")\n .action(async (file: string, flags: PublishFlags) => {\n const output = new CliOutput(runtime.stdout, runtime.stderr, flags.quiet, flags.json);\n try {\n const config = resolveCliConfig(flags, runtime.env);\n output.verbose(`Publishing ${file} to ${config.site}`, Boolean(flags.verbose));\n const service = new PublishService(\n new NodeFileAdapter(),\n new FetchKnowFlowHttpAdapter(config.site),\n );\n output.success(\n await service.publish(\n { file, title: flags.title, space: flags.space, tags: parseTags(flags.tags) },\n config.apiKey,\n ),\n );\n } catch (error) {\n const cliError =\n error instanceof CliError\n ? error\n : new CliError(\n \"INTERNAL\",\n error instanceof Error ? error.message : \"Unexpected CLI error\",\n EXIT_GENERIC,\n );\n output.diagnostic(`${cliError.code}: ${cliError.message}`);\n exitCode = cliError.exitCode;\n }\n });\n\n try {\n await program.parseAsync(argv, { from: \"user\" });\n } catch (error) {\n if (error instanceof CommanderError) {\n return error.exitCode === 0 ? EXIT_SUCCESS : EXIT_USAGE;\n }\n throw error;\n }\n return exitCode;\n}","import { readFile } from \"node:fs/promises\";\nimport type { FileAdapter } from \"./file-adapter.interface\";\n\nexport class NodeFileAdapter implements FileAdapter {\n async readText(path: string, signal: AbortSignal): Promise<string> {\n // CLI users explicitly select this local path.\n // eslint-disable-next-line security/detect-non-literal-fs-filename\n return readFile(path, { encoding: \"utf8\", signal });\n }\n}","import createClient from \"openapi-fetch\";\nimport type { paths } from \"../generated/api\";\nimport type {\n KnowFlowHttpAdapter,\n PublishBody,\n PublishResult,\n} from \"./http-adapter.interface\";\n\nexport class FetchKnowFlowHttpAdapter implements KnowFlowHttpAdapter {\n private readonly client: ReturnType<typeof createClient<paths>>;\n private readonly site: string;\n\n constructor(site: string) {\n this.site = site;\n this.client = createClient<paths>({ baseUrl: site });\n }\n\n async publish(\n body: PublishBody,\n apiKey: string,\n idempotencyKey: string,\n signal: AbortSignal,\n ): Promise<PublishResult> {\n const { data, error, response } = await this.client.POST(\"/api/v1/posts\", {\n body,\n headers: {\n authorization: `Bearer ${apiKey}`,\n \"idempotency-key\": idempotencyKey,\n },\n signal,\n });\n if (data) {\n return {\n ok: true,\n post: {\n ...data,\n url: data.url ? new URL(data.url, this.site).toString() : data.url,\n },\n };\n }\n\n const payload = typeof error === \"object\" && error !== null ? error : {};\n return {\n ok: false,\n error: {\n status: response.status,\n code: \"code\" in payload && typeof payload.code === \"string\" ? payload.code : \"HTTP_ERROR\",\n message:\n \"message\" in payload && typeof payload.message === \"string\"\n ? payload.message\n : `HTTP ${response.status}`,\n },\n };\n }\n}","import { z } from \"zod\";\nimport { CliError, EXIT_USAGE } from \"./errors\";\n\nconst configSchema = z.object({\n apiKey: z.string().startsWith(\"kf_\"),\n site: z.string().url().transform((value) => value.replace(/\\/$/, \"\")),\n});\n\nexport interface CliConfig {\n apiKey: string;\n site: string;\n}\n\nexport function resolveCliConfig(\n flags: { site?: string },\n env: Record<string, string | undefined>,\n): CliConfig {\n const parsed = configSchema.safeParse({\n apiKey: env.KNOWFLOW_API_KEY,\n site: flags.site ?? env.KNOWFLOW_SITE,\n });\n if (!parsed.success) {\n const missing = [\n !env.KNOWFLOW_API_KEY ? \"KNOWFLOW_API_KEY\" : null,\n !flags.site && !env.KNOWFLOW_SITE ? \"KNOWFLOW_SITE\" : null,\n ].filter((value): value is string => value !== null);\n throw new CliError(\n \"CONFIG_REQUIRED\",\n missing.length > 0\n ? `Configure ${missing.join(\" and \")} or pass the matching flags.`\n : \"KNOWFLOW_API_KEY or KNOWFLOW_SITE is invalid.\",\n EXIT_USAGE,\n );\n }\n return parsed.data;\n}","export const EXIT_SUCCESS = 0;\nexport const EXIT_GENERIC = 1;\nexport const EXIT_USAGE = 2;\nexport const EXIT_API = 3;\n\nexport class CliError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly exitCode: number,\n ) {\n super(message);\n this.name = \"CliError\";\n }\n}","import type { Writable } from \"node:stream\";\n\nexport class CliOutput {\n constructor(\n private readonly stdout: Writable,\n private readonly stderr: Writable,\n private readonly quiet = false,\n private readonly json = false,\n ) {}\n\n success(url: string): void {\n if (this.quiet) return;\n this.stdout.write(this.json ? `${JSON.stringify({ url })}\\n` : `${url}\\n`);\n }\n\n diagnostic(message: string): void {\n this.stderr.write(this.json ? `${JSON.stringify({ error: message })}\\n` : `${message}\\n`);\n }\n\n verbose(message: string, enabled: boolean): void {\n if (enabled) this.stderr.write(`${message}\\n`);\n }\n}","import { createHash } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { FileAdapter } from \"./adapters/file-adapter.interface\";\nimport type { KnowFlowHttpAdapter } from \"./adapters/http-adapter.interface\";\nimport { CliError, EXIT_API, EXIT_USAGE } from \"./core/errors\";\n\nconst FILE_TIMEOUT_MS = 5_000;\nconst HTTP_TIMEOUT_MS = 10_000;\nconst MAX_MARKDOWN_BYTES = 1024 * 1024;\n\nexport interface PublishOptions {\n file: string;\n title?: string;\n space?: string;\n tags: string[];\n}\n\nexport class PublishService {\n constructor(\n private readonly fileAdapter: FileAdapter,\n private readonly httpAdapter: KnowFlowHttpAdapter,\n ) {}\n\n async publish(\n options: PublishOptions,\n apiKey: string,\n ): Promise<string> {\n let markdown: string;\n try {\n markdown = await this.fileAdapter.readText(\n options.file,\n AbortSignal.timeout(FILE_TIMEOUT_MS),\n );\n } catch (error) {\n throw new CliError(\n \"FILE_READ_ERROR\",\n `Unable to read ${options.file}: ${error instanceof Error ? error.message : \"unknown error\"}`,\n EXIT_USAGE,\n );\n }\n if (!markdown.trim()) {\n throw new CliError(\"EMPTY_FILE\", \"Markdown file is empty.\", EXIT_USAGE);\n }\n if (Buffer.byteLength(markdown, \"utf8\") > MAX_MARKDOWN_BYTES) {\n throw new CliError(\"FILE_TOO_LARGE\", \"Markdown file exceeds 1MB.\", EXIT_USAGE);\n }\n\n const title = options.title?.trim() || basename(options.file).replace(/\\.md$/i, \"\");\n const body = {\n title,\n markdown,\n visibility: options.space ? (\"space\" as const) : (\"public\" as const),\n ...(options.space ? { space_id: options.space } : {}),\n ...(options.tags.length > 0 ? { tags: options.tags } : {}),\n };\n const digest = createHash(\"sha256\")\n .update(JSON.stringify(body))\n .digest(\"hex\")\n .slice(0, 32);\n const idempotencyKey = `cli-${digest}`;\n\n let result;\n try {\n result = await this.httpAdapter.publish(\n body,\n apiKey,\n idempotencyKey,\n AbortSignal.timeout(HTTP_TIMEOUT_MS),\n );\n } catch (error) {\n throw new CliError(\n \"NETWORK_ERROR\",\n error instanceof Error ? error.message : \"Network request failed.\",\n EXIT_API,\n );\n }\n if (!result.ok) {\n throw new CliError(result.error.code, result.error.message, EXIT_API);\n }\n if (!result.post.url) {\n throw new CliError(\"INVALID_RESPONSE\", \"API response did not include a post URL.\", EXIT_API);\n }\n return result.post.url;\n }\n}","import { runCli } from \"./cli\";\n\nvoid runCli(process.argv.slice(2))\n\t.then((exitCode) => {\n\t\tprocess.exitCode = exitCode;\n\t})\n\t.catch((error: unknown) => {\n\t\tprocess.stderr.write(`${error instanceof Error ? error.message : \"Unexpected CLI error\"}\\n`);\n\t\tprocess.exitCode = 1;\n\t});"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AACA,uBAAwC;;;ACDxC,sBAAyB;AAGlB,IAAM,kBAAN,MAA6C;AAAA,EAClD,MAAM,SAAS,MAAc,QAAsC;AAGjE,eAAO,0BAAS,MAAM,EAAE,UAAU,QAAQ,OAAO,CAAC;AAAA,EACpD;AACF;;;ACTA,2BAAyB;AAQlB,IAAM,2BAAN,MAA8D;AAAA,EAClD;AAAA,EACA;AAAA,EAEjB,YAAY,MAAc;AACxB,SAAK,OAAO;AACZ,SAAK,aAAS,qBAAAA,SAAoB,EAAE,SAAS,KAAK,CAAC;AAAA,EACrD;AAAA,EAEA,MAAM,QACJ,MACA,QACA,gBACA,QACwB;AACxB,UAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,iBAAiB;AAAA,MACxE;AAAA,MACA,SAAS;AAAA,QACP,eAAe,UAAU,MAAM;AAAA,QAC/B,mBAAmB;AAAA,MACrB;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,MAAM;AACR,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,UACJ,GAAG;AAAA,UACH,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,EAAE,SAAS,IAAI,KAAK;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,UAAU,YAAY,UAAU,OAAO,QAAQ,CAAC;AACvE,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,QAAQ,SAAS;AAAA,QACjB,MAAM,UAAU,WAAW,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAAA,QAC7E,SACE,aAAa,WAAW,OAAO,QAAQ,YAAY,WAC/C,QAAQ,UACR,QAAQ,SAAS,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AACF;;;ACtDA,iBAAkB;;;ACAX,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,aAAa;AACnB,IAAM,WAAW;AAEjB,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YACkB,MAChB,SACgB,UAChB;AACA,UAAM,OAAO;AAJG;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EANkB;AAAA,EAEA;AAKpB;;;ADXA,IAAM,eAAe,aAAE,OAAO;AAAA,EAC5B,QAAQ,aAAE,OAAO,EAAE,WAAW,KAAK;AAAA,EACnC,MAAM,aAAE,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,UAAU,MAAM,QAAQ,OAAO,EAAE,CAAC;AACtE,CAAC;AAOM,SAAS,iBACd,OACA,KACW;AACX,QAAM,SAAS,aAAa,UAAU;AAAA,IACpC,QAAQ,IAAI;AAAA,IACZ,MAAM,MAAM,QAAQ,IAAI;AAAA,EAC1B,CAAC;AACD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,UAAU;AAAA,MACd,CAAC,IAAI,mBAAmB,qBAAqB;AAAA,MAC7C,CAAC,MAAM,QAAQ,CAAC,IAAI,gBAAgB,kBAAkB;AAAA,IACxD,EAAE,OAAO,CAAC,UAA2B,UAAU,IAAI;AACnD,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ,SAAS,IACb,aAAa,QAAQ,KAAK,OAAO,CAAC,iCAClC;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO;AAChB;;;AEjCO,IAAM,YAAN,MAAgB;AAAA,EACrB,YACmB,QACA,QACA,QAAQ,OACR,OAAO,OACxB;AAJiB;AACA;AACA;AACA;AAAA,EAChB;AAAA,EAJgB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGnB,QAAQ,KAAmB;AACzB,QAAI,KAAK,MAAO;AAChB,SAAK,OAAO,MAAM,KAAK,OAAO,GAAG,KAAK,UAAU,EAAE,IAAI,CAAC,CAAC;AAAA,IAAO,GAAG,GAAG;AAAA,CAAI;AAAA,EAC3E;AAAA,EAEA,WAAW,SAAuB;AAChC,SAAK,OAAO,MAAM,KAAK,OAAO,GAAG,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,CAAC;AAAA,IAAO,GAAG,OAAO;AAAA,CAAI;AAAA,EAC1F;AAAA,EAEA,QAAQ,SAAiB,SAAwB;AAC/C,QAAI,QAAS,MAAK,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,EAC/C;AACF;;;ACtBA,yBAA2B;AAC3B,uBAAyB;AAKzB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,qBAAqB,OAAO;AAS3B,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YACmB,aACA,aACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGnB,MAAM,QACJ,SACA,QACiB;AACjB,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,KAAK,YAAY;AAAA,QAChC,QAAQ;AAAA,QACR,YAAY,QAAQ,eAAe;AAAA,MACrC;AAAA,IACF,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR;AAAA,QACA,kBAAkB,QAAQ,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,QAC3F;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,SAAS,KAAK,GAAG;AACpB,YAAM,IAAI,SAAS,cAAc,2BAA2B,UAAU;AAAA,IACxE;AACA,QAAI,OAAO,WAAW,UAAU,MAAM,IAAI,oBAAoB;AAC5D,YAAM,IAAI,SAAS,kBAAkB,8BAA8B,UAAU;AAAA,IAC/E;AAEA,UAAM,QAAQ,QAAQ,OAAO,KAAK,SAAK,2BAAS,QAAQ,IAAI,EAAE,QAAQ,UAAU,EAAE;AAClF,UAAM,OAAO;AAAA,MACX;AAAA,MACA;AAAA,MACA,YAAY,QAAQ,QAAS,UAAqB;AAAA,MAClD,GAAI,QAAQ,QAAQ,EAAE,UAAU,QAAQ,MAAM,IAAI,CAAC;AAAA,MACnD,GAAI,QAAQ,KAAK,SAAS,IAAI,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC1D;AACA,UAAM,aAAS,+BAAW,QAAQ,EAC/B,OAAO,KAAK,UAAU,IAAI,CAAC,EAC3B,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AACd,UAAM,iBAAiB,OAAO,MAAM;AAEpC,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,KAAK,YAAY;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,QAAQ,eAAe;AAAA,MACrC;AAAA,IACF,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,IAAI,SAAS,OAAO,MAAM,MAAM,OAAO,MAAM,SAAS,QAAQ;AAAA,IACtE;AACA,QAAI,CAAC,OAAO,KAAK,KAAK;AACpB,YAAM,IAAI,SAAS,oBAAoB,4CAA4C,QAAQ;AAAA,IAC7F;AACA,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;;;AN3DA,SAAS,UAAU,OAAqC;AACtD,SAAO,QACH,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IACzF,CAAC;AACP;AAEA,eAAsB,OACpB,MACA,UAAsB,EAAE,KAAK,QAAQ,KAAK,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,GACxE;AACjB,MAAI,WAAW;AACf,QAAM,UAAU,IAAI,yBAAQ,EACzB,KAAK,UAAU,EACf,YAAY,8BAA8B,EAC1C,QAAQ,OAAO,EACf,mBAAmB,EACnB,aAAa,EACb,gBAAgB;AAAA,IACf,UAAU,CAAC,SAAS,QAAQ,OAAO,MAAM,IAAI;AAAA,IAC7C,UAAU,CAAC,SAAS,QAAQ,OAAO,MAAM,IAAI;AAAA,EAC/C,CAAC;AAEH,UACG,QAAQ,SAAS,EACjB,YAAY,2CAA2C,EACvD,SAAS,aAAa,0BAA0B,EAChD,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,iBAAiB,sBAAsB,EAC9C,OAAO,mBAAmB,iCAAiC,EAC3D,OAAO,gBAAgB,yCAAyC,EAChE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,WAAW,4BAA4B,EAC9C,OAAO,aAAa,6BAA6B,EACjD,YAAY,SAAS,oEAAoE,EACzF,OAAO,OAAO,MAAc,UAAwB;AACnD,UAAM,SAAS,IAAI,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,MAAM,OAAO,MAAM,IAAI;AACpF,QAAI;AACF,YAAM,SAAS,iBAAiB,OAAO,QAAQ,GAAG;AAClD,aAAO,QAAQ,cAAc,IAAI,OAAO,OAAO,IAAI,IAAI,QAAQ,MAAM,OAAO,CAAC;AAC7E,YAAM,UAAU,IAAI;AAAA,QAClB,IAAI,gBAAgB;AAAA,QACpB,IAAI,yBAAyB,OAAO,IAAI;AAAA,MAC1C;AACA,aAAO;AAAA,QACL,MAAM,QAAQ;AAAA,UACZ,EAAE,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,MAAM,UAAU,MAAM,IAAI,EAAE;AAAA,UAC5E,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,WACJ,iBAAiB,WACb,QACA,IAAI;AAAA,QACF;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACzC;AAAA,MACF;AACN,aAAO,WAAW,GAAG,SAAS,IAAI,KAAK,SAAS,OAAO,EAAE;AACzD,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF,CAAC;AAEH,MAAI;AACF,UAAM,QAAQ,WAAW,MAAM,EAAE,MAAM,OAAO,CAAC;AAAA,EACjD,SAAS,OAAO;AACd,QAAI,iBAAiB,iCAAgB;AACnC,aAAO,MAAM,aAAa,IAAI,eAAe;AAAA,IAC/C;AACA,UAAM;AAAA,EACR;AACA,SAAO;AACT;;;AO/FA,KAAK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,EAC/B,KAAK,CAAC,aAAa;AACnB,UAAQ,WAAW;AACpB,CAAC,EACA,MAAM,CAAC,UAAmB;AAC1B,UAAQ,OAAO,MAAM,GAAG,iBAAiB,QAAQ,MAAM,UAAU,sBAAsB;AAAA,CAAI;AAC3F,UAAQ,WAAW;AACpB,CAAC;","names":["createClient"]}
|
|
1
|
+
{"version":3,"sources":["../../src/features/cli/cli.ts","../../src/features/cli/adapters/node-file.adapter.ts","../../src/features/cli/adapters/fetch-http.adapter.ts","../../src/features/cli/core/config.ts","../../src/features/cli/core/errors.ts","../../src/features/cli/io/output.ts","../../src/features/cli/publish.service.ts","../../src/features/cli/entry.ts"],"sourcesContent":["import type { Writable } from \"node:stream\";\nimport { Command, CommanderError } from \"commander\";\nimport { NodeFileAdapter } from \"./adapters/node-file.adapter\";\nimport { FetchKnowFlowHttpAdapter } from \"./adapters/fetch-http.adapter\";\nimport { resolveCliConfig } from \"./core/config\";\nimport { CliError, EXIT_GENERIC, EXIT_SUCCESS, EXIT_USAGE } from \"./core/errors\";\nimport { CliOutput } from \"./io/output\";\nimport { PublishService } from \"./publish.service\";\n\ndeclare const __CLI_VERSION__: string;\n\ninterface CliRuntime {\n env: Record<string, string | undefined>;\n stdout: Writable;\n stderr: Writable;\n}\n\ninterface PublishFlags {\n json?: boolean;\n quiet?: boolean;\n site?: string;\n space?: string;\n tags?: string;\n title?: string;\n verbose?: boolean;\n}\n\nfunction parseTags(value: string | undefined): string[] {\n return value\n ? Array.from(new Set(value.split(\",\").map((tag) => tag.trim()).filter(Boolean))).slice(0, 5)\n : [];\n}\n\nexport async function runCli(\n argv: string[],\n runtime: CliRuntime = { env: process.env, stdout: process.stdout, stderr: process.stderr },\n): Promise<number> {\n let exitCode = EXIT_SUCCESS;\n const program = new Command()\n .name(\"knowflow\")\n .description(\"Publish Markdown to KnowFlow\")\n .version(__CLI_VERSION__)\n .showHelpAfterError()\n .addHelpText(\n \"after\",\n \"\\nOptions are configured with KNOWFLOW_SITE and KNOWFLOW_API_KEY. HTTP requests wait up to 60 seconds and retry timeouts or rate limits up to 2 times.\\nExit codes: 0 success, 1 internal, 2 usage/config, 3 API/network\\n\",\n )\n .exitOverride()\n .configureOutput({\n writeOut: (text) => runtime.stdout.write(text),\n writeErr: (text) => runtime.stderr.write(text),\n });\n\n program\n .command(\"publish\")\n .description(\"Publish a Markdown file and print its URL\")\n .argument(\"<file.md>\", \"Markdown file to publish\")\n .option(\"--space <slug>\", \"Publish to a team space by slug\")\n .option(\"--tags <list>\", \"Comma-separated tags (up to 5 unique tags)\")\n .option(\"--title <title>\", \"Override the title derived from the file name\")\n .option(\"--site <url>\", \"Override the KNOWFLOW_SITE environment variable\")\n .option(\"--json\", \"Print a machine-readable JSON result\")\n .option(\"--quiet\", \"Suppress successful output\")\n .option(\"--verbose\", \"Print request diagnostics to stderr\")\n .addHelpText(\n \"after\",\n \"\\nKNOWFLOW_API_KEY is read from the environment and is never accepted as a command-line option.\\nHTTP requests wait up to 60 seconds and retry timeouts or rate limits up to 2 times.\\nExit codes: 0 success, 1 internal, 2 usage/config, 3 API/network\\n\",\n )\n .action(async (file: string, flags: PublishFlags) => {\n const output = new CliOutput(runtime.stdout, runtime.stderr, flags.quiet, flags.json);\n try {\n const config = resolveCliConfig(flags, runtime.env);\n output.verbose(`Publishing ${file} to ${config.site}`, Boolean(flags.verbose));\n const service = new PublishService(\n new NodeFileAdapter(),\n new FetchKnowFlowHttpAdapter(config.site),\n );\n output.success(\n await service.publish(\n { file, title: flags.title, space: flags.space, tags: parseTags(flags.tags) },\n config.apiKey,\n ),\n );\n } catch (error) {\n const cliError =\n error instanceof CliError\n ? error\n : new CliError(\n \"INTERNAL\",\n error instanceof Error ? error.message : \"Unexpected CLI error\",\n EXIT_GENERIC,\n );\n output.diagnostic(`${cliError.code}: ${cliError.message}`);\n exitCode = cliError.exitCode;\n }\n });\n\n try {\n await program.parseAsync(argv, { from: \"user\" });\n } catch (error) {\n if (error instanceof CommanderError) {\n return error.exitCode === 0 ? EXIT_SUCCESS : EXIT_USAGE;\n }\n throw error;\n }\n return exitCode;\n}","import { readFile } from \"node:fs/promises\";\nimport type { FileAdapter } from \"./file-adapter.interface\";\n\nexport class NodeFileAdapter implements FileAdapter {\n async readText(path: string, signal: AbortSignal): Promise<string> {\n // CLI users explicitly select this local path.\n // eslint-disable-next-line security/detect-non-literal-fs-filename\n return readFile(path, { encoding: \"utf8\", signal });\n }\n}","import createClient from \"openapi-fetch\";\nimport type { paths } from \"../generated/api\";\nimport type {\n KnowFlowHttpAdapter,\n PublishBody,\n PublishResult,\n} from \"./http-adapter.interface\";\n\nexport class FetchKnowFlowHttpAdapter implements KnowFlowHttpAdapter {\n private readonly client: ReturnType<typeof createClient<paths>>;\n private readonly site: string;\n\n constructor(site: string) {\n this.site = site;\n this.client = createClient<paths>({ baseUrl: site });\n }\n\n async publish(\n body: PublishBody,\n apiKey: string,\n idempotencyKey: string,\n signal: AbortSignal,\n ): Promise<PublishResult> {\n const { data, error, response } = await this.client.POST(\"/api/v1/posts\", {\n body,\n headers: {\n authorization: `Bearer ${apiKey}`,\n \"idempotency-key\": idempotencyKey,\n },\n signal,\n });\n if (data) {\n return {\n ok: true,\n post: {\n ...data,\n url: data.url ? new URL(data.url, this.site).toString() : data.url,\n },\n };\n }\n\n const payload = typeof error === \"object\" && error !== null ? error : {};\n return {\n ok: false,\n error: {\n status: response.status,\n code: \"code\" in payload && typeof payload.code === \"string\" ? payload.code : \"HTTP_ERROR\",\n message:\n \"message\" in payload && typeof payload.message === \"string\"\n ? payload.message\n : `HTTP ${response.status}`,\n },\n };\n }\n}","import { z } from \"zod\";\nimport { CliError, EXIT_USAGE } from \"./errors\";\n\nconst configSchema = z.object({\n apiKey: z.string().startsWith(\"kf_\"),\n site: z.string().url().transform((value) => value.replace(/\\/$/, \"\")),\n});\n\nexport interface CliConfig {\n apiKey: string;\n site: string;\n}\n\nexport function resolveCliConfig(\n flags: { site?: string },\n env: Record<string, string | undefined>,\n): CliConfig {\n const parsed = configSchema.safeParse({\n apiKey: env.KNOWFLOW_API_KEY,\n site: flags.site ?? env.KNOWFLOW_SITE,\n });\n if (!parsed.success) {\n const missing = [\n !env.KNOWFLOW_API_KEY ? \"KNOWFLOW_API_KEY\" : null,\n !flags.site && !env.KNOWFLOW_SITE ? \"KNOWFLOW_SITE\" : null,\n ].filter((value): value is string => value !== null);\n throw new CliError(\n \"CONFIG_REQUIRED\",\n missing.length > 0\n ? `Configure ${missing.join(\" and \")} or pass the matching flags.`\n : \"KNOWFLOW_API_KEY or KNOWFLOW_SITE is invalid.\",\n EXIT_USAGE,\n );\n }\n return parsed.data;\n}","export const EXIT_SUCCESS = 0;\nexport const EXIT_GENERIC = 1;\nexport const EXIT_USAGE = 2;\nexport const EXIT_API = 3;\n\nexport class CliError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly exitCode: number,\n ) {\n super(message);\n this.name = \"CliError\";\n }\n}","import type { Writable } from \"node:stream\";\n\nexport class CliOutput {\n constructor(\n private readonly stdout: Writable,\n private readonly stderr: Writable,\n private readonly quiet = false,\n private readonly json = false,\n ) {}\n\n success(url: string): void {\n if (this.quiet) return;\n this.stdout.write(this.json ? `${JSON.stringify({ url })}\\n` : `${url}\\n`);\n }\n\n diagnostic(message: string): void {\n this.stderr.write(this.json ? `${JSON.stringify({ error: message })}\\n` : `${message}\\n`);\n }\n\n verbose(message: string, enabled: boolean): void {\n if (enabled) this.stderr.write(`${message}\\n`);\n }\n}","import { createHash } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { FileAdapter } from \"./adapters/file-adapter.interface\";\nimport type { KnowFlowHttpAdapter } from \"./adapters/http-adapter.interface\";\nimport { CliError, EXIT_API, EXIT_USAGE } from \"./core/errors\";\n\nconst FILE_TIMEOUT_MS = 5_000;\nconst HTTP_TIMEOUT_MS = 60_000;\nconst MAX_HTTP_RETRIES = 2;\nconst RETRY_DELAYS_MS = [1_000, 2_000] as const;\nconst MAX_MARKDOWN_BYTES = 1024 * 1024;\n\nexport interface PublishServiceOptions {\n sleep?: (delayMs: number) => Promise<void>;\n httpTimeoutMs?: number;\n maxHttpRetries?: number;\n}\n\nexport interface PublishOptions {\n file: string;\n title?: string;\n space?: string;\n tags: string[];\n}\n\nexport class PublishService {\n constructor(\n private readonly fileAdapter: FileAdapter,\n private readonly httpAdapter: KnowFlowHttpAdapter,\n private readonly options: PublishServiceOptions = {},\n ) {}\n\n async publish(\n options: PublishOptions,\n apiKey: string,\n ): Promise<string> {\n let markdown: string;\n try {\n markdown = await this.fileAdapter.readText(\n options.file,\n AbortSignal.timeout(FILE_TIMEOUT_MS),\n );\n } catch (error) {\n throw new CliError(\n \"FILE_READ_ERROR\",\n `Unable to read ${options.file}: ${error instanceof Error ? error.message : \"unknown error\"}`,\n EXIT_USAGE,\n );\n }\n if (!markdown.trim()) {\n throw new CliError(\"EMPTY_FILE\", \"Markdown file is empty.\", EXIT_USAGE);\n }\n if (Buffer.byteLength(markdown, \"utf8\") > MAX_MARKDOWN_BYTES) {\n throw new CliError(\"FILE_TOO_LARGE\", \"Markdown file exceeds 1MB.\", EXIT_USAGE);\n }\n\n const title = options.title?.trim() || basename(options.file).replace(/\\.md$/i, \"\");\n const body = {\n title,\n markdown,\n visibility: options.space ? (\"space\" as const) : (\"public\" as const),\n ...(options.space ? { space_id: options.space } : {}),\n ...(options.tags.length > 0 ? { tags: options.tags } : {}),\n };\n const digest = createHash(\"sha256\")\n .update(JSON.stringify(body))\n .digest(\"hex\")\n .slice(0, 32);\n const idempotencyKey = `cli-${digest}`;\n\n const sleep = this.options.sleep ?? ((delayMs: number) => new Promise<void>((resolve) => {\n setTimeout(resolve, delayMs);\n }));\n const maxRetries = this.options.maxHttpRetries ?? MAX_HTTP_RETRIES;\n const timeoutMs = this.options.httpTimeoutMs ?? HTTP_TIMEOUT_MS;\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n try {\n const result = await this.httpAdapter.publish(\n body,\n apiKey,\n idempotencyKey,\n AbortSignal.timeout(timeoutMs),\n );\n if (result.ok) {\n if (!result.post.url) {\n throw new CliError(\n \"INVALID_RESPONSE\",\n \"API response did not include a post URL.\",\n EXIT_API,\n );\n }\n return result.post.url;\n }\n\n if (!isRetryableFailure(result.error) || attempt === maxRetries) {\n throw new CliError(result.error.code, result.error.message, EXIT_API);\n }\n } catch (error) {\n if (error instanceof CliError) {\n throw error;\n }\n if (!isRetryableNetworkError(error) || attempt === maxRetries) {\n throw new CliError(\n \"NETWORK_ERROR\",\n error instanceof Error ? error.message : \"Network request failed.\",\n EXIT_API,\n );\n }\n }\n\n await sleep(RETRY_DELAYS_MS[Math.min(attempt, RETRY_DELAYS_MS.length - 1)]);\n }\n\n throw new CliError(\"NETWORK_ERROR\", \"Network request failed.\", EXIT_API);\n }\n}\n\nfunction isRetryableFailure(error: { status: number; code: string }): boolean {\n return error.status === 429 || error.code === \"RATE_LIMITED\";\n}\n\nfunction isRetryableNetworkError(error: unknown): boolean {\n return error instanceof Error && (error.name === \"AbortError\" || error.name === \"TimeoutError\");\n}","import { runCli } from \"./cli\";\n\nvoid runCli(process.argv.slice(2))\n\t.then((exitCode) => {\n\t\tprocess.exitCode = exitCode;\n\t})\n\t.catch((error: unknown) => {\n\t\tprocess.stderr.write(`${error instanceof Error ? error.message : \"Unexpected CLI error\"}\\n`);\n\t\tprocess.exitCode = 1;\n\t});"],"mappings":"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","names":["createClient"]}
|