wholestack 0.5.3 → 0.5.5
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 +1 -1
- package/dist/{chunk-FI67ER5S.js → chunk-7NZ77Q7Q.js} +371 -133
- package/dist/cli.js +64 -117
- package/dist/index.d.ts +8 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19,84 +19,26 @@ import {
|
|
|
19
19
|
loadMcpTools,
|
|
20
20
|
loadPlugins,
|
|
21
21
|
loadProjectMemory,
|
|
22
|
+
loadStoredEnv,
|
|
22
23
|
mergeHookSets,
|
|
23
24
|
modelContextWindow,
|
|
24
25
|
modelLabel,
|
|
25
26
|
resolveModel,
|
|
26
27
|
resolveModelKey,
|
|
27
28
|
runProver,
|
|
29
|
+
saveKey,
|
|
30
|
+
stateDir,
|
|
28
31
|
statusLine,
|
|
29
32
|
supportsThinking,
|
|
30
33
|
tasks,
|
|
31
34
|
userBox,
|
|
32
35
|
visionCapable
|
|
33
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-7NZ77Q7Q.js";
|
|
34
37
|
|
|
35
38
|
// src/cli.ts
|
|
36
39
|
import { createInterface } from "readline/promises";
|
|
37
40
|
import { stdin, stdout, argv, exit, cwd } from "process";
|
|
38
41
|
|
|
39
|
-
// src/config.ts
|
|
40
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from "fs";
|
|
41
|
-
import { homedir } from "os";
|
|
42
|
-
import { join } from "path";
|
|
43
|
-
var CONFIG_DIR = join(homedir(), ".zeta-g");
|
|
44
|
-
var CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
45
|
-
function parseDotenv(text) {
|
|
46
|
-
const out = {};
|
|
47
|
-
for (const raw of text.split("\n")) {
|
|
48
|
-
const l = raw.trim();
|
|
49
|
-
if (!l || l.startsWith("#")) continue;
|
|
50
|
-
const eq = l.indexOf("=");
|
|
51
|
-
if (eq < 0) continue;
|
|
52
|
-
const k = l.slice(0, eq).trim();
|
|
53
|
-
let v = l.slice(eq + 1).trim();
|
|
54
|
-
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
55
|
-
v = v.slice(1, -1);
|
|
56
|
-
}
|
|
57
|
-
if (k) out[k] = v;
|
|
58
|
-
}
|
|
59
|
-
return out;
|
|
60
|
-
}
|
|
61
|
-
function fill(src) {
|
|
62
|
-
for (const [k, v] of Object.entries(src)) {
|
|
63
|
-
if (v && process.env[k] === void 0) process.env[k] = v;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function loadStoredEnv() {
|
|
67
|
-
const localEnv = join(process.cwd(), ".env");
|
|
68
|
-
if (existsSync(localEnv)) {
|
|
69
|
-
try {
|
|
70
|
-
fill(parseDotenv(readFileSync(localEnv, "utf8")));
|
|
71
|
-
} catch {
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (existsSync(CONFIG_PATH)) {
|
|
75
|
-
try {
|
|
76
|
-
const json = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
77
|
-
const flat = {};
|
|
78
|
-
for (const [k, v] of Object.entries(json)) if (typeof v === "string") flat[k] = v;
|
|
79
|
-
fill(flat);
|
|
80
|
-
} catch {
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function saveKey(name, value) {
|
|
85
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
86
|
-
let current = {};
|
|
87
|
-
if (existsSync(CONFIG_PATH)) {
|
|
88
|
-
try {
|
|
89
|
-
current = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
90
|
-
} catch {
|
|
91
|
-
current = {};
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
current[name] = value;
|
|
95
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(current, null, 2) + "\n", { mode: 384 });
|
|
96
|
-
chmodSync(CONFIG_PATH, 384);
|
|
97
|
-
return CONFIG_PATH;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
42
|
// src/cli-login.ts
|
|
101
43
|
import { createServer } from "http";
|
|
102
44
|
import { spawn } from "child_process";
|
|
@@ -284,7 +226,7 @@ var CheckpointStore = class {
|
|
|
284
226
|
|
|
285
227
|
// src/mentions.ts
|
|
286
228
|
import { readFile as readFile2, stat, readdir } from "fs/promises";
|
|
287
|
-
import { resolve, relative, join
|
|
229
|
+
import { resolve, relative, join, isAbsolute } from "path";
|
|
288
230
|
import fg from "fast-glob";
|
|
289
231
|
var IGNORE = [
|
|
290
232
|
"**/node_modules/**",
|
|
@@ -341,7 +283,7 @@ async function renderTree(absDir, relDir) {
|
|
|
341
283
|
}
|
|
342
284
|
count++;
|
|
343
285
|
lines.push(`${prefix}${e.name}${e.isDirectory() ? "/" : ""}`);
|
|
344
|
-
if (e.isDirectory()) await walk(
|
|
286
|
+
if (e.isDirectory()) await walk(join(dir, e.name), prefix + " ", depth + 1);
|
|
345
287
|
}
|
|
346
288
|
}
|
|
347
289
|
await walk(absDir, "", 0);
|
|
@@ -357,7 +299,7 @@ async function expandMentions(message, cwd2, tokenBudget = DEFAULT_TOKEN_BUDGET)
|
|
|
357
299
|
let spent = 0;
|
|
358
300
|
for (const mention of mentions) {
|
|
359
301
|
if (spent >= tokenBudget) break;
|
|
360
|
-
const raw = mention.startsWith("~/") ?
|
|
302
|
+
const raw = mention.startsWith("~/") ? join(process.env.HOME ?? "", mention.slice(2)) : mention;
|
|
361
303
|
const direct = isAbsolute(raw) ? raw : resolve(cwd2, raw);
|
|
362
304
|
let isDir = false;
|
|
363
305
|
try {
|
|
@@ -484,7 +426,7 @@ function buildSubagentTool(deps) {
|
|
|
484
426
|
|
|
485
427
|
// src/images.ts
|
|
486
428
|
import { readFile as readFile3, stat as stat2 } from "fs/promises";
|
|
487
|
-
import { resolve as resolve2, extname, relative as relative2, isAbsolute as isAbsolute2, join as
|
|
429
|
+
import { resolve as resolve2, extname, relative as relative2, isAbsolute as isAbsolute2, join as join2 } from "path";
|
|
488
430
|
import { execFile } from "child_process";
|
|
489
431
|
import { tmpdir, platform as platform2 } from "os";
|
|
490
432
|
var EXT_TO_MEDIA = {
|
|
@@ -505,7 +447,7 @@ function run(cmd, args) {
|
|
|
505
447
|
});
|
|
506
448
|
}
|
|
507
449
|
async function grabClipboardImage() {
|
|
508
|
-
const out =
|
|
450
|
+
const out = join2(tmpdir(), `zeta-clip-${process.pid}-${process.hrtime.bigint()}.png`);
|
|
509
451
|
const os = platform2();
|
|
510
452
|
if (os === "darwin") {
|
|
511
453
|
const script = `set thePath to "${out}"
|
|
@@ -568,7 +510,7 @@ async function scanImages(message, cwd2) {
|
|
|
568
510
|
}
|
|
569
511
|
}
|
|
570
512
|
for (const tok of tokens) {
|
|
571
|
-
const raw = tok.startsWith("~/") ?
|
|
513
|
+
const raw = tok.startsWith("~/") ? join2(process.env.HOME ?? "", tok.slice(2)) : tok;
|
|
572
514
|
const abs = isAbsolute2(raw) ? raw : resolve2(cwd2, raw);
|
|
573
515
|
const mediaType = EXT_TO_MEDIA[extname(abs).toLowerCase()];
|
|
574
516
|
if (!mediaType) continue;
|
|
@@ -624,7 +566,7 @@ async function fetchReadable(url) {
|
|
|
624
566
|
const res = await fetch(url, {
|
|
625
567
|
signal: ctrl.signal,
|
|
626
568
|
redirect: "follow",
|
|
627
|
-
headers: { "user-agent": "
|
|
569
|
+
headers: { "user-agent": "wholestack-cli (+web-context)" }
|
|
628
570
|
});
|
|
629
571
|
if (!res.ok) return null;
|
|
630
572
|
const ctype = res.headers.get("content-type") ?? "";
|
|
@@ -675,7 +617,7 @@ ${body}`);
|
|
|
675
617
|
}
|
|
676
618
|
|
|
677
619
|
// src/export.ts
|
|
678
|
-
import { writeFileSync
|
|
620
|
+
import { writeFileSync } from "fs";
|
|
679
621
|
import { resolve as resolve3 } from "path";
|
|
680
622
|
function renderContent(content) {
|
|
681
623
|
if (typeof content === "string") return content.trim();
|
|
@@ -692,7 +634,7 @@ function renderContent(content) {
|
|
|
692
634
|
}
|
|
693
635
|
function renderTranscript(messages, meta) {
|
|
694
636
|
const head = [
|
|
695
|
-
`#
|
|
637
|
+
`# wholestack transcript`,
|
|
696
638
|
``,
|
|
697
639
|
`- model: ${meta.model}`,
|
|
698
640
|
meta.startedAt ? `- started: ${meta.startedAt}` : "",
|
|
@@ -716,33 +658,31 @@ ${body}
|
|
|
716
658
|
}
|
|
717
659
|
function writeTranscript(messages, meta, file, cwd2) {
|
|
718
660
|
const abs = resolve3(cwd2, file);
|
|
719
|
-
|
|
661
|
+
writeFileSync(abs, renderTranscript(messages, meta), "utf8");
|
|
720
662
|
return abs;
|
|
721
663
|
}
|
|
722
664
|
|
|
723
665
|
// src/cli.ts
|
|
724
|
-
import { existsSync as
|
|
725
|
-
import {
|
|
726
|
-
import { join as join6 } from "path";
|
|
666
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
667
|
+
import { join as join5 } from "path";
|
|
727
668
|
|
|
728
669
|
// src/update-check.ts
|
|
729
|
-
import { existsSync
|
|
730
|
-
import {
|
|
731
|
-
import { join as join4 } from "path";
|
|
670
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
671
|
+
import { join as join3 } from "path";
|
|
732
672
|
var PKG = "wholestack";
|
|
733
|
-
var CACHE =
|
|
673
|
+
var CACHE = join3(stateDir(), "update-check.json");
|
|
734
674
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
735
675
|
function readCache() {
|
|
736
676
|
try {
|
|
737
|
-
return JSON.parse(
|
|
677
|
+
return JSON.parse(readFileSync(CACHE, "utf8"));
|
|
738
678
|
} catch {
|
|
739
679
|
return { lastCheck: 0, latest: null };
|
|
740
680
|
}
|
|
741
681
|
}
|
|
742
682
|
function writeCache(c2) {
|
|
743
683
|
try {
|
|
744
|
-
|
|
745
|
-
|
|
684
|
+
mkdirSync(stateDir(), { recursive: true });
|
|
685
|
+
writeFileSync2(CACHE, JSON.stringify(c2));
|
|
746
686
|
} catch {
|
|
747
687
|
}
|
|
748
688
|
}
|
|
@@ -757,7 +697,7 @@ function isNewer(a, b) {
|
|
|
757
697
|
return false;
|
|
758
698
|
}
|
|
759
699
|
async function checkForUpdate(current) {
|
|
760
|
-
if (process.env.ZETA_NO_UPDATE_CHECK || !
|
|
700
|
+
if (process.env.ZETA_NO_UPDATE_CHECK || !existsSync) return null;
|
|
761
701
|
const cache = readCache();
|
|
762
702
|
const fresh = Date.now() - cache.lastCheck < DAY_MS;
|
|
763
703
|
let latest = cache.latest;
|
|
@@ -783,22 +723,21 @@ async function checkForUpdate(current) {
|
|
|
783
723
|
}
|
|
784
724
|
|
|
785
725
|
// src/access.ts
|
|
786
|
-
import { mkdirSync as
|
|
787
|
-
import {
|
|
788
|
-
|
|
789
|
-
var CACHE2 = join5(homedir3(), ".zeta-g", "access.json");
|
|
726
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
727
|
+
import { join as join4 } from "path";
|
|
728
|
+
var CACHE2 = join4(stateDir(), "access.json");
|
|
790
729
|
var TTL_MS = 60 * 60 * 1e3;
|
|
791
730
|
function readCache2() {
|
|
792
731
|
try {
|
|
793
|
-
return JSON.parse(
|
|
732
|
+
return JSON.parse(readFileSync2(CACHE2, "utf8"));
|
|
794
733
|
} catch {
|
|
795
734
|
return null;
|
|
796
735
|
}
|
|
797
736
|
}
|
|
798
737
|
function writeCache2(c2) {
|
|
799
738
|
try {
|
|
800
|
-
|
|
801
|
-
|
|
739
|
+
mkdirSync2(stateDir(), { recursive: true });
|
|
740
|
+
writeFileSync3(CACHE2, JSON.stringify(c2));
|
|
802
741
|
} catch {
|
|
803
742
|
}
|
|
804
743
|
}
|
|
@@ -858,12 +797,20 @@ function showPaywall(loggedIn, webUrl) {
|
|
|
858
797
|
}
|
|
859
798
|
|
|
860
799
|
// src/cli.ts
|
|
861
|
-
import { readFileSync as
|
|
862
|
-
import { basename } from "path";
|
|
863
|
-
|
|
800
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
801
|
+
import { basename, dirname as dirname2 } from "path";
|
|
802
|
+
import { fileURLToPath } from "url";
|
|
803
|
+
var VERSION = (() => {
|
|
804
|
+
try {
|
|
805
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
806
|
+
return JSON.parse(readFileSync3(join5(here, "..", "package.json"), "utf8")).version;
|
|
807
|
+
} catch {
|
|
808
|
+
return "0.0.0";
|
|
809
|
+
}
|
|
810
|
+
})();
|
|
864
811
|
function gitBranch(dir) {
|
|
865
812
|
try {
|
|
866
|
-
const head =
|
|
813
|
+
const head = readFileSync3(join5(dir, ".git", "HEAD"), "utf8").trim();
|
|
867
814
|
const m = head.match(/ref:\s*refs\/heads\/(.+)$/);
|
|
868
815
|
return m ? m[1] : head.slice(0, 7);
|
|
869
816
|
} catch {
|
|
@@ -917,19 +864,19 @@ function parse(raw) {
|
|
|
917
864
|
a.prompt = rest.join(" ").trim();
|
|
918
865
|
return a;
|
|
919
866
|
}
|
|
920
|
-
var HELP = `${c.cyan("
|
|
867
|
+
var HELP = `${c.cyan("wholestack")} \u2014 conversational coding agent for the Wholestack engine ${c.dim("(alias: zeta)")}
|
|
921
868
|
|
|
922
869
|
${c.bold("Usage")}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
870
|
+
wholestack start an interactive session
|
|
871
|
+
wholestack "build me a todo app" run one prompt and exit
|
|
872
|
+
wholestack -m zeta-g1-max "..." drive it with the most capable brain
|
|
926
873
|
|
|
927
874
|
${c.bold("Web3 security")} ${c.dim("(forge \xB7 slither \xB7 firewall \xB7 halmos \xB7 signed cert)")}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
875
|
+
wholestack audit <dir> <Contract> full auto-detect security sweep
|
|
876
|
+
wholestack prove <dir> <Contract> --property <k> prove one invariant
|
|
877
|
+
wholestack verify <dir> <Contract> --cert c.json passthrough + signed certificate
|
|
931
878
|
${c.dim("kinds: reentrancy-safety, access-control, conservation, no-value-extraction, \u2026")}
|
|
932
|
-
|
|
879
|
+
wholestack --nzt48 "audit ./contracts" NZT-48 web3 special-ops persona
|
|
933
880
|
|
|
934
881
|
${c.bold("Session")}
|
|
935
882
|
-m, --model <key> zeta-g1-lite | zeta-g1 | zeta-g1-max | vision
|
|
@@ -949,15 +896,15 @@ ${c.bold("Extensibility")}
|
|
|
949
896
|
--no-mcp skip MCP servers --no-plugins skip plugins
|
|
950
897
|
|
|
951
898
|
${c.bold("Build engine")}
|
|
952
|
-
--zeta-url <u>
|
|
899
|
+
--zeta-url <u> build engine base URL (default https://wholestack.ai)
|
|
953
900
|
--local build via the in-repo worker (no server needed)
|
|
954
|
-
--http build via the running
|
|
901
|
+
--http build via the running engine only
|
|
955
902
|
|
|
956
|
-
${c.bold("Auth")} ${c.dim("(set once, then just run
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
903
|
+
${c.bold("Auth")} ${c.dim("(set once, then just run wholestack)")}
|
|
904
|
+
wholestack login browser sign-in (or pick member/brain/engine, paste key)
|
|
905
|
+
wholestack login --member <key> membership key (keep + deploy generated apps)
|
|
906
|
+
wholestack login --brain <key> brain key (powers the Zeta-G1.0 tiers)
|
|
907
|
+
wholestack login --build <key> build-engine key (for /build)
|
|
961
908
|
|
|
962
909
|
${c.bold("In a session")} ${c.dim("(type /help for the full list)")}
|
|
963
910
|
/model /cost /tools /undo /redo /checkpoints /compact /resume /memory /mcp /mode /think /init /doctor /clear /exit
|
|
@@ -992,14 +939,14 @@ async function runSecuritySubcommand(raw) {
|
|
|
992
939
|
}
|
|
993
940
|
function maybeYoloNotice() {
|
|
994
941
|
try {
|
|
995
|
-
const dir =
|
|
996
|
-
const marker =
|
|
997
|
-
if (
|
|
942
|
+
const dir = stateDir();
|
|
943
|
+
const marker = join5(dir, "yolo-notice-seen");
|
|
944
|
+
if (existsSync2(marker)) return;
|
|
998
945
|
line(
|
|
999
946
|
" " + c.yellow("\u26A1 yolo mode") + c.dim(" \u2014 actions run without confirmation. ") + c.cyan("/mode default") + c.dim(" to require approvals \xB7 /undo reverts.") + "\n"
|
|
1000
947
|
);
|
|
1001
|
-
|
|
1002
|
-
|
|
948
|
+
mkdirSync3(dir, { recursive: true });
|
|
949
|
+
writeFileSync4(marker, (/* @__PURE__ */ new Date()).toISOString());
|
|
1003
950
|
} catch {
|
|
1004
951
|
}
|
|
1005
952
|
}
|
|
@@ -1054,7 +1001,7 @@ async function runLogin(raw) {
|
|
|
1054
1001
|
}
|
|
1055
1002
|
if (!name || !value) {
|
|
1056
1003
|
if (!stdin.isTTY) {
|
|
1057
|
-
line(c.red(" usage:
|
|
1004
|
+
line(c.red(" usage: wholestack login --member <key> | --brain <key> | --build <key>"));
|
|
1058
1005
|
return 1;
|
|
1059
1006
|
}
|
|
1060
1007
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
@@ -1073,7 +1020,7 @@ async function runLogin(raw) {
|
|
|
1073
1020
|
const path = saveKey(name, value);
|
|
1074
1021
|
if (name === "ZETA_API_KEY") clearAccessCache();
|
|
1075
1022
|
line(c.green(` \u2713 saved key for the ${what}`) + c.dim(` \u2192 ${path} (chmod 600)`));
|
|
1076
|
-
line(c.dim(" now just run `
|
|
1023
|
+
line(c.dim(" now just run `wholestack`."));
|
|
1077
1024
|
return 0;
|
|
1078
1025
|
}
|
|
1079
1026
|
var EMPTY_PLUGINS = {
|
|
@@ -1295,7 +1242,7 @@ ${m.context}` : args.prompt;
|
|
|
1295
1242
|
await ic.runInterruptible((sig) => agent.send(text, sig, images));
|
|
1296
1243
|
statusLine({
|
|
1297
1244
|
model: modelLabel(modelKey),
|
|
1298
|
-
tokens: agent.usage.
|
|
1245
|
+
tokens: agent.usage.outputTokens,
|
|
1299
1246
|
tps: agent.lastTps,
|
|
1300
1247
|
elapsedMs: Date.now() - t0,
|
|
1301
1248
|
cost: agent.usage.totalCost,
|
package/dist/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ declare class Permissions {
|
|
|
70
70
|
private readonly confirm?;
|
|
71
71
|
/**
|
|
72
72
|
* Persist a chosen mode so it survives across sessions. Wired by the CLI to
|
|
73
|
-
* write `~/.
|
|
73
|
+
* write `~/.wholestack/config.json`. Optional — when absent, choices are
|
|
74
74
|
* session-only (e.g. piped / non-TTY runs).
|
|
75
75
|
*/
|
|
76
76
|
private readonly persistMode?;
|
|
@@ -79,7 +79,7 @@ declare class Permissions {
|
|
|
79
79
|
constructor(mode: PermissionMode, confirm?: ConfirmFn | undefined,
|
|
80
80
|
/**
|
|
81
81
|
* Persist a chosen mode so it survives across sessions. Wired by the CLI to
|
|
82
|
-
* write `~/.
|
|
82
|
+
* write `~/.wholestack/config.json`. Optional — when absent, choices are
|
|
83
83
|
* session-only (e.g. piped / non-TTY runs).
|
|
84
84
|
*/
|
|
85
85
|
persistMode?: ((mode: PermissionMode) => void) | undefined);
|
|
@@ -194,6 +194,7 @@ declare function buildTools(ctx: ToolContext): {
|
|
|
194
194
|
scope: "full" | "static" | "component" | "page";
|
|
195
195
|
buildModel: "zeta-g1" | "zeta-g1-max";
|
|
196
196
|
keep: boolean;
|
|
197
|
+
themeId?: "slate-minimal" | "clean-inter" | "friendly-nunito" | "geometric-jakarta" | "techno-mono" | undefined;
|
|
197
198
|
}, BuildResult | {
|
|
198
199
|
ok: boolean;
|
|
199
200
|
liveUrl: string | undefined;
|
|
@@ -566,7 +567,7 @@ declare class HookRunner {
|
|
|
566
567
|
}
|
|
567
568
|
/** Merge hook sets (later wins on nothing — they all concatenate). */
|
|
568
569
|
declare function mergeHookSets(...sets: HookSet[]): HookSet;
|
|
569
|
-
/** Load hooks.json from the global config dir and the project's .zeta-g
|
|
570
|
+
/** Load hooks.json from the global config dir and the project's .wholestack/ (or legacy .zeta-g/). */
|
|
570
571
|
declare function loadHookFiles(cwd: string): HookSet;
|
|
571
572
|
/**
|
|
572
573
|
* Wrap every tool's execute so PreToolUse hooks can block it and PostToolUse
|
|
@@ -635,6 +636,8 @@ declare class UsageMeter {
|
|
|
635
636
|
private cost;
|
|
636
637
|
add(modelId: string, u: TokenUsage): void;
|
|
637
638
|
get totalTokens(): number;
|
|
639
|
+
/** Output tokens only — the "what did it actually generate" number. */
|
|
640
|
+
get outputTokens(): number;
|
|
638
641
|
get totalCost(): number;
|
|
639
642
|
snapshot(): {
|
|
640
643
|
input: number;
|
|
@@ -905,7 +908,7 @@ declare function loadMcpTools(opts: LoadMcpOptions): Promise<LoadedMcp>;
|
|
|
905
908
|
|
|
906
909
|
/**
|
|
907
910
|
* Slash commands — the in-session control surface. An extensible registry, not
|
|
908
|
-
* a hardcoded if/else: built-ins live here, plugins and ~/.
|
|
911
|
+
* a hardcoded if/else: built-ins live here, plugins and ~/.wholestack/commands/*.md
|
|
909
912
|
* register more. A command returns a CommandResult the REPL acts on, so the
|
|
910
913
|
* registry stays decoupled from the agent it drives.
|
|
911
914
|
*/
|
|
@@ -971,7 +974,7 @@ declare class CommandRegistry {
|
|
|
971
974
|
get(name: string): SlashCommand | undefined;
|
|
972
975
|
list(): SlashCommand[];
|
|
973
976
|
names(): string[];
|
|
974
|
-
/** Load *.md commands from ~/.
|
|
977
|
+
/** Load *.md commands from ~/.wholestack/commands and <cwd>/.wholestack/commands (or legacy .zeta-g/). */
|
|
975
978
|
loadCustom(cwd: string): void;
|
|
976
979
|
dispatch(input: string, base: Omit<CommandContext, "args" | "commands">): Promise<CommandResult | null>;
|
|
977
980
|
}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wholestack",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "Wholestack — a pro-grade conversational terminal agent for the Wholestack codegen engine. Talk to it in plain language: it writes ISL, generates full-stack or Solidity apps, and proves them with ShipGate. Browser login, membership-gated builds, slash commands, sessions, plan mode, diffs, MCP, plugins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|