indusagi-coding-agent 0.2.2 → 0.2.4
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 +46 -0
- package/dist/entry.js +12434 -9445
- package/dist/guardrails.js +897 -37
- package/dist/index.js +14081 -11111
- package/dist/types/boot/heap.d.ts +31 -0
- package/dist/types/boot/runners/delegate-runner.d.ts +27 -1
- package/dist/types/boot/runners/server-mode.d.ts +71 -0
- package/dist/types/boot/runners/session.d.ts +26 -18
- package/dist/types/boot/runners/session.test.d.ts +6 -1
- package/dist/types/boot/server-token.d.ts +97 -0
- package/dist/types/capability-deck/cards/index.d.ts +1 -0
- package/dist/types/capability-deck/cards/task-card.d.ts +26 -2
- package/dist/types/capability-deck/cards/workflow-card.d.ts +55 -0
- package/dist/types/capability-deck/cards/workflow-card.test.d.ts +12 -0
- package/dist/types/capability-deck/contract.d.ts +7 -6
- package/dist/types/capability-deck/index.d.ts +1 -1
- package/dist/types/conductor/conductor.d.ts +24 -0
- package/dist/types/conductor/contract.d.ts +79 -7
- package/dist/types/conductor/index.d.ts +3 -3
- package/dist/types/conductor/permissions.d.ts +74 -4
- package/dist/types/conductor/post-edit-diagnostics.test.d.ts +8 -3
- package/dist/types/conductor/quota-error.d.ts +35 -0
- package/dist/types/conductor/signal-hub/translate.d.ts +4 -1
- package/dist/types/console/auth-status.d.ts +28 -0
- package/dist/types/console/components/AgentsView.d.ts +41 -0
- package/dist/types/console/components/BackgroundAgents.d.ts +63 -0
- package/dist/types/console/components/BackgroundAgents.test.d.ts +8 -0
- package/dist/types/console/components/Banner.d.ts +67 -33
- package/dist/types/console/components/TerminalConsole.d.ts +0 -5
- package/dist/types/console/components/welcome.d.ts +115 -0
- package/dist/types/console/components/welcome.test.d.ts +9 -0
- package/dist/types/console/contract.d.ts +16 -1
- package/dist/types/console/index.d.ts +3 -0
- package/dist/types/console/input/index.d.ts +1 -1
- package/dist/types/console/input/keymap.d.ts +2 -2
- package/dist/types/console/input/paste.d.ts +58 -6
- package/dist/types/console/overlays/approval-queue.d.ts +18 -1
- package/dist/types/console/overlays/boards.d.ts +55 -0
- package/dist/types/console/overlays/index.d.ts +1 -1
- package/dist/types/console/theme/adapter.d.ts +1 -1
- package/dist/types/console/theme/index.d.ts +1 -1
- package/dist/types/console/theme/palette.d.ts +10 -0
- package/dist/types/launch/login.d.ts +68 -0
- package/dist/types/launch/oauth.test.d.ts +20 -0
- package/dist/types/window-budget/summarize/condense.d.ts +6 -0
- package/dist/types/workflow-engine/agent-runner.d.ts +124 -0
- package/dist/types/workflow-engine/agent-runner.test.d.ts +8 -0
- package/dist/types/workflow-engine/display.d.ts +148 -0
- package/dist/types/workflow-engine/display.test.d.ts +1 -0
- package/dist/types/workflow-engine/engine.d.ts +183 -0
- package/dist/types/workflow-engine/engine.test.d.ts +1 -0
- package/dist/types/workflow-engine/index.d.ts +21 -0
- package/dist/types/workflow-engine/parse.d.ts +64 -0
- package/dist/types/workflow-engine/parse.test.d.ts +1 -0
- package/dist/types/workflow-engine/structured-output.d.ts +51 -0
- package/dist/types/workflow-engine/structured-output.test.d.ts +1 -0
- package/dist/types/workspace/brand.d.ts +1 -1
- package/package.json +2 -2
- package/dist/types/console/components/Emblem.d.ts +0 -49
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Welcome-card content & per-session variation — the pure data behind the
|
|
3
|
+
* "IndusCode Saffron" startup card (the boxed masthead the {@link Banner} draws
|
|
4
|
+
* in its loud mode).
|
|
5
|
+
*
|
|
6
|
+
* This module holds *no* React or Ink: it is the render-agnostic source of the
|
|
7
|
+
* card's rotating mascot, the rotating "getting started" tip, the static
|
|
8
|
+
* "what's new" notes, the slash chips, and the small block-art robot mascot
|
|
9
|
+
* geometry. The banner reads these and paints them through the theme adapter;
|
|
10
|
+
* the geometry is returned as tone-tagged {@link MascotSegment}s so the banner
|
|
11
|
+
* maps a tone → a colour role without re-deriving the layout.
|
|
12
|
+
*
|
|
13
|
+
* Per-session freshness ("every new session the welcome looks a little
|
|
14
|
+
* different") is a *pure* selection: {@link pickWelcomeVariant} maps an integer
|
|
15
|
+
* seed onto one mascot + one tip deterministically, so a test pins an exact
|
|
16
|
+
* variant while the live surface seeds it once at mount from
|
|
17
|
+
* {@link randomWelcomeSeed}. Nothing here reads a clock or mutates state — same
|
|
18
|
+
* seed in, same variant out.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* One robot-mascot face: the two eye glyphs and the three-cell mouth.
|
|
22
|
+
*
|
|
23
|
+
* The face is drawn into a fixed nine-cell-wide rounded head (see
|
|
24
|
+
* {@link mascotRows}); only the eyes and mouth change between variants, so a
|
|
25
|
+
* face is just those glyphs plus a human-readable key for tests/logs. Each eye
|
|
26
|
+
* is exactly one display cell and the mouth exactly three so every face packs
|
|
27
|
+
* into the same head outline without shifting the columns.
|
|
28
|
+
*/
|
|
29
|
+
export interface MascotFace {
|
|
30
|
+
/** Stable identifier for the expression (for tests and selection logs). */
|
|
31
|
+
readonly key: string;
|
|
32
|
+
/** The left/right eye glyphs (one display cell each). */
|
|
33
|
+
readonly eyes: readonly [string, string];
|
|
34
|
+
/** The three-cell mouth glyph row. */
|
|
35
|
+
readonly mouth: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The rotating mascot expressions, in selection order.
|
|
39
|
+
*
|
|
40
|
+
* Each is the same rounded saffron head with dark eyes and a teal mouth — the
|
|
41
|
+
* expression is the only thing that changes session to session.
|
|
42
|
+
*/
|
|
43
|
+
export declare const MASCOTS: readonly MascotFace[];
|
|
44
|
+
/** A drawn cell's colour intent, mapped to a theme role by the banner. */
|
|
45
|
+
export type MascotTone = "head" | "eye" | "mouth" | "feet";
|
|
46
|
+
/** One painted span of a mascot row: literal text plus its colour intent. */
|
|
47
|
+
export interface MascotSegment {
|
|
48
|
+
/** The literal glyphs to draw. */
|
|
49
|
+
readonly text: string;
|
|
50
|
+
/** Which colour role the banner paints this span in. */
|
|
51
|
+
readonly tone: MascotTone;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Lay a {@link MascotFace} out into its drawable rows.
|
|
55
|
+
*
|
|
56
|
+
* Returns one array of {@link MascotSegment}s per terminal row of the mascot — a
|
|
57
|
+
* five-row rounded head (top, eyes, mouth, base, feet). The head outline is the
|
|
58
|
+
* `head` tone, the eyes the `eye` tone, the mouth the `mouth` tone, and the feet
|
|
59
|
+
* the `feet` tone; the banner resolves each tone to a concrete colour. Every row
|
|
60
|
+
* is the same nine-cell width (the feet row is centred under it), so the column
|
|
61
|
+
* stays rectangular whichever expression is chosen.
|
|
62
|
+
*
|
|
63
|
+
* @param face the expression to lay out
|
|
64
|
+
*/
|
|
65
|
+
export declare function mascotRows(face: MascotFace): readonly (readonly MascotSegment[])[];
|
|
66
|
+
/**
|
|
67
|
+
* The rotating "Tips for getting started" lines.
|
|
68
|
+
*
|
|
69
|
+
* One is shown per session (chosen by {@link pickWelcomeVariant}); the pool is
|
|
70
|
+
* ordinary onboarding guidance so a returning user sees a different nudge each
|
|
71
|
+
* launch rather than the same line forever.
|
|
72
|
+
*/
|
|
73
|
+
export declare const TIPS: readonly string[];
|
|
74
|
+
/**
|
|
75
|
+
* The static "What's new" notes shown in the card's right column.
|
|
76
|
+
*
|
|
77
|
+
* These are stable per release (the banner can override them from a live
|
|
78
|
+
* changelog); they describe the most recent user-facing changes.
|
|
79
|
+
*/
|
|
80
|
+
export declare const WHATS_NEW: readonly string[];
|
|
81
|
+
/** The chosen per-session presentation: one mascot face and one tip line. */
|
|
82
|
+
export interface WelcomeVariant {
|
|
83
|
+
/** The mascot expression to draw this session. */
|
|
84
|
+
readonly mascot: MascotFace;
|
|
85
|
+
/** The "getting started" tip to show this session. */
|
|
86
|
+
readonly tip: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Pick the welcome card's mascot + tip for a session seed.
|
|
90
|
+
*
|
|
91
|
+
* Pure and total: the same seed always yields the same variant, and any integer
|
|
92
|
+
* (including a negative one) lands on a valid mascot and tip. The mascot and the
|
|
93
|
+
* tip are advanced by different strides of the seed so they do not move in
|
|
94
|
+
* lock-step — two nearby seeds vary both independently.
|
|
95
|
+
*
|
|
96
|
+
* @param seed the per-session seed (e.g. from {@link randomWelcomeSeed})
|
|
97
|
+
*/
|
|
98
|
+
export declare function pickWelcomeVariant(seed: number): WelcomeVariant;
|
|
99
|
+
/**
|
|
100
|
+
* The PINNED welcome-card variant seed. The card no longer rotates per session
|
|
101
|
+
* (one stable brand look): seeded with this, {@link pickWelcomeVariant} always
|
|
102
|
+
* resolves to the clean "focus" mascot (`MASCOTS[0]` — `● ●` eyes, flat `───`
|
|
103
|
+
* mouth) + the Shift+Tab tip (`TIPS[2]`). (`12 % MASCOTS.length === 0` → focus;
|
|
104
|
+
* `Math.trunc(12 / MASCOTS.length) % TIPS.length === 2` → the Shift+Tab tip.) Swap
|
|
105
|
+
* the mount back to {@link randomWelcomeSeed} to restore per-session rotation.
|
|
106
|
+
*/
|
|
107
|
+
export declare const PINNED_WELCOME_SEED = 12;
|
|
108
|
+
/**
|
|
109
|
+
* Mint a fresh seed for the current session.
|
|
110
|
+
*
|
|
111
|
+
* Impure by design (it reads the RNG), so the live surface calls it *once* at
|
|
112
|
+
* mount and threads the result into the otherwise-pure banner. Tests never call
|
|
113
|
+
* this — they pass a fixed seed to {@link pickWelcomeVariant} instead.
|
|
114
|
+
*/
|
|
115
|
+
export declare function randomWelcomeSeed(): number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Welcome-card content & variation — pure behavioural tests.
|
|
3
|
+
*
|
|
4
|
+
* These exercise the render-agnostic data behind the saffron welcome card
|
|
5
|
+
* without mounting Ink: the per-session variant selection (deterministic,
|
|
6
|
+
* total, independent strides) and the mascot geometry (rectangular, tone-tagged,
|
|
7
|
+
* expression-driven).
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -60,13 +60,15 @@ export type { SessionConductor, SessionSignal, ConductorState };
|
|
|
60
60
|
*
|
|
61
61
|
* Named for the time-of-day they evoke rather than a bare light/dark axis, with
|
|
62
62
|
* a daltonized (color-blind-friendly) variant of each:
|
|
63
|
+
* - `saffron` — the IndusCode brand scheme: a warm saffron-on-cream dark
|
|
64
|
+
* terminal look with a cool teal accent. The shipped default.
|
|
63
65
|
* - `midnight` — a low-luminance scheme for dark terminals.
|
|
64
66
|
* - `daylight` — a high-luminance scheme for light terminals.
|
|
65
67
|
* - `midnight-cb` — the dark scheme re-derived so success vs failure separates
|
|
66
68
|
* off the red-green axis (success → blue), deuteran/protan-safe.
|
|
67
69
|
* - `daylight-cb` — the light scheme's color-blind-safe counterpart.
|
|
68
70
|
*/
|
|
69
|
-
export type ThemeScheme = "midnight" | "daylight" | "midnight-cb" | "daylight-cb";
|
|
71
|
+
export type ThemeScheme = "saffron" | "midnight" | "daylight" | "midnight-cb" | "daylight-cb";
|
|
70
72
|
/** The default scheme applied before any user preference is loaded. */
|
|
71
73
|
export declare const DEFAULT_SCHEME: ThemeScheme;
|
|
72
74
|
/**
|
|
@@ -357,6 +359,12 @@ export type ConsoleEvent = {
|
|
|
357
359
|
} | {
|
|
358
360
|
readonly type: "buffer:insert";
|
|
359
361
|
readonly text: string;
|
|
362
|
+
}
|
|
363
|
+
/** Swap the first occurrence of `find` for `replaceWith` (paste-marker growth). */
|
|
364
|
+
| {
|
|
365
|
+
readonly type: "buffer:replaceSpan";
|
|
366
|
+
readonly find: string;
|
|
367
|
+
readonly replaceWith: string;
|
|
360
368
|
} | {
|
|
361
369
|
readonly type: "buffer:erasePrev";
|
|
362
370
|
} | {
|
|
@@ -546,6 +554,13 @@ export interface OverlayServices {
|
|
|
546
554
|
readonly openLoginUrl: (url: string) => Promise<boolean>;
|
|
547
555
|
/** The credential store sign-in / sign-out overlays read and write. */
|
|
548
556
|
readonly vault: AuthVault;
|
|
557
|
+
/**
|
|
558
|
+
* Recompute the server-tier gateway routing map from current vault/token
|
|
559
|
+
* state and push it onto the live conductor, so a sign-in that happens
|
|
560
|
+
* mid-session (the "Indus Server" entry in `/login`) takes effect on the
|
|
561
|
+
* NEXT turn without needing a session restart.
|
|
562
|
+
*/
|
|
563
|
+
readonly refreshGatewayRouting: () => Promise<void>;
|
|
549
564
|
}
|
|
550
565
|
/**
|
|
551
566
|
* What the root `TerminalConsole` surface receives at mount.
|
|
@@ -26,6 +26,9 @@ export { TerminalConsole } from "./components/TerminalConsole";
|
|
|
26
26
|
export { Composer, type ComposerProps } from "./components/Composer";
|
|
27
27
|
export { StatusBar, type StatusBarProps } from "./components/StatusBar";
|
|
28
28
|
export { Banner, type BannerProps } from "./components/Banner";
|
|
29
|
+
export { BackgroundAgents, deriveAgentRuns, type BackgroundAgentsProps, type AgentRun, type AgentRunStatus, } from "./components/BackgroundAgents";
|
|
30
|
+
export { AgentsView, type AgentsViewProps } from "./components/AgentsView";
|
|
31
|
+
export { MASCOTS, TIPS, WHATS_NEW, mascotRows, pickWelcomeVariant, randomWelcomeSeed, type MascotFace, type MascotTone, type MascotSegment, type WelcomeVariant, } from "./components/welcome";
|
|
29
32
|
export { gatherStartup, gatherChangelog } from "./startup";
|
|
30
33
|
export type { StartupMap, StartupSection, StartupChangelog, StartupChangelogMode, StartupNotice, StartupNoticeKind, StartupInputs, } from "./startup";
|
|
31
34
|
export { mountConsole, type MountConsoleOptions, type MountResult, } from "./mount";
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
export type { KeyChord, ConsoleVerb, ConsoleIntent, ChordOutcome, ChordLatch, ChordStep, } from "./keymap";
|
|
19
19
|
export { NO_INTENT, readKey, NO_CHORD, advanceChord } from "./keymap";
|
|
20
20
|
export type { PasteThresholds, PasteVault, PasteCapture, } from "./paste";
|
|
21
|
-
export { PASTE_THRESHOLDS, PASTE_BURST_GAP_MS, EMPTY_PASTE_VAULT, pasteMarker, classifyPaste, coalescePaste, expandMarkers, hasMarkers, } from "./paste";
|
|
21
|
+
export { PASTE_THRESHOLDS, PASTE_BURST_GAP_MS, PASTE_CONTINUATION_MS, PASTE_MARKER_LINE_CAP, EMPTY_PASTE_VAULT, pasteMarker, classifyPaste, coalescePaste, appendToPaste, pasteLines, expandMarkers, hasMarkers, } from "./paste";
|
|
22
22
|
export type { CompletionKind, Suggestion, TokenSpan, CompletionResult, DirEntry, DirReader, } from "./complete";
|
|
23
23
|
export { completeAt, applySuggestion } from "./complete";
|
|
24
24
|
export { createDirReader } from "./dir-reader";
|
|
@@ -82,7 +82,7 @@ export interface KeyChord {
|
|
|
82
82
|
* - `flow:cycleModel` — rotate to the next model.
|
|
83
83
|
*
|
|
84
84
|
* Model / reasoning
|
|
85
|
-
* - `model:cycleThinking` — advance the reasoning-effort ladder one step.
|
|
85
|
+
* - `model:cycleThinking` — advance the reasoning-effort ladder one step (via /thinking command).
|
|
86
86
|
*
|
|
87
87
|
* Permission mode
|
|
88
88
|
* - `mode:cyclePermission` — cycle through ALL permission modes (Shift+Tab),
|
|
@@ -115,7 +115,7 @@ export interface KeyChord {
|
|
|
115
115
|
* Inert
|
|
116
116
|
* - `none` — the keystroke carries no console meaning.
|
|
117
117
|
*/
|
|
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";
|
|
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" | "queue:steer" | "input:pasteImage" | "input:externalEditor" | "overlay:open" | "view:expandTools" | "view:toggleReasoning" | "none";
|
|
119
119
|
/**
|
|
120
120
|
* A classified keystroke: a {@link ConsoleVerb} plus the small payload a verb
|
|
121
121
|
* may carry — the literal text for a `text:type` insert, or the target overlay
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* the whole paste pipeline is unit-tested in isolation. The component owns only
|
|
25
25
|
* the live vault value and the burst-coalescing timer; the decisions are here.
|
|
26
26
|
*
|
|
27
|
-
* The marker format is the console's own:
|
|
28
|
-
* 1-based mint order and `K` is the hidden line count.
|
|
27
|
+
* The marker format is the console's own: `[Pasted text #N +K lines]`, where `N` is the
|
|
28
|
+
* 1-based mint order and `K` is the hidden line count. Matches induscode style:
|
|
29
29
|
* visually distinct in the composer, unambiguous to match, and trivial to strip.
|
|
30
30
|
*/
|
|
31
31
|
/**
|
|
@@ -41,7 +41,14 @@ export interface PasteThresholds {
|
|
|
41
41
|
/** Minimum character count to treat a chunk as a large paste. */
|
|
42
42
|
readonly chars: number;
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* The default cut-offs above which a paste is coalesced into a marker.
|
|
46
|
+
*
|
|
47
|
+
* Matched to the reference agent: a paste of MORE than 10 lines (i.e. ≥10
|
|
48
|
+
* newlines) or more than 1000 characters hides behind a marker; anything
|
|
49
|
+
* smaller — including the common 8-line snippet — splices inline and renders
|
|
50
|
+
* as visible multi-line text in the composer.
|
|
51
|
+
*/
|
|
45
52
|
export declare const PASTE_THRESHOLDS: PasteThresholds;
|
|
46
53
|
/**
|
|
47
54
|
* The maximum gap, in milliseconds, between per-character events still treated
|
|
@@ -53,6 +60,30 @@ export declare const PASTE_THRESHOLDS: PasteThresholds;
|
|
|
53
60
|
* it. Exposed as data so the coalescing timer and any test share one value.
|
|
54
61
|
*/
|
|
55
62
|
export declare const PASTE_BURST_GAP_MS = 24;
|
|
63
|
+
/**
|
|
64
|
+
* How long, after a coalesced flush, a paste stays "active" — a further
|
|
65
|
+
* multi-character chunk landing within this window APPENDS to the active
|
|
66
|
+
* marker instead of minting a new one.
|
|
67
|
+
*
|
|
68
|
+
* Terminals deliver a big paste as a series of ~1KB stdin reads whose gaps can
|
|
69
|
+
* exceed any reasonable per-chunk debounce, so timing alone shreds one paste
|
|
70
|
+
* into many markers (`[Pasted #11][Pasted #12]…`, issue #18's second form).
|
|
71
|
+
* Sized GENEROUSLY: a very long paste (the spec case is 1000 lines) must
|
|
72
|
+
* survive mid-stream read hiccups as ONE marker, and the failure mode of a
|
|
73
|
+
* too-long window is mild — two lightning-fast deliberate pastes merge into
|
|
74
|
+
* one marker whose expansion is still the correct concatenated text — while a
|
|
75
|
+
* too-short window re-creates the shredding this exists to fix. Two human
|
|
76
|
+
* paste chords are >300ms apart in practice; single characters (real typing)
|
|
77
|
+
* never extend the window.
|
|
78
|
+
*/
|
|
79
|
+
export declare const PASTE_CONTINUATION_MS = 250;
|
|
80
|
+
/**
|
|
81
|
+
* Ceiling on the line count a single marker absorbs via continuation. One
|
|
82
|
+
* user paste stays ONE marker up to this many lines; a paste that keeps
|
|
83
|
+
* streaming past it rolls over into a fresh marker ("one more paste") so a
|
|
84
|
+
* runaway multi-megabyte paste can't grow a single unbounded vault body.
|
|
85
|
+
*/
|
|
86
|
+
export declare const PASTE_MARKER_LINE_CAP = 1000;
|
|
56
87
|
/** The console's own placeholder format for a hidden paste body. */
|
|
57
88
|
export declare function pasteMarker(ordinal: number, lineCount: number): string;
|
|
58
89
|
/**
|
|
@@ -69,14 +100,14 @@ export declare function classifyPaste(chunk: string, thresholds?: PasteThreshold
|
|
|
69
100
|
/**
|
|
70
101
|
* The immutable marker → body store.
|
|
71
102
|
*
|
|
72
|
-
* `bodies` maps each
|
|
103
|
+
* `bodies` maps each ordinal number to the exact text it hides; `minted`
|
|
73
104
|
* is the running count that drives the next ordinal. The store is replaced (not
|
|
74
105
|
* mutated) on every coalesce, so the surface holds it as a plain value and React
|
|
75
106
|
* reconciliation stays correct.
|
|
76
107
|
*/
|
|
77
108
|
export interface PasteVault {
|
|
78
|
-
/**
|
|
79
|
-
readonly bodies: ReadonlyMap<
|
|
109
|
+
/** Ordinal number → the original pasted text it stands for. */
|
|
110
|
+
readonly bodies: ReadonlyMap<number, string>;
|
|
80
111
|
/** How many markers have been minted so far (the next ordinal is this + 1). */
|
|
81
112
|
readonly minted: number;
|
|
82
113
|
}
|
|
@@ -106,6 +137,27 @@ export interface PasteCapture {
|
|
|
106
137
|
* @param body the full pasted text to hide
|
|
107
138
|
*/
|
|
108
139
|
export declare function coalescePaste(body: string, vault?: PasteVault): PasteCapture;
|
|
140
|
+
/**
|
|
141
|
+
* Grow an existing paste body with a follow-on chunk, reminting its marker.
|
|
142
|
+
*
|
|
143
|
+
* The continuation path for a paste the terminal split across reads: the extra
|
|
144
|
+
* text is appended to `ordinal`'s stored body and a fresh marker (same ordinal,
|
|
145
|
+
* updated line count) is returned so the surface can swap the token already
|
|
146
|
+
* spliced into the buffer. `minted` is unchanged — no new ordinal is consumed.
|
|
147
|
+
* An unknown ordinal starts from an empty body, so the call never throws.
|
|
148
|
+
*
|
|
149
|
+
* @param ordinal the marker ordinal to grow
|
|
150
|
+
* @param extra the follow-on pasted text to append
|
|
151
|
+
* @param vault the store holding the ordinal's current body
|
|
152
|
+
*/
|
|
153
|
+
export declare function appendToPaste(ordinal: number, extra: string, vault: PasteVault): PasteCapture;
|
|
154
|
+
/**
|
|
155
|
+
* The line count of an ordinal's stored body — the surface consults this
|
|
156
|
+
* against {@link PASTE_MARKER_LINE_CAP} to decide whether a continuation chunk
|
|
157
|
+
* may still append or must roll over into a fresh marker. Zero for an unknown
|
|
158
|
+
* ordinal or an empty body.
|
|
159
|
+
*/
|
|
160
|
+
export declare function pasteLines(vault: PasteVault, ordinal: number): number;
|
|
109
161
|
/**
|
|
110
162
|
* Rewrite every paste marker in a buffer back to the text it stands for.
|
|
111
163
|
*
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* abort/clear settles every outstanding entry with `"deny"` so a cancelled turn
|
|
16
16
|
* never hangs on a pending prompt.
|
|
17
17
|
*/
|
|
18
|
-
import type { ApprovalChoice } from "../../conductor";
|
|
18
|
+
import type { ApprovalChoice, PermissionMode } from "../../conductor";
|
|
19
19
|
import type { ApprovalRequest } from "./approval";
|
|
20
20
|
/** One parked approval request awaiting the user's choice. */
|
|
21
21
|
export interface ApprovalEntry {
|
|
@@ -69,3 +69,20 @@ export declare function approvalQueueReducer(state: ApprovalQueueState, event: A
|
|
|
69
69
|
* @param state the queue state
|
|
70
70
|
*/
|
|
71
71
|
export declare function activeApproval(state: ApprovalQueueState): ApprovalEntry | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Whether switching INTO `mode` mid-prompt should release (auto-allow) every
|
|
74
|
+
* PARKED approval request.
|
|
75
|
+
*
|
|
76
|
+
* Only `bypass` qualifies: a parked entry already passed the deny-rule and
|
|
77
|
+
* catastrophic-blocklist scans before it reached `ask`, and under bypass the
|
|
78
|
+
* engine allows everything not denied — so settling the parked prompts with
|
|
79
|
+
* `allow-once` matches exactly what the mode now means, and the run resumes
|
|
80
|
+
* instead of idling behind a prompt the user just declared moot. Every other
|
|
81
|
+
* mode keeps the prompts parked: `default`/`acceptEdits` still want the answer,
|
|
82
|
+
* and `plan` must not auto-ALLOW a mutating call (the user can still deny).
|
|
83
|
+
*
|
|
84
|
+
* Pure; the component wires it to the actual settle.
|
|
85
|
+
*
|
|
86
|
+
* @param mode the permission mode just switched into
|
|
87
|
+
*/
|
|
88
|
+
export declare function modeReleasesApprovals(mode: PermissionMode): boolean;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saffron picker boards — the themed `/settings` and `/model` overlays styled to
|
|
3
|
+
* the "IndusCode Saffron · Settings · Config" design.
|
|
4
|
+
*
|
|
5
|
+
* The framework ships plain (un-themed) `SettingsDialog` / `ModelDialog`. These
|
|
6
|
+
* boards are the console's own theme-aware replacements for those two pickers: a
|
|
7
|
+
* saffron tab-pill header, a teal-bordered search box with a magnifier and a
|
|
8
|
+
* block caret, a two-column list whose values are tinted by kind (on/true →
|
|
9
|
+
* green, off/false → dim, everything else → teal), a windowed "↓ N more" hint,
|
|
10
|
+
* and a top-ruled footer of key hints. They reuse the framework's pure
|
|
11
|
+
* {@link matchesSearchQuery} / {@link wrapSelectionIndex} helpers (and the
|
|
12
|
+
* {@link SettingsDialogItem} shape) so only the *presentation* is re-authored,
|
|
13
|
+
* not the filter/navigation logic.
|
|
14
|
+
*
|
|
15
|
+
* All colour comes through the framework {@link InkThemeAdapter} the overlay
|
|
16
|
+
* group already holds, so the boards recolour with the active scheme; the one
|
|
17
|
+
* raw-hex touch is the chalk tab-pill (dark text on the accent fill), which has
|
|
18
|
+
* no theme role to resolve against.
|
|
19
|
+
*/
|
|
20
|
+
import { type InkThemeAdapter, type SettingsDialogItem } from "indusagi/react-ink";
|
|
21
|
+
import type { Model } from "indusagi/ai";
|
|
22
|
+
/** What the {@link SettingsBoard} renders. */
|
|
23
|
+
export interface SettingsBoardProps {
|
|
24
|
+
/** The framework adapter that turns token roles into terminal colours. */
|
|
25
|
+
readonly theme: InkThemeAdapter;
|
|
26
|
+
/** The settings rows to present and cycle. */
|
|
27
|
+
readonly items: readonly SettingsDialogItem[];
|
|
28
|
+
/** Invoked when the board is dismissed. */
|
|
29
|
+
readonly onClose: () => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The saffron `/settings` board: a filterable, value-cycling settings list in the
|
|
33
|
+
* design's look. Up/Down move (wrapping), Left/Right or Enter cycle the value,
|
|
34
|
+
* typing filters, Ctrl+U clears, Esc closes.
|
|
35
|
+
*/
|
|
36
|
+
export declare function SettingsBoard({ theme, items, onClose }: SettingsBoardProps): JSX.Element;
|
|
37
|
+
/** What the {@link ModelBoard} renders. */
|
|
38
|
+
export interface ModelBoardProps {
|
|
39
|
+
/** The framework adapter that turns token roles into terminal colours. */
|
|
40
|
+
readonly theme: InkThemeAdapter;
|
|
41
|
+
/** The selectable models. */
|
|
42
|
+
readonly models: readonly Model<any>[];
|
|
43
|
+
/** Optional initial search query. */
|
|
44
|
+
readonly search?: string;
|
|
45
|
+
/** Invoked with the chosen model. */
|
|
46
|
+
readonly onSelect: (model: Model<any>) => void | Promise<void>;
|
|
47
|
+
/** Invoked when the board is dismissed. */
|
|
48
|
+
readonly onClose: () => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The saffron `/model` board: a filterable model list in the design's look.
|
|
52
|
+
* Up/Down move (wrapping), Enter selects, typing filters, Ctrl+U clears, Esc
|
|
53
|
+
* closes.
|
|
54
|
+
*/
|
|
55
|
+
export declare function ModelBoard({ theme, models, onClose, onSelect, search }: ModelBoardProps): JSX.Element;
|
|
@@ -12,4 +12,4 @@ export { PickerOverlays, type OverlayGroupProps } from "./pickers";
|
|
|
12
12
|
export { SessionOverlays } from "./sessions";
|
|
13
13
|
export { AuthOverlays } from "./auth";
|
|
14
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";
|
|
15
|
+
export { approvalQueueReducer, activeApproval, modeReleasesApprovals, EMPTY_APPROVAL_QUEUE, type ApprovalEntry, type ApprovalQueueState, type ApprovalQueueEvent, } from "./approval-queue";
|
|
@@ -34,7 +34,7 @@ import type { InkThemeAdapter, ThemeTokens } from "../contract";
|
|
|
34
34
|
* accent ← signal (primary accent the components highlight in)
|
|
35
35
|
* borderMuted ← quietFrame (de-emphasised borders/separators)
|
|
36
36
|
* bashBorder ← frame (the bash-block border tone)
|
|
37
|
-
* userMessage ←
|
|
37
|
+
* userMessage ← "" (no background, plain text)
|
|
38
38
|
* customMessage ← cardAccent (custom/plugin message background tint)
|
|
39
39
|
* success ← affirm
|
|
40
40
|
* warning ← caution
|
|
@@ -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, MIDNIGHT_CB_PALETTE, DAYLIGHT_CB_PALETTE, PALETTES, } from "./palette";
|
|
15
|
+
export { SAFFRON_PALETTE, 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,16 @@ 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 "IndusCode Saffron" dark-terminal ramp — the brand scheme.
|
|
38
|
+
*
|
|
39
|
+
* The console's signature look: a warm saffron primary (borders, headings, the
|
|
40
|
+
* brand wordmark) against a cream neutral gradient, with a cool teal secondary
|
|
41
|
+
* for the interactive accents (the prompt caret, chips, bullets) — the two hues
|
|
42
|
+
* the IndusCode masthead is built from. The status hues stay warm-leaning so the
|
|
43
|
+
* whole scheme reads as one saffron identity rather than a recoloured midnight.
|
|
44
|
+
*/
|
|
45
|
+
export declare const SAFFRON_PALETTE: ThemePalette;
|
|
36
46
|
/**
|
|
37
47
|
* The dark-terminal color-blind-safe ramp.
|
|
38
48
|
*
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login command — `runLogin`.
|
|
3
|
+
*
|
|
4
|
+
* The top-level `login` / `logout` / `whoami` surface that authenticates the CLI
|
|
5
|
+
* against the indus-server so a user with **no local provider key** can still run
|
|
6
|
+
* model turns through the server gateway (the session token is vended as the
|
|
7
|
+
* provider key downstream — see `src/boot/runners/server-mode.ts`).
|
|
8
|
+
*
|
|
9
|
+
* `login` drives the OAuth 2.0 **device-authorization** flow (RFC 8628) against
|
|
10
|
+
* the server's better-auth endpoints under `${INDUS_SERVER_URL}/api/auth`:
|
|
11
|
+
*
|
|
12
|
+
* 1. POST `/api/auth/device/code` → a `user_code` + verification URL.
|
|
13
|
+
* 2. The user opens the URL in a browser and approves the device.
|
|
14
|
+
* 3. We poll POST `/api/auth/device/token` until it returns an `access_token`.
|
|
15
|
+
* 4. The token is persisted via {@link storeServerToken} (A1's token store).
|
|
16
|
+
*
|
|
17
|
+
* This is a **pre-pipeline router**, not a runner: a no-key user cannot build a
|
|
18
|
+
* session, so login must short-circuit before the stage pipeline. {@link runLogin}
|
|
19
|
+
* therefore mirrors `runCredential` in `boot.ts` — it owns the first positional
|
|
20
|
+
* token only and returns `undefined` (fall through to a normal launch) when that
|
|
21
|
+
* token is not one of its verbs.
|
|
22
|
+
*
|
|
23
|
+
* The app does not depend on `better-auth/client`, `open`, or a spinner library,
|
|
24
|
+
* so the device flow is implemented over raw `fetch` and the console is driven
|
|
25
|
+
* with `chalk` to match the rest of the launch surface. `--server-url` and
|
|
26
|
+
* `--client-id` are parsed from the argv tail here (the declarative flag table is
|
|
27
|
+
* for the launch invocation, not these auth-only verbs).
|
|
28
|
+
*/
|
|
29
|
+
import type { OAuthLoginCallbacks } from "indusagi/ai";
|
|
30
|
+
import type { BootContext } from "../boot/contract";
|
|
31
|
+
/**
|
|
32
|
+
* The sign-in directory id for the indus-server session (as opposed to a
|
|
33
|
+
* per-model-provider credential). Used by `src/launch/oauth.ts` to special-case
|
|
34
|
+
* this entry in `listLoginProviders` / `startOAuthLogin` so the interactive
|
|
35
|
+
* `/login` picker can drive the same device-authorization flow as the `indus
|
|
36
|
+
* login` CLI verb.
|
|
37
|
+
*/
|
|
38
|
+
export declare const SERVER_TIER_PROVIDER_ID = "indus-server";
|
|
39
|
+
/**
|
|
40
|
+
* Drive the indus-server device-authorization flow through the framework's
|
|
41
|
+
* generic {@link OAuthLoginCallbacks} shape, so the interactive `/login` picker
|
|
42
|
+
* (`src/console/overlays/auth.tsx`'s `OAuthFlowDialog`) can establish a
|
|
43
|
+
* server-tier session the same way the `indus login` CLI verb does.
|
|
44
|
+
*
|
|
45
|
+
* Reuses the private {@link requestDeviceCode} / {@link pollForToken} helpers
|
|
46
|
+
* above rather than duplicating the request+poll sequence, and reports the
|
|
47
|
+
* verification URL / code through `callbacks.onAuth` exactly once, mirroring
|
|
48
|
+
* how `doLogin` renders them to the console. On success the token is persisted
|
|
49
|
+
* via {@link storeServerToken}; any thrown error (network failure, denial,
|
|
50
|
+
* expiry, timeout) propagates to the caller unchanged — `startOAuthLogin`'s
|
|
51
|
+
* caller (the dialog's try/catch) already renders a generic failure state.
|
|
52
|
+
*
|
|
53
|
+
* @param callbacks the framework's OAuth login callbacks (url + progress)
|
|
54
|
+
* @param serverUrl the indus-server base url (defaults to {@link INDUS_SERVER_URL})
|
|
55
|
+
* @param clientId the device-flow client id (defaults to {@link INDUS_CLIENT_ID})
|
|
56
|
+
*/
|
|
57
|
+
export declare function runServerTierLogin(callbacks: OAuthLoginCallbacks, serverUrl?: string, clientId?: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Route a `login` / `logout` / `whoami` verb, if this invocation is one.
|
|
60
|
+
*
|
|
61
|
+
* Inspects `ctx.argv[0]`: returns a numeric exit code when it handled one of the
|
|
62
|
+
* auth verbs, or `undefined` when the leading token is something else so the
|
|
63
|
+
* caller falls through to a normal launch. Modeled on `runCredential` in
|
|
64
|
+
* `boot.ts`; `--server-url` / `--client-id` are parsed from the argv tail.
|
|
65
|
+
*
|
|
66
|
+
* @param ctx the seeded boot context (carries the raw argv)
|
|
67
|
+
*/
|
|
68
|
+
export declare function runLogin(ctx: BootContext): Promise<number | undefined>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `src/launch/oauth.ts` — unit tests for the indus-server bridge added to the
|
|
3
|
+
* merged sign-in directory and `startOAuthLogin`.
|
|
4
|
+
*
|
|
5
|
+
* Covers:
|
|
6
|
+
* 1. {@link listLoginProviders} includes the `indus-server` entry
|
|
7
|
+
* (`SERVER_TIER_PROVIDER_ID`, `authKind: "oauth"`).
|
|
8
|
+
* 2. {@link startOAuthLogin} for `SERVER_TIER_PROVIDER_ID` drives the device
|
|
9
|
+
* flow over a mocked `fetch`, reports `onAuth` exactly once with the right
|
|
10
|
+
* shape, reports progress, never touches the vault, and resolves.
|
|
11
|
+
* 3. {@link startOAuthLogin} for an unregistered id still throws the
|
|
12
|
+
* pre-existing "No browser sign-in is available" error (regression check).
|
|
13
|
+
* 4. A device/token failure (`access_denied`) propagates out of
|
|
14
|
+
* `startOAuthLogin` unchanged rather than being swallowed.
|
|
15
|
+
*
|
|
16
|
+
* `storeServerToken` is mocked (partial mock of `../boot/server-token`) so the
|
|
17
|
+
* success-path test never touches the real `~/.indusagi/agent/server-token.json`
|
|
18
|
+
* file on the machine running the suite.
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
|
@@ -38,6 +38,12 @@ export interface SummarizeDeps {
|
|
|
38
38
|
readonly priorDigest?: string;
|
|
39
39
|
/** Cancellation signal forwarded to the completer. */
|
|
40
40
|
readonly signal?: AbortSignal;
|
|
41
|
+
/**
|
|
42
|
+
* Credential for the summarization model's provider, forwarded to the
|
|
43
|
+
* completer. Required in practice for sessions whose key is resolved
|
|
44
|
+
* per-call (server tier) rather than from an environment variable.
|
|
45
|
+
*/
|
|
46
|
+
readonly apiKey?: string;
|
|
41
47
|
/**
|
|
42
48
|
* Optional cap on the digest size, in tokens, forwarded to the completer's
|
|
43
49
|
* `maxTokens`. A modest ceiling keeps the summary itself from eating the
|