agent-sh 0.14.1 → 0.14.2

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.
Files changed (55) hide show
  1. package/dist/agent/agent-loop.d.ts +1 -1
  2. package/dist/agent/agent-loop.js +42 -31
  3. package/dist/agent/conversation-state.d.ts +3 -2
  4. package/dist/agent/conversation-state.js +20 -3
  5. package/dist/agent/events.d.ts +2 -0
  6. package/dist/agent/host-types.d.ts +3 -0
  7. package/dist/agent/index.js +2 -1
  8. package/dist/agent/subagent.d.ts +1 -1
  9. package/dist/agent/subagent.js +5 -1
  10. package/dist/agent/tool-protocol.d.ts +2 -2
  11. package/dist/agent/tool-protocol.js +5 -4
  12. package/dist/agent/tools/glob.d.ts +1 -1
  13. package/dist/agent/tools/glob.js +4 -2
  14. package/dist/agent/tools/grep.d.ts +1 -1
  15. package/dist/agent/tools/grep.js +4 -2
  16. package/dist/agent/tools/ls.d.ts +1 -1
  17. package/dist/agent/tools/ls.js +4 -2
  18. package/dist/agent/tools/read-file.d.ts +1 -1
  19. package/dist/agent/tools/read-file.js +30 -2
  20. package/dist/agent/types.d.ts +11 -1
  21. package/dist/agent/types.js +6 -1
  22. package/dist/cli/index.js +0 -0
  23. package/dist/core/index.d.ts +1 -1
  24. package/dist/core/settings.d.ts +3 -0
  25. package/dist/core/settings.js +2 -2
  26. package/dist/shell/index.d.ts +6 -0
  27. package/dist/shell/index.js +10 -10
  28. package/dist/shell/shell.d.ts +4 -0
  29. package/dist/shell/shell.js +15 -29
  30. package/dist/shell/terminal.d.ts +33 -0
  31. package/dist/shell/terminal.js +62 -0
  32. package/examples/extensions/ash-scheme/index.ts +2170 -0
  33. package/examples/extensions/ash-scheme/package.json +11 -0
  34. package/examples/extensions/ash-scheme-render.ts +58 -0
  35. package/examples/extensions/ashi/README.md +36 -26
  36. package/examples/extensions/ashi/package.json +9 -1
  37. package/examples/extensions/ashi/src/capture.ts +1 -0
  38. package/examples/extensions/ashi/src/cli.ts +21 -7
  39. package/examples/extensions/ashi/src/compaction.ts +25 -96
  40. package/examples/extensions/ashi/src/components.ts +64 -166
  41. package/examples/extensions/ashi/src/default-schema-renderers.ts +229 -0
  42. package/examples/extensions/ashi/src/display-config.ts +21 -22
  43. package/examples/extensions/ashi/src/frontend.ts +64 -65
  44. package/examples/extensions/ashi/src/hooks.ts +47 -63
  45. package/examples/extensions/ashi/src/multi-session-store.ts +44 -3
  46. package/examples/extensions/ashi/src/schema.ts +407 -0
  47. package/examples/extensions/ashi/src/session-store.ts +55 -4
  48. package/examples/extensions/ashi/src/status-footer.ts +27 -6
  49. package/examples/extensions/ashi-compact-llm.ts +93 -0
  50. package/examples/extensions/claude-code-bridge/index.ts +2 -0
  51. package/examples/extensions/opencode-bridge/index.ts +3 -0
  52. package/examples/extensions/opencode-provider.ts +252 -0
  53. package/examples/extensions/pi-bridge/index.ts +1 -0
  54. package/package.json +12 -1
  55. package/examples/extensions/ashi/src/default-renderers.ts +0 -171
@@ -147,6 +147,7 @@ export default function activate(ctx: ExtensionContext): void {
147
147
  announcedTools.add(callID);
148
148
  bus.emit("agent:tool-started", {
149
149
  title: toolName,
150
+ name: toolName,
150
151
  toolCallId: callID,
151
152
  kind,
152
153
  locations: toolLocations(state.input ?? {}),
@@ -290,6 +291,7 @@ export default function activate(ctx: ExtensionContext): void {
290
291
  : req.questions.map((q, i) => `${q.header || `Q${i + 1}`}: ${q.question}`).join("; ");
291
292
  bus.emit("agent:tool-started", {
292
293
  title: "question",
294
+ name: "question",
293
295
  toolCallId: callID,
294
296
  kind: "execute",
295
297
  displayDetail: detail,
@@ -355,6 +357,7 @@ export default function activate(ctx: ExtensionContext): void {
355
357
  const summary = opts?.note ? `denied (${opts.note})` : `denied: ${detail}`;
356
358
  bus.emit("agent:tool-started", {
357
359
  title: "permission",
360
+ name: "permission",
358
361
  toolCallId: callID,
359
362
  kind: "execute",
360
363
  displayDetail: detail,
@@ -0,0 +1,252 @@
1
+ /**
2
+ * opencode-provider — OpenCode Zen & Go LLM providers for agent-sh
3
+ *
4
+ * Registers two providers with runtime model discovery:
5
+ * - opencode — Zen tier (https://opencode.ai/zen/v1)
6
+ * - opencode-go — Go tier (https://opencode.ai/zen/go/v1)
7
+ *
8
+ * Both are OpenAI-compatible endpoints. OpenCode's backend proxies
9
+ * all models (OpenAI, Anthropic, Google, etc.) through them — no
10
+ * per-model transport routing needed at the agent-sh level.
11
+ *
12
+ * ## Setup
13
+ * export OPENCODE_***REDACTED***
14
+ * agent-sh -e ./examples/extensions/opencode-provider.ts
15
+ *
16
+ * # Or add to settings.json:
17
+ * { "extensions": ["./examples/extensions/opencode-provider.ts"] }
18
+ *
19
+ * # Or store via auth:
20
+ * agent-sh auth login opencode
21
+ *
22
+ * ## Model discovery
23
+ * On startup the extension:
24
+ * 1. Fetches official /models endpoints (authoritative model list)
25
+ * 2. Merges metadata from models.dev (context windows, reasoning flags)
26
+ * 3. Falls back to models.dev membership → conservative defaults
27
+ *
28
+ * Usage:
29
+ * /model — tab-completes all discovered models
30
+ * /provider — switch between opencode / opencode-go
31
+ */
32
+
33
+ import type { AgentContext } from "agent-sh/types";
34
+ import { resolveApiKey } from "agent-sh/auth";
35
+
36
+ // ── Constants ──────────────────────────────────────────────────────
37
+
38
+ const ZEN_BASE_URL = "https://opencode.ai/zen/v1";
39
+ const GO_BASE_URL = "https://opencode.ai/zen/go/v1";
40
+ const ZEN_MODELS_ENDPOINT = `${ZEN_BASE_URL}/models`;
41
+ const GO_MODELS_ENDPOINT = `${GO_BASE_URL}/models`;
42
+ const MODELS_DEV_ENDPOINT = "https://models.dev/api.json";
43
+
44
+ /** Conservative defaults when models.dev metadata is unavailable. */
45
+ const DEFAULT_CONTEXT_WINDOW = 128_000;
46
+ const DEFAULT_MAX_TOKENS = 16_384;
47
+
48
+ // ── Fallback model lists (curated; kept in sync with OpenCode docs) ──
49
+
50
+ // Single fallback model per tier — the live /models catalog replaces these on startup.
51
+ const ZEN_FALLBACK_MODELS = ["claude-sonnet-4-6"];
52
+
53
+ const GO_FALLBACK_MODELS = ["gpt-5.2"];
54
+
55
+ // ── Types ───────────────────────────────────────────────────────────
56
+
57
+ interface ModelsDevLimit {
58
+ context?: number;
59
+ output?: number;
60
+ }
61
+
62
+ interface ModelsDevModelEntry {
63
+ id?: string;
64
+ name?: string;
65
+ reasoning?: boolean;
66
+ limit?: ModelsDevLimit;
67
+ modalities?: { input?: readonly string[] };
68
+ }
69
+
70
+ interface ModelsDevProviderEntry {
71
+ models?: Record<string, ModelsDevModelEntry>;
72
+ }
73
+
74
+ type ModelsDevResponse = Record<string, ModelsDevProviderEntry>;
75
+
76
+ interface OpenCodeModelListEntry {
77
+ id?: string;
78
+ }
79
+
80
+ interface OpenCodeModelListResponse {
81
+ data?: OpenCodeModelListEntry[];
82
+ }
83
+
84
+ interface ModelDef {
85
+ id: string;
86
+ reasoning: boolean;
87
+ contextWindow: number;
88
+ maxTokens: number;
89
+ modalities: ("text" | "image")[];
90
+ }
91
+
92
+ // ── Helpers ─────────────────────────────────────────────────────────
93
+
94
+ async function fetchJson<T>(url: string): Promise<T> {
95
+ const res = await fetch(url, {
96
+ headers: { Accept: "application/json" },
97
+ signal: AbortSignal.timeout(15_000),
98
+ });
99
+ if (!res.ok) {
100
+ throw new Error(`HTTP ${res.status} from ${url}`);
101
+ }
102
+ return res.json() as T;
103
+ }
104
+
105
+ function normalizePosNum(v: unknown): number | undefined {
106
+ return typeof v === "number" && Number.isFinite(v) && v > 0 ? v : undefined;
107
+ }
108
+
109
+ // ── models.dev ──────────────────────────────────────────────────────
110
+
111
+ async function fetchModelsDev(): Promise<ModelsDevResponse | undefined> {
112
+ try {
113
+ const payload = await fetchJson<ModelsDevResponse>(MODELS_DEV_ENDPOINT);
114
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return undefined;
115
+ return payload;
116
+ } catch {
117
+ return undefined;
118
+ }
119
+ }
120
+
121
+ function getModelsDevModel(
122
+ provider: ModelsDevProviderEntry | undefined,
123
+ modelId: string,
124
+ ): ModelsDevModelEntry | undefined {
125
+ const direct = provider?.models?.[modelId];
126
+ if (direct) return direct;
127
+ if (!provider?.models) return undefined;
128
+ for (const m of Object.values(provider.models)) {
129
+ if (m.id === modelId) return m;
130
+ }
131
+ return undefined;
132
+ }
133
+
134
+ // ── Official /models ────────────────────────────────────────────────
135
+
136
+ async function fetchOfficialModelIds(url: string): Promise<string[]> {
137
+ try {
138
+ const payload = await fetchJson<OpenCodeModelListResponse>(url);
139
+ if (!Array.isArray(payload.data)) throw new Error("Unexpected format");
140
+ const ids = new Set<string>();
141
+ for (const entry of payload.data) {
142
+ if (typeof entry.id === "string" && entry.id.trim()) {
143
+ ids.add(entry.id.trim());
144
+ }
145
+ }
146
+ return Array.from(ids);
147
+ } catch {
148
+ return [];
149
+ }
150
+ }
151
+
152
+ // ── Merge ───────────────────────────────────────────────────────────
153
+
154
+ function resolveModel(
155
+ modelId: string,
156
+ metadata: ModelsDevModelEntry | undefined,
157
+ ): ModelDef {
158
+ const rawModalities = metadata?.modalities?.input;
159
+ const modalities: ("text" | "image")[] = Array.isArray(rawModalities)
160
+ ? rawModalities.filter((v): v is "text" | "image" => v === "text" || v === "image")
161
+ : ["text"];
162
+ return {
163
+ id: modelId,
164
+ reasoning: metadata?.reasoning ?? false,
165
+ contextWindow: normalizePosNum(metadata?.limit?.context) ?? DEFAULT_CONTEXT_WINDOW,
166
+ maxTokens: normalizePosNum(metadata?.limit?.output) ?? DEFAULT_MAX_TOKENS,
167
+ modalities,
168
+ };
169
+ }
170
+
171
+ // ── Reasoning params (OpenAI-compatible) ────────────────────────────
172
+
173
+ function buildReasoningParams(level: string): Record<string, unknown> {
174
+ if (level === "off") return {};
175
+ return { reasoning_effort: level === "xhigh" ? "high" : level };
176
+ }
177
+
178
+ // ── Activation ──────────────────────────────────────────────────────
179
+
180
+ export default function activate(ctx: AgentContext): void {
181
+ const apiKey =
182
+ process.env.OPENCODE_API_KEY ??
183
+ resolveApiKey("opencode").key ?? undefined;
184
+
185
+ // ── Phase 1: register both providers synchronously with fallback models ──
186
+
187
+ ctx.agent.providers.configure("opencode", { reasoningParams: buildReasoningParams });
188
+ ctx.agent.providers.register({
189
+ id: "opencode",
190
+ apiKey,
191
+ baseURL: ZEN_BASE_URL,
192
+ defaultModel: ZEN_FALLBACK_MODELS[0],
193
+ models: ZEN_FALLBACK_MODELS,
194
+ supportsReasoningEffort: true,
195
+ });
196
+
197
+ ctx.agent.providers.configure("opencode-go", { reasoningParams: buildReasoningParams });
198
+ ctx.agent.providers.register({
199
+ id: "opencode-go",
200
+ apiKey,
201
+ baseURL: GO_BASE_URL,
202
+ defaultModel: GO_FALLBACK_MODELS[0],
203
+ models: GO_FALLBACK_MODELS,
204
+ supportsReasoningEffort: true,
205
+ });
206
+
207
+ if (!apiKey) return;
208
+
209
+ // ── Phase 2: fetch live catalogs and re-register with enriched metadata ──
210
+
211
+ fetchModelsDev()
212
+ .then(async (modelsDev) => {
213
+ const zenProvider = modelsDev?.opencode;
214
+ const goProvider = modelsDev?.["opencode-go"];
215
+
216
+ const [zenIds, goIds] = await Promise.all([
217
+ fetchOfficialModelIds(ZEN_MODELS_ENDPOINT),
218
+ fetchOfficialModelIds(GO_MODELS_ENDPOINT),
219
+ ]);
220
+
221
+ const resolveModels = (
222
+ ids: string[],
223
+ provider: ModelsDevProviderEntry | undefined,
224
+ fallback: string[],
225
+ ): ModelDef[] => {
226
+ const source = ids.length > 0 ? ids : fallback;
227
+ return source.map((id) => resolveModel(id, getModelsDevModel(provider, id)));
228
+ };
229
+
230
+ const zenModels = resolveModels(zenIds, zenProvider, ZEN_FALLBACK_MODELS);
231
+ const goModels = resolveModels(goIds, goProvider, GO_FALLBACK_MODELS);
232
+
233
+ ctx.agent.providers.register({
234
+ id: "opencode",
235
+ apiKey,
236
+ baseURL: ZEN_BASE_URL,
237
+ defaultModel: zenModels[0]?.id ?? ZEN_FALLBACK_MODELS[0],
238
+ models: zenModels,
239
+ supportsReasoningEffort: true,
240
+ });
241
+
242
+ ctx.agent.providers.register({
243
+ id: "opencode-go",
244
+ apiKey,
245
+ baseURL: GO_BASE_URL,
246
+ defaultModel: goModels[0]?.id ?? GO_FALLBACK_MODELS[0],
247
+ models: goModels,
248
+ supportsReasoningEffort: true,
249
+ });
250
+ })
251
+ .catch(() => {});
252
+ }
@@ -206,6 +206,7 @@ export default function activate(ctx: ExtensionContext): void {
206
206
  }
207
207
  bus.emit("agent:tool-started", {
208
208
  title: ev.toolName,
209
+ name: ev.toolName,
209
210
  toolCallId: ev.toolCallId,
210
211
  kind: kindForTool(ev.toolName),
211
212
  rawInput: ev.args,
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "agent-sh",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "A shell-first terminal where AI is one keystroke away",
5
5
  "type": "module",
6
+ "workspaces": [
7
+ "examples/extensions/*"
8
+ ],
6
9
  "main": "dist/core/index.js",
7
10
  "types": "dist/core/index.d.ts",
8
11
  "bin": {
@@ -38,6 +41,14 @@
38
41
  "types": "./dist/shell/shell.d.ts",
39
42
  "default": "./dist/shell/shell.js"
40
43
  },
44
+ "./shell/strategies": {
45
+ "types": "./dist/shell/strategies/index.d.ts",
46
+ "default": "./dist/shell/strategies/index.js"
47
+ },
48
+ "./shell/terminal": {
49
+ "types": "./dist/shell/terminal.d.ts",
50
+ "default": "./dist/shell/terminal.js"
51
+ },
41
52
  "./utils/stream-transform": {
42
53
  "types": "./dist/utils/stream-transform.d.ts",
43
54
  "default": "./dist/utils/stream-transform.js"
@@ -1,171 +0,0 @@
1
- import { Container, Spacer, Text } from "@earendil-works/pi-tui";
2
- import type { ExtensionContext } from "agent-sh/types";
3
- import { theme } from "./theme.js";
4
- import { GROUP_ICONS } from "./components.js";
5
- import type { ToolCallArgs, ToolCallView } from "./hooks.js";
6
-
7
- const TOOL_ICON: Record<string, string> = {
8
- read_file: GROUP_ICONS.read!,
9
- read: GROUP_ICONS.read!,
10
- ls: GROUP_ICONS.read!,
11
- grep: GROUP_ICONS.search!,
12
- glob: GROUP_ICONS.search!,
13
- edit: "✎",
14
- edit_file: "✎",
15
- write: "✎",
16
- write_file: "✎",
17
- };
18
-
19
- function iconPrefix(name: string): string {
20
- const icon = TOOL_ICON[name] ?? "⚙";
21
- return `${theme.fg("warning", icon)} `;
22
- }
23
-
24
- interface StatusOpts { exitCode: number | null; elapsedMs: number; summary?: string }
25
-
26
- function fmtElapsed(ms: number): string {
27
- if (ms < 1000) return `${ms}ms`;
28
- if (ms < 10_000) return `${(ms / 1000).toFixed(2)}s`;
29
- if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
30
- const totalSeconds = Math.floor(ms / 1000);
31
- const m = Math.floor(totalSeconds / 60);
32
- const s = totalSeconds % 60;
33
- return `${m}m ${s}s`;
34
- }
35
-
36
- function parseRaw(raw: unknown): Record<string, unknown> {
37
- if (typeof raw === "string") {
38
- try { return JSON.parse(raw) as Record<string, unknown>; } catch { return {}; }
39
- }
40
- if (raw && typeof raw === "object") return raw as Record<string, unknown>;
41
- return {};
42
- }
43
-
44
- function str(v: unknown): string | undefined {
45
- return typeof v === "string" && v.length > 0 ? v : undefined;
46
- }
47
-
48
- function num(v: unknown): number | undefined {
49
- return typeof v === "number" && Number.isFinite(v) ? v : undefined;
50
- }
51
-
52
- function relativize(fp: string): string {
53
- const home = process.env.HOME;
54
- const cwd = process.cwd();
55
- if (fp.startsWith(`${cwd}/`)) return fp.slice(cwd.length + 1);
56
- if (home && fp.startsWith(`${home}/`)) return `~/${fp.slice(home.length + 1)}`;
57
- return fp;
58
- }
59
-
60
- function statusSuffix(opts?: StatusOpts): string {
61
- if (!opts) return ` ${theme.fg("muted", "…")}`;
62
- const ok = opts.exitCode === null || opts.exitCode === 0;
63
- const mark = ok ? theme.fg("success", "✓") : theme.fg("error", "✗");
64
- const elapsed = opts.elapsedMs > 0 ? ` ${theme.fg("muted", fmtElapsed(opts.elapsedMs))}` : "";
65
- const sum = opts.summary ? ` ${theme.fg("muted", opts.summary)}` : "";
66
- return ` ${mark}${elapsed}${sum}`;
67
- }
68
-
69
- /** Renders a one-line tool call header from a label producer. The label is
70
- * recomputed on setStatus so the trailing status mark updates in place. */
71
- class LabeledCallLine extends Container implements ToolCallView {
72
- private line: Text;
73
- private status?: StatusOpts;
74
- constructor(private label: () => string) {
75
- super();
76
- this.line = new Text("", 1, 0);
77
- this.addChild(new Spacer(1));
78
- this.addChild(this.line);
79
- this.repaint();
80
- }
81
- setStatus(opts: StatusOpts): void {
82
- this.status = opts;
83
- this.repaint();
84
- }
85
- private repaint(): void {
86
- this.line.setText(`${this.label()}${statusSuffix(this.status)}`);
87
- }
88
- }
89
-
90
- const bold = (t: string): string => theme.bold(theme.fg("toolTitle", t));
91
- const accent = (t: string): string => theme.fg("accent", t);
92
- const muted = (t: string): string => theme.fg("muted", t);
93
-
94
- function bashLabel(args: ToolCallArgs): string {
95
- const r = parseRaw(args.rawInput);
96
- const command = str(r.command) ?? "…";
97
- const timeout = num(r.timeout);
98
- const to = timeout ? muted(` (timeout ${timeout}s)`) : "";
99
- return `${bold("$")} ${accent(command)}${to}`;
100
- }
101
-
102
- function readLabel(args: ToolCallArgs): string {
103
- const r = parseRaw(args.rawInput);
104
- const path = str(r.file_path) ?? str(r.path);
105
- const offset = num(r.offset);
106
- const limit = num(r.limit);
107
- let range = "";
108
- if (offset !== undefined || limit !== undefined) {
109
- const from = offset ?? 1;
110
- const to = limit !== undefined ? from + limit - 1 : undefined;
111
- range = theme.fg("warning", to ? `:${from}-${to}` : `:${from}`);
112
- }
113
- return `${iconPrefix("read")}${bold("read")} ${accent(path ? relativize(path) : "…")}${range}`;
114
- }
115
-
116
- function grepLabel(args: ToolCallArgs): string {
117
- const r = parseRaw(args.rawInput);
118
- const pattern = str(r.pattern) ?? "…";
119
- const scope = relativize(str(r.path) ?? ".");
120
- const glob = str(r.glob);
121
- const limit = num(r.limit);
122
- const extras = [glob ? `(${glob})` : "", limit !== undefined ? `limit ${limit}` : ""].filter(Boolean).join(" ");
123
- const tail = extras ? muted(` ${extras}`) : "";
124
- return `${iconPrefix("grep")}${bold("grep")} ${accent(`/${pattern}/`)} ${muted(`in ${scope}`)}${tail}`;
125
- }
126
-
127
- function globLabel(args: ToolCallArgs): string {
128
- const r = parseRaw(args.rawInput);
129
- const pattern = str(r.pattern) ?? "…";
130
- const scope = relativize(str(r.path) ?? ".");
131
- return `${iconPrefix("glob")}${bold("glob")} ${accent(pattern)} ${muted(`in ${scope}`)}`;
132
- }
133
-
134
- function lsLabel(args: ToolCallArgs): string {
135
- const r = parseRaw(args.rawInput);
136
- const p = str(r.path) ?? ".";
137
- return `${iconPrefix("ls")}${bold("ls")} ${accent(relativize(p))}`;
138
- }
139
-
140
- function pathOnlyLabel(name: string, args: ToolCallArgs): string {
141
- const r = parseRaw(args.rawInput);
142
- const path = str(r.file_path) ?? str(r.path);
143
- return `${iconPrefix(name)}${bold(name)} ${accent(path ? relativize(path) : "…")}`;
144
- }
145
-
146
- function genericLabel(args: ToolCallArgs): string {
147
- const detail = args.displayDetail ? ` ${muted(args.displayDetail)}` : "";
148
- return `${iconPrefix(args.name)}${bold(args.title)}${detail}`;
149
- }
150
-
151
- export function registerDefaultToolRenderers(ctx: ExtensionContext): void {
152
- const define = (name: string, fn: (args: ToolCallArgs) => ToolCallView): void => {
153
- ctx.define(`ashi:render-tool-call:${name}`, fn);
154
- };
155
-
156
- define("bash", (args) => new LabeledCallLine(() => bashLabel(args)));
157
-
158
- define("read_file", (args) => new LabeledCallLine(() => readLabel(args)));
159
- define("read", (args) => new LabeledCallLine(() => readLabel(args)));
160
-
161
- define("grep", (args) => new LabeledCallLine(() => grepLabel(args)));
162
- define("glob", (args) => new LabeledCallLine(() => globLabel(args)));
163
- define("ls", (args) => new LabeledCallLine(() => lsLabel(args)));
164
-
165
- define("edit_file", (args) => new LabeledCallLine(() => pathOnlyLabel("edit", args)));
166
- define("edit", (args) => new LabeledCallLine(() => pathOnlyLabel("edit", args)));
167
- define("write_file", (args) => new LabeledCallLine(() => pathOnlyLabel("write", args)));
168
- define("write", (args) => new LabeledCallLine(() => pathOnlyLabel("write", args)));
169
-
170
- define("default", (args) => new LabeledCallLine(() => genericLabel(args)));
171
- }