@keystrokehq/cli 0.0.17 → 0.0.18
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/dist/{accept.handler-BPwp_UAE.mjs → accept.handler-B7QzdKCh.mjs} +4 -4
- package/dist/{admin-Bb9Hx-gO.mjs → admin-CYpulx_A.mjs} +11 -11
- package/dist/{agents-CbmvvOAx.mjs → agents-Co6Jy_N8.mjs} +10 -10
- package/dist/{api-jkf0TTgD.mjs → api-DsK8M-ZH.mjs} +1 -1
- package/dist/{api-keys-DJlyIf10.mjs → api-keys-BUCLzRv_.mjs} +6 -6
- package/dist/{auth-DpDEkJz7.mjs → auth-niNm-yNT.mjs} +12 -7
- package/dist/{auth.handler-u3qmoUX0.mjs → auth.handler-BTH-Qb00.mjs} +59 -26
- package/dist/{build-agents-DseUtzd4-VYWtIZy9.mjs → build-agents-DseUtzd4-CthuIecx.mjs} +6 -6
- package/dist/{build-metadata-C8Ra_Gi--BdoyLQMl.mjs → build-metadata-C8Ra_Gi--L3l8w0rh.mjs} +7 -7
- package/dist/{build-progress-BZivcVz4.mjs → build-progress-AR8xow4_.mjs} +2 -2
- package/dist/{build-tasks-GVuMLS0h-p08mMOyK.mjs → build-tasks-GVuMLS0h-CCxCqd02.mjs} +3 -3
- package/dist/{build-workflows-CV4tBo6S-knCnBKTc.mjs → build-workflows-CV4tBo6S-DhFBlp6m.mjs} +10 -10
- package/dist/{build.handler-BNSC_zhQ.mjs → build.handler-BmlXPhed.mjs} +7 -7
- package/dist/{clear-cache.handler-gr5VmEYB.mjs → clear-cache.handler-CTLQ1PIN.mjs} +3 -3
- package/dist/clear.handler-BDlwBzX4.mjs +68 -0
- package/dist/{clear.handler-CtOZ4aRn.mjs → clear.handler-C_pXAeBG.mjs} +3 -2
- package/dist/{commander-D15UZVjp.mjs → commander-BE37hxR3.mjs} +4 -4
- package/dist/{connect-DzSNDSmI.mjs → connect-C9NMD8Ky.mjs} +3 -3
- package/dist/{connect.handler-DRO05ak3.mjs → connect.handler-C7kysvhz.mjs} +5 -5
- package/dist/{context-B1L8pZsH.mjs → context-Bid-Rqj7.mjs} +49 -17
- package/dist/{create.handler-DF1Ye4nr.mjs → create.handler-Cp9CV6SN.mjs} +3 -3
- package/dist/{credential-env-map-B2nVJXPn.mjs → credential-env-map-BA4LNI7x.mjs} +6 -5
- package/dist/{credential-requirements-FtBk5JVB.mjs → credential-requirements-DrrQ9x9P.mjs} +3 -3
- package/dist/{credential-schema-mismatch-CfyBUMPS.mjs → credential-schema-mismatch-z74ud-YZ.mjs} +1 -1
- package/dist/{credentials-CiOwDS5y.mjs → credentials-DUkVbhvj.mjs} +1 -1
- package/dist/{credentials-VidBoOd7.mjs → credentials-fMfKVlEn.mjs} +7 -7
- package/dist/{current-deployment-workflow-BRUEdPrN.mjs → current-deployment-workflow-DiwUcKoB.mjs} +6 -6
- package/dist/{current.handler-QZQ-l84v.mjs → current.handler-eCR4nClu.mjs} +3 -3
- package/dist/{delete.handler-Bude0SVP.mjs → delete.handler-D4ElSAcr.mjs} +2 -2
- package/dist/{deploy-eshEEiP-.mjs → deploy-B7LRWcp6.mjs} +2 -2
- package/dist/{deploy-CJbVB7e2.mjs → deploy-DyZh--f7.mjs} +1 -1
- package/dist/{deploy-progress-DJHph1Fz.mjs → deploy-progress-DK87VKJ-.mjs} +2 -2
- package/dist/{deploy.handler-BxxWI7nV.mjs → deploy.handler-DVnH-Niv.mjs} +20 -20
- package/dist/{detect-env-access-CwkOYeYM-CZIixHeR.mjs → detect-env-access-CwkOYeYM-CNTyUzme.mjs} +1 -1
- package/dist/{diff-utils-4OQTpP5s.mjs → diff-utils-B0ED-Igv.mjs} +1 -1
- package/dist/{diff.handler-CzrKCj7N.mjs → diff.handler-lIA2pRBX.mjs} +7 -7
- package/dist/dist-CIInPRGh.mjs +1071 -0
- package/dist/{dist-FQYQ2FLm.mjs → dist-WFPTDQB3.mjs} +15 -15
- package/dist/{env.handler-B3YDQIVE.mjs → env.handler-BIzQLlmo.mjs} +10 -10
- package/dist/{error-boundary-CyLcinp1.mjs → error-boundary-B8cmSwJH.mjs} +3 -3
- package/dist/{file-metadata-DaPPpiTh.mjs → file-metadata-lrX05iRt.mjs} +1 -1
- package/dist/{iam-command-utils-ByLX0A-V.mjs → iam-command-utils-CSZj4XlH.mjs} +2 -2
- package/dist/{import-module--8x5SLum-DaUNACER.mjs → import-module--8x5SLum-D7EiPjwl.mjs} +6 -6
- package/dist/{init-CWFJdKNs.mjs → init-jaqNLGmB.mjs} +3 -3
- package/dist/{init.handler-BZSoM76V.mjs → init.handler-DamvbPEw.mjs} +8 -8
- package/dist/{inspect.handler-umc7of-r.mjs → inspect.handler-_UcN7dxE.mjs} +8 -8
- package/dist/{integration-catalog-BgT4mLzW.mjs → integration-catalog-m8tj_XlD.mjs} +3 -3
- package/dist/{integrations-DKtl_aES.mjs → integrations-DRL3JmC8.mjs} +6 -6
- package/dist/{invites-Cqi7iyIN.mjs → invites-VntHNMYk.mjs} +5 -5
- package/dist/{invites.list.handler-CErgY35S.mjs → invites.list.handler-CPl4QHfc.mjs} +4 -4
- package/dist/{invites.resend.handler-DRCRIA4F.mjs → invites.resend.handler-BAtb3AX4.mjs} +4 -4
- package/dist/{invites.revoke.handler-C0FZdAR0.mjs → invites.revoke.handler-qXOF1Vgx.mjs} +4 -4
- package/dist/keystroke.mjs +558 -207
- package/dist/{list-enrichment-C6u5eI0j.mjs → list-enrichment-DYvr3XDb.mjs} +3 -3
- package/dist/{list.handler-c-8RpgB9.mjs → list.handler-BLkQKiV1.mjs} +17 -16
- package/dist/{list.handler-CBEXiTAK.mjs → list.handler-BdRsjRlf.mjs} +3 -3
- package/dist/{list.handler-DYdNWjgk.mjs → list.handler-CEjKSezx.mjs} +4 -4
- package/dist/{list2.handler-T5v4EK20.mjs → list.handler-CJUFdmaU.mjs} +7 -7
- package/dist/{list.handler-Cr_DFAae.mjs → list.handler-C_iBLBmS.mjs} +3 -3
- package/dist/{list.handler-FlchXrKz.mjs → list.handler-DUz1bJ4x.mjs} +4 -4
- package/dist/{list.handler-D-YFoKLU.mjs → list.handler-pHnPFep8.mjs} +7 -7
- package/dist/{listen-rHLiCWbn.mjs → listen-DLGZEQRL.mjs} +3 -3
- package/dist/{listen.handler-B9T58yAj.mjs → listen.handler-kaAvYk-B.mjs} +4 -4
- package/dist/logs-CcYqFKRU.mjs +58 -0
- package/dist/logs.handler-DyRoevtO.mjs +53 -0
- package/dist/{logs.handler-DGcGN2qb.mjs → logs.handler-lboRKNoE.mjs} +4 -4
- package/dist/{members.add.handler-DmYI43rZ.mjs → members.add.handler-DBydP0SR.mjs} +4 -4
- package/dist/{members.invite.handler-B_KVxv5m.mjs → members.invite.handler-D4-7fiYC.mjs} +4 -4
- package/dist/{members.list.handler-BtuuIgQS.mjs → members.list.handler-Z4cIbcNg.mjs} +4 -4
- package/dist/{members.remove.handler-Lvg-CqVv.mjs → members.remove.handler-J56D83O7.mjs} +4 -4
- package/dist/{members.update.handler-D-8izeso.mjs → members.update.handler-B5rBv6dt.mjs} +4 -4
- package/dist/{normalize-path-CojS-CgQ-DFTvyA27.mjs → normalize-path-CojS-CgQ-D4wSBHgG.mjs} +1 -1
- package/dist/{org-DUCts2MV.mjs → org-DGS91uc-.mjs} +17 -17
- package/dist/{orgs.create.handler-vXQgDJZ_.mjs → orgs.create.handler-B4naNUSN.mjs} +4 -4
- package/dist/{orgs.get.handler-D_Jfl18x.mjs → orgs.get.handler-Ci_JrT08.mjs} +4 -4
- package/dist/{orgs.list.handler-BNjoTJvV.mjs → orgs.list.handler-CJ2byIEj.mjs} +4 -4
- package/dist/{output-CGdYhH0p.mjs → output-BWcVRt-T.mjs} +1 -1
- package/dist/paths-JzzFkXQA-CEipIeVl.mjs +36 -0
- package/dist/{paused.handler-ST9dCe8E.mjs → paused.handler-BQSQvQhB.mjs} +3 -3
- package/dist/{projects-CbquwUlm.mjs → projects-D90_uEC2.mjs} +5 -5
- package/dist/{projects-DfaG_3WP.mjs → projects-fWvIJQ80.mjs} +1 -1
- package/dist/{register.handler-BAx0IC-u.mjs → register.handler-CleQJhtQ.mjs} +2 -2
- package/dist/{requirements.handler-D5dFi7XZ.mjs → requirements.handler-B51sxQSy.mjs} +7 -7
- package/dist/resolve-cli-credentials-DytxgMwn.mjs +47 -0
- package/dist/{resolve-project-CURYMjex.mjs → resolve-project-CNQtOWE4.mjs} +7 -7
- package/dist/{run-polling-BWcLQvm0.mjs → run-polling-CC6y2XXI.mjs} +5 -5
- package/dist/{run.handler-BiBDLoeH.mjs → run.handler-B31BpZJP.mjs} +9 -9
- package/dist/{runs-Bc3zjk7V.mjs → runs-Bg_qDeQi.mjs} +4 -4
- package/dist/{skill-installer-DkRJ6oLi.mjs → skill-installer-BBgN2tzW.mjs} +2 -2
- package/dist/{skills-sync.handler-C4ztv1Vu.mjs → skills-sync.handler-DOxudKmV.mjs} +3 -3
- package/dist/{skills.command-DuL4kLUi.mjs → skills.command-JwKWpGvU.mjs} +5 -5
- package/dist/{skills.handler-R5KAbioE.mjs → skills.handler-Do9I3dQS.mjs} +1 -1
- package/dist/{source-analysis-BBg2E_6G-BQqm16RR.mjs → source-analysis-BBg2E_6G-Ut7kYHOz.mjs} +4 -4
- package/dist/{spinner-progress-DfkMzwGx.mjs → spinner-progress-Bx-fYItP.mjs} +1 -1
- package/dist/{src-BQdOWkyv.mjs → src-B0tNjKMg.mjs} +1 -1
- package/dist/{status.handler-DxCJRm1n.mjs → status.handler-BsVtDW_V.mjs} +19 -4
- package/dist/{switch.handler-CTwhIcaQ.mjs → switch.handler-Cu81T2HY.mjs} +5 -5
- package/dist/{sync-Pssitj6K.mjs → sync-CXNveL61.mjs} +2 -2
- package/dist/{sync.handler-Be0U3x-n.mjs → sync.handler-7g1yDt0H.mjs} +9 -9
- package/dist/{task-BNXDZU71.mjs → task-BguWXIiH.mjs} +2 -2
- package/dist/{task-target-build-BG6cC3bz.mjs → task-target-build-BaMtXnN7.mjs} +8 -7
- package/dist/{task-target-deploy-CZBGNC0H-Ck724yF4.mjs → task-target-deploy-CZBGNC0H-I-tvkGCC.mjs} +1 -1
- package/dist/{task-target-deploy-gMQC8kXU.mjs → task-target-deploy-DmpCWE3u.mjs} +1 -1
- package/dist/task-target-deploy-runner.mjs +22 -17
- package/dist/{test-CKBpp1gg.mjs → test-A5hz3c7j.mjs} +4 -4
- package/dist/{test.handler-DkizZhVu.mjs → test.handler-CJtaMZVy.mjs} +12 -12
- package/dist/{test.handler-Dk3CmTa7.mjs → test.handler-Cq2l7SAr.mjs} +2 -2
- package/dist/{tool.handler--IzRGelu.mjs → tool.handler-B-mOL128.mjs} +34 -14
- package/dist/{trigger-artifacts-RizI57RC-CxHwCkQ_.mjs → trigger-artifacts-RizI57RC-DjhOsdOm.mjs} +4 -4
- package/dist/{trigger-manifest-PTjVYL1r.mjs → trigger-manifest-Bq2zRbkV.mjs} +1 -1
- package/dist/{upgrade-cH9I_pZq.mjs → upgrade-DhfpoyRV.mjs} +2 -2
- package/dist/{upgrade.handler-CXEF4ue0.mjs → upgrade.handler-5qSzPC7D.mjs} +1 -1
- package/dist/{upload.handler-CpKuAaQ_.mjs → upload.handler-D3-W_1kq.mjs} +10 -10
- package/dist/{users.get.handler-D0WO6D1K.mjs → users.get.handler-Bd0OBI-E.mjs} +4 -4
- package/dist/{users.list.handler-BSTIniF1.mjs → users.list.handler-CacJz6eC.mjs} +4 -4
- package/dist/{users.set-role.handler-DAKdSkbn.mjs → users.set-role.handler-bZMQtUR0.mjs} +4 -4
- package/dist/{utils-VC0Vl_pm.mjs → utils-BMUWnz1P.mjs} +2 -2
- package/dist/{validate.handler-I8LY-UkG.mjs → validate.handler-Ccq66ki4.mjs} +8 -8
- package/dist/{workflow-build-C9rQQ4qU.mjs → workflow-build-_WNsLKwW.mjs} +23 -23
- package/dist/{workflow-build-manifest-OPFqFD6f.mjs → workflow-build-manifest-B2GqHyWE.mjs} +3 -3
- package/dist/{workflow-bundler-BzHk73PM-AIB4-u4Y.mjs → workflow-bundler-BzHk73PM-WI31RJjH.mjs} +3 -3
- package/dist/{workflows-CL1jYSLR.mjs → workflows-Dy2M9bEr.mjs} +16 -16
- package/dist/{writer-B-SpZ0G2-olEAgSLc.mjs → writer-B-SpZ0G2-tq1MFgid.mjs} +6 -6
- package/package.json +4 -4
- package/dist/clear.handler-Dpe05eTq.mjs +0 -42
- package/dist/dist-BF6r1hfv.mjs +0 -308
- package/dist/logs-DUwdYZB-.mjs +0 -28
- package/dist/logs.handler-dcRq-zoc.mjs +0 -35
- package/dist/{agent-bundle-package-DWV6B_5q-rRTPU13L.mjs → agent-bundle-package-DWV6B_5q-FPT0bJaA.mjs} +0 -0
- package/dist/{agent-manifest-CZdlCTFs.mjs → agent-manifest-tIsqF2OP.mjs} +0 -0
- package/dist/{browser-3cUiPlk2.mjs → browser-BpJ8ut9z.mjs} +0 -0
- package/dist/{common-BaGFkj3n.mjs → common-AK0q0Oz0.mjs} +0 -0
- package/dist/{concurrency-gXn9Rw8x-BI6HQNfC.mjs → concurrency-gXn9Rw8x-BTlfau8D.mjs} +0 -0
- package/dist/{cron-parser-C2eJD0yD.mjs → cron-parser-Dw_cWzFu.mjs} +0 -0
- package/dist/{declared-credential-requirements-B6h4WRv4.mjs → declared-credential-requirements-D6KT-r-e.mjs} +0 -0
- package/dist/{default-urls-BS4twrsS.mjs → default-urls-CTQqM1_A.mjs} +0 -0
- package/dist/{layout-CXkZEsXI.mjs → layout-P1v-Gssz.mjs} +0 -0
- package/dist/{metadata-layout-Bv-B0nHj-CqlcZz_g.mjs → metadata-layout-Bv-B0nHj-B1c5giJ7.mjs} +1 -1
- package/dist/{oxc-B3KI3rf_-DdiZWqe2.mjs → oxc-B3KI3rf_-Cvx4Z-4H.mjs} +0 -0
- package/dist/{project-config-CsBMT4TL.mjs → project-config-DudGRFPO.mjs} +1 -1
- package/dist/{read-credential-keys-77a91T8M-DMmY6oDW.mjs → read-credential-keys-77a91T8M-B0eiobOd.mjs} +0 -0
- package/dist/{rolldown-runtime-twds-ZHy-CO5ir_za.mjs → rolldown-runtime-twds-ZHy-8uqgIurC.mjs} +0 -0
- package/dist/{run-polling-CwlzB5-9.mjs → run-polling-DARidqo-.mjs} +0 -0
- package/dist/{schema-O9xTWad_.mjs → schema-BjH_e4Fo.mjs} +0 -0
- package/dist/{schema-_FQrHcIS.mjs → schema-Lbp5lGJu.mjs} +0 -0
- package/dist/{schema-display-CNqiYBIb.mjs → schema-display-NVEl_DFY.mjs} +0 -0
- package/dist/{schemas-DodkHgnS.mjs → schemas-B8c7Z5Iy.mjs} +0 -0
- package/dist/{source-analysis-CJPymdaA.mjs → source-analysis-Cs0CTBQk.mjs} +0 -0
- package/dist/{types-D04ah3uY.mjs → types-BMBuhHhW.mjs} +0 -0
- package/dist/{upload-wwSPAC5_.mjs → upload-BbcMkyVl.mjs} +1 -1
package/dist/keystroke.mjs
CHANGED
|
@@ -1,19 +1,527 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
import * as fs from "node:fs";
|
|
6
|
-
import { existsSync, writeFileSync } from "node:fs";
|
|
7
|
-
import * as fsPromises from "node:fs/promises";
|
|
3
|
+
import { n as getKeystrokeBaseDir } from "./paths-JzzFkXQA-CEipIeVl.mjs";
|
|
4
|
+
import { n as DEFAULT_CLI_WEB_URL, t as DEFAULT_CLI_SERVER_URL } from "./default-urls-CTQqM1_A.mjs";
|
|
8
5
|
import * as os from "node:os";
|
|
9
6
|
import * as path$1 from "node:path";
|
|
10
7
|
import path from "node:path";
|
|
8
|
+
import * as fsPromises from "node:fs/promises";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { Command, CommanderError, Option } from "commander";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
13
|
import { config } from "dotenv";
|
|
13
14
|
import { z } from "zod";
|
|
14
15
|
import { log } from "@clack/prompts";
|
|
16
|
+
//#region ../../packages/local-memory/dist/logger/index.mjs
|
|
17
|
+
const LOGS_DIR = "logs";
|
|
18
|
+
const LOG_FILE = "cli.jsonl";
|
|
19
|
+
/**
|
|
20
|
+
* Returns the absolute path to the active CLI log file.
|
|
21
|
+
*
|
|
22
|
+
* Defaults to `~/.keystroke/logs/cli.jsonl`; tests pass a custom `homeDir`
|
|
23
|
+
* to isolate from the real user home.
|
|
24
|
+
*/
|
|
25
|
+
function getLogFilePath(homeDir = os.homedir()) {
|
|
26
|
+
return path$1.join(getKeystrokeBaseDir(homeDir), LOGS_DIR, LOG_FILE);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Clears the active CLI log file in place. Returns `true` when the file existed
|
|
30
|
+
* and was truncated, `false` when no log file was present (idempotent).
|
|
31
|
+
*/
|
|
32
|
+
async function clearLog(homeDir) {
|
|
33
|
+
try {
|
|
34
|
+
await fsPromises.truncate(getLogFilePath(homeDir), 0);
|
|
35
|
+
return true;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (isNotFoundError(error)) return false;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isNotFoundError(error) {
|
|
42
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Original console methods, captured at module load time before any patching.
|
|
46
|
+
*
|
|
47
|
+
* Use these from CLI code that needs to write to the real terminal regardless
|
|
48
|
+
* of whether `installConsoleCapture()` has been called (e.g. `keystroke logs`
|
|
49
|
+
* pretty-printer, table renderers, spinners).
|
|
50
|
+
*/
|
|
51
|
+
const originalConsole = {
|
|
52
|
+
log: console.log.bind(console),
|
|
53
|
+
info: console.info.bind(console),
|
|
54
|
+
warn: console.warn.bind(console),
|
|
55
|
+
error: console.error.bind(console),
|
|
56
|
+
debug: console.debug.bind(console)
|
|
57
|
+
};
|
|
58
|
+
/** Methods we patch and the log level each one maps to. */
|
|
59
|
+
const METHOD_LEVEL_MAP = {
|
|
60
|
+
log: "info",
|
|
61
|
+
info: "info",
|
|
62
|
+
warn: "warn",
|
|
63
|
+
error: "error",
|
|
64
|
+
debug: "debug"
|
|
65
|
+
};
|
|
66
|
+
let capturing = false;
|
|
67
|
+
let restoreCapture = null;
|
|
68
|
+
/**
|
|
69
|
+
* Patches global `console.{log,info,warn,error,debug}` to capture output from
|
|
70
|
+
* third-party and workspace packages. Captured output is routed through
|
|
71
|
+
* `options.emit` (typically into the log file). When `forwardToConsole`
|
|
72
|
+
* returns true, the original console method is also invoked so the user
|
|
73
|
+
* sees the output in the terminal — used by `--debug` mode.
|
|
74
|
+
*
|
|
75
|
+
* Idempotent: calling twice has no additional effect and returns the active
|
|
76
|
+
* restore function.
|
|
77
|
+
*/
|
|
78
|
+
function installConsoleCapture(options) {
|
|
79
|
+
if (capturing) return restoreCapture ?? (() => void 0);
|
|
80
|
+
capturing = true;
|
|
81
|
+
const previousConsole = {
|
|
82
|
+
log: console.log,
|
|
83
|
+
info: console.info,
|
|
84
|
+
warn: console.warn,
|
|
85
|
+
error: console.error,
|
|
86
|
+
debug: console.debug
|
|
87
|
+
};
|
|
88
|
+
for (const [method, level] of Object.entries(METHOD_LEVEL_MAP)) {
|
|
89
|
+
const original = originalConsole[method];
|
|
90
|
+
console[method] = (...args) => {
|
|
91
|
+
const message = args.map(String).join(" ");
|
|
92
|
+
options.emit(level, `[captured] ${message}`);
|
|
93
|
+
if (options.forwardToConsole?.()) original(...args);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
restoreCapture = () => {
|
|
97
|
+
for (const method of Object.keys(METHOD_LEVEL_MAP)) console[method] = previousConsole[method];
|
|
98
|
+
capturing = false;
|
|
99
|
+
restoreCapture = null;
|
|
100
|
+
};
|
|
101
|
+
return restoreCapture;
|
|
102
|
+
}
|
|
103
|
+
/** Restores console methods patched by `installConsoleCapture()`, if active. */
|
|
104
|
+
function restoreConsoleCapture() {
|
|
105
|
+
restoreCapture?.();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Reads CLI log entries as parsed `LogEntry` objects. Returns an empty array
|
|
109
|
+
* when the file does not exist.
|
|
110
|
+
*
|
|
111
|
+
* Lines that fail to parse as valid `LogEntry` JSON are dropped silently —
|
|
112
|
+
* the log file is best-effort, and corrupt lines should never break
|
|
113
|
+
* `keystroke logs`.
|
|
114
|
+
*/
|
|
115
|
+
async function readLogEntries(optionsOrCount = 100, homeDir) {
|
|
116
|
+
const options = normalizeOptions(optionsOrCount, homeDir);
|
|
117
|
+
const filePath = getLogFilePath(options.homeDir);
|
|
118
|
+
let content;
|
|
119
|
+
try {
|
|
120
|
+
content = await fsPromises.readFile(filePath, "utf-8");
|
|
121
|
+
} catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
const lines = content.split("\n");
|
|
125
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
126
|
+
const entries = [];
|
|
127
|
+
for (const line of lines) {
|
|
128
|
+
const parsed = parseEntry(line);
|
|
129
|
+
if (parsed && matchesFilters(parsed, options)) entries.push(parsed);
|
|
130
|
+
}
|
|
131
|
+
return entries.slice(-options.count);
|
|
132
|
+
}
|
|
133
|
+
function normalizeOptions(optionsOrCount, homeDir) {
|
|
134
|
+
if (typeof optionsOrCount === "number") return {
|
|
135
|
+
count: optionsOrCount,
|
|
136
|
+
homeDir
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
...optionsOrCount,
|
|
140
|
+
count: optionsOrCount.count ?? 100
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function matchesFilters(entry, options) {
|
|
144
|
+
if (options.level !== void 0 && entry.level !== options.level) return false;
|
|
145
|
+
if (options.messageIncludes !== void 0 && !entry.message.includes(options.messageIncludes)) return false;
|
|
146
|
+
if (options.meta !== void 0 && !matchesMeta(entry, options.meta)) return false;
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
function matchesMeta(entry, expected) {
|
|
150
|
+
if (entry.meta === void 0) return false;
|
|
151
|
+
return Object.entries(expected).every(([key, value]) => entry.meta?.[key] === value);
|
|
152
|
+
}
|
|
153
|
+
function parseEntry(line) {
|
|
154
|
+
let raw;
|
|
155
|
+
try {
|
|
156
|
+
raw = JSON.parse(line);
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (!isPlainObject$1(raw)) return null;
|
|
161
|
+
const timestamp = raw.timestamp;
|
|
162
|
+
const level = raw.level;
|
|
163
|
+
const message = raw.message;
|
|
164
|
+
if (typeof timestamp !== "string") return null;
|
|
165
|
+
if (typeof message !== "string") return null;
|
|
166
|
+
if (!isLogLevel(level)) return null;
|
|
167
|
+
const meta = raw.meta;
|
|
168
|
+
if (meta !== void 0 && !isPlainObject$1(meta)) return null;
|
|
169
|
+
return {
|
|
170
|
+
timestamp,
|
|
171
|
+
level,
|
|
172
|
+
message,
|
|
173
|
+
...meta !== void 0 ? { meta } : {}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function isPlainObject$1(value) {
|
|
177
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
178
|
+
}
|
|
179
|
+
function isLogLevel(value) {
|
|
180
|
+
return value === "debug" || value === "info" || value === "warn" || value === "error";
|
|
181
|
+
}
|
|
182
|
+
const REDACTED = "[REDACTED]";
|
|
183
|
+
const SENSITIVE_KEYS = new Set([
|
|
184
|
+
"apikey",
|
|
185
|
+
"authorization",
|
|
186
|
+
"cookie",
|
|
187
|
+
"jwt",
|
|
188
|
+
"privatekey",
|
|
189
|
+
"session",
|
|
190
|
+
"setcookie",
|
|
191
|
+
"token",
|
|
192
|
+
"accesstoken",
|
|
193
|
+
"refreshtoken",
|
|
194
|
+
"clientsecret",
|
|
195
|
+
"secret",
|
|
196
|
+
"password",
|
|
197
|
+
"xapikey"
|
|
198
|
+
]);
|
|
199
|
+
function redactLogMeta(meta) {
|
|
200
|
+
return redactPlainObject(meta, /* @__PURE__ */ new WeakSet());
|
|
201
|
+
}
|
|
202
|
+
function redactValue(value, ancestors) {
|
|
203
|
+
if (Array.isArray(value)) {
|
|
204
|
+
if (ancestors.has(value)) return value;
|
|
205
|
+
ancestors.add(value);
|
|
206
|
+
const redacted = value.map((item) => redactValue(item, ancestors));
|
|
207
|
+
ancestors.delete(value);
|
|
208
|
+
return redacted;
|
|
209
|
+
}
|
|
210
|
+
if (isPlainObject(value)) {
|
|
211
|
+
if (ancestors.has(value)) return value;
|
|
212
|
+
ancestors.add(value);
|
|
213
|
+
const redacted = redactPlainObject(value, ancestors);
|
|
214
|
+
ancestors.delete(value);
|
|
215
|
+
return redacted;
|
|
216
|
+
}
|
|
217
|
+
return value;
|
|
218
|
+
}
|
|
219
|
+
function redactPlainObject(value, ancestors) {
|
|
220
|
+
const redacted = {};
|
|
221
|
+
for (const [key, childValue] of Object.entries(value)) redacted[key] = isSensitiveKey(key) ? REDACTED : redactValue(childValue, ancestors);
|
|
222
|
+
return redacted;
|
|
223
|
+
}
|
|
224
|
+
function isSensitiveKey(key) {
|
|
225
|
+
return SENSITIVE_KEYS.has(normalizeKey(key));
|
|
226
|
+
}
|
|
227
|
+
function normalizeKey(key) {
|
|
228
|
+
return key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
229
|
+
}
|
|
230
|
+
function isPlainObject(value) {
|
|
231
|
+
if (value === null || typeof value !== "object") return false;
|
|
232
|
+
const prototype = Object.getPrototypeOf(value);
|
|
233
|
+
return prototype === Object.prototype || prototype === null;
|
|
234
|
+
}
|
|
235
|
+
const LEVEL_RANK = {
|
|
236
|
+
debug: 10,
|
|
237
|
+
info: 20,
|
|
238
|
+
warn: 30,
|
|
239
|
+
error: 40
|
|
240
|
+
};
|
|
241
|
+
/** Returns true if `entryLevel` should be emitted given the configured `minLevel`. */
|
|
242
|
+
function shouldEmit(entryLevel, minLevel) {
|
|
243
|
+
return LEVEL_RANK[entryLevel] >= LEVEL_RANK[minLevel];
|
|
244
|
+
}
|
|
245
|
+
function createLogger(options) {
|
|
246
|
+
let currentLevel = options.level ?? "info";
|
|
247
|
+
let stream;
|
|
248
|
+
let closed = false;
|
|
249
|
+
const ownsStream = options.destination === void 0;
|
|
250
|
+
if (options.destination) stream = options.destination;
|
|
251
|
+
else {
|
|
252
|
+
fs.mkdirSync(path$1.dirname(options.filePath), { recursive: true });
|
|
253
|
+
stream = fs.createWriteStream(options.filePath, { flags: "a" });
|
|
254
|
+
stream.on("error", () => {});
|
|
255
|
+
}
|
|
256
|
+
function write(level, message, meta) {
|
|
257
|
+
if (closed || !shouldEmit(level, currentLevel)) return;
|
|
258
|
+
const redactedMeta = meta !== void 0 ? redactLogMeta(meta) : void 0;
|
|
259
|
+
const entry = {
|
|
260
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
261
|
+
level,
|
|
262
|
+
message,
|
|
263
|
+
...redactedMeta !== void 0 ? { meta: redactedMeta } : {}
|
|
264
|
+
};
|
|
265
|
+
if ("destroyed" in stream && stream.destroyed) return;
|
|
266
|
+
if ("writable" in stream && stream.writable === false) return;
|
|
267
|
+
try {
|
|
268
|
+
stream.write(`${JSON.stringify(entry)}\n`);
|
|
269
|
+
} catch {}
|
|
270
|
+
}
|
|
271
|
+
function makeLogger(boundMeta) {
|
|
272
|
+
const mergeMeta = (meta) => {
|
|
273
|
+
if (Object.keys(boundMeta).length === 0) return meta;
|
|
274
|
+
return meta ? {
|
|
275
|
+
...boundMeta,
|
|
276
|
+
...meta
|
|
277
|
+
} : { ...boundMeta };
|
|
278
|
+
};
|
|
279
|
+
return {
|
|
280
|
+
debug: (msg, meta) => write("debug", msg, mergeMeta(meta)),
|
|
281
|
+
info: (msg, meta) => write("info", msg, mergeMeta(meta)),
|
|
282
|
+
warn: (msg, meta) => write("warn", msg, mergeMeta(meta)),
|
|
283
|
+
error: (msg, meta) => write("error", msg, mergeMeta(meta)),
|
|
284
|
+
child: (bindings) => makeLogger({
|
|
285
|
+
...boundMeta,
|
|
286
|
+
...bindings
|
|
287
|
+
}),
|
|
288
|
+
flush: async () => {}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
logger: makeLogger({}),
|
|
293
|
+
setLevel(level) {
|
|
294
|
+
currentLevel = level;
|
|
295
|
+
},
|
|
296
|
+
getLevel() {
|
|
297
|
+
return currentLevel;
|
|
298
|
+
},
|
|
299
|
+
flush: async () => {
|
|
300
|
+
if (!ownsStream) return;
|
|
301
|
+
await new Promise((resolve) => {
|
|
302
|
+
stream.write("", () => resolve());
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
close: async () => {
|
|
306
|
+
if (closed) return;
|
|
307
|
+
closed = true;
|
|
308
|
+
if (!ownsStream) return;
|
|
309
|
+
await new Promise((resolve) => {
|
|
310
|
+
const fileStream = stream;
|
|
311
|
+
if (fileStream.destroyed) {
|
|
312
|
+
resolve();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
fileStream.end(() => resolve());
|
|
316
|
+
});
|
|
317
|
+
},
|
|
318
|
+
filePath: options.filePath
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Tiny ANSI helper used by the debug-mode mirror to dim log lines on stderr.
|
|
323
|
+
*
|
|
324
|
+
* Internal to the logger module — the wider local-memory package has no UI
|
|
325
|
+
* concern. CLI consumers have richer terminal/colors libraries; we only need
|
|
326
|
+
* "dim" here so the captured log lines visually fade behind the user-facing
|
|
327
|
+
* output.
|
|
328
|
+
*/
|
|
329
|
+
const ESC = "\x1B[";
|
|
330
|
+
const ANSI$1 = {
|
|
331
|
+
reset: `${ESC}0m`,
|
|
332
|
+
dim: `${ESC}2m`
|
|
333
|
+
};
|
|
334
|
+
/** Returns `code + s + reset`, or `s` unchanged if stderr is not a TTY. */
|
|
335
|
+
function style$1(s, code) {
|
|
336
|
+
if (!process.stderr.isTTY) return s;
|
|
337
|
+
return `${code}${s}${ANSI$1.reset}`;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Maximum number of log lines to keep when pruning. Lines beyond this count
|
|
341
|
+
* (oldest first) are dropped on next prune.
|
|
342
|
+
*/
|
|
343
|
+
const MAX_LOG_LINES = 25e4;
|
|
344
|
+
/**
|
|
345
|
+
* Maximum number of bytes to read from the tail of the log file when pruning.
|
|
346
|
+
* If the file is larger than this, only this many bytes are inspected — older
|
|
347
|
+
* lines beyond this window are dropped wholesale.
|
|
348
|
+
*/
|
|
349
|
+
const MAX_PRUNE_READ_BYTES = 32 * 1024 * 1024;
|
|
350
|
+
/**
|
|
351
|
+
* Truncates the log file to keep only the most recent `MAX_LOG_LINES` lines.
|
|
352
|
+
* Best-effort: failures are silent (the file is non-critical telemetry).
|
|
353
|
+
*
|
|
354
|
+
* This remains the local CLI log retention strategy: simple, dependency-free,
|
|
355
|
+
* and best-effort because the file is non-critical telemetry.
|
|
356
|
+
*/
|
|
357
|
+
async function pruneLogFile(homeDir) {
|
|
358
|
+
const filePath = getLogFilePath(homeDir);
|
|
359
|
+
let content;
|
|
360
|
+
try {
|
|
361
|
+
content = await readTailForPrune(filePath);
|
|
362
|
+
} catch {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const lines = content.split("\n");
|
|
366
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
367
|
+
if (lines.length <= 25e4) return;
|
|
368
|
+
const kept = lines.slice(lines.length - MAX_LOG_LINES);
|
|
369
|
+
await fsPromises.writeFile(filePath, `${kept.join("\n")}\n`);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Reads up to the last `MAX_PRUNE_READ_BYTES` of the file. If the file is
|
|
373
|
+
* larger than that, drops the first partial line so we don't try to parse
|
|
374
|
+
* a half-written record.
|
|
375
|
+
*/
|
|
376
|
+
async function readTailForPrune(filePath) {
|
|
377
|
+
const handle = await fsPromises.open(filePath, "r");
|
|
378
|
+
try {
|
|
379
|
+
const stats = await handle.stat();
|
|
380
|
+
const bytesToRead = Math.min(stats.size, MAX_PRUNE_READ_BYTES);
|
|
381
|
+
if (bytesToRead <= 0) return "";
|
|
382
|
+
const start = Math.max(0, stats.size - bytesToRead);
|
|
383
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
384
|
+
const { bytesRead } = await handle.read(buffer, 0, bytesToRead, start);
|
|
385
|
+
let content = buffer.subarray(0, bytesRead).toString("utf8");
|
|
386
|
+
if (start > 0) {
|
|
387
|
+
const firstNewline = content.indexOf("\n");
|
|
388
|
+
if (firstNewline === -1) return "";
|
|
389
|
+
content = content.slice(firstNewline + 1);
|
|
390
|
+
}
|
|
391
|
+
return content;
|
|
392
|
+
} finally {
|
|
393
|
+
await handle.close();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
let instance = null;
|
|
397
|
+
let debugMode = false;
|
|
398
|
+
const DEBUG_PREFIXES = {
|
|
399
|
+
debug: "[DEBUG]",
|
|
400
|
+
info: "[INFO]",
|
|
401
|
+
warn: "[WARN]",
|
|
402
|
+
error: "[ERROR]"
|
|
403
|
+
};
|
|
404
|
+
function formatTimestamp() {
|
|
405
|
+
const now = /* @__PURE__ */ new Date();
|
|
406
|
+
return `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}.${String(now.getMilliseconds()).padStart(3, "0")}`;
|
|
407
|
+
}
|
|
408
|
+
function maybeMirrorToStderr(level, message, meta) {
|
|
409
|
+
if (!debugMode) return;
|
|
410
|
+
const ts = formatTimestamp();
|
|
411
|
+
const prefix = DEBUG_PREFIXES[level];
|
|
412
|
+
const redactedMeta = meta !== void 0 ? redactLogMeta(meta) : void 0;
|
|
413
|
+
const formatted = meta ? `${ts} ${prefix} ${message} ${JSON.stringify(redactedMeta)}` : `${ts} ${prefix} ${message}`;
|
|
414
|
+
originalConsole.info(style$1(formatted, ANSI$1.dim));
|
|
415
|
+
}
|
|
416
|
+
function withDebugMirroring(inner, boundMeta = {}) {
|
|
417
|
+
const mergeMeta = (meta) => {
|
|
418
|
+
if (Object.keys(boundMeta).length === 0) return meta;
|
|
419
|
+
return meta ? {
|
|
420
|
+
...boundMeta,
|
|
421
|
+
...meta
|
|
422
|
+
} : { ...boundMeta };
|
|
423
|
+
};
|
|
424
|
+
return {
|
|
425
|
+
debug: (msg, meta) => {
|
|
426
|
+
maybeMirrorToStderr("debug", msg, mergeMeta(meta));
|
|
427
|
+
inner.debug(msg, meta);
|
|
428
|
+
},
|
|
429
|
+
info: (msg, meta) => {
|
|
430
|
+
maybeMirrorToStderr("info", msg, mergeMeta(meta));
|
|
431
|
+
inner.info(msg, meta);
|
|
432
|
+
},
|
|
433
|
+
warn: (msg, meta) => {
|
|
434
|
+
maybeMirrorToStderr("warn", msg, mergeMeta(meta));
|
|
435
|
+
inner.warn(msg, meta);
|
|
436
|
+
},
|
|
437
|
+
error: (msg, meta) => {
|
|
438
|
+
maybeMirrorToStderr("error", msg, mergeMeta(meta));
|
|
439
|
+
inner.error(msg, meta);
|
|
440
|
+
},
|
|
441
|
+
child: (bindings) => withDebugMirroring(inner.child(bindings), {
|
|
442
|
+
...boundMeta,
|
|
443
|
+
...bindings
|
|
444
|
+
}),
|
|
445
|
+
flush: () => inner.flush()
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
function buildSingleton(options = {}) {
|
|
449
|
+
const internal = createLogger({
|
|
450
|
+
filePath: getLogFilePath(options.homeDir),
|
|
451
|
+
level: options.level ?? "info"
|
|
452
|
+
});
|
|
453
|
+
return {
|
|
454
|
+
...internal,
|
|
455
|
+
logger: withDebugMirroring(internal.logger)
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Initializes the process-wide singleton logger. Optional — the singleton is
|
|
460
|
+
* lazily created on first `getLogger()` call. Use `initLogger()` explicitly
|
|
461
|
+
* when you want to control the level, prune the log file, or install console
|
|
462
|
+
* capture at a known point in CLI startup.
|
|
463
|
+
*/
|
|
464
|
+
async function initLogger(options = {}) {
|
|
465
|
+
if (instance === null && options.prune !== false) await pruneLogFile(options.homeDir).catch((error) => {
|
|
466
|
+
if (process.env.KEYSTROKE_DEBUG_LOGGER === "1") {
|
|
467
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
468
|
+
originalConsole.warn(`[logger] Failed to prune CLI log file: ${message}`);
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
if (instance === null) instance = buildSingleton(options);
|
|
472
|
+
else if (options.level !== void 0) instance.setLevel(options.level);
|
|
473
|
+
if (options.captureConsole !== false) installConsoleCapture({
|
|
474
|
+
emit: (level, message) => {
|
|
475
|
+
instance?.logger[level](message);
|
|
476
|
+
},
|
|
477
|
+
forwardToConsole: () => debugMode
|
|
478
|
+
});
|
|
479
|
+
else restoreConsoleCapture();
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Returns the singleton logger. Lazily initialized on first call (with
|
|
483
|
+
* default options) if `initLogger()` has not been called yet.
|
|
484
|
+
*/
|
|
485
|
+
function getLogger() {
|
|
486
|
+
if (instance === null) instance = buildSingleton();
|
|
487
|
+
return instance.logger;
|
|
488
|
+
}
|
|
489
|
+
/** Flushes pending writes and closes the underlying file stream. Idempotent. */
|
|
490
|
+
async function closeLogger() {
|
|
491
|
+
if (instance === null) {
|
|
492
|
+
restoreConsoleCapture();
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
await instance.flush();
|
|
496
|
+
await instance.close();
|
|
497
|
+
instance = null;
|
|
498
|
+
restoreConsoleCapture();
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Toggles debug mode. When enabled:
|
|
502
|
+
* - Every log line is mirrored to stderr (dimmed) for visibility.
|
|
503
|
+
* - Console capture forwards captured calls to the real console method.
|
|
504
|
+
*/
|
|
505
|
+
function setDebug(enabled) {
|
|
506
|
+
debugMode = enabled;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Convenience proxy that delegates every call to the singleton logger. Lets
|
|
510
|
+
* call sites use `import { logger } from '@keystroke/local-memory/logger'`
|
|
511
|
+
* without thinking about lifecycle — the singleton lazily initializes on
|
|
512
|
+
* first use.
|
|
513
|
+
*/
|
|
514
|
+
const logger = {
|
|
515
|
+
debug: (msg, meta) => getLogger().debug(msg, meta),
|
|
516
|
+
info: (msg, meta) => getLogger().info(msg, meta),
|
|
517
|
+
warn: (msg, meta) => getLogger().warn(msg, meta),
|
|
518
|
+
error: (msg, meta) => getLogger().error(msg, meta),
|
|
519
|
+
child: (bindings) => getLogger().child(bindings),
|
|
520
|
+
flush: () => getLogger().flush()
|
|
521
|
+
};
|
|
522
|
+
//#endregion
|
|
15
523
|
//#region package.json
|
|
16
|
-
var version = "0.0.
|
|
524
|
+
var version = "0.0.18";
|
|
17
525
|
//#endregion
|
|
18
526
|
//#region src/command-registry.ts
|
|
19
527
|
const ROOT_OPTIONS_WITH_VALUES$1 = new Set([
|
|
@@ -25,84 +533,84 @@ const ROOT_VERSION_FLAGS = new Set(["-V", "--version"]);
|
|
|
25
533
|
const lazyCommandDefinitions = [
|
|
26
534
|
{
|
|
27
535
|
name: "agents",
|
|
28
|
-
loadCommand: async () => (await import("./agents-
|
|
536
|
+
loadCommand: async () => (await import("./agents-Co6Jy_N8.mjs")).createAgentsCommand()
|
|
29
537
|
},
|
|
30
538
|
{
|
|
31
539
|
name: "admin",
|
|
32
|
-
loadCommand: async () => (await import("./admin-
|
|
540
|
+
loadCommand: async () => (await import("./admin-CYpulx_A.mjs")).createAdminCommand()
|
|
33
541
|
},
|
|
34
542
|
{
|
|
35
543
|
name: "api-keys",
|
|
36
|
-
loadCommand: async () => (await import("./api-keys-
|
|
544
|
+
loadCommand: async () => (await import("./api-keys-BUCLzRv_.mjs")).createApiKeysCommand()
|
|
37
545
|
},
|
|
38
546
|
{
|
|
39
547
|
name: "auth",
|
|
40
|
-
loadCommand: async () => (await import("./auth-
|
|
548
|
+
loadCommand: async () => (await import("./auth-niNm-yNT.mjs")).createAuthCommand()
|
|
41
549
|
},
|
|
42
550
|
{
|
|
43
551
|
name: "connect",
|
|
44
|
-
loadCommand: async () => (await import("./connect-
|
|
552
|
+
loadCommand: async () => (await import("./connect-C9NMD8Ky.mjs")).createConnectCommand()
|
|
45
553
|
},
|
|
46
554
|
{
|
|
47
555
|
name: "credentials",
|
|
48
|
-
loadCommand: async () => (await import("./credentials-
|
|
556
|
+
loadCommand: async () => (await import("./credentials-fMfKVlEn.mjs")).createCredentialsCommand(),
|
|
49
557
|
copyInheritedSettings: true
|
|
50
558
|
},
|
|
51
559
|
{
|
|
52
560
|
name: "org",
|
|
53
|
-
loadCommand: async () => (await import("./org-
|
|
561
|
+
loadCommand: async () => (await import("./org-DGS91uc-.mjs")).createOrgCommand()
|
|
54
562
|
},
|
|
55
563
|
{
|
|
56
564
|
name: "deploy",
|
|
57
|
-
loadCommand: async () => (await import("./deploy-
|
|
565
|
+
loadCommand: async () => (await import("./deploy-B7LRWcp6.mjs")).createDeployCommand()
|
|
58
566
|
},
|
|
59
567
|
{
|
|
60
568
|
name: "init",
|
|
61
|
-
loadCommand: async () => (await import("./init-
|
|
569
|
+
loadCommand: async () => (await import("./init-jaqNLGmB.mjs")).createInitCommand()
|
|
62
570
|
},
|
|
63
571
|
{
|
|
64
572
|
name: "integrations",
|
|
65
|
-
loadCommand: async () => (await import("./integrations-
|
|
573
|
+
loadCommand: async () => (await import("./integrations-DRL3JmC8.mjs")).createIntegrationsCommand()
|
|
66
574
|
},
|
|
67
575
|
{
|
|
68
576
|
name: "invites",
|
|
69
|
-
loadCommand: async () => (await import("./invites-
|
|
577
|
+
loadCommand: async () => (await import("./invites-VntHNMYk.mjs")).createInvitesCommand()
|
|
70
578
|
},
|
|
71
579
|
{
|
|
72
580
|
name: "logs",
|
|
73
|
-
loadCommand: async () => (await import("./logs-
|
|
581
|
+
loadCommand: async () => (await import("./logs-CcYqFKRU.mjs")).createLogsCommand()
|
|
74
582
|
},
|
|
75
583
|
{
|
|
76
584
|
name: "listen",
|
|
77
|
-
loadCommand: async () => (await import("./listen-
|
|
585
|
+
loadCommand: async () => (await import("./listen-DLGZEQRL.mjs")).createListenCommand()
|
|
78
586
|
},
|
|
79
587
|
{
|
|
80
588
|
name: "projects",
|
|
81
|
-
loadCommand: async () => (await import("./projects-
|
|
589
|
+
loadCommand: async () => (await import("./projects-D90_uEC2.mjs")).createProjectsCommand()
|
|
82
590
|
},
|
|
83
591
|
{
|
|
84
592
|
name: "runs",
|
|
85
|
-
loadCommand: async () => (await import("./runs-
|
|
593
|
+
loadCommand: async () => (await import("./runs-Bg_qDeQi.mjs")).createRunsCommand()
|
|
86
594
|
},
|
|
87
595
|
{
|
|
88
596
|
name: "skills",
|
|
89
|
-
loadCommand: async () => (await import("./skills.command-
|
|
597
|
+
loadCommand: async () => (await import("./skills.command-JwKWpGvU.mjs")).createSkillsCommand()
|
|
90
598
|
},
|
|
91
599
|
{
|
|
92
600
|
name: "sync",
|
|
93
|
-
loadCommand: async () => (await import("./sync-
|
|
601
|
+
loadCommand: async () => (await import("./sync-CXNveL61.mjs")).createSyncCommand()
|
|
94
602
|
},
|
|
95
603
|
{
|
|
96
604
|
name: "test",
|
|
97
|
-
loadCommand: async () => (await import("./test-
|
|
605
|
+
loadCommand: async () => (await import("./test-A5hz3c7j.mjs")).createTestCommand()
|
|
98
606
|
},
|
|
99
607
|
{
|
|
100
608
|
name: "upgrade",
|
|
101
|
-
loadCommand: async () => (await import("./upgrade-
|
|
609
|
+
loadCommand: async () => (await import("./upgrade-DhfpoyRV.mjs")).createUpgradeCommand()
|
|
102
610
|
},
|
|
103
611
|
{
|
|
104
612
|
name: "workflows",
|
|
105
|
-
loadCommand: async () => (await import("./workflows-
|
|
613
|
+
loadCommand: async () => (await import("./workflows-Dy2M9bEr.mjs")).createWorkflowsCommand()
|
|
106
614
|
}
|
|
107
615
|
];
|
|
108
616
|
function selectCommandRegistration(argv, commandNames = new Set(lazyCommandDefinitions.map((definition) => definition.name))) {
|
|
@@ -295,183 +803,6 @@ async function getApiErrorCode(error) {
|
|
|
295
803
|
}
|
|
296
804
|
}
|
|
297
805
|
//#endregion
|
|
298
|
-
//#region src/lib/tty.ts
|
|
299
|
-
function isTTY() {
|
|
300
|
-
return process.stdout.isTTY === true;
|
|
301
|
-
}
|
|
302
|
-
//#endregion
|
|
303
|
-
//#region src/lib/terminal.ts
|
|
304
|
-
const ANSI = {
|
|
305
|
-
reset: "\x1B[0m",
|
|
306
|
-
bold: "\x1B[1m",
|
|
307
|
-
dim: "\x1B[2m",
|
|
308
|
-
red: "\x1B[31m",
|
|
309
|
-
cyan: "\x1B[36m",
|
|
310
|
-
green: "\x1B[32m",
|
|
311
|
-
yellow: "\x1B[33m"
|
|
312
|
-
};
|
|
313
|
-
function style(text, color) {
|
|
314
|
-
if (!isTTY()) return text;
|
|
315
|
-
return `${color}${text}${ANSI.reset}`;
|
|
316
|
-
}
|
|
317
|
-
//#endregion
|
|
318
|
-
//#region src/lib/logger.ts
|
|
319
|
-
/**
|
|
320
|
-
* Original console methods, saved before any patching.
|
|
321
|
-
* Used by ui.ts to always write to the real terminal regardless of capture.
|
|
322
|
-
*/
|
|
323
|
-
const originalConsole = {
|
|
324
|
-
log: console.log.bind(console),
|
|
325
|
-
info: console.info.bind(console),
|
|
326
|
-
warn: console.warn.bind(console),
|
|
327
|
-
error: console.error.bind(console),
|
|
328
|
-
debug: console.debug.bind(console)
|
|
329
|
-
};
|
|
330
|
-
let stream = null;
|
|
331
|
-
let debugMode = false;
|
|
332
|
-
/** When true, do not open or write the log file (avoids races after {@link logger.close}). */
|
|
333
|
-
let loggingClosed = false;
|
|
334
|
-
const KEYSTROKE_CREDENTIALS_DIR = ".keystroke";
|
|
335
|
-
const KEYSTROKE_LOGS_DIR = "logs";
|
|
336
|
-
const KEYSTROKE_LOG_FILE = "cli.jsonl";
|
|
337
|
-
const MAX_LOG_LINES = 25e4;
|
|
338
|
-
const MAX_PRUNE_READ_BYTES = 32 * 1024 * 1024;
|
|
339
|
-
const DEBUG_PREFIXES = {
|
|
340
|
-
debug: "[DEBUG]",
|
|
341
|
-
info: "[INFO]",
|
|
342
|
-
warn: "[WARN]",
|
|
343
|
-
error: "[ERROR]"
|
|
344
|
-
};
|
|
345
|
-
const LEVEL_MAP = {
|
|
346
|
-
log: "info",
|
|
347
|
-
info: "info",
|
|
348
|
-
warn: "warn",
|
|
349
|
-
error: "error",
|
|
350
|
-
debug: "debug"
|
|
351
|
-
};
|
|
352
|
-
function ensureStream() {
|
|
353
|
-
if (loggingClosed) return null;
|
|
354
|
-
if (!stream) {
|
|
355
|
-
const logFilePath = getLogFilePath();
|
|
356
|
-
fs.mkdirSync(path$1.dirname(logFilePath), { recursive: true });
|
|
357
|
-
stream = fs.createWriteStream(logFilePath, { flags: "a" });
|
|
358
|
-
stream.on("error", () => {});
|
|
359
|
-
}
|
|
360
|
-
return stream;
|
|
361
|
-
}
|
|
362
|
-
function getLogFilePath(homeDir = os.homedir()) {
|
|
363
|
-
return path$1.join(homeDir, KEYSTROKE_CREDENTIALS_DIR, KEYSTROKE_LOGS_DIR, KEYSTROKE_LOG_FILE);
|
|
364
|
-
}
|
|
365
|
-
async function readTailForPrune(filePath) {
|
|
366
|
-
const handle = await fsPromises.open(filePath, "r");
|
|
367
|
-
try {
|
|
368
|
-
const stats = await handle.stat();
|
|
369
|
-
const bytesToRead = Math.min(stats.size, MAX_PRUNE_READ_BYTES);
|
|
370
|
-
if (bytesToRead <= 0) return "";
|
|
371
|
-
const start = Math.max(0, stats.size - bytesToRead);
|
|
372
|
-
const buffer = Buffer.alloc(bytesToRead);
|
|
373
|
-
const { bytesRead } = await handle.read(buffer, 0, bytesToRead, start);
|
|
374
|
-
let content = buffer.subarray(0, bytesRead).toString("utf8");
|
|
375
|
-
if (start > 0) {
|
|
376
|
-
const firstNewline = content.indexOf("\n");
|
|
377
|
-
if (firstNewline === -1) return "";
|
|
378
|
-
content = content.slice(firstNewline + 1);
|
|
379
|
-
}
|
|
380
|
-
return content;
|
|
381
|
-
} finally {
|
|
382
|
-
await handle.close();
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
async function pruneLogFile() {
|
|
386
|
-
const filePath = getLogFilePath();
|
|
387
|
-
let content;
|
|
388
|
-
try {
|
|
389
|
-
content = await readTailForPrune(filePath);
|
|
390
|
-
} catch {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
const lines = content.split("\n");
|
|
394
|
-
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
395
|
-
if (lines.length <= MAX_LOG_LINES) return;
|
|
396
|
-
const kept = lines.slice(lines.length - MAX_LOG_LINES);
|
|
397
|
-
await fsPromises.writeFile(filePath, `${kept.join("\n")}\n`);
|
|
398
|
-
}
|
|
399
|
-
function formatTimestamp() {
|
|
400
|
-
const now = /* @__PURE__ */ new Date();
|
|
401
|
-
return `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}.${String(now.getMilliseconds()).padStart(3, "0")}`;
|
|
402
|
-
}
|
|
403
|
-
function write(level, message, meta) {
|
|
404
|
-
if (loggingClosed) return;
|
|
405
|
-
const entry = {
|
|
406
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
407
|
-
level,
|
|
408
|
-
message,
|
|
409
|
-
...meta !== void 0 ? { meta } : {}
|
|
410
|
-
};
|
|
411
|
-
const s = ensureStream();
|
|
412
|
-
if (s && !s.destroyed && s.writable) try {
|
|
413
|
-
s.write(`${JSON.stringify(entry)}\n`);
|
|
414
|
-
} catch {}
|
|
415
|
-
if (debugMode) {
|
|
416
|
-
const ts = formatTimestamp();
|
|
417
|
-
const prefix = DEBUG_PREFIXES[level];
|
|
418
|
-
const formatted = meta ? `${ts} ${prefix} ${message} ${JSON.stringify(meta)}` : `${ts} ${prefix} ${message}`;
|
|
419
|
-
originalConsole.info(style(formatted, ANSI.dim));
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Patches global console methods to capture output from third-party
|
|
424
|
-
* and workspace packages. Captured output is always written to the
|
|
425
|
-
* log file and only forwarded to the real console when --debug is active.
|
|
426
|
-
*/
|
|
427
|
-
function installConsoleCapture() {
|
|
428
|
-
for (const method of [
|
|
429
|
-
"log",
|
|
430
|
-
"info",
|
|
431
|
-
"warn",
|
|
432
|
-
"error",
|
|
433
|
-
"debug"
|
|
434
|
-
]) {
|
|
435
|
-
const level = LEVEL_MAP[method] ?? "info";
|
|
436
|
-
const original = originalConsole[method];
|
|
437
|
-
console[method] = (...args) => {
|
|
438
|
-
write(level, `[captured] ${args.map(String).join(" ")}`);
|
|
439
|
-
if (debugMode) original(...args);
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Initialize the logger: install console capture and prune the log file.
|
|
445
|
-
* Call once at CLI startup.
|
|
446
|
-
*/
|
|
447
|
-
function initLogger() {
|
|
448
|
-
installConsoleCapture();
|
|
449
|
-
pruneLogFile().catch((error) => {
|
|
450
|
-
if (process.env.KEYSTROKE_DEBUG_LOGGER === "1") {
|
|
451
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
452
|
-
originalConsole.warn(`[logger] Failed to prune CLI log file: ${message}`);
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
const logger = {
|
|
457
|
-
debug: (msg, meta) => write("debug", msg, meta),
|
|
458
|
-
info: (msg, meta) => write("info", msg, meta),
|
|
459
|
-
warn: (msg, meta) => write("warn", msg, meta),
|
|
460
|
-
error: (msg, meta) => write("error", msg, meta),
|
|
461
|
-
/** Enable or disable debug mode (shows all log entries in the console). */
|
|
462
|
-
setDebug(enabled) {
|
|
463
|
-
debugMode = enabled;
|
|
464
|
-
},
|
|
465
|
-
/** Stop accepting log writes and tear down the log file stream. */
|
|
466
|
-
close() {
|
|
467
|
-
loggingClosed = true;
|
|
468
|
-
if (stream) {
|
|
469
|
-
stream.end();
|
|
470
|
-
stream = null;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
//#endregion
|
|
475
806
|
//#region src/lib/cli-telemetry.ts
|
|
476
807
|
const TELEMETRY_TIMEOUT_MS = 2500;
|
|
477
808
|
let state = null;
|
|
@@ -822,6 +1153,26 @@ function isNpmPackageMetadata(value) {
|
|
|
822
1153
|
return typeof distTags.latest === "string";
|
|
823
1154
|
}
|
|
824
1155
|
//#endregion
|
|
1156
|
+
//#region src/lib/tty.ts
|
|
1157
|
+
function isTTY() {
|
|
1158
|
+
return process.stdout.isTTY === true;
|
|
1159
|
+
}
|
|
1160
|
+
//#endregion
|
|
1161
|
+
//#region src/lib/terminal.ts
|
|
1162
|
+
const ANSI = {
|
|
1163
|
+
reset: "\x1B[0m",
|
|
1164
|
+
bold: "\x1B[1m",
|
|
1165
|
+
dim: "\x1B[2m",
|
|
1166
|
+
red: "\x1B[31m",
|
|
1167
|
+
cyan: "\x1B[36m",
|
|
1168
|
+
green: "\x1B[32m",
|
|
1169
|
+
yellow: "\x1B[33m"
|
|
1170
|
+
};
|
|
1171
|
+
function style(text, color) {
|
|
1172
|
+
if (!isTTY()) return text;
|
|
1173
|
+
return `${color}${text}${ANSI.reset}`;
|
|
1174
|
+
}
|
|
1175
|
+
//#endregion
|
|
825
1176
|
//#region src/lib/update-notice.ts
|
|
826
1177
|
const CLI_PACKAGE_NAME = "@keystrokehq/cli";
|
|
827
1178
|
const DEFAULT_TIMEOUT_MS = 750;
|
|
@@ -934,8 +1285,8 @@ function resolveCliExitCode(error) {
|
|
|
934
1285
|
return 1;
|
|
935
1286
|
}
|
|
936
1287
|
async function runCli() {
|
|
937
|
-
initLogger();
|
|
938
|
-
if (process.argv.includes("--debug"))
|
|
1288
|
+
await initLogger();
|
|
1289
|
+
if (process.argv.includes("--debug")) setDebug(true);
|
|
939
1290
|
if (shouldLogCliStartup(process.argv.slice(2))) logger.info("CLI started", {
|
|
940
1291
|
argv: process.argv.slice(2),
|
|
941
1292
|
runMode: getRunMode()
|
|
@@ -968,9 +1319,9 @@ async function main() {
|
|
|
968
1319
|
await new Promise((resolve) => {
|
|
969
1320
|
setImmediate(resolve);
|
|
970
1321
|
});
|
|
971
|
-
|
|
1322
|
+
await closeLogger();
|
|
972
1323
|
process.exit(exitCode);
|
|
973
1324
|
}
|
|
974
1325
|
main();
|
|
975
1326
|
//#endregion
|
|
976
|
-
export {
|
|
1327
|
+
export { WorkflowResolutionError as A, CALLBACK_LOOPBACK_ORIGIN as C, CliExitError as D, AuthenticationError as E, originalConsole as F, readLogEntries as I, setDebug as L, clearLog as M, closeLogger as N, InputValidationError as O, logger as P, CALLBACK_LOOPBACK_HOST as S, CLI_AUTH_COMMAND as T, isAuthError as _, ui as a, AUTH_TIMEOUT_SECONDS as b, getProcessEnv as c, resolveCliWebUrl as d, captureCliTelemetryResolvedContext as f, getHttpStatus as g, getApiErrorCode as h, fetchLatestNpmPackageVersion as i, throwReportedCliExit as j, ProjectNotFoundError as k, isLocalMode as l, REAUTH_HINT as m, style as n, createHiddenGlobalOptions as o, AUTH_HINT as p, isTTY as r, getEnv as s, ANSI as t, resolveCliServerUrl as u, isNetworkError as v, CALLBACK_PATH as w, AUTH_URL_PATH as x, toErrorMessage as y };
|