stackai 0.1.2 → 0.1.4
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/cli.js +268 -38
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -173,6 +173,40 @@ function toLLMError(err) {
|
|
|
173
173
|
// ../core/dist/file-agent.js
|
|
174
174
|
import { promises as fs } from "fs";
|
|
175
175
|
import path from "path";
|
|
176
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
177
|
+
"node_modules",
|
|
178
|
+
".git",
|
|
179
|
+
"dist",
|
|
180
|
+
".next",
|
|
181
|
+
".turbo",
|
|
182
|
+
"build",
|
|
183
|
+
"out",
|
|
184
|
+
"coverage",
|
|
185
|
+
".cache"
|
|
186
|
+
]);
|
|
187
|
+
function globToRegExp(glob) {
|
|
188
|
+
let re = "";
|
|
189
|
+
for (let i = 0; i < glob.length; i++) {
|
|
190
|
+
const c = glob[i];
|
|
191
|
+
if (c === "*") {
|
|
192
|
+
if (glob[i + 1] === "*") {
|
|
193
|
+
re += ".*";
|
|
194
|
+
i++;
|
|
195
|
+
if (glob[i + 1] === "/")
|
|
196
|
+
i++;
|
|
197
|
+
} else {
|
|
198
|
+
re += "[^/]*";
|
|
199
|
+
}
|
|
200
|
+
} else if (c === "?") {
|
|
201
|
+
re += "[^/]";
|
|
202
|
+
} else if (".+^${}()|[]\\".includes(c)) {
|
|
203
|
+
re += `\\${c}`;
|
|
204
|
+
} else {
|
|
205
|
+
re += c;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return new RegExp(`^${re}$`);
|
|
209
|
+
}
|
|
176
210
|
var FileAgent = class {
|
|
177
211
|
root;
|
|
178
212
|
constructor(cwd) {
|
|
@@ -220,6 +254,70 @@ var FileAgent = class {
|
|
|
220
254
|
async createDir(relPath) {
|
|
221
255
|
await fs.mkdir(this.resolve(relPath), { recursive: true });
|
|
222
256
|
}
|
|
257
|
+
/** Recursively yield every file path under `dir`, skipping ignored dirs. */
|
|
258
|
+
async *walkFiles(dir) {
|
|
259
|
+
let entries;
|
|
260
|
+
try {
|
|
261
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
262
|
+
} catch {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
for (const e of entries) {
|
|
266
|
+
if (e.isDirectory()) {
|
|
267
|
+
if (IGNORE_DIRS.has(e.name))
|
|
268
|
+
continue;
|
|
269
|
+
yield* this.walkFiles(path.join(dir, e.name));
|
|
270
|
+
} else {
|
|
271
|
+
yield path.join(dir, e.name);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
rel(abs) {
|
|
276
|
+
return path.relative(this.root, abs).split(path.sep).join("/");
|
|
277
|
+
}
|
|
278
|
+
/** Search file contents (regex). Returns `path:line: text` matches. */
|
|
279
|
+
async grep(pattern, maxResults = 80) {
|
|
280
|
+
let re;
|
|
281
|
+
try {
|
|
282
|
+
re = new RegExp(pattern);
|
|
283
|
+
} catch {
|
|
284
|
+
re = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
285
|
+
}
|
|
286
|
+
const out = [];
|
|
287
|
+
for await (const abs of this.walkFiles(this.root)) {
|
|
288
|
+
if (out.length >= maxResults)
|
|
289
|
+
break;
|
|
290
|
+
let content;
|
|
291
|
+
try {
|
|
292
|
+
content = await fs.readFile(abs, "utf8");
|
|
293
|
+
} catch {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const lines = content.split("\n");
|
|
297
|
+
for (let i = 0; i < lines.length; i++) {
|
|
298
|
+
if (re.test(lines[i])) {
|
|
299
|
+
out.push(`${this.rel(abs)}:${i + 1}: ${lines[i].trim().slice(0, 160)}`);
|
|
300
|
+
if (out.length >= maxResults)
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
307
|
+
/** Find files whose relative path matches a glob pattern. */
|
|
308
|
+
async glob(pattern, maxResults = 200) {
|
|
309
|
+
const re = globToRegExp(pattern);
|
|
310
|
+
const out = [];
|
|
311
|
+
for await (const abs of this.walkFiles(this.root)) {
|
|
312
|
+
const rel = this.rel(abs);
|
|
313
|
+
if (re.test(rel)) {
|
|
314
|
+
out.push(rel);
|
|
315
|
+
if (out.length >= maxResults)
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
320
|
+
}
|
|
223
321
|
};
|
|
224
322
|
|
|
225
323
|
// ../core/dist/system-prompt.js
|
|
@@ -227,10 +325,14 @@ var SYSTEM_PROMPT = `You are StackAI, an autonomous coding agent operating insid
|
|
|
227
325
|
|
|
228
326
|
You can read, write, and edit files by calling the provided tools. Be DECISIVE and make the FEWEST tool calls possible \u2014 every call is a slow round-trip.
|
|
229
327
|
|
|
328
|
+
Tools: read_file, write_file, edit_file, list_files, create_dir, search_files (regex content search), find_files (glob).
|
|
329
|
+
|
|
230
330
|
How to work:
|
|
231
|
-
1. To
|
|
232
|
-
2. To
|
|
233
|
-
3.
|
|
331
|
+
1. To explore an unfamiliar project, use find_files (e.g. "src/**/*.ts") and search_files (regex) instead of reading everything.
|
|
332
|
+
2. To create a new file: call write_file once. Do NOT list_files or read_file first.
|
|
333
|
+
3. To change an existing file: call read_file ONCE to see its contents, then make ONE edit_file (or one write_file) call to apply the change.
|
|
334
|
+
4. If project instructions were provided (from STACKAI.md / AGENTS.md), follow them.
|
|
335
|
+
5. When the task is done, stop calling tools and reply with ONE short sentence summarizing what you changed.
|
|
234
336
|
|
|
235
337
|
Hard rules:
|
|
236
338
|
- Make each distinct tool call AT MOST ONCE. Never repeat the same read or edit.
|
|
@@ -307,6 +409,30 @@ var TOOLS = [
|
|
|
307
409
|
required: ["path"]
|
|
308
410
|
}
|
|
309
411
|
}
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
type: "function",
|
|
415
|
+
function: {
|
|
416
|
+
name: "search_files",
|
|
417
|
+
description: "Search file contents across the project with a regular expression. Returns matching `path:line: text`.",
|
|
418
|
+
parameters: {
|
|
419
|
+
type: "object",
|
|
420
|
+
properties: { pattern: { type: "string" } },
|
|
421
|
+
required: ["pattern"]
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
type: "function",
|
|
427
|
+
function: {
|
|
428
|
+
name: "find_files",
|
|
429
|
+
description: "Find files by glob pattern (e.g. `src/**/*.ts`, `*.json`). Returns matching paths.",
|
|
430
|
+
parameters: {
|
|
431
|
+
type: "object",
|
|
432
|
+
properties: { pattern: { type: "string" } },
|
|
433
|
+
required: ["pattern"]
|
|
434
|
+
}
|
|
435
|
+
}
|
|
310
436
|
}
|
|
311
437
|
];
|
|
312
438
|
var AgentRunner = class {
|
|
@@ -318,16 +444,40 @@ var AgentRunner = class {
|
|
|
318
444
|
}
|
|
319
445
|
async run({ prompt, cwd, onStep }) {
|
|
320
446
|
const files = new FileAgent(cwd);
|
|
321
|
-
const messages =
|
|
322
|
-
|
|
323
|
-
{ role: "user", content: prompt }
|
|
324
|
-
];
|
|
447
|
+
const messages = await this.systemMessages(files);
|
|
448
|
+
messages.push({ role: "user", content: prompt });
|
|
325
449
|
return this.runLoop(messages, files, onStep);
|
|
326
450
|
}
|
|
327
451
|
/** Start a stateful chat session that retains history across prompts. */
|
|
328
452
|
session(cwd) {
|
|
329
453
|
return new AgentSession(this, cwd);
|
|
330
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* Build the leading system messages: the base system prompt plus any
|
|
457
|
+
* project context found in STACKAI.md / AGENTS.md at the project root.
|
|
458
|
+
* @internal
|
|
459
|
+
*/
|
|
460
|
+
async systemMessages(files) {
|
|
461
|
+
const messages = [
|
|
462
|
+
{ role: "system", content: SYSTEM_PROMPT }
|
|
463
|
+
];
|
|
464
|
+
for (const name of ["STACKAI.md", "AGENTS.md"]) {
|
|
465
|
+
try {
|
|
466
|
+
const ctx = (await files.readFile(name)).trim();
|
|
467
|
+
if (ctx) {
|
|
468
|
+
messages.push({
|
|
469
|
+
role: "system",
|
|
470
|
+
content: `Project instructions from ${name}:
|
|
471
|
+
|
|
472
|
+
${ctx}`
|
|
473
|
+
});
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
} catch {
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return messages;
|
|
480
|
+
}
|
|
331
481
|
/**
|
|
332
482
|
* Run the tool-call loop over an existing message history (mutated in place).
|
|
333
483
|
* Shared by one-shot run() and the interactive AgentSession.
|
|
@@ -409,6 +559,14 @@ var AgentRunner = class {
|
|
|
409
559
|
case "create_dir":
|
|
410
560
|
await files.createDir(str(args.path));
|
|
411
561
|
return `Created ${str(args.path)}`;
|
|
562
|
+
case "search_files": {
|
|
563
|
+
const matches = await files.grep(str(args.pattern));
|
|
564
|
+
return matches.join("\n") || "(no matches)";
|
|
565
|
+
}
|
|
566
|
+
case "find_files": {
|
|
567
|
+
const found = await files.glob(str(args.pattern));
|
|
568
|
+
return found.join("\n") || "(no files matched)";
|
|
569
|
+
}
|
|
412
570
|
default:
|
|
413
571
|
return `Error: unknown tool ${name}`;
|
|
414
572
|
}
|
|
@@ -422,16 +580,19 @@ function str(value) {
|
|
|
422
580
|
}
|
|
423
581
|
var AgentSession = class {
|
|
424
582
|
runner;
|
|
425
|
-
messages = [
|
|
426
|
-
{ role: "system", content: SYSTEM_PROMPT }
|
|
427
|
-
];
|
|
583
|
+
messages = [];
|
|
428
584
|
files;
|
|
585
|
+
initialized = false;
|
|
429
586
|
constructor(runner, cwd) {
|
|
430
587
|
this.runner = runner;
|
|
431
588
|
this.files = new FileAgent(cwd);
|
|
432
589
|
}
|
|
433
590
|
/** Send a user message; the agent acts with full prior context. */
|
|
434
591
|
async send(prompt, onStep) {
|
|
592
|
+
if (!this.initialized) {
|
|
593
|
+
this.messages = await this.runner.systemMessages(this.files);
|
|
594
|
+
this.initialized = true;
|
|
595
|
+
}
|
|
435
596
|
this.messages.push({ role: "user", content: prompt });
|
|
436
597
|
return this.runner.runLoop(this.messages, this.files, onStep);
|
|
437
598
|
}
|
|
@@ -501,36 +662,99 @@ import { Box as Box2, Text as Text2, useApp } from "ink";
|
|
|
501
662
|
import Spinner from "ink-spinner";
|
|
502
663
|
|
|
503
664
|
// src/ui/format.ts
|
|
504
|
-
|
|
505
|
-
|
|
665
|
+
var ACCENT = "#e8ff47";
|
|
666
|
+
var MAX_PREVIEW = 6;
|
|
667
|
+
function splitLines(s) {
|
|
668
|
+
return s.replace(/\n+$/, "").split("\n");
|
|
669
|
+
}
|
|
670
|
+
function clip(s, n = 76) {
|
|
671
|
+
return s.length > n ? `${s.slice(0, n)}\u2026` : s;
|
|
672
|
+
}
|
|
673
|
+
function preview(lines, prefix, color) {
|
|
674
|
+
const out = lines.slice(0, MAX_PREVIEW).map((l) => ({ kind: "sub", color, text: `${prefix} ${clip(l)}` }));
|
|
675
|
+
if (lines.length > MAX_PREVIEW) {
|
|
676
|
+
out.push({
|
|
677
|
+
kind: "sub",
|
|
678
|
+
color: "gray",
|
|
679
|
+
text: `\u2026 ${lines.length - MAX_PREVIEW} more lines`
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
684
|
+
function toolEntries(step) {
|
|
685
|
+
const args = step.args;
|
|
686
|
+
const path3 = String(args.path ?? args.dir ?? "");
|
|
506
687
|
switch (step.name) {
|
|
688
|
+
case "write_file": {
|
|
689
|
+
const lines = splitLines(String(args.content ?? ""));
|
|
690
|
+
return [
|
|
691
|
+
{ kind: "tool", color: ACCENT, label: `Write(${path3})` },
|
|
692
|
+
{ kind: "sub", color: "green", text: `+${lines.length} lines` },
|
|
693
|
+
...preview(lines, "+", "green")
|
|
694
|
+
];
|
|
695
|
+
}
|
|
696
|
+
case "edit_file": {
|
|
697
|
+
const removed = splitLines(String(args.oldStr ?? ""));
|
|
698
|
+
const added = splitLines(String(args.newStr ?? ""));
|
|
699
|
+
return [
|
|
700
|
+
{ kind: "tool", color: ACCENT, label: `Edit(${path3})` },
|
|
701
|
+
{
|
|
702
|
+
kind: "sub",
|
|
703
|
+
color: "gray",
|
|
704
|
+
text: `+${added.length} -${removed.length} lines`
|
|
705
|
+
},
|
|
706
|
+
...preview(removed, "-", "red"),
|
|
707
|
+
...preview(added, "+", "green")
|
|
708
|
+
];
|
|
709
|
+
}
|
|
507
710
|
case "read_file":
|
|
508
|
-
return `
|
|
509
|
-
case "write_file":
|
|
510
|
-
return `Writing ${p}`;
|
|
511
|
-
case "edit_file":
|
|
512
|
-
return `Editing ${p}`;
|
|
711
|
+
return [{ kind: "tool", color: ACCENT, label: `Read(${path3})` }];
|
|
513
712
|
case "list_files":
|
|
514
|
-
return `
|
|
713
|
+
return [{ kind: "tool", color: ACCENT, label: `List(${path3 || "."})` }];
|
|
515
714
|
case "create_dir":
|
|
516
|
-
return `
|
|
715
|
+
return [{ kind: "tool", color: ACCENT, label: `Create(${path3}/)` }];
|
|
716
|
+
case "search_files":
|
|
717
|
+
return [
|
|
718
|
+
{ kind: "tool", color: ACCENT, label: `Search(${String(args.pattern ?? "")})` }
|
|
719
|
+
];
|
|
720
|
+
case "find_files":
|
|
721
|
+
return [
|
|
722
|
+
{ kind: "tool", color: ACCENT, label: `Find(${String(args.pattern ?? "")})` }
|
|
723
|
+
];
|
|
517
724
|
default:
|
|
518
|
-
return step.name;
|
|
725
|
+
return [{ kind: "tool", color: ACCENT, label: step.name }];
|
|
519
726
|
}
|
|
520
727
|
}
|
|
521
728
|
function applyStep(entries, step) {
|
|
522
729
|
if (step.type === "token") {
|
|
523
730
|
const last = entries[entries.length - 1];
|
|
524
731
|
if (last && last.kind === "text") {
|
|
525
|
-
return [
|
|
732
|
+
return [
|
|
733
|
+
...entries.slice(0, -1),
|
|
734
|
+
{ kind: "text", text: last.text + step.text }
|
|
735
|
+
];
|
|
526
736
|
}
|
|
527
737
|
return [...entries, { kind: "text", text: step.text }];
|
|
528
738
|
}
|
|
529
739
|
if (step.type === "tool_call") {
|
|
530
|
-
return [...entries,
|
|
740
|
+
return [...entries, ...toolEntries(step)];
|
|
531
741
|
}
|
|
532
|
-
if (step.type === "tool_result"
|
|
533
|
-
|
|
742
|
+
if (step.type === "tool_result") {
|
|
743
|
+
if (!step.ok) {
|
|
744
|
+
return [
|
|
745
|
+
...entries,
|
|
746
|
+
{ kind: "sub", color: "red", text: `\u2717 ${step.detail}` }
|
|
747
|
+
];
|
|
748
|
+
}
|
|
749
|
+
if (step.name === "read_file") {
|
|
750
|
+
const n = step.detail ? splitLines(step.detail).length : 0;
|
|
751
|
+
return [...entries, { kind: "sub", color: "gray", text: `read ${n} lines` }];
|
|
752
|
+
}
|
|
753
|
+
if (step.name === "search_files" || step.name === "find_files") {
|
|
754
|
+
const empty = /^\(no /.test(step.detail);
|
|
755
|
+
const n = empty ? 0 : splitLines(step.detail).length;
|
|
756
|
+
return [...entries, { kind: "sub", color: "gray", text: `${n} results` }];
|
|
757
|
+
}
|
|
534
758
|
}
|
|
535
759
|
return entries;
|
|
536
760
|
}
|
|
@@ -539,12 +763,18 @@ function applyStep(entries, step) {
|
|
|
539
763
|
import { Box, Text } from "ink";
|
|
540
764
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
541
765
|
function EntryLines({ entries }) {
|
|
542
|
-
return /* @__PURE__ */ jsx(Fragment, { children: entries.map(
|
|
543
|
-
(e
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
766
|
+
return /* @__PURE__ */ jsx(Fragment, { children: entries.map((e, i) => {
|
|
767
|
+
if (e.kind === "tool") {
|
|
768
|
+
return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: e.color, bold: true, children: [
|
|
769
|
+
"\u25CF ",
|
|
770
|
+
e.label
|
|
771
|
+
] }) }, i);
|
|
772
|
+
}
|
|
773
|
+
if (e.kind === "sub") {
|
|
774
|
+
return /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: e.color, children: e.text }) }, i);
|
|
775
|
+
}
|
|
776
|
+
return /* @__PURE__ */ jsx(Box, { marginTop: 1, marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { children: e.text }) }, i);
|
|
777
|
+
}) });
|
|
548
778
|
}
|
|
549
779
|
|
|
550
780
|
// src/ui/run-view.tsx
|
|
@@ -597,7 +827,7 @@ import { Box as Box3, Text as Text3, useApp as useApp2 } from "ink";
|
|
|
597
827
|
import Spinner2 from "ink-spinner";
|
|
598
828
|
import TextInput from "ink-text-input";
|
|
599
829
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
600
|
-
var
|
|
830
|
+
var ACCENT2 = "#e8ff47";
|
|
601
831
|
var LOGO = [
|
|
602
832
|
"\u2588\u2580\u2580 \u2580\u2588\u2580 \u2588\u2580\u2588 \u2588\u2580\u2580 \u2588\u2584\u2580 \u2588\u2580\u2588 \u2588",
|
|
603
833
|
"\u2584\u2584\u2588 \u2588 \u2588\u2580\u2588 \u2588\u2584\u2584 \u2588\u2580\u2584 \u2588\u2580\u2588 \u2588"
|
|
@@ -647,11 +877,11 @@ function Interactive({ session, cwd, version }) {
|
|
|
647
877
|
{
|
|
648
878
|
flexDirection: "column",
|
|
649
879
|
borderStyle: "round",
|
|
650
|
-
borderColor:
|
|
880
|
+
borderColor: ACCENT2,
|
|
651
881
|
paddingX: 2,
|
|
652
882
|
paddingY: 1,
|
|
653
883
|
children: [
|
|
654
|
-
LOGO.map((line, i) => /* @__PURE__ */ jsx3(Text3, { color:
|
|
884
|
+
LOGO.map((line, i) => /* @__PURE__ */ jsx3(Text3, { color: ACCENT2, bold: true, children: line }, i)),
|
|
655
885
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
656
886
|
"v",
|
|
657
887
|
version,
|
|
@@ -664,12 +894,12 @@ function Interactive({ session, cwd, version }) {
|
|
|
664
894
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
665
895
|
"Describe what you want to build \xB7 type",
|
|
666
896
|
" ",
|
|
667
|
-
/* @__PURE__ */ jsx3(Text3, { color:
|
|
897
|
+
/* @__PURE__ */ jsx3(Text3, { color: ACCENT2, children: "/exit" }),
|
|
668
898
|
" to quit"
|
|
669
899
|
] }) }),
|
|
670
900
|
history.map(
|
|
671
901
|
(block, i) => block.kind === "user" ? /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, children: [
|
|
672
|
-
/* @__PURE__ */ jsxs3(Text3, { color:
|
|
902
|
+
/* @__PURE__ */ jsxs3(Text3, { color: ACCENT2, bold: true, children: [
|
|
673
903
|
"\u203A",
|
|
674
904
|
" "
|
|
675
905
|
] }),
|
|
@@ -685,13 +915,13 @@ function Interactive({ session, cwd, version }) {
|
|
|
685
915
|
{
|
|
686
916
|
marginTop: 1,
|
|
687
917
|
borderStyle: "round",
|
|
688
|
-
borderColor: busy ? "gray" :
|
|
918
|
+
borderColor: busy ? "gray" : ACCENT2,
|
|
689
919
|
paddingX: 1,
|
|
690
920
|
children: busy ? /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
691
921
|
/* @__PURE__ */ jsx3(Spinner2, { type: "dots" }),
|
|
692
922
|
" working\u2026"
|
|
693
923
|
] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
694
|
-
/* @__PURE__ */ jsx3(Text3, { color:
|
|
924
|
+
/* @__PURE__ */ jsx3(Text3, { color: ACCENT2, children: "\u203A " }),
|
|
695
925
|
/* @__PURE__ */ jsx3(
|
|
696
926
|
TextInput,
|
|
697
927
|
{
|
|
@@ -776,7 +1006,7 @@ function LoginView() {
|
|
|
776
1006
|
|
|
777
1007
|
// src/cli.tsx
|
|
778
1008
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
779
|
-
var VERSION = "0.1.
|
|
1009
|
+
var VERSION = "0.1.4";
|
|
780
1010
|
var HELP = `
|
|
781
1011
|
StackAI \u2014 AI coding agent in your terminal
|
|
782
1012
|
|