indusagi-coding-agent 0.1.61 → 0.2.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/CHANGELOG.md +27 -0
- package/dist/entry.js +11589 -14719
- package/dist/types/boot/contract.d.ts +2 -0
- package/dist/types/boot/runners/addon-wiring.d.ts +103 -0
- package/dist/types/boot/runners/addon-wiring.test.d.ts +19 -0
- package/dist/types/boot/runners/checkpoint.d.ts +133 -0
- package/dist/types/boot/runners/checkpoint.test.d.ts +12 -0
- package/dist/types/boot/runners/delegate-runner.d.ts +83 -0
- package/dist/types/boot/runners/delegate-runner.test.d.ts +13 -0
- package/dist/types/boot/runners/memdir.d.ts +103 -0
- package/dist/types/boot/runners/memdir.test.d.ts +12 -0
- package/dist/types/boot/runners/read-state.d.ts +82 -0
- package/dist/types/boot/runners/read-state.test.d.ts +10 -0
- package/dist/types/boot/runners/session.d.ts +37 -2
- package/dist/types/boot/runners/session.test.d.ts +10 -0
- package/dist/types/briefing/context-docs.d.ts +38 -0
- package/dist/types/briefing/context-docs.test.d.ts +18 -0
- package/dist/types/briefing/index.d.ts +2 -0
- package/dist/types/capability-deck/cards/index.d.ts +6 -0
- package/dist/types/capability-deck/cards/memory-card.d.ts +9 -10
- package/dist/types/capability-deck/cards/plan-file.d.ts +56 -0
- package/dist/types/capability-deck/cards/plan-tools.d.ts +97 -0
- package/dist/types/capability-deck/cards/plan-tools.test.d.ts +9 -0
- package/dist/types/capability-deck/checkpoint.int.test.d.ts +25 -0
- package/dist/types/capability-deck/index.d.ts +1 -1
- package/dist/types/capability-deck/read-edit-gate.int.test.d.ts +21 -0
- package/dist/types/conductor/bash-guard.d.ts +106 -0
- package/dist/types/conductor/bash-guard.test.d.ts +17 -0
- package/dist/types/conductor/conductor.d.ts +38 -6
- package/dist/types/conductor/contract.d.ts +221 -2
- package/dist/types/conductor/diagnostics.d.ts +183 -0
- package/dist/types/conductor/diagnostics.test.d.ts +10 -0
- package/dist/types/conductor/index.d.ts +4 -1
- package/dist/types/conductor/permission-gate.integration.test.d.ts +22 -0
- package/dist/types/conductor/permission-wiring.test.d.ts +14 -0
- package/dist/types/conductor/permissions.d.ts +217 -0
- package/dist/types/conductor/permissions.test.d.ts +12 -0
- package/dist/types/conductor/plan-mode.integration.test.d.ts +23 -0
- package/dist/types/conductor/post-edit-diagnostics.test.d.ts +13 -0
- package/dist/types/conductor/transcript-store/serialize.test.d.ts +10 -0
- package/dist/types/conductor/transcript-store/store.d.ts +18 -0
- package/dist/types/console/components/Banner.d.ts +28 -6
- package/dist/types/console/components/Emblem.d.ts +49 -0
- package/dist/types/console/components/StatusBar.d.ts +14 -3
- package/dist/types/console/components/WorkingIndicator.d.ts +44 -0
- package/dist/types/console/components/WorkingIndicator.test.d.ts +9 -0
- package/dist/types/console/components/banner-sweep.d.ts +55 -0
- package/dist/types/console/components/banner.test.d.ts +9 -0
- package/dist/types/console/contract.d.ts +41 -7
- package/dist/types/console/input/keymap.d.ts +10 -1
- package/dist/types/console/overlays/approval-queue.d.ts +71 -0
- package/dist/types/console/overlays/approval.d.ts +104 -0
- package/dist/types/console/overlays/approval.test.d.ts +17 -0
- package/dist/types/console/overlays/host.d.ts +4 -3
- package/dist/types/console/overlays/index.d.ts +2 -0
- package/dist/types/console/theme/adapter.d.ts +19 -0
- package/dist/types/console/theme/index.d.ts +1 -1
- package/dist/types/console/theme/palette.d.ts +25 -0
- package/dist/types/console/theme/tokens.d.ts +23 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/launch/contract.d.ts +2 -0
- package/dist/types/launch/index.d.ts +1 -1
- package/dist/types/launch/oauth.d.ts +13 -0
- package/dist/types/settings/contract.d.ts +59 -0
- package/dist/types/settings/index.d.ts +2 -2
- package/dist/types/window-budget/condenser.d.ts +15 -1
- package/dist/types/window-budget/index.d.ts +3 -1
- package/dist/types/window-budget/microcompact.d.ts +68 -0
- package/dist/types/window-budget/microcompact.test.d.ts +16 -0
- package/dist/types/window-budget/rehydrate.d.ts +56 -0
- package/dist/types/workspace/brand.d.ts +6 -0
- package/dist/types/workspace/index.d.ts +1 -1
- package/package.json +2 -2
|
@@ -84,6 +84,15 @@ export interface KeyChord {
|
|
|
84
84
|
* Model / reasoning
|
|
85
85
|
* - `model:cycleThinking` — advance the reasoning-effort ladder one step.
|
|
86
86
|
*
|
|
87
|
+
* Permission mode
|
|
88
|
+
* - `mode:cyclePermission` — cycle through ALL permission modes (Shift+Tab),
|
|
89
|
+
* advancing one step per press: default → acceptEdits → plan → bypass →
|
|
90
|
+
* (wrap) default. In `plan` mode every mutating tool is blocked; in `bypass`
|
|
91
|
+
* every tool is auto-allowed.
|
|
92
|
+
* - `mode:togglePlan` — toggle read-only plan mode on/off. Drives `/plan`; no
|
|
93
|
+
* longer bound to Shift+Tab (which now cycles all modes). In plan mode every
|
|
94
|
+
* mutating tool is blocked at the permission gate.
|
|
95
|
+
*
|
|
87
96
|
* Queue
|
|
88
97
|
* - `queue:dequeue` — pull the most recently queued input back into the
|
|
89
98
|
* composer so it can be edited or dropped.
|
|
@@ -106,7 +115,7 @@ export interface KeyChord {
|
|
|
106
115
|
* Inert
|
|
107
116
|
* - `none` — the keystroke carries no console meaning.
|
|
108
117
|
*/
|
|
109
|
-
export type ConsoleVerb = "text:type" | "text:newline" | "edit:erasePrev" | "edit:eraseNext" | "edit:clearLine" | "nav:left" | "nav:right" | "nav:home" | "nav:end" | "nav:up" | "nav:down" | "flow:submit" | "flow:dismiss" | "flow:accept" | "flow:interrupt" | "flow:suspend" | "flow:cycleModel" | "model:cycleThinking" | "queue:dequeue" | "input:pasteImage" | "input:externalEditor" | "overlay:open" | "view:expandTools" | "view:toggleReasoning" | "none";
|
|
118
|
+
export type ConsoleVerb = "text:type" | "text:newline" | "edit:erasePrev" | "edit:eraseNext" | "edit:clearLine" | "nav:left" | "nav:right" | "nav:home" | "nav:end" | "nav:up" | "nav:down" | "flow:submit" | "flow:dismiss" | "flow:accept" | "flow:interrupt" | "flow:suspend" | "flow:cycleModel" | "model:cycleThinking" | "mode:cyclePermission" | "mode:togglePlan" | "queue:dequeue" | "input:pasteImage" | "input:externalEditor" | "overlay:open" | "view:expandTools" | "view:toggleReasoning" | "none";
|
|
110
119
|
/**
|
|
111
120
|
* A classified keystroke: a {@link ConsoleVerb} plus the small payload a verb
|
|
112
121
|
* may carry — the literal text for a `text:type` insert, or the target overlay
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval queue — the headless, pure serializer behind the approval overlay.
|
|
3
|
+
*
|
|
4
|
+
* The permission gate may reach an `ask` decision while another approval prompt is
|
|
5
|
+
* already on screen (e.g. a turn that batches several tool calls). The UI shows ONE
|
|
6
|
+
* prompt at a time, so the pending requests are held in an ordered queue: each
|
|
7
|
+
* `enqueue` parks a request, the HEAD is the prompt currently shown, and `settle`
|
|
8
|
+
* resolves the head's parked promise then advances to the next. This module is a
|
|
9
|
+
* pure reducer over an immutable {@link ApprovalQueueState} plus a couple of tiny
|
|
10
|
+
* helpers — no React, no Ink, no timers — so the queue logic is unit-testable in
|
|
11
|
+
* isolation (the overlay component only renders the head and dispatches settles).
|
|
12
|
+
*
|
|
13
|
+
* Each queued entry carries the parked promise's `resolve` (the gate awaits it) and
|
|
14
|
+
* the request itself. Settling resolves with an {@link ApprovalChoice}; an
|
|
15
|
+
* abort/clear settles every outstanding entry with `"deny"` so a cancelled turn
|
|
16
|
+
* never hangs on a pending prompt.
|
|
17
|
+
*/
|
|
18
|
+
import type { ApprovalChoice } from "../../conductor";
|
|
19
|
+
import type { ApprovalRequest } from "./approval";
|
|
20
|
+
/** One parked approval request awaiting the user's choice. */
|
|
21
|
+
export interface ApprovalEntry {
|
|
22
|
+
/** A stable id, unique within the queue's lifetime, used to settle the right one. */
|
|
23
|
+
readonly id: string;
|
|
24
|
+
/** The pending request the prompt renders. */
|
|
25
|
+
readonly request: ApprovalRequest;
|
|
26
|
+
/** Fulfil the gate's parked promise with the user's choice. Called exactly once. */
|
|
27
|
+
readonly resolve: (choice: ApprovalChoice) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The immutable queue state. The array is ordered oldest-first; the head (index 0)
|
|
31
|
+
* is the request currently prompted. An empty queue means no prompt is showing.
|
|
32
|
+
*/
|
|
33
|
+
export interface ApprovalQueueState {
|
|
34
|
+
/** The parked entries, oldest first; `[0]` is the active prompt. */
|
|
35
|
+
readonly entries: readonly ApprovalEntry[];
|
|
36
|
+
}
|
|
37
|
+
/** The empty queue — no approval prompt pending. */
|
|
38
|
+
export declare const EMPTY_APPROVAL_QUEUE: ApprovalQueueState;
|
|
39
|
+
/**
|
|
40
|
+
* The closed action union the queue reducer folds:
|
|
41
|
+
* - `enqueue` — park a new request at the tail.
|
|
42
|
+
* - `settle` — resolve the entry matching `id` with `choice` and drop it.
|
|
43
|
+
* - `clear` — drop EVERY entry (the caller resolves each with `"deny"`).
|
|
44
|
+
*/
|
|
45
|
+
export type ApprovalQueueEvent = {
|
|
46
|
+
readonly type: "enqueue";
|
|
47
|
+
readonly entry: ApprovalEntry;
|
|
48
|
+
} | {
|
|
49
|
+
readonly type: "settle";
|
|
50
|
+
readonly id: string;
|
|
51
|
+
} | {
|
|
52
|
+
readonly type: "clear";
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Fold one {@link ApprovalQueueEvent} over the queue, returning a fresh state.
|
|
56
|
+
*
|
|
57
|
+
* Pure and total: it never resolves a promise itself (the caller does that around
|
|
58
|
+
* a `settle`/`clear`), it only mutates the ordered entry list. `enqueue` appends;
|
|
59
|
+
* `settle` removes the entry with the matching `id` (a no-op when absent, e.g. a
|
|
60
|
+
* double-settle); `clear` empties the queue.
|
|
61
|
+
*
|
|
62
|
+
* @param state the prior queue state
|
|
63
|
+
* @param event the action to apply
|
|
64
|
+
*/
|
|
65
|
+
export declare function approvalQueueReducer(state: ApprovalQueueState, event: ApprovalQueueEvent): ApprovalQueueState;
|
|
66
|
+
/**
|
|
67
|
+
* The active prompt — the head entry — or `undefined` when the queue is empty.
|
|
68
|
+
*
|
|
69
|
+
* @param state the queue state
|
|
70
|
+
*/
|
|
71
|
+
export declare function activeApproval(state: ApprovalQueueState): ApprovalEntry | undefined;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval overlay — the interactive tool-permission prompt.
|
|
3
|
+
*
|
|
4
|
+
* This group owns the single modal kind raised when the permission gate reaches an
|
|
5
|
+
* `ask` decision for a tool call: it shows the pending request (tool name, a short
|
|
6
|
+
* rendering of the arguments, and any suggested allow-rule) and lets the user pick
|
|
7
|
+
* one of three outcomes — allow this one call, allow it for the rest of the session
|
|
8
|
+
* (which the gate turns into a session allow-rule), or deny it. It is mounted
|
|
9
|
+
* unconditionally by {@link import("./host").OverlayHost}, which routes by
|
|
10
|
+
* {@link ModalState.kind}; this component renders a dialog body only for its own
|
|
11
|
+
* `approval` kind and is otherwise inert.
|
|
12
|
+
*
|
|
13
|
+
* The wiring is a parked promise: when the React layer builds the conductor's
|
|
14
|
+
* approval resolver it returns a promise and stashes the request (plus the
|
|
15
|
+
* promise's `resolve`) under {@link ModalState.payload}. This overlay reads that
|
|
16
|
+
* payload, renders the choices, and on a pick calls `payload.resolve(choice)` then
|
|
17
|
+
* closes the modal — handing control back to the gate, which proceeds or denies. An
|
|
18
|
+
* Esc (the dialog's own close) resolves `"deny"` so a dismissed prompt never hangs
|
|
19
|
+
* the in-flight turn. The actual select UI reuses the framework `ThemeDialog`
|
|
20
|
+
* (a labelled, navigable pick-from-list with descriptions), so the overlay needs no
|
|
21
|
+
* bespoke key handling.
|
|
22
|
+
*
|
|
23
|
+
* React/Ink are obtained the same way the other overlays do (default React export
|
|
24
|
+
* from `indusagi/react-host`, `Box`/`Text` from `indusagi/react-host/ink`).
|
|
25
|
+
*/
|
|
26
|
+
import { type ThemeDialogItem } from "indusagi/react-ink";
|
|
27
|
+
import type { ApprovalChoice } from "../../conductor";
|
|
28
|
+
import type { OverlayGroupProps } from "./pickers";
|
|
29
|
+
/**
|
|
30
|
+
* The pending tool-permission request a prompt is raised for. Mirrors the
|
|
31
|
+
* arguments the conductor's approval resolver is handed for an `ask` decision.
|
|
32
|
+
*/
|
|
33
|
+
export interface ApprovalRequest {
|
|
34
|
+
/** The tool the model asked to run (e.g. `"Bash"`, `"Edit"`). */
|
|
35
|
+
readonly toolName: string;
|
|
36
|
+
/** The validated arguments the tool would run with. */
|
|
37
|
+
readonly input: unknown;
|
|
38
|
+
/**
|
|
39
|
+
* Optional human-readable allow-rule suggestions the prompt surfaces (e.g.
|
|
40
|
+
* `"Bash(npm run test:*)"`), so the user knows what an "allow always" remembers.
|
|
41
|
+
*/
|
|
42
|
+
readonly suggestions?: readonly string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The opaque {@link ModalState.payload} the `approval` overlay narrows: the pending
|
|
46
|
+
* request plus the resolver of the parked approval promise. The overlay calls
|
|
47
|
+
* `resolve(choice)` exactly once, then closes the modal.
|
|
48
|
+
*/
|
|
49
|
+
export interface ApprovalPayload {
|
|
50
|
+
/** The pending request to render. */
|
|
51
|
+
readonly request: ApprovalRequest;
|
|
52
|
+
/** Fulfil the parked approval promise with the user's choice. */
|
|
53
|
+
readonly resolve: (choice: ApprovalChoice) => void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The three offerable outcomes, in listing order. The `id` is the
|
|
57
|
+
* {@link ApprovalChoice} the gate consumes; `label`/`description` are what the
|
|
58
|
+
* prompt shows. Kept as data (not an `if`-ladder) so the choice→resolution mapping
|
|
59
|
+
* is a pure table the headless test asserts against.
|
|
60
|
+
*/
|
|
61
|
+
export declare const APPROVAL_CHOICES: readonly (ThemeDialogItem & {
|
|
62
|
+
id: ApprovalChoice;
|
|
63
|
+
})[];
|
|
64
|
+
/** The {@link ApprovalChoice} a dismissed (Esc) prompt resolves to. */
|
|
65
|
+
export declare const DISMISS_CHOICE: ApprovalChoice;
|
|
66
|
+
/**
|
|
67
|
+
* Map a selected dialog `id` back to the {@link ApprovalChoice} the gate consumes.
|
|
68
|
+
*
|
|
69
|
+
* Pure and total: a recognised id maps to itself; anything unrecognised falls back
|
|
70
|
+
* to {@link DISMISS_CHOICE} (`"deny"`) so a stray selection can never silently
|
|
71
|
+
* allow a tool. This is the unit the headless test pins.
|
|
72
|
+
*
|
|
73
|
+
* @param id the `id` the {@link ThemeDialog} reported on select
|
|
74
|
+
*/
|
|
75
|
+
export declare function choiceFromId(id: string): ApprovalChoice;
|
|
76
|
+
/**
|
|
77
|
+
* Narrow the opaque modal payload into a typed {@link ApprovalPayload}, or
|
|
78
|
+
* `undefined` when it is not a well-formed approval request (a defensive guard —
|
|
79
|
+
* the overlay renders nothing rather than crash on a malformed payload).
|
|
80
|
+
*
|
|
81
|
+
* @param payload the opaque {@link ModalState.payload}
|
|
82
|
+
*/
|
|
83
|
+
export declare function readApprovalPayload(payload: unknown): ApprovalPayload | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Render a tool call's arguments as a single short, human-readable line for the
|
|
86
|
+
* prompt body. A shell `command` (or any `command` field) shows verbatim;
|
|
87
|
+
* otherwise a compact JSON encoding is used. Long values are elided so the prompt
|
|
88
|
+
* never floods the terminal.
|
|
89
|
+
*
|
|
90
|
+
* @param input the validated tool arguments
|
|
91
|
+
*/
|
|
92
|
+
export declare function summarizeInput(input: unknown): string;
|
|
93
|
+
/**
|
|
94
|
+
* The approval overlay group: the single `approval` modal kind.
|
|
95
|
+
*
|
|
96
|
+
* Renders the prompt body when the active modal is `approval` and its payload is a
|
|
97
|
+
* well-formed {@link ApprovalPayload}; every other kind (and a malformed payload)
|
|
98
|
+
* yields nothing. Unlike the session/auth groups this does NOT require the runtime
|
|
99
|
+
* services bundle — the payload carries everything the prompt needs — so it works
|
|
100
|
+
* on any mount path that wired a resolver.
|
|
101
|
+
*
|
|
102
|
+
* @param props the forwarded overlay props (modal, services, theme, dispatch, closer)
|
|
103
|
+
*/
|
|
104
|
+
export declare function ApprovalOverlays(props: OverlayGroupProps): JSX.Element | null;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval overlay — headless unit tests for the pure logic behind the prompt.
|
|
3
|
+
*
|
|
4
|
+
* Rendering an Ink dialog headlessly is brittle, so these tests pin the two pure
|
|
5
|
+
* pieces the interactive overlay is built from — exactly the bar the task sets:
|
|
6
|
+
*
|
|
7
|
+
* 1. The choice→resolution mapping ({@link choiceFromId}) + the payload narrowing
|
|
8
|
+
* ({@link readApprovalPayload}) + the argument summary ({@link summarizeInput}):
|
|
9
|
+
* a selected dialog row maps to the {@link ApprovalChoice} the gate consumes, a
|
|
10
|
+
* malformed payload is rejected, and a stray id falls back to `deny`.
|
|
11
|
+
* 2. The queue reducer ({@link approvalQueueReducer}) + head selector
|
|
12
|
+
* ({@link activeApproval}): requests serialise oldest-first, a settle drops the
|
|
13
|
+
* matching entry (and a double-settle is inert), and a clear empties the queue.
|
|
14
|
+
*
|
|
15
|
+
* No React, no Ink, no conductor — just the exported functions.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* owns a disjoint slice of the kind space and renders a body only for its own
|
|
11
11
|
* kinds:
|
|
12
12
|
*
|
|
13
|
-
* - {@link PickerOverlays}
|
|
14
|
-
* - {@link SessionOverlays}
|
|
15
|
-
* - {@link AuthOverlays}
|
|
13
|
+
* - {@link PickerOverlays} — `models`, `scopedModels`, `theme`, `settings`.
|
|
14
|
+
* - {@link SessionOverlays} — `sessions`, `tree`, `userTurns`.
|
|
15
|
+
* - {@link AuthOverlays} — `signIn`, `signOut`, `oauth`, `plugin`.
|
|
16
|
+
* - {@link ApprovalOverlays} — `approval` (the tool-permission prompt).
|
|
16
17
|
*
|
|
17
18
|
* When no overlay is raised (`kind === "none"`) the host renders nothing, so the
|
|
18
19
|
* composer keeps focus and the groups are never mounted needlessly.
|
|
@@ -11,3 +11,5 @@ export { OverlayHost, type OverlayHostProps } from "./host";
|
|
|
11
11
|
export { PickerOverlays, type OverlayGroupProps } from "./pickers";
|
|
12
12
|
export { SessionOverlays } from "./sessions";
|
|
13
13
|
export { AuthOverlays } from "./auth";
|
|
14
|
+
export { ApprovalOverlays, choiceFromId, readApprovalPayload, summarizeInput, APPROVAL_CHOICES, DISMISS_CHOICE, type ApprovalRequest, type ApprovalPayload, } from "./approval";
|
|
15
|
+
export { approvalQueueReducer, activeApproval, EMPTY_APPROVAL_QUEUE, type ApprovalEntry, type ApprovalQueueState, type ApprovalQueueEvent, } from "./approval-queue";
|
|
@@ -42,6 +42,25 @@ import type { InkThemeAdapter, ThemeTokens } from "../contract";
|
|
|
42
42
|
* info ← notice (informational status tone)
|
|
43
43
|
* highlight ← inkText (high-contrast on-accent text)
|
|
44
44
|
*
|
|
45
|
+
* Plus the markdown / diff / syntax-highlight role keys the framework's rich
|
|
46
|
+
* render path (`theme.role(...)` / `theme.roleBackground(...)`) resolves. These
|
|
47
|
+
* key names match the framework adapter's default role → key map exactly, so the
|
|
48
|
+
* styled transcript, colored diffs, and fenced-code highlighting resolve their
|
|
49
|
+
* colours straight from the console's derived tokens:
|
|
50
|
+
*
|
|
51
|
+
* codeInline ← codeInline (inline `code` foreground)
|
|
52
|
+
* heading ← heading (markdown heading foreground)
|
|
53
|
+
* blockquoteBar ← blockquoteBar (dim quote bar)
|
|
54
|
+
* diffAddedBg ← diffAddedBg (added-line background tint)
|
|
55
|
+
* diffRemovedBg ← diffRemovedBg (removed-line background tint)
|
|
56
|
+
* diffAddedText ← diffAddedText (added foreground / `+`)
|
|
57
|
+
* diffRemovedText ← diffRemovedText (removed foreground / `-`)
|
|
58
|
+
* synKeyword ← synKeyword (syntax: keywords)
|
|
59
|
+
* synString ← synString (syntax: strings)
|
|
60
|
+
* synNumber ← synNumber (syntax: numbers)
|
|
61
|
+
* synComment ← synComment (syntax: comments)
|
|
62
|
+
* synType ← synType (syntax: types / classes)
|
|
63
|
+
*
|
|
45
64
|
* @param tokens the derived semantic token map for a scheme
|
|
46
65
|
* @returns a flat colour Record keyed by the framework's vocabulary
|
|
47
66
|
*/
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Consumers import from `src/console/theme` and never reach into the individual
|
|
13
13
|
* palette/tokens/adapter/resolve modules.
|
|
14
14
|
*/
|
|
15
|
-
export { MIDNIGHT_PALETTE, DAYLIGHT_PALETTE, PALETTES } from "./palette";
|
|
15
|
+
export { MIDNIGHT_PALETTE, DAYLIGHT_PALETTE, MIDNIGHT_CB_PALETTE, DAYLIGHT_CB_PALETTE, PALETTES, } from "./palette";
|
|
16
16
|
export { deriveTokens } from "./tokens";
|
|
17
17
|
export { themeAdapter, frameworkColors } from "./adapter";
|
|
18
18
|
export { THEMES, THEME_SCHEMES, resolveTheme } from "./resolve";
|
|
@@ -33,6 +33,31 @@ export declare const MIDNIGHT_PALETTE: ThemePalette;
|
|
|
33
33
|
* to a dark-on-light slate.
|
|
34
34
|
*/
|
|
35
35
|
export declare const DAYLIGHT_PALETTE: ThemePalette;
|
|
36
|
+
/**
|
|
37
|
+
* The dark-terminal color-blind-safe ramp.
|
|
38
|
+
*
|
|
39
|
+
* A clone of {@link MIDNIGHT_PALETTE} that re-derives the three *status* hues so
|
|
40
|
+
* a red-green color-blind user (deuteran/protan, ~8% of men) can tell success
|
|
41
|
+
* from failure without relying on the red-green axis. Success moves off green
|
|
42
|
+
* onto a vivid blue (`affirm → #4aa3ff`); failure stays red but is deepened to a
|
|
43
|
+
* darker tone (`alarm → #c83232`) so it sits well below the bright blue in
|
|
44
|
+
* lightness, and the amber warning is nudged brighter — so the three status
|
|
45
|
+
* tones separate by *lightness*, not hue alone. The three accent hues and the
|
|
46
|
+
* neutral gradient are carried over unchanged from the base midnight ramp — only
|
|
47
|
+
* the status stops move, so the overall look stays the midnight scheme.
|
|
48
|
+
*/
|
|
49
|
+
export declare const MIDNIGHT_CB_PALETTE: ThemePalette;
|
|
50
|
+
/**
|
|
51
|
+
* The light-terminal color-blind-safe ramp.
|
|
52
|
+
*
|
|
53
|
+
* The daylight counterpart of {@link MIDNIGHT_CB_PALETTE}: clones
|
|
54
|
+
* {@link DAYLIGHT_PALETTE} and remaps success to a deeper blue tuned for a
|
|
55
|
+
* bright background (`affirm → #1f6fd6`), deepens the red alarm
|
|
56
|
+
* (`alarm → #b02622`) for lightness separation from that blue, and darkens the
|
|
57
|
+
* amber warning so the three status tones stay separable by lightness on a light
|
|
58
|
+
* terminal too.
|
|
59
|
+
*/
|
|
60
|
+
export declare const DAYLIGHT_CB_PALETTE: ThemePalette;
|
|
36
61
|
/**
|
|
37
62
|
* The raw ramp for each scheme, keyed by {@link ThemeScheme}.
|
|
38
63
|
*
|
|
@@ -25,6 +25,28 @@
|
|
|
25
25
|
* - `caution` ← `caution` (warning tone)
|
|
26
26
|
* - `alarm` ← `alarm` (error/fault tone)
|
|
27
27
|
* - `pending` ← `primary` (busy/in-flight tone)
|
|
28
|
+
*
|
|
29
|
+
* Rich-render roles (markdown / diff / syntax highlighting) are derived from the
|
|
30
|
+
* same nine stops so the rebuild's new styled-transcript / colored-diff /
|
|
31
|
+
* fenced-code surfaces recolour with the scheme and need no extra palette stop:
|
|
32
|
+
*
|
|
33
|
+
* - `codeInline` ← `primary` (inline code accent)
|
|
34
|
+
* - `heading` ← `primary` (heading accent)
|
|
35
|
+
* - `blockquoteBar` ← `muted` (dim quote bar)
|
|
36
|
+
* - `diffAddedBg` ← `affirm` darkened toward ink (added-line tint)
|
|
37
|
+
* - `diffRemovedBg` ← `alarm` darkened toward ink (removed-line tint)
|
|
38
|
+
* - `diffAddedText` ← `affirm` (added foreground / `+`)
|
|
39
|
+
* - `diffRemovedText` ← `alarm` (removed foreground / `-`)
|
|
40
|
+
* - `synKeyword` ← `primary` (keywords)
|
|
41
|
+
* - `synString` ← `affirm` (strings)
|
|
42
|
+
* - `synNumber` ← `caution` (numbers)
|
|
43
|
+
* - `synComment` ← `muted` (comments)
|
|
44
|
+
* - `synType` ← `tertiary` (types / classes)
|
|
45
|
+
*
|
|
46
|
+
* Deriving the two diff backgrounds (rather than adding raw stops) keeps the
|
|
47
|
+
* {@link ThemePalette} a flat nine-stop ramp while guaranteeing every scheme —
|
|
48
|
+
* including the color-blind variants — gets a legible `+`/`-` tint that tracks
|
|
49
|
+
* its own success/alarm hue.
|
|
28
50
|
*/
|
|
29
51
|
import type { ThemePalette, ThemeTokens } from "../contract";
|
|
30
52
|
/**
|
|
@@ -35,6 +57,6 @@ import type { ThemePalette, ThemeTokens } from "../contract";
|
|
|
35
57
|
* assignments are shared by both schemes — only the ramp handed in differs.
|
|
36
58
|
*
|
|
37
59
|
* @param palette the raw nine-stop ramp for a scheme
|
|
38
|
-
* @returns the
|
|
60
|
+
* @returns the full semantic token map (status + rich-render roles)
|
|
39
61
|
*/
|
|
40
62
|
export declare function deriveTokens(palette: ThemePalette): ThemeTokens;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -171,6 +171,8 @@ export interface Invocation {
|
|
|
171
171
|
readonly attachments?: Attachments;
|
|
172
172
|
/** Explicit model selector (`--model` / `-m`), provider-qualified or bare. */
|
|
173
173
|
readonly model?: string;
|
|
174
|
+
/** Model to fall back to when the selected model is overloaded mid-turn (`--fallback-model`). */
|
|
175
|
+
readonly fallbackModel?: string;
|
|
174
176
|
/** Named credential account to authenticate the run with (`--account`). */
|
|
175
177
|
readonly account?: string;
|
|
176
178
|
/** Working directory the run is scoped to (`--cwd`); absent means process cwd. */
|
|
@@ -20,7 +20,7 @@ export { runPackageCommand, defaultPackageIo, PACKAGE_COMMANDS, } from "./packag
|
|
|
20
20
|
export type { PackageCommand, PackageIo, PackageCommandOptions, PackageResult, } from "./packages";
|
|
21
21
|
export { runCredentialCommand, defaultCredentialIo, formatCredentialFault, validateApiKey, validateAccountName, findProvider, isOAuthCapable, asSigninMethod, PROVIDER_DIRECTORY, } from "./credentials";
|
|
22
22
|
export type { CredentialIo, CredentialResult, SigninMethod } from "./credentials";
|
|
23
|
-
export { registerBuiltInOAuthProviders, listLoginProviders, startOAuthLogin, openLoginUrl, } from "./oauth";
|
|
23
|
+
export { registerBuiltInOAuthProviders, listLoginProviders, startOAuthLogin, openLoginUrl, hasRegisteredOAuthClientId, } from "./oauth";
|
|
24
24
|
export type { AuthKind, LoginProvider, OAuthLoginResult, } from "./oauth";
|
|
25
25
|
export { printModelCatalog, defaultCatalogIo, registrySource } from "./catalog";
|
|
26
26
|
export type { CatalogIo, CatalogModelSource } from "./catalog";
|
|
@@ -29,6 +29,19 @@ import type { AuthVault } from "./contract";
|
|
|
29
29
|
* that are registered after the call, for callers that want to confirm the set.
|
|
30
30
|
*/
|
|
31
31
|
export declare function registerBuiltInOAuthProviders(): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Whether a registered sign-in provider has a *real* OAuth client id wired in
|
|
34
|
+
* (its env var is set to something other than the framework's sentinel), so its
|
|
35
|
+
* browser sign-in can actually complete.
|
|
36
|
+
*
|
|
37
|
+
* Reads the env var live (not at import time) so a deployer that exports the id
|
|
38
|
+
* before launching `/login` is honored. A provider with no known client-id
|
|
39
|
+
* wiring (i.e. not one of the three sentinel-shipped framework providers) is
|
|
40
|
+
* treated as registered — we only gate the providers we know ship a sentinel.
|
|
41
|
+
*
|
|
42
|
+
* @param providerId the registered sign-in provider id
|
|
43
|
+
*/
|
|
44
|
+
export declare function hasRegisteredOAuthClientId(providerId: string): boolean;
|
|
32
45
|
/** How a provider authenticates in the merged sign-in directory. */
|
|
33
46
|
export type AuthKind = "oauth" | "apiKey";
|
|
34
47
|
/** One row of the merged sign-in directory. */
|
|
@@ -48,6 +48,46 @@ export type DeliveryMode = "all" | "one-at-a-time";
|
|
|
48
48
|
export declare const DELIVERY_MODES: readonly DeliveryMode[];
|
|
49
49
|
/** Narrow an arbitrary value to a known {@link DeliveryMode}. */
|
|
50
50
|
export declare function isDeliveryMode(value: unknown): value is DeliveryMode;
|
|
51
|
+
/**
|
|
52
|
+
* How aggressively the per-tool permission gate auto-allows tool calls before it
|
|
53
|
+
* falls back to asking (or denying):
|
|
54
|
+
*
|
|
55
|
+
* - `default` — consult the allow/ask/deny rules; read-only tools are
|
|
56
|
+
* auto-allowed, anything else with no matching allow rule
|
|
57
|
+
* falls through to `ask`.
|
|
58
|
+
* - `acceptEdits` — additionally auto-allow filesystem edits/writes (the
|
|
59
|
+
* mutating edit/write/multiedit tools), leaving everything
|
|
60
|
+
* else on the `default` path.
|
|
61
|
+
* - `bypass` — allow every tool with no prompt (the unsafe "trust all"
|
|
62
|
+
* mode; `bypassPermissions` is accepted as an alias).
|
|
63
|
+
* - `plan` — deny every mutating tool outright (read-only research only)
|
|
64
|
+
* so the agent can plan without touching the workspace.
|
|
65
|
+
*/
|
|
66
|
+
export type PermissionMode = "default" | "acceptEdits" | "bypass" | "plan" | "bypassPermissions";
|
|
67
|
+
/** The canonical {@link PermissionMode} values, as a frozen tuple for menus/guards. */
|
|
68
|
+
export declare const PERMISSION_MODES: readonly PermissionMode[];
|
|
69
|
+
/** Narrow an arbitrary value to a known {@link PermissionMode} (folds the alias). */
|
|
70
|
+
export declare function isPermissionMode(value: unknown): value is PermissionMode;
|
|
71
|
+
/**
|
|
72
|
+
* The declarative permission policy a session reads at startup.
|
|
73
|
+
*
|
|
74
|
+
* `allow`/`ask`/`deny` are ordered lists of induscode-style rule strings — a bare
|
|
75
|
+
* tool name (`"Bash"`) or a tool name with an argument specifier
|
|
76
|
+
* (`"Bash(npm run test:*)"`). Across tiers the three lists are concatenated, and
|
|
77
|
+
* `deny` wins over `ask` wins over `allow`. `defaultMode` seeds the session's
|
|
78
|
+
* permission mode when no flag overrides it. Every field is optional so an empty
|
|
79
|
+
* `{}` (or an absent `permissions` key) keeps today's allow-all behavior.
|
|
80
|
+
*/
|
|
81
|
+
export interface PermissionSettings {
|
|
82
|
+
/** Rule strings that auto-allow a matching tool call (lowest precedence). */
|
|
83
|
+
allow?: string[];
|
|
84
|
+
/** Rule strings that force a matching tool call to prompt for approval. */
|
|
85
|
+
ask?: string[];
|
|
86
|
+
/** Rule strings that hard-block a matching tool call (highest precedence). */
|
|
87
|
+
deny?: string[];
|
|
88
|
+
/** The permission mode the session opens in when no flag overrides it. */
|
|
89
|
+
defaultMode?: PermissionMode;
|
|
90
|
+
}
|
|
51
91
|
/**
|
|
52
92
|
* Every preference an interactive coding-agent session reads, as one flat,
|
|
53
93
|
* fully-optional record.
|
|
@@ -93,12 +133,31 @@ export interface Preferences {
|
|
|
93
133
|
defaultThinkingLevel?: ThinkingLevel;
|
|
94
134
|
/** Suppress the banner / tips shown on a normal interactive launch. */
|
|
95
135
|
quietStartup?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* The last product version whose full masthead the user has already seen. The
|
|
138
|
+
* banner auto-condenses to a one-line header when this equals the running
|
|
139
|
+
* version (and nothing else demands the full block); it is rewritten to the
|
|
140
|
+
* running version after the full masthead is shown, so a launch only shows the
|
|
141
|
+
* big wordmark on the first sight of a version or a version bump.
|
|
142
|
+
*/
|
|
143
|
+
lastSeenVersion?: string;
|
|
144
|
+
/** Opt-in static colour-sweep flourish tinting the startup wordmark / emblem. */
|
|
145
|
+
logoSweep?: boolean;
|
|
146
|
+
/** When set, motion-flavoured flourishes (e.g. the logo sweep) are suppressed. */
|
|
147
|
+
reducedMotion?: boolean;
|
|
96
148
|
/** Whether the window-budget manager compacts the transcript automatically. */
|
|
97
149
|
autoCompact?: boolean;
|
|
98
150
|
/** What a double-escape does in the console. */
|
|
99
151
|
doubleEscapeAction?: EscapeAction;
|
|
100
152
|
/** Extension-package sources the launcher installs and loads (npm / git / local). */
|
|
101
153
|
extensionPackages?: string[];
|
|
154
|
+
/**
|
|
155
|
+
* The declarative tool-permission policy: ordered allow/ask/deny rule lists and
|
|
156
|
+
* the opening permission mode. Across the project/global tiers the rule lists
|
|
157
|
+
* are concatenated (not overridden) and `deny > ask > allow` decides; an absent
|
|
158
|
+
* value (or an empty object) preserves today's allow-all behavior.
|
|
159
|
+
*/
|
|
160
|
+
permissions?: PermissionSettings;
|
|
102
161
|
}
|
|
103
162
|
/** The set of legal preference keys, derived from {@link Preferences}. */
|
|
104
163
|
export type SettingKey = keyof Preferences;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* {@link PreferenceStore} reader/writer. Console surfaces and boot stages depend
|
|
8
8
|
* on this module rather than reaching into the individual files.
|
|
9
9
|
*/
|
|
10
|
-
export type { Preferences, SettingKey, EscapeAction, DeliveryMode, ThinkingLevel, } from "./contract";
|
|
11
|
-
export { DEFAULT_PREFERENCES, SETTING_KEYS, ESCAPE_ACTIONS, isEscapeAction, DELIVERY_MODES, isDeliveryMode, } from "./contract";
|
|
10
|
+
export type { Preferences, SettingKey, EscapeAction, DeliveryMode, ThinkingLevel, PermissionMode, PermissionSettings, } from "./contract";
|
|
11
|
+
export { DEFAULT_PREFERENCES, SETTING_KEYS, ESCAPE_ACTIONS, isEscapeAction, DELIVERY_MODES, isDeliveryMode, PERMISSION_MODES, isPermissionMode, } from "./contract";
|
|
12
12
|
export { PreferenceStore } from "./manager";
|
|
13
13
|
export type { PreferenceLocations } from "./manager";
|
|
@@ -28,8 +28,22 @@
|
|
|
28
28
|
* matching session-scope entrypoint. Both are re-exported here so callers can
|
|
29
29
|
* summarize a slice directly without building a full {@link Condenser}.
|
|
30
30
|
*/
|
|
31
|
-
import type { AgentMessage, CondenserDeps, Condenser, Summary } from "./contract.js";
|
|
31
|
+
import type { AgentMessage, BudgetPolicy, CondenserDeps, Condenser, Summary } from "./contract.js";
|
|
32
32
|
import { condenseScope, type SummarizeDeps } from "./summarize/index.js";
|
|
33
|
+
/**
|
|
34
|
+
* The fallback {@link BudgetPolicy} when the caller supplies none. These are
|
|
35
|
+
* ordinary configuration defaults — a window-relative ratio plus a token tail —
|
|
36
|
+
* computed from the model's own context window rather than fixed magic numbers.
|
|
37
|
+
* - `triggerRatio` 0.75 — condense once ~three-quarters of the window is used.
|
|
38
|
+
* - `keepRecent` 6000 — keep roughly the last 6k tokens of turns verbatim.
|
|
39
|
+
* - `reserveTokens` 2048 — carve a little headroom off the window first.
|
|
40
|
+
*
|
|
41
|
+
* Exported as {@link AUTO_CONDENSE_POLICY} so the conductor's token gate and the
|
|
42
|
+
* session runner's slice planner share **one** policy — the value the auto-path
|
|
43
|
+
* trigger ({@link isOverBudget}) compares against must equal the value the slice
|
|
44
|
+
* planner ({@link planSlice}) cuts with, or the gate and the cut disagree.
|
|
45
|
+
*/
|
|
46
|
+
export declare const AUTO_CONDENSE_POLICY: BudgetPolicy;
|
|
33
47
|
/**
|
|
34
48
|
* Build a {@link Condenser} from a {@link CondenserDeps} bundle. The result plugs
|
|
35
49
|
* straight into the conductor's `CondenseFn` seam.
|
|
@@ -12,4 +12,6 @@ export type { AgentMessage, BudgetPolicy, CompleteFn, CondensePlan, Condenser, C
|
|
|
12
12
|
export { budgetLimit, estimateMessageTokens, estimateTokens, isOverBudget, planSlice, prefixTokens, } from "./budget/index.js";
|
|
13
13
|
export { buildSummaryPrompt, CONDENSER_BRIEF, flattenTranscript, summarize, } from "./summarize/index.js";
|
|
14
14
|
export type { SummarizeDeps } from "./summarize/index.js";
|
|
15
|
-
export { condense, condenseScope, createCondenser } from "./condenser.js";
|
|
15
|
+
export { AUTO_CONDENSE_POLICY, condense, condenseScope, createCondenser } from "./condenser.js";
|
|
16
|
+
export { CLEARED_TOOL_RESULT, clearStaleToolResults, COMPACTABLE_TOOL_NAMES, } from "./microcompact.js";
|
|
17
|
+
export { rehydrateRecentReads, RESTORED_FILE_PREFIX } from "./rehydrate.js";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window-budget / microcompact — clear stale tool-result bodies in place.
|
|
3
|
+
*
|
|
4
|
+
* The cheapest token to reclaim is one that is already dead weight: the verbatim
|
|
5
|
+
* body of a tool result the model has long since acted on. Once an agent has
|
|
6
|
+
* read a file, run a search, or executed a command and moved several turns past
|
|
7
|
+
* it, the full body of that result rarely needs to stay in the window — the
|
|
8
|
+
* model's subsequent reasoning already captured what mattered. Yet those bodies
|
|
9
|
+
* (a 2,000-line `read`, a noisy `bash` log, a wide `grep`) dominate the token
|
|
10
|
+
* budget.
|
|
11
|
+
*
|
|
12
|
+
* **Microcompaction** runs *before* a full {@link condense}: it walks the
|
|
13
|
+
* transcript, keeps the last few tool results verbatim (the model may still be
|
|
14
|
+
* working with them), and replaces the body of every older compactable tool
|
|
15
|
+
* result with a short sentinel. This reclaims tokens for free — no model call,
|
|
16
|
+
* no summary round-trip — and often defers (or shrinks the input to) the real
|
|
17
|
+
* condense.
|
|
18
|
+
*
|
|
19
|
+
* Shape note (this rebuild): a tool result is its OWN top-level
|
|
20
|
+
* {@link ToolResultMessage} (`role: 'toolResult'`), not a block nested inside a
|
|
21
|
+
* user message. Clearing one therefore means replacing *that message's*
|
|
22
|
+
* `content` array with a single sentinel text block — never editing a sub-block
|
|
23
|
+
* of some other message. We only clear results whose owning assistant `toolCall`
|
|
24
|
+
* named a compactable tool, so structural/control results stay intact.
|
|
25
|
+
*
|
|
26
|
+
* Behavior-preserving by construction: when there is nothing to clear (no
|
|
27
|
+
* compactable results, or every one is within the keep window) the *same input
|
|
28
|
+
* reference* is returned, so a caller can cheaply detect a no-op.
|
|
29
|
+
*/
|
|
30
|
+
import type { AgentMessage } from "./contract.js";
|
|
31
|
+
/**
|
|
32
|
+
* The placeholder spliced in where a stale tool-result body used to be. Kept
|
|
33
|
+
* short on purpose — the whole point is to reclaim the tokens the original body
|
|
34
|
+
* occupied — while still signalling to the model (and to a human reading the
|
|
35
|
+
* transcript) that real content was elided rather than lost.
|
|
36
|
+
*/
|
|
37
|
+
export declare const CLEARED_TOOL_RESULT = "[Old tool result content cleared]";
|
|
38
|
+
/**
|
|
39
|
+
* The wire names of tools whose results are safe to clear once stale.
|
|
40
|
+
*
|
|
41
|
+
* These are the read-mostly / output-heavy tools whose bodies are reconstructable
|
|
42
|
+
* (re-read the file, re-run the search) and whose stale content the model has
|
|
43
|
+
* already digested. Control/state tools (todo, memory, task) are deliberately
|
|
44
|
+
* absent — their results can carry standing instructions the model still needs.
|
|
45
|
+
*/
|
|
46
|
+
export declare const COMPACTABLE_TOOL_NAMES: ReadonlySet<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Clear the bodies of stale compactable tool results, keeping the most recent
|
|
49
|
+
* `keepRecent` of them verbatim.
|
|
50
|
+
*
|
|
51
|
+
* Walks the transcript, identifies every `role:'toolResult'` message that
|
|
52
|
+
* belongs to a compactable tool call, keeps the last `keepRecent` (floored at 1
|
|
53
|
+
* — `slice(-0)` would keep everything), and replaces each older one's `content`
|
|
54
|
+
* with a single `{ type:'text', text: CLEARED_TOOL_RESULT }` block. Non-tool
|
|
55
|
+
* messages, control-tool results, and already-cleared results are left exactly
|
|
56
|
+
* as they were.
|
|
57
|
+
*
|
|
58
|
+
* Returns the **same input array reference** when nothing was cleared, so the
|
|
59
|
+
* caller can detect a no-op by identity. Otherwise returns a new array; cleared
|
|
60
|
+
* messages are fresh objects (the originals are not mutated).
|
|
61
|
+
*
|
|
62
|
+
* @param messages the active transcript, oldest-first
|
|
63
|
+
* @param opts.keepRecent how many most-recent compactable results to keep
|
|
64
|
+
* verbatim (default {@link DEFAULT_KEEP_RECENT}, floored at 1)
|
|
65
|
+
*/
|
|
66
|
+
export declare function clearStaleToolResults(messages: AgentMessage[], opts?: {
|
|
67
|
+
keepRecent?: number;
|
|
68
|
+
}): AgentMessage[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window-budget / microcompact + rehydrate — unit tests for item #18.
|
|
3
|
+
*
|
|
4
|
+
* Three layers ride the condense path:
|
|
5
|
+
* 1. microcompact ({@link clearStaleToolResults}) — blank older completed
|
|
6
|
+
* tool-result bodies to a sentinel, keeping the last N verbatim; no-op
|
|
7
|
+
* (same reference) otherwise.
|
|
8
|
+
* 2. rehydration ({@link rehydrateRecentReads}) — re-attach the most-recently
|
|
9
|
+
* dropped file reads as synthetic user messages, deduped against the kept
|
|
10
|
+
* tail, honoring maxFiles / tokenBudget.
|
|
11
|
+
* 3. circuit breaker — covered in the conductor suite (3 throwing condense
|
|
12
|
+
* calls stop further attempts, a success resets).
|
|
13
|
+
*
|
|
14
|
+
* Pure + network-free: no model is bound anywhere here.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|