@wrongstack/cli 0.299.0 → 0.301.0
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/{acp-S4LZQB66.js → acp-DATHHPNT.js} +36 -17
- package/dist/acp-server-agent.d.ts +1 -1
- package/dist/{audit-2ZSFGNIF.js → audit-QRCLEHHW.js} +5 -1
- package/dist/{auth-G5YKKSRH.js → auth-JASC4K3F.js} +151 -38
- package/dist/auth-menu/loopback-server.d.ts +41 -55
- package/dist/auth-menu/openai-codex-oauth.d.ts +36 -123
- package/dist/auto-discover-providers-DRW4OZHG.js +8 -0
- package/dist/boot/dispatch-webui.d.ts +3 -0
- package/dist/boot/launch-menu.d.ts +2 -4
- package/dist/boot/tool-registry.d.ts +3 -0
- package/dist/chimera-reviewer-policy.d.ts +10 -3
- package/dist/chimera-work-registry.d.ts +19 -0
- package/dist/{chronicle-QQEQFSSE.js → chronicle-63MFCZN6.js} +26 -5
- package/dist/{chunk-YWUPHRGB.js → chunk-263G3FMB.js} +33 -10
- package/dist/{chunk-2SLSUDYS.js → chunk-2KDOFTTM.js} +312 -211
- package/dist/{chunk-TGDHN4LM.js → chunk-4GVH7V3S.js} +4 -24
- package/dist/chunk-CSAPOCBP.js +24 -0
- package/dist/{chunk-66T43Q4Y.js → chunk-ETOEGL3V.js} +6 -9
- package/dist/{chunk-PEKUKUCH.js → chunk-GUHQQG63.js} +32 -14
- package/dist/chunk-KE7E7DPX.js +38 -0
- package/dist/{chunk-ZNZJ34RF.js → chunk-MHF2IJDE.js} +21 -4
- package/dist/{chunk-4HH3YGG4.js → chunk-MRLYDHQ7.js} +8 -5
- package/dist/{chunk-L5CE52XW.js → chunk-O7XNGCRT.js} +317 -309
- package/dist/chunk-PYTFS4MC.js +238 -0
- package/dist/{chunk-DPJZQCVP.js → chunk-YMXXOOFN.js} +1 -1
- package/dist/{chunk-4U3DMA2Y.js → chunk-ZECLGUTF.js} +28 -21
- package/dist/{cli-main-3MQDFSYK.js → cli-main-XWC57MGE.js} +849 -242
- package/dist/{execution-ANOYMWPO.js → execution-LHMSMDHB.js} +174 -55
- package/dist/execution-chimera-cascade.d.ts +3 -4
- package/dist/execution-chimera-review.d.ts +2 -3
- package/dist/execution-cleanup.d.ts +3 -2
- package/dist/execution.d.ts +1 -1
- package/dist/{export-TPORYVRZ.js → export-DOBGPY23.js} +12 -1
- package/dist/fleet/budget-source.d.ts +18 -0
- package/dist/fleet/host-context.d.ts +1 -1
- package/dist/fleet/host-helpers.d.ts +14 -0
- package/dist/fleet/host-status.d.ts +31 -0
- package/dist/fleet/host-types.d.ts +8 -0
- package/dist/fleet/host.d.ts +5 -0
- package/dist/fleet/status-broadcast.d.ts +1 -1
- package/dist/{hq-BDO56CX6.js → hq-LN5CJHCM.js} +22 -3
- package/dist/hq-server/auth-state.d.ts +29 -1
- package/dist/hq-server/auth.d.ts +16 -0
- package/dist/hq-server/client-address.d.ts +56 -0
- package/dist/hq-server/login-attempt-store.d.ts +30 -10
- package/dist/hq-server/routes/auth-handlers.d.ts +66 -26
- package/dist/hq-server/routes.d.ts +23 -1
- package/dist/hq-server/types.d.ts +10 -0
- package/dist/hq-server/ws.d.ts +17 -6
- package/dist/{hq-server-RJLJJZU7.js → hq-server-S7HZG3PA.js} +3 -2
- package/dist/hq-server.d.ts +19 -0
- package/dist/index.js +69 -104
- package/dist/live-settings-input.d.ts +5 -0
- package/dist/{mcp-CYLPUEHC.js → mcp-OHPJH73U.js} +6 -2
- package/dist/{modeldiag-HENYJ4N7.js → modeldiag-3DOK4BWW.js} +3 -3
- package/dist/{plugin-usage-VTL7ZTVC.js → plugin-usage-YEVLOR33.js} +7 -3
- package/dist/{plugins-ETY6W3DC.js → plugins-K3BAUP4D.js} +3 -3
- package/dist/profile-config-path.d.ts +0 -2
- package/dist/provider-helpers.d.ts +0 -5
- package/dist/{providers-models-GDELBHZK.js → providers-models-WEZ4EGLL.js} +38 -12
- package/dist/{replay-KCTXNMZQ.js → replay-FCBNHW3K.js} +5 -1
- package/dist/{rewind-EJMVFVLS.js → rewind-AOD3JIYX.js} +5 -1
- package/dist/{sessions-config-NLCMK3BY.js → sessions-config-XXN7267N.js} +8 -3
- package/dist/slash-commands/command-context.d.ts +19 -0
- package/dist/subcommands/flags.d.ts +23 -0
- package/dist/terminal-format.d.ts +15 -0
- package/dist/webui-server/setup-events.d.ts +17 -0
- package/dist/webui-server/terminal-log-view.d.ts +29 -12
- package/dist/{webui-server-PCLSXX6L.js → webui-server-DD35QFNO.js} +113 -50
- package/dist/webui-server-options.d.ts +16 -0
- package/dist/wiring/brain-and-orchestration.d.ts +4 -1
- package/dist/wiring/director-setup.d.ts +4 -0
- package/dist/wiring/fallback-gate.d.ts +31 -0
- package/dist/wiring/fleet-command-handlers.d.ts +1 -1
- package/dist/wiring/mailbox-bridge-bootstrap.d.ts +3 -1
- package/dist/wiring/management-tools.d.ts +9 -1
- package/dist/wiring/pipeline.d.ts +5 -5
- package/dist/wiring/plugins.d.ts +3 -10
- package/dist/wiring/provider-utility-tools.d.ts +27 -1
- package/dist/wiring/tools.d.ts +4 -5
- package/package.json +23 -23
- package/dist/chunk-GO3TJICK.js +0 -489
|
@@ -1,138 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OpenAI Codex — "Sign in with ChatGPT"
|
|
2
|
+
* OpenAI Codex — "Sign in with ChatGPT", terminal flow.
|
|
3
3
|
*
|
|
4
|
-
* This is
|
|
5
|
-
*
|
|
4
|
+
* This module is now only the *terminal* half of the login: the rendered
|
|
5
|
+
* instructions, the SIGINT / TUI-signal cancellation contract, the
|
|
6
|
+
* manual-paste prompt, and writing the resulting tokens into the encrypted
|
|
7
|
+
* profile config.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 6. Store the tokens in the vault as an `oauth` ProviderApiKey.
|
|
9
|
+
* The protocol itself — client id, endpoints, PKCE, the authorize URL, the
|
|
10
|
+
* token exchange and refresh, the JWT account-id claim, and model discovery —
|
|
11
|
+
* lives in `@wrongstack/providers/oauth`. It used to live here AND in
|
|
12
|
+
* `providers/src/oauth/chatgpt.ts` (the headless WebUI flow) AND in
|
|
13
|
+
* `providers/src/openai-codex.ts` (the runtime refresh path), whose header
|
|
14
|
+
* said outright that it was mirroring this file.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* Three copies is what let the OAuth abort-listener leak sit in two of them
|
|
17
|
+
* while a third flow in this same directory was already correct — nothing
|
|
18
|
+
* forced them to agree, so a fix applied to one silently left the others
|
|
19
|
+
* broken. A rotated client id or a changed token-endpoint contract carries the
|
|
20
|
+
* same risk, with the failure being "one surface stops authenticating" rather
|
|
21
|
+
* than a compile error.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* The protocol constants live in `providers` (not here) because the dependency
|
|
24
|
+
* edge runs `cli → providers → core`: the runtime provider needs them to
|
|
25
|
+
* refresh a token and must never import from `cli`.
|
|
26
|
+
*
|
|
27
|
+
* Everything the protocol layer defines is re-exported below, so existing
|
|
28
|
+
* importers (`auth-menu/index.ts`, `wiring/provider.ts`, the CLI tests) keep
|
|
29
|
+
* working against this module unchanged.
|
|
25
30
|
*/
|
|
31
|
+
import { buildCodexAuthorizeUrl, exchangeCodexAuthorizationCode, refreshCodexTokens } from '@wrongstack/providers/oauth';
|
|
26
32
|
import { type LoopbackServer } from './loopback-server.js';
|
|
27
|
-
import { type ModelsRegistry } from '@wrongstack/core/types';
|
|
28
33
|
import type { AuthMenuDeps } from './types.js';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* Codex-specific compatibility wrapper retained for callers that imported the
|
|
35
|
-
* helper from this module before the shared OAuth loopback server extraction.
|
|
36
|
-
*/
|
|
37
|
-
export declare function startLoopbackServer(expectedState: string, signal?: AbortSignal): Promise<LoopbackServer>;
|
|
38
|
-
/**
|
|
39
|
-
* Fallback model list used when BOTH the live backend AND the models.dev
|
|
40
|
-
* catalog are unreachable. This should never happen in practice — the
|
|
41
|
-
* catalog is cached locally and the only scenario where both fail is a
|
|
42
|
-
* fresh install with no network on first login.
|
|
43
|
-
*
|
|
44
|
-
* The primary resolution order in `resolveCodexModels()` is:
|
|
45
|
-
* 1. Live backend (`GET /models`)
|
|
46
|
-
* 2. models.dev catalog (`family: gpt-codex*` under `openai` provider)
|
|
47
|
-
* 3. This inline fallback
|
|
48
|
-
*/
|
|
49
|
-
export interface CodexTokens {
|
|
50
|
-
access: string;
|
|
51
|
-
refresh: string;
|
|
52
|
-
/** Absolute expiry in epoch milliseconds. */
|
|
53
|
-
expires: number;
|
|
54
|
-
idToken?: string | undefined;
|
|
55
|
-
}
|
|
56
|
-
export interface Pkce {
|
|
57
|
-
verifier: string;
|
|
58
|
-
challenge: string;
|
|
59
|
-
}
|
|
60
|
-
/** Generate a PKCE verifier + S256 challenge. */
|
|
61
|
-
export declare function generatePkce(): Pkce;
|
|
62
|
-
/** Build the full authorize URL with all Codex-required query params. */
|
|
63
|
-
export declare function buildAuthorizeUrl(challenge: string, state: string, port?: number): string;
|
|
64
|
-
/**
|
|
65
|
-
* Extract `chatgpt_account_id` from an access/id token JWT. Returns null when
|
|
66
|
-
* the token isn't a JWT or lacks the claim (the caller decides whether that
|
|
67
|
-
* is fatal — for login it is; for a cached display value it isn't).
|
|
68
|
-
*/
|
|
69
|
-
export declare function extractAccountId(token: string): string | null;
|
|
70
|
-
/**
|
|
71
|
-
* Recommended Codex models for ChatGPT sign-in. Live backend discovery
|
|
72
|
-
* wins; these values are only used when the backend/catalog cannot
|
|
73
|
-
* provide a list. Derived from `CODEX_MODELS` in core (the single source of
|
|
74
|
-
* truth for Codex id/name/description) — used both by OAuth login
|
|
75
|
-
* (resolveCodexModels → tier 3) and by the provider-boot synthesis
|
|
76
|
-
* path (wiring/provider.ts when the catalog is unavailable).
|
|
77
|
-
*/
|
|
78
|
-
export declare const FALLBACK_CODEX_MODELS: ReadonlyArray<{
|
|
79
|
-
id: string;
|
|
80
|
-
name: string;
|
|
81
|
-
}>;
|
|
82
|
-
/** Families in the models.dev catalog that indicate Codex / Responses API compatibility. */
|
|
83
|
-
export declare const CODEX_CATALOG_FAMILIES: Set<string>;
|
|
84
|
-
export declare function fallbackCodexModelIds(): string[];
|
|
85
|
-
export declare function fallbackCodexProviderModels(): Array<{
|
|
86
|
-
id: string;
|
|
87
|
-
name: string;
|
|
88
|
-
}>;
|
|
89
|
-
/**
|
|
90
|
-
* Filter a list of available model ids down to the ones that are still
|
|
91
|
-
* current for ChatGPT sign-in (i.e. present in FALLBACK_CODEX_MODELS).
|
|
92
|
-
* Used by both OAuth login (to drop deprecated ids from the live /models
|
|
93
|
-
* response) and by the provider-boot synthesis (to pick current ids out
|
|
94
|
-
* of the models.dev catalog).
|
|
95
|
-
*/
|
|
96
|
-
export declare function filterCurrentCodexModelIds(ids: Iterable<string>): string[];
|
|
97
|
-
export declare function isCodexCatalogModel(model: {
|
|
98
|
-
family?: string | undefined;
|
|
99
|
-
}): boolean;
|
|
100
|
-
/**
|
|
101
|
-
* Resolve the list of available Codex models using a 3-tier fallback chain:
|
|
102
|
-
*
|
|
103
|
-
* 1. **Live backend** — `fetchCodexModels()` hits `GET <baseUrl>/models`
|
|
104
|
-
* and keeps only current Codex model ids.
|
|
105
|
-
* 2. **models.dev catalog** — queries the `openai` provider in the cached
|
|
106
|
-
* models.dev registry and picks models whose `family` is `gpt-codex` or
|
|
107
|
-
* `gpt-codex-spark` and whose ids are current for ChatGPT sign-in.
|
|
108
|
-
* 3. **Inline fallback** — a minimal list of documented mainstream models
|
|
109
|
-
* (`gpt-5.6-sol`, `gpt-5.5`, `gpt-5.6-terra`, `gpt-5.6-luna`,
|
|
110
|
-
* `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.3-codex-spark`).
|
|
111
|
-
*
|
|
112
|
-
* The live/catalog tiers gate account availability, while the shared current
|
|
113
|
-
* model list filters out deprecated ChatGPT sign-in ids before config is saved.
|
|
114
|
-
*/
|
|
115
|
-
export declare function resolveCodexModels(modelsRegistry: ModelsRegistry, accessToken: Promise<string> | string, baseUrl?: string | undefined, signal?: AbortSignal): Promise<string[]>;
|
|
34
|
+
export { CODEX_BASE_URL, CODEX_CATALOG_FAMILIES, CODEX_PROVIDER_ID, type CodexTokens, extractAccountId, FALLBACK_CODEX_MODELS, fallbackCodexModelIds, fallbackCodexProviderModels, fetchCodexModels, filterCurrentCodexModelIds, generatePkce, isCodexCatalogModel, parseAuthorizationInput, type Pkce, resolveCodexModels, } from '@wrongstack/providers/oauth';
|
|
35
|
+
/** Build the Codex authorize URL. Alias kept for the historical local name. */
|
|
36
|
+
export declare const buildAuthorizeUrl: typeof buildCodexAuthorizeUrl;
|
|
37
|
+
/** Exchange an authorization code (+ PKCE verifier) for tokens. */
|
|
38
|
+
export declare const exchangeAuthorizationCode: typeof exchangeCodexAuthorizationCode;
|
|
116
39
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* Hits `GET <baseUrl>/models` — the standard OpenAI-compatible model listing
|
|
120
|
-
* endpoint, which the Codex backend may expose. Best-effort: returns an empty
|
|
121
|
-
* array on any failure so login still succeeds with the hardcoded fallback.
|
|
40
|
+
* Refresh an expired access token. Alias kept for the historical local name;
|
|
41
|
+
* `wiring/provider.ts` and the CLI tests import it from here.
|
|
122
42
|
*/
|
|
123
|
-
export declare
|
|
124
|
-
/** Exchange an authorization code (+ PKCE verifier) for tokens. */
|
|
125
|
-
export declare function exchangeAuthorizationCode(code: string, verifier: string, signal?: AbortSignal, port?: number): Promise<CodexTokens>;
|
|
43
|
+
export declare const refreshCodexToken: typeof refreshCodexTokens;
|
|
126
44
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
45
|
+
* Codex-specific loopback wrapper. Stays CLI-side because this flow pairs it
|
|
46
|
+
* with {@link openBrowser}, which is terminal-only.
|
|
129
47
|
*/
|
|
130
|
-
export declare function
|
|
131
|
-
/** Parse a pasted authorization code or full redirect URL into { code, state }. */
|
|
132
|
-
export declare function parseAuthorizationInput(input: string): {
|
|
133
|
-
code?: string | undefined;
|
|
134
|
-
state?: string | undefined;
|
|
135
|
-
};
|
|
48
|
+
export declare function startLoopbackServer(expectedState: string, signal?: AbortSignal): Promise<LoopbackServer>;
|
|
136
49
|
export interface CodexLoginOptions {
|
|
137
50
|
/** Storage provider id. Defaults to the canonical `openai-codex`. */
|
|
138
51
|
providerId?: string;
|
|
@@ -22,6 +22,7 @@ import type { Config, MemoryPort, ModelsRegistry, ModeStore, SessionStore, Sessi
|
|
|
22
22
|
import type { MCPRegistry } from '@wrongstack/mcp';
|
|
23
23
|
import type { TerminalRenderer } from '../renderer.js';
|
|
24
24
|
import type { AutonomyMode } from '../services/autonomy-mode.js';
|
|
25
|
+
import type { CliWebUIOptions } from '../webui-server-options.js';
|
|
25
26
|
export interface WebUIDispatchContext {
|
|
26
27
|
agent: Agent;
|
|
27
28
|
events: EventBus;
|
|
@@ -96,6 +97,8 @@ export interface WebUIDispatchContext {
|
|
|
96
97
|
error?: string | undefined;
|
|
97
98
|
}) => void | Promise<void>) | undefined;
|
|
98
99
|
}) => Promise<string>) | undefined;
|
|
100
|
+
/** Live fleet budget for WebUI concurrency/spawn gauges (issue #323). */
|
|
101
|
+
getFleetBudget?: CliWebUIOptions['getFleetBudget'];
|
|
99
102
|
}
|
|
100
103
|
/**
|
|
101
104
|
* Run the WebUI server and block until it shuts down.
|
|
@@ -50,13 +50,11 @@ declare const DEFAULT_PORTS: Record<Exclude<LaunchMenuMode, 'tui-repl'>, number>
|
|
|
50
50
|
* - `--webui`, `--simpleui`, `--hq`, or `--desktop` flag is set
|
|
51
51
|
* (the user already chose a surface)
|
|
52
52
|
* - stdin is not a TTY (CI, pipes, redirects)
|
|
53
|
-
* - the first positional looks like a known subcommand (auth,
|
|
54
|
-
* init, mcp, plugin, doctor, version, help, …)
|
|
55
53
|
* - `--no-interactive` or `--skip` (existing "skip all prompts"
|
|
56
54
|
* contract from boot.ts)
|
|
57
55
|
* - a one-shot prompt (`--prompt <x>`) is supplied
|
|
58
|
-
* -
|
|
59
|
-
*
|
|
56
|
+
* - ANY positional argument is present — a subcommand or a one-shot
|
|
57
|
+
* query. The user already said what they wanted.
|
|
60
58
|
*/
|
|
61
59
|
export declare function shouldSkipMenu(argv: string[], flags: Record<string, string | boolean>, positional: string[]): boolean;
|
|
62
60
|
interface RunLaunchMenuDeps {
|
|
@@ -15,6 +15,9 @@ interface RegisterBuiltinToolsDeps {
|
|
|
15
15
|
descriptionMode?: ToolDescriptionModeConfig | undefined;
|
|
16
16
|
resultRenderMode?: ToolResultRenderModeConfig | undefined;
|
|
17
17
|
disabledTools?: string[] | undefined;
|
|
18
|
+
nextsteps?: {
|
|
19
|
+
enabled?: boolean | undefined;
|
|
20
|
+
} | undefined;
|
|
18
21
|
exec?: {
|
|
19
22
|
allow?: string[] | undefined;
|
|
20
23
|
deny?: string[] | undefined;
|
|
@@ -17,9 +17,10 @@ export declare function __resetReviewerRoundRobinCursor(value?: number): void;
|
|
|
17
17
|
/**
|
|
18
18
|
* Assign provider/model/fallbackModels for a Chimera reviewer spawn.
|
|
19
19
|
*
|
|
20
|
-
* Builds the pool from the configured primary + fallback chain, then
|
|
21
|
-
* the next
|
|
22
|
-
*
|
|
20
|
+
* Builds the pool from the configured primary + fallback chain, then chooses
|
|
21
|
+
* either the next round-robin entry or a random starting entry. The injected
|
|
22
|
+
* random source keeps the random policy deterministic in tests. When the pool
|
|
23
|
+
* has <=1 usable entry the original primary/fallbacks are returned unchanged.
|
|
23
24
|
*
|
|
24
25
|
* When a {@link ProviderModelStatusTracker} is supplied, blocked entries
|
|
25
26
|
* (waiting-room / token-reset-limit room) are filtered from both the pool
|
|
@@ -27,6 +28,12 @@ export declare function __resetReviewerRoundRobinCursor(value?: number): void;
|
|
|
27
28
|
* a concurrent reviewer turn. Without the tracker, the legacy pre-waiting-
|
|
28
29
|
* room behavior is preserved.
|
|
29
30
|
*/
|
|
31
|
+
export declare function assignReviewerModels(provider: string, model: string, fallbackModels: readonly string[], selection?: 'round-robin' | 'random', statusTracker?: ProviderModelStatusTracker | undefined, random?: () => number): {
|
|
32
|
+
provider: string;
|
|
33
|
+
model: string;
|
|
34
|
+
fallbackModels: string[];
|
|
35
|
+
};
|
|
36
|
+
/** Backward-compatible round-robin entry point for existing callers. */
|
|
30
37
|
export declare function assignReviewerModelsRoundRobin(provider: string, model: string, fallbackModels: readonly string[], statusTracker?: ProviderModelStatusTracker | undefined): {
|
|
31
38
|
provider: string;
|
|
32
39
|
model: string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ChimeraWorkRegistry {
|
|
2
|
+
/** Track one review/cascade promise until it settles. */
|
|
3
|
+
track(work: Promise<void>): boolean;
|
|
4
|
+
/** Snapshot currently pending work for parent-before-child ordering. */
|
|
5
|
+
pending(): Promise<void> | undefined;
|
|
6
|
+
/** Stop accepting new roots after draining all accepted work to a fixed point. */
|
|
7
|
+
drainAndClose(): Promise<void>;
|
|
8
|
+
readonly size: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Session-scoped registry for Chimera review and cascade work.
|
|
12
|
+
*
|
|
13
|
+
* A single Promise slot loses overlapping reviews. A single Promise.all snapshot
|
|
14
|
+
* can also miss cascades or re-reviews registered while an earlier batch is
|
|
15
|
+
* settling. This registry retains every accepted promise and drains repeatedly
|
|
16
|
+
* until no accepted work remains, then seals admission.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createChimeraWorkRegistry(): ChimeraWorkRegistry;
|
|
19
|
+
//# sourceMappingURL=chimera-work-registry.d.ts.map
|
|
@@ -2,8 +2,12 @@ import "./chunk-7OCVIDC7.js";
|
|
|
2
2
|
|
|
3
3
|
// src/subcommands/handlers/chronicle.ts
|
|
4
4
|
import { statSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
+
chronicleProjectServerMetadataPath,
|
|
8
|
+
compactChronicleSqlite,
|
|
9
|
+
createChronicleProjectAccess,
|
|
10
|
+
resolveChronicleProjectServerOptions
|
|
7
11
|
} from "@wrongstack/core/chronicle";
|
|
8
12
|
var facets = /* @__PURE__ */ new Set([
|
|
9
13
|
"eventType",
|
|
@@ -26,6 +30,22 @@ var chronicleCmd = async (args, deps) => {
|
|
|
26
30
|
}
|
|
27
31
|
let access;
|
|
28
32
|
try {
|
|
33
|
+
if (operation === "compact") {
|
|
34
|
+
if (args.length !== 1) {
|
|
35
|
+
throw new Error("Usage: wstack chronicle compact (stop the Chronicle daemon first)");
|
|
36
|
+
}
|
|
37
|
+
const resolved = resolveChronicleProjectServerOptions({
|
|
38
|
+
projectRoot: deps.projectRoot,
|
|
39
|
+
userHome: deps.userHome
|
|
40
|
+
});
|
|
41
|
+
const result2 = compactChronicleSqlite({
|
|
42
|
+
dbPath: path.join(resolved.projectDir, "chronicle", "chronicle.sqlite"),
|
|
43
|
+
endpointMetadataPath: chronicleProjectServerMetadataPath(resolved.projectDir)
|
|
44
|
+
});
|
|
45
|
+
deps.renderer.write(`${JSON.stringify(result2, null, 2)}
|
|
46
|
+
`);
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
29
49
|
access = createChronicleProjectAccess({
|
|
30
50
|
projectRoot: deps.projectRoot,
|
|
31
51
|
userHome: deps.userHome
|
|
@@ -60,9 +80,10 @@ var chronicleCmd = async (args, deps) => {
|
|
|
60
80
|
return 0;
|
|
61
81
|
}
|
|
62
82
|
if (operation === "prune") {
|
|
63
|
-
const
|
|
83
|
+
const flags = deps.flags ?? {};
|
|
84
|
+
const dryRun = args.includes("--dry-run") || args.includes("-n") || flags["dry-run"] === true || flags["dry-run"] === "true" || flags["n"] === true;
|
|
64
85
|
const daysIndex = args.indexOf("--days");
|
|
65
|
-
const rawDays = daysIndex >= 0 && daysIndex + 1 < args.length ? args[daysIndex + 1] : void 0;
|
|
86
|
+
const rawDays = daysIndex >= 0 && daysIndex + 1 < args.length ? args[daysIndex + 1] : typeof flags["days"] === "string" ? flags["days"] : void 0;
|
|
66
87
|
const days = rawDays ? parseInt(rawDays, 10) : 30;
|
|
67
88
|
if (!Number.isFinite(days) || days < 1) {
|
|
68
89
|
deps.renderer.writeError(
|
|
@@ -235,7 +256,7 @@ function parseValue(value) {
|
|
|
235
256
|
}
|
|
236
257
|
}
|
|
237
258
|
function usage() {
|
|
238
|
-
return "Usage:\n wstack chronicle query [field=value ...]\n wstack chronicle status\n wstack chronicle facet <field> [field=value ...]\n wstack chronicle metrics [providers|tasks|files|summary] [field=value ...]\n wstack chronicle prune [--days N] [--dry-run]\n\nExamples:\n wstack chronicle status\n wstack chronicle query path=src/app.ts line=42\n wstack chronicle query providerId=openai outcome=failure\n wstack chronicle query eventType=tool.executed sessionId=<id> limit=50\n wstack chronicle query attr.tool.name=read\n wstack chronicle facet modelId from=2026-07-01T00:00:00Z\n wstack chronicle metrics providers from=2026-07-01\n wstack chronicle metrics files path=src/app.ts\n wstack chronicle metrics tasks limit=20\n wstack chronicle prune --days 7 --dry-run\n wstack chronicle prune --days 30\n";
|
|
259
|
+
return "Usage:\n wstack chronicle query [field=value ...]\n wstack chronicle status\n wstack chronicle facet <field> [field=value ...]\n wstack chronicle metrics [providers|tasks|files|summary] [field=value ...]\n wstack chronicle prune [--days N] [--dry-run]\n wstack chronicle compact\n\nExamples:\n wstack chronicle status\n wstack chronicle query path=src/app.ts line=42\n wstack chronicle query providerId=openai outcome=failure\n wstack chronicle query eventType=tool.executed sessionId=<id> limit=50\n wstack chronicle query attr.tool.name=read\n wstack chronicle facet modelId from=2026-07-01T00:00:00Z\n wstack chronicle metrics providers from=2026-07-01\n wstack chronicle metrics files path=src/app.ts\n wstack chronicle metrics tasks limit=20\n wstack chronicle prune --days 7 --dry-run\n wstack chronicle prune --days 30\n wstack chronicle compact\n";
|
|
239
260
|
}
|
|
240
261
|
function formatBytes(bytes) {
|
|
241
262
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -253,4 +274,4 @@ function tryStat(file) {
|
|
|
253
274
|
export {
|
|
254
275
|
chronicleCmd
|
|
255
276
|
};
|
|
256
|
-
//# sourceMappingURL=chronicle-
|
|
277
|
+
//# sourceMappingURL=chronicle-63MFCZN6.js.map
|
|
@@ -80,20 +80,40 @@ async function safeDelete(filePath) {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
var REDACTED = "[REDACTED]";
|
|
84
|
+
function maskValue(v) {
|
|
85
|
+
if (Array.isArray(v)) return v.map(maskValue);
|
|
86
|
+
if (typeof v === "object" && v !== null) return maskConfigSecrets(v);
|
|
87
|
+
return v;
|
|
88
|
+
}
|
|
83
89
|
function maskConfigSecrets(cfg) {
|
|
84
90
|
if (typeof cfg !== "object" || cfg === null) return {};
|
|
85
91
|
const out = {};
|
|
86
92
|
for (const [k, v] of Object.entries(cfg)) {
|
|
87
93
|
if (isSecretField(k)) {
|
|
88
|
-
out[k] =
|
|
89
|
-
} else if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
|
90
|
-
out[k] = maskConfigSecrets(v);
|
|
94
|
+
out[k] = REDACTED;
|
|
91
95
|
} else {
|
|
92
|
-
out[k] = v;
|
|
96
|
+
out[k] = maskValue(v);
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
return out;
|
|
96
100
|
}
|
|
101
|
+
function reviveSecrets(masked, current) {
|
|
102
|
+
if (masked === REDACTED) return current;
|
|
103
|
+
if (Array.isArray(masked)) {
|
|
104
|
+
const cur = Array.isArray(current) ? current : [];
|
|
105
|
+
return masked.map((item, i) => reviveSecrets(item, cur[i]));
|
|
106
|
+
}
|
|
107
|
+
if (typeof masked !== "object" || masked === null) return masked;
|
|
108
|
+
const curObj = typeof current === "object" && current !== null && !Array.isArray(current) ? current : {};
|
|
109
|
+
const out = {};
|
|
110
|
+
for (const [k, v] of Object.entries(masked)) {
|
|
111
|
+
const revived = reviveSecrets(v, curObj[k]);
|
|
112
|
+
if (revived === void 0) continue;
|
|
113
|
+
out[k] = revived;
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
97
117
|
function diffSummary(oldCfg, newCfg) {
|
|
98
118
|
const changes = [];
|
|
99
119
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(oldCfg), ...Object.keys(newCfg)]);
|
|
@@ -199,7 +219,7 @@ async function backupCurrent(homeFn = defaultHomeDir, targetConfigPath) {
|
|
|
199
219
|
}
|
|
200
220
|
if (content !== void 0) {
|
|
201
221
|
try {
|
|
202
|
-
await atomicWrite(last, content);
|
|
222
|
+
await atomicWrite(last, content, { mode: 384 });
|
|
203
223
|
} catch (err) {
|
|
204
224
|
writeErr(
|
|
205
225
|
`[config-history] .last backup failed: ${toErrorMessage(err)}`
|
|
@@ -209,7 +229,7 @@ async function backupCurrent(homeFn = defaultHomeDir, targetConfigPath) {
|
|
|
209
229
|
if (content !== void 0) {
|
|
210
230
|
try {
|
|
211
231
|
const bakPath = `${cfg}.${ts}.bak`;
|
|
212
|
-
await atomicWrite(bakPath, content);
|
|
232
|
+
await atomicWrite(bakPath, content, { mode: 384 });
|
|
213
233
|
} catch (err) {
|
|
214
234
|
writeErr(
|
|
215
235
|
`[config-history] timestamped backup failed: ${toErrorMessage(err)}`
|
|
@@ -244,7 +264,7 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
|
|
|
244
264
|
await fs.writeFile(
|
|
245
265
|
path.join(historyDir(homeFn, targetConfigPath), `${id}.json`),
|
|
246
266
|
JSON.stringify(entry, null, 2),
|
|
247
|
-
"utf8"
|
|
267
|
+
{ encoding: "utf8", mode: 384 }
|
|
248
268
|
);
|
|
249
269
|
} catch (err) {
|
|
250
270
|
throw new FsError({
|
|
@@ -292,14 +312,17 @@ async function restoreFromHistory(id, homeFn = defaultHomeDir, targetConfigPath)
|
|
|
292
312
|
oldCfg = JSON.parse(raw);
|
|
293
313
|
} catch {
|
|
294
314
|
}
|
|
315
|
+
const restored = reviveSecrets(entry.snapshotMasked, oldCfg);
|
|
295
316
|
try {
|
|
296
|
-
await atomicWrite(configPath(homeFn, targetConfigPath), JSON.stringify(
|
|
317
|
+
await atomicWrite(configPath(homeFn, targetConfigPath), JSON.stringify(restored, null, 2), {
|
|
318
|
+
mode: 384
|
|
319
|
+
});
|
|
297
320
|
} catch (err) {
|
|
298
321
|
return { ok: false, backupId: null, error: String(err) };
|
|
299
322
|
}
|
|
300
323
|
const backupId = await appendHistory(
|
|
301
324
|
oldCfg,
|
|
302
|
-
|
|
325
|
+
restored,
|
|
303
326
|
`Restored from history ${id}`,
|
|
304
327
|
homeFn,
|
|
305
328
|
targetConfigPath
|
|
@@ -343,4 +366,4 @@ export {
|
|
|
343
366
|
restoreFromHistory,
|
|
344
367
|
restoreLast
|
|
345
368
|
};
|
|
346
|
-
//# sourceMappingURL=chunk-
|
|
369
|
+
//# sourceMappingURL=chunk-263G3FMB.js.map
|