claude-code-infinite 1.0.28 → 1.0.30

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 (121) hide show
  1. package/README.md +96 -19
  2. package/dist/auto-update.d.ts +2 -0
  3. package/dist/auto-update.d.ts.map +1 -1
  4. package/dist/auto-update.js +4 -0
  5. package/dist/auto-update.js.map +1 -1
  6. package/dist/claude-auth.d.ts +27 -2
  7. package/dist/claude-auth.d.ts.map +1 -1
  8. package/dist/claude-auth.js +76 -4
  9. package/dist/claude-auth.js.map +1 -1
  10. package/dist/claude-install.d.ts +73 -0
  11. package/dist/claude-install.d.ts.map +1 -0
  12. package/dist/claude-install.js +142 -0
  13. package/dist/claude-install.js.map +1 -0
  14. package/dist/claude-plan-warning.d.ts +70 -7
  15. package/dist/claude-plan-warning.d.ts.map +1 -1
  16. package/dist/claude-plan-warning.js +152 -8
  17. package/dist/claude-plan-warning.js.map +1 -1
  18. package/dist/cli-lifecycle.d.ts +45 -1
  19. package/dist/cli-lifecycle.d.ts.map +1 -1
  20. package/dist/cli-lifecycle.js +59 -0
  21. package/dist/cli-lifecycle.js.map +1 -1
  22. package/dist/cli-main.js +136 -29
  23. package/dist/cli-main.js.map +1 -1
  24. package/dist/count-tokens.d.ts +15 -0
  25. package/dist/count-tokens.d.ts.map +1 -1
  26. package/dist/count-tokens.js +23 -1
  27. package/dist/count-tokens.js.map +1 -1
  28. package/dist/diagnostics-schema.d.ts +4 -0
  29. package/dist/diagnostics-schema.d.ts.map +1 -1
  30. package/dist/diagnostics-schema.js +25 -0
  31. package/dist/diagnostics-schema.js.map +1 -1
  32. package/dist/diagnostics.d.ts +24 -1
  33. package/dist/diagnostics.d.ts.map +1 -1
  34. package/dist/diagnostics.js +86 -5
  35. package/dist/diagnostics.js.map +1 -1
  36. package/dist/final-index.d.ts +7 -1
  37. package/dist/final-index.d.ts.map +1 -1
  38. package/dist/final-index.js +10 -3
  39. package/dist/final-index.js.map +1 -1
  40. package/dist/image-refs.d.ts +51 -0
  41. package/dist/image-refs.d.ts.map +1 -0
  42. package/dist/image-refs.js +169 -0
  43. package/dist/image-refs.js.map +1 -0
  44. package/dist/image-tokens.d.ts +37 -0
  45. package/dist/image-tokens.d.ts.map +1 -0
  46. package/dist/image-tokens.js +158 -0
  47. package/dist/image-tokens.js.map +1 -0
  48. package/dist/install-ping.d.ts +54 -0
  49. package/dist/install-ping.d.ts.map +1 -0
  50. package/dist/install-ping.js +177 -0
  51. package/dist/install-ping.js.map +1 -0
  52. package/dist/memtree-body.d.ts +52 -0
  53. package/dist/memtree-body.d.ts.map +1 -0
  54. package/dist/memtree-body.js +99 -0
  55. package/dist/memtree-body.js.map +1 -0
  56. package/dist/memtree-finder.d.ts +2 -1
  57. package/dist/memtree-finder.d.ts.map +1 -1
  58. package/dist/memtree-finder.js +4 -5
  59. package/dist/memtree-finder.js.map +1 -1
  60. package/dist/memtree-mcp.d.ts.map +1 -1
  61. package/dist/memtree-mcp.js +17 -7
  62. package/dist/memtree-mcp.js.map +1 -1
  63. package/dist/memtree-times.d.ts +35 -0
  64. package/dist/memtree-times.d.ts.map +1 -0
  65. package/dist/memtree-times.js +166 -0
  66. package/dist/memtree-times.js.map +1 -0
  67. package/dist/memtree-tools.d.ts +12 -0
  68. package/dist/memtree-tools.d.ts.map +1 -1
  69. package/dist/memtree-tools.js +63 -7
  70. package/dist/memtree-tools.js.map +1 -1
  71. package/dist/memtree.d.ts +77 -3
  72. package/dist/memtree.d.ts.map +1 -1
  73. package/dist/memtree.js +267 -53
  74. package/dist/memtree.js.map +1 -1
  75. package/dist/paused-session.d.ts.map +1 -1
  76. package/dist/paused-session.js +11 -8
  77. package/dist/paused-session.js.map +1 -1
  78. package/dist/postinstall.d.ts +2 -0
  79. package/dist/postinstall.d.ts.map +1 -0
  80. package/dist/postinstall.js +4 -0
  81. package/dist/postinstall.js.map +1 -0
  82. package/dist/prefix-store.d.ts +2 -0
  83. package/dist/prefix-store.d.ts.map +1 -1
  84. package/dist/prefix-store.js +4 -0
  85. package/dist/prefix-store.js.map +1 -1
  86. package/dist/prepared-compression.d.ts +78 -0
  87. package/dist/prepared-compression.d.ts.map +1 -0
  88. package/dist/prepared-compression.js +127 -0
  89. package/dist/prepared-compression.js.map +1 -0
  90. package/dist/proxy.d.ts +370 -13
  91. package/dist/proxy.d.ts.map +1 -1
  92. package/dist/proxy.js +790 -92
  93. package/dist/proxy.js.map +1 -1
  94. package/dist/rate-limit.d.ts +64 -0
  95. package/dist/rate-limit.d.ts.map +1 -0
  96. package/dist/rate-limit.js +126 -0
  97. package/dist/rate-limit.js.map +1 -0
  98. package/dist/reqlog.d.ts +66 -2
  99. package/dist/reqlog.d.ts.map +1 -1
  100. package/dist/reqlog.js.map +1 -1
  101. package/dist/request-sizing.d.ts +21 -2
  102. package/dist/request-sizing.d.ts.map +1 -1
  103. package/dist/request-sizing.js +57 -11
  104. package/dist/request-sizing.js.map +1 -1
  105. package/dist/route-identity.d.ts +27 -0
  106. package/dist/route-identity.d.ts.map +1 -1
  107. package/dist/route-identity.js +88 -8
  108. package/dist/route-identity.js.map +1 -1
  109. package/dist/token-estimate.d.ts +3 -20
  110. package/dist/token-estimate.d.ts.map +1 -1
  111. package/dist/token-estimate.js +9 -50
  112. package/dist/token-estimate.js.map +1 -1
  113. package/dist/tool-output-store.d.ts +12 -0
  114. package/dist/tool-output-store.d.ts.map +1 -0
  115. package/dist/tool-output-store.js +146 -0
  116. package/dist/tool-output-store.js.map +1 -0
  117. package/dist/tool-result-truncation.d.ts +32 -0
  118. package/dist/tool-result-truncation.d.ts.map +1 -0
  119. package/dist/tool-result-truncation.js +135 -0
  120. package/dist/tool-result-truncation.js.map +1 -0
  121. package/package.json +2 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Offering to install Claude Code when ccc can't find it (claude-locate.ts).
3
+ *
4
+ * In a terminal ccc asks once: "Claude Code isn't installed. Install it now? [Y/n]".
5
+ * Only a typed yes (or Enter, the prompt's default) runs Anthropic's official
6
+ * installer, the same one-liner its docs give; its output streams to the terminal.
7
+ * ccc then looks for Claude Code again, including the installers' own folders,
8
+ * so no new terminal is needed, and starts it (Claude Code asks the user to sign
9
+ * in the first time). Without a terminal nothing is asked or installed: ccc prints
10
+ * the install steps, as before.
11
+ *
12
+ * CCC_INSTALL_PROMPT=1 asks even without a terminal, reading the answer from stdin
13
+ * (the CI check of this flow); it still installs only on a yes. The answer is read
14
+ * with readline, which takes all of piped stdin, so don't also pipe a prompt then.
15
+ */
16
+ import { type ClaudeLocation } from "./claude-locate.js";
17
+ /** Anthropic's official install one-liners (https://code.claude.com/docs/en/setup). */
18
+ export declare const WINDOWS_INSTALL_SCRIPT = "irm https://claude.ai/install.ps1 | iex";
19
+ export declare const POSIX_INSTALL_SCRIPT = "curl -fsSL https://claude.ai/install.sh | bash";
20
+ export declare const INSTALL_QUESTION = "Claude Code isn't installed. Install it now? [Y/n] ";
21
+ export declare const DESKTOP_ONLY_LINE = "You have the Claude desktop app; ccc needs Claude Code (the command-line tool).";
22
+ export declare const INSTALL_PROMPT_ENV = "CCC_INSTALL_PROMPT";
23
+ /** install_failed's reason (diagnostics-schema.ts INSTALL_FAILURES). */
24
+ export type InstallFailure = "spawn" | "exit" | "not_found";
25
+ export interface InstallerCommand {
26
+ command: string;
27
+ args: string[];
28
+ /** What the user would type themselves. */
29
+ display: string;
30
+ /** The installer's environment, when it differs from ccc's. */
31
+ env?: NodeJS.ProcessEnv;
32
+ }
33
+ export interface InstallerRun {
34
+ /** The installer's exit code; null when it was killed or never started. */
35
+ code: number | null;
36
+ /** Set when it could not be started. */
37
+ error?: Error;
38
+ }
39
+ export interface InstallOfferDeps {
40
+ platform?: NodeJS.Platform;
41
+ /** A person can answer (a terminal, or CCC_INSTALL_PROMPT=1). */
42
+ canAsk: boolean;
43
+ /** Only the Claude desktop app is installed. */
44
+ desktopOnly: boolean;
45
+ /** The answer typed, or null when there is none (stdin closed, Ctrl+C). */
46
+ ask: (question: string) => Promise<string | null>;
47
+ runInstaller: (installer: InstallerCommand) => Promise<InstallerRun>;
48
+ /** claude-locate.ts locateClaude, run again after the install. */
49
+ locate: () => ClaudeLocation | null;
50
+ /** A line (or lines) for the user. */
51
+ print: (text: string) => void;
52
+ /** Diagnostics: enums and numbers only. */
53
+ record: (name: string, fields?: Record<string, unknown>) => void;
54
+ /** Send what is recorded now (the install may take a while, or be interrupted). */
55
+ flushNow?: () => void;
56
+ now?: () => number;
57
+ }
58
+ /**
59
+ * Claude Code isn't installed: offer to install it. Returns where it is after a
60
+ * successful install, else null (declined, no terminal, or the install failed),
61
+ * having printed what to do by hand.
62
+ */
63
+ export declare function offerClaudeInstall(deps: InstallOfferDeps): Promise<ClaudeLocation | null>;
64
+ /** A yes: Enter (the default) or y/yes, in any case. Anything else, or no answer, is a no. */
65
+ export declare function isYes(answer: string | null): boolean;
66
+ /** The installer for this OS: the official one-liner, run by the shell its docs name. */
67
+ export declare function installerCommand(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): InstallerCommand;
68
+ /**
69
+ * Run the installer with its output on this terminal; never throws. `toStderr`:
70
+ * its stdout goes to stderr too (a print run's stdout is Claude Code's alone).
71
+ */
72
+ export declare function runInstaller(installer: InstallerCommand, toStderr?: boolean): Promise<InstallerRun>;
73
+ //# sourceMappingURL=claude-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-install.d.ts","sourceRoot":"","sources":["../src/claude-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE5E,uFAAuF;AACvF,eAAO,MAAM,sBAAsB,4CAA4C,CAAC;AAChF,eAAO,MAAM,oBAAoB,mDAAmD,CAAC;AACrF,eAAO,MAAM,gBAAgB,wDAAwD,CAAC;AACtF,eAAO,MAAM,iBAAiB,oFACqD,CAAC;AACpF,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,iEAAiE;IACjE,MAAM,EAAE,OAAO,CAAC;IAChB,gDAAgD;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClD,YAAY,EAAE,CAAC,SAAS,EAAE,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACrE,kEAAkE;IAClE,MAAM,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;IACpC,sCAAsC;IACtC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,2CAA2C;IAC3C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACjE,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAe/F;AAED,8FAA8F;AAC9F,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAGpD;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB,CAC9B,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,gBAAgB,CAelB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAajG"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Offering to install Claude Code when ccc can't find it (claude-locate.ts).
3
+ *
4
+ * In a terminal ccc asks once: "Claude Code isn't installed. Install it now? [Y/n]".
5
+ * Only a typed yes (or Enter, the prompt's default) runs Anthropic's official
6
+ * installer, the same one-liner its docs give; its output streams to the terminal.
7
+ * ccc then looks for Claude Code again, including the installers' own folders,
8
+ * so no new terminal is needed, and starts it (Claude Code asks the user to sign
9
+ * in the first time). Without a terminal nothing is asked or installed: ccc prints
10
+ * the install steps, as before.
11
+ *
12
+ * CCC_INSTALL_PROMPT=1 asks even without a terminal, reading the answer from stdin
13
+ * (the CI check of this flow); it still installs only on a yes. The answer is read
14
+ * with readline, which takes all of piped stdin, so don't also pipe a prompt then.
15
+ */
16
+ import spawn from "cross-spawn";
17
+ import * as path from "node:path";
18
+ import { claudeMissingText } from "./claude-locate.js";
19
+ /** Anthropic's official install one-liners (https://code.claude.com/docs/en/setup). */
20
+ export const WINDOWS_INSTALL_SCRIPT = "irm https://claude.ai/install.ps1 | iex";
21
+ export const POSIX_INSTALL_SCRIPT = "curl -fsSL https://claude.ai/install.sh | bash";
22
+ export const INSTALL_QUESTION = "Claude Code isn't installed. Install it now? [Y/n] ";
23
+ export const DESKTOP_ONLY_LINE = "You have the Claude desktop app; ccc needs Claude Code (the command-line tool).";
24
+ export const INSTALL_PROMPT_ENV = "CCC_INSTALL_PROMPT";
25
+ /**
26
+ * Claude Code isn't installed: offer to install it. Returns where it is after a
27
+ * successful install, else null (declined, no terminal, or the install failed),
28
+ * having printed what to do by hand.
29
+ */
30
+ export async function offerClaudeInstall(deps) {
31
+ const platform = deps.platform ?? process.platform;
32
+ if (!deps.canAsk)
33
+ return null;
34
+ if (deps.desktopOnly)
35
+ deps.print(DESKTOP_ONLY_LINE);
36
+ deps.record("install_offered", { desktop_only: deps.desktopOnly });
37
+ deps.flushNow?.();
38
+ const answer = await deps.ask(INSTALL_QUESTION);
39
+ if (!isYes(answer)) {
40
+ deps.record("install_declined");
41
+ deps.print(claudeMissingText(platform));
42
+ return null;
43
+ }
44
+ deps.record("install_accepted");
45
+ deps.flushNow?.();
46
+ return installClaude(deps, platform);
47
+ }
48
+ /** A yes: Enter (the default) or y/yes, in any case. Anything else, or no answer, is a no. */
49
+ export function isYes(answer) {
50
+ if (answer === null)
51
+ return false;
52
+ return /^(y|yes)?$/i.test(answer.trim());
53
+ }
54
+ /** The installer for this OS: the official one-liner, run by the shell its docs name. */
55
+ export function installerCommand(platform = process.platform, env = process.env) {
56
+ if (platform === "win32") {
57
+ return {
58
+ command: windowsPowerShell(env),
59
+ args: ["-NoProfile", "-Command", WINDOWS_INSTALL_SCRIPT],
60
+ display: WINDOWS_INSTALL_SCRIPT,
61
+ env: withoutPsModulePath(env),
62
+ };
63
+ }
64
+ // pipefail: a failed download fails the install instead of running an empty script.
65
+ return {
66
+ command: "bash",
67
+ args: ["-c", `set -o pipefail; ${POSIX_INSTALL_SCRIPT}`],
68
+ display: POSIX_INSTALL_SCRIPT,
69
+ };
70
+ }
71
+ /**
72
+ * Run the installer with its output on this terminal; never throws. `toStderr`:
73
+ * its stdout goes to stderr too (a print run's stdout is Claude Code's alone).
74
+ */
75
+ export function runInstaller(installer, toStderr = false) {
76
+ return new Promise((resolve) => {
77
+ try {
78
+ const child = spawn(installer.command, installer.args, {
79
+ stdio: ["inherit", toStderr ? process.stderr : "inherit", "inherit"],
80
+ ...(installer.env ? { env: installer.env } : {}),
81
+ });
82
+ child.on("error", (error) => resolve({ code: null, error }));
83
+ child.on("close", (code) => resolve({ code }));
84
+ }
85
+ catch (error) {
86
+ resolve({ code: null, error: error });
87
+ }
88
+ });
89
+ }
90
+ // ---------------------------------------------------------------------------
91
+ // Installing
92
+ // ---------------------------------------------------------------------------
93
+ async function installClaude(deps, platform) {
94
+ const installer = installerCommand(platform);
95
+ const now = deps.now ?? Date.now;
96
+ const started = now();
97
+ deps.print(`Installing Claude Code with Anthropic's installer:\n ${installer.display}\n`);
98
+ const run = await deps.runInstaller(installer);
99
+ const ms = now() - started;
100
+ const found = run.error ? null : deps.locate();
101
+ if (found) {
102
+ deps.record("install_succeeded", { ms, claude_found: found.source });
103
+ deps.print("\n✔ Claude Code is installed. When it starts, " +
104
+ "it asks you to sign in to your Claude account the first time.\n");
105
+ return found;
106
+ }
107
+ const reason = run.error ? "spawn" : run.code !== 0 ? "exit" : "not_found";
108
+ deps.record("install_failed", { reason, code: run.code ?? undefined, ms });
109
+ deps.print(`\n${failureLine(run, installer)}\n\n${claudeMissingText(platform)}`);
110
+ return null;
111
+ }
112
+ function failureLine(run, installer) {
113
+ if (run.error) {
114
+ return `Couldn't run Claude Code's installer (${installer.command}): ${run.error.message}`;
115
+ }
116
+ if (run.code !== 0) {
117
+ return `Claude Code's installer failed (exit code ${run.code ?? "none: it was stopped"}).`;
118
+ }
119
+ return "Claude Code's installer finished, but ccc still can't find `claude`.";
120
+ }
121
+ /**
122
+ * Windows PowerShell, always by full path: PATH may be what is broken, and a
123
+ * search by name would try the current folder (a project's powershell.exe) first.
124
+ * Missing, the spawn fails and the manual steps are shown.
125
+ */
126
+ function windowsPowerShell(env) {
127
+ const root = envValue(env, "SystemRoot") || envValue(env, "windir") || "C:\\Windows";
128
+ return path.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
129
+ }
130
+ /**
131
+ * ccc started from PowerShell 7 inherits its PSModulePath, which makes Windows
132
+ * PowerShell 5.1 load 7's modules and lose its own (the installer's Get-FileHash
133
+ * is then "not recognized"). Without it, 5.1 builds its default path.
134
+ */
135
+ function withoutPsModulePath(env) {
136
+ return Object.fromEntries(Object.entries(env).filter(([key]) => key.toUpperCase() !== "PSMODULEPATH"));
137
+ }
138
+ function envValue(env, name) {
139
+ const key = Object.keys(env).find((k) => k.toUpperCase() === name.toUpperCase());
140
+ return key === undefined ? undefined : env[key];
141
+ }
142
+ //# sourceMappingURL=claude-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-install.js","sourceRoot":"","sources":["../src/claude-install.ts"],"names":[],"mappings":"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"}
@@ -4,18 +4,26 @@
4
4
  * is billed by Anthropic, and a key with no credit is refused outright
5
5
  * (credit_balance_too_low, the most common first-prompt failure). The line is
6
6
  * printed once before Claude Code starts when its sign-in is an API key or
7
- * missing, and never for a subscription; the credit refusal gets the same text
8
- * as ccc exits (claude-auth.ts creditNoticeText).
7
+ * missing, and never for a subscription. When ANTHROPIC_AUTH_TOKEN,
8
+ * ANTHROPIC_API_KEY or an apiKeyHelper beats a Claude.ai login on file, a
9
+ * line says so instead. A credit refusal gets the plan advice as ccc exits,
10
+ * whatever the sign-in (claude-auth.ts creditNoticeText).
11
+ *
12
+ * A credit refusal is also remembered (CREDIT_REFUSED_FILE, a bare marker) until
13
+ * Anthropic answers a request or a paid tier is on record, so the next launch
14
+ * gives the same advice before the first prompt rather than after it fails.
9
15
  *
10
16
  * Which sign-in Claude Code really used is only known from its requests'
11
17
  * auth headers (claude-auth.ts claudeAuthFromHeaders). The last one seen is
12
18
  * kept as a type name in ccc's config directory so the next launch decides on
13
19
  * fact rather than on the config files' guess.
14
20
  */
15
- import type { ClaudeAuthType, ClaudePlan } from "./claude-auth.js";
21
+ import type { ApiKeyOverride, ApiKeySource, ClaudeAuthType, ClaudePlan } from "./claude-auth.js";
16
22
  export declare const NO_PLAN_TEXT: string;
17
23
  /** The file in ccc's config directory holding the last sign-in type Claude Code sent. */
18
24
  export declare const SEEN_AUTH_FILE = "claude-auth-seen";
25
+ /** Present while Anthropic's last answer to Claude Code was a credit refusal. */
26
+ export declare const CREDIT_REFUSED_FILE = "claude-credit-refused";
19
27
  export interface PlanWarningInput {
20
28
  /** From env and Claude Code's config files (claudeAuthFromConfig). */
21
29
  auth: ClaudeAuthType;
@@ -36,11 +44,61 @@ export declare function needsPlanWarning(input: PlanWarningInput): boolean;
36
44
  /** `claude --version`, `claude doctor` and the like: no session, so no line. */
37
45
  export declare function isInfoOnlyRun(args: readonly string[]): boolean;
38
46
  /**
39
- * Whether a credit_balance_too_low refusal gets the advice at exit: for an API
40
- * key, or a request with no auth header ccc could read; not for a subscription
41
- * token (extra usage spent) or a bearer ccc does not recognise.
47
+ * Whether a credit_balance_too_low refusal gets the advice at exit: for every
48
+ * sign-in type. An OAuth token is no proof of a plan: Claude Code's "Anthropic
49
+ * Console account" sign-in (API usage billing) sends one too, with no plan tier
50
+ * on record, and that is how most new users met this refusal. Only a
51
+ * subscription token with a paid tier on record is spared the advice to
52
+ * `/login` with a plan it already has.
53
+ */
54
+ export declare function creditAdviceApplies(auth: ClaudeAuthType | undefined, plan: ClaudePlan): boolean;
55
+ /** The credit refusal's advice, naming the env variable or setting when one is known. */
56
+ export declare function creditAdviceText(color: boolean, source?: ApiKeySource): string;
57
+ /**
58
+ * The line when an API key beats a Claude.ai login that is on file (stderr,
59
+ * like the no-plan line). Returns whether it was printed.
60
+ */
61
+ export declare function printApiKeyOverrideWarning(override: ApiKeyOverride | undefined, subscriptionLogin: boolean, color: boolean): boolean;
62
+ export declare function apiKeyOverrideText(override: ApiKeyOverride, color: boolean): string;
63
+ export interface CreditReminderInput {
64
+ /** A credit refusal is on file from an earlier session (creditRefusedOnFile). */
65
+ refused: boolean;
66
+ /** From Claude Code's config files (claudePlanFromConfig). */
67
+ plan: ClaudePlan;
68
+ }
69
+ /** True when an earlier session was refused for credit and no paid tier is on record yet. */
70
+ export declare function needsCreditReminder(input: CreditReminderInput): boolean;
71
+ export interface StartupSignInInput extends CreditReminderInput {
72
+ signIn: PlanWarningInput;
73
+ /** An API key that beats the user's `/login` (claude-auth.ts apiKeyOverride). */
74
+ override: ApiKeyOverride | undefined;
75
+ color: boolean;
76
+ }
77
+ /**
78
+ * The sign-in lines before Claude Code starts: a remembered credit refusal's
79
+ * advice (naming the overriding key, so the override line would repeat it),
80
+ * else the no-plan line, plus the override line. `warned` is whether a
81
+ * no-plan or credit line is among them.
42
82
  */
43
- export declare function creditAdviceApplies(auth: ClaudeAuthType | undefined): boolean;
83
+ export declare function startupSignInLines(input: StartupSignInInput): {
84
+ lines: string[];
85
+ warned: boolean;
86
+ };
87
+ /** startupSignInLines on stderr (stdout stays Claude Code's); returns `warned`. */
88
+ export declare function printStartupSignInLines(input: StartupSignInInput): boolean;
89
+ /**
90
+ * Remembers a credit refusal across launches and sessions: every refusal
91
+ * writes the marker and every answered request removes it, whatever this
92
+ * process saw before, since other ccc sessions share the file.
93
+ */
94
+ export declare class CreditRefusalMemory {
95
+ private readonly configDir;
96
+ /** A refusal was on file when this launch started. */
97
+ readonly refusedAtStart: boolean;
98
+ constructor(configDir: string);
99
+ refused(): void;
100
+ answered(): void;
101
+ }
44
102
  export declare function noPlanWarningText(color: boolean): string;
45
103
  /**
46
104
  * The line on stderr when it applies: stdout stays Claude Code's in print
@@ -52,4 +110,9 @@ export declare function printNoPlanWarning(input: PlanWarningInput, color: boole
52
110
  export declare function readSeenClaudeAuth(configDir: string): ClaudeAuthType | undefined;
53
111
  /** Keep a subscription or API-key sign-in for the next launch; never throws. */
54
112
  export declare function writeSeenClaudeAuth(configDir: string, auth: ClaudeAuthType): void;
113
+ /** Remember a credit refusal for the next launch; never throws. */
114
+ export declare function markCreditRefused(configDir: string): void;
115
+ /** Forget a remembered credit refusal; never throws. */
116
+ export declare function clearCreditRefused(configDir: string): void;
117
+ export declare function creditRefusedOnFile(configDir: string): boolean;
55
118
  //# sourceMappingURL=claude-plan-warning.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude-plan-warning.d.ts","sourceRoot":"","sources":["../src/claude-plan-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnE,eAAO,MAAM,YAAY,QAE4D,CAAC;AAEtF,yFAAyF;AACzF,eAAO,MAAM,cAAc,qBAAqB,CAAC;AAKjD,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,IAAI,EAAE,cAAc,CAAC;IACrB,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAOjE;AAQD,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,OAAO,CAE7E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAExD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAInF;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAOhF;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAOjF"}
1
+ {"version":3,"file":"claude-plan-warning.d.ts","sourceRoot":"","sources":["../src/claude-plan-warning.ts"],"names":[],"mappings":"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"}
@@ -4,8 +4,14 @@
4
4
  * is billed by Anthropic, and a key with no credit is refused outright
5
5
  * (credit_balance_too_low, the most common first-prompt failure). The line is
6
6
  * printed once before Claude Code starts when its sign-in is an API key or
7
- * missing, and never for a subscription; the credit refusal gets the same text
8
- * as ccc exits (claude-auth.ts creditNoticeText).
7
+ * missing, and never for a subscription. When ANTHROPIC_AUTH_TOKEN,
8
+ * ANTHROPIC_API_KEY or an apiKeyHelper beats a Claude.ai login on file, a
9
+ * line says so instead. A credit refusal gets the plan advice as ccc exits,
10
+ * whatever the sign-in (claude-auth.ts creditNoticeText).
11
+ *
12
+ * A credit refusal is also remembered (CREDIT_REFUSED_FILE, a bare marker) until
13
+ * Anthropic answers a request or a paid tier is on record, so the next launch
14
+ * gives the same advice before the first prompt rather than after it fails.
9
15
  *
10
16
  * Which sign-in Claude Code really used is only known from its requests'
11
17
  * auth headers (claude-auth.ts claudeAuthFromHeaders). The last one seen is
@@ -16,10 +22,26 @@ import * as fs from "node:fs";
16
22
  import * as path from "node:path";
17
23
  export const NO_PLAN_TEXT = "ccc needs Claude Code signed in with a Claude Pro or Max plan (run `claude`, then `/login`). " +
18
24
  "With an API key you pay Anthropic per token, and a key with no credit won't work.";
25
+ /**
26
+ * What a credit refusal means: the sign-in bills prepaid credit (an API key, or
27
+ * Claude Code's keyless "Anthropic Console account" sign-in, which sends an
28
+ * OAuth token too) or is a Claude account without a paid plan, and that
29
+ * balance is empty.
30
+ */
31
+ const CREDIT_ADVICE = "Claude Code is billing an API key, an Anthropic Console account or a Claude account " +
32
+ "without a paid plan. ccc needs a Pro or Max plan: run `claude`, `/logout`, then `/login` " +
33
+ "and choose \"Claude account with subscription\".";
34
+ const CREDIT_TEXT = `Anthropic refused Claude Code's request: credit balance too low. ${CREDIT_ADVICE}`;
35
+ const CREDIT_ENV_HINT = " If ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN is set, unset it too: it beats `/login`.";
19
36
  /** The file in ccc's config directory holding the last sign-in type Claude Code sent. */
20
37
  export const SEEN_AUTH_FILE = "claude-auth-seen";
38
+ /** Present while Anthropic's last answer to Claude Code was a credit refusal. */
39
+ export const CREDIT_REFUSED_FILE = "claude-credit-refused";
40
+ const CREDIT_REMINDER_LEAD = "Last time, Anthropic refused Claude Code's requests: credit " +
41
+ "balance too low. ";
21
42
  const PAID_PLANS = ["pro", "max", "max_5x", "max_20x", "team", "enterprise"];
22
43
  const SEEN_TYPES = ["subscription", "api_key"];
44
+ const CLOUD_AUTH = ["bedrock", "vertex", "foundry"];
23
45
  /**
24
46
  * True when Claude Code is on an API key or not signed in, and nothing shows a
25
47
  * paid plan. Any sign of a subscription wins, a stale API-key sighting
@@ -28,7 +50,7 @@ const SEEN_TYPES = ["subscription", "api_key"];
28
50
  */
29
51
  export function needsPlanWarning(input) {
30
52
  const { auth, plan, seen } = input;
31
- if (auth === "bedrock" || auth === "vertex" || auth === "foundry")
53
+ if (CLOUD_AUTH.includes(auth))
32
54
  return false;
33
55
  if (PAID_PLANS.includes(plan))
34
56
  return false;
@@ -50,12 +72,109 @@ export function isInfoOnlyRun(args) {
50
72
  return (end === -1 ? args : args.slice(0, end)).some((a) => INFO_FLAGS.includes(a));
51
73
  }
52
74
  /**
53
- * Whether a credit_balance_too_low refusal gets the advice at exit: for an API
54
- * key, or a request with no auth header ccc could read; not for a subscription
55
- * token (extra usage spent) or a bearer ccc does not recognise.
75
+ * Whether a credit_balance_too_low refusal gets the advice at exit: for every
76
+ * sign-in type. An OAuth token is no proof of a plan: Claude Code's "Anthropic
77
+ * Console account" sign-in (API usage billing) sends one too, with no plan tier
78
+ * on record, and that is how most new users met this refusal. Only a
79
+ * subscription token with a paid tier on record is spared the advice to
80
+ * `/login` with a plan it already has.
81
+ */
82
+ export function creditAdviceApplies(auth, plan) {
83
+ return !(auth === "subscription" && PAID_PLANS.includes(plan));
84
+ }
85
+ /** The credit refusal's advice, naming the env variable or setting when one is known. */
86
+ export function creditAdviceText(color, source) {
87
+ const text = `${CREDIT_TEXT}${creditSourceHint(source)}`;
88
+ return color ? `\x1b[33m${text}\x1b[39m` : text;
89
+ }
90
+ /**
91
+ * The line when an API key beats a Claude.ai login that is on file (stderr,
92
+ * like the no-plan line). Returns whether it was printed.
93
+ */
94
+ export function printApiKeyOverrideWarning(override, subscriptionLogin, color) {
95
+ if (!override || !subscriptionLogin)
96
+ return false;
97
+ process.stderr.write(`${apiKeyOverrideText(override, color)}\n`);
98
+ return true;
99
+ }
100
+ export function apiKeyOverrideText(override, color) {
101
+ const text = override.source === "apiKeyHelper"
102
+ ? "Claude Code's settings set an apiKeyHelper, so Claude Code bills that API key instead " +
103
+ "of your Pro/Max plan. Remove apiKeyHelper from settings.json to use your plan."
104
+ : override.asks
105
+ ? `${override.source} is set: if Claude Code asks whether to use it, answer No, or it ` +
106
+ "bills that API key instead of your Pro/Max plan. Unset it to stop the question."
107
+ : `${override.source} is set, so Claude Code bills that API key instead of your Pro/Max ` +
108
+ "plan. Unset it (or run `ccc` without it) to use your plan.";
109
+ return color ? `\x1b[33m${text}\x1b[39m` : text;
110
+ }
111
+ function creditSourceHint(source) {
112
+ if (source === "apiKeyHelper") {
113
+ return " Claude Code's settings set an apiKeyHelper, and it beats `/login`: remove it " +
114
+ "from settings.json.";
115
+ }
116
+ if (source) {
117
+ return ` ${source} is set, and it beats \`/login\`: unset it (or run \`ccc\` without it).`;
118
+ }
119
+ return CREDIT_ENV_HINT;
120
+ }
121
+ /** True when an earlier session was refused for credit and no paid tier is on record yet. */
122
+ export function needsCreditReminder(input) {
123
+ return input.refused && !PAID_PLANS.includes(input.plan);
124
+ }
125
+ /**
126
+ * The sign-in lines before Claude Code starts: a remembered credit refusal's
127
+ * advice (naming the overriding key, so the override line would repeat it),
128
+ * else the no-plan line, plus the override line. `warned` is whether a
129
+ * no-plan or credit line is among them.
130
+ */
131
+ export function startupSignInLines(input) {
132
+ const { override, color } = input;
133
+ // Bedrock, Vertex and Foundry bill elsewhere: an Anthropic refusal no longer applies.
134
+ if (CLOUD_AUTH.includes(input.signIn.auth))
135
+ return { lines: [], warned: false };
136
+ if (needsCreditReminder(input)) {
137
+ // A key the user may decline at Claude Code's question isn't named (as at exit).
138
+ const source = override?.asks ? undefined : override?.source;
139
+ const text = `${CREDIT_REMINDER_LEAD}${creditAdviceBody(source)}`;
140
+ return { lines: [color ? `\x1b[33m${text}\x1b[39m` : text], warned: true };
141
+ }
142
+ const lines = [];
143
+ const warned = needsPlanWarning(input.signIn);
144
+ if (warned)
145
+ lines.push(noPlanWarningText(color));
146
+ if (override && input.signIn.subscriptionLogin === true) {
147
+ lines.push(apiKeyOverrideText(override, color));
148
+ }
149
+ return { lines, warned };
150
+ }
151
+ /** startupSignInLines on stderr (stdout stays Claude Code's); returns `warned`. */
152
+ export function printStartupSignInLines(input) {
153
+ const { lines, warned } = startupSignInLines(input);
154
+ for (const line of lines)
155
+ process.stderr.write(`${line}\n`);
156
+ return warned;
157
+ }
158
+ /**
159
+ * Remembers a credit refusal across launches and sessions: every refusal
160
+ * writes the marker and every answered request removes it, whatever this
161
+ * process saw before, since other ccc sessions share the file.
56
162
  */
57
- export function creditAdviceApplies(auth) {
58
- return auth === "api_key" || auth === undefined;
163
+ export class CreditRefusalMemory {
164
+ configDir;
165
+ /** A refusal was on file when this launch started. */
166
+ refusedAtStart;
167
+ constructor(configDir) {
168
+ this.configDir = configDir;
169
+ this.refusedAtStart = creditRefusedOnFile(configDir);
170
+ }
171
+ refused() {
172
+ markCreditRefused(this.configDir);
173
+ }
174
+ answered() {
175
+ if (creditRefusedOnFile(this.configDir))
176
+ clearCreditRefused(this.configDir);
177
+ }
59
178
  }
60
179
  export function noPlanWarningText(color) {
61
180
  return color ? `\x1b[33m${NO_PLAN_TEXT}\x1b[39m` : NO_PLAN_TEXT;
@@ -92,4 +211,29 @@ export function writeSeenClaudeAuth(configDir, auth) {
92
211
  // Best effort: the next launch falls back to the config files.
93
212
  }
94
213
  }
214
+ /** Remember a credit refusal for the next launch; never throws. */
215
+ export function markCreditRefused(configDir) {
216
+ try {
217
+ fs.writeFileSync(path.join(configDir, CREDIT_REFUSED_FILE), "credit_balance_too_low\n", { mode: 0o600 });
218
+ }
219
+ catch {
220
+ // Best effort: the next launch just goes without the reminder.
221
+ }
222
+ }
223
+ /** Forget a remembered credit refusal; never throws. */
224
+ export function clearCreditRefused(configDir) {
225
+ try {
226
+ fs.rmSync(path.join(configDir, CREDIT_REFUSED_FILE), { force: true });
227
+ }
228
+ catch {
229
+ // Best effort.
230
+ }
231
+ }
232
+ export function creditRefusedOnFile(configDir) {
233
+ return fs.existsSync(path.join(configDir, CREDIT_REFUSED_FILE));
234
+ }
235
+ /** The credit advice after its "Anthropic refused…" sentence, with the source hint. */
236
+ function creditAdviceBody(source) {
237
+ return `${CREDIT_ADVICE}${creditSourceHint(source)}`;
238
+ }
95
239
  //# sourceMappingURL=claude-plan-warning.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude-plan-warning.js","sourceRoot":"","sources":["../src/claude-plan-warning.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-plan-warning.js","sourceRoot":"","sources":["../src/claude-plan-warning.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type ShutdownSignal = "SIGINT" | "SIGTERM";
1
+ export type ShutdownSignal = "SIGINT" | "SIGTERM" | "SIGHUP";
2
2
  /** Conventional shell status for a process terminated by a POSIX signal. */
3
3
  export declare function exitCodeForSignal(signal: NodeJS.Signals): number;
4
4
  /** Preserve a child's numeric status or translate its terminating signal. */
@@ -23,4 +23,48 @@ export declare function createSignalShutdownHandler(actions: SignalShutdownActio
23
23
  export declare function writeStdout(text: string, stream?: Pick<NodeJS.WriteStream, "write">): Promise<void>;
24
24
  /** Waits for `pending` at most `ms`; a bound for cleanup that must not hang exit. */
25
25
  export declare function settleWithin(pending: Promise<unknown>, ms: number): Promise<void>;
26
+ /** The exit drain's wait for MemTree calls in flight (the final index above all). */
27
+ export declare const SHUTDOWN_MEMTREE_DRAIN_MS = 2000;
28
+ /** Windows: the final index of a large session needs longer than 2 s to upload. */
29
+ export declare const WIN32_MEMTREE_DRAIN_MS = 4000;
30
+ /**
31
+ * Closing a Windows console window (SIGHUP) leaves ccc ~5 s before it is killed, and
32
+ * the final index was cut at 2 s on every close. From the close, each shutdown step
33
+ * ends by its mark here, so the diagnostics flush (exit_index_cut too) still fits.
34
+ */
35
+ export declare const CONSOLE_CLOSE_MARKS_MS: {
36
+ readonly proxyDrain: 1000;
37
+ readonly memtreeDrain: 3500;
38
+ readonly childWait: 3750;
39
+ readonly flush: 4500;
40
+ };
41
+ /**
42
+ * How a closed terminal reaches ccc. Windows: the console window closed, and Windows ends
43
+ * ccc ~5 s later ("console-close", each shutdown step ends by its mark). macOS and Linux:
44
+ * the terminal hung up ("terminal-hangup"); nothing ends ccc after it, but its terminal is
45
+ * gone. Either way it is SIGHUP, whose default is to exit at once: before this, closing a
46
+ * macOS or Linux terminal killed ccc with no final index.
47
+ */
48
+ export type HangupKind = "console-close" | "terminal-hangup";
49
+ /**
50
+ * Calls `handler` on SIGHUP with the kind of close it means. On macOS and Linux only
51
+ * with a terminal to hang up (`terminal`: stdout or stderr is a TTY): under nohup, which
52
+ * points both away from the terminal, SIGHUP stays ignored as nohup asked. There a
53
+ * hangup can arrive more than once (the shell's, then the terminal's) and is one close:
54
+ * a repeat must not become the second signal that skips the final index.
55
+ */
56
+ export declare function onHangup(proc: Pick<NodeJS.Process, "on" | "platform">, handler: (kind: HangupKind) => void, terminal: boolean): void;
57
+ /** Claude Code ended by the same hangup (macOS, Linux), possibly before ccc saw it. */
58
+ export declare function childExitMeansHangup(platform: NodeJS.Platform, code: number | null, signal: NodeJS.Signals | null): boolean;
59
+ /** After a hangup, writes to the gone terminal fail (EIO, EPIPE): never fatal to the drain. */
60
+ export declare function ignoreStreamErrors(streams: Array<Pick<NodeJS.EventEmitter, "on">>): void;
61
+ /**
62
+ * The exit drain's wait for MemTree calls after a terminal hangup (macOS, Linux): nobody
63
+ * waits for ccc then, and a large session's final index takes seconds to upload.
64
+ */
65
+ export declare const HANGUP_MEMTREE_DRAIN_MS = 10000;
66
+ /** How long the exit drain may wait for MemTree calls, starting `now`. */
67
+ export declare function shutdownMemtreeDrainMs(platform: NodeJS.Platform, consoleClosedAt: number | undefined, now?: number): number;
68
+ /** `ms`, or less when it would end past `markMs` after the console's close. */
69
+ export declare function closeBoundedMs(ms: number, consoleClosedAt: number | undefined, markMs: number, now?: number): number;
26
70
  //# sourceMappingURL=cli-lifecycle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-lifecycle.d.ts","sourceRoot":"","sources":["../src/cli-lifecycle.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAGhE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,GAC5B,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,EAC7B,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,GACvB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAO7C;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,qBAAqB,GAC7B,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CASlC;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAkB,GACzD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjF"}
1
+ {"version":3,"file":"cli-lifecycle.d.ts","sourceRoot":"","sources":["../src/cli-lifecycle.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE7D,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAGhE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,GAC5B,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,EAC7B,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,GACvB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAO7C;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,qBAAqB,GAC7B,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CASlC;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAkB,GACzD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjF;AAED,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAC/C,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AAC5C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;CAEzB,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,GAAG,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,EAClF,QAAQ,EAAE,OAAO,GAChB,IAAI,CAYN;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,GAC5E,OAAO,CAET;AAED,+FAA+F;AAC/F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,CAExF;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAE9C,0EAA0E;AAC1E,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAa,GAC/E,MAAM,CAGR;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAa,GAChF,MAAM,CAGR"}