@use-aistack/cli 0.15.0 → 0.16.1
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 +252 -100
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -377,12 +377,13 @@ 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.1" : "0.0.0-dev";
|
|
381
381
|
|
|
382
382
|
// src/api.ts
|
|
383
383
|
var BASE_URL = process.env.AISTACK_URL || "https://aistack.to";
|
|
384
|
-
|
|
385
|
-
|
|
384
|
+
var STARTUP_READ_TIMEOUT_MS = 5e3;
|
|
385
|
+
async function request(path14, options = {}) {
|
|
386
|
+
return fetch(`${BASE_URL}${path14}`, {
|
|
386
387
|
...options,
|
|
387
388
|
headers: {
|
|
388
389
|
"Content-Type": "application/json",
|
|
@@ -501,6 +502,7 @@ async function syncPublish(token, bodyJson) {
|
|
|
501
502
|
}
|
|
502
503
|
async function fetchDayManifest(baseUrl, token) {
|
|
503
504
|
const res = await fetch(`${baseUrl}/api/cli/sync-manifest`, {
|
|
505
|
+
signal: AbortSignal.timeout(STARTUP_READ_TIMEOUT_MS),
|
|
504
506
|
headers: { "Content-Type": "application/json", ...authHeaders(token) }
|
|
505
507
|
});
|
|
506
508
|
if (res.status === 404) return null;
|
|
@@ -524,6 +526,7 @@ async function fetchDayManifest(baseUrl, token) {
|
|
|
524
526
|
}
|
|
525
527
|
async function fetchPriceTable(baseUrl) {
|
|
526
528
|
const res = await fetch(`${baseUrl}/api/prices`, {
|
|
529
|
+
signal: AbortSignal.timeout(STARTUP_READ_TIMEOUT_MS),
|
|
527
530
|
headers: { Accept: "application/json" }
|
|
528
531
|
});
|
|
529
532
|
if (res.status === 404) return null;
|
|
@@ -800,9 +803,9 @@ function canonicalizeRepoUrl(input) {
|
|
|
800
803
|
function repoNameFromCanonical(canonical) {
|
|
801
804
|
return parseRepo(canonical)?.repo ?? "";
|
|
802
805
|
}
|
|
803
|
-
function normalizeUpstreamPath(
|
|
804
|
-
if (!
|
|
805
|
-
return
|
|
806
|
+
function normalizeUpstreamPath(path14) {
|
|
807
|
+
if (!path14) return "";
|
|
808
|
+
return path14.split("/").filter(Boolean).join("/");
|
|
806
809
|
}
|
|
807
810
|
|
|
808
811
|
// src/git.ts
|
|
@@ -848,16 +851,16 @@ function buildRepoLinkResource(canonical) {
|
|
|
848
851
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
849
852
|
import { homedir as homedir2 } from "node:os";
|
|
850
853
|
import { join as join2 } from "node:path";
|
|
851
|
-
function readJson(
|
|
854
|
+
function readJson(path14) {
|
|
852
855
|
try {
|
|
853
|
-
if (!existsSync2(
|
|
854
|
-
return JSON.parse(readFileSync2(
|
|
856
|
+
if (!existsSync2(path14)) return null;
|
|
857
|
+
return JSON.parse(readFileSync2(path14, "utf-8"));
|
|
855
858
|
} catch {
|
|
856
859
|
return null;
|
|
857
860
|
}
|
|
858
861
|
}
|
|
859
|
-
function hooksFrom(
|
|
860
|
-
const hooks = readJson(
|
|
862
|
+
function hooksFrom(path14, source, out, seen) {
|
|
863
|
+
const hooks = readJson(path14)?.hooks;
|
|
861
864
|
if (!hooks || typeof hooks !== "object") return;
|
|
862
865
|
for (const [event, config] of Object.entries(hooks)) {
|
|
863
866
|
const stableKey = `hooks:${source}:${event}`;
|
|
@@ -1006,16 +1009,16 @@ function buildMcpResource(name, group, pkg) {
|
|
|
1006
1009
|
pkg
|
|
1007
1010
|
};
|
|
1008
1011
|
}
|
|
1009
|
-
function readText(
|
|
1012
|
+
function readText(path14) {
|
|
1010
1013
|
try {
|
|
1011
|
-
if (!existsSync3(
|
|
1012
|
-
return readFileSync3(
|
|
1014
|
+
if (!existsSync3(path14)) return null;
|
|
1015
|
+
return readFileSync3(path14, "utf-8");
|
|
1013
1016
|
} catch {
|
|
1014
1017
|
return null;
|
|
1015
1018
|
}
|
|
1016
1019
|
}
|
|
1017
|
-
function readParsed(
|
|
1018
|
-
const raw = readText(
|
|
1020
|
+
function readParsed(path14, parse2) {
|
|
1021
|
+
const raw = readText(path14);
|
|
1019
1022
|
if (raw === null) return null;
|
|
1020
1023
|
try {
|
|
1021
1024
|
return parse2(raw);
|
|
@@ -1023,14 +1026,14 @@ function readParsed(path13, parse2) {
|
|
|
1023
1026
|
return null;
|
|
1024
1027
|
}
|
|
1025
1028
|
}
|
|
1026
|
-
function readJson2(
|
|
1027
|
-
return readParsed(
|
|
1029
|
+
function readJson2(path14) {
|
|
1030
|
+
return readParsed(path14, JSON.parse);
|
|
1028
1031
|
}
|
|
1029
|
-
function readYaml(
|
|
1030
|
-
return readParsed(
|
|
1032
|
+
function readYaml(path14) {
|
|
1033
|
+
return readParsed(path14, parseYaml);
|
|
1031
1034
|
}
|
|
1032
|
-
function readToml(
|
|
1033
|
-
return readParsed(
|
|
1035
|
+
function readToml(path14) {
|
|
1036
|
+
return readParsed(path14, parseToml);
|
|
1034
1037
|
}
|
|
1035
1038
|
function continueListToMap(file) {
|
|
1036
1039
|
if (!file?.mcpServers?.length) return void 0;
|
|
@@ -1169,8 +1172,8 @@ function resolveSource(entry, mpRepoUrl) {
|
|
|
1169
1172
|
const src = entry.source;
|
|
1170
1173
|
if (typeof src === "string") {
|
|
1171
1174
|
if (!mpRepoUrl) return null;
|
|
1172
|
-
const
|
|
1173
|
-
return { url: mpRepoUrl, path:
|
|
1175
|
+
const path14 = src.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
1176
|
+
return { url: mpRepoUrl, path: path14 || void 0 };
|
|
1174
1177
|
}
|
|
1175
1178
|
if (src && typeof src === "object" && src.url) {
|
|
1176
1179
|
return { url: src.url, path: src.path, sha: src.sha };
|
|
@@ -1207,10 +1210,10 @@ function resolvePluginLinks(installed, marketplaces, manifests) {
|
|
|
1207
1210
|
}
|
|
1208
1211
|
return out;
|
|
1209
1212
|
}
|
|
1210
|
-
function readJson3(
|
|
1213
|
+
function readJson3(path14) {
|
|
1211
1214
|
try {
|
|
1212
|
-
if (!existsSync4(
|
|
1213
|
-
return JSON.parse(readFileSync4(
|
|
1215
|
+
if (!existsSync4(path14)) return null;
|
|
1216
|
+
return JSON.parse(readFileSync4(path14, "utf-8"));
|
|
1214
1217
|
} catch {
|
|
1215
1218
|
return null;
|
|
1216
1219
|
}
|
|
@@ -1844,7 +1847,7 @@ function diffResources(current, existing) {
|
|
|
1844
1847
|
// src/commands/connect.ts
|
|
1845
1848
|
import { spawnSync } from "node:child_process";
|
|
1846
1849
|
import { cpSync, existsSync as existsSync6 } from "node:fs";
|
|
1847
|
-
import { homedir as
|
|
1850
|
+
import { homedir as homedir14 } from "node:os";
|
|
1848
1851
|
import { dirname as dirname3, join as join6 } from "node:path";
|
|
1849
1852
|
import { fileURLToPath } from "node:url";
|
|
1850
1853
|
import * as p3 from "@clack/prompts";
|
|
@@ -3634,13 +3637,13 @@ function canonicalJson(value) {
|
|
|
3634
3637
|
function fnv1a64(text) {
|
|
3635
3638
|
const prime = 0x100000001b3n;
|
|
3636
3639
|
const mask = 0xffffffffffffffffn;
|
|
3637
|
-
let
|
|
3640
|
+
let hash2 = 0xcbf29ce484222325n;
|
|
3638
3641
|
const bytes = new TextEncoder().encode(text);
|
|
3639
3642
|
for (const byte of bytes) {
|
|
3640
|
-
|
|
3641
|
-
|
|
3643
|
+
hash2 ^= BigInt(byte);
|
|
3644
|
+
hash2 = hash2 * prime & mask;
|
|
3642
3645
|
}
|
|
3643
|
-
return
|
|
3646
|
+
return hash2.toString(16).padStart(16, "0");
|
|
3644
3647
|
}
|
|
3645
3648
|
function dayFingerprint(day) {
|
|
3646
3649
|
return fnv1a64(
|
|
@@ -5441,11 +5444,11 @@ function ingestWithRetry(agg, file, opts) {
|
|
|
5441
5444
|
}
|
|
5442
5445
|
}
|
|
5443
5446
|
function ingestFile2(agg, file, opts) {
|
|
5444
|
-
const
|
|
5447
|
+
const readFile4 = opts.readFileImpl ?? readFileSync6;
|
|
5445
5448
|
let text;
|
|
5446
5449
|
if (file.endsWith(".zst")) {
|
|
5447
5450
|
if (zstdDecompress === null) throw readError("zstd-unsupported");
|
|
5448
|
-
const raw =
|
|
5451
|
+
const raw = readFile4(file);
|
|
5449
5452
|
try {
|
|
5450
5453
|
text = zstdDecompress(
|
|
5451
5454
|
Buffer.isBuffer(raw) ? raw : Buffer.from(raw)
|
|
@@ -5454,7 +5457,7 @@ function ingestFile2(agg, file, opts) {
|
|
|
5454
5457
|
throw readError("zstd-corrupt");
|
|
5455
5458
|
}
|
|
5456
5459
|
} else {
|
|
5457
|
-
text =
|
|
5460
|
+
text = readFile4(file).toString("utf8");
|
|
5458
5461
|
}
|
|
5459
5462
|
const records = [];
|
|
5460
5463
|
let nonEmptyLines = 0;
|
|
@@ -6610,15 +6613,129 @@ function ingestContribution(agg, row) {
|
|
|
6610
6613
|
|
|
6611
6614
|
// src/harness/grok/scan.ts
|
|
6612
6615
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
6613
|
-
import { readdir as
|
|
6614
|
-
import { homedir as
|
|
6615
|
-
import
|
|
6616
|
+
import { readdir as readdir5, readFile as readFile3, stat as stat5 } from "node:fs/promises";
|
|
6617
|
+
import { homedir as homedir11 } from "node:os";
|
|
6618
|
+
import path9 from "node:path";
|
|
6616
6619
|
import readline2 from "node:readline";
|
|
6617
6620
|
import { parse as parseToml3 } from "smol-toml";
|
|
6621
|
+
|
|
6622
|
+
// src/harness/grok/context.ts
|
|
6623
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
6624
|
+
import { appendFile, mkdir as mkdir2, readdir as readdir4, readFile as readFile2, unlink } from "node:fs/promises";
|
|
6625
|
+
import { homedir as homedir10 } from "node:os";
|
|
6626
|
+
import path8 from "node:path";
|
|
6627
|
+
var DAY_MS = 864e5;
|
|
6628
|
+
var hash = (value) => createHash2("sha256").update(value).digest("hex");
|
|
6629
|
+
function contextCall(value) {
|
|
6630
|
+
const row = asObj(value);
|
|
6631
|
+
if (row?.src !== "shell" || row.msg !== "shell.turn.inference_done")
|
|
6632
|
+
return null;
|
|
6633
|
+
const session = asStr(row.sid);
|
|
6634
|
+
const ts = asStr(row.ts);
|
|
6635
|
+
const ctx = asObj(row.ctx);
|
|
6636
|
+
const tokens = ctx?.prompt_tokens;
|
|
6637
|
+
const loop = ctx?.loop_index;
|
|
6638
|
+
const tsMs = ts ? Date.parse(ts) : NaN;
|
|
6639
|
+
if (!session || !Number.isFinite(tsMs) || typeof tokens !== "number" || !Number.isSafeInteger(tokens) || tokens < 0 || typeof loop !== "number" || !Number.isSafeInteger(loop) || loop < 0)
|
|
6640
|
+
return null;
|
|
6641
|
+
return {
|
|
6642
|
+
id: hash(JSON.stringify([session, tsMs, row.pid ?? null, loop, tokens])),
|
|
6643
|
+
session,
|
|
6644
|
+
tsMs,
|
|
6645
|
+
tokens
|
|
6646
|
+
};
|
|
6647
|
+
}
|
|
6648
|
+
function contextCacheDirectory(root) {
|
|
6649
|
+
return path8.join(
|
|
6650
|
+
homedir10(),
|
|
6651
|
+
".config",
|
|
6652
|
+
"aistack",
|
|
6653
|
+
"grok-context",
|
|
6654
|
+
hash(path8.resolve(root))
|
|
6655
|
+
);
|
|
6656
|
+
}
|
|
6657
|
+
async function optionalRead(file) {
|
|
6658
|
+
try {
|
|
6659
|
+
return await readFile2(file, "utf8");
|
|
6660
|
+
} catch (error) {
|
|
6661
|
+
if (error.code === "ENOENT") return "";
|
|
6662
|
+
throw error;
|
|
6663
|
+
}
|
|
6664
|
+
}
|
|
6665
|
+
async function retainedContextCalls(root, sessions, cacheDir = contextCacheDirectory(root), now = Date.now()) {
|
|
6666
|
+
const cutoff = now - 400 * DAY_MS;
|
|
6667
|
+
const calls = /* @__PURE__ */ new Map();
|
|
6668
|
+
let files = [];
|
|
6669
|
+
try {
|
|
6670
|
+
files = await readdir4(cacheDir);
|
|
6671
|
+
} catch (error) {
|
|
6672
|
+
if (error.code !== "ENOENT") throw error;
|
|
6673
|
+
}
|
|
6674
|
+
for (const file of files) {
|
|
6675
|
+
if (!/^\d{4}-\d{2}-\d{2}\.jsonl$/.test(file)) continue;
|
|
6676
|
+
if (Date.parse(file.slice(0, 10)) + DAY_MS < cutoff) {
|
|
6677
|
+
await unlink(path8.join(cacheDir, file)).catch(
|
|
6678
|
+
(error) => {
|
|
6679
|
+
if (error.code !== "ENOENT") throw error;
|
|
6680
|
+
}
|
|
6681
|
+
);
|
|
6682
|
+
continue;
|
|
6683
|
+
}
|
|
6684
|
+
const raw2 = await optionalRead(path8.join(cacheDir, file));
|
|
6685
|
+
if (raw2 && !raw2.endsWith("\n"))
|
|
6686
|
+
throw new Error("Incomplete Grok context cache");
|
|
6687
|
+
for (const line of raw2.split("\n").filter(Boolean)) {
|
|
6688
|
+
const call = asObj(JSON.parse(line));
|
|
6689
|
+
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)
|
|
6690
|
+
throw new Error("Invalid Grok context cache");
|
|
6691
|
+
if (call.tsMs >= cutoff && call.tsMs <= now)
|
|
6692
|
+
calls.set(call.id, {
|
|
6693
|
+
id: call.id,
|
|
6694
|
+
session: call.session,
|
|
6695
|
+
tsMs: call.tsMs,
|
|
6696
|
+
tokens: call.tokens
|
|
6697
|
+
});
|
|
6698
|
+
}
|
|
6699
|
+
}
|
|
6700
|
+
const raw = await optionalRead(
|
|
6701
|
+
path8.join(root, "..", "logs", "unified.jsonl")
|
|
6702
|
+
);
|
|
6703
|
+
const additions = /* @__PURE__ */ new Map();
|
|
6704
|
+
for (const line of raw.slice(0, raw.lastIndexOf("\n") + 1).split("\n")) {
|
|
6705
|
+
let value;
|
|
6706
|
+
try {
|
|
6707
|
+
value = JSON.parse(line);
|
|
6708
|
+
} catch {
|
|
6709
|
+
continue;
|
|
6710
|
+
}
|
|
6711
|
+
const call = contextCall(value);
|
|
6712
|
+
if (!call || !sessions.has(call.session) || call.tsMs < cutoff || call.tsMs > now || calls.has(call.id))
|
|
6713
|
+
continue;
|
|
6714
|
+
calls.set(call.id, call);
|
|
6715
|
+
const date = new Date(call.tsMs).toISOString().slice(0, 10);
|
|
6716
|
+
const lines2 = additions.get(date) ?? [];
|
|
6717
|
+
lines2.push(JSON.stringify(call));
|
|
6718
|
+
additions.set(date, lines2);
|
|
6719
|
+
}
|
|
6720
|
+
if (additions.size) {
|
|
6721
|
+
await mkdir2(cacheDir, { recursive: true, mode: 448 });
|
|
6722
|
+
for (const [date, lines2] of additions) {
|
|
6723
|
+
await appendFile(
|
|
6724
|
+
path8.join(cacheDir, `${date}.jsonl`),
|
|
6725
|
+
`${lines2.join("\n")}
|
|
6726
|
+
`,
|
|
6727
|
+
{ mode: 384 }
|
|
6728
|
+
);
|
|
6729
|
+
}
|
|
6730
|
+
}
|
|
6731
|
+
return [...calls.values()].filter((call) => sessions.has(call.session)).sort((a, b) => a.tsMs - b.tsMs || a.id.localeCompare(b.id));
|
|
6732
|
+
}
|
|
6733
|
+
|
|
6734
|
+
// src/harness/grok/scan.ts
|
|
6618
6735
|
function sessionRoots() {
|
|
6619
6736
|
return [
|
|
6620
|
-
|
|
6621
|
-
process.env.GROK_HOME ||
|
|
6737
|
+
path9.join(
|
|
6738
|
+
process.env.GROK_HOME || path9.join(homedir11(), ".grok"),
|
|
6622
6739
|
"sessions"
|
|
6623
6740
|
)
|
|
6624
6741
|
];
|
|
@@ -6650,7 +6767,7 @@ async function stableRead(file, jsonl) {
|
|
|
6650
6767
|
if (before.size === after.size && before.mtimeMs === after.mtimeMs)
|
|
6651
6768
|
return { lines: lines2, complete: true };
|
|
6652
6769
|
} else {
|
|
6653
|
-
const raw = await
|
|
6770
|
+
const raw = await readFile3(file, "utf8");
|
|
6654
6771
|
const after = await stat5(file);
|
|
6655
6772
|
if (before.size === after.size && before.mtimeMs === after.mtimeMs)
|
|
6656
6773
|
return { json: JSON.parse(raw), complete: true };
|
|
@@ -6662,16 +6779,16 @@ async function stableRead(file, jsonl) {
|
|
|
6662
6779
|
}
|
|
6663
6780
|
async function directories(root) {
|
|
6664
6781
|
try {
|
|
6665
|
-
const workspaces = await
|
|
6782
|
+
const workspaces = await readdir5(root, { withFileTypes: true });
|
|
6666
6783
|
const out = [];
|
|
6667
6784
|
for (const workspace of workspaces) {
|
|
6668
6785
|
if (!workspace.isDirectory() || workspace.isSymbolicLink()) continue;
|
|
6669
|
-
const workspacePath =
|
|
6670
|
-
for (const session of await
|
|
6786
|
+
const workspacePath = path9.join(root, workspace.name);
|
|
6787
|
+
for (const session of await readdir5(workspacePath, {
|
|
6671
6788
|
withFileTypes: true
|
|
6672
6789
|
})) {
|
|
6673
6790
|
if (session.isDirectory() && !session.isSymbolicLink())
|
|
6674
|
-
out.push(
|
|
6791
|
+
out.push(path9.join(workspacePath, session.name));
|
|
6675
6792
|
}
|
|
6676
6793
|
}
|
|
6677
6794
|
return out.sort();
|
|
@@ -6683,7 +6800,7 @@ async function modelAliasesForRoot(root) {
|
|
|
6683
6800
|
if (process.env.GROK_MODELS_BASE_URL) return /* @__PURE__ */ new Map();
|
|
6684
6801
|
try {
|
|
6685
6802
|
const parsed = asObj(
|
|
6686
|
-
parseToml3(await
|
|
6803
|
+
parseToml3(await readFile3(path9.join(root, "..", "config.toml"), "utf8"))
|
|
6687
6804
|
);
|
|
6688
6805
|
if (!parsed || asObj(parsed.endpoints)?.models_base_url) return /* @__PURE__ */ new Map();
|
|
6689
6806
|
const models = asObj(parsed.model);
|
|
@@ -6706,6 +6823,7 @@ async function scan4(agg, opts = {}) {
|
|
|
6706
6823
|
let complete = true;
|
|
6707
6824
|
for (const root of opts.roots ?? sessionRoots()) {
|
|
6708
6825
|
const aliases = await modelAliasesForRoot(root);
|
|
6826
|
+
const contextSessions = /* @__PURE__ */ new Map();
|
|
6709
6827
|
const dirs = await directories(root);
|
|
6710
6828
|
if (dirs === null) {
|
|
6711
6829
|
complete = false;
|
|
@@ -6714,7 +6832,7 @@ async function scan4(agg, opts = {}) {
|
|
|
6714
6832
|
for (const dir of dirs) {
|
|
6715
6833
|
let entries;
|
|
6716
6834
|
try {
|
|
6717
|
-
entries = await
|
|
6835
|
+
entries = await readdir5(dir, { withFileTypes: true });
|
|
6718
6836
|
} catch {
|
|
6719
6837
|
complete = false;
|
|
6720
6838
|
continue;
|
|
@@ -6722,10 +6840,10 @@ async function scan4(agg, opts = {}) {
|
|
|
6722
6840
|
const files = new Map(
|
|
6723
6841
|
entries.filter(
|
|
6724
6842
|
(e) => e.isFile() && (isGrokEvidenceFile(e.name) || e.name === "summary.json")
|
|
6725
|
-
).map((e) => [e.name,
|
|
6843
|
+
).map((e) => [e.name, path9.join(dir, e.name)])
|
|
6726
6844
|
);
|
|
6727
6845
|
let projectDir = dir;
|
|
6728
|
-
let sessionFallback =
|
|
6846
|
+
let sessionFallback = path9.basename(dir);
|
|
6729
6847
|
let child = false;
|
|
6730
6848
|
let parentSession;
|
|
6731
6849
|
const summary = files.get("summary.json");
|
|
@@ -6743,6 +6861,7 @@ async function scan4(agg, opts = {}) {
|
|
|
6743
6861
|
parentSession = asStr(value?.parentSessionId) ?? asStr(value?.parent_session_id) ?? asStr(info?.parentSessionId) ?? asStr(info?.parent_session_id) ?? void 0;
|
|
6744
6862
|
child = parentSession !== void 0;
|
|
6745
6863
|
}
|
|
6864
|
+
contextSessions.set(sessionFallback, { projectDir, parentSession });
|
|
6746
6865
|
let rows = [];
|
|
6747
6866
|
let precedence = 0;
|
|
6748
6867
|
const usage = files.get("usage.json");
|
|
@@ -6756,7 +6875,11 @@ async function scan4(agg, opts = {}) {
|
|
|
6756
6875
|
}
|
|
6757
6876
|
stats.filesRead++;
|
|
6758
6877
|
rows = sidecarContributions(read3.json, projectDir);
|
|
6759
|
-
if (rows.length > 0)
|
|
6878
|
+
if (rows.length > 0) {
|
|
6879
|
+
precedence = 2;
|
|
6880
|
+
for (const row of rows)
|
|
6881
|
+
contextSessions.set(row.sessionId, { projectDir, parentSession });
|
|
6882
|
+
}
|
|
6760
6883
|
}
|
|
6761
6884
|
if (child) {
|
|
6762
6885
|
rows = [];
|
|
@@ -6829,6 +6952,32 @@ async function scan4(agg, opts = {}) {
|
|
|
6829
6952
|
}
|
|
6830
6953
|
opts.onProgress?.(stats.filesFound);
|
|
6831
6954
|
}
|
|
6955
|
+
try {
|
|
6956
|
+
const calls = await retainedContextCalls(
|
|
6957
|
+
root,
|
|
6958
|
+
new Set(contextSessions.keys()),
|
|
6959
|
+
opts.contextCacheDir
|
|
6960
|
+
);
|
|
6961
|
+
for (const call of calls) {
|
|
6962
|
+
if (opts.sinceMs !== void 0 && call.tsMs < opts.sinceMs) continue;
|
|
6963
|
+
const source = contextSessions.get(call.session);
|
|
6964
|
+
agg.workflow.ingest({
|
|
6965
|
+
type: "response",
|
|
6966
|
+
session: call.session,
|
|
6967
|
+
projectWorkspace: source?.projectDir,
|
|
6968
|
+
parentSession: source?.parentSession,
|
|
6969
|
+
tsMs: call.tsMs,
|
|
6970
|
+
responseId: `context:${call.id}`,
|
|
6971
|
+
contextTokens: call.tokens
|
|
6972
|
+
});
|
|
6973
|
+
const dates = sessionDates.get(call.session) ?? /* @__PURE__ */ new Set();
|
|
6974
|
+
dates.add(new Date(call.tsMs).toISOString().slice(0, 10));
|
|
6975
|
+
sessionDates.set(call.session, dates);
|
|
6976
|
+
}
|
|
6977
|
+
} catch {
|
|
6978
|
+
complete = false;
|
|
6979
|
+
stats.filesUnreadable++;
|
|
6980
|
+
}
|
|
6832
6981
|
}
|
|
6833
6982
|
for (const { rows } of candidates.values()) {
|
|
6834
6983
|
for (const row of rows) {
|
|
@@ -7056,14 +7205,14 @@ function noteConfiguredMcpServers2(agg, state, serverNames) {
|
|
|
7056
7205
|
|
|
7057
7206
|
// src/harness/opencode/scan.ts
|
|
7058
7207
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
7059
|
-
import { readdir as
|
|
7060
|
-
import { homedir as
|
|
7061
|
-
import
|
|
7208
|
+
import { readdir as readdir6, stat as stat6 } from "node:fs/promises";
|
|
7209
|
+
import { homedir as homedir12 } from "node:os";
|
|
7210
|
+
import path10 from "node:path";
|
|
7062
7211
|
var OPENCODE_MIGRATION_CEILING = 20260622202450;
|
|
7063
7212
|
function opencodeDataDirs() {
|
|
7064
7213
|
const xdg = process.env.XDG_DATA_HOME;
|
|
7065
|
-
const base = xdg ||
|
|
7066
|
-
return [
|
|
7214
|
+
const base = xdg || path10.join(homedir12(), ".local", "share");
|
|
7215
|
+
return [path10.join(base, "opencode")];
|
|
7067
7216
|
}
|
|
7068
7217
|
function isStoreFile(basename2) {
|
|
7069
7218
|
return basename2 === "opencode.db" || /^opencode-[^/]+\.db$/.test(basename2);
|
|
@@ -7072,8 +7221,8 @@ async function dbFilesIn(root) {
|
|
|
7072
7221
|
const override = process.env.OPENCODE_DB;
|
|
7073
7222
|
if (override) return [override];
|
|
7074
7223
|
try {
|
|
7075
|
-
const entries = await
|
|
7076
|
-
return entries.filter((e) => e.isFile() && isStoreFile(e.name)).map((e) =>
|
|
7224
|
+
const entries = await readdir6(root, { withFileTypes: true });
|
|
7225
|
+
return entries.filter((e) => e.isFile() && isStoreFile(e.name)).map((e) => path10.join(root, e.name)).sort();
|
|
7077
7226
|
} catch {
|
|
7078
7227
|
return [];
|
|
7079
7228
|
}
|
|
@@ -7110,7 +7259,7 @@ async function scan5(agg, opts = {}) {
|
|
|
7110
7259
|
} catch (e) {
|
|
7111
7260
|
stats.filesUnreadable++;
|
|
7112
7261
|
stats.unreadableFiles.push({
|
|
7113
|
-
path:
|
|
7262
|
+
path: path10.basename(file),
|
|
7114
7263
|
reason: errorClass2(e)
|
|
7115
7264
|
});
|
|
7116
7265
|
}
|
|
@@ -7277,8 +7426,8 @@ function pickTs(jsonTs, columnTs) {
|
|
|
7277
7426
|
}
|
|
7278
7427
|
function opencodeConfigFile() {
|
|
7279
7428
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
7280
|
-
const base = xdg ||
|
|
7281
|
-
return
|
|
7429
|
+
const base = xdg || path10.join(homedir12(), ".config");
|
|
7430
|
+
return path10.join(base, "opencode", "opencode.json");
|
|
7282
7431
|
}
|
|
7283
7432
|
function readConfiguredMcpServers2(agg, state, configFile) {
|
|
7284
7433
|
const file = configFile ?? opencodeConfigFile();
|
|
@@ -7580,17 +7729,17 @@ function readCounts2(usageRaw) {
|
|
|
7580
7729
|
|
|
7581
7730
|
// src/harness/pi/scan.ts
|
|
7582
7731
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
7583
|
-
import { readdir as
|
|
7584
|
-
import { homedir as
|
|
7585
|
-
import
|
|
7732
|
+
import { readdir as readdir7, realpath as realpath3, stat as stat7 } from "node:fs/promises";
|
|
7733
|
+
import { homedir as homedir13 } from "node:os";
|
|
7734
|
+
import path11 from "node:path";
|
|
7586
7735
|
import readline3 from "node:readline";
|
|
7587
7736
|
var MAX_SESSION_VERSION = 3;
|
|
7588
7737
|
function piAgentDir() {
|
|
7589
|
-
return process.env.PI_CODING_AGENT_DIR ||
|
|
7738
|
+
return process.env.PI_CODING_AGENT_DIR || path11.join(homedir13(), ".pi", "agent");
|
|
7590
7739
|
}
|
|
7591
7740
|
function sessionRoots2() {
|
|
7592
7741
|
const override = process.env.PI_CODING_AGENT_SESSION_DIR;
|
|
7593
|
-
return [override ||
|
|
7742
|
+
return [override || path11.join(piAgentDir(), "sessions")];
|
|
7594
7743
|
}
|
|
7595
7744
|
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
7745
|
function isSessionFile(basename2) {
|
|
@@ -7599,12 +7748,12 @@ function isSessionFile(basename2) {
|
|
|
7599
7748
|
async function* walkSessions(dir) {
|
|
7600
7749
|
let entries;
|
|
7601
7750
|
try {
|
|
7602
|
-
entries = await
|
|
7751
|
+
entries = await readdir7(dir, { withFileTypes: true });
|
|
7603
7752
|
} catch {
|
|
7604
7753
|
return;
|
|
7605
7754
|
}
|
|
7606
7755
|
for (const e of entries) {
|
|
7607
|
-
const full =
|
|
7756
|
+
const full = path11.join(dir, e.name);
|
|
7608
7757
|
if (e.isDirectory()) yield* walkSessions(full);
|
|
7609
7758
|
else if (e.isFile() && isSessionFile(e.name)) yield full;
|
|
7610
7759
|
}
|
|
@@ -7652,7 +7801,7 @@ async function scan6(agg, opts = {}) {
|
|
|
7652
7801
|
stats.filesUnreadable++;
|
|
7653
7802
|
stats.filesRead--;
|
|
7654
7803
|
stats.unreadableFiles.push({
|
|
7655
|
-
path:
|
|
7804
|
+
path: path11.relative(root, file),
|
|
7656
7805
|
reason: "version-too-new"
|
|
7657
7806
|
});
|
|
7658
7807
|
}
|
|
@@ -7660,7 +7809,7 @@ async function scan6(agg, opts = {}) {
|
|
|
7660
7809
|
stats.filesUnreadable++;
|
|
7661
7810
|
stats.filesRead--;
|
|
7662
7811
|
stats.unreadableFiles.push({
|
|
7663
|
-
path:
|
|
7812
|
+
path: path11.relative(root, file),
|
|
7664
7813
|
reason: "read-error"
|
|
7665
7814
|
});
|
|
7666
7815
|
}
|
|
@@ -7798,7 +7947,7 @@ var MCP_ADD_ARGS = [
|
|
|
7798
7947
|
"mcp"
|
|
7799
7948
|
];
|
|
7800
7949
|
var MCP_REMOVE_ARGS = ["mcp", "remove", "--scope", "user", "aistack"];
|
|
7801
|
-
var SKILL_DEST = join6(
|
|
7950
|
+
var SKILL_DEST = join6(homedir14(), ".claude", "skills", "aistack-sync");
|
|
7802
7951
|
function runClaude(args) {
|
|
7803
7952
|
const r = spawnSync("claude", args, { encoding: "utf-8" });
|
|
7804
7953
|
const notFound = r.error !== void 0 && r.error.code === "ENOENT";
|
|
@@ -8120,13 +8269,13 @@ async function loginCommand(options = {}) {
|
|
|
8120
8269
|
import * as p7 from "@clack/prompts";
|
|
8121
8270
|
|
|
8122
8271
|
// src/autosync/codexHook.ts
|
|
8123
|
-
import { createHash as
|
|
8272
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
8124
8273
|
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8125
|
-
import { homedir as
|
|
8274
|
+
import { homedir as homedir15 } from "node:os";
|
|
8126
8275
|
import { dirname as dirname5, join as join8 } from "node:path";
|
|
8127
8276
|
import { parse } from "smol-toml";
|
|
8128
8277
|
function codexHome2() {
|
|
8129
|
-
return process.env.CODEX_HOME || join8(
|
|
8278
|
+
return process.env.CODEX_HOME || join8(homedir15(), ".codex");
|
|
8130
8279
|
}
|
|
8131
8280
|
function codexHooksFile() {
|
|
8132
8281
|
return join8(codexHome2(), "hooks.json");
|
|
@@ -8235,7 +8384,7 @@ function codexHookTrusted(configFile = codexConfigFile(), hooksFile = codexHooks
|
|
|
8235
8384
|
hooks: [normalizedHandler]
|
|
8236
8385
|
};
|
|
8237
8386
|
if (typeof group.matcher === "string") identity.matcher = group.matcher;
|
|
8238
|
-
const currentHash = `sha256:${
|
|
8387
|
+
const currentHash = `sha256:${createHash3("sha256").update(JSON.stringify(canonicalJson2(identity))).digest("hex")}`;
|
|
8239
8388
|
const key2 = `${hooksFile}:session_start:${groupIndex}:${handlerIndex}`;
|
|
8240
8389
|
matches.push(config.hooks?.state?.[key2]?.trusted_hash === currentHash);
|
|
8241
8390
|
}
|
|
@@ -8267,14 +8416,14 @@ import * as p6 from "@clack/prompts";
|
|
|
8267
8416
|
|
|
8268
8417
|
// src/autosync/cursorHook.ts
|
|
8269
8418
|
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8270
|
-
import { homedir as
|
|
8419
|
+
import { homedir as homedir17, platform as platform2 } from "node:os";
|
|
8271
8420
|
import { dirname as dirname7, join as join10 } from "node:path";
|
|
8272
8421
|
|
|
8273
8422
|
// src/autosync/hook.ts
|
|
8274
8423
|
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
|
|
8275
|
-
import { homedir as
|
|
8424
|
+
import { homedir as homedir16 } from "node:os";
|
|
8276
8425
|
import { dirname as dirname6, join as join9 } from "node:path";
|
|
8277
|
-
var CLAUDE_SETTINGS_FILE = join9(
|
|
8426
|
+
var CLAUDE_SETTINGS_FILE = join9(homedir16(), ".claude", "settings.json");
|
|
8278
8427
|
var AUTO_SYNC_HOOK_COMMAND = "npx -y @use-aistack/cli@latest sync --auto || npx -y --prefer-offline @use-aistack/cli sync --auto";
|
|
8279
8428
|
function isOurs2(entry) {
|
|
8280
8429
|
return typeof entry.command === "string" && entry.command.includes("@use-aistack/cli") && entry.command.includes("sync --auto");
|
|
@@ -8347,7 +8496,7 @@ function autoSyncHookInstalled(file = CLAUDE_SETTINGS_FILE) {
|
|
|
8347
8496
|
}
|
|
8348
8497
|
|
|
8349
8498
|
// src/autosync/cursorHook.ts
|
|
8350
|
-
var CURSOR_HOOK_FILE = join10(
|
|
8499
|
+
var CURSOR_HOOK_FILE = join10(homedir17(), ".cursor", "hooks.json");
|
|
8351
8500
|
function cursorHookCommand(os = platform2()) {
|
|
8352
8501
|
if (os === "win32") {
|
|
8353
8502
|
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 +8576,10 @@ import {
|
|
|
8427
8576
|
unlinkSync,
|
|
8428
8577
|
writeFileSync as writeFileSync6
|
|
8429
8578
|
} from "node:fs";
|
|
8430
|
-
import { homedir as
|
|
8579
|
+
import { homedir as homedir18, platform as platform3 } from "node:os";
|
|
8431
8580
|
import { dirname as dirname8, join as join11 } from "node:path";
|
|
8432
8581
|
var GROK_HOOK_FILE = join11(
|
|
8433
|
-
process.env.GROK_HOME || join11(
|
|
8582
|
+
process.env.GROK_HOME || join11(homedir18(), ".grok"),
|
|
8434
8583
|
"hooks",
|
|
8435
8584
|
"aistack.json"
|
|
8436
8585
|
);
|
|
@@ -8788,11 +8937,11 @@ import {
|
|
|
8788
8937
|
unlinkSync as unlinkSync2,
|
|
8789
8938
|
writeFileSync as writeFileSync8
|
|
8790
8939
|
} from "node:fs";
|
|
8791
|
-
import { homedir as
|
|
8940
|
+
import { homedir as homedir20 } from "node:os";
|
|
8792
8941
|
import { dirname as dirname9, join as join12 } from "node:path";
|
|
8793
8942
|
|
|
8794
8943
|
// src/sync/stage.ts
|
|
8795
|
-
import { createHash as
|
|
8944
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
8796
8945
|
|
|
8797
8946
|
// src/usage/days.ts
|
|
8798
8947
|
var round6 = (n) => Math.round(n * 1e6) / 1e6;
|
|
@@ -8907,11 +9056,11 @@ function buildMeasuredDays(input) {
|
|
|
8907
9056
|
|
|
8908
9057
|
// src/usage/diff.ts
|
|
8909
9058
|
var MAX_DAY_WINDOW = 400;
|
|
8910
|
-
var
|
|
9059
|
+
var DAY_MS2 = 864e5;
|
|
8911
9060
|
function retentionFloor(todayUtc, days) {
|
|
8912
9061
|
const span = Math.max(1, Math.min(days, MAX_DAY_WINDOW));
|
|
8913
9062
|
const todayMs = Date.parse(`${todayUtc}T00:00:00.000Z`);
|
|
8914
|
-
return new Date(todayMs - (span - 1) *
|
|
9063
|
+
return new Date(todayMs - (span - 1) * DAY_MS2).toISOString().slice(0, 10);
|
|
8915
9064
|
}
|
|
8916
9065
|
function selectDaysToPublish(input) {
|
|
8917
9066
|
const { local, manifest, todayUtc } = input;
|
|
@@ -8948,7 +9097,7 @@ function selectDaysToPublish(input) {
|
|
|
8948
9097
|
|
|
8949
9098
|
// src/workflow/git.ts
|
|
8950
9099
|
import { execFile, execFileSync as execFileSync2 } from "node:child_process";
|
|
8951
|
-
import
|
|
9100
|
+
import path12 from "node:path";
|
|
8952
9101
|
var TEST_FILE_RULE_VERSION = "test-files/v2";
|
|
8953
9102
|
var FILE_TYPE_RULE_VERSION = "file-types/v2";
|
|
8954
9103
|
var COMMIT_SET_RULE_VERSION = "commit-set/v1";
|
|
@@ -9212,10 +9361,10 @@ function reduceGitHistories(histories, options) {
|
|
|
9212
9361
|
const field = fields[fieldIndex] ?? "";
|
|
9213
9362
|
if (field.replace(/^\n+/, "") === COMMIT_MARKER) {
|
|
9214
9363
|
finishCommit();
|
|
9215
|
-
const
|
|
9364
|
+
const hash2 = fields[++fieldIndex] ?? "";
|
|
9216
9365
|
const authoredAt = fields[++fieldIndex] ?? "";
|
|
9217
9366
|
const authoredMs = Date.parse(authoredAt);
|
|
9218
|
-
const included = Number.isFinite(authoredMs) && authoredMs >= options.fromMs && authoredMs <= options.toMs && !seenCommits.has(
|
|
9367
|
+
const included = Number.isFinite(authoredMs) && authoredMs >= options.fromMs && authoredMs <= options.toMs && !seenCommits.has(hash2);
|
|
9219
9368
|
current = {
|
|
9220
9369
|
included,
|
|
9221
9370
|
date: included ? new Date(authoredMs).toISOString().slice(0, 10) : "",
|
|
@@ -9228,7 +9377,7 @@ function reduceGitHistories(histories, options) {
|
|
|
9228
9377
|
withheldLines: 0,
|
|
9229
9378
|
extensionLines: /* @__PURE__ */ new Map()
|
|
9230
9379
|
};
|
|
9231
|
-
if (included) seenCommits.add(
|
|
9380
|
+
if (included) seenCommits.add(hash2);
|
|
9232
9381
|
continue;
|
|
9233
9382
|
}
|
|
9234
9383
|
const stat8 = parseNumstat(field);
|
|
@@ -9247,7 +9396,7 @@ function reduceGitHistories(histories, options) {
|
|
|
9247
9396
|
current.changedLines += fileChangedLines;
|
|
9248
9397
|
if (isTestFile(file)) current.touchesTest = true;
|
|
9249
9398
|
if (fileChangedLines <= 0) continue;
|
|
9250
|
-
const extension =
|
|
9399
|
+
const extension = path12.extname(file).toLowerCase();
|
|
9251
9400
|
if (APPROVED_EXTENSIONS.has(extension)) {
|
|
9252
9401
|
current.extensionLines.set(
|
|
9253
9402
|
extension,
|
|
@@ -9351,18 +9500,18 @@ function buildWorkflowExtraction(harnessWorkflows, git, utcOffsetMinutes = machi
|
|
|
9351
9500
|
}
|
|
9352
9501
|
|
|
9353
9502
|
// src/sync/grokDateCache.ts
|
|
9354
|
-
import { createHash as
|
|
9503
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
9355
9504
|
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
|
-
|
|
9505
|
+
import { homedir as homedir19 } from "node:os";
|
|
9506
|
+
import path13 from "node:path";
|
|
9507
|
+
var defaultFile = path13.join(
|
|
9508
|
+
homedir19(),
|
|
9360
9509
|
".config",
|
|
9361
9510
|
"aistack",
|
|
9362
9511
|
"grok-session-dates.json"
|
|
9363
9512
|
);
|
|
9364
9513
|
function grokCacheScope(baseUrl, stack, token) {
|
|
9365
|
-
return
|
|
9514
|
+
return createHash4("sha256").update(`${baseUrl}\0${stack}\0${token}`).digest("hex");
|
|
9366
9515
|
}
|
|
9367
9516
|
function read2(file) {
|
|
9368
9517
|
if (!existsSync12(file)) return {};
|
|
@@ -9379,7 +9528,7 @@ function loadGrokDateHints(scope, file = defaultFile) {
|
|
|
9379
9528
|
function saveGrokDateHints(scope, hints, file = defaultFile) {
|
|
9380
9529
|
const cache = read2(file);
|
|
9381
9530
|
cache[scope] = hints;
|
|
9382
|
-
mkdirSync7(
|
|
9531
|
+
mkdirSync7(path13.dirname(file), { recursive: true });
|
|
9383
9532
|
writeFileSync7(file, JSON.stringify(cache, null, 2));
|
|
9384
9533
|
}
|
|
9385
9534
|
function mapToHints(value, floor) {
|
|
@@ -9791,7 +9940,7 @@ function buildGateSummary(ctx) {
|
|
|
9791
9940
|
// src/sync/stage.ts
|
|
9792
9941
|
var utcDate2 = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
9793
9942
|
function stageId(bodyJson) {
|
|
9794
|
-
return
|
|
9943
|
+
return createHash5("sha256").update(bodyJson).digest("hex").slice(0, 12);
|
|
9795
9944
|
}
|
|
9796
9945
|
async function stageSync(deps) {
|
|
9797
9946
|
const now = (deps.now ?? Date.now)();
|
|
@@ -9808,7 +9957,7 @@ async function stageSync(deps) {
|
|
|
9808
9957
|
id: BUNDLED_PRICE_TABLE_ID,
|
|
9809
9958
|
origin: "bundled"
|
|
9810
9959
|
};
|
|
9811
|
-
progress("Checking prices
|
|
9960
|
+
progress("Checking prices");
|
|
9812
9961
|
try {
|
|
9813
9962
|
const table = await fetchPrices(deps.baseUrl);
|
|
9814
9963
|
if (table) {
|
|
@@ -9820,12 +9969,14 @@ async function stageSync(deps) {
|
|
|
9820
9969
|
} catch {
|
|
9821
9970
|
setActivePricer(null);
|
|
9822
9971
|
}
|
|
9972
|
+
progress("Checking stack settings");
|
|
9823
9973
|
const { config, source } = await loadConfig({
|
|
9824
9974
|
baseUrl: deps.baseUrl,
|
|
9825
9975
|
...token ? { token } : {}
|
|
9826
9976
|
});
|
|
9827
9977
|
let manifest = null;
|
|
9828
9978
|
if (token) {
|
|
9979
|
+
progress("Checking previously synced days");
|
|
9829
9980
|
try {
|
|
9830
9981
|
manifest = await fetchManifest(deps.baseUrl, token);
|
|
9831
9982
|
} catch {
|
|
@@ -9842,6 +9993,7 @@ async function stageSync(deps) {
|
|
|
9842
9993
|
const usageScans = [];
|
|
9843
9994
|
const sinceMs = windowStartMs(now, windowDays);
|
|
9844
9995
|
const daysSinceMs = windowStartMs(now, retentionDays);
|
|
9996
|
+
progress("Detecting local harnesses");
|
|
9845
9997
|
const active2 = await adapters(sinceMs);
|
|
9846
9998
|
const historical = await adapters(daysSinceMs);
|
|
9847
9999
|
let dayScansComplete = true;
|
|
@@ -9996,7 +10148,7 @@ async function stageSync(deps) {
|
|
|
9996
10148
|
}
|
|
9997
10149
|
|
|
9998
10150
|
// src/autosync/run.ts
|
|
9999
|
-
var SYNC_LOG_FILE = join12(
|
|
10151
|
+
var SYNC_LOG_FILE = join12(homedir20(), ".config", "aistack", "sync.log");
|
|
10000
10152
|
var SYNC_LOG_MAX_LINES = 200;
|
|
10001
10153
|
var FIX_COMMAND = "npx @use-aistack/cli sync";
|
|
10002
10154
|
var REVOKED_RESULT = "off - auto-sync is switched off for this stack";
|
|
@@ -10049,7 +10201,7 @@ async function runAutoSync(deps) {
|
|
|
10049
10201
|
const state = settings.autoSyncState ?? {};
|
|
10050
10202
|
const lastRunAt = state.lastRunAt ?? 0;
|
|
10051
10203
|
if (now - lastRunAt < windowMs) return;
|
|
10052
|
-
const reservationFile = deps.reservationFile ?? `${settingsFile ?? join12(
|
|
10204
|
+
const reservationFile = deps.reservationFile ?? `${settingsFile ?? join12(homedir20(), ".config", "aistack", "settings.json")}.auto-sync-attempt`;
|
|
10053
10205
|
if (!reserveAttempt(reservationFile, now, windowMs)) return;
|
|
10054
10206
|
saveSettings({ autoSyncState: { ...state, lastRunAt: now } }, settingsFile);
|
|
10055
10207
|
const stage = deps.stageImpl ?? stageSync;
|