@sagmans/dsh-tui 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/LICENSE +21 -0
- package/README.md +266 -0
- package/cordis.patch.yml +123 -0
- package/lib/agent/fork.d.ts +24 -0
- package/lib/agent/fork.d.ts.map +1 -0
- package/lib/agent/fork.js +25 -0
- package/lib/agent/fork.js.map +1 -0
- package/lib/agent/history.d.ts +78 -0
- package/lib/agent/history.d.ts.map +1 -0
- package/lib/agent/history.js +179 -0
- package/lib/agent/history.js.map +1 -0
- package/lib/agent/host.d.ts +58 -0
- package/lib/agent/host.d.ts.map +1 -0
- package/lib/agent/host.js +59 -0
- package/lib/agent/host.js.map +1 -0
- package/lib/agent/model.d.ts +61 -0
- package/lib/agent/model.d.ts.map +1 -0
- package/lib/agent/model.js +92 -0
- package/lib/agent/model.js.map +1 -0
- package/lib/agent/present.d.ts +12 -0
- package/lib/agent/present.d.ts.map +1 -0
- package/lib/agent/present.js +52 -0
- package/lib/agent/present.js.map +1 -0
- package/lib/agent/presets.d.ts +75 -0
- package/lib/agent/presets.d.ts.map +1 -0
- package/lib/agent/presets.js +117 -0
- package/lib/agent/presets.js.map +1 -0
- package/lib/agent/projections.d.ts +16 -0
- package/lib/agent/projections.d.ts.map +1 -0
- package/lib/agent/projections.js +31 -0
- package/lib/agent/projections.js.map +1 -0
- package/lib/agent/status.d.ts +46 -0
- package/lib/agent/status.d.ts.map +1 -0
- package/lib/agent/status.js +67 -0
- package/lib/agent/status.js.map +1 -0
- package/lib/cards.d.ts +88 -0
- package/lib/cards.d.ts.map +1 -0
- package/lib/cards.js +218 -0
- package/lib/cards.js.map +1 -0
- package/lib/compat/probe.d.ts +33 -0
- package/lib/compat/probe.d.ts.map +1 -0
- package/lib/compat/probe.js +74 -0
- package/lib/compat/probe.js.map +1 -0
- package/lib/config.d.ts +13 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +49 -0
- package/lib/config.js.map +1 -0
- package/lib/contracts.d.ts +32 -0
- package/lib/contracts.d.ts.map +1 -0
- package/lib/contracts.js +2 -0
- package/lib/contracts.js.map +1 -0
- package/lib/export.d.ts +15 -0
- package/lib/export.d.ts.map +1 -0
- package/lib/export.js +52 -0
- package/lib/export.js.map +1 -0
- package/lib/gates.d.ts +85 -0
- package/lib/gates.d.ts.map +1 -0
- package/lib/gates.js +216 -0
- package/lib/gates.js.map +1 -0
- package/lib/identity.d.ts +33 -0
- package/lib/identity.d.ts.map +1 -0
- package/lib/identity.js +49 -0
- package/lib/identity.js.map +1 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1196 -0
- package/lib/index.js.map +1 -0
- package/lib/input/completion.d.ts +22 -0
- package/lib/input/completion.d.ts.map +1 -0
- package/lib/input/completion.js +27 -0
- package/lib/input/completion.js.map +1 -0
- package/lib/input/submission.d.ts +62 -0
- package/lib/input/submission.d.ts.map +1 -0
- package/lib/input/submission.js +80 -0
- package/lib/input/submission.js.map +1 -0
- package/lib/jobs.d.ts +64 -0
- package/lib/jobs.d.ts.map +1 -0
- package/lib/jobs.js +123 -0
- package/lib/jobs.js.map +1 -0
- package/lib/startup.d.ts +17 -0
- package/lib/startup.d.ts.map +1 -0
- package/lib/startup.js +67 -0
- package/lib/startup.js.map +1 -0
- package/lib/subagents.d.ts +74 -0
- package/lib/subagents.d.ts.map +1 -0
- package/lib/subagents.js +141 -0
- package/lib/subagents.js.map +1 -0
- package/lib/terminal/bell.d.ts +18 -0
- package/lib/terminal/bell.d.ts.map +1 -0
- package/lib/terminal/bell.js +16 -0
- package/lib/terminal/bell.js.map +1 -0
- package/lib/terminal/clipboard.d.ts +11 -0
- package/lib/terminal/clipboard.d.ts.map +1 -0
- package/lib/terminal/clipboard.js +18 -0
- package/lib/terminal/clipboard.js.map +1 -0
- package/lib/terminal/restore.d.ts +17 -0
- package/lib/terminal/restore.d.ts.map +1 -0
- package/lib/terminal/restore.js +43 -0
- package/lib/terminal/restore.js.map +1 -0
- package/lib/terminal/title.d.ts +22 -0
- package/lib/terminal/title.d.ts.map +1 -0
- package/lib/terminal/title.js +34 -0
- package/lib/terminal/title.js.map +1 -0
- package/lib/text.d.ts +19 -0
- package/lib/text.d.ts.map +1 -0
- package/lib/text.js +61 -0
- package/lib/text.js.map +1 -0
- package/lib/theme.d.ts +47 -0
- package/lib/theme.d.ts.map +1 -0
- package/lib/theme.js +84 -0
- package/lib/theme.js.map +1 -0
- package/lib/transcript.d.ts +91 -0
- package/lib/transcript.d.ts.map +1 -0
- package/lib/transcript.js +315 -0
- package/lib/transcript.js.map +1 -0
- package/lib/ui/dock.d.ts +36 -0
- package/lib/ui/dock.d.ts.map +1 -0
- package/lib/ui/dock.js +110 -0
- package/lib/ui/dock.js.map +1 -0
- package/lib/ui/markdown.d.ts +17 -0
- package/lib/ui/markdown.d.ts.map +1 -0
- package/lib/ui/markdown.js +35 -0
- package/lib/ui/markdown.js.map +1 -0
- package/lib/ui/picker.d.ts +103 -0
- package/lib/ui/picker.d.ts.map +1 -0
- package/lib/ui/picker.js +165 -0
- package/lib/ui/picker.js.map +1 -0
- package/lib/ui/rows.d.ts +30 -0
- package/lib/ui/rows.d.ts.map +1 -0
- package/lib/ui/rows.js +49 -0
- package/lib/ui/rows.js.map +1 -0
- package/lib/ui/status.d.ts +49 -0
- package/lib/ui/status.d.ts.map +1 -0
- package/lib/ui/status.js +90 -0
- package/lib/ui/status.js.map +1 -0
- package/lib/ui/view.d.ts +56 -0
- package/lib/ui/view.d.ts.map +1 -0
- package/lib/ui/view.js +184 -0
- package/lib/ui/view.js.map +1 -0
- package/lib/work.d.ts +39 -0
- package/lib/work.d.ts.map +1 -0
- package/lib/work.js +97 -0
- package/lib/work.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
/** One delegation this session started, as the surface shows it. */
|
|
3
|
+
export interface SubagentRun {
|
|
4
|
+
readonly runId: string;
|
|
5
|
+
readonly provider: string;
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly startedAt: number;
|
|
8
|
+
readonly status: 'running' | 'completed' | 'failed';
|
|
9
|
+
readonly stopReason?: string;
|
|
10
|
+
readonly finishedAt?: number;
|
|
11
|
+
}
|
|
12
|
+
/** Child rows the dock lists before the count takes over. */
|
|
13
|
+
export declare const DOCK_SUBAGENT_LIMIT = 2;
|
|
14
|
+
/** Short form of a child session id: enough to tell two children apart. */
|
|
15
|
+
export declare function shortId(id: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Track the delegations of one session.
|
|
18
|
+
*
|
|
19
|
+
* Subagent lifecycle arrives as service events rather than durable session
|
|
20
|
+
* events, so this is live state: the durable record of a delegation is the tool
|
|
21
|
+
* call that asked for it, and a resumed run starts with an empty roster.
|
|
22
|
+
*/
|
|
23
|
+
export declare class SubagentRoster {
|
|
24
|
+
private readonly now;
|
|
25
|
+
private readonly runs;
|
|
26
|
+
constructor(now?: () => number);
|
|
27
|
+
/** Record a started run; an unknown shape is ignored rather than guessed at. */
|
|
28
|
+
start(info: unknown): void;
|
|
29
|
+
/** Settle a run; an end without its start still becomes a row. */
|
|
30
|
+
end(info: unknown): void;
|
|
31
|
+
list(): readonly SubagentRun[];
|
|
32
|
+
running(): readonly SubagentRun[];
|
|
33
|
+
reset(): void;
|
|
34
|
+
}
|
|
35
|
+
/** One delegation as a row. */
|
|
36
|
+
export declare function describeSubagent(run: SubagentRun, now: number): string;
|
|
37
|
+
/** The whole roster as lines. */
|
|
38
|
+
export declare function describeSubagents(runs: readonly SubagentRun[], now: number): string;
|
|
39
|
+
/** What a `/subagents` argument asks the surface to do. */
|
|
40
|
+
export type SubagentsCommand = {
|
|
41
|
+
readonly kind: 'list';
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: 'open';
|
|
44
|
+
readonly id: string;
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: 'kill';
|
|
47
|
+
readonly id: string;
|
|
48
|
+
} | {
|
|
49
|
+
readonly kind: 'invalid';
|
|
50
|
+
readonly reason: string;
|
|
51
|
+
};
|
|
52
|
+
/** Read a `/subagents` argument; the id is the only handle, so actions stay explicit. */
|
|
53
|
+
export declare function parseSubagentsArgument(argument: string): SubagentsCommand;
|
|
54
|
+
/** Names the most recent run, for a reader who just watched one start. */
|
|
55
|
+
export declare const LAST_RUN = "last";
|
|
56
|
+
/**
|
|
57
|
+
* Find one run by exact id or unambiguous prefix.
|
|
58
|
+
*
|
|
59
|
+
* Rows show a short id, so the reader types what they can see; an ambiguous
|
|
60
|
+
* prefix resolves to nothing rather than to the wrong child. \`last\` names the
|
|
61
|
+
* newest run, because copying a uuid out of a terminal is not a workflow.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveRun(runs: readonly SubagentRun[], idOrPrefix: string): SubagentRun | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Stop one live child.
|
|
66
|
+
*
|
|
67
|
+
* A delegation is an ordinary agent in the same process, so a stop is the same
|
|
68
|
+
* cancel a reader's Ctrl+C sends to the parent; a child that already settled is
|
|
69
|
+
* reported rather than pretended away.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createSubagentControl(ctx: Context): {
|
|
72
|
+
stop(id: string): boolean;
|
|
73
|
+
} | undefined;
|
|
74
|
+
//# sourceMappingURL=subagents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagents.d.ts","sourceRoot":"","sources":["../src/subagents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAA;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,6DAA6D;AAC7D,eAAO,MAAM,mBAAmB,IAAI,CAAA;AASpC,2EAA2E;AAC3E,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IAGb,OAAO,CAAC,QAAQ,CAAC,GAAG;IAFhC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;gBAEzB,GAAG,GAAE,MAAM,MAAyB;IAEjE,gFAAgF;IAChF,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAc1B,kEAAkE;IAClE,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAiBxB,IAAI,IAAI,SAAS,WAAW,EAAE;IAI9B,OAAO,IAAI,SAAS,WAAW,EAAE;IAIjC,KAAK,IAAI,IAAI;CAGd;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKtE;AAED,iCAAiC;AACjC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKnF;AAED,2DAA2D;AAC3D,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAKzD,yFAAyF;AACzF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CASzE;AAED,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,SAAS,CAAA;AAE9B;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAapG;AAOD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,SAAS,CAW7F"}
|
package/lib/subagents.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { describeDuration } from "./jobs.js";
|
|
2
|
+
/** Child rows the dock lists before the count takes over. */
|
|
3
|
+
export const DOCK_SUBAGENT_LIMIT = 2;
|
|
4
|
+
/** Id characters kept in a row, so an id cannot smuggle in a control sequence. */
|
|
5
|
+
const SHORT_ID_LENGTH = 8;
|
|
6
|
+
function asRecord(value) {
|
|
7
|
+
return typeof value === 'object' && value !== null ? value : undefined;
|
|
8
|
+
}
|
|
9
|
+
/** Short form of a child session id: enough to tell two children apart. */
|
|
10
|
+
export function shortId(id) {
|
|
11
|
+
return id.length <= SHORT_ID_LENGTH ? id : id.slice(0, SHORT_ID_LENGTH);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Track the delegations of one session.
|
|
15
|
+
*
|
|
16
|
+
* Subagent lifecycle arrives as service events rather than durable session
|
|
17
|
+
* events, so this is live state: the durable record of a delegation is the tool
|
|
18
|
+
* call that asked for it, and a resumed run starts with an empty roster.
|
|
19
|
+
*/
|
|
20
|
+
export class SubagentRoster {
|
|
21
|
+
now;
|
|
22
|
+
runs = new Map();
|
|
23
|
+
constructor(now = () => Date.now()) {
|
|
24
|
+
this.now = now;
|
|
25
|
+
}
|
|
26
|
+
/** Record a started run; an unknown shape is ignored rather than guessed at. */
|
|
27
|
+
start(info) {
|
|
28
|
+
const record = asRecord(info);
|
|
29
|
+
const runId = record?.runId;
|
|
30
|
+
const id = record?.id;
|
|
31
|
+
if (typeof runId !== 'string' || typeof id !== 'string')
|
|
32
|
+
return;
|
|
33
|
+
this.runs.set(runId, {
|
|
34
|
+
runId,
|
|
35
|
+
id,
|
|
36
|
+
provider: typeof record?.provider === 'string' ? record.provider : 'subagent',
|
|
37
|
+
startedAt: this.now(),
|
|
38
|
+
status: 'running',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Settle a run; an end without its start still becomes a row. */
|
|
42
|
+
end(info) {
|
|
43
|
+
const record = asRecord(info);
|
|
44
|
+
const runId = record?.runId;
|
|
45
|
+
if (typeof runId !== 'string')
|
|
46
|
+
return;
|
|
47
|
+
const existing = this.runs.get(runId);
|
|
48
|
+
const stopReason = typeof record?.stopReason === 'string' ? record.stopReason : undefined;
|
|
49
|
+
this.runs.set(runId, {
|
|
50
|
+
runId,
|
|
51
|
+
id: typeof record?.id === 'string' ? record.id : existing?.id ?? runId,
|
|
52
|
+
provider: typeof record?.provider === 'string' ? record.provider : existing?.provider ?? 'subagent',
|
|
53
|
+
startedAt: existing?.startedAt ?? this.now(),
|
|
54
|
+
status: stopReason === undefined || stopReason === 'completed' ? 'completed' : 'failed',
|
|
55
|
+
...(stopReason === undefined ? {} : { stopReason }),
|
|
56
|
+
finishedAt: this.now(),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
list() {
|
|
60
|
+
return [...this.runs.values()].sort((left, right) => right.startedAt - left.startedAt);
|
|
61
|
+
}
|
|
62
|
+
running() {
|
|
63
|
+
return this.list().filter(run => run.status === 'running');
|
|
64
|
+
}
|
|
65
|
+
reset() {
|
|
66
|
+
this.runs.clear();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** One delegation as a row. */
|
|
70
|
+
export function describeSubagent(run, now) {
|
|
71
|
+
const age = run.status === 'running'
|
|
72
|
+
? `running ${describeDuration(now - run.startedAt)}`
|
|
73
|
+
: `${run.status}${run.stopReason === undefined || run.stopReason === 'completed' ? '' : ` (${run.stopReason})`} ${describeDuration((run.finishedAt ?? run.startedAt) - run.startedAt)}`;
|
|
74
|
+
return `${shortId(run.id)} · ${run.provider} · ${age}`;
|
|
75
|
+
}
|
|
76
|
+
/** The whole roster as lines. */
|
|
77
|
+
export function describeSubagents(runs, now) {
|
|
78
|
+
if (runs.length === 0)
|
|
79
|
+
return 'no subagents have run in this session';
|
|
80
|
+
const running = runs.filter(run => run.status === 'running').length;
|
|
81
|
+
const header = `subagents · ${runs.length}${running === 0 ? '' : ` (${running} running)`}`;
|
|
82
|
+
return [header, ...runs.map(run => ` ${describeSubagent(run, now)}`)].join('\n');
|
|
83
|
+
}
|
|
84
|
+
/** Actions a reader can name, so an unknown verb is refused instead of guessed at. */
|
|
85
|
+
const ACTIONS = new Set(['open', 'kill']);
|
|
86
|
+
/** Read a `/subagents` argument; the id is the only handle, so actions stay explicit. */
|
|
87
|
+
export function parseSubagentsArgument(argument) {
|
|
88
|
+
const parts = argument.trim().split(/\s+/u).filter(part => part !== '');
|
|
89
|
+
if (parts.length === 0)
|
|
90
|
+
return { kind: 'list' };
|
|
91
|
+
const [verb = '', id = ''] = parts;
|
|
92
|
+
if (!ACTIONS.has(verb)) {
|
|
93
|
+
return { kind: 'invalid', reason: `unknown action "${verb}" — use /subagents, /subagents open <id>, or /subagents kill <id>` };
|
|
94
|
+
}
|
|
95
|
+
if (id === '')
|
|
96
|
+
return { kind: 'invalid', reason: `${verb} needs a child id; /subagents lists them` };
|
|
97
|
+
return verb === 'open' ? { kind: 'open', id } : { kind: 'kill', id };
|
|
98
|
+
}
|
|
99
|
+
/** Names the most recent run, for a reader who just watched one start. */
|
|
100
|
+
export const LAST_RUN = 'last';
|
|
101
|
+
/**
|
|
102
|
+
* Find one run by exact id or unambiguous prefix.
|
|
103
|
+
*
|
|
104
|
+
* Rows show a short id, so the reader types what they can see; an ambiguous
|
|
105
|
+
* prefix resolves to nothing rather than to the wrong child. \`last\` names the
|
|
106
|
+
* newest run, because copying a uuid out of a terminal is not a workflow.
|
|
107
|
+
*/
|
|
108
|
+
export function resolveRun(runs, idOrPrefix) {
|
|
109
|
+
// The roster happens to hand these over newest first; picking by time keeps
|
|
110
|
+
// the shortcut honest even if a caller ever hands them over differently.
|
|
111
|
+
if (idOrPrefix === LAST_RUN) {
|
|
112
|
+
return runs.reduce((newest, run) => newest === undefined || run.startedAt > newest.startedAt ? run : newest, undefined);
|
|
113
|
+
}
|
|
114
|
+
const exact = runs.find(run => run.id === idOrPrefix);
|
|
115
|
+
if (exact !== undefined)
|
|
116
|
+
return exact;
|
|
117
|
+
const matches = runs.filter(run => run.id.startsWith(idOrPrefix));
|
|
118
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Stop one live child.
|
|
122
|
+
*
|
|
123
|
+
* A delegation is an ordinary agent in the same process, so a stop is the same
|
|
124
|
+
* cancel a reader's Ctrl+C sends to the parent; a child that already settled is
|
|
125
|
+
* reported rather than pretended away.
|
|
126
|
+
*/
|
|
127
|
+
export function createSubagentControl(ctx) {
|
|
128
|
+
const agents = ctx.get('agents');
|
|
129
|
+
if (typeof agents?.get !== 'function')
|
|
130
|
+
return undefined;
|
|
131
|
+
return {
|
|
132
|
+
stop: id => {
|
|
133
|
+
const child = agents.get?.(id);
|
|
134
|
+
if (child?.cancel === undefined)
|
|
135
|
+
return false;
|
|
136
|
+
child.cancel({ kind: 'user' });
|
|
137
|
+
return true;
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=subagents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagents.js","sourceRoot":"","sources":["../src/subagents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The terminal bell.
|
|
3
|
+
*
|
|
4
|
+
* A bell is a courtesy for the turn the reader walked away from, and noise for
|
|
5
|
+
* every other one, so it is bound to how long the turn ran and can be turned
|
|
6
|
+
* off entirely.
|
|
7
|
+
*/
|
|
8
|
+
/** The terminal bell character. */
|
|
9
|
+
export declare const BELL = "\u0007";
|
|
10
|
+
/** How long a turn has to run before its end is worth a bell. */
|
|
11
|
+
export declare const BELL_AFTER_MS = 10000;
|
|
12
|
+
/** Whether this turn's end should ring. */
|
|
13
|
+
export declare function shouldRingBell(input: {
|
|
14
|
+
readonly bell: boolean;
|
|
15
|
+
readonly ranForMs: number;
|
|
16
|
+
readonly exiting: boolean;
|
|
17
|
+
}): boolean;
|
|
18
|
+
//# sourceMappingURL=bell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bell.d.ts","sourceRoot":"","sources":["../../src/terminal/bell.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mCAAmC;AACnC,eAAO,MAAM,IAAI,WAAW,CAAA;AAE5B,iEAAiE;AACjE,eAAO,MAAM,aAAa,QAAS,CAAA;AAEnC,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B,GAAG,OAAO,CAEV"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The terminal bell.
|
|
3
|
+
*
|
|
4
|
+
* A bell is a courtesy for the turn the reader walked away from, and noise for
|
|
5
|
+
* every other one, so it is bound to how long the turn ran and can be turned
|
|
6
|
+
* off entirely.
|
|
7
|
+
*/
|
|
8
|
+
/** The terminal bell character. */
|
|
9
|
+
export const BELL = '\u0007';
|
|
10
|
+
/** How long a turn has to run before its end is worth a bell. */
|
|
11
|
+
export const BELL_AFTER_MS = 10_000;
|
|
12
|
+
/** Whether this turn's end should ring. */
|
|
13
|
+
export function shouldRingBell(input) {
|
|
14
|
+
return input.bell && !input.exiting && input.ranForMs >= BELL_AFTER_MS;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=bell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bell.js","sourceRoot":"","sources":["../../src/terminal/bell.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mCAAmC;AACnC,MAAM,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAA;AAE5B,iEAAiE;AACjE,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAA;AAEnC,2CAA2C;AAC3C,MAAM,UAAU,cAAc,CAAC,KAI9B;IACC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,aAAa,CAAA;AACxE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard writes.
|
|
3
|
+
*
|
|
4
|
+
* OSC 52 is the only clipboard a terminal program has: it asks the terminal to
|
|
5
|
+
* put text on the reader's clipboard, and it works over SSH, where no local
|
|
6
|
+
* clipboard API exists. The payload is base64 by design, so no control
|
|
7
|
+
* character in the copied text can end the sequence early.
|
|
8
|
+
*/
|
|
9
|
+
/** The sequence that asks the terminal to copy `text`. */
|
|
10
|
+
export declare function clipboardSequence(text: string): string;
|
|
11
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../src/terminal/clipboard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard writes.
|
|
3
|
+
*
|
|
4
|
+
* OSC 52 is the only clipboard a terminal program has: it asks the terminal to
|
|
5
|
+
* put text on the reader's clipboard, and it works over SSH, where no local
|
|
6
|
+
* clipboard API exists. The payload is base64 by design, so no control
|
|
7
|
+
* character in the copied text can end the sequence early.
|
|
8
|
+
*/
|
|
9
|
+
const OSC_INTRODUCER = '\u001b]';
|
|
10
|
+
const STRING_TERMINATOR = '\u0007';
|
|
11
|
+
const CLIPBOARD_CODE = '52';
|
|
12
|
+
/** `c` selects the system clipboard, as opposed to the primary selection. */
|
|
13
|
+
const CLIPBOARD_SELECTION = 'c';
|
|
14
|
+
/** The sequence that asks the terminal to copy `text`. */
|
|
15
|
+
export function clipboardSequence(text) {
|
|
16
|
+
return `${OSC_INTRODUCER}${CLIPBOARD_CODE};${CLIPBOARD_SELECTION};${Buffer.from(text, 'utf8').toString('base64')}${STRING_TERMINATOR}`;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/terminal/clipboard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,cAAc,GAAG,SAAS,CAAA;AAChC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAClC,MAAM,cAAc,GAAG,IAAI,CAAA;AAC3B,6EAA6E;AAC7E,MAAM,mBAAmB,GAAG,GAAG,CAAA;AAE/B,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,GAAG,cAAc,GAAG,cAAc,IAAI,mBAAmB,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,iBAAiB,EAAE,CAAA;AACxI,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** One reversible terminal mutation. */
|
|
2
|
+
export type RestoreHook = () => void;
|
|
3
|
+
/** Registry that guarantees every registered hook runs exactly once. */
|
|
4
|
+
export interface RestoreRegistry {
|
|
5
|
+
add(hook: RestoreHook): () => void;
|
|
6
|
+
restore(): void;
|
|
7
|
+
readonly size: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Collect the terminal-release hooks for one surface.
|
|
11
|
+
*
|
|
12
|
+
* Restoring the terminal is the one thing that must happen even when boot
|
|
13
|
+
* fails halfway, so hooks run in reverse registration order, each isolated:
|
|
14
|
+
* a throwing hook must not strand the ones registered before it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createRestoreRegistry(): RestoreRegistry;
|
|
17
|
+
//# sourceMappingURL=restore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../src/terminal/restore.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAA;AAEpC,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,IAAI,CAAA;IAClC,OAAO,IAAI,IAAI,CAAA;IACf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAgCvD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collect the terminal-release hooks for one surface.
|
|
3
|
+
*
|
|
4
|
+
* Restoring the terminal is the one thing that must happen even when boot
|
|
5
|
+
* fails halfway, so hooks run in reverse registration order, each isolated:
|
|
6
|
+
* a throwing hook must not strand the ones registered before it.
|
|
7
|
+
*/
|
|
8
|
+
export function createRestoreRegistry() {
|
|
9
|
+
const hooks = [];
|
|
10
|
+
let restored = false;
|
|
11
|
+
return {
|
|
12
|
+
add(hook) {
|
|
13
|
+
if (restored) {
|
|
14
|
+
// Registering after release means the owner is already gone; run it now
|
|
15
|
+
// rather than silently keeping a mutation the terminal never reclaims.
|
|
16
|
+
hook();
|
|
17
|
+
return () => { };
|
|
18
|
+
}
|
|
19
|
+
hooks.push(hook);
|
|
20
|
+
return () => {
|
|
21
|
+
const index = hooks.indexOf(hook);
|
|
22
|
+
if (index >= 0)
|
|
23
|
+
hooks.splice(index, 1);
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
restore() {
|
|
27
|
+
restored = true;
|
|
28
|
+
while (hooks.length > 0) {
|
|
29
|
+
const hook = hooks.pop();
|
|
30
|
+
try {
|
|
31
|
+
hook?.();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// A failing hook must not prevent the remaining ones from running.
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
get size() {
|
|
39
|
+
return hooks.length;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=restore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.js","sourceRoot":"","sources":["../../src/terminal/restore.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAkB,EAAE,CAAA;IAC/B,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,OAAO;QACL,GAAG,CAAC,IAAI;YACN,IAAI,QAAQ,EAAE,CAAC;gBACb,wEAAwE;gBACxE,uEAAuE;gBACvE,IAAI,EAAE,CAAA;gBACN,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;YACjB,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChB,OAAO,GAAG,EAAE;gBACV,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;gBACjC,IAAI,KAAK,IAAI,CAAC;oBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;YACxC,CAAC,CAAA;QACH,CAAC;QACD,OAAO;YACL,QAAQ,GAAG,IAAI,CAAA;YACf,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;gBACxB,IAAI,CAAC;oBACH,IAAI,EAAE,EAAE,CAAA;gBACV,CAAC;gBAAC,MAAM,CAAC;oBACP,mEAAmE;gBACrE,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,IAAI;YACN,OAAO,KAAK,CAAC,MAAM,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal title.
|
|
3
|
+
*
|
|
4
|
+
* The window title is the one piece of terminal state a reader sees while the
|
|
5
|
+
* surface is not on screen — in a tab bar, a window list, or a multiplexer — so
|
|
6
|
+
* it says what this session is and whether it is working.
|
|
7
|
+
*/
|
|
8
|
+
/** How much of a directory name the title keeps. */
|
|
9
|
+
export declare const TITLE_DIR_LIMIT = 40;
|
|
10
|
+
/**
|
|
11
|
+
* Build the title sequence.
|
|
12
|
+
*
|
|
13
|
+
* Anything a terminal would read as the end of the title is removed rather than
|
|
14
|
+
* escaped: this is a window label, and a hostile directory name has no business
|
|
15
|
+
* reaching the terminal as a control character.
|
|
16
|
+
*/
|
|
17
|
+
export declare function titleSequence(title: string): string;
|
|
18
|
+
/** The window title for a session, in the terms a tab bar can show. */
|
|
19
|
+
export declare function windowTitle(cwd: string, activity: 'ready' | 'working'): string;
|
|
20
|
+
/** Hand the title back: the shell sets its own on the next prompt. */
|
|
21
|
+
export declare const CLEAR_TITLE: string;
|
|
22
|
+
//# sourceMappingURL=title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.d.ts","sourceRoot":"","sources":["../../src/terminal/title.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,oDAAoD;AACpD,eAAO,MAAM,eAAe,KAAK,CAAA;AAEjC;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAK9E;AAED,sEAAsE;AACtE,eAAO,MAAM,WAAW,QAAoB,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal title.
|
|
3
|
+
*
|
|
4
|
+
* The window title is the one piece of terminal state a reader sees while the
|
|
5
|
+
* surface is not on screen — in a tab bar, a window list, or a multiplexer — so
|
|
6
|
+
* it says what this session is and whether it is working.
|
|
7
|
+
*/
|
|
8
|
+
const OSC_INTRODUCER = '\u001b]';
|
|
9
|
+
const STRING_TERMINATOR = '\u0007';
|
|
10
|
+
const TITLE_CODE = '0';
|
|
11
|
+
/** Characters that would end the sequence early and let the rest execute. */
|
|
12
|
+
const UNSAFE = /[\u0000-\u001f\u007f]/gu;
|
|
13
|
+
/** How much of a directory name the title keeps. */
|
|
14
|
+
export const TITLE_DIR_LIMIT = 40;
|
|
15
|
+
/**
|
|
16
|
+
* Build the title sequence.
|
|
17
|
+
*
|
|
18
|
+
* Anything a terminal would read as the end of the title is removed rather than
|
|
19
|
+
* escaped: this is a window label, and a hostile directory name has no business
|
|
20
|
+
* reaching the terminal as a control character.
|
|
21
|
+
*/
|
|
22
|
+
export function titleSequence(title) {
|
|
23
|
+
return `${OSC_INTRODUCER}${TITLE_CODE};${title.replace(UNSAFE, '')}${STRING_TERMINATOR}`;
|
|
24
|
+
}
|
|
25
|
+
/** The window title for a session, in the terms a tab bar can show. */
|
|
26
|
+
export function windowTitle(cwd, activity) {
|
|
27
|
+
const segments = cwd.split('/').filter(segment => segment !== '');
|
|
28
|
+
const tail = segments.slice(-2).join('/');
|
|
29
|
+
const cut = tail.length > TITLE_DIR_LIMIT ? `…${tail.slice(-(TITLE_DIR_LIMIT - 1))}` : tail;
|
|
30
|
+
return titleSequence(`dsh-tui · ${cut === '' ? cwd : cut} · ${activity}`);
|
|
31
|
+
}
|
|
32
|
+
/** Hand the title back: the shell sets its own on the next prompt. */
|
|
33
|
+
export const CLEAR_TITLE = titleSequence('');
|
|
34
|
+
//# sourceMappingURL=title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.js","sourceRoot":"","sources":["../../src/terminal/title.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,cAAc,GAAG,SAAS,CAAA;AAChC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAClC,MAAM,UAAU,GAAG,GAAG,CAAA;AAEtB,6EAA6E;AAC7E,MAAM,MAAM,GAAG,yBAAyB,CAAA;AAExC,oDAAoD;AACpD,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAA;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,GAAG,cAAc,GAAG,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAA;AAC1F,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,QAA6B;IACpE,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC,CAAA;IACjE,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAC3F,OAAO,aAAa,CAAC,aAAa,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,QAAQ,EAAE,CAAC,CAAA;AAC3E,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA"}
|
package/lib/text.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make untrusted text safe to hand to a terminal.
|
|
3
|
+
*
|
|
4
|
+
* Model output, tool output, and file content all reach the screen, and a
|
|
5
|
+
* terminal executes the escape sequences it is given: a crafted result could
|
|
6
|
+
* repaint the frame, retitle the window, or write the clipboard. Escaping here,
|
|
7
|
+
* at the one boundary every rendered fragment crosses, means no component has
|
|
8
|
+
* to remember to do it.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Render control characters as visible escapes, keeping line feeds.
|
|
12
|
+
*
|
|
13
|
+
* A line feed is the only control a renderer already understands; everything
|
|
14
|
+
* else becomes text so the reader can see that it was there instead of the
|
|
15
|
+
* terminal acting on it. Tabs are escaped too: a tab advances the cursor by a
|
|
16
|
+
* stop the layout cannot predict, which would desynchronize wrapping.
|
|
17
|
+
*/
|
|
18
|
+
export declare function displayText(raw: string): string;
|
|
19
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAwBH;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwB/C"}
|
package/lib/text.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make untrusted text safe to hand to a terminal.
|
|
3
|
+
*
|
|
4
|
+
* Model output, tool output, and file content all reach the screen, and a
|
|
5
|
+
* terminal executes the escape sequences it is given: a crafted result could
|
|
6
|
+
* repaint the frame, retitle the window, or write the clipboard. Escaping here,
|
|
7
|
+
* at the one boundary every rendered fragment crosses, means no component has
|
|
8
|
+
* to remember to do it.
|
|
9
|
+
*/
|
|
10
|
+
const LINE_FEED = 0x0a;
|
|
11
|
+
const LAST_C0 = 0x1f;
|
|
12
|
+
const DELETE = 0x7f;
|
|
13
|
+
const FIRST_C1 = 0x80;
|
|
14
|
+
const LAST_C1 = 0x9f;
|
|
15
|
+
const FIRST_SURROGATE = 0xd800;
|
|
16
|
+
const LAST_SURROGATE = 0xdfff;
|
|
17
|
+
const REPLACEMENT = '\uFFFD';
|
|
18
|
+
const C0_PREFIX = '\\x';
|
|
19
|
+
const UNICODE_PREFIX = '\\u';
|
|
20
|
+
/** Directional overrides and isolates can reorder the frame around a payload. */
|
|
21
|
+
const BIDI_CONTROLS = new Set([0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x2066, 0x2067, 0x2068, 0x2069]);
|
|
22
|
+
/** Separators that end a line without a line feed. */
|
|
23
|
+
const LINE_SEPARATOR = 0x2028;
|
|
24
|
+
const PARAGRAPH_SEPARATOR = 0x2029;
|
|
25
|
+
function escapeCode(prefix, code, digits) {
|
|
26
|
+
return prefix + code.toString(16).toUpperCase().padStart(digits, '0');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Render control characters as visible escapes, keeping line feeds.
|
|
30
|
+
*
|
|
31
|
+
* A line feed is the only control a renderer already understands; everything
|
|
32
|
+
* else becomes text so the reader can see that it was there instead of the
|
|
33
|
+
* terminal acting on it. Tabs are escaped too: a tab advances the cursor by a
|
|
34
|
+
* stop the layout cannot predict, which would desynchronize wrapping.
|
|
35
|
+
*/
|
|
36
|
+
export function displayText(raw) {
|
|
37
|
+
let out = '';
|
|
38
|
+
for (const character of raw) {
|
|
39
|
+
const code = character.codePointAt(0) ?? 0;
|
|
40
|
+
if (code === LINE_FEED) {
|
|
41
|
+
out += character;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (code <= LAST_C0 || code === DELETE || (code >= FIRST_C1 && code <= LAST_C1)) {
|
|
45
|
+
out += escapeCode(C0_PREFIX, code, 2);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
// A code point in this range is an unpaired half, which no terminal font has.
|
|
49
|
+
if (code >= FIRST_SURROGATE && code <= LAST_SURROGATE) {
|
|
50
|
+
out += REPLACEMENT;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (BIDI_CONTROLS.has(code) || code === LINE_SEPARATOR || code === PARAGRAPH_SEPARATOR) {
|
|
54
|
+
out += escapeCode(UNICODE_PREFIX, code, 4);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
out += character;
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=text.js.map
|
package/lib/text.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,SAAS,GAAG,IAAI,CAAA;AACtB,MAAM,OAAO,GAAG,IAAI,CAAA;AACpB,MAAM,MAAM,GAAG,IAAI,CAAA;AACnB,MAAM,QAAQ,GAAG,IAAI,CAAA;AACrB,MAAM,OAAO,GAAG,IAAI,CAAA;AACpB,MAAM,eAAe,GAAG,MAAM,CAAA;AAC9B,MAAM,cAAc,GAAG,MAAM,CAAA;AAC7B,MAAM,WAAW,GAAG,QAAQ,CAAA;AAC5B,MAAM,SAAS,GAAG,KAAK,CAAA;AACvB,MAAM,cAAc,GAAG,KAAK,CAAA;AAE5B,iFAAiF;AACjF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAEvG,sDAAsD;AACtD,MAAM,cAAc,GAAG,MAAM,CAAA;AAC7B,MAAM,mBAAmB,GAAG,MAAM,CAAA;AAElC,SAAS,UAAU,CAAC,MAAc,EAAE,IAAY,EAAE,MAAc;IAC9D,OAAO,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,KAAK,MAAM,SAAS,IAAI,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC1C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,GAAG,IAAI,SAAS,CAAA;YAChB,SAAQ;QACV,CAAC;QACD,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,IAAI,QAAQ,IAAI,IAAI,IAAI,OAAO,CAAC,EAAE,CAAC;YAChF,GAAG,IAAI,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YACrC,SAAQ;QACV,CAAC;QACD,8EAA8E;QAC9E,IAAI,IAAI,IAAI,eAAe,IAAI,IAAI,IAAI,cAAc,EAAE,CAAC;YACtD,GAAG,IAAI,WAAW,CAAA;YAClB,SAAQ;QACV,CAAC;QACD,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACvF,GAAG,IAAI,UAAU,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YAC1C,SAAQ;QACV,CAAC;QACD,GAAG,IAAI,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
package/lib/theme.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { EditorTheme, MarkdownTheme } from '@earendil-works/pi-tui';
|
|
2
|
+
/** Glyph that introduces each transcript row kind. */
|
|
3
|
+
export interface TranscriptGlyphs {
|
|
4
|
+
readonly user: string;
|
|
5
|
+
readonly assistant: string;
|
|
6
|
+
readonly tool: string;
|
|
7
|
+
readonly notice: string;
|
|
8
|
+
readonly reasoning: string;
|
|
9
|
+
readonly marker: string;
|
|
10
|
+
}
|
|
11
|
+
/** Styling the surface applies, and the editor/select themes pi-tui needs. */
|
|
12
|
+
export interface TuiTheme {
|
|
13
|
+
readonly color: boolean;
|
|
14
|
+
readonly glyphs: TranscriptGlyphs;
|
|
15
|
+
dim(text: string): string;
|
|
16
|
+
bold(text: string): string;
|
|
17
|
+
tool(text: string): string;
|
|
18
|
+
notice(text: string): string;
|
|
19
|
+
/** Diff additions and removals, colored by background rather than by hue alone. */
|
|
20
|
+
added(text: string): string;
|
|
21
|
+
removed(text: string): string;
|
|
22
|
+
/** A boundary in the conversation rather than something anyone said. */
|
|
23
|
+
marker(text: string): string;
|
|
24
|
+
/** Structure the reader scans for: headings, links, inline code, list bullets. */
|
|
25
|
+
accent(text: string): string;
|
|
26
|
+
italic(text: string): string;
|
|
27
|
+
readonly editor: EditorTheme;
|
|
28
|
+
readonly markdown: MarkdownTheme;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Whether styling is on, given the launch flag and the environment.
|
|
32
|
+
*
|
|
33
|
+
* `NO_COLOR` is a cross-tool convention (no-color.org): when it is present and
|
|
34
|
+
* not empty, a program that colors by default must not, regardless of its own
|
|
35
|
+
* flags. Honouring it means one environment variable turns styling off for
|
|
36
|
+
* every tool in a session, which is how a reader actually wants it to work.
|
|
37
|
+
*/
|
|
38
|
+
export declare function colorEnabled(requested: boolean, env?: Record<string, string | undefined>): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Build the surface theme.
|
|
41
|
+
*
|
|
42
|
+
* Styling uses the standard 16 ANSI colors and terminal defaults rather than
|
|
43
|
+
* true-color values, so a light or dark terminal remaps the interface on its
|
|
44
|
+
* own and the surface needs no theme setting.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createTheme(color: boolean): TuiTheme;
|
|
47
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAmB,MAAM,wBAAwB,CAAA;AAQzF,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,8EAA8E;AAC9E,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IACjC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,mFAAmF;IACnF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC7B,wEAAwE;IACxE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,kFAAkF;IAClF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CACjC;AA6CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,OAAO,CAG/G;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAyBpD"}
|