@keystrokehq/cli 0.0.16 → 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.
Files changed (150) hide show
  1. package/dist/{accept.handler-BPwp_UAE.mjs → accept.handler-B7QzdKCh.mjs} +4 -4
  2. package/dist/{admin-Bb9Hx-gO.mjs → admin-CYpulx_A.mjs} +11 -11
  3. package/dist/{agents-CbmvvOAx.mjs → agents-Co6Jy_N8.mjs} +10 -10
  4. package/dist/{api-jkf0TTgD.mjs → api-DsK8M-ZH.mjs} +1 -1
  5. package/dist/{api-keys-DJlyIf10.mjs → api-keys-BUCLzRv_.mjs} +6 -6
  6. package/dist/{auth-DpDEkJz7.mjs → auth-niNm-yNT.mjs} +12 -7
  7. package/dist/{auth.handler-u3qmoUX0.mjs → auth.handler-BTH-Qb00.mjs} +59 -26
  8. package/dist/{build-agents-DseUtzd4-VYWtIZy9.mjs → build-agents-DseUtzd4-CthuIecx.mjs} +6 -6
  9. package/dist/{build-metadata-C8Ra_Gi--BdoyLQMl.mjs → build-metadata-C8Ra_Gi--L3l8w0rh.mjs} +7 -7
  10. package/dist/{build-progress-BZivcVz4.mjs → build-progress-AR8xow4_.mjs} +2 -2
  11. package/dist/{build-tasks-GVuMLS0h-p08mMOyK.mjs → build-tasks-GVuMLS0h-CCxCqd02.mjs} +3 -3
  12. package/dist/{build-workflows-CV4tBo6S-knCnBKTc.mjs → build-workflows-CV4tBo6S-DhFBlp6m.mjs} +10 -10
  13. package/dist/{build.handler-BNSC_zhQ.mjs → build.handler-BmlXPhed.mjs} +7 -7
  14. package/dist/{clear-cache.handler-gr5VmEYB.mjs → clear-cache.handler-CTLQ1PIN.mjs} +3 -3
  15. package/dist/clear.handler-BDlwBzX4.mjs +68 -0
  16. package/dist/{clear.handler-CtOZ4aRn.mjs → clear.handler-C_pXAeBG.mjs} +3 -2
  17. package/dist/{commander-D15UZVjp.mjs → commander-BE37hxR3.mjs} +4 -4
  18. package/dist/{connect-DzSNDSmI.mjs → connect-C9NMD8Ky.mjs} +3 -3
  19. package/dist/{connect.handler-DRO05ak3.mjs → connect.handler-C7kysvhz.mjs} +5 -5
  20. package/dist/{context-B1L8pZsH.mjs → context-Bid-Rqj7.mjs} +49 -17
  21. package/dist/{create.handler-DF1Ye4nr.mjs → create.handler-Cp9CV6SN.mjs} +3 -3
  22. package/dist/{credential-env-map-B2nVJXPn.mjs → credential-env-map-BA4LNI7x.mjs} +6 -5
  23. package/dist/{credential-requirements-FtBk5JVB.mjs → credential-requirements-DrrQ9x9P.mjs} +3 -3
  24. package/dist/{credential-schema-mismatch-CfyBUMPS.mjs → credential-schema-mismatch-z74ud-YZ.mjs} +1 -1
  25. package/dist/{credentials-CiOwDS5y.mjs → credentials-DUkVbhvj.mjs} +1 -1
  26. package/dist/{credentials-VidBoOd7.mjs → credentials-fMfKVlEn.mjs} +7 -7
  27. package/dist/{current-deployment-workflow-BRUEdPrN.mjs → current-deployment-workflow-DiwUcKoB.mjs} +6 -6
  28. package/dist/{current.handler-QZQ-l84v.mjs → current.handler-eCR4nClu.mjs} +3 -3
  29. package/dist/{delete.handler-Bude0SVP.mjs → delete.handler-D4ElSAcr.mjs} +2 -2
  30. package/dist/{deploy-eshEEiP-.mjs → deploy-B7LRWcp6.mjs} +2 -2
  31. package/dist/{deploy-CJbVB7e2.mjs → deploy-DyZh--f7.mjs} +1 -1
  32. package/dist/{deploy-progress-DJHph1Fz.mjs → deploy-progress-DK87VKJ-.mjs} +2 -2
  33. package/dist/{deploy.handler-BxxWI7nV.mjs → deploy.handler-DVnH-Niv.mjs} +20 -20
  34. package/dist/{detect-env-access-CwkOYeYM-CZIixHeR.mjs → detect-env-access-CwkOYeYM-CNTyUzme.mjs} +1 -1
  35. package/dist/{diff-utils-4OQTpP5s.mjs → diff-utils-B0ED-Igv.mjs} +1 -1
  36. package/dist/{diff.handler-CzrKCj7N.mjs → diff.handler-lIA2pRBX.mjs} +7 -7
  37. package/dist/dist-CIInPRGh.mjs +1071 -0
  38. package/dist/{dist-FQYQ2FLm.mjs → dist-WFPTDQB3.mjs} +15 -15
  39. package/dist/{env.handler-B3YDQIVE.mjs → env.handler-BIzQLlmo.mjs} +10 -10
  40. package/dist/{error-boundary-CyLcinp1.mjs → error-boundary-B8cmSwJH.mjs} +3 -3
  41. package/dist/{file-metadata-DaPPpiTh.mjs → file-metadata-lrX05iRt.mjs} +1 -1
  42. package/dist/{iam-command-utils-ByLX0A-V.mjs → iam-command-utils-CSZj4XlH.mjs} +2 -2
  43. package/dist/{import-module--8x5SLum-DaUNACER.mjs → import-module--8x5SLum-D7EiPjwl.mjs} +6 -6
  44. package/dist/{init-PTwX63_P.mjs → init-jaqNLGmB.mjs} +3 -3
  45. package/dist/{init.handler-CdytFiFt.mjs → init.handler-DamvbPEw.mjs} +11 -9
  46. package/dist/{inspect.handler-umc7of-r.mjs → inspect.handler-_UcN7dxE.mjs} +8 -8
  47. package/dist/{integration-catalog-BgT4mLzW.mjs → integration-catalog-m8tj_XlD.mjs} +3 -3
  48. package/dist/{integrations-B0Gv-L0s.mjs → integrations-DRL3JmC8.mjs} +12 -7
  49. package/dist/{invites-Cqi7iyIN.mjs → invites-VntHNMYk.mjs} +5 -5
  50. package/dist/{invites.list.handler-CErgY35S.mjs → invites.list.handler-CPl4QHfc.mjs} +4 -4
  51. package/dist/{invites.resend.handler-DRCRIA4F.mjs → invites.resend.handler-BAtb3AX4.mjs} +4 -4
  52. package/dist/{invites.revoke.handler-C0FZdAR0.mjs → invites.revoke.handler-qXOF1Vgx.mjs} +4 -4
  53. package/dist/keystroke.mjs +558 -207
  54. package/dist/{list-enrichment-C6u5eI0j.mjs → list-enrichment-DYvr3XDb.mjs} +3 -3
  55. package/dist/{list.handler-c-8RpgB9.mjs → list.handler-BLkQKiV1.mjs} +17 -16
  56. package/dist/{list.handler-CBEXiTAK.mjs → list.handler-BdRsjRlf.mjs} +3 -3
  57. package/dist/{list.handler-BjutlIkE.mjs → list.handler-CEjKSezx.mjs} +59 -13
  58. package/dist/{list2.handler-T5v4EK20.mjs → list.handler-CJUFdmaU.mjs} +7 -7
  59. package/dist/{list.handler-Cr_DFAae.mjs → list.handler-C_iBLBmS.mjs} +3 -3
  60. package/dist/{list.handler-FlchXrKz.mjs → list.handler-DUz1bJ4x.mjs} +4 -4
  61. package/dist/{list.handler-D-YFoKLU.mjs → list.handler-pHnPFep8.mjs} +7 -7
  62. package/dist/{listen-rHLiCWbn.mjs → listen-DLGZEQRL.mjs} +3 -3
  63. package/dist/{listen.handler-B9T58yAj.mjs → listen.handler-kaAvYk-B.mjs} +4 -4
  64. package/dist/logs-CcYqFKRU.mjs +58 -0
  65. package/dist/logs.handler-DyRoevtO.mjs +53 -0
  66. package/dist/{logs.handler-DGcGN2qb.mjs → logs.handler-lboRKNoE.mjs} +4 -4
  67. package/dist/{members.add.handler-DmYI43rZ.mjs → members.add.handler-DBydP0SR.mjs} +4 -4
  68. package/dist/{members.invite.handler-B_KVxv5m.mjs → members.invite.handler-D4-7fiYC.mjs} +4 -4
  69. package/dist/{members.list.handler-BtuuIgQS.mjs → members.list.handler-Z4cIbcNg.mjs} +4 -4
  70. package/dist/{members.remove.handler-Lvg-CqVv.mjs → members.remove.handler-J56D83O7.mjs} +4 -4
  71. package/dist/{members.update.handler-D-8izeso.mjs → members.update.handler-B5rBv6dt.mjs} +4 -4
  72. package/dist/{normalize-path-CojS-CgQ-DFTvyA27.mjs → normalize-path-CojS-CgQ-D4wSBHgG.mjs} +1 -1
  73. package/dist/{org-DUCts2MV.mjs → org-DGS91uc-.mjs} +17 -17
  74. package/dist/{orgs.create.handler-vXQgDJZ_.mjs → orgs.create.handler-B4naNUSN.mjs} +4 -4
  75. package/dist/{orgs.get.handler-D_Jfl18x.mjs → orgs.get.handler-Ci_JrT08.mjs} +4 -4
  76. package/dist/{orgs.list.handler-BNjoTJvV.mjs → orgs.list.handler-CJ2byIEj.mjs} +4 -4
  77. package/dist/{output-CGdYhH0p.mjs → output-BWcVRt-T.mjs} +1 -1
  78. package/dist/paths-JzzFkXQA-CEipIeVl.mjs +36 -0
  79. package/dist/{paused.handler-ST9dCe8E.mjs → paused.handler-BQSQvQhB.mjs} +3 -3
  80. package/dist/{projects-CbquwUlm.mjs → projects-D90_uEC2.mjs} +5 -5
  81. package/dist/{projects-DfaG_3WP.mjs → projects-fWvIJQ80.mjs} +1 -1
  82. package/dist/{register.handler-BAx0IC-u.mjs → register.handler-CleQJhtQ.mjs} +2 -2
  83. package/dist/{requirements.handler-D5dFi7XZ.mjs → requirements.handler-B51sxQSy.mjs} +7 -7
  84. package/dist/resolve-cli-credentials-DytxgMwn.mjs +47 -0
  85. package/dist/{resolve-project-CURYMjex.mjs → resolve-project-CNQtOWE4.mjs} +7 -7
  86. package/dist/{run-polling-BWcLQvm0.mjs → run-polling-CC6y2XXI.mjs} +5 -5
  87. package/dist/{run.handler-BiBDLoeH.mjs → run.handler-B31BpZJP.mjs} +9 -9
  88. package/dist/{runs-Bc3zjk7V.mjs → runs-Bg_qDeQi.mjs} +4 -4
  89. package/dist/{skill-installer-DkRJ6oLi.mjs → skill-installer-BBgN2tzW.mjs} +2 -2
  90. package/dist/{skills-sync.handler-C4ztv1Vu.mjs → skills-sync.handler-DOxudKmV.mjs} +3 -3
  91. package/dist/{skills.command-DuL4kLUi.mjs → skills.command-JwKWpGvU.mjs} +5 -5
  92. package/dist/{skills.handler-R5KAbioE.mjs → skills.handler-Do9I3dQS.mjs} +1 -1
  93. package/dist/{source-analysis-BBg2E_6G-BQqm16RR.mjs → source-analysis-BBg2E_6G-Ut7kYHOz.mjs} +4 -4
  94. package/dist/{spinner-progress-DfkMzwGx.mjs → spinner-progress-Bx-fYItP.mjs} +1 -1
  95. package/dist/{src-BQdOWkyv.mjs → src-B0tNjKMg.mjs} +1 -1
  96. package/dist/{status.handler-DxCJRm1n.mjs → status.handler-BsVtDW_V.mjs} +19 -4
  97. package/dist/{switch.handler-CTwhIcaQ.mjs → switch.handler-Cu81T2HY.mjs} +5 -5
  98. package/dist/{sync-Pssitj6K.mjs → sync-CXNveL61.mjs} +2 -2
  99. package/dist/{sync.handler-Be0U3x-n.mjs → sync.handler-7g1yDt0H.mjs} +9 -9
  100. package/dist/{task-BNXDZU71.mjs → task-BguWXIiH.mjs} +2 -2
  101. package/dist/{task-target-build-BG6cC3bz.mjs → task-target-build-BaMtXnN7.mjs} +8 -7
  102. package/dist/{task-target-deploy-CZBGNC0H-Ck724yF4.mjs → task-target-deploy-CZBGNC0H-I-tvkGCC.mjs} +1 -1
  103. package/dist/{task-target-deploy-gMQC8kXU.mjs → task-target-deploy-DmpCWE3u.mjs} +1 -1
  104. package/dist/task-target-deploy-runner.mjs +22 -17
  105. package/dist/{test-BISghlKg.mjs → test-A5hz3c7j.mjs} +4 -4
  106. package/dist/{test.handler-DkizZhVu.mjs → test.handler-CJtaMZVy.mjs} +12 -12
  107. package/dist/{test.handler-Dk3CmTa7.mjs → test.handler-Cq2l7SAr.mjs} +2 -2
  108. package/dist/{tool.handler-Bu130Vcz.mjs → tool.handler-B-mOL128.mjs} +115 -95
  109. package/dist/{trigger-artifacts-RizI57RC-CxHwCkQ_.mjs → trigger-artifacts-RizI57RC-DjhOsdOm.mjs} +4 -4
  110. package/dist/{trigger-manifest-PTjVYL1r.mjs → trigger-manifest-Bq2zRbkV.mjs} +1 -1
  111. package/dist/{upgrade-cH9I_pZq.mjs → upgrade-DhfpoyRV.mjs} +2 -2
  112. package/dist/{upgrade.handler-CXEF4ue0.mjs → upgrade.handler-5qSzPC7D.mjs} +1 -1
  113. package/dist/{upload.handler-CpKuAaQ_.mjs → upload.handler-D3-W_1kq.mjs} +10 -10
  114. package/dist/{users.get.handler-D0WO6D1K.mjs → users.get.handler-Bd0OBI-E.mjs} +4 -4
  115. package/dist/{users.list.handler-BSTIniF1.mjs → users.list.handler-CacJz6eC.mjs} +4 -4
  116. package/dist/{users.set-role.handler-DAKdSkbn.mjs → users.set-role.handler-bZMQtUR0.mjs} +4 -4
  117. package/dist/{utils-VC0Vl_pm.mjs → utils-BMUWnz1P.mjs} +2 -2
  118. package/dist/{validate.handler-I8LY-UkG.mjs → validate.handler-Ccq66ki4.mjs} +8 -8
  119. package/dist/{workflow-build-C9rQQ4qU.mjs → workflow-build-_WNsLKwW.mjs} +23 -23
  120. package/dist/{workflow-build-manifest-OPFqFD6f.mjs → workflow-build-manifest-B2GqHyWE.mjs} +3 -3
  121. package/dist/{workflow-bundler-BzHk73PM-AIB4-u4Y.mjs → workflow-bundler-BzHk73PM-WI31RJjH.mjs} +3 -3
  122. package/dist/{workflows-CL1jYSLR.mjs → workflows-Dy2M9bEr.mjs} +16 -16
  123. package/dist/{writer-B-SpZ0G2-olEAgSLc.mjs → writer-B-SpZ0G2-tq1MFgid.mjs} +6 -6
  124. package/package.json +6 -6
  125. package/dist/clear.handler-Dpe05eTq.mjs +0 -42
  126. package/dist/dist-BF6r1hfv.mjs +0 -308
  127. package/dist/logs-DUwdYZB-.mjs +0 -28
  128. package/dist/logs.handler-dcRq-zoc.mjs +0 -35
  129. package/dist/{agent-bundle-package-DWV6B_5q-rRTPU13L.mjs → agent-bundle-package-DWV6B_5q-FPT0bJaA.mjs} +0 -0
  130. package/dist/{agent-manifest-CZdlCTFs.mjs → agent-manifest-tIsqF2OP.mjs} +0 -0
  131. package/dist/{browser-3cUiPlk2.mjs → browser-BpJ8ut9z.mjs} +0 -0
  132. package/dist/{common-BaGFkj3n.mjs → common-AK0q0Oz0.mjs} +0 -0
  133. package/dist/{concurrency-gXn9Rw8x-BI6HQNfC.mjs → concurrency-gXn9Rw8x-BTlfau8D.mjs} +0 -0
  134. package/dist/{cron-parser-C2eJD0yD.mjs → cron-parser-Dw_cWzFu.mjs} +0 -0
  135. package/dist/{declared-credential-requirements-B6h4WRv4.mjs → declared-credential-requirements-D6KT-r-e.mjs} +0 -0
  136. package/dist/{default-urls-BS4twrsS.mjs → default-urls-CTQqM1_A.mjs} +0 -0
  137. package/dist/{layout-CXkZEsXI.mjs → layout-P1v-Gssz.mjs} +0 -0
  138. package/dist/{metadata-layout-Bv-B0nHj-CqlcZz_g.mjs → metadata-layout-Bv-B0nHj-B1c5giJ7.mjs} +1 -1
  139. package/dist/{oxc-B3KI3rf_-DdiZWqe2.mjs → oxc-B3KI3rf_-Cvx4Z-4H.mjs} +0 -0
  140. package/dist/{project-config-CsBMT4TL.mjs → project-config-DudGRFPO.mjs} +1 -1
  141. package/dist/{read-credential-keys-77a91T8M-DMmY6oDW.mjs → read-credential-keys-77a91T8M-B0eiobOd.mjs} +0 -0
  142. package/dist/{rolldown-runtime-twds-ZHy-CO5ir_za.mjs → rolldown-runtime-twds-ZHy-8uqgIurC.mjs} +0 -0
  143. package/dist/{run-polling-CwlzB5-9.mjs → run-polling-DARidqo-.mjs} +0 -0
  144. package/dist/{schema-O9xTWad_.mjs → schema-BjH_e4Fo.mjs} +0 -0
  145. package/dist/{schema-_FQrHcIS.mjs → schema-Lbp5lGJu.mjs} +0 -0
  146. package/dist/{schema-display-CNqiYBIb.mjs → schema-display-NVEl_DFY.mjs} +0 -0
  147. package/dist/{schemas-DodkHgnS.mjs → schemas-B8c7Z5Iy.mjs} +0 -0
  148. package/dist/{source-analysis-CJPymdaA.mjs → source-analysis-Cs0CTBQk.mjs} +0 -0
  149. package/dist/{types-D04ah3uY.mjs → types-BMBuhHhW.mjs} +0 -0
  150. package/dist/{upload-wwSPAC5_.mjs → upload-BbcMkyVl.mjs} +1 -1
@@ -1,19 +1,527 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { n as DEFAULT_CLI_WEB_URL, t as DEFAULT_CLI_SERVER_URL } from "./default-urls-BS4twrsS.mjs";
4
- import { Command, CommanderError, Option } from "commander";
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.16";
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-CbmvvOAx.mjs")).createAgentsCommand()
536
+ loadCommand: async () => (await import("./agents-Co6Jy_N8.mjs")).createAgentsCommand()
29
537
  },
30
538
  {
31
539
  name: "admin",
32
- loadCommand: async () => (await import("./admin-Bb9Hx-gO.mjs")).createAdminCommand()
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-DJlyIf10.mjs")).createApiKeysCommand()
544
+ loadCommand: async () => (await import("./api-keys-BUCLzRv_.mjs")).createApiKeysCommand()
37
545
  },
38
546
  {
39
547
  name: "auth",
40
- loadCommand: async () => (await import("./auth-DpDEkJz7.mjs")).createAuthCommand()
548
+ loadCommand: async () => (await import("./auth-niNm-yNT.mjs")).createAuthCommand()
41
549
  },
42
550
  {
43
551
  name: "connect",
44
- loadCommand: async () => (await import("./connect-DzSNDSmI.mjs")).createConnectCommand()
552
+ loadCommand: async () => (await import("./connect-C9NMD8Ky.mjs")).createConnectCommand()
45
553
  },
46
554
  {
47
555
  name: "credentials",
48
- loadCommand: async () => (await import("./credentials-VidBoOd7.mjs")).createCredentialsCommand(),
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-DUCts2MV.mjs")).createOrgCommand()
561
+ loadCommand: async () => (await import("./org-DGS91uc-.mjs")).createOrgCommand()
54
562
  },
55
563
  {
56
564
  name: "deploy",
57
- loadCommand: async () => (await import("./deploy-eshEEiP-.mjs")).createDeployCommand()
565
+ loadCommand: async () => (await import("./deploy-B7LRWcp6.mjs")).createDeployCommand()
58
566
  },
59
567
  {
60
568
  name: "init",
61
- loadCommand: async () => (await import("./init-PTwX63_P.mjs")).createInitCommand()
569
+ loadCommand: async () => (await import("./init-jaqNLGmB.mjs")).createInitCommand()
62
570
  },
63
571
  {
64
572
  name: "integrations",
65
- loadCommand: async () => (await import("./integrations-B0Gv-L0s.mjs")).createIntegrationsCommand()
573
+ loadCommand: async () => (await import("./integrations-DRL3JmC8.mjs")).createIntegrationsCommand()
66
574
  },
67
575
  {
68
576
  name: "invites",
69
- loadCommand: async () => (await import("./invites-Cqi7iyIN.mjs")).createInvitesCommand()
577
+ loadCommand: async () => (await import("./invites-VntHNMYk.mjs")).createInvitesCommand()
70
578
  },
71
579
  {
72
580
  name: "logs",
73
- loadCommand: async () => (await import("./logs-DUwdYZB-.mjs")).createLogsCommand()
581
+ loadCommand: async () => (await import("./logs-CcYqFKRU.mjs")).createLogsCommand()
74
582
  },
75
583
  {
76
584
  name: "listen",
77
- loadCommand: async () => (await import("./listen-rHLiCWbn.mjs")).createListenCommand()
585
+ loadCommand: async () => (await import("./listen-DLGZEQRL.mjs")).createListenCommand()
78
586
  },
79
587
  {
80
588
  name: "projects",
81
- loadCommand: async () => (await import("./projects-CbquwUlm.mjs")).createProjectsCommand()
589
+ loadCommand: async () => (await import("./projects-D90_uEC2.mjs")).createProjectsCommand()
82
590
  },
83
591
  {
84
592
  name: "runs",
85
- loadCommand: async () => (await import("./runs-Bc3zjk7V.mjs")).createRunsCommand()
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-DuL4kLUi.mjs")).createSkillsCommand()
597
+ loadCommand: async () => (await import("./skills.command-JwKWpGvU.mjs")).createSkillsCommand()
90
598
  },
91
599
  {
92
600
  name: "sync",
93
- loadCommand: async () => (await import("./sync-Pssitj6K.mjs")).createSyncCommand()
601
+ loadCommand: async () => (await import("./sync-CXNveL61.mjs")).createSyncCommand()
94
602
  },
95
603
  {
96
604
  name: "test",
97
- loadCommand: async () => (await import("./test-BISghlKg.mjs")).createTestCommand()
605
+ loadCommand: async () => (await import("./test-A5hz3c7j.mjs")).createTestCommand()
98
606
  },
99
607
  {
100
608
  name: "upgrade",
101
- loadCommand: async () => (await import("./upgrade-cH9I_pZq.mjs")).createUpgradeCommand()
609
+ loadCommand: async () => (await import("./upgrade-DhfpoyRV.mjs")).createUpgradeCommand()
102
610
  },
103
611
  {
104
612
  name: "workflows",
105
- loadCommand: async () => (await import("./workflows-CL1jYSLR.mjs")).createWorkflowsCommand()
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")) logger.setDebug(true);
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
- logger.close();
1322
+ await closeLogger();
972
1323
  process.exit(exitCode);
973
1324
  }
974
1325
  main();
975
1326
  //#endregion
976
- export { InputValidationError as A, AUTH_URL_PATH as C, CLI_AUTH_COMMAND as D, CALLBACK_PATH as E, WorkflowResolutionError as M, throwReportedCliExit as N, AuthenticationError as O, AUTH_TIMEOUT_SECONDS as S, CALLBACK_LOOPBACK_ORIGIN as T, getApiErrorCode as _, getProcessEnv as a, isNetworkError as b, resolveCliWebUrl as c, originalConsole as d, ANSI as f, REAUTH_HINT as g, AUTH_HINT as h, getEnv as i, ProjectNotFoundError as j, CliExitError as k, captureCliTelemetryResolvedContext as l, isTTY as m, ui as n, isLocalMode as o, style as p, createHiddenGlobalOptions as r, resolveCliServerUrl as s, fetchLatestNpmPackageVersion as t, logger as u, getHttpStatus as v, CALLBACK_LOOPBACK_HOST as w, toErrorMessage as x, isAuthError as y };
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 };