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.
- package/README.md +25 -0
- package/dist/{archymedes-brkqgrxv.mjs → archymedes-4kx65anz.mjs} +47 -50
- package/dist/{archymedes-jecyxv5c.mjs → archymedes-a10k8yrk.mjs} +218 -3
- package/dist/{archymedes-76z6n643.mjs → archymedes-aj30app4.mjs} +160 -150
- package/dist/{archymedes-0jxzsh4z.mjs → archymedes-d5wqcmdr.mjs} +97 -97
- package/dist/archymedes-dz59nvw7.mjs +315 -0
- package/dist/{archymedes-dwvn4c51.mjs → archymedes-g8y3rt6t.mjs} +220 -200
- package/dist/{archymedes-1g1y6q74.mjs → archymedes-h13ap0za.mjs} +1 -1
- package/dist/archymedes-main.mjs +17634 -14542
- package/dist/{archymedes-k1bx08z9.mjs → archymedes-sf9t1hz9.mjs} +481 -50
- package/dist/{archymedes-44c1mqas.mjs → archymedes-tsne2m7p.mjs} +17 -44
- package/dist/{archymedes-2tp22t9a.mjs → archymedes-twbks7g3.mjs} +9 -7
- package/dist/{editor-screen-51z7z11j.mjs → editor-screen-g08zzt70.mjs} +263 -14
- package/dist/{factory-96yy6mxr.mjs → factory-7vtm2fed.mjs} +326 -326
- package/dist/{file-screen-eg28a3ky.mjs → file-screen-ma9yxq2b.mjs} +9 -9
- package/dist/guide-screen-gd129txd.mjs +271 -0
- package/dist/{index-teq1cta4.mjs → index-qvgcwsvm.mjs} +1 -1
- package/dist/{node-0fh63p8z.mjs → node-mdgzx68h.mjs} +7 -7
- package/dist/{sandbox-templates-8sd1psez.mjs → sandbox-templates-9jcjws23.mjs} +2 -2
- package/dist/{workspace-screen-3zztn4by.mjs → workspace-screen-8cwk6jz9.mjs} +10 -9
- package/package.json +2 -2
- package/dist/guide-screen-mfvwkdhb.mjs +0 -565
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ASCII_GLYPHS,
|
|
3
|
-
UNICODE_GLYPHS,
|
|
4
2
|
padToWidth,
|
|
5
3
|
progressBar,
|
|
6
|
-
sliceToWidth
|
|
4
|
+
sliceToWidth
|
|
5
|
+
} from "./archymedes-g8y3rt6t.mjs";
|
|
6
|
+
import {
|
|
7
|
+
ASCII_GLYPHS,
|
|
8
|
+
UNICODE_GLYPHS,
|
|
7
9
|
visibleWidth
|
|
8
|
-
} from "./archymedes-
|
|
10
|
+
} from "./archymedes-a10k8yrk.mjs";
|
|
9
11
|
|
|
10
|
-
//
|
|
12
|
+
// src/render/canvas.ts
|
|
11
13
|
var BRAILLE_DOTS = [
|
|
12
14
|
[1, 2, 4, 64],
|
|
13
15
|
[8, 16, 32, 128]
|
|
@@ -93,7 +95,7 @@ function seriesBounds(values) {
|
|
|
93
95
|
return { low, high, span: high - low === 0 ? 1 : high - low };
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
//
|
|
98
|
+
// src/render/charts.ts
|
|
97
99
|
function barChart(data, options) {
|
|
98
100
|
if (data.length === 0)
|
|
99
101
|
return [];
|
|
@@ -251,4 +253,4 @@ function heatStrip(data, options) {
|
|
|
251
253
|
});
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
export {
|
|
256
|
+
export { barChart, lineChart, plotSeries, scatterChart, waveLine, StreamSeries, heatStrip };
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
diffLines,
|
|
3
|
+
languageOf
|
|
4
|
+
} from "./archymedes-dz59nvw7.mjs";
|
|
5
|
+
import"./archymedes-tsne2m7p.mjs";
|
|
1
6
|
import {
|
|
2
7
|
NO_COLOR_PALETTE
|
|
3
|
-
} from "./archymedes-
|
|
8
|
+
} from "./archymedes-a10k8yrk.mjs";
|
|
4
9
|
import {
|
|
5
10
|
__require
|
|
6
11
|
} from "./archymedes-x67v3n58.mjs";
|
|
7
12
|
|
|
8
|
-
//
|
|
13
|
+
// src/ui/editor-screen.tsx
|
|
9
14
|
import { useInput, useState } from "@termuijs/jsx";
|
|
10
15
|
import { Box, Text } from "@termuijs/widgets";
|
|
11
16
|
|
|
12
|
-
//
|
|
17
|
+
// src/ui/editor.ts
|
|
13
18
|
function initialEditorState(path, content, viewportRows = 20) {
|
|
14
19
|
const lines = content.split(`
|
|
15
20
|
`);
|
|
@@ -342,14 +347,234 @@ function caretInto(text, cursorCol) {
|
|
|
342
347
|
return `${padded.slice(0, cursorCol)}█${padded.slice(cursorCol + 1)}`;
|
|
343
348
|
}
|
|
344
349
|
|
|
345
|
-
//
|
|
350
|
+
// src/ui/explain-view.ts
|
|
351
|
+
var PATTERNS = {
|
|
352
|
+
typescript: {
|
|
353
|
+
imports: /^\s*import\b.*from\s+["'](.+)["']/,
|
|
354
|
+
exports: /^\s*export\s+(?:default\s+)?(?:const|function|class|interface|type|enum)\s+([\w$]+)/,
|
|
355
|
+
functions: /^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*([\w$]+)/,
|
|
356
|
+
classes: /^\s*(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+([\w$]+)/
|
|
357
|
+
},
|
|
358
|
+
javascript: {},
|
|
359
|
+
jsx: {},
|
|
360
|
+
tsx: {},
|
|
361
|
+
python: {
|
|
362
|
+
imports: /^\s*(?:import\s+([\w.]+)|from\s+([\w.]+)\s+import\b)/,
|
|
363
|
+
functions: /^\s*(?:async\s+)?def\s+([\w]+)/,
|
|
364
|
+
classes: /^\s*class\s+([\w]+)/
|
|
365
|
+
},
|
|
366
|
+
go: {
|
|
367
|
+
imports: /^\s*import\s+["'](.+)["']/,
|
|
368
|
+
functions: /^\s*func\s+(?:\([^)]*\)\s*)?([\w]+)/
|
|
369
|
+
},
|
|
370
|
+
rust: {
|
|
371
|
+
imports: /^\s*use\s+([\w:]+)/,
|
|
372
|
+
functions: /^\s*(?:pub\s+)?(?:async\s+)?fn\s+([\w]+)/,
|
|
373
|
+
classes: /^\s*(?:pub\s+)?struct\s+([\w]+)/
|
|
374
|
+
},
|
|
375
|
+
ruby: {
|
|
376
|
+
imports: /^\s*require\s+["'](.+)["']/,
|
|
377
|
+
functions: /^\s*def\s+([\w?!]+)/,
|
|
378
|
+
classes: /^\s*class\s+([\w:]+)/
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
PATTERNS.javascript = PATTERNS.typescript;
|
|
382
|
+
PATTERNS.jsx = PATTERNS.typescript;
|
|
383
|
+
PATTERNS.tsx = PATTERNS.typescript;
|
|
384
|
+
function structuralFacts(content, path) {
|
|
385
|
+
const language = languageOf(path);
|
|
386
|
+
const rules = PATTERNS[language] ?? {};
|
|
387
|
+
const facts = { imports: [], exports: [], functions: [], classes: [] };
|
|
388
|
+
const lines = content.split(`
|
|
389
|
+
`);
|
|
390
|
+
lines.forEach((raw, index) => {
|
|
391
|
+
for (const key of Object.keys(rules)) {
|
|
392
|
+
const pattern = rules[key];
|
|
393
|
+
if (!pattern)
|
|
394
|
+
continue;
|
|
395
|
+
const match = pattern.exec(raw);
|
|
396
|
+
if (!match)
|
|
397
|
+
continue;
|
|
398
|
+
const name = match.slice(1).find((group) => group !== undefined);
|
|
399
|
+
facts[key].push({ line: index + 1, text: name ?? raw.trim() });
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
return facts;
|
|
403
|
+
}
|
|
404
|
+
var MAX_LINE_LENGTH = 120;
|
|
405
|
+
var MAGIC_NUMBER = /(?<![\w.])(?!0\b|1\b)\d{2,}(?![\w.])/;
|
|
406
|
+
function annotateLines(content) {
|
|
407
|
+
const lines = content.split(`
|
|
408
|
+
`);
|
|
409
|
+
const notes = [];
|
|
410
|
+
lines.forEach((raw, index) => {
|
|
411
|
+
const line = index + 1;
|
|
412
|
+
if (/\b(TODO|FIXME|HACK|XXX)\b/.test(raw)) {
|
|
413
|
+
notes.push({ line, note: "unfinished work flagged here", severity: "warn" });
|
|
414
|
+
}
|
|
415
|
+
if (raw.length > MAX_LINE_LENGTH) {
|
|
416
|
+
notes.push({ line, note: `long line (${raw.length} chars)`, severity: "info" });
|
|
417
|
+
}
|
|
418
|
+
if (MAGIC_NUMBER.test(raw) && !/^\s*(?:\/\/|#|\*)/.test(raw)) {
|
|
419
|
+
notes.push({ line, note: "unexplained numeric literal", severity: "info" });
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
return notes;
|
|
423
|
+
}
|
|
424
|
+
var EXPLAIN_TABS = ["facts", "notes", "diff", "ai"];
|
|
425
|
+
function initialExplainPanelState() {
|
|
426
|
+
return { open: false, tab: "facts", ai: { status: "idle" } };
|
|
427
|
+
}
|
|
428
|
+
function toggleExplainPanel(state) {
|
|
429
|
+
return { ...state, open: !state.open };
|
|
430
|
+
}
|
|
431
|
+
function cycleExplainTab(state, step = 1) {
|
|
432
|
+
const index = EXPLAIN_TABS.indexOf(state.tab);
|
|
433
|
+
const next = ((index + step) % EXPLAIN_TABS.length + EXPLAIN_TABS.length) % EXPLAIN_TABS.length;
|
|
434
|
+
return { ...state, tab: EXPLAIN_TABS[next] };
|
|
435
|
+
}
|
|
436
|
+
function withAiExplanation(state, ai) {
|
|
437
|
+
return { ...state, ai };
|
|
438
|
+
}
|
|
439
|
+
var DEFAULT_EXPLAIN_COLORS = { success: "green", warning: "yellow", error: "red" };
|
|
440
|
+
var TAB_LABELS = { facts: "Structure", notes: "Notes", diff: "Diff", ai: "AI" };
|
|
441
|
+
function tabStrip(active) {
|
|
442
|
+
const text = EXPLAIN_TABS.map((tab) => tab === active ? `[${TAB_LABELS[tab]}]` : ` ${TAB_LABELS[tab]} `).join(" ");
|
|
443
|
+
return { text, bold: true };
|
|
444
|
+
}
|
|
445
|
+
function hintRow(active) {
|
|
446
|
+
const ask = active === "ai" ? " ? ask" : "";
|
|
447
|
+
return { text: `[ ] tabs ^E close${ask}`, dim: true };
|
|
448
|
+
}
|
|
449
|
+
function wrap(text, width) {
|
|
450
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
451
|
+
const rows = [];
|
|
452
|
+
let line = "";
|
|
453
|
+
for (const word of words) {
|
|
454
|
+
const candidate = line ? `${line} ${word}` : word;
|
|
455
|
+
if (candidate.length > width && line) {
|
|
456
|
+
rows.push(line);
|
|
457
|
+
line = word;
|
|
458
|
+
} else {
|
|
459
|
+
line = candidate;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (line)
|
|
463
|
+
rows.push(line);
|
|
464
|
+
return rows.length > 0 ? rows : [""];
|
|
465
|
+
}
|
|
466
|
+
function factsRows(facts, width) {
|
|
467
|
+
const section = (title, entries) => {
|
|
468
|
+
if (entries.length === 0)
|
|
469
|
+
return [];
|
|
470
|
+
return [
|
|
471
|
+
{ text: title, bold: true },
|
|
472
|
+
...entries.slice(0, 40).map((entry) => ({ text: ` ${String(entry.line).padStart(4)} ${entry.text}`.slice(0, width) })),
|
|
473
|
+
{ text: "" }
|
|
474
|
+
];
|
|
475
|
+
};
|
|
476
|
+
const rows = [
|
|
477
|
+
...section("Imports", facts.imports),
|
|
478
|
+
...section("Exports", facts.exports),
|
|
479
|
+
...section("Classes", facts.classes),
|
|
480
|
+
...section("Functions", facts.functions)
|
|
481
|
+
];
|
|
482
|
+
if (rows.length === 0)
|
|
483
|
+
return [{ text: "No imports, exports, functions or classes recognised.", dim: true }];
|
|
484
|
+
return rows.slice(0, -1);
|
|
485
|
+
}
|
|
486
|
+
function notesRows(notes, width, colors) {
|
|
487
|
+
if (notes.length === 0)
|
|
488
|
+
return [{ text: "Nothing flagged.", dim: true }];
|
|
489
|
+
return notes.slice(0, 60).map((entry) => ({
|
|
490
|
+
text: `${String(entry.line).padStart(4)} ${entry.note}`.slice(0, width),
|
|
491
|
+
color: entry.severity === "warn" ? colors.warning : undefined
|
|
492
|
+
}));
|
|
493
|
+
}
|
|
494
|
+
function diffRows(diff, width, colors) {
|
|
495
|
+
if (diff.length === 0 || diff.every((line) => line.kind === "context")) {
|
|
496
|
+
return [{ text: "No changes yet.", dim: true }];
|
|
497
|
+
}
|
|
498
|
+
return diff.filter((line) => line.kind !== "context").slice(0, 200).map((line) => ({
|
|
499
|
+
text: `${line.kind === "add" ? "+" : "-"} ${line.text}`.slice(0, width),
|
|
500
|
+
color: line.kind === "add" ? colors.success : colors.error
|
|
501
|
+
}));
|
|
502
|
+
}
|
|
503
|
+
function aiRows(ai, width, colors) {
|
|
504
|
+
switch (ai.status) {
|
|
505
|
+
case "idle":
|
|
506
|
+
return [{ text: "Press ? to ask the model to explain this file.", dim: true }];
|
|
507
|
+
case "loading":
|
|
508
|
+
return [{ text: "Thinking…", dim: true }];
|
|
509
|
+
case "error":
|
|
510
|
+
return [{ text: `Could not get an explanation: ${ai.message}`, color: colors.error }];
|
|
511
|
+
case "ready":
|
|
512
|
+
return ai.text.split(`
|
|
513
|
+
`).flatMap((line) => wrap(line, width)).map((text) => ({ text }));
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
function composeExplainPanel(input, width, height, colors = DEFAULT_EXPLAIN_COLORS) {
|
|
517
|
+
const body = (() => {
|
|
518
|
+
switch (input.panel.tab) {
|
|
519
|
+
case "facts":
|
|
520
|
+
return factsRows(structuralFacts(input.after, input.path), width);
|
|
521
|
+
case "notes":
|
|
522
|
+
return notesRows(annotateLines(input.after), width, colors);
|
|
523
|
+
case "diff":
|
|
524
|
+
return diffRows(diffLines(input.before, input.after), width, colors);
|
|
525
|
+
case "ai":
|
|
526
|
+
return aiRows(input.panel.ai, width, colors);
|
|
527
|
+
}
|
|
528
|
+
})();
|
|
529
|
+
const rows = [tabStrip(input.panel.tab), hintRow(input.panel.tab), { text: "" }, ...body];
|
|
530
|
+
const padded = rows.length >= height ? rows.slice(0, height) : [...rows, ...Array.from({ length: height - rows.length }, () => ({ text: "" }))];
|
|
531
|
+
return padded;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/ui/editor-screen.tsx
|
|
346
535
|
import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
|
|
347
536
|
var Panel = Box;
|
|
348
537
|
var Line = Text;
|
|
349
538
|
var CHROME_ROWS = 2;
|
|
350
|
-
|
|
539
|
+
var MIN_CODE_COLUMNS = 30;
|
|
540
|
+
var MAX_PANEL_COLUMNS = 52;
|
|
541
|
+
function panelWidthFor(columns) {
|
|
542
|
+
if (columns - MIN_CODE_COLUMNS < 20)
|
|
543
|
+
return 0;
|
|
544
|
+
return Math.min(MAX_PANEL_COLUMNS, Math.floor(columns * 0.38), columns - MIN_CODE_COLUMNS);
|
|
545
|
+
}
|
|
546
|
+
function EditorScreen({ columns, rows, path, content, onExit, palette = NO_COLOR_PALETTE, explain }) {
|
|
351
547
|
const [state, setState] = useState(() => initialEditorState(path, content, Math.max(1, rows - CHROME_ROWS)));
|
|
548
|
+
const [panel, setPanel] = useState(() => initialExplainPanelState());
|
|
549
|
+
const panelWidth = panel.open ? panelWidthFor(columns) : 0;
|
|
550
|
+
const codeWidth = panelWidth > 0 ? columns - panelWidth - 1 : columns;
|
|
551
|
+
const askAi = (currentContent) => {
|
|
552
|
+
if (!explain) {
|
|
553
|
+
setPanel((current) => withAiExplanation(current, { status: "error", message: "no model available in this session" }));
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
setPanel((current) => withAiExplanation(current, { status: "loading" }));
|
|
557
|
+
explain(currentContent, path).then((text) => setPanel((current) => withAiExplanation(current, { status: "ready", text })), (error) => setPanel((current) => withAiExplanation(current, { status: "error", message: error instanceof Error ? error.message : String(error) })));
|
|
558
|
+
};
|
|
352
559
|
useInput((input, key) => {
|
|
560
|
+
if (key?.ctrl && key?.key === "e") {
|
|
561
|
+
setPanel((current) => toggleExplainPanel(current));
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (panel.open && state.mode === "normal" && !state.search.typing) {
|
|
565
|
+
if (input === "]") {
|
|
566
|
+
setPanel((current) => cycleExplainTab(current, 1));
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (input === "[") {
|
|
570
|
+
setPanel((current) => cycleExplainTab(current, -1));
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (input === "?" && panel.tab === "ai" && panel.ai.status !== "loading") {
|
|
574
|
+
askAi(editorContent(state));
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
353
578
|
setState((current) => {
|
|
354
579
|
const action = keyToEditorAction({ name: key?.key, ctrl: key?.ctrl, shift: key?.shift }, input, current);
|
|
355
580
|
const { state: next, effect } = applyEditorAction(current, action);
|
|
@@ -360,18 +585,41 @@ function EditorScreen({ columns, rows, path, content, onExit, palette = NO_COLOR
|
|
|
360
585
|
return next;
|
|
361
586
|
});
|
|
362
587
|
});
|
|
363
|
-
const frame = composeEditorFrame(state,
|
|
588
|
+
const frame = composeEditorFrame(state, codeWidth, palette.tokens.accent);
|
|
589
|
+
const lastRow = frame.length - 1;
|
|
590
|
+
if (!panel.open && lastRow >= 0 && frame[lastRow].text.length + " ^E explain".length <= codeWidth) {
|
|
591
|
+
frame[lastRow] = { ...frame[lastRow], text: `${frame[lastRow].text} ^E explain` };
|
|
592
|
+
}
|
|
593
|
+
const panelRows = panelWidth > 0 ? composeExplainPanel({ path, before: content, after: editorContent(state), panel }, panelWidth - 2, rows, palette.tokens) : [];
|
|
364
594
|
return /* @__PURE__ */ jsxDEV(Panel, {
|
|
365
|
-
flexDirection: "
|
|
595
|
+
flexDirection: "row",
|
|
366
596
|
width: columns,
|
|
367
597
|
height: rows,
|
|
368
|
-
children:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
598
|
+
children: [
|
|
599
|
+
/* @__PURE__ */ jsxDEV(Panel, {
|
|
600
|
+
flexDirection: "column",
|
|
601
|
+
width: codeWidth,
|
|
602
|
+
height: rows,
|
|
603
|
+
children: frame.map((line, index) => /* @__PURE__ */ jsxDEV(Line, {
|
|
604
|
+
bold: line.bold,
|
|
605
|
+
dimColor: line.dim,
|
|
606
|
+
color: line.color,
|
|
607
|
+
children: line.text
|
|
608
|
+
}, `row-${index}`, false, undefined, this))
|
|
609
|
+
}, undefined, false, undefined, this),
|
|
610
|
+
panelWidth > 0 && /* @__PURE__ */ jsxDEV(Panel, {
|
|
611
|
+
flexDirection: "column",
|
|
612
|
+
width: panelWidth,
|
|
613
|
+
height: rows,
|
|
614
|
+
children: panelRows.map((line, index) => /* @__PURE__ */ jsxDEV(Line, {
|
|
615
|
+
bold: line.bold,
|
|
616
|
+
dimColor: line.dim,
|
|
617
|
+
color: line.color,
|
|
618
|
+
children: line.text
|
|
619
|
+
}, `explain-${index}`, false, undefined, this))
|
|
620
|
+
}, undefined, false, undefined, this)
|
|
621
|
+
]
|
|
622
|
+
}, undefined, true, undefined, this);
|
|
375
623
|
}
|
|
376
624
|
async function runEditorScreen(options) {
|
|
377
625
|
const { renderApp } = await import("@termuijs/jsx");
|
|
@@ -389,6 +637,7 @@ async function runEditorScreen(options) {
|
|
|
389
637
|
path: options.path,
|
|
390
638
|
content: options.content,
|
|
391
639
|
palette: options.palette,
|
|
640
|
+
explain: options.explain,
|
|
392
641
|
onExit: finish,
|
|
393
642
|
fullscreen: true
|
|
394
643
|
}).catch(() => finish(undefined));
|