archymedes-cli 2.1.0 → 2.3.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.
@@ -1,24 +1,24 @@
1
1
  import {
2
2
  windowStart
3
- } from "./archymedes-brkqgrxv.mjs";
3
+ } from "./archymedes-4kx65anz.mjs";
4
4
  import {
5
- UNICODE_GLYPHS,
6
5
  joinHorizontal,
7
6
  padToWidth,
8
7
  paginator
9
- } from "./archymedes-dwvn4c51.mjs";
8
+ } from "./archymedes-g8y3rt6t.mjs";
10
9
  import {
11
- NO_COLOR_PALETTE
12
- } from "./archymedes-jecyxv5c.mjs";
10
+ NO_COLOR_PALETTE,
11
+ UNICODE_GLYPHS
12
+ } from "./archymedes-a10k8yrk.mjs";
13
13
  import {
14
14
  __require
15
15
  } from "./archymedes-x67v3n58.mjs";
16
16
 
17
- // packages/archymedes-cli/src/file-screen.tsx
17
+ // src/ui/file-screen.tsx
18
18
  import { useAsync, useInput, useState } from "@termuijs/jsx";
19
19
  import { Box, Text } from "@termuijs/widgets";
20
20
 
21
- // packages/core/src/cli/file-tree.ts
21
+ // ../core/src/cli/file-tree.ts
22
22
  function buildFileTree(paths) {
23
23
  const root = { name: "", path: "", kind: "dir", children: [] };
24
24
  for (const raw of paths) {
@@ -59,7 +59,7 @@ function directorySummary(node) {
59
59
  }
60
60
  return { files, dirs };
61
61
  }
62
- // packages/archymedes-cli/src/file-browser.ts
62
+ // src/ui/file-browser.ts
63
63
  function flattenTree(tree, expanded, depth = 0, trunks = []) {
64
64
  const rows = [];
65
65
  for (const [index, node] of tree.entries()) {
@@ -251,7 +251,7 @@ function previewToLines(preview, width) {
251
251
  }
252
252
  }
253
253
 
254
- // packages/archymedes-cli/src/file-screen.tsx
254
+ // src/ui/file-screen.tsx
255
255
  import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
256
256
  var Panel = Box;
257
257
  var Line = Text;
@@ -0,0 +1,271 @@
1
+ import {
2
+ GUIDE_TOPICS,
3
+ applyViewport,
4
+ newViewport,
5
+ visibleLines,
6
+ wrapText
7
+ } from "./archymedes-sf9t1hz9.mjs";
8
+ import {
9
+ joinHorizontal,
10
+ padToWidth,
11
+ scrollIndicator,
12
+ scrollPercent,
13
+ sliceToWidth
14
+ } from "./archymedes-g8y3rt6t.mjs";
15
+ import"./archymedes-tsne2m7p.mjs";
16
+ import {
17
+ NO_COLOR_PALETTE,
18
+ visibleWidth
19
+ } from "./archymedes-a10k8yrk.mjs";
20
+ import {
21
+ __require
22
+ } from "./archymedes-x67v3n58.mjs";
23
+
24
+ // src/ui/guide-screen.tsx
25
+ import { useInput, useState } from "@termuijs/jsx";
26
+ import { Box, Text } from "@termuijs/widgets";
27
+
28
+ // src/ui/guide-browser.ts
29
+ function initialGuideState(columns, rows, palette = NO_COLOR_PALETTE) {
30
+ return { topics: GUIDE_TOPICS, selected: 0, scroll: 0, query: "", searching: false, columns, rows, palette };
31
+ }
32
+ function visibleTopics(state) {
33
+ const needle = state.query.trim().toLowerCase();
34
+ if (!needle)
35
+ return [...state.topics];
36
+ return state.topics.filter((topic) => [topic.title, topic.summary, topic.id, ...topic.body, ...(topic.examples ?? []).flatMap((example) => [example.input, example.effect])].some((text) => text.toLowerCase().includes(needle)));
37
+ }
38
+ function currentTopic(state) {
39
+ const topics = visibleTopics(state);
40
+ if (topics.length === 0)
41
+ return;
42
+ return topics[Math.max(0, Math.min(state.selected, topics.length - 1))];
43
+ }
44
+ function sidebarWidth(columns) {
45
+ const width = Math.max(1, Math.floor(columns));
46
+ return Math.min(width, Math.max(14, Math.min(26, Math.floor(width * 0.28))));
47
+ }
48
+ function bodyHeight(rows) {
49
+ return Math.max(0, Math.floor(rows) - 2);
50
+ }
51
+ function keyToGuideAction(key, character, searching) {
52
+ const name = key.name ?? "";
53
+ if (key.ctrl && name === "c")
54
+ return { kind: "exit" };
55
+ const isEnter = name === "return" || name === "enter" || name === "\r" || name === `
56
+ `;
57
+ const isEscape = name === "escape" || name === "\x1B";
58
+ if (searching) {
59
+ if (isEscape || isEnter)
60
+ return { kind: "commit" };
61
+ if (name === "backspace")
62
+ return { kind: "backspace" };
63
+ if (name === "up")
64
+ return { kind: "move", step: -1 };
65
+ if (name === "down")
66
+ return { kind: "move", step: 1 };
67
+ if (character && character.length === 1 && character >= " ")
68
+ return { kind: "type", character };
69
+ return { kind: "none" };
70
+ }
71
+ if (isEscape || name === "q")
72
+ return { kind: "exit" };
73
+ if (character === "/" || name === "f3")
74
+ return { kind: "search" };
75
+ if (name === "up" || name === "k")
76
+ return { kind: "move", step: -1 };
77
+ if (name === "down" || name === "j")
78
+ return { kind: "move", step: 1 };
79
+ if (name === "tab")
80
+ return { kind: "move", step: key.shift ? -1 : 1 };
81
+ if (name === "pagedown" || character === " ")
82
+ return { kind: "page", step: 1 };
83
+ if (name === "pageup")
84
+ return { kind: "page", step: -1 };
85
+ if (name === "right")
86
+ return { kind: "scroll", rows: 1 };
87
+ if (name === "left")
88
+ return { kind: "scroll", rows: -1 };
89
+ return { kind: "none" };
90
+ }
91
+ function applyGuideAction(state, action) {
92
+ const topics = visibleTopics(state);
93
+ switch (action.kind) {
94
+ case "move": {
95
+ if (topics.length === 0)
96
+ return state;
97
+ const next = ((state.selected + action.step) % topics.length + topics.length) % topics.length;
98
+ return { ...state, selected: next, scroll: 0 };
99
+ }
100
+ case "scroll":
101
+ case "page": {
102
+ const topic = currentTopic(state);
103
+ if (!topic)
104
+ return state;
105
+ const lines = topicLines(topic, bodyWidth(state.columns)).map((line) => line.text);
106
+ const viewport = { ...newViewport(lines, bodyHeight(state.rows)), top: state.scroll };
107
+ const moved = action.kind === "page" ? applyViewport(viewport, { kind: action.step === 1 ? "pageDown" : "pageUp" }) : applyViewport(viewport, action.rows > 0 ? { kind: "down", rows: action.rows } : { kind: "up", rows: -action.rows });
108
+ return { ...state, scroll: moved.top };
109
+ }
110
+ case "search":
111
+ return { ...state, searching: true };
112
+ case "commit":
113
+ return { ...state, searching: false };
114
+ case "backspace":
115
+ return { ...state, query: state.query.slice(0, -1), selected: 0, scroll: 0 };
116
+ case "type":
117
+ return { ...state, query: state.query + action.character, selected: 0, scroll: 0 };
118
+ default:
119
+ return state;
120
+ }
121
+ }
122
+ function bodyWidth(columns) {
123
+ const width = Math.max(1, Math.floor(columns));
124
+ return width < 40 ? width : Math.max(1, width - sidebarWidth(width) - 3);
125
+ }
126
+ function topicLines(topic, width) {
127
+ const measure = Math.max(1, Math.floor(width));
128
+ const wrap = (text, available = measure) => wrapText(text, Math.max(1, available)).flatMap((line) => hardWrap(line, Math.max(1, available)));
129
+ const rows = [
130
+ ...wrap(topic.title).map((line) => ({ text: line, bold: true })),
131
+ { text: "" }
132
+ ];
133
+ for (const paragraph of topic.body) {
134
+ for (const line of wrap(paragraph))
135
+ rows.push({ text: line });
136
+ rows.push({ text: "" });
137
+ }
138
+ if (topic.examples && topic.examples.length > 0) {
139
+ rows.push({ text: "try", bold: true });
140
+ for (const example of topic.examples) {
141
+ const commandIndent = " ".repeat(Math.min(2, Math.max(0, measure - 1)));
142
+ const detailIndent = " ".repeat(Math.min(4, Math.max(0, measure - 1)));
143
+ const [head, ...rest] = wrap(example.input, measure - visibleWidth(detailIndent));
144
+ rows.push({ text: `${commandIndent}${head ?? ""}`, bold: true });
145
+ for (const line of rest)
146
+ rows.push({ text: `${detailIndent}${line}`, bold: true });
147
+ for (const line of wrap(example.effect, measure - visibleWidth(detailIndent)))
148
+ rows.push({ text: `${detailIndent}${line}`, dim: true });
149
+ }
150
+ }
151
+ return rows;
152
+ }
153
+ function hardWrap(text, width) {
154
+ if (visibleWidth(text) <= width)
155
+ return [text];
156
+ const lines = [];
157
+ let line = "";
158
+ const segments = typeof Intl.Segmenter === "function" ? [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(text)].map((entry) => entry.segment) : [...text];
159
+ for (const segment of segments) {
160
+ if (line && visibleWidth(line + segment) > width) {
161
+ lines.push(line);
162
+ line = "";
163
+ }
164
+ if (visibleWidth(segment) > width) {
165
+ lines.push("…");
166
+ continue;
167
+ }
168
+ line += segment;
169
+ }
170
+ if (line)
171
+ lines.push(line);
172
+ return lines;
173
+ }
174
+ function composeGuideFrame(state) {
175
+ const columns = Math.max(1, Math.floor(state.columns));
176
+ const rowCount = Math.max(1, Math.floor(state.rows));
177
+ const compact = columns < 40;
178
+ const sidebar = compact ? 0 : sidebarWidth(columns);
179
+ const body = bodyWidth(columns);
180
+ const height = bodyHeight(rowCount);
181
+ const topics = visibleTopics(state);
182
+ const selectedIndex = topics.length === 0 ? -1 : Math.max(0, Math.min(state.selected, topics.length - 1));
183
+ const topic = selectedIndex === -1 ? undefined : topics[selectedIndex];
184
+ const theme = state.palette.tokens;
185
+ const rows = [];
186
+ rows.push({
187
+ text: padToWidth(compact ? ` archymedes guide · ${topic?.title ?? "no matches"}` : " archymedes guide", columns),
188
+ bold: true,
189
+ color: theme.primary
190
+ });
191
+ if (rowCount === 1)
192
+ return rows;
193
+ const lines = topic ? topicLines(topic, body) : [{ text: "Nothing matches that." }];
194
+ const indices = visibleLines({ ...newViewport(lines.map((_, index) => `${index}`), height), top: state.scroll });
195
+ const start = indices.length > 0 ? Number(indices[0]) : 0;
196
+ const window = lines.slice(start, start + height);
197
+ const listStart = Math.max(0, Math.min(selectedIndex - Math.floor(height / 2), Math.max(0, topics.length - height)));
198
+ for (let offset = 0;offset < height; offset += 1) {
199
+ const listed = topics[listStart + offset];
200
+ const chosen = listed !== undefined && listStart + offset === selectedIndex;
201
+ const cell = listed ? `${chosen ? "›" : " "} ${listed.title}` : "";
202
+ const line = window[offset];
203
+ rows.push({
204
+ text: compact ? padToWidth(line?.text ?? "", columns) : joinHorizontal(sliceToWidth(cell, sidebar), line?.text ?? "", { leftWidth: sidebar, rightWidth: body, separator: " │ " }),
205
+ bold: chosen || line?.bold,
206
+ dim: line?.dim && !chosen,
207
+ ...chosen ? { color: theme.accent } : line?.bold ? { color: theme.primary } : {}
208
+ });
209
+ }
210
+ const position = lines.length > height ? ` ${scrollIndicator(scrollPercent(start, lines.length, height))}` : "";
211
+ const footer = state.searching ? `search: ${state.query}▏ Enter done · Esc done` : `↑↓ topic · ←→ scroll · space page · / search · q leave${state.query ? ` filter: ${state.query}` : ""}${position}`;
212
+ rows.push({ text: padToWidth(` ${footer}`, columns), dim: true, color: theme.textMuted });
213
+ return rows;
214
+ }
215
+
216
+ // src/ui/guide-screen.tsx
217
+ import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
218
+ var Panel = Box;
219
+ var Line = Text;
220
+ function GuideScreen({ columns, rows, onExit, startAt, palette = NO_COLOR_PALETTE }) {
221
+ const [state, setState] = useState(() => {
222
+ const initial = initialGuideState(columns, rows, palette);
223
+ const index = startAt ? initial.topics.findIndex((topic) => topic.id === startAt) : -1;
224
+ return index >= 0 ? { ...initial, selected: index } : initial;
225
+ });
226
+ useInput((input, key) => {
227
+ const action = keyToGuideAction({ name: key?.key, ctrl: key?.ctrl, shift: key?.shift }, input, state.searching);
228
+ if (action.kind === "exit") {
229
+ onExit();
230
+ return;
231
+ }
232
+ setState((current) => applyGuideAction(current, action));
233
+ });
234
+ const frame = composeGuideFrame(state);
235
+ return /* @__PURE__ */ jsxDEV(Panel, {
236
+ flexDirection: "column",
237
+ width: state.columns,
238
+ height: state.rows,
239
+ children: frame.map((row, index) => /* @__PURE__ */ jsxDEV(Line, {
240
+ bold: row.bold,
241
+ dimColor: row.dim,
242
+ inverse: row.inverse,
243
+ color: row.color,
244
+ children: row.text
245
+ }, `row-${index}`, false, undefined, this))
246
+ }, undefined, false, undefined, this);
247
+ }
248
+ async function runGuideScreen(options) {
249
+ const { renderApp } = await import("@termuijs/jsx");
250
+ await new Promise((resolve) => {
251
+ let settled = false;
252
+ const finish = () => {
253
+ if (settled)
254
+ return;
255
+ settled = true;
256
+ resolve();
257
+ };
258
+ renderApp(GuideScreen, {
259
+ columns: options.columns,
260
+ rows: options.rows,
261
+ startAt: options.startAt,
262
+ palette: options.palette,
263
+ onExit: finish,
264
+ fullscreen: true
265
+ }).catch(finish);
266
+ });
267
+ }
268
+ export {
269
+ runGuideScreen,
270
+ GuideScreen
271
+ };
@@ -22,7 +22,7 @@ import {
22
22
  UnprocessableEntityError,
23
23
  betaRefusalFallbackMiddleware,
24
24
  toFile
25
- } from "./archymedes-0jxzsh4z.mjs";
25
+ } from "./archymedes-d5wqcmdr.mjs";
26
26
  import"./archymedes-x67v3n58.mjs";
27
27
  export {
28
28
  toFile,
@@ -5,10 +5,10 @@ import {
5
5
  __classPrivateFieldSet,
6
6
  loggerFor,
7
7
  promiseWithResolvers
8
- } from "./archymedes-0jxzsh4z.mjs";
8
+ } from "./archymedes-d5wqcmdr.mjs";
9
9
  import"./archymedes-x67v3n58.mjs";
10
10
 
11
- // node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/node.mjs
11
+ // ../../node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/node.mjs
12
12
  import * as fs3 from "node:fs/promises";
13
13
  import * as fssync2 from "node:fs";
14
14
  import * as path3 from "node:path";
@@ -16,7 +16,7 @@ import * as cp from "node:child_process";
16
16
  import * as crypto from "node:crypto";
17
17
  import * as readline from "node:readline";
18
18
 
19
- // node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/lib/transform-json-schema.mjs
19
+ // ../../node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/lib/transform-json-schema.mjs
20
20
  var SUPPORTED_STRING_FORMATS = new Set([
21
21
  "date-time",
22
22
  "time",
@@ -30,7 +30,7 @@ var SUPPORTED_STRING_FORMATS = new Set([
30
30
  "uuid"
31
31
  ]);
32
32
 
33
- // node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/helpers/beta/json-schema.mjs
33
+ // ../../node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/helpers/beta/json-schema.mjs
34
34
  function betaTool(options) {
35
35
  if (options.inputSchema.type !== "object") {
36
36
  throw new Error(`JSON schema for tool "${options.name}" must be an object, but got ${options.inputSchema.type}`);
@@ -46,7 +46,7 @@ function betaTool(options) {
46
46
  };
47
47
  }
48
48
 
49
- // node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/fs-util.mjs
49
+ // ../../node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/fs-util.mjs
50
50
  import * as fs from "node:fs/promises";
51
51
  import * as path from "node:path";
52
52
  import { randomUUID } from "node:crypto";
@@ -145,7 +145,7 @@ function fsErrorMessage(err, file) {
145
145
  }
146
146
  }
147
147
 
148
- // node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/skills.mjs
148
+ // ../../node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/skills.mjs
149
149
  import * as fs2 from "node:fs/promises";
150
150
  import * as fssync from "node:fs";
151
151
  import * as path2 from "node:path";
@@ -304,7 +304,7 @@ async function readHead(file, n) {
304
304
  }
305
305
  }
306
306
 
307
- // node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/node.mjs
307
+ // ../../node_modules/.bun/@anthropic-ai+sdk@0.116.0+ab3ed8e9421bfd7b/node_modules/@anthropic-ai/sdk/tools/agent-toolset/node.mjs
308
308
  var _BashSession_instances;
309
309
  var _BashSession_proc;
310
310
  var _BashSession_buf;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ALLOWED_SANDBOX_PROGRAMS
3
- } from "./archymedes-1g1y6q74.mjs";
3
+ } from "./archymedes-h13ap0za.mjs";
4
4
  import"./archymedes-x67v3n58.mjs";
5
5
 
6
- // packages/core/src/sandbox-templates.ts
6
+ // ../core/src/sandbox-templates.ts
7
7
  var WORKSPACE_PRESETS = [
8
8
  {
9
9
  id: "general",
@@ -1,25 +1,26 @@
1
1
  import {
2
2
  StreamSeries,
3
3
  waveLine
4
- } from "./archymedes-2tp22t9a.mjs";
4
+ } from "./archymedes-twbks7g3.mjs";
5
+ import {
6
+ scrollIndicator,
7
+ scrollPercent
8
+ } from "./archymedes-g8y3rt6t.mjs";
5
9
  import {
6
10
  clip
7
- } from "./archymedes-44c1mqas.mjs";
11
+ } from "./archymedes-tsne2m7p.mjs";
8
12
  import {
9
- scrollIndicator,
10
- scrollPercent,
11
13
  visibleWidth
12
- } from "./archymedes-dwvn4c51.mjs";
13
- import"./archymedes-jecyxv5c.mjs";
14
+ } from "./archymedes-a10k8yrk.mjs";
14
15
  import {
15
16
  __require
16
17
  } from "./archymedes-x67v3n58.mjs";
17
18
 
18
- // packages/archymedes-cli/src/workspace-screen.tsx
19
+ // src/ui/workspace-screen.tsx
19
20
  import { useInput, useInterval, useState } from "@termuijs/jsx";
20
21
  import { Box, Text } from "@termuijs/widgets";
21
22
 
22
- // packages/archymedes-cli/src/workspace-model.ts
23
+ // src/ui/workspace-model.ts
23
24
  function paneHeight(rows) {
24
25
  return Math.max(1, rows - 4);
25
26
  }
@@ -185,7 +186,7 @@ function composeFrame(snapshot) {
185
186
  return rows.map((row) => ({ ...row, text: clip(row.text, columns) }));
186
187
  }
187
188
 
188
- // packages/archymedes-cli/src/workspace-screen.tsx
189
+ // src/ui/workspace-screen.tsx
189
190
  import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
190
191
  var Panel = Box;
191
192
  var Line = Text;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "archymedes-cli",
3
- "version": "2.1.0",
4
- "description": "Archymedes CLI — a coding agent that shows its work. Runs against your working tree or an isolated remote sandbox, with guarded approvals, git checkpoints, and exact, measured cost accounting.",
3
+ "version": "2.3.0",
4
+ "description": "Archymedes CLI \u2014 a coding agent that shows its work. Runs against your working tree or an isolated remote sandbox, with guarded approvals, git checkpoints, and exact, measured cost accounting.",
5
5
  "keywords": [
6
6
  "cli",
7
7
  "coding-agent",