agent-sh 0.14.2 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/shell/events.d.ts +2 -0
- package/dist/shell/output-parser.d.ts +11 -22
- package/dist/shell/output-parser.js +16 -34
- package/dist/shell/shell-context.d.ts +3 -6
- package/dist/shell/shell-context.js +15 -7
- package/dist/shell/shell.js +3 -1
- package/dist/shell/strategies/types.d.ts +6 -0
- package/dist/shell/strategies/zsh.js +7 -0
- package/examples/extensions/ashi/src/cli.ts +32 -4
- package/examples/extensions/ashi/src/commands.ts +2 -20
- package/examples/extensions/ashi/src/default-schema-renderers.ts +28 -25
- package/examples/extensions/ashi/src/frontend.ts +298 -60
- package/examples/extensions/ashi/src/schema.ts +32 -53
- package/examples/extensions/ashi/src/session-store.ts +60 -13
- package/examples/extensions/ashi/src/shell-mode.ts +52 -0
- package/examples/extensions/ashi/src/status-footer.ts +19 -5
- package/examples/extensions/ashi/src/theme.ts +2 -1
- package/package.json +5 -1
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
// Declarative render schema for tool-call hooks.
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
// The view function is pure: `view(state, env)` returns a ToolDisplay describing
|
|
7
|
-
// title + status + body. Ashi owns the pi-tui mapping, theming, streaming
|
|
8
|
-
// buffer policy, diff reflow on resize, expand/collapse — everything that used
|
|
9
|
-
// to leak into renderer subclasses.
|
|
10
|
-
|
|
11
|
-
import { Container, Spacer, Text } from "@earendil-works/pi-tui";
|
|
1
|
+
// Declarative render schema for tool-call hooks. External renderers register
|
|
2
|
+
// `ctx.define("ashi:render-tool:<name>", () => ({ initial, reducers, view }))`.
|
|
3
|
+
|
|
4
|
+
import { Container, Spacer, Text, visibleWidth } from "@earendil-works/pi-tui";
|
|
12
5
|
import type { Component } from "@earendil-works/pi-tui";
|
|
13
6
|
import type { ThemeColor } from "./theme.js";
|
|
14
7
|
import type { ToolEntryConfig } from "./display-config.js";
|
|
@@ -29,9 +22,8 @@ export type Segment = string | { text: string; style?: StyleHint; highlight?: st
|
|
|
29
22
|
export type Body =
|
|
30
23
|
| { kind: "text"; segments: Segment[] }
|
|
31
24
|
| { kind: "code"; lang?: string; text: string }
|
|
32
|
-
/**
|
|
33
|
-
*
|
|
34
|
-
* opt in by returning { kind: "diff" } and reading hasDiff from state. */
|
|
25
|
+
/** Width-aware renderer is supplied via setDiffRenderer; view() opts in by
|
|
26
|
+
* returning { kind: "diff" } and gating on hasDiff in state. */
|
|
35
27
|
| { kind: "diff" }
|
|
36
28
|
| { kind: "stream"; text: string }
|
|
37
29
|
| { kind: "lines"; lines: Segment[][] }
|
|
@@ -43,22 +35,22 @@ export interface DisplayStatus {
|
|
|
43
35
|
summary?: string;
|
|
44
36
|
}
|
|
45
37
|
|
|
46
|
-
/**
|
|
47
|
-
* ashi picks the glyph. Falls back to the generic gear if absent. */
|
|
38
|
+
/** Renderers pick a category; ashi picks the glyph. Falls back to generic. */
|
|
48
39
|
export type TitleIcon = "read" | "search" | "edit" | "shell" | "generic" | "scheme";
|
|
49
40
|
|
|
50
41
|
export interface ToolDisplay {
|
|
51
42
|
titleIcon?: TitleIcon;
|
|
52
43
|
title: Segment[];
|
|
44
|
+
/** Right-aligned on the title line; framework handles padding and reserves
|
|
45
|
+
* space for the status suffix so renderers don't compute widths. */
|
|
46
|
+
titleRight?: Segment[];
|
|
53
47
|
status?: DisplayStatus;
|
|
54
48
|
body?: Body;
|
|
55
49
|
expandable?: boolean;
|
|
56
50
|
defaultExpanded?: boolean;
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
/**
|
|
60
|
-
* changes here trigger a re-invocation of view(). `mode` and `previewLines`
|
|
61
|
-
* come from ashi.display.{name} — see display-config.ts. */
|
|
53
|
+
/** `mode` and `previewLines` come from ashi.display.{name} (display-config.ts). */
|
|
62
54
|
export interface Env {
|
|
63
55
|
width: number;
|
|
64
56
|
expanded: boolean;
|
|
@@ -69,9 +61,8 @@ export interface Env {
|
|
|
69
61
|
|
|
70
62
|
export type Reducer<S, P = unknown> = (state: S, payload: P) => S;
|
|
71
63
|
|
|
72
|
-
/**
|
|
73
|
-
*
|
|
74
|
-
* hasDiff is true once setDiffRenderer has been called (edit/write tools). */
|
|
64
|
+
/** Framework tracks `output`, `status`, `hasDiff` — renderers don't wire
|
|
65
|
+
* `chunk` / `status` / `diff` reducers themselves. */
|
|
75
66
|
export type ViewState<S> = S & {
|
|
76
67
|
output: string;
|
|
77
68
|
status?: DisplayStatus;
|
|
@@ -88,8 +79,7 @@ export interface RenderInitArgs {
|
|
|
88
79
|
|
|
89
80
|
export interface RenderModel<S = Record<string, never>> {
|
|
90
81
|
initial: (args: RenderInitArgs) => S;
|
|
91
|
-
/**
|
|
92
|
-
* reducers here only for tool-specific state transitions. */
|
|
82
|
+
/** Only for tool-specific state transitions; `status`/`chunk` are framework-tracked. */
|
|
93
83
|
reducers?: Record<string, Reducer<ViewState<S>, never>>;
|
|
94
84
|
view: (state: ViewState<S>, env: Env) => ToolDisplay;
|
|
95
85
|
display?: Partial<ToolEntryConfig>;
|
|
@@ -101,12 +91,8 @@ export function isRenderModel(v: unknown): v is RenderModel<unknown> {
|
|
|
101
91
|
return typeof o.initial === "function" && typeof o.view === "function";
|
|
102
92
|
}
|
|
103
93
|
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
// Both Components share a single state cell so that a `chunk` dispatch from
|
|
108
|
-
// the result side repaints the call line too (e.g. for renderers that show
|
|
109
|
-
// progress in the title).
|
|
94
|
+
// Call-side and result-side components share one state cell, so chunks from
|
|
95
|
+
// the result side can repaint the call line (e.g. for in-title progress).
|
|
110
96
|
|
|
111
97
|
import { theme } from "./theme.js";
|
|
112
98
|
|
|
@@ -131,10 +117,7 @@ interface RenderHandle<S> {
|
|
|
131
117
|
dispatch: (action: string, payload?: unknown) => void;
|
|
132
118
|
}
|
|
133
119
|
|
|
134
|
-
/**
|
|
135
|
-
* mount find the call-side cell so they can share state. Once the result
|
|
136
|
-
* component is mounted, both views hold their own handle reference and the
|
|
137
|
-
* map entry is dead weight; cleared on finalize. */
|
|
120
|
+
/** Lets the result-side mount find the call-side cell. Cleared on finalize. */
|
|
138
121
|
const HANDLES = new Map<string, RenderHandle<unknown>>();
|
|
139
122
|
|
|
140
123
|
export interface MountArgs {
|
|
@@ -191,9 +174,7 @@ function handleFor<S>(
|
|
|
191
174
|
return handle as unknown as RenderHandle<S>;
|
|
192
175
|
}
|
|
193
176
|
|
|
194
|
-
//
|
|
195
|
-
// Segment / Body → ANSI string rendering. Lives here so it's the only place
|
|
196
|
-
// that knows about theme colors + highlighting; renderers stay pure-data.
|
|
177
|
+
// Sole place that knows about theme colors + highlighting; renderers stay pure-data.
|
|
197
178
|
|
|
198
179
|
import { highlight, supportsLanguage } from "cli-highlight";
|
|
199
180
|
|
|
@@ -271,9 +252,7 @@ function renderBody(body: Body, env: Env, diff: DiffSlot, exitCode?: number | nu
|
|
|
271
252
|
}
|
|
272
253
|
}
|
|
273
254
|
|
|
274
|
-
//
|
|
275
|
-
// policy is host-wide display config, not per-tool, so it lives here once and
|
|
276
|
-
// every schema renderer with a kind:"stream" body inherits it for free.
|
|
255
|
+
// Host-wide preview/summary/hidden policy inherited by every kind:"stream" body.
|
|
277
256
|
function renderStream(buffer: string, env: Env, exitCode: number | null | undefined): string {
|
|
278
257
|
const display = buffer.replace(/\n+$/, "");
|
|
279
258
|
if (env.expanded) return theme.fg("toolOutput", display);
|
|
@@ -306,10 +285,7 @@ function lineCountHint(buffer: string, exitCode: number | null | undefined): str
|
|
|
306
285
|
return `${arrow}${theme.fg("muted", label)}`;
|
|
307
286
|
}
|
|
308
287
|
|
|
309
|
-
//
|
|
310
|
-
// Pi-tui Components produced by the adapter. Implement the existing
|
|
311
|
-
// ToolCallView / ToolResultView contracts so the ashi resolver doesn't care
|
|
312
|
-
// whether a renderer is legacy or schema-style.
|
|
288
|
+
// Components that satisfy the legacy ToolCallView / ToolResultView contracts.
|
|
313
289
|
|
|
314
290
|
class SchemaCallComponent extends Container {
|
|
315
291
|
private line: Text;
|
|
@@ -330,7 +306,16 @@ class SchemaCallComponent extends Container {
|
|
|
330
306
|
const display = this.handle.model.view(this.handle.cell.state as ViewState<unknown>, this.handle.cell.env);
|
|
331
307
|
const icon = iconString(display.titleIcon);
|
|
332
308
|
const title = segmentsToString(display.title);
|
|
333
|
-
|
|
309
|
+
const status = statusSuffix(display.status);
|
|
310
|
+
if (display.titleRight && display.titleRight.length > 0) {
|
|
311
|
+
const right = segmentsToString(display.titleRight);
|
|
312
|
+
// env.width − 2 accounts for Text's paddingX=1 on each side.
|
|
313
|
+
const used = visibleWidth(icon) + visibleWidth(title) + visibleWidth(status) + visibleWidth(right);
|
|
314
|
+
const pad = " ".repeat(Math.max(2, this.handle.cell.env.width - 2 - used));
|
|
315
|
+
this.line.setText(`${icon}${title}${status}${pad}${right}`);
|
|
316
|
+
} else {
|
|
317
|
+
this.line.setText(`${icon}${title}${status}`);
|
|
318
|
+
}
|
|
334
319
|
}
|
|
335
320
|
}
|
|
336
321
|
|
|
@@ -369,9 +354,8 @@ class SchemaResultComponent extends Container {
|
|
|
369
354
|
const env = this.handle.cell.env;
|
|
370
355
|
const display = this.handle.model.view(this.handle.cell.state as ViewState<unknown>, env);
|
|
371
356
|
if (!display.body) { this.body.setText(""); return; }
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
// Other kinds show iff expanded or the view requested defaultExpanded.
|
|
357
|
+
// stream embeds the preview/summary/hidden policy; diff shows in preview
|
|
358
|
+
// or when expanded; other kinds show only when expanded/defaultExpanded.
|
|
375
359
|
if (display.body.kind === "diff" && !env.expanded && env.mode !== "preview") {
|
|
376
360
|
this.body.setText("");
|
|
377
361
|
return;
|
|
@@ -385,11 +369,6 @@ class SchemaResultComponent extends Container {
|
|
|
385
369
|
}
|
|
386
370
|
}
|
|
387
371
|
|
|
388
|
-
// ---------------------------------------------------------------------------
|
|
389
|
-
// Public mount functions used by hooks.ts when resolving a schema-style
|
|
390
|
-
// renderer. Each returns a Component that satisfies the legacy view contract,
|
|
391
|
-
// so the rest of ashi doesn't need to know schema renderers exist.
|
|
392
|
-
|
|
393
372
|
export interface MountEnv {
|
|
394
373
|
width: number;
|
|
395
374
|
mode: Env["mode"];
|
|
@@ -44,7 +44,25 @@ export interface CompactionEntry {
|
|
|
44
44
|
tokensBefore: number;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
/** Omitted from buildMessages — the agent already saw it via <shell_events>
|
|
48
|
+
* (or didn't, if private). The frontend replays it for scrollback fidelity. */
|
|
49
|
+
export interface ShellExchangeEntry {
|
|
50
|
+
type: "shell-exchange";
|
|
51
|
+
id: string;
|
|
52
|
+
parentId: string;
|
|
53
|
+
timestamp: number;
|
|
54
|
+
command: string;
|
|
55
|
+
output: string;
|
|
56
|
+
exitCode: number | null;
|
|
57
|
+
cwd?: string;
|
|
58
|
+
private?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type SessionEntry =
|
|
62
|
+
| SessionHeaderEntry
|
|
63
|
+
| MessageEntry
|
|
64
|
+
| CompactionEntry
|
|
65
|
+
| ShellExchangeEntry;
|
|
48
66
|
|
|
49
67
|
export interface SessionMeta {
|
|
50
68
|
name?: string;
|
|
@@ -96,13 +114,22 @@ export function summarizeMessage(m: AgentMessage): string {
|
|
|
96
114
|
return `${role}: ${snippet(extractText(m.content), 500)}`;
|
|
97
115
|
}
|
|
98
116
|
|
|
117
|
+
/** For displayed user text. Loops because both wrappers can stack at the head. */
|
|
118
|
+
export function stripContextWrappers(content: string): string {
|
|
119
|
+
let out = content;
|
|
120
|
+
for (;;) {
|
|
121
|
+
const next = out.replace(/^\s*<(query_context|dynamic_context)>[\s\S]*?<\/\1>\s*/, "");
|
|
122
|
+
if (next === out) return out;
|
|
123
|
+
out = next;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
99
127
|
export function renderEvictedSummary(evicted: AgentMessage[]): string {
|
|
100
128
|
const lines = evicted.map((m) => `- ${summarizeMessage(m)}`);
|
|
101
129
|
return `${lines.length} message(s) elided\n${lines.join("\n")}`;
|
|
102
130
|
}
|
|
103
131
|
|
|
104
|
-
/**
|
|
105
|
-
* Tree is implicit via parentId pointers; entries kept in memory after load. */
|
|
132
|
+
/** Tree is implicit via parentId pointers; entries are kept in memory after load. */
|
|
106
133
|
export class SessionStore {
|
|
107
134
|
private entriesPath: string;
|
|
108
135
|
private leafPath: string;
|
|
@@ -170,9 +197,6 @@ export class SessionStore {
|
|
|
170
197
|
this.persistMeta();
|
|
171
198
|
}
|
|
172
199
|
|
|
173
|
-
/** Append messages as a chain of MessageEntry, each parented at the
|
|
174
|
-
* previously appended id (starting from current leaf). Returns the new
|
|
175
|
-
* entry ids in order. */
|
|
176
200
|
async appendMessages(messages: AgentMessage[]): Promise<string[]> {
|
|
177
201
|
if (messages.length === 0) return [];
|
|
178
202
|
this.flushHeader();
|
|
@@ -198,6 +222,32 @@ export class SessionStore {
|
|
|
198
222
|
return newIds;
|
|
199
223
|
}
|
|
200
224
|
|
|
225
|
+
async appendShellExchange(e: {
|
|
226
|
+
command: string;
|
|
227
|
+
output: string;
|
|
228
|
+
exitCode: number | null;
|
|
229
|
+
cwd?: string;
|
|
230
|
+
private?: boolean;
|
|
231
|
+
}): Promise<string> {
|
|
232
|
+
this.flushHeader();
|
|
233
|
+
const entry: ShellExchangeEntry = {
|
|
234
|
+
type: "shell-exchange",
|
|
235
|
+
id: newEntryId(),
|
|
236
|
+
parentId: this.activeLeaf,
|
|
237
|
+
timestamp: Date.now(),
|
|
238
|
+
command: e.command,
|
|
239
|
+
output: e.output,
|
|
240
|
+
exitCode: e.exitCode,
|
|
241
|
+
...(e.cwd !== undefined ? { cwd: e.cwd } : {}),
|
|
242
|
+
...(e.private ? { private: true } : {}),
|
|
243
|
+
};
|
|
244
|
+
this.entries.set(entry.id, entry);
|
|
245
|
+
this.activeLeaf = entry.id;
|
|
246
|
+
await fsp.appendFile(this.entriesPath, JSON.stringify(entry) + "\n");
|
|
247
|
+
this.persistLeaf();
|
|
248
|
+
return entry.id;
|
|
249
|
+
}
|
|
250
|
+
|
|
201
251
|
async appendCompaction(firstKeptId: string, tokensBefore: number, summary?: string): Promise<string> {
|
|
202
252
|
if (!this.entries.has(firstKeptId)) throw new Error(`firstKeptId unknown: ${firstKeptId}`);
|
|
203
253
|
this.flushHeader();
|
|
@@ -217,7 +267,7 @@ export class SessionStore {
|
|
|
217
267
|
return e.id;
|
|
218
268
|
}
|
|
219
269
|
|
|
220
|
-
/**
|
|
270
|
+
/** Oldest-first walk from leaf to root. */
|
|
221
271
|
getBranch(leafId: string = this.activeLeaf): SessionEntry[] {
|
|
222
272
|
const out: SessionEntry[] = [];
|
|
223
273
|
const seen = new Set<string>();
|
|
@@ -232,9 +282,7 @@ export class SessionStore {
|
|
|
232
282
|
return out.reverse();
|
|
233
283
|
}
|
|
234
284
|
|
|
235
|
-
/**
|
|
236
|
-
* latest compaction on the branch (summary + kept tail). Mirrors pi's
|
|
237
|
-
* buildSessionContext. */
|
|
285
|
+
/** Honors the latest compaction on the branch (summary + kept tail). */
|
|
238
286
|
buildMessages(leafId: string = this.activeLeaf): AgentMessage[] {
|
|
239
287
|
const branch = this.getBranch(leafId);
|
|
240
288
|
let compactionIdx = -1;
|
|
@@ -265,12 +313,11 @@ export class SessionStore {
|
|
|
265
313
|
return out;
|
|
266
314
|
}
|
|
267
315
|
|
|
268
|
-
/** A short, human-friendly preview for picker rows. Uses the first user
|
|
269
|
-
* message's text when available, else the session id. */
|
|
270
316
|
getPreview(): string {
|
|
271
317
|
for (const e of this.entries.values()) {
|
|
272
318
|
if (e.type === "message" && e.message.role === "user") {
|
|
273
|
-
const
|
|
319
|
+
const raw = typeof e.message.content === "string" ? e.message.content : "";
|
|
320
|
+
const txt = stripContextWrappers(raw);
|
|
274
321
|
if (txt) return txt.slice(0, 80);
|
|
275
322
|
}
|
|
276
323
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface ChangeHandlerResult {
|
|
2
|
+
mode: boolean;
|
|
3
|
+
/** When set, caller must `editor.setText(replaceText)` to strip the `!`. */
|
|
4
|
+
replaceText?: string;
|
|
5
|
+
/** Whether the next submit (if in shell mode) is marked private. */
|
|
6
|
+
pendingPrivate: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Strips `!` (entry), `!!` (entry + private), in-mode `!` (upgrade to private).
|
|
10
|
+
* Shell mode is sticky — exit only via the Backspace-on-empty intercept;
|
|
11
|
+
* auto-exit on empty text would fire during pi-tui's pre-emptive onChange("")
|
|
12
|
+
* inside Editor.submitValue() and misroute the submit. pendingPrivate is
|
|
13
|
+
* sticky for the same reason. */
|
|
14
|
+
export function deriveChangeHandlerResult(
|
|
15
|
+
mode: boolean,
|
|
16
|
+
pendingPrivate: boolean,
|
|
17
|
+
text: string,
|
|
18
|
+
): ChangeHandlerResult {
|
|
19
|
+
if (!mode && text.startsWith("!!")) {
|
|
20
|
+
return { mode: true, replaceText: text.slice(2), pendingPrivate: true };
|
|
21
|
+
}
|
|
22
|
+
if (!mode && text.startsWith("!")) {
|
|
23
|
+
return { mode: true, replaceText: text.slice(1), pendingPrivate: false };
|
|
24
|
+
}
|
|
25
|
+
if (mode && text.startsWith("!")) {
|
|
26
|
+
return { mode: true, replaceText: text.slice(1), pendingPrivate: true };
|
|
27
|
+
}
|
|
28
|
+
return { mode, pendingPrivate: pendingPrivate && mode };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type SubmitAction =
|
|
32
|
+
| { kind: "noop" }
|
|
33
|
+
| { kind: "shell"; line: string; private: boolean }
|
|
34
|
+
| { kind: "command"; name: string; args: string }
|
|
35
|
+
| { kind: "agent"; query: string };
|
|
36
|
+
|
|
37
|
+
export function classifySubmit(
|
|
38
|
+
text: string,
|
|
39
|
+
shellMode: boolean,
|
|
40
|
+
pendingPrivate: boolean,
|
|
41
|
+
): SubmitAction {
|
|
42
|
+
const query = text.trim();
|
|
43
|
+
if (!query) return { kind: "noop" };
|
|
44
|
+
if (shellMode) return { kind: "shell", line: query, private: pendingPrivate };
|
|
45
|
+
if (query.startsWith("/")) {
|
|
46
|
+
const sp = query.indexOf(" ");
|
|
47
|
+
const name = sp === -1 ? query : query.slice(0, sp);
|
|
48
|
+
const args = sp === -1 ? "" : query.slice(sp + 1).trim();
|
|
49
|
+
return { kind: "command", name, args };
|
|
50
|
+
}
|
|
51
|
+
return { kind: "agent", query };
|
|
52
|
+
}
|
|
@@ -12,6 +12,7 @@ interface StatusFields {
|
|
|
12
12
|
tokens?: number;
|
|
13
13
|
compactions?: number;
|
|
14
14
|
thinking?: string;
|
|
15
|
+
shellMode?: "off" | "on" | "private";
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export class StatusFooter extends Container {
|
|
@@ -40,12 +41,25 @@ export class StatusFooter extends Container {
|
|
|
40
41
|
|
|
41
42
|
private repaint(width: number): void {
|
|
42
43
|
const contentWidth = width > 0 ? Math.max(1, width - 2) : 0;
|
|
44
|
+
const right = this.buildRight();
|
|
45
|
+
const rightWidth = visibleWidth(right);
|
|
46
|
+
const join = (left: string): string => {
|
|
47
|
+
if (!right) return left;
|
|
48
|
+
const leftWidth = visibleWidth(left);
|
|
49
|
+
const gap = Math.max(1, contentWidth - leftWidth - rightWidth);
|
|
50
|
+
return `${left}${" ".repeat(gap)}${right}`;
|
|
51
|
+
};
|
|
43
52
|
const full = this.buildLine("full");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
const fullFits = contentWidth === 0
|
|
54
|
+
|| visibleWidth(full) + (right ? rightWidth + 1 : 0) <= contentWidth;
|
|
55
|
+
this.text.setText(fullFits ? join(full) : join(this.buildLine("basename")));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private buildRight(): string {
|
|
59
|
+
const mode = this.fields.shellMode;
|
|
60
|
+
if (mode === "on") return theme.fg("bashMode", "▸ shell");
|
|
61
|
+
if (mode === "private") return theme.fg("bashModePrivate", "▸ shell · private");
|
|
62
|
+
return "";
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
private buildLine(cwdMode: "full" | "basename"): string {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-sh",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "A shell-first terminal where AI is one keystroke away",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"types": "./dist/shell/terminal.d.ts",
|
|
50
50
|
"default": "./dist/shell/terminal.js"
|
|
51
51
|
},
|
|
52
|
+
"./shell/context": {
|
|
53
|
+
"types": "./dist/shell/shell-context.d.ts",
|
|
54
|
+
"default": "./dist/shell/shell-context.js"
|
|
55
|
+
},
|
|
52
56
|
"./utils/stream-transform": {
|
|
53
57
|
"types": "./dist/utils/stream-transform.d.ts",
|
|
54
58
|
"default": "./dist/utils/stream-transform.js"
|