@use-aistack/cli 0.15.0 → 0.16.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 +2 -0
- package/dist/index.js +245 -99
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -377,12 +377,12 @@ function apiEquivalentCost(modelKey, t, atMs) {
|
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
// src/version.ts
|
|
380
|
-
var CLI_VERSION = true ? "0.
|
|
380
|
+
var CLI_VERSION = true ? "0.16.0" : "0.0.0-dev";
|
|
381
381
|
|
|
382
382
|
// src/api.ts
|
|
383
383
|
var BASE_URL = process.env.AISTACK_URL || "https://aistack.to";
|
|
384
|
-
async function request(
|
|
385
|
-
return fetch(`${BASE_URL}${
|
|
384
|
+
async function request(path14, options = {}) {
|
|
385
|
+
return fetch(`${BASE_URL}${path14}`, {
|
|
386
386
|
...options,
|
|
387
387
|
headers: {
|
|
388
388
|
"Content-Type": "application/json",
|
|
@@ -800,9 +800,9 @@ function canonicalizeRepoUrl(input) {
|
|
|
800
800
|
function repoNameFromCanonical(canonical) {
|
|
801
801
|
return parseRepo(canonical)?.repo ?? "";
|
|
802
802
|
}
|
|
803
|
-
function normalizeUpstreamPath(
|
|
804
|
-
if (!
|
|
805
|
-
return
|
|
803
|
+
function normalizeUpstreamPath(path14) {
|
|
804
|
+
if (!path14) return "";
|
|
805
|
+
return path14.split("/").filter(Boolean).join("/");
|
|
806
806
|
}
|
|
807
807
|
|
|
808
808
|
// src/git.ts
|
|
@@ -848,16 +848,16 @@ function buildRepoLinkResource(canonical) {
|
|
|
848
848
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
849
849
|
import { homedir as homedir2 } from "node:os";
|
|
850
850
|
import { join as join2 } from "node:path";
|
|
851
|
-
function readJson(
|
|
851
|
+
function readJson(path14) {
|
|
852
852
|
try {
|
|
853
|
-
if (!existsSync2(
|
|
854
|
-
return JSON.parse(readFileSync2(
|
|
853
|
+
if (!existsSync2(path14)) return null;
|
|
854
|
+
return JSON.parse(readFileSync2(path14, "utf-8"));
|
|
855
855
|
} catch {
|
|
856
856
|
return null;
|
|
857
857
|
}
|
|
858
858
|
}
|
|
859
|
-
function hooksFrom(
|
|
860
|
-
const hooks = readJson(
|
|
859
|
+
function hooksFrom(path14, source, out, seen) {
|
|
860
|
+
const hooks = readJson(path14)?.hooks;
|
|
861
861
|
if (!hooks || typeof hooks !== "object") return;
|
|
862
862
|
for (const [event, config] of Object.entries(hooks)) {
|
|
863
863
|
const stableKey = `hooks:${source}:${event}`;
|
|
@@ -1006,16 +1006,16 @@ function buildMcpResource(name, group, pkg) {
|
|
|
1006
1006
|
pkg
|
|
1007
1007
|
};
|
|
1008
1008
|
}
|
|
1009
|
-
function readText(
|
|
1009
|
+
function readText(path14) {
|
|
1010
1010
|
try {
|
|
1011
|
-
if (!existsSync3(
|
|
1012
|
-
return readFileSync3(
|
|
1011
|
+
if (!existsSync3(path14)) return null;
|
|
1012
|
+
return readFileSync3(path14, "utf-8");
|
|
1013
1013
|
} catch {
|
|
1014
1014
|
return null;
|
|
1015
1015
|
}
|
|
1016
1016
|
}
|
|
1017
|
-
function readParsed(
|
|
1018
|
-
const raw = readText(
|
|
1017
|
+
function readParsed(path14, parse2) {
|
|
1018
|
+
const raw = readText(path14);
|
|
1019
1019
|
if (raw === null) return null;
|
|
1020
1020
|
try {
|
|
1021
1021
|
return parse2(raw);
|
|
@@ -1023,14 +1023,14 @@ function readParsed(path13, parse2) {
|
|
|
1023
1023
|
return null;
|
|
1024
1024
|
}
|
|
1025
1025
|
}
|
|
1026
|
-
function readJson2(
|
|
1027
|
-
return readParsed(
|
|
1026
|
+
function readJson2(path14) {
|
|
1027
|
+
return readParsed(path14, JSON.parse);
|
|
1028
1028
|
}
|
|
1029
|
-
function readYaml(
|
|
1030
|
-
return readParsed(
|
|
1029
|
+
function readYaml(path14) {
|
|
1030
|
+
return readParsed(path14, parseYaml);
|
|
1031
1031
|
}
|
|
1032
|
-
function readToml(
|
|
1033
|
-
return readParsed(
|
|
1032
|
+
function readToml(path14) {
|
|
1033
|
+
return readParsed(path14, parseToml);
|
|
1034
1034
|
}
|
|
1035
1035
|
function continueListToMap(file) {
|
|
1036
1036
|
if (!file?.mcpServers?.length) return void 0;
|
|
@@ -1169,8 +1169,8 @@ function resolveSource(entry, mpRepoUrl) {
|
|
|
1169
1169
|
const src = entry.source;
|
|
1170
1170
|
if (typeof src === "string") {
|
|
1171
1171
|
if (!mpRepoUrl) return null;
|
|
1172
|
-
const
|
|
1173
|
-
return { url: mpRepoUrl, path:
|
|
1172
|
+
const path14 = src.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
1173
|
+
return { url: mpRepoUrl, path: path14 || void 0 };
|
|
1174
1174
|
}
|
|
1175
1175
|
if (src && typeof src === "object" && src.url) {
|
|
1176
1176
|
return { url: src.url, path: src.path, sha: src.sha };
|
|
@@ -1207,10 +1207,10 @@ function resolvePluginLinks(installed, marketplaces, manifests) {
|
|
|
1207
1207
|
}
|
|
1208
1208
|
return out;
|
|
1209
1209
|
}
|
|
1210
|
-
function readJson3(
|
|
1210
|
+
function readJson3(path14) {
|
|
1211
1211
|
try {
|
|
1212
|
-
if (!existsSync4(
|
|
1213
|
-
return JSON.parse(readFileSync4(
|
|
1212
|
+
if (!existsSync4(path14)) return null;
|
|
1213
|
+
return JSON.parse(readFileSync4(path14, "utf-8"));
|
|
1214
1214
|
} catch {
|
|
1215
1215
|
return null;
|
|
1216
1216
|
}
|
|
@@ -1844,7 +1844,7 @@ function diffResources(current, existing) {
|
|
|
1844
1844
|
// src/commands/connect.ts
|
|
1845
1845
|
import { spawnSync } from "node:child_process";
|
|
1846
1846
|
import { cpSync, existsSync as existsSync6 } from "node:fs";
|
|
1847
|
-
import { homedir as
|
|
1847
|
+
import { homedir as homedir14 } from "node:os";
|
|
1848
1848
|
import { dirname as dirname3, join as join6 } from "node:path";
|
|
1849
1849
|
import { fileURLToPath } from "node:url";
|
|
1850
1850
|
import * as p3 from "@clack/prompts";
|
|
@@ -3634,13 +3634,13 @@ function canonicalJson(value) {
|
|
|
3634
3634
|
function fnv1a64(text) {
|
|
3635
3635
|
const prime = 0x100000001b3n;
|
|
3636
3636
|
const mask = 0xffffffffffffffffn;
|
|
3637
|
-
let
|
|
3637
|
+
let hash2 = 0xcbf29ce484222325n;
|
|
3638
3638
|
const bytes = new TextEncoder().encode(text);
|
|
3639
3639
|
for (const byte of bytes) {
|
|
3640
|
-
|
|
3641
|
-
|
|
3640
|
+
hash2 ^= BigInt(byte);
|
|
3641
|
+
hash2 = hash2 * prime & mask;
|
|
3642
3642
|
}
|
|
3643
|
-
return
|
|
3643
|
+
return hash2.toString(16).padStart(16, "0");
|
|
3644
3644
|
}
|
|
3645
3645
|
function dayFingerprint(day) {
|
|
3646
3646
|
return fnv1a64(
|
|
@@ -5441,11 +5441,11 @@ function ingestWithRetry(agg, file, opts) {
|
|
|
5441
5441
|
}
|
|
5442
5442
|
}
|
|
5443
5443
|
function ingestFile2(agg, file, opts) {
|
|
5444
|
-
const
|
|
5444
|
+
const readFile4 = opts.readFileImpl ?? readFileSync6;
|
|
5445
5445
|
let text;
|
|
5446
5446
|
if (file.endsWith(".zst")) {
|
|
5447
5447
|
if (zstdDecompress === null) throw readError("zstd-unsupported");
|
|
5448
|
-
const raw =
|
|
5448
|
+
const raw = readFile4(file);
|
|
5449
5449
|
try {
|
|
5450
5450
|
text = zstdDecompress(
|
|
5451
5451
|
Buffer.isBuffer(raw) ? raw : Buffer.from(raw)
|
|
@@ -5454,7 +5454,7 @@ function ingestFile2(agg, file, opts) {
|
|
|
5454
5454
|
throw readError("zstd-corrupt");
|
|
5455
5455
|
}
|
|
5456
5456
|
} else {
|
|
5457
|
-
text =
|
|
5457
|
+
text = readFile4(file).toString("utf8");
|
|
5458
5458
|
}
|
|
5459
5459
|
const records = [];
|
|
5460
5460
|
let nonEmptyLines = 0;
|
|
@@ -6610,15 +6610,129 @@ function ingestContribution(agg, row) {
|
|
|
6610
6610
|
|
|
6611
6611
|
// src/harness/grok/scan.ts
|
|
6612
6612
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
6613
|
-
import { readdir as
|
|
6614
|
-
import { homedir as
|
|
6615
|
-
import
|
|
6613
|
+
import { readdir as readdir5, readFile as readFile3, stat as stat5 } from "node:fs/promises";
|
|
6614
|
+
import { homedir as homedir11 } from "node:os";
|
|
6615
|
+
import path9 from "node:path";
|
|
6616
6616
|
import readline2 from "node:readline";
|
|
6617
6617
|
import { parse as parseToml3 } from "smol-toml";
|
|
6618
|
+
|
|
6619
|
+
// src/harness/grok/context.ts
|
|
6620
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
6621
|
+
import { appendFile, mkdir as mkdir2, readdir as readdir4, readFile as readFile2, unlink } from "node:fs/promises";
|
|
6622
|
+
import { homedir as homedir10 } from "node:os";
|
|
6623
|
+
import path8 from "node:path";
|
|
6624
|
+
var DAY_MS = 864e5;
|
|
6625
|
+
var hash = (value) => createHash2("sha256").update(value).digest("hex");
|
|
6626
|
+
function contextCall(value) {
|
|
6627
|
+
const row = asObj(value);
|
|
6628
|
+
if (row?.src !== "shell" || row.msg !== "shell.turn.inference_done")
|
|
6629
|
+
return null;
|
|
6630
|
+
const session = asStr(row.sid);
|
|
6631
|
+
const ts = asStr(row.ts);
|
|
6632
|
+
const ctx = asObj(row.ctx);
|
|
6633
|
+
const tokens = ctx?.prompt_tokens;
|
|
6634
|
+
const loop = ctx?.loop_index;
|
|
6635
|
+
const tsMs = ts ? Date.parse(ts) : NaN;
|
|
6636
|
+
if (!session || !Number.isFinite(tsMs) || typeof tokens !== "number" || !Number.isSafeInteger(tokens) || tokens < 0 || typeof loop !== "number" || !Number.isSafeInteger(loop) || loop < 0)
|
|
6637
|
+
return null;
|
|
6638
|
+
return {
|
|
6639
|
+
id: hash(JSON.stringify([session, tsMs, row.pid ?? null, loop, tokens])),
|
|
6640
|
+
session,
|
|
6641
|
+
tsMs,
|
|
6642
|
+
tokens
|
|
6643
|
+
};
|
|
6644
|
+
}
|
|
6645
|
+
function contextCacheDirectory(root) {
|
|
6646
|
+
return path8.join(
|
|
6647
|
+
homedir10(),
|
|
6648
|
+
".config",
|
|
6649
|
+
"aistack",
|
|
6650
|
+
"grok-context",
|
|
6651
|
+
hash(path8.resolve(root))
|
|
6652
|
+
);
|
|
6653
|
+
}
|
|
6654
|
+
async function optionalRead(file) {
|
|
6655
|
+
try {
|
|
6656
|
+
return await readFile2(file, "utf8");
|
|
6657
|
+
} catch (error) {
|
|
6658
|
+
if (error.code === "ENOENT") return "";
|
|
6659
|
+
throw error;
|
|
6660
|
+
}
|
|
6661
|
+
}
|
|
6662
|
+
async function retainedContextCalls(root, sessions, cacheDir = contextCacheDirectory(root), now = Date.now()) {
|
|
6663
|
+
const cutoff = now - 400 * DAY_MS;
|
|
6664
|
+
const calls = /* @__PURE__ */ new Map();
|
|
6665
|
+
let files = [];
|
|
6666
|
+
try {
|
|
6667
|
+
files = await readdir4(cacheDir);
|
|
6668
|
+
} catch (error) {
|
|
6669
|
+
if (error.code !== "ENOENT") throw error;
|
|
6670
|
+
}
|
|
6671
|
+
for (const file of files) {
|
|
6672
|
+
if (!/^\d{4}-\d{2}-\d{2}\.jsonl$/.test(file)) continue;
|
|
6673
|
+
if (Date.parse(file.slice(0, 10)) + DAY_MS < cutoff) {
|
|
6674
|
+
await unlink(path8.join(cacheDir, file)).catch(
|
|
6675
|
+
(error) => {
|
|
6676
|
+
if (error.code !== "ENOENT") throw error;
|
|
6677
|
+
}
|
|
6678
|
+
);
|
|
6679
|
+
continue;
|
|
6680
|
+
}
|
|
6681
|
+
const raw2 = await optionalRead(path8.join(cacheDir, file));
|
|
6682
|
+
if (raw2 && !raw2.endsWith("\n"))
|
|
6683
|
+
throw new Error("Incomplete Grok context cache");
|
|
6684
|
+
for (const line of raw2.split("\n").filter(Boolean)) {
|
|
6685
|
+
const call = asObj(JSON.parse(line));
|
|
6686
|
+
if (!call || typeof call.id !== "string" || !/^[a-f0-9]{64}$/.test(call.id) || typeof call.session !== "string" || typeof call.tsMs !== "number" || !Number.isFinite(call.tsMs) || typeof call.tokens !== "number" || !Number.isSafeInteger(call.tokens) || call.tokens < 0)
|
|
6687
|
+
throw new Error("Invalid Grok context cache");
|
|
6688
|
+
if (call.tsMs >= cutoff && call.tsMs <= now)
|
|
6689
|
+
calls.set(call.id, {
|
|
6690
|
+
id: call.id,
|
|
6691
|
+
session: call.session,
|
|
6692
|
+
tsMs: call.tsMs,
|
|
6693
|
+
tokens: call.tokens
|
|
6694
|
+
});
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6697
|
+
const raw = await optionalRead(
|
|
6698
|
+
path8.join(root, "..", "logs", "unified.jsonl")
|
|
6699
|
+
);
|
|
6700
|
+
const additions = /* @__PURE__ */ new Map();
|
|
6701
|
+
for (const line of raw.slice(0, raw.lastIndexOf("\n") + 1).split("\n")) {
|
|
6702
|
+
let value;
|
|
6703
|
+
try {
|
|
6704
|
+
value = JSON.parse(line);
|
|
6705
|
+
} catch {
|
|
6706
|
+
continue;
|
|
6707
|
+
}
|
|
6708
|
+
const call = contextCall(value);
|
|
6709
|
+
if (!call || !sessions.has(call.session) || call.tsMs < cutoff || call.tsMs > now || calls.has(call.id))
|
|
6710
|
+
continue;
|
|
6711
|
+
calls.set(call.id, call);
|
|
6712
|
+
const date = new Date(call.tsMs).toISOString().slice(0, 10);
|
|
6713
|
+
const lines2 = additions.get(date) ?? [];
|
|
6714
|
+
lines2.push(JSON.stringify(call));
|
|
6715
|
+
additions.set(date, lines2);
|
|
6716
|
+
}
|
|
6717
|
+
if (additions.size) {
|
|
6718
|
+
await mkdir2(cacheDir, { recursive: true, mode: 448 });
|
|
6719
|
+
for (const [date, lines2] of additions) {
|
|
6720
|
+
await appendFile(
|
|
6721
|
+
path8.join(cacheDir, `${date}.jsonl`),
|
|
6722
|
+
`${lines2.join("\n")}
|
|
6723
|
+
`,
|
|
6724
|
+
{ mode: 384 }
|
|
6725
|
+
);
|
|
6726
|
+
}
|
|
6727
|
+
}
|
|
6728
|
+
return [...calls.values()].filter((call) => sessions.has(call.session)).sort((a, b) => a.tsMs - b.tsMs || a.id.localeCompare(b.id));
|
|
6729
|
+
}
|
|
6730
|
+
|
|
6731
|
+
// src/harness/grok/scan.ts
|
|
6618
6732
|
function sessionRoots() {
|
|
6619
6733
|
return [
|
|
6620
|
-
|
|
6621
|
-
process.env.GROK_HOME ||
|
|
6734
|
+
path9.join(
|
|
6735
|
+
process.env.GROK_HOME || path9.join(homedir11(), ".grok"),
|
|
6622
6736
|
"sessions"
|
|
6623
6737
|
)
|
|
6624
6738
|
];
|
|
@@ -6650,7 +6764,7 @@ async function stableRead(file, jsonl) {
|
|
|
6650
6764
|
if (before.size === after.size && before.mtimeMs === after.mtimeMs)
|
|
6651
6765
|
return { lines: lines2, complete: true };
|
|
6652
6766
|
} else {
|
|
6653
|
-
const raw = await
|
|
6767
|
+
const raw = await readFile3(file, "utf8");
|
|
6654
6768
|
const after = await stat5(file);
|
|
6655
6769
|
if (before.size === after.size && before.mtimeMs === after.mtimeMs)
|
|
6656
6770
|
return { json: JSON.parse(raw), complete: true };
|
|
@@ -6662,16 +6776,16 @@ async function stableRead(file, jsonl) {
|
|
|
6662
6776
|
}
|
|
6663
6777
|
async function directories(root) {
|
|
6664
6778
|
try {
|
|
6665
|
-
const workspaces = await
|
|
6779
|
+
const workspaces = await readdir5(root, { withFileTypes: true });
|
|
6666
6780
|
const out = [];
|
|
6667
6781
|
for (const workspace of workspaces) {
|
|
6668
6782
|
if (!workspace.isDirectory() || workspace.isSymbolicLink()) continue;
|
|
6669
|
-
const workspacePath =
|
|
6670
|
-
for (const session of await
|
|
6783
|
+
const workspacePath = path9.join(root, workspace.name);
|
|
6784
|
+
for (const session of await readdir5(workspacePath, {
|
|
6671
6785
|
withFileTypes: true
|
|
6672
6786
|
})) {
|
|
6673
6787
|
if (session.isDirectory() && !session.isSymbolicLink())
|
|
6674
|
-
out.push(
|
|
6788
|
+
out.push(path9.join(workspacePath, session.name));
|
|
6675
6789
|
}
|
|
6676
6790
|
}
|
|
6677
6791
|
return out.sort();
|
|
@@ -6683,7 +6797,7 @@ async function modelAliasesForRoot(root) {
|
|
|
6683
6797
|
if (process.env.GROK_MODELS_BASE_URL) return /* @__PURE__ */ new Map();
|
|
6684
6798
|
try {
|
|
6685
6799
|
const parsed = asObj(
|
|
6686
|
-
parseToml3(await
|
|
6800
|
+
parseToml3(await readFile3(path9.join(root, "..", "config.toml"), "utf8"))
|
|
6687
6801
|
);
|
|
6688
6802
|
if (!parsed || asObj(parsed.endpoints)?.models_base_url) return /* @__PURE__ */ new Map();
|
|
6689
6803
|
const models = asObj(parsed.model);
|
|
@@ -6706,6 +6820,7 @@ async function scan4(agg, opts = {}) {
|
|
|
6706
6820
|
let complete = true;
|
|
6707
6821
|
for (const root of opts.roots ?? sessionRoots()) {
|
|
6708
6822
|
const aliases = await modelAliasesForRoot(root);
|
|
6823
|
+
const contextSessions = /* @__PURE__ */ new Map();
|
|
6709
6824
|
const dirs = await directories(root);
|
|
6710
6825
|
if (dirs === null) {
|
|
6711
6826
|
complete = false;
|
|
@@ -6714,7 +6829,7 @@ async function scan4(agg, opts = {}) {
|
|
|
6714
6829
|
for (const dir of dirs) {
|
|
6715
6830
|
let entries;
|
|
6716
6831
|
try {
|
|
6717
|
-
entries = await
|
|
6832
|
+
entries = await readdir5(dir, { withFileTypes: true });
|
|
6718
6833
|
} catch {
|
|
6719
6834
|
complete = false;
|
|
6720
6835
|
continue;
|
|
@@ -6722,10 +6837,10 @@ async function scan4(agg, opts = {}) {
|
|
|
6722
6837
|
const files = new Map(
|
|
6723
6838
|
entries.filter(
|
|
6724
6839
|
(e) => e.isFile() && (isGrokEvidenceFile(e.name) || e.name === "summary.json")
|
|
6725
|
-
).map((e) => [e.name,
|
|
6840
|
+
).map((e) => [e.name, path9.join(dir, e.name)])
|
|
6726
6841
|
);
|
|
6727
6842
|
let projectDir = dir;
|
|
6728
|
-
let sessionFallback =
|
|
6843
|
+
let sessionFallback = path9.basename(dir);
|
|
6729
6844
|
let child = false;
|
|
6730
6845
|
let parentSession;
|
|
6731
6846
|
const summary = files.get("summary.json");
|
|
@@ -6743,6 +6858,7 @@ async function scan4(agg, opts = {}) {
|
|
|
6743
6858
|
parentSession = asStr(value?.parentSessionId) ?? asStr(value?.parent_session_id) ?? asStr(info?.parentSessionId) ?? asStr(info?.parent_session_id) ?? void 0;
|
|
6744
6859
|
child = parentSession !== void 0;
|
|
6745
6860
|
}
|
|
6861
|
+
contextSessions.set(sessionFallback, { projectDir, parentSession });
|
|
6746
6862
|
let rows = [];
|
|
6747
6863
|
let precedence = 0;
|
|
6748
6864
|
const usage = files.get("usage.json");
|
|
@@ -6756,7 +6872,11 @@ async function scan4(agg, opts = {}) {
|
|
|
6756
6872
|
}
|
|
6757
6873
|
stats.filesRead++;
|
|
6758
6874
|
rows = sidecarContributions(read3.json, projectDir);
|
|
6759
|
-
if (rows.length > 0)
|
|
6875
|
+
if (rows.length > 0) {
|
|
6876
|
+
precedence = 2;
|
|
6877
|
+
for (const row of rows)
|
|
6878
|
+
contextSessions.set(row.sessionId, { projectDir, parentSession });
|
|
6879
|
+
}
|
|
6760
6880
|
}
|
|
6761
6881
|
if (child) {
|
|
6762
6882
|
rows = [];
|
|
@@ -6829,6 +6949,32 @@ async function scan4(agg, opts = {}) {
|
|
|
6829
6949
|
}
|
|
6830
6950
|
opts.onProgress?.(stats.filesFound);
|
|
6831
6951
|
}
|
|
6952
|
+
try {
|
|
6953
|
+
const calls = await retainedContextCalls(
|
|
6954
|
+
root,
|
|
6955
|
+
new Set(contextSessions.keys()),
|
|
6956
|
+
opts.contextCacheDir
|
|
6957
|
+
);
|
|
6958
|
+
for (const call of calls) {
|
|
6959
|
+
if (opts.sinceMs !== void 0 && call.tsMs < opts.sinceMs) continue;
|
|
6960
|
+
const source = contextSessions.get(call.session);
|
|
6961
|
+
agg.workflow.ingest({
|
|
6962
|
+
type: "response",
|
|
6963
|
+
session: call.session,
|
|
6964
|
+
projectWorkspace: source?.projectDir,
|
|
6965
|
+
parentSession: source?.parentSession,
|
|
6966
|
+
tsMs: call.tsMs,
|
|
6967
|
+
responseId: `context:${call.id}`,
|
|
6968
|
+
contextTokens: call.tokens
|
|
6969
|
+
});
|
|
6970
|
+
const dates = sessionDates.get(call.session) ?? /* @__PURE__ */ new Set();
|
|
6971
|
+
dates.add(new Date(call.tsMs).toISOString().slice(0, 10));
|
|
6972
|
+
sessionDates.set(call.session, dates);
|
|
6973
|
+
}
|
|
6974
|
+
} catch {
|
|
6975
|
+
complete = false;
|
|
6976
|
+
stats.filesUnreadable++;
|
|
6977
|
+
}
|
|
6832
6978
|
}
|
|
6833
6979
|
for (const { rows } of candidates.values()) {
|
|
6834
6980
|
for (const row of rows) {
|
|
@@ -7056,14 +7202,14 @@ function noteConfiguredMcpServers2(agg, state, serverNames) {
|
|
|
7056
7202
|
|
|
7057
7203
|
// src/harness/opencode/scan.ts
|
|
7058
7204
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
7059
|
-
import { readdir as
|
|
7060
|
-
import { homedir as
|
|
7061
|
-
import
|
|
7205
|
+
import { readdir as readdir6, stat as stat6 } from "node:fs/promises";
|
|
7206
|
+
import { homedir as homedir12 } from "node:os";
|
|
7207
|
+
import path10 from "node:path";
|
|
7062
7208
|
var OPENCODE_MIGRATION_CEILING = 20260622202450;
|
|
7063
7209
|
function opencodeDataDirs() {
|
|
7064
7210
|
const xdg = process.env.XDG_DATA_HOME;
|
|
7065
|
-
const base = xdg ||
|
|
7066
|
-
return [
|
|
7211
|
+
const base = xdg || path10.join(homedir12(), ".local", "share");
|
|
7212
|
+
return [path10.join(base, "opencode")];
|
|
7067
7213
|
}
|
|
7068
7214
|
function isStoreFile(basename2) {
|
|
7069
7215
|
return basename2 === "opencode.db" || /^opencode-[^/]+\.db$/.test(basename2);
|
|
@@ -7072,8 +7218,8 @@ async function dbFilesIn(root) {
|
|
|
7072
7218
|
const override = process.env.OPENCODE_DB;
|
|
7073
7219
|
if (override) return [override];
|
|
7074
7220
|
try {
|
|
7075
|
-
const entries = await
|
|
7076
|
-
return entries.filter((e) => e.isFile() && isStoreFile(e.name)).map((e) =>
|
|
7221
|
+
const entries = await readdir6(root, { withFileTypes: true });
|
|
7222
|
+
return entries.filter((e) => e.isFile() && isStoreFile(e.name)).map((e) => path10.join(root, e.name)).sort();
|
|
7077
7223
|
} catch {
|
|
7078
7224
|
return [];
|
|
7079
7225
|
}
|
|
@@ -7110,7 +7256,7 @@ async function scan5(agg, opts = {}) {
|
|
|
7110
7256
|
} catch (e) {
|
|
7111
7257
|
stats.filesUnreadable++;
|
|
7112
7258
|
stats.unreadableFiles.push({
|
|
7113
|
-
path:
|
|
7259
|
+
path: path10.basename(file),
|
|
7114
7260
|
reason: errorClass2(e)
|
|
7115
7261
|
});
|
|
7116
7262
|
}
|
|
@@ -7277,8 +7423,8 @@ function pickTs(jsonTs, columnTs) {
|
|
|
7277
7423
|
}
|
|
7278
7424
|
function opencodeConfigFile() {
|
|
7279
7425
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
7280
|
-
const base = xdg ||
|
|
7281
|
-
return
|
|
7426
|
+
const base = xdg || path10.join(homedir12(), ".config");
|
|
7427
|
+
return path10.join(base, "opencode", "opencode.json");
|
|
7282
7428
|
}
|
|
7283
7429
|
function readConfiguredMcpServers2(agg, state, configFile) {
|
|
7284
7430
|
const file = configFile ?? opencodeConfigFile();
|
|
@@ -7580,17 +7726,17 @@ function readCounts2(usageRaw) {
|
|
|
7580
7726
|
|
|
7581
7727
|
// src/harness/pi/scan.ts
|
|
7582
7728
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
7583
|
-
import { readdir as
|
|
7584
|
-
import { homedir as
|
|
7585
|
-
import
|
|
7729
|
+
import { readdir as readdir7, realpath as realpath3, stat as stat7 } from "node:fs/promises";
|
|
7730
|
+
import { homedir as homedir13 } from "node:os";
|
|
7731
|
+
import path11 from "node:path";
|
|
7586
7732
|
import readline3 from "node:readline";
|
|
7587
7733
|
var MAX_SESSION_VERSION = 3;
|
|
7588
7734
|
function piAgentDir() {
|
|
7589
|
-
return process.env.PI_CODING_AGENT_DIR ||
|
|
7735
|
+
return process.env.PI_CODING_AGENT_DIR || path11.join(homedir13(), ".pi", "agent");
|
|
7590
7736
|
}
|
|
7591
7737
|
function sessionRoots2() {
|
|
7592
7738
|
const override = process.env.PI_CODING_AGENT_SESSION_DIR;
|
|
7593
|
-
return [override ||
|
|
7739
|
+
return [override || path11.join(piAgentDir(), "sessions")];
|
|
7594
7740
|
}
|
|
7595
7741
|
var SESSION_FILE_RE = /^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/;
|
|
7596
7742
|
function isSessionFile(basename2) {
|
|
@@ -7599,12 +7745,12 @@ function isSessionFile(basename2) {
|
|
|
7599
7745
|
async function* walkSessions(dir) {
|
|
7600
7746
|
let entries;
|
|
7601
7747
|
try {
|
|
7602
|
-
entries = await
|
|
7748
|
+
entries = await readdir7(dir, { withFileTypes: true });
|
|
7603
7749
|
} catch {
|
|
7604
7750
|
return;
|
|
7605
7751
|
}
|
|
7606
7752
|
for (const e of entries) {
|
|
7607
|
-
const full =
|
|
7753
|
+
const full = path11.join(dir, e.name);
|
|
7608
7754
|
if (e.isDirectory()) yield* walkSessions(full);
|
|
7609
7755
|
else if (e.isFile() && isSessionFile(e.name)) yield full;
|
|
7610
7756
|
}
|
|
@@ -7652,7 +7798,7 @@ async function scan6(agg, opts = {}) {
|
|
|
7652
7798
|
stats.filesUnreadable++;
|
|
7653
7799
|
stats.filesRead--;
|
|
7654
7800
|
stats.unreadableFiles.push({
|
|
7655
|
-
path:
|
|
7801
|
+
path: path11.relative(root, file),
|
|
7656
7802
|
reason: "version-too-new"
|
|
7657
7803
|
});
|
|
7658
7804
|
}
|
|
@@ -7660,7 +7806,7 @@ async function scan6(agg, opts = {}) {
|
|
|
7660
7806
|
stats.filesUnreadable++;
|
|
7661
7807
|
stats.filesRead--;
|
|
7662
7808
|
stats.unreadableFiles.push({
|
|
7663
|
-
path:
|
|
7809
|
+
path: path11.relative(root, file),
|
|
7664
7810
|
reason: "read-error"
|
|
7665
7811
|
});
|
|
7666
7812
|
}
|
|
@@ -7798,7 +7944,7 @@ var MCP_ADD_ARGS = [
|
|
|
7798
7944
|
"mcp"
|
|
7799
7945
|
];
|
|
7800
7946
|
var MCP_REMOVE_ARGS = ["mcp", "remove", "--scope", "user", "aistack"];
|
|
7801
|
-
var SKILL_DEST = join6(
|
|
7947
|
+
var SKILL_DEST = join6(homedir14(), ".claude", "skills", "aistack-sync");
|
|
7802
7948
|
function runClaude(args) {
|
|
7803
7949
|
const r = spawnSync("claude", args, { encoding: "utf-8" });
|
|
7804
7950
|
const notFound = r.error !== void 0 && r.error.code === "ENOENT";
|
|
@@ -8120,13 +8266,13 @@ async function loginCommand(options = {}) {
|
|
|
8120
8266
|
import * as p7 from "@clack/prompts";
|
|
8121
8267
|
|
|
8122
8268
|
// src/autosync/codexHook.ts
|
|
8123
|
-
import { createHash as
|
|
8269
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
8124
8270
|
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8125
|
-
import { homedir as
|
|
8271
|
+
import { homedir as homedir15 } from "node:os";
|
|
8126
8272
|
import { dirname as dirname5, join as join8 } from "node:path";
|
|
8127
8273
|
import { parse } from "smol-toml";
|
|
8128
8274
|
function codexHome2() {
|
|
8129
|
-
return process.env.CODEX_HOME || join8(
|
|
8275
|
+
return process.env.CODEX_HOME || join8(homedir15(), ".codex");
|
|
8130
8276
|
}
|
|
8131
8277
|
function codexHooksFile() {
|
|
8132
8278
|
return join8(codexHome2(), "hooks.json");
|
|
@@ -8235,7 +8381,7 @@ function codexHookTrusted(configFile = codexConfigFile(), hooksFile = codexHooks
|
|
|
8235
8381
|
hooks: [normalizedHandler]
|
|
8236
8382
|
};
|
|
8237
8383
|
if (typeof group.matcher === "string") identity.matcher = group.matcher;
|
|
8238
|
-
const currentHash = `sha256:${
|
|
8384
|
+
const currentHash = `sha256:${createHash3("sha256").update(JSON.stringify(canonicalJson2(identity))).digest("hex")}`;
|
|
8239
8385
|
const key2 = `${hooksFile}:session_start:${groupIndex}:${handlerIndex}`;
|
|
8240
8386
|
matches.push(config.hooks?.state?.[key2]?.trusted_hash === currentHash);
|
|
8241
8387
|
}
|
|
@@ -8267,14 +8413,14 @@ import * as p6 from "@clack/prompts";
|
|
|
8267
8413
|
|
|
8268
8414
|
// src/autosync/cursorHook.ts
|
|
8269
8415
|
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8270
|
-
import { homedir as
|
|
8416
|
+
import { homedir as homedir17, platform as platform2 } from "node:os";
|
|
8271
8417
|
import { dirname as dirname7, join as join10 } from "node:path";
|
|
8272
8418
|
|
|
8273
8419
|
// src/autosync/hook.ts
|
|
8274
8420
|
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
|
|
8275
|
-
import { homedir as
|
|
8421
|
+
import { homedir as homedir16 } from "node:os";
|
|
8276
8422
|
import { dirname as dirname6, join as join9 } from "node:path";
|
|
8277
|
-
var CLAUDE_SETTINGS_FILE = join9(
|
|
8423
|
+
var CLAUDE_SETTINGS_FILE = join9(homedir16(), ".claude", "settings.json");
|
|
8278
8424
|
var AUTO_SYNC_HOOK_COMMAND = "npx -y @use-aistack/cli@latest sync --auto || npx -y --prefer-offline @use-aistack/cli sync --auto";
|
|
8279
8425
|
function isOurs2(entry) {
|
|
8280
8426
|
return typeof entry.command === "string" && entry.command.includes("@use-aistack/cli") && entry.command.includes("sync --auto");
|
|
@@ -8347,7 +8493,7 @@ function autoSyncHookInstalled(file = CLAUDE_SETTINGS_FILE) {
|
|
|
8347
8493
|
}
|
|
8348
8494
|
|
|
8349
8495
|
// src/autosync/cursorHook.ts
|
|
8350
|
-
var CURSOR_HOOK_FILE = join10(
|
|
8496
|
+
var CURSOR_HOOK_FILE = join10(homedir17(), ".cursor", "hooks.json");
|
|
8351
8497
|
function cursorHookCommand(os = platform2()) {
|
|
8352
8498
|
if (os === "win32") {
|
|
8353
8499
|
const script = `Start-Process -WindowStyle Hidden -FilePath 'cmd.exe' -ArgumentList '/d /s /c "set AISTACK_HOOK_SOURCE=cursor&& (${AUTO_SYNC_HOOK_COMMAND}) <NUL >NUL 2>&1"'`;
|
|
@@ -8427,10 +8573,10 @@ import {
|
|
|
8427
8573
|
unlinkSync,
|
|
8428
8574
|
writeFileSync as writeFileSync6
|
|
8429
8575
|
} from "node:fs";
|
|
8430
|
-
import { homedir as
|
|
8576
|
+
import { homedir as homedir18, platform as platform3 } from "node:os";
|
|
8431
8577
|
import { dirname as dirname8, join as join11 } from "node:path";
|
|
8432
8578
|
var GROK_HOOK_FILE = join11(
|
|
8433
|
-
process.env.GROK_HOME || join11(
|
|
8579
|
+
process.env.GROK_HOME || join11(homedir18(), ".grok"),
|
|
8434
8580
|
"hooks",
|
|
8435
8581
|
"aistack.json"
|
|
8436
8582
|
);
|
|
@@ -8788,11 +8934,11 @@ import {
|
|
|
8788
8934
|
unlinkSync as unlinkSync2,
|
|
8789
8935
|
writeFileSync as writeFileSync8
|
|
8790
8936
|
} from "node:fs";
|
|
8791
|
-
import { homedir as
|
|
8937
|
+
import { homedir as homedir20 } from "node:os";
|
|
8792
8938
|
import { dirname as dirname9, join as join12 } from "node:path";
|
|
8793
8939
|
|
|
8794
8940
|
// src/sync/stage.ts
|
|
8795
|
-
import { createHash as
|
|
8941
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
8796
8942
|
|
|
8797
8943
|
// src/usage/days.ts
|
|
8798
8944
|
var round6 = (n) => Math.round(n * 1e6) / 1e6;
|
|
@@ -8907,11 +9053,11 @@ function buildMeasuredDays(input) {
|
|
|
8907
9053
|
|
|
8908
9054
|
// src/usage/diff.ts
|
|
8909
9055
|
var MAX_DAY_WINDOW = 400;
|
|
8910
|
-
var
|
|
9056
|
+
var DAY_MS2 = 864e5;
|
|
8911
9057
|
function retentionFloor(todayUtc, days) {
|
|
8912
9058
|
const span = Math.max(1, Math.min(days, MAX_DAY_WINDOW));
|
|
8913
9059
|
const todayMs = Date.parse(`${todayUtc}T00:00:00.000Z`);
|
|
8914
|
-
return new Date(todayMs - (span - 1) *
|
|
9060
|
+
return new Date(todayMs - (span - 1) * DAY_MS2).toISOString().slice(0, 10);
|
|
8915
9061
|
}
|
|
8916
9062
|
function selectDaysToPublish(input) {
|
|
8917
9063
|
const { local, manifest, todayUtc } = input;
|
|
@@ -8948,7 +9094,7 @@ function selectDaysToPublish(input) {
|
|
|
8948
9094
|
|
|
8949
9095
|
// src/workflow/git.ts
|
|
8950
9096
|
import { execFile, execFileSync as execFileSync2 } from "node:child_process";
|
|
8951
|
-
import
|
|
9097
|
+
import path12 from "node:path";
|
|
8952
9098
|
var TEST_FILE_RULE_VERSION = "test-files/v2";
|
|
8953
9099
|
var FILE_TYPE_RULE_VERSION = "file-types/v2";
|
|
8954
9100
|
var COMMIT_SET_RULE_VERSION = "commit-set/v1";
|
|
@@ -9212,10 +9358,10 @@ function reduceGitHistories(histories, options) {
|
|
|
9212
9358
|
const field = fields[fieldIndex] ?? "";
|
|
9213
9359
|
if (field.replace(/^\n+/, "") === COMMIT_MARKER) {
|
|
9214
9360
|
finishCommit();
|
|
9215
|
-
const
|
|
9361
|
+
const hash2 = fields[++fieldIndex] ?? "";
|
|
9216
9362
|
const authoredAt = fields[++fieldIndex] ?? "";
|
|
9217
9363
|
const authoredMs = Date.parse(authoredAt);
|
|
9218
|
-
const included = Number.isFinite(authoredMs) && authoredMs >= options.fromMs && authoredMs <= options.toMs && !seenCommits.has(
|
|
9364
|
+
const included = Number.isFinite(authoredMs) && authoredMs >= options.fromMs && authoredMs <= options.toMs && !seenCommits.has(hash2);
|
|
9219
9365
|
current = {
|
|
9220
9366
|
included,
|
|
9221
9367
|
date: included ? new Date(authoredMs).toISOString().slice(0, 10) : "",
|
|
@@ -9228,7 +9374,7 @@ function reduceGitHistories(histories, options) {
|
|
|
9228
9374
|
withheldLines: 0,
|
|
9229
9375
|
extensionLines: /* @__PURE__ */ new Map()
|
|
9230
9376
|
};
|
|
9231
|
-
if (included) seenCommits.add(
|
|
9377
|
+
if (included) seenCommits.add(hash2);
|
|
9232
9378
|
continue;
|
|
9233
9379
|
}
|
|
9234
9380
|
const stat8 = parseNumstat(field);
|
|
@@ -9247,7 +9393,7 @@ function reduceGitHistories(histories, options) {
|
|
|
9247
9393
|
current.changedLines += fileChangedLines;
|
|
9248
9394
|
if (isTestFile(file)) current.touchesTest = true;
|
|
9249
9395
|
if (fileChangedLines <= 0) continue;
|
|
9250
|
-
const extension =
|
|
9396
|
+
const extension = path12.extname(file).toLowerCase();
|
|
9251
9397
|
if (APPROVED_EXTENSIONS.has(extension)) {
|
|
9252
9398
|
current.extensionLines.set(
|
|
9253
9399
|
extension,
|
|
@@ -9351,18 +9497,18 @@ function buildWorkflowExtraction(harnessWorkflows, git, utcOffsetMinutes = machi
|
|
|
9351
9497
|
}
|
|
9352
9498
|
|
|
9353
9499
|
// src/sync/grokDateCache.ts
|
|
9354
|
-
import { createHash as
|
|
9500
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
9355
9501
|
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
|
|
9356
|
-
import { homedir as
|
|
9357
|
-
import
|
|
9358
|
-
var defaultFile =
|
|
9359
|
-
|
|
9502
|
+
import { homedir as homedir19 } from "node:os";
|
|
9503
|
+
import path13 from "node:path";
|
|
9504
|
+
var defaultFile = path13.join(
|
|
9505
|
+
homedir19(),
|
|
9360
9506
|
".config",
|
|
9361
9507
|
"aistack",
|
|
9362
9508
|
"grok-session-dates.json"
|
|
9363
9509
|
);
|
|
9364
9510
|
function grokCacheScope(baseUrl, stack, token) {
|
|
9365
|
-
return
|
|
9511
|
+
return createHash4("sha256").update(`${baseUrl}\0${stack}\0${token}`).digest("hex");
|
|
9366
9512
|
}
|
|
9367
9513
|
function read2(file) {
|
|
9368
9514
|
if (!existsSync12(file)) return {};
|
|
@@ -9379,7 +9525,7 @@ function loadGrokDateHints(scope, file = defaultFile) {
|
|
|
9379
9525
|
function saveGrokDateHints(scope, hints, file = defaultFile) {
|
|
9380
9526
|
const cache = read2(file);
|
|
9381
9527
|
cache[scope] = hints;
|
|
9382
|
-
mkdirSync7(
|
|
9528
|
+
mkdirSync7(path13.dirname(file), { recursive: true });
|
|
9383
9529
|
writeFileSync7(file, JSON.stringify(cache, null, 2));
|
|
9384
9530
|
}
|
|
9385
9531
|
function mapToHints(value, floor) {
|
|
@@ -9791,7 +9937,7 @@ function buildGateSummary(ctx) {
|
|
|
9791
9937
|
// src/sync/stage.ts
|
|
9792
9938
|
var utcDate2 = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
9793
9939
|
function stageId(bodyJson) {
|
|
9794
|
-
return
|
|
9940
|
+
return createHash5("sha256").update(bodyJson).digest("hex").slice(0, 12);
|
|
9795
9941
|
}
|
|
9796
9942
|
async function stageSync(deps) {
|
|
9797
9943
|
const now = (deps.now ?? Date.now)();
|
|
@@ -9996,7 +10142,7 @@ async function stageSync(deps) {
|
|
|
9996
10142
|
}
|
|
9997
10143
|
|
|
9998
10144
|
// src/autosync/run.ts
|
|
9999
|
-
var SYNC_LOG_FILE = join12(
|
|
10145
|
+
var SYNC_LOG_FILE = join12(homedir20(), ".config", "aistack", "sync.log");
|
|
10000
10146
|
var SYNC_LOG_MAX_LINES = 200;
|
|
10001
10147
|
var FIX_COMMAND = "npx @use-aistack/cli sync";
|
|
10002
10148
|
var REVOKED_RESULT = "off - auto-sync is switched off for this stack";
|
|
@@ -10049,7 +10195,7 @@ async function runAutoSync(deps) {
|
|
|
10049
10195
|
const state = settings.autoSyncState ?? {};
|
|
10050
10196
|
const lastRunAt = state.lastRunAt ?? 0;
|
|
10051
10197
|
if (now - lastRunAt < windowMs) return;
|
|
10052
|
-
const reservationFile = deps.reservationFile ?? `${settingsFile ?? join12(
|
|
10198
|
+
const reservationFile = deps.reservationFile ?? `${settingsFile ?? join12(homedir20(), ".config", "aistack", "settings.json")}.auto-sync-attempt`;
|
|
10053
10199
|
if (!reserveAttempt(reservationFile, now, windowMs)) return;
|
|
10054
10200
|
saveSettings({ autoSyncState: { ...state, lastRunAt: now } }, settingsFile);
|
|
10055
10201
|
const stage = deps.stageImpl ?? stageSync;
|