@corenel/term 0.1.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/README.md +44 -0
- package/dist/chunk-47IH6X5H.js +20 -0
- package/dist/chunk-HAQGHLW6.js +235 -0
- package/dist/chunk-HYWLODZT.js +1230 -0
- package/dist/chunk-R6AXTD55.js +47 -0
- package/dist/chunk-TCVDVYMF.js +40 -0
- package/dist/commands.d.ts +25 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +10 -0
- package/dist/describe.d.ts +25 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +14 -0
- package/dist/ink/App.d.ts +30 -0
- package/dist/ink/App.d.ts.map +1 -0
- package/dist/ink/Modal.d.ts +6 -0
- package/dist/ink/Modal.d.ts.map +1 -0
- package/dist/ink/Palette.d.ts +7 -0
- package/dist/ink/Palette.d.ts.map +1 -0
- package/dist/ink/index.d.ts +18 -0
- package/dist/ink/index.d.ts.map +1 -0
- package/dist/ink/index.js +573 -0
- package/dist/ink/items.d.ts +12 -0
- package/dist/ink/items.d.ts.map +1 -0
- package/dist/ink/scroll.d.ts +17 -0
- package/dist/ink/scroll.d.ts.map +1 -0
- package/dist/ink/status.d.ts +21 -0
- package/dist/ink/status.d.ts.map +1 -0
- package/dist/ink/theme.d.ts +22 -0
- package/dist/ink/theme.d.ts.map +1 -0
- package/dist/markdown.d.ts +33 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/persist.d.ts +30 -0
- package/dist/persist.d.ts.map +1 -0
- package/dist/persist.js +10 -0
- package/dist/session.d.ts +153 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +12 -0
- package/dist/state.d.ts +75 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +6 -0
- package/package.json +63 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type MdBlock = {
|
|
2
|
+
kind: 'h';
|
|
3
|
+
level: number;
|
|
4
|
+
text: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'p';
|
|
7
|
+
text: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'li';
|
|
10
|
+
text: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'code';
|
|
13
|
+
lang: string;
|
|
14
|
+
text: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'blank';
|
|
17
|
+
text: '';
|
|
18
|
+
};
|
|
19
|
+
export declare function parseMarkdown(text: string): MdBlock[];
|
|
20
|
+
/** One block, paired with the exact raw source text (original line endings
|
|
21
|
+
* normalized to '\n', markup un-stripped) that produced it. Concatenating
|
|
22
|
+
* every span's `raw` in order, joined by '\n', reproduces `text` exactly
|
|
23
|
+
* (mod CRLF normalization) — this is what lets the TUI commit a block as it
|
|
24
|
+
* completes and still guarantee the user sees the reply exactly once. */
|
|
25
|
+
export interface MdBlockSpan {
|
|
26
|
+
block: MdBlock;
|
|
27
|
+
raw: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function parseMarkdownSpans(text: string): MdBlockSpan[];
|
|
30
|
+
/** Drop inline markup a terminal cannot show. Emphasis must have no space next
|
|
31
|
+
* to its markers, or `2 * 3` loses its asterisk. */
|
|
32
|
+
export declare function stripInline(s: string): string;
|
|
33
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AAOhC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAErD;AAED;;;;yEAIyE;AACzE,MAAM,WAAW,WAAW;IAAG,KAAK,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAE5D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAsC9D;AAED;oDACoD;AACpD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM7C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AgentSession, FileService } from '@corenel/protocol';
|
|
2
|
+
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
3
|
+
import type { CommittedItem } from './state';
|
|
4
|
+
export interface SaveInput {
|
|
5
|
+
id: string | null;
|
|
6
|
+
title: string;
|
|
7
|
+
messages: ChatCompletionMessageParam[];
|
|
8
|
+
}
|
|
9
|
+
export interface LoadedSession {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
messages: ChatCompletionMessageParam[];
|
|
13
|
+
}
|
|
14
|
+
export interface SessionPersistence {
|
|
15
|
+
save(input: SaveInput): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
}>;
|
|
18
|
+
load(id?: string): Promise<LoadedSession | null>;
|
|
19
|
+
list(): Promise<AgentSession[]>;
|
|
20
|
+
}
|
|
21
|
+
export declare function createSessionPersistence(files: FileService): SessionPersistence;
|
|
22
|
+
/** The display transcript for a restored conversation.
|
|
23
|
+
*
|
|
24
|
+
* User and assistant TEXT only, deliberately: an identity mapping keeps the
|
|
25
|
+
* restored transcript lined up with the history the next turn sends, which is
|
|
26
|
+
* the trap a richer rebuild walks into. */
|
|
27
|
+
export declare function committedFromMessages(messages: ChatCompletionMessageParam[]): CommittedItem[];
|
|
28
|
+
/** The first line of the first user message, as a session title. */
|
|
29
|
+
export declare function titleFrom(messages: ChatCompletionMessageParam[]): string;
|
|
30
|
+
//# sourceMappingURL=persist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AACpF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,0BAA0B,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,0BAA0B,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACjD,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACjC;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB,CA4B/E;AAED;;;;2CAI2C;AAC3C,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,0BAA0B,EAAE,GAAG,aAAa,EAAE,CAW7F;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,0BAA0B,EAAE,GAAG,MAAM,CAKxE"}
|
package/dist/persist.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
2
|
+
import type OpenAI from 'openai';
|
|
3
|
+
import type { AgentEvent, AgentTool, AskAnswers, AskQuestion, PermissionDecision, ToolContext } from '@corenel/protocol';
|
|
4
|
+
import { type RunAgentArgs, type RunAgentResult } from '@corenel/harness/core/loop';
|
|
5
|
+
import type { PermissionService } from '@corenel/harness/guardrail/permission-service';
|
|
6
|
+
import { type CommittedItem, type TuiState } from './state';
|
|
7
|
+
import { type SessionPersistence } from './persist';
|
|
8
|
+
export interface TermSessionDeps {
|
|
9
|
+
cwd: string;
|
|
10
|
+
model: string;
|
|
11
|
+
system?: string;
|
|
12
|
+
client: OpenAI;
|
|
13
|
+
tools: AgentTool[];
|
|
14
|
+
/** Built per turn so each turn gets its own signal, and so `ask` reaches the
|
|
15
|
+
* tool context — which is how ask_user finally works in node. */
|
|
16
|
+
toolCtx: (signal: AbortSignal, ask: (q: AskQuestion[]) => Promise<AskAnswers | null>) => ToolContext;
|
|
17
|
+
/** Skip the per-command approval prompt (`--allow-shell`). */
|
|
18
|
+
approveAll?: boolean;
|
|
19
|
+
/** Injected so tests can drive a turn without a model. Defaults to runAgent. */
|
|
20
|
+
runner?: (args: RunAgentArgs) => Promise<RunAgentResult>;
|
|
21
|
+
/** Raw event tap for a face that renders the turn as it happens (the readline
|
|
22
|
+
* face streams from this; the Ink face renders state instead). Called before
|
|
23
|
+
* the event is reduced. */
|
|
24
|
+
onEvent?: (e: AgentEvent) => void;
|
|
25
|
+
/** Conversation persistence. Omit and the session is not written to disk. */
|
|
26
|
+
persistence?: SessionPersistence;
|
|
27
|
+
/** Read back a tool result that was offloaded to save context. */
|
|
28
|
+
recall?: (id: string) => Promise<string | null>;
|
|
29
|
+
}
|
|
30
|
+
/** Deltas arrive per token; re-rendering React that often thrashes for output
|
|
31
|
+
* no eye can follow. They coalesce on this interval instead. */
|
|
32
|
+
export declare const DELTA_FLUSH_MS = 50;
|
|
33
|
+
export declare class TermSession {
|
|
34
|
+
protected readonly deps: TermSessionDeps;
|
|
35
|
+
protected state: TuiState;
|
|
36
|
+
private listeners;
|
|
37
|
+
private nextOrd;
|
|
38
|
+
private idSeq;
|
|
39
|
+
private pendingDelta;
|
|
40
|
+
private flushTimer;
|
|
41
|
+
private streamFull;
|
|
42
|
+
/** How many leading blocks of `streamFull` have already been committed.
|
|
43
|
+
* Only the block at this index (the last one seen so far) is still live. */
|
|
44
|
+
private streamCommittedBlocks;
|
|
45
|
+
private pendingOffload;
|
|
46
|
+
/** The model's truth, as opposed to `committed`, which is display. */
|
|
47
|
+
private history;
|
|
48
|
+
private turnAc;
|
|
49
|
+
/** Monotonic turn id. Events stamped with an older one are dropped: a late
|
|
50
|
+
* delta from an aborted turn must never paint into the next one. */
|
|
51
|
+
private turnId;
|
|
52
|
+
private activeTurn;
|
|
53
|
+
private pending;
|
|
54
|
+
private draining;
|
|
55
|
+
private historyGen;
|
|
56
|
+
private settling;
|
|
57
|
+
/** The approval gate. Supplied by whichever face can show a prompt (readline's
|
|
58
|
+
* `ask`, the Ink modal, ...) — the controller has no rendering of its own, so
|
|
59
|
+
* it cannot build one itself. Unattached, `runTurn` simply omits `permission`
|
|
60
|
+
* from the runner args, and the loop runs every tool ungated. */
|
|
61
|
+
private permission;
|
|
62
|
+
wantsExit: boolean;
|
|
63
|
+
constructor(deps: TermSessionDeps);
|
|
64
|
+
attachPermission(p: PermissionService): void;
|
|
65
|
+
historyForTest(): ChatCompletionMessageParam[];
|
|
66
|
+
getSnapshot(): TuiState;
|
|
67
|
+
subscribe(fn: () => void): () => void;
|
|
68
|
+
/** Replace state and notify. Every mutation goes through here so `seq` and the
|
|
69
|
+
* snapshot identity can never drift from the data. */
|
|
70
|
+
protected set(patch: Partial<TuiState>): void;
|
|
71
|
+
protected id(prefix: string): string;
|
|
72
|
+
protected commit(item: CommittedItem): void;
|
|
73
|
+
protected note(level: 'info' | 'warn' | 'error', text: string, detail?: string): void;
|
|
74
|
+
/** Open a live turn. Public-for-test until Task 4 gives it a real caller. */
|
|
75
|
+
beginTurnForTest(): void;
|
|
76
|
+
flushDeltasForTest(): void;
|
|
77
|
+
protected beginTurn(): void;
|
|
78
|
+
/** Commit every markdown block in `streamFull` that can no longer change --
|
|
79
|
+
* i.e. every block except the last, which more text can still extend --
|
|
80
|
+
* and return the still-live trailing block's raw text. This is what keeps
|
|
81
|
+
* the live region Ink redraws every frame bounded by one block instead of
|
|
82
|
+
* the whole reply: see the module comment for why an unbounded live region
|
|
83
|
+
* corrupts the frame once it scrolls out of the viewport.
|
|
84
|
+
*
|
|
85
|
+
* KNOWN LIMIT: any single block taller than the terminal -- not just a
|
|
86
|
+
* fenced code block, but equally one long unbroken paragraph, or any other
|
|
87
|
+
* span with no internal blank-line break -- stays "the trailing block", and
|
|
88
|
+
* so stays live and unbounded, until it closes (or the blank line that ends
|
|
89
|
+
* it arrives). That bounds the live region by one block rather than by the
|
|
90
|
+
* viewport, which the headless controller has no way to know. It is still
|
|
91
|
+
* a large improvement over the whole reply staying live, and a single block
|
|
92
|
+
* taller than the terminal is rare. */
|
|
93
|
+
private commitCompletedBlocks;
|
|
94
|
+
private flushDeltas;
|
|
95
|
+
private scheduleFlush;
|
|
96
|
+
/** Commit whatever the live region still holds -- the trailing block that
|
|
97
|
+
* flushDeltas kept live, since every block before it is already committed
|
|
98
|
+
* -- and close the turn. */
|
|
99
|
+
protected endTurn(): void;
|
|
100
|
+
handleEvent(e: AgentEvent): void;
|
|
101
|
+
/** Route one line: a command runs here; anything else is a turn. */
|
|
102
|
+
submit(text: string): Promise<void>;
|
|
103
|
+
private runCommand;
|
|
104
|
+
/** Save after the turn, never during: a half-written turn is a lie on disk. */
|
|
105
|
+
private persist;
|
|
106
|
+
/** Reopen a conversation: `id` if given, otherwise the most recent. */
|
|
107
|
+
resume(id?: string): Promise<void>;
|
|
108
|
+
/** Re-print a committed tool row in full, as a NEW block at the bottom.
|
|
109
|
+
* Inline rendering owns this trade: the original row's bytes belong to the
|
|
110
|
+
* terminal's scrollback and cannot be rewritten in place. */
|
|
111
|
+
protected expand(ord: number): Promise<void>;
|
|
112
|
+
/** The full body of a committed row. `committed` only ever keeps the capped
|
|
113
|
+
* `preview`, and a second copy would be redundant AND wrong: `history`
|
|
114
|
+
* already carries the exact string the model saw for this call (the full
|
|
115
|
+
* body when it wasn't offloaded, the short offload ref when it was — see
|
|
116
|
+
* @corenel/harness core/loop.ts's `messages.push({ role: 'tool', ... })`),
|
|
117
|
+
* and `history` is cleared by `/clear`, so a stale row can't outlive the
|
|
118
|
+
* conversation it belongs to the way a side map would. Task 8 adds the (a)
|
|
119
|
+
* branch below: reading an offloaded body back out of the blob store by
|
|
120
|
+
* `row.offloadRefId` — the seam, not the wiring: the CLI does not pass
|
|
121
|
+
* `deps.recall` (context compression in node is a separate feature), so
|
|
122
|
+
* this branch is currently always skipped in practice. */
|
|
123
|
+
protected fullResult(_id: string, row: Extract<CommittedItem, {
|
|
124
|
+
kind: 'tool';
|
|
125
|
+
}>): Promise<string>;
|
|
126
|
+
private runTurn;
|
|
127
|
+
/** Close out a turn that produced nothing usable -- aborted, or failed.
|
|
128
|
+
* Drops the abandoned user message: a user message with no reply, or a tool
|
|
129
|
+
* call with no result, poisons the next request. Exactly once, and never when
|
|
130
|
+
* the conversation was replaced under it (`/clear`, `/resume`), where the
|
|
131
|
+
* message it would drop belongs to someone else's history. */
|
|
132
|
+
private finishAbandoned;
|
|
133
|
+
private drain;
|
|
134
|
+
/** Stop the TURN, never the process. A long tool call you regret is the common
|
|
135
|
+
* case, and killing the shell to escape it loses the conversation. */
|
|
136
|
+
abort(): void;
|
|
137
|
+
askPermission(req: {
|
|
138
|
+
tool: string;
|
|
139
|
+
input: unknown;
|
|
140
|
+
}): Promise<PermissionDecision>;
|
|
141
|
+
askUser(questions: AskQuestion[]): Promise<AskAnswers | null>;
|
|
142
|
+
/** The view's answer to whichever modal is open. */
|
|
143
|
+
answer(value: PermissionDecision | AskAnswers | null): void;
|
|
144
|
+
/** Force-close whatever modal is open, on turn teardown or `abort()`. The
|
|
145
|
+
* sentinel must match the modal's OWN contract, not a shared default:
|
|
146
|
+
* `askPermission` promises `PermissionDecision`, where `'deny'` is a real
|
|
147
|
+
* value; `askUser` promises `AskAnswers | null`, and `'deny'` there would be
|
|
148
|
+
* a bogus truthy string standing in for the documented "dismissed" (`null`)
|
|
149
|
+
* outcome that `askUserTool` (packages/harness/tools/builtins.ts) checks for. */
|
|
150
|
+
private forceClosePending;
|
|
151
|
+
private resolvePending;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/session.js
ADDED
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { AskQuestion, Usage } from '@corenel/protocol';
|
|
2
|
+
/** An item that can no longer change. Rendered ONCE, then owned by the terminal. */
|
|
3
|
+
export type CommittedItem = {
|
|
4
|
+
kind: 'user';
|
|
5
|
+
id: string;
|
|
6
|
+
text: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'assistant';
|
|
9
|
+
id: string;
|
|
10
|
+
text: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'tool';
|
|
13
|
+
id: string;
|
|
14
|
+
callId: string;
|
|
15
|
+
ord: number;
|
|
16
|
+
name: string;
|
|
17
|
+
subject: string;
|
|
18
|
+
preview: string[];
|
|
19
|
+
isError: boolean;
|
|
20
|
+
durationMs?: number;
|
|
21
|
+
offloadedBytes?: number;
|
|
22
|
+
offloadRefId?: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'note';
|
|
25
|
+
id: string;
|
|
26
|
+
level: 'info' | 'warn' | 'error';
|
|
27
|
+
text: string;
|
|
28
|
+
detail?: string;
|
|
29
|
+
};
|
|
30
|
+
/** A tool call announced but not yet resolved. */
|
|
31
|
+
export interface LiveTool {
|
|
32
|
+
callId: string;
|
|
33
|
+
ord: number;
|
|
34
|
+
name: string;
|
|
35
|
+
subject: string;
|
|
36
|
+
}
|
|
37
|
+
export interface PermissionAsk {
|
|
38
|
+
kind: 'permission';
|
|
39
|
+
tool: string;
|
|
40
|
+
/** The command or path being approved — never just the tool name. */
|
|
41
|
+
detail: string;
|
|
42
|
+
}
|
|
43
|
+
export interface UserAsk {
|
|
44
|
+
kind: 'user';
|
|
45
|
+
questions: AskQuestion[];
|
|
46
|
+
}
|
|
47
|
+
export type Modal = PermissionAsk | UserAsk;
|
|
48
|
+
export interface TuiState {
|
|
49
|
+
/** Bumped on every change so subscribers using useSyncExternalStore refresh. */
|
|
50
|
+
seq: number;
|
|
51
|
+
transcriptGen: number;
|
|
52
|
+
committed: CommittedItem[];
|
|
53
|
+
live: {
|
|
54
|
+
streaming: string;
|
|
55
|
+
tools: LiveTool[];
|
|
56
|
+
turn: number;
|
|
57
|
+
} | null;
|
|
58
|
+
queued: string[];
|
|
59
|
+
modal: Modal | null;
|
|
60
|
+
usage: Usage;
|
|
61
|
+
/** Usage for the CURRENT exchange only -- everything since the user pressed
|
|
62
|
+
* Enter, including every tool round-trip. Reset when a turn begins;
|
|
63
|
+
* accumulated (alongside `usage`) on every `usage` event, because the loop
|
|
64
|
+
* emits one such event per model call and a single submission can span
|
|
65
|
+
* several (a round of tool calls means another call back to the model). */
|
|
66
|
+
turnUsage: Usage;
|
|
67
|
+
session: {
|
|
68
|
+
id: string;
|
|
69
|
+
title: string;
|
|
70
|
+
} | null;
|
|
71
|
+
status: 'idle' | 'running' | 'aborting';
|
|
72
|
+
error: string | null;
|
|
73
|
+
}
|
|
74
|
+
export declare function emptyState(): TuiState;
|
|
75
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE5D,oFAAoF;AACpF,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IACrF,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5G;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,WAAW,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,KAAK,GAAG,aAAa,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,QAAQ;IACvB,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IASZ,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,KAAK,CAAC;IACb;;;;+EAI2E;IAC3E,SAAS,EAAE,KAAK,CAAC;IACjB,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,UAAU,IAAI,QAAQ,CAcrC"}
|
package/dist/state.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@corenel/term",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Corenel's terminal face — a headless chat controller plus its Ink views. `./session` is ink-free and shared with the CLI's readline fallback; only `./ink` pulls React. dist/ is bundled (see build.mjs), so @corenel/harness and @corenel/protocol are inlined at build time and are NOT runtime dependencies; they are needed only to consume the published .d.ts.",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./session": {
|
|
8
|
+
"types": "./dist/session.d.ts",
|
|
9
|
+
"default": "./dist/session.js"
|
|
10
|
+
},
|
|
11
|
+
"./state": {
|
|
12
|
+
"types": "./dist/state.d.ts",
|
|
13
|
+
"default": "./dist/state.js"
|
|
14
|
+
},
|
|
15
|
+
"./commands": {
|
|
16
|
+
"types": "./dist/commands.d.ts",
|
|
17
|
+
"default": "./dist/commands.js"
|
|
18
|
+
},
|
|
19
|
+
"./describe": {
|
|
20
|
+
"types": "./dist/describe.d.ts",
|
|
21
|
+
"default": "./dist/describe.js"
|
|
22
|
+
},
|
|
23
|
+
"./persist": {
|
|
24
|
+
"types": "./dist/persist.d.ts",
|
|
25
|
+
"default": "./dist/persist.js"
|
|
26
|
+
},
|
|
27
|
+
"./ink": {
|
|
28
|
+
"types": "./dist/ink/index.d.ts",
|
|
29
|
+
"default": "./dist/ink/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"ink": "^5.2.1",
|
|
34
|
+
"ink-text-input": "^6.0.0",
|
|
35
|
+
"openai": "^4.77.0",
|
|
36
|
+
"react": "^18.3.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^24.13.1",
|
|
40
|
+
"@types/react": "^18.3.29",
|
|
41
|
+
"esbuild": "^0.21.5",
|
|
42
|
+
"ink-testing-library": "^4.0.0",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"@corenel/harness": "0.3.2",
|
|
45
|
+
"@corenel/protocol": "0.3.2",
|
|
46
|
+
"@corenel/tools-node": "0.2.0"
|
|
47
|
+
},
|
|
48
|
+
"license": "Elastic-2.0",
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"dist",
|
|
54
|
+
"README.md"
|
|
55
|
+
],
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"build": "node build.mjs && tsc -p tsconfig.build.json"
|
|
62
|
+
}
|
|
63
|
+
}
|