chat-recall 0.5.8 → 0.5.9
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 +11 -24
- package/dist/cli.js +388 -131
- package/dist/cli.js.map +1 -1
- package/dist/intent-drain.d.ts.map +1 -1
- package/dist/intent-drain.js +68 -2
- package/dist/intent-drain.js.map +1 -1
- package/dist/mcp.js +258 -38
- package/dist/mcp.js.map +1 -1
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +12 -2
- package/dist/sync-client.js.map +1 -1
- package/dist/watch.js +2485 -2050
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +2 -0
package/dist/cli.js
CHANGED
|
@@ -7456,7 +7456,7 @@ async function archiveRawSession(store, sessionId) {
|
|
|
7456
7456
|
}
|
|
7457
7457
|
function detectForkPredecessor(sessionPath) {
|
|
7458
7458
|
const { readFileSync: readFileSync49, readdirSync: readdirSync35 } = requireFs();
|
|
7459
|
-
const { dirname:
|
|
7459
|
+
const { dirname: dirname27, join: join61, basename: basename29 } = requirePath();
|
|
7460
7460
|
let text;
|
|
7461
7461
|
try {
|
|
7462
7462
|
text = readFileSync49(sessionPath, "utf-8");
|
|
@@ -7481,7 +7481,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7481
7481
|
return null;
|
|
7482
7482
|
if (text.includes(`"uuid":"${headParent}"`))
|
|
7483
7483
|
return null;
|
|
7484
|
-
const dir =
|
|
7484
|
+
const dir = dirname27(sessionPath);
|
|
7485
7485
|
const self = basename29(sessionPath);
|
|
7486
7486
|
let entries;
|
|
7487
7487
|
try {
|
|
@@ -14608,10 +14608,10 @@ var init_types = __esm({
|
|
|
14608
14608
|
|
|
14609
14609
|
// ../engine/dist/transcript/opencode.js
|
|
14610
14610
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
14611
|
-
const { existsSync:
|
|
14611
|
+
const { existsSync: existsSync57 } = await import("fs");
|
|
14612
14612
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
14613
14613
|
const dbPath = opencodeBackend2.dbPath();
|
|
14614
|
-
if (!
|
|
14614
|
+
if (!existsSync57(dbPath))
|
|
14615
14615
|
return [];
|
|
14616
14616
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
14617
14617
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -14652,10 +14652,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
14652
14652
|
}
|
|
14653
14653
|
}
|
|
14654
14654
|
async function parseOpenCodeTranscript(sessionId) {
|
|
14655
|
-
const { existsSync:
|
|
14655
|
+
const { existsSync: existsSync57 } = await import("fs");
|
|
14656
14656
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
14657
14657
|
const dbPath = opencodeBackend2.dbPath();
|
|
14658
|
-
if (!
|
|
14658
|
+
if (!existsSync57(dbPath))
|
|
14659
14659
|
return [];
|
|
14660
14660
|
const realId = sessionId.replace("opencode_", "");
|
|
14661
14661
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -18052,10 +18052,55 @@ var init_diary_source = __esm({
|
|
|
18052
18052
|
}
|
|
18053
18053
|
});
|
|
18054
18054
|
|
|
18055
|
+
// ../engine/dist/core/redact-inline.js
|
|
18056
|
+
function redactInlineSecrets(value) {
|
|
18057
|
+
let redacted = false;
|
|
18058
|
+
let out = value;
|
|
18059
|
+
out = out.replace(/(\w+:\/\/[^:/@\s]+:)([^@\s]{1,512})(@)/g, (_m, head, _pw, tail) => {
|
|
18060
|
+
redacted = true;
|
|
18061
|
+
return `${head}__SECRET_NOT_SYNCED__${tail}`;
|
|
18062
|
+
});
|
|
18063
|
+
const tokenShapes = [
|
|
18064
|
+
/\bsk-[A-Za-z0-9_-]{16,}\b/g,
|
|
18065
|
+
// OpenAI-style
|
|
18066
|
+
/\bgh[pousr]_[A-Za-z0-9]{16,}\b/g,
|
|
18067
|
+
// GitHub
|
|
18068
|
+
/\bAIza[0-9A-Za-z_-]{20,}\b/g,
|
|
18069
|
+
// Google
|
|
18070
|
+
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g
|
|
18071
|
+
// Slack
|
|
18072
|
+
];
|
|
18073
|
+
for (const re of tokenShapes) {
|
|
18074
|
+
out = out.replace(re, () => {
|
|
18075
|
+
redacted = true;
|
|
18076
|
+
return "__SECRET_NOT_SYNCED__";
|
|
18077
|
+
});
|
|
18078
|
+
}
|
|
18079
|
+
return { text: out, redacted };
|
|
18080
|
+
}
|
|
18081
|
+
var init_redact_inline = __esm({
|
|
18082
|
+
"../engine/dist/core/redact-inline.js"() {
|
|
18083
|
+
"use strict";
|
|
18084
|
+
}
|
|
18085
|
+
});
|
|
18086
|
+
|
|
18055
18087
|
// ../engine/dist/parsers/skills-source.js
|
|
18056
18088
|
import { existsSync as existsSync35, readdirSync as readdirSync26, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
18057
18089
|
import { homedir as homedir12 } from "os";
|
|
18058
18090
|
import { join as join34 } from "path";
|
|
18091
|
+
function rebuildBody(content) {
|
|
18092
|
+
const { text, redacted } = redactInlineSecrets(content);
|
|
18093
|
+
const out = {};
|
|
18094
|
+
if (text.length > MAX_BODY_CHARS) {
|
|
18095
|
+
out.body = text.slice(0, MAX_BODY_CHARS);
|
|
18096
|
+
out.bodyTruncated = true;
|
|
18097
|
+
} else {
|
|
18098
|
+
out.body = text;
|
|
18099
|
+
}
|
|
18100
|
+
if (redacted)
|
|
18101
|
+
out.bodySecretsRedacted = true;
|
|
18102
|
+
return out;
|
|
18103
|
+
}
|
|
18059
18104
|
function resolveRoots() {
|
|
18060
18105
|
const home = homedir12();
|
|
18061
18106
|
const all = [];
|
|
@@ -18099,7 +18144,7 @@ function parseFrontmatter3(text) {
|
|
|
18099
18144
|
}
|
|
18100
18145
|
return out;
|
|
18101
18146
|
}
|
|
18102
|
-
var MAX_CHUNK_CHARS12, SkillsSource;
|
|
18147
|
+
var MAX_CHUNK_CHARS12, MAX_BODY_CHARS, SkillsSource;
|
|
18103
18148
|
var init_skills_source = __esm({
|
|
18104
18149
|
"../engine/dist/parsers/skills-source.js"() {
|
|
18105
18150
|
"use strict";
|
|
@@ -18108,7 +18153,9 @@ var init_skills_source = __esm({
|
|
|
18108
18153
|
init_codex2();
|
|
18109
18154
|
init_tool_paths();
|
|
18110
18155
|
init_settings();
|
|
18156
|
+
init_redact_inline();
|
|
18111
18157
|
MAX_CHUNK_CHARS12 = 2e3;
|
|
18158
|
+
MAX_BODY_CHARS = 512 * 1024;
|
|
18112
18159
|
SkillsSource = class {
|
|
18113
18160
|
sourceType = "skill";
|
|
18114
18161
|
async *discover() {
|
|
@@ -18186,7 +18233,10 @@ var init_skills_source = __esm({
|
|
|
18186
18233
|
skillName,
|
|
18187
18234
|
description: fm.description || "",
|
|
18188
18235
|
skillDir,
|
|
18189
|
-
subdirs
|
|
18236
|
+
subdirs,
|
|
18237
|
+
// The whole file, so another machine can rebuild this skill. The
|
|
18238
|
+
// search chunk below stays capped at 2000 chars; this does not.
|
|
18239
|
+
...rebuildBody(content)
|
|
18190
18240
|
};
|
|
18191
18241
|
if (root.readonly || pluginName !== void 0)
|
|
18192
18242
|
extra.readonly = true;
|
|
@@ -18259,31 +18309,6 @@ function commandPreview(cfg) {
|
|
|
18259
18309
|
}
|
|
18260
18310
|
return "";
|
|
18261
18311
|
}
|
|
18262
|
-
function redactInlineSecrets(value) {
|
|
18263
|
-
let redacted = false;
|
|
18264
|
-
let out = value;
|
|
18265
|
-
out = out.replace(/(\w+:\/\/[^:/@\s]+:)([^@\s]{1,512})(@)/g, (_m, head, _pw, tail) => {
|
|
18266
|
-
redacted = true;
|
|
18267
|
-
return `${head}__SECRET_NOT_SYNCED__${tail}`;
|
|
18268
|
-
});
|
|
18269
|
-
const tokenShapes = [
|
|
18270
|
-
/\bsk-[A-Za-z0-9_-]{16,}\b/g,
|
|
18271
|
-
// OpenAI-style
|
|
18272
|
-
/\bgh[pousr]_[A-Za-z0-9]{16,}\b/g,
|
|
18273
|
-
// GitHub
|
|
18274
|
-
/\bAIza[0-9A-Za-z_-]{20,}\b/g,
|
|
18275
|
-
// Google
|
|
18276
|
-
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g
|
|
18277
|
-
// Slack
|
|
18278
|
-
];
|
|
18279
|
-
for (const re of tokenShapes) {
|
|
18280
|
-
out = out.replace(re, () => {
|
|
18281
|
-
redacted = true;
|
|
18282
|
-
return "__SECRET_NOT_SYNCED__";
|
|
18283
|
-
});
|
|
18284
|
-
}
|
|
18285
|
-
return { text: out, redacted };
|
|
18286
|
-
}
|
|
18287
18312
|
function reconstructionSpec(cfg) {
|
|
18288
18313
|
const out = {
|
|
18289
18314
|
type: cfg.type || (cfg.url ? "remote" : "local"),
|
|
@@ -18320,6 +18345,7 @@ var init_mcps_source = __esm({
|
|
|
18320
18345
|
init_codex2();
|
|
18321
18346
|
init_settings();
|
|
18322
18347
|
init_tool_paths();
|
|
18348
|
+
init_redact_inline();
|
|
18323
18349
|
McpsSource = class {
|
|
18324
18350
|
sourceType = "mcp";
|
|
18325
18351
|
async *discover() {
|
|
@@ -18598,6 +18624,19 @@ var init_toolkit_format = __esm({
|
|
|
18598
18624
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
18599
18625
|
import { existsSync as existsSync37, readdirSync as readdirSync28, readFileSync as readFileSync27, statSync as statSync33 } from "fs";
|
|
18600
18626
|
import { join as join36, basename as basename20 } from "path";
|
|
18627
|
+
function rebuildBody2(content) {
|
|
18628
|
+
const { text, redacted } = redactInlineSecrets(content);
|
|
18629
|
+
const out = {};
|
|
18630
|
+
if (text.length > MAX_BODY_CHARS2) {
|
|
18631
|
+
out.body = text.slice(0, MAX_BODY_CHARS2);
|
|
18632
|
+
out.bodyTruncated = true;
|
|
18633
|
+
} else {
|
|
18634
|
+
out.body = text;
|
|
18635
|
+
}
|
|
18636
|
+
if (redacted)
|
|
18637
|
+
out.bodySecretsRedacted = true;
|
|
18638
|
+
return out;
|
|
18639
|
+
}
|
|
18601
18640
|
function parseCommand(content, fallbackName, format) {
|
|
18602
18641
|
if (format === "toml") {
|
|
18603
18642
|
const t = parseScalarToml(content);
|
|
@@ -18614,7 +18653,7 @@ function parseCommand(content, fallbackName, format) {
|
|
|
18614
18653
|
body: body.trim()
|
|
18615
18654
|
};
|
|
18616
18655
|
}
|
|
18617
|
-
var MAX_CHUNK_CHARS13, SlashCommandsSource;
|
|
18656
|
+
var MAX_CHUNK_CHARS13, MAX_BODY_CHARS2, SlashCommandsSource;
|
|
18618
18657
|
var init_slash_commands_source = __esm({
|
|
18619
18658
|
"../engine/dist/parsers/slash-commands-source.js"() {
|
|
18620
18659
|
"use strict";
|
|
@@ -18626,7 +18665,9 @@ var init_slash_commands_source = __esm({
|
|
|
18626
18665
|
init_tool_paths();
|
|
18627
18666
|
init_toolkit_format();
|
|
18628
18667
|
init_project_dir_name();
|
|
18668
|
+
init_redact_inline();
|
|
18629
18669
|
MAX_CHUNK_CHARS13 = 2e3;
|
|
18670
|
+
MAX_BODY_CHARS2 = 512 * 1024;
|
|
18630
18671
|
SlashCommandsSource = class {
|
|
18631
18672
|
sourceType = "command";
|
|
18632
18673
|
roots() {
|
|
@@ -18690,7 +18731,10 @@ var init_slash_commands_source = __esm({
|
|
|
18690
18731
|
commandName: parsed.name,
|
|
18691
18732
|
description: parsed.description,
|
|
18692
18733
|
scope: root.scope,
|
|
18693
|
-
format: root.format
|
|
18734
|
+
format: root.format,
|
|
18735
|
+
// The whole file, so another machine can rebuild it. The search
|
|
18736
|
+
// chunk stays capped at 2000 chars; this does not.
|
|
18737
|
+
...rebuildBody2(content)
|
|
18694
18738
|
}
|
|
18695
18739
|
};
|
|
18696
18740
|
} catch {
|
|
@@ -18726,6 +18770,19 @@ var init_slash_commands_source = __esm({
|
|
|
18726
18770
|
// ../engine/dist/parsers/subagents-source.js
|
|
18727
18771
|
import { existsSync as existsSync38, readdirSync as readdirSync29, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
|
|
18728
18772
|
import { join as join37, basename as basename21 } from "path";
|
|
18773
|
+
function rebuildBody3(content) {
|
|
18774
|
+
const { text, redacted } = redactInlineSecrets(content);
|
|
18775
|
+
const out = {};
|
|
18776
|
+
if (text.length > MAX_BODY_CHARS3) {
|
|
18777
|
+
out.body = text.slice(0, MAX_BODY_CHARS3);
|
|
18778
|
+
out.bodyTruncated = true;
|
|
18779
|
+
} else {
|
|
18780
|
+
out.body = text;
|
|
18781
|
+
}
|
|
18782
|
+
if (redacted)
|
|
18783
|
+
out.bodySecretsRedacted = true;
|
|
18784
|
+
return out;
|
|
18785
|
+
}
|
|
18729
18786
|
function parseAgent(content, fallbackName, format) {
|
|
18730
18787
|
if (format === "toml") {
|
|
18731
18788
|
const t = parseScalarToml(content);
|
|
@@ -18744,7 +18801,7 @@ function parseAgent(content, fallbackName, format) {
|
|
|
18744
18801
|
body: body.trim()
|
|
18745
18802
|
};
|
|
18746
18803
|
}
|
|
18747
|
-
var MAX_CHUNK_CHARS14, SubagentsSource;
|
|
18804
|
+
var MAX_CHUNK_CHARS14, MAX_BODY_CHARS3, SubagentsSource;
|
|
18748
18805
|
var init_subagents_source = __esm({
|
|
18749
18806
|
"../engine/dist/parsers/subagents-source.js"() {
|
|
18750
18807
|
"use strict";
|
|
@@ -18756,7 +18813,9 @@ var init_subagents_source = __esm({
|
|
|
18756
18813
|
init_tool_paths();
|
|
18757
18814
|
init_toolkit_format();
|
|
18758
18815
|
init_project_dir_name();
|
|
18816
|
+
init_redact_inline();
|
|
18759
18817
|
MAX_CHUNK_CHARS14 = 2e3;
|
|
18818
|
+
MAX_BODY_CHARS3 = 512 * 1024;
|
|
18760
18819
|
SubagentsSource = class {
|
|
18761
18820
|
sourceType = "agent";
|
|
18762
18821
|
roots() {
|
|
@@ -18821,7 +18880,10 @@ var init_subagents_source = __esm({
|
|
|
18821
18880
|
description: parsed.description,
|
|
18822
18881
|
tools: parsed.tools,
|
|
18823
18882
|
scope: root.scope,
|
|
18824
|
-
format: root.format
|
|
18883
|
+
format: root.format,
|
|
18884
|
+
// The whole file, so another machine can rebuild it. The search
|
|
18885
|
+
// chunk stays capped at 2000 chars; this does not.
|
|
18886
|
+
...rebuildBody3(content)
|
|
18825
18887
|
}
|
|
18826
18888
|
};
|
|
18827
18889
|
} catch {
|
|
@@ -19210,6 +19272,9 @@ var init_all_sources = __esm({
|
|
|
19210
19272
|
});
|
|
19211
19273
|
|
|
19212
19274
|
// ../engine/dist/core/extractor-version.js
|
|
19275
|
+
function extractorVersionForItem(id, sourceType) {
|
|
19276
|
+
return extractorVersionForTool(toolOfId(id)) + (ITEM_SOURCE_BUMP[sourceType] ?? 0);
|
|
19277
|
+
}
|
|
19213
19278
|
function toolOfId(id) {
|
|
19214
19279
|
if (id.startsWith("agy_"))
|
|
19215
19280
|
return "agy";
|
|
@@ -19229,11 +19294,17 @@ function extractorVersionForTool(tool) {
|
|
|
19229
19294
|
function extractorVersionForId(id) {
|
|
19230
19295
|
return extractorVersionForTool(toolOfId(id));
|
|
19231
19296
|
}
|
|
19232
|
-
var BASE_EXTRACTOR_VERSION, TOOL_EXTRACTOR_BUMP, EXTRACTOR_VERSION;
|
|
19297
|
+
var BASE_EXTRACTOR_VERSION, ITEM_SOURCE_BUMP, TOOL_EXTRACTOR_BUMP, EXTRACTOR_VERSION;
|
|
19233
19298
|
var init_extractor_version = __esm({
|
|
19234
19299
|
"../engine/dist/core/extractor-version.js"() {
|
|
19235
19300
|
"use strict";
|
|
19236
19301
|
BASE_EXTRACTOR_VERSION = 2;
|
|
19302
|
+
ITEM_SOURCE_BUMP = {
|
|
19303
|
+
mcp: 1,
|
|
19304
|
+
skill: 1,
|
|
19305
|
+
agent: 1,
|
|
19306
|
+
command: 1
|
|
19307
|
+
};
|
|
19237
19308
|
TOOL_EXTRACTOR_BUMP = {
|
|
19238
19309
|
agy: 2,
|
|
19239
19310
|
claude: 1,
|
|
@@ -19623,7 +19694,7 @@ var init_http = __esm({
|
|
|
19623
19694
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19624
19695
|
} catch {
|
|
19625
19696
|
try {
|
|
19626
|
-
if (true) CLI_VERSION = "0.5.
|
|
19697
|
+
if (true) CLI_VERSION = "0.5.9";
|
|
19627
19698
|
} catch {
|
|
19628
19699
|
}
|
|
19629
19700
|
}
|
|
@@ -20135,7 +20206,7 @@ var init_telemetry = __esm({
|
|
|
20135
20206
|
init_sync_client();
|
|
20136
20207
|
cliVersion2 = () => {
|
|
20137
20208
|
try {
|
|
20138
|
-
return true ? "0.5.
|
|
20209
|
+
return true ? "0.5.9" : "dev";
|
|
20139
20210
|
} catch {
|
|
20140
20211
|
return "dev";
|
|
20141
20212
|
}
|
|
@@ -21367,6 +21438,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21367
21438
|
}
|
|
21368
21439
|
const itemVersions = loadItemVersions(base2);
|
|
21369
21440
|
const seenTools = /* @__PURE__ */ new Set();
|
|
21441
|
+
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
21370
21442
|
const registry = buildSourceRegistry();
|
|
21371
21443
|
for (const sourceType of registry.getRegisteredTypes()) {
|
|
21372
21444
|
if (sourceType === "session") continue;
|
|
@@ -21381,7 +21453,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21381
21453
|
for await (const item of discovered) {
|
|
21382
21454
|
const itemTool = toolOfId(item.id);
|
|
21383
21455
|
seenTools.add(itemTool);
|
|
21384
|
-
const
|
|
21456
|
+
const itemKey = `${itemTool}:${item.sourceType}`;
|
|
21457
|
+
seenItemKeys.set(itemKey, extractorVersionForItem(item.id, item.sourceType));
|
|
21458
|
+
const versionStale = (itemVersions[itemKey] ?? EXTRACTOR_VERSION) < extractorVersionForItem(item.id, item.sourceType);
|
|
21385
21459
|
if ((item.mtime || 0) < (opts.sinceMs ?? 0) && !versionStale) continue;
|
|
21386
21460
|
if (excluded(item.projectPath || "")) continue;
|
|
21387
21461
|
if (!includedProject(item.projectPath || "")) continue;
|
|
@@ -21464,6 +21538,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21464
21538
|
try {
|
|
21465
21539
|
const rec = {};
|
|
21466
21540
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
21541
|
+
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
21467
21542
|
saveItemVersions(base2, rec);
|
|
21468
21543
|
} catch {
|
|
21469
21544
|
}
|
|
@@ -21903,7 +21978,7 @@ var init_sync_client = __esm({
|
|
|
21903
21978
|
ownVersion = JSON.parse(readFileSync36(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21904
21979
|
} catch {
|
|
21905
21980
|
try {
|
|
21906
|
-
if (true) ownVersion = "0.5.
|
|
21981
|
+
if (true) ownVersion = "0.5.9";
|
|
21907
21982
|
} catch {
|
|
21908
21983
|
}
|
|
21909
21984
|
}
|
|
@@ -22719,27 +22794,31 @@ var init_install_skills = __esm({
|
|
|
22719
22794
|
import { readFileSync as readFileSync41 } from "fs";
|
|
22720
22795
|
import { join as join50 } from "path";
|
|
22721
22796
|
import { homedir as homedir17 } from "os";
|
|
22722
|
-
function
|
|
22723
|
-
const content = readFileSync41(filePath, "utf-8");
|
|
22797
|
+
function parseCommandText(content, format, fallbackName) {
|
|
22724
22798
|
if (format === "toml") {
|
|
22725
22799
|
const t = parseScalarToml(content);
|
|
22726
|
-
return { name: t.name ||
|
|
22800
|
+
return { name: t.name || fallbackName, description: t.description || "", body: t.prompt || "" };
|
|
22727
22801
|
}
|
|
22728
22802
|
const { fm, body } = parseFrontmatter4(content);
|
|
22729
|
-
return { name: fm.name ||
|
|
22803
|
+
return { name: fm.name || fallbackName, description: fm.description || "", body: body.trim() };
|
|
22730
22804
|
}
|
|
22731
|
-
function
|
|
22732
|
-
const content = readFileSync41(filePath, "utf-8");
|
|
22805
|
+
function parseAgentText(content, format, fallbackName) {
|
|
22733
22806
|
if (format === "toml") {
|
|
22734
22807
|
const t = parseScalarToml(content);
|
|
22735
22808
|
return {
|
|
22736
|
-
name: t.name ||
|
|
22809
|
+
name: t.name || fallbackName,
|
|
22737
22810
|
description: t.description || "",
|
|
22738
22811
|
body: t.developer_instructions || t.instructions || ""
|
|
22739
22812
|
};
|
|
22740
22813
|
}
|
|
22741
22814
|
const { fm, body } = parseFrontmatter4(content);
|
|
22742
|
-
return { name: fm.name ||
|
|
22815
|
+
return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body.trim() };
|
|
22816
|
+
}
|
|
22817
|
+
function readCommand(filePath, format) {
|
|
22818
|
+
return parseCommandText(readFileSync41(filePath, "utf-8"), format, base(filePath));
|
|
22819
|
+
}
|
|
22820
|
+
function readAgent(filePath, format) {
|
|
22821
|
+
return parseAgentText(readFileSync41(filePath, "utf-8"), format, base(filePath));
|
|
22743
22822
|
}
|
|
22744
22823
|
function readInstructions(filePath, name) {
|
|
22745
22824
|
const content = readFileSync41(filePath, "utf-8");
|
|
@@ -23332,8 +23411,8 @@ __export(toolkit_pull_exports, {
|
|
|
23332
23411
|
planPull: () => planPull,
|
|
23333
23412
|
portableCommand: () => portableCommand
|
|
23334
23413
|
});
|
|
23335
|
-
import { statSync as statSync42 } from "node:fs";
|
|
23336
|
-
import { delimiter as delimiter3, join as join52, basename as basename25, isAbsolute as isAbsolute3 } from "node:path";
|
|
23414
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync14, statSync as statSync42, writeFileSync as writeFileSync15 } from "node:fs";
|
|
23415
|
+
import { delimiter as delimiter3, dirname as dirname21, join as join52, basename as basename25, isAbsolute as isAbsolute3 } from "node:path";
|
|
23337
23416
|
function isExecutableFile(p) {
|
|
23338
23417
|
try {
|
|
23339
23418
|
return statSync42(p).isFile();
|
|
@@ -23393,8 +23472,58 @@ function planPull(rows, opts = {}) {
|
|
|
23393
23472
|
const wanted = opts.types;
|
|
23394
23473
|
const seenUnsupported = /* @__PURE__ */ new Map();
|
|
23395
23474
|
const byName = /* @__PURE__ */ new Map();
|
|
23475
|
+
const skillsByName = /* @__PURE__ */ new Map();
|
|
23476
|
+
const agentsByName = /* @__PURE__ */ new Map();
|
|
23477
|
+
const commandsByName = /* @__PURE__ */ new Map();
|
|
23396
23478
|
for (const row of rows) {
|
|
23397
23479
|
const type = row.source_type;
|
|
23480
|
+
if (type === "skill") {
|
|
23481
|
+
if (wanted && !wanted.includes("skill"))
|
|
23482
|
+
continue;
|
|
23483
|
+
const extra2 = parseExtra(row);
|
|
23484
|
+
const name2 = extra2.skillName || row.title;
|
|
23485
|
+
const body = extra2.body;
|
|
23486
|
+
if (!name2 || typeof body !== "string" || !body.trim()) {
|
|
23487
|
+
seenUnsupported.set("skill", (seenUnsupported.get("skill") || 0) + 1);
|
|
23488
|
+
continue;
|
|
23489
|
+
}
|
|
23490
|
+
const tool = String(extra2.tool || "");
|
|
23491
|
+
const rank = SOURCE_PRECEDENCE.skill.indexOf(tool);
|
|
23492
|
+
const prev2 = skillsByName.get(name2);
|
|
23493
|
+
if (!prev2 || rank >= 0 && (prev2.rank < 0 || rank < prev2.rank)) {
|
|
23494
|
+
skillsByName.set(name2, {
|
|
23495
|
+
body,
|
|
23496
|
+
rank,
|
|
23497
|
+
truncated: extra2.bodyTruncated === true,
|
|
23498
|
+
redacted: extra2.bodySecretsRedacted === true
|
|
23499
|
+
});
|
|
23500
|
+
}
|
|
23501
|
+
continue;
|
|
23502
|
+
}
|
|
23503
|
+
if (type === "agent" || type === "command") {
|
|
23504
|
+
if (wanted && !wanted.includes(type))
|
|
23505
|
+
continue;
|
|
23506
|
+
const extra2 = parseExtra(row);
|
|
23507
|
+
const name2 = extra2[type === "agent" ? "agentName" : "commandName"] || row.title;
|
|
23508
|
+
const body = extra2.body;
|
|
23509
|
+
if (!name2 || typeof body !== "string" || !body.trim() || extra2.bodyTruncated === true) {
|
|
23510
|
+
seenUnsupported.set(type, (seenUnsupported.get(type) || 0) + 1);
|
|
23511
|
+
continue;
|
|
23512
|
+
}
|
|
23513
|
+
const tool = String(extra2.tool || "");
|
|
23514
|
+
const rank = SOURCE_PRECEDENCE[type].indexOf(tool);
|
|
23515
|
+
const bucket = type === "agent" ? agentsByName : commandsByName;
|
|
23516
|
+
const prev2 = bucket.get(name2);
|
|
23517
|
+
if (!prev2 || rank >= 0 && (prev2.rank < 0 || rank < prev2.rank)) {
|
|
23518
|
+
bucket.set(name2, {
|
|
23519
|
+
body,
|
|
23520
|
+
rank,
|
|
23521
|
+
format: extra2.format === "toml" ? "toml" : "md",
|
|
23522
|
+
redacted: extra2.bodySecretsRedacted === true
|
|
23523
|
+
});
|
|
23524
|
+
}
|
|
23525
|
+
continue;
|
|
23526
|
+
}
|
|
23398
23527
|
if (type !== "mcp") {
|
|
23399
23528
|
if (NOT_REBUILDABLE[type])
|
|
23400
23529
|
seenUnsupported.set(type, (seenUnsupported.get(type) || 0) + 1);
|
|
@@ -23416,16 +23545,93 @@ function planPull(rows, opts = {}) {
|
|
|
23416
23545
|
}
|
|
23417
23546
|
const targets = SUPPORTED_TARGETS.mcp;
|
|
23418
23547
|
const mcps = [...byName.entries()].map(([name, spec]) => ({ name, spec, tools: targets }));
|
|
23548
|
+
const skills = [...skillsByName.entries()].map(([name, v]) => ({
|
|
23549
|
+
name,
|
|
23550
|
+
body: v.body,
|
|
23551
|
+
truncated: v.truncated,
|
|
23552
|
+
redacted: v.redacted,
|
|
23553
|
+
tools: SUPPORTED_TARGETS.skill
|
|
23554
|
+
}));
|
|
23419
23555
|
const unsupported = [...seenUnsupported.entries()].map(([type, count]) => ({
|
|
23420
23556
|
type,
|
|
23421
23557
|
rows: count,
|
|
23422
|
-
reason: NOT_REBUILDABLE[type]
|
|
23558
|
+
reason: NOT_REBUILDABLE[type] ?? "the stored rows carry no full body \u2014 re-index on the device that has them"
|
|
23423
23559
|
}));
|
|
23424
|
-
|
|
23560
|
+
const codecs = [
|
|
23561
|
+
...[...agentsByName.entries()].map(([name, v]) => ({ type: "agent", name, body: v.body, format: v.format, redacted: v.redacted, tools: SUPPORTED_TARGETS.agent })),
|
|
23562
|
+
...[...commandsByName.entries()].map(([name, v]) => ({ type: "command", name, body: v.body, format: v.format, redacted: v.redacted, tools: SUPPORTED_TARGETS.command }))
|
|
23563
|
+
];
|
|
23564
|
+
return { mcps, skills, codecs, unsupported };
|
|
23425
23565
|
}
|
|
23426
23566
|
function executePull(rows, opts = {}) {
|
|
23427
|
-
const { mcps, unsupported } = planPull(rows, opts);
|
|
23567
|
+
const { mcps, skills, codecs, unsupported } = planPull(rows, opts);
|
|
23428
23568
|
const outcomes = [];
|
|
23569
|
+
for (const { name, body, truncated, redacted, tools } of skills) {
|
|
23570
|
+
for (const tool of tools) {
|
|
23571
|
+
const dir = join52(skillsDirFor(tool), name);
|
|
23572
|
+
const file = join52(dir, "SKILL.md");
|
|
23573
|
+
if (existsSync48(file)) {
|
|
23574
|
+
outcomes.push({ type: "skill", name, tool, status: "present" });
|
|
23575
|
+
continue;
|
|
23576
|
+
}
|
|
23577
|
+
if (truncated) {
|
|
23578
|
+
outcomes.push({ type: "skill", name, tool, status: "skipped", reason: "the stored body was truncated \u2014 installing it would write a corrupted skill" });
|
|
23579
|
+
continue;
|
|
23580
|
+
}
|
|
23581
|
+
if (opts.dryRun) {
|
|
23582
|
+
outcomes.push({ type: "skill", name, tool, status: "written", reason: "dry run", redactedContent: redacted });
|
|
23583
|
+
continue;
|
|
23584
|
+
}
|
|
23585
|
+
try {
|
|
23586
|
+
mkdirSync14(dir, { recursive: true });
|
|
23587
|
+
writeFileSync15(file, body);
|
|
23588
|
+
outcomes.push({ type: "skill", name, tool, status: "written", path: file, redactedContent: redacted });
|
|
23589
|
+
} catch (e) {
|
|
23590
|
+
outcomes.push({ type: "skill", name, tool, status: "failed", reason: e instanceof Error ? e.message : "write failed" });
|
|
23591
|
+
}
|
|
23592
|
+
}
|
|
23593
|
+
}
|
|
23594
|
+
for (const { type, name, body, format, redacted, tools } of codecs) {
|
|
23595
|
+
let art;
|
|
23596
|
+
try {
|
|
23597
|
+
art = type === "agent" ? parseAgentText(body, format, name) : parseCommandText(body, format, name);
|
|
23598
|
+
} catch (e) {
|
|
23599
|
+
for (const tool of tools) {
|
|
23600
|
+
outcomes.push({ type, name, tool, status: "failed", reason: `could not parse the stored body: ${e instanceof Error ? e.message : "failed"}` });
|
|
23601
|
+
}
|
|
23602
|
+
continue;
|
|
23603
|
+
}
|
|
23604
|
+
if (!art.body.trim()) {
|
|
23605
|
+
for (const tool of tools) {
|
|
23606
|
+
outcomes.push({ type, name, tool, status: "skipped", reason: `the stored body did not parse as ${format}` });
|
|
23607
|
+
}
|
|
23608
|
+
continue;
|
|
23609
|
+
}
|
|
23610
|
+
for (const tool of tools) {
|
|
23611
|
+
let out;
|
|
23612
|
+
try {
|
|
23613
|
+
out = emit(type, art, tool);
|
|
23614
|
+
} catch (e) {
|
|
23615
|
+
outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
|
|
23616
|
+
continue;
|
|
23617
|
+
}
|
|
23618
|
+
if (existsSync48(out.path)) {
|
|
23619
|
+
outcomes.push({ type, name, tool, status: "present" });
|
|
23620
|
+
continue;
|
|
23621
|
+
}
|
|
23622
|
+
if (opts.dryRun) {
|
|
23623
|
+
outcomes.push({ type, name, tool, status: "written", reason: "dry run", redactedContent: redacted });
|
|
23624
|
+
continue;
|
|
23625
|
+
}
|
|
23626
|
+
try {
|
|
23627
|
+
mkdirSync14(dirname21(out.path), { recursive: true });
|
|
23628
|
+
writeFileSync15(out.path, out.content);
|
|
23629
|
+
outcomes.push({ type, name, tool, status: "written", path: out.path, redactedContent: redacted });
|
|
23630
|
+
} catch (e) {
|
|
23631
|
+
outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "write failed" });
|
|
23632
|
+
}
|
|
23633
|
+
}
|
|
23634
|
+
}
|
|
23429
23635
|
for (const { name, spec, tools } of mcps) {
|
|
23430
23636
|
const built = entryFromSpec(spec);
|
|
23431
23637
|
for (const tool of tools) {
|
|
@@ -23484,11 +23690,12 @@ var init_toolkit_pull = __esm({
|
|
|
23484
23690
|
"../engine/dist/core/toolkit-pull.js"() {
|
|
23485
23691
|
"use strict";
|
|
23486
23692
|
init_toolkit_sync();
|
|
23693
|
+
init_artifact_codec();
|
|
23487
23694
|
NOT_REBUILDABLE = {
|
|
23488
|
-
|
|
23489
|
-
|
|
23490
|
-
|
|
23491
|
-
instructions: "project-scoped
|
|
23695
|
+
// Instructions are the one type that SHOULD not travel by device: a CLAUDE.md
|
|
23696
|
+
// belongs to a repository, so installing one per machine would put a
|
|
23697
|
+
// project's rules somewhere they do not apply.
|
|
23698
|
+
instructions: "project-scoped \u2014 it belongs to a repo, not to a machine"
|
|
23492
23699
|
};
|
|
23493
23700
|
}
|
|
23494
23701
|
});
|
|
@@ -23984,11 +24191,11 @@ var verify_repair_exports = {};
|
|
|
23984
24191
|
__export(verify_repair_exports, {
|
|
23985
24192
|
forceFullResync: () => forceFullResync
|
|
23986
24193
|
});
|
|
23987
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
24194
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync49 } from "fs";
|
|
23988
24195
|
function forceFullResync(server, sessionIds) {
|
|
23989
24196
|
if (sessionIds.length === 0) return 0;
|
|
23990
24197
|
const path = ledgerFilePath();
|
|
23991
|
-
if (
|
|
24198
|
+
if (existsSync49(path)) {
|
|
23992
24199
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
23993
24200
|
try {
|
|
23994
24201
|
copyFileSync3(path, `${path}.bak-${stamp}`);
|
|
@@ -25063,8 +25270,8 @@ __export(project_tasks_exports, {
|
|
|
25063
25270
|
pushProjectTaskStatuses: () => pushProjectTaskStatuses,
|
|
25064
25271
|
renderTeamTasksMd: () => renderTeamTasksMd
|
|
25065
25272
|
});
|
|
25066
|
-
import { existsSync as
|
|
25067
|
-
import { join as join54, dirname as
|
|
25273
|
+
import { existsSync as existsSync50, readFileSync as readFileSync44, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15, statSync as statSync43 } from "node:fs";
|
|
25274
|
+
import { join as join54, dirname as dirname22 } from "node:path";
|
|
25068
25275
|
import { homedir as homedir19 } from "node:os";
|
|
25069
25276
|
function isTeamTaskStatus(v) {
|
|
25070
25277
|
return !!v && TEAM_STATUSES.has(v);
|
|
@@ -25126,11 +25333,11 @@ function readLedger() {
|
|
|
25126
25333
|
}
|
|
25127
25334
|
function writeLedger(l) {
|
|
25128
25335
|
try {
|
|
25129
|
-
|
|
25336
|
+
mkdirSync15(dirname22(ledgerPath2()), { recursive: true });
|
|
25130
25337
|
} catch {
|
|
25131
25338
|
}
|
|
25132
25339
|
try {
|
|
25133
|
-
|
|
25340
|
+
writeFileSync16(ledgerPath2(), JSON.stringify(l));
|
|
25134
25341
|
} catch {
|
|
25135
25342
|
}
|
|
25136
25343
|
}
|
|
@@ -25149,7 +25356,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
25149
25356
|
}
|
|
25150
25357
|
for (const project of projects) {
|
|
25151
25358
|
const file = join54(project, fk.filename);
|
|
25152
|
-
if (!
|
|
25359
|
+
if (!existsSync50(file)) continue;
|
|
25153
25360
|
let mtime;
|
|
25154
25361
|
try {
|
|
25155
25362
|
mtime = statSync43(file).mtimeMs;
|
|
@@ -25229,18 +25436,18 @@ var intent_drain_exports = {};
|
|
|
25229
25436
|
__export(intent_drain_exports, {
|
|
25230
25437
|
drainSyncIntents: () => drainSyncIntents
|
|
25231
25438
|
});
|
|
25232
|
-
import { existsSync as
|
|
25439
|
+
import { existsSync as existsSync51, readFileSync as readFileSync45, writeFileSync as writeFileSync17, appendFileSync, mkdirSync as mkdirSync16 } from "node:fs";
|
|
25233
25440
|
import { join as join55 } from "node:path";
|
|
25234
25441
|
import { homedir as homedir20 } from "node:os";
|
|
25235
25442
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
25236
|
-
import { dirname as
|
|
25443
|
+
import { dirname as dirname23 } from "node:path";
|
|
25237
25444
|
function applyCodeRecommendation(intent) {
|
|
25238
25445
|
try {
|
|
25239
25446
|
const meta = JSON.parse(intent.name || "{}");
|
|
25240
25447
|
if (intent.artifact_type === "write_tasks_file") {
|
|
25241
25448
|
if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
|
|
25242
25449
|
const file = join55(meta.rootPath, meta.filename || "CODE_TASKS.md");
|
|
25243
|
-
|
|
25450
|
+
writeFileSync17(file, meta.content);
|
|
25244
25451
|
return { status: "done", result: JSON.stringify({ wrote: file }) };
|
|
25245
25452
|
}
|
|
25246
25453
|
if (intent.artifact_type === "append_claude_md") {
|
|
@@ -25251,7 +25458,7 @@ function applyCodeRecommendation(intent) {
|
|
|
25251
25458
|
if (isGlobal) {
|
|
25252
25459
|
const dir = join55(homedir20(), ".claude");
|
|
25253
25460
|
try {
|
|
25254
|
-
|
|
25461
|
+
mkdirSync16(dir, { recursive: true });
|
|
25255
25462
|
} catch {
|
|
25256
25463
|
}
|
|
25257
25464
|
file = join55(dir, "CLAUDE.md");
|
|
@@ -25259,14 +25466,14 @@ function applyCodeRecommendation(intent) {
|
|
|
25259
25466
|
if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
|
|
25260
25467
|
file = join55(meta.rootPath, "CLAUDE.md");
|
|
25261
25468
|
}
|
|
25262
|
-
const existing =
|
|
25469
|
+
const existing = existsSync51(file) ? readFileSync45(file, "utf8") : "";
|
|
25263
25470
|
if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
|
|
25264
25471
|
const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
|
|
25265
25472
|
## Rule (added by chat-recall recommendation)
|
|
25266
25473
|
${text}
|
|
25267
25474
|
`;
|
|
25268
25475
|
if (existing) appendFileSync(file, block);
|
|
25269
|
-
else
|
|
25476
|
+
else writeFileSync17(file, `# ${meta.rootPath?.split("/").pop() || "Global"} instructions
|
|
25270
25477
|
${block}`);
|
|
25271
25478
|
return { status: "done", result: JSON.stringify({ appended: file }) };
|
|
25272
25479
|
}
|
|
@@ -25275,6 +25482,46 @@ ${block}`);
|
|
|
25275
25482
|
return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
|
|
25276
25483
|
}
|
|
25277
25484
|
}
|
|
25485
|
+
async function runPull(base2, opts) {
|
|
25486
|
+
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
25487
|
+
const { hostname: hostname3 } = await import("node:os");
|
|
25488
|
+
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base2.replace(/\/+$/, ""));
|
|
25489
|
+
const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
|
|
25490
|
+
const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
|
|
25491
|
+
const rows = [];
|
|
25492
|
+
for (const type of wanted) {
|
|
25493
|
+
try {
|
|
25494
|
+
const res = await fetchWithTimeout(`${base2}/api/toolkit/browse/${type}?limit=1000`, { headers });
|
|
25495
|
+
if (!res.ok) continue;
|
|
25496
|
+
const body = await res.json();
|
|
25497
|
+
for (const it of body.items || []) rows.push(it);
|
|
25498
|
+
} catch {
|
|
25499
|
+
}
|
|
25500
|
+
}
|
|
25501
|
+
const filtered = opts.name ? rows.filter((r) => {
|
|
25502
|
+
try {
|
|
25503
|
+
return (JSON.parse(r.extra_json || "{}").mcpName || r.title) === opts.name;
|
|
25504
|
+
} catch {
|
|
25505
|
+
return r.title === opts.name;
|
|
25506
|
+
}
|
|
25507
|
+
}) : rows;
|
|
25508
|
+
const report = executePull2(filtered, { thisDeviceId: hostname3(), types: wanted });
|
|
25509
|
+
const written = report.outcomes.filter((o) => o.status === "written");
|
|
25510
|
+
const failed = report.outcomes.filter((o) => o.status === "failed");
|
|
25511
|
+
return {
|
|
25512
|
+
// A skip is a reported outcome, not a failure — the artifact genuinely
|
|
25513
|
+
// cannot be installed here and the reason travels back with the ack.
|
|
25514
|
+
status: failed.length > 0 ? "error" : "done",
|
|
25515
|
+
result: JSON.stringify({
|
|
25516
|
+
installed: written.length,
|
|
25517
|
+
present: report.outcomes.filter((o) => o.status === "present").length,
|
|
25518
|
+
skipped: report.outcomes.filter((o) => o.status === "skipped").map((o) => `${o.name}: ${o.reason}`).slice(0, 20),
|
|
25519
|
+
failed: failed.map((o) => `${o.name}: ${o.reason}`).slice(0, 20),
|
|
25520
|
+
needsEnv: [...new Set(written.flatMap((o) => o.needsEnv || []))],
|
|
25521
|
+
unsupported: report.unsupported
|
|
25522
|
+
})
|
|
25523
|
+
};
|
|
25524
|
+
}
|
|
25278
25525
|
async function runIntent(intent, ctx) {
|
|
25279
25526
|
try {
|
|
25280
25527
|
if (intent.kind === "recheck_session") {
|
|
@@ -25287,6 +25534,14 @@ async function runIntent(intent, ctx) {
|
|
|
25287
25534
|
if (intent.kind === "code_apply") {
|
|
25288
25535
|
return applyCodeRecommendation(intent);
|
|
25289
25536
|
}
|
|
25537
|
+
if (intent.kind === "pull") {
|
|
25538
|
+
const types = (intent.artifact_type || "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
25539
|
+
const r2 = await runPull(ctx.base, {
|
|
25540
|
+
types: types.length ? types : void 0,
|
|
25541
|
+
name: intent.name || void 0
|
|
25542
|
+
});
|
|
25543
|
+
return r2;
|
|
25544
|
+
}
|
|
25290
25545
|
if (intent.kind === "sync_all") {
|
|
25291
25546
|
const report = await executeSyncAll();
|
|
25292
25547
|
const status2 = report.failed.length > 0 ? "error" : "done";
|
|
@@ -25330,7 +25585,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
25330
25585
|
if (status === "done") out.done++;
|
|
25331
25586
|
else out.errored++;
|
|
25332
25587
|
if (opts.verbose) {
|
|
25333
|
-
const label = intent.kind === "sync_all" ? "sync_all" : intent.kind === "recheck_session" ? `recheck ${intent.name}` : `${intent.artifact_type} "${intent.name}" ${intent.from_tool}\u2192${intent.to_tool}`;
|
|
25588
|
+
const label = intent.kind === "sync_all" ? "sync_all" : intent.kind === "pull" ? `pull ${intent.artifact_type || "all"}${intent.name ? ` "${intent.name}"` : ""}` : intent.kind === "recheck_session" ? `recheck ${intent.name}` : `${intent.artifact_type} "${intent.name}" ${intent.from_tool}\u2192${intent.to_tool}`;
|
|
25334
25589
|
console.error(`[sync-intent] ${label}: ${status}`);
|
|
25335
25590
|
}
|
|
25336
25591
|
try {
|
|
@@ -25365,11 +25620,11 @@ var init_intent_drain = __esm({
|
|
|
25365
25620
|
init_project_tasks();
|
|
25366
25621
|
ownVersion2 = "0.0.0";
|
|
25367
25622
|
try {
|
|
25368
|
-
const dir =
|
|
25623
|
+
const dir = dirname23(fileURLToPath3(import.meta.url));
|
|
25369
25624
|
ownVersion2 = JSON.parse(readFileSync45(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25370
25625
|
} catch {
|
|
25371
25626
|
try {
|
|
25372
|
-
if (true) ownVersion2 = "0.5.
|
|
25627
|
+
if (true) ownVersion2 = "0.5.9";
|
|
25373
25628
|
} catch {
|
|
25374
25629
|
}
|
|
25375
25630
|
}
|
|
@@ -25570,8 +25825,8 @@ var team_merge_exports = {};
|
|
|
25570
25825
|
__export(team_merge_exports, {
|
|
25571
25826
|
mergePullResult: () => mergePullResult
|
|
25572
25827
|
});
|
|
25573
|
-
import { existsSync as
|
|
25574
|
-
import { dirname as
|
|
25828
|
+
import { existsSync as existsSync52, mkdirSync as mkdirSync17, readFileSync as readFileSync46, rmSync as rmSync7, writeFileSync as writeFileSync18, statSync as statSync44 } from "fs";
|
|
25829
|
+
import { dirname as dirname24, join as join56 } from "path";
|
|
25575
25830
|
import { createHash as createHash17 } from "crypto";
|
|
25576
25831
|
function installPathFor(art, tool) {
|
|
25577
25832
|
switch (art.type) {
|
|
@@ -25664,8 +25919,8 @@ async function mergePullResult(opts) {
|
|
|
25664
25919
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
25665
25920
|
continue;
|
|
25666
25921
|
}
|
|
25667
|
-
|
|
25668
|
-
|
|
25922
|
+
mkdirSync17(dirname24(path), { recursive: true });
|
|
25923
|
+
writeFileSync18(path, body);
|
|
25669
25924
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
25670
25925
|
report.written.push({ artifactId: a.id, path });
|
|
25671
25926
|
} catch (err) {
|
|
@@ -25686,7 +25941,7 @@ async function mergePullResult(opts) {
|
|
|
25686
25941
|
if (!path)
|
|
25687
25942
|
continue;
|
|
25688
25943
|
try {
|
|
25689
|
-
if (
|
|
25944
|
+
if (existsSync52(path))
|
|
25690
25945
|
rmSync7(path, { force: true });
|
|
25691
25946
|
await teamInstallsForget(id, row.tool);
|
|
25692
25947
|
report.removed.push({ artifactId: id, path });
|
|
@@ -25704,7 +25959,7 @@ async function mergePullResult(opts) {
|
|
|
25704
25959
|
}
|
|
25705
25960
|
function readFileIfExists(path) {
|
|
25706
25961
|
try {
|
|
25707
|
-
if (!
|
|
25962
|
+
if (!existsSync52(path))
|
|
25708
25963
|
return null;
|
|
25709
25964
|
const s = statSync44(path);
|
|
25710
25965
|
if (!s.isFile())
|
|
@@ -25791,7 +26046,7 @@ var init_vault_crypto = __esm({
|
|
|
25791
26046
|
});
|
|
25792
26047
|
|
|
25793
26048
|
// ../engine/dist/core/vault-source.js
|
|
25794
|
-
import { existsSync as
|
|
26049
|
+
import { existsSync as existsSync53, readdirSync as readdirSync34, statSync as statSync45 } from "fs";
|
|
25795
26050
|
import { extname, join as join57 } from "path";
|
|
25796
26051
|
function* walkVaultSources() {
|
|
25797
26052
|
const t = loadSettings().team.vault;
|
|
@@ -25819,7 +26074,7 @@ function safeStat(path) {
|
|
|
25819
26074
|
}
|
|
25820
26075
|
function* walkClaude() {
|
|
25821
26076
|
const root = claudeBackend.projectsDir();
|
|
25822
|
-
if (!
|
|
26077
|
+
if (!existsSync53(root))
|
|
25823
26078
|
return;
|
|
25824
26079
|
let projectDirs = [];
|
|
25825
26080
|
try {
|
|
@@ -25852,7 +26107,7 @@ function* walkClaude() {
|
|
|
25852
26107
|
}
|
|
25853
26108
|
function* walkGemini() {
|
|
25854
26109
|
const tmp = geminiBackend.tmpDir();
|
|
25855
|
-
if (!
|
|
26110
|
+
if (!existsSync53(tmp))
|
|
25856
26111
|
return;
|
|
25857
26112
|
let hashDirs = [];
|
|
25858
26113
|
try {
|
|
@@ -25862,7 +26117,7 @@ function* walkGemini() {
|
|
|
25862
26117
|
}
|
|
25863
26118
|
for (const hash of hashDirs) {
|
|
25864
26119
|
const chatsDir = join57(tmp, hash, "chats");
|
|
25865
|
-
if (!
|
|
26120
|
+
if (!existsSync53(chatsDir))
|
|
25866
26121
|
continue;
|
|
25867
26122
|
let entries = [];
|
|
25868
26123
|
try {
|
|
@@ -25905,7 +26160,7 @@ function* walkCursor() {
|
|
|
25905
26160
|
}
|
|
25906
26161
|
function* walkCodex() {
|
|
25907
26162
|
const sessionsRoot = join57(codexBackend.homeDir(), "sessions");
|
|
25908
|
-
if (!
|
|
26163
|
+
if (!existsSync53(sessionsRoot))
|
|
25909
26164
|
return;
|
|
25910
26165
|
const stack = [sessionsRoot];
|
|
25911
26166
|
while (stack.length) {
|
|
@@ -25934,7 +26189,7 @@ function* walkCodex() {
|
|
|
25934
26189
|
}
|
|
25935
26190
|
function* walkAgy() {
|
|
25936
26191
|
const brainDir = join57(agyBackend.homeDir(), "brain");
|
|
25937
|
-
if (!
|
|
26192
|
+
if (!existsSync53(brainDir))
|
|
25938
26193
|
return;
|
|
25939
26194
|
let sessionDirs = [];
|
|
25940
26195
|
try {
|
|
@@ -25951,10 +26206,10 @@ function* walkAgy() {
|
|
|
25951
26206
|
continue;
|
|
25952
26207
|
}
|
|
25953
26208
|
let filePath = join57(sessionPath, ".system_generated", "logs", "transcript.jsonl");
|
|
25954
|
-
if (!
|
|
26209
|
+
if (!existsSync53(filePath)) {
|
|
25955
26210
|
filePath = join57(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
|
|
25956
26211
|
}
|
|
25957
|
-
if (!
|
|
26212
|
+
if (!existsSync53(filePath))
|
|
25958
26213
|
continue;
|
|
25959
26214
|
const s = safeStat(filePath);
|
|
25960
26215
|
if (!s)
|
|
@@ -25991,8 +26246,8 @@ __export(vault_client_exports, {
|
|
|
25991
26246
|
vaultStatus: () => vaultStatus,
|
|
25992
26247
|
vaultSync: () => vaultSync
|
|
25993
26248
|
});
|
|
25994
|
-
import { mkdirSync as
|
|
25995
|
-
import { dirname as
|
|
26249
|
+
import { mkdirSync as mkdirSync18, readFileSync as readFileSync47, writeFileSync as writeFileSync19, existsSync as existsSync54 } from "fs";
|
|
26250
|
+
import { dirname as dirname25, join as join58 } from "path";
|
|
25996
26251
|
function context2() {
|
|
25997
26252
|
const s = loadSettings().team;
|
|
25998
26253
|
if (!s.enabled)
|
|
@@ -26204,7 +26459,7 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
26204
26459
|
}
|
|
26205
26460
|
try {
|
|
26206
26461
|
const path = importedPathFor(blob.tool, blob.sessionId);
|
|
26207
|
-
if (
|
|
26462
|
+
if (existsSync54(path)) {
|
|
26208
26463
|
const localStat = await import("fs").then((m) => m.statSync(path));
|
|
26209
26464
|
if (Math.abs(localStat.mtimeMs - blob.mtimeSourceMs) < 1) {
|
|
26210
26465
|
report.skipped.push({ sessionId: blob.sessionId, tool: blob.tool, reason: "unchanged" });
|
|
@@ -26220,8 +26475,8 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
26220
26475
|
throw new Error("cipher integrity check failed");
|
|
26221
26476
|
}
|
|
26222
26477
|
const plaintext = decryptBlob(key2, cipher);
|
|
26223
|
-
|
|
26224
|
-
|
|
26478
|
+
mkdirSync18(dirname25(path), { recursive: true });
|
|
26479
|
+
writeFileSync19(path, Buffer.from(plaintext));
|
|
26225
26480
|
const { utimesSync } = await import("fs");
|
|
26226
26481
|
const t = blob.mtimeSourceMs / 1e3;
|
|
26227
26482
|
utimesSync(path, t, t);
|
|
@@ -26426,7 +26681,7 @@ __export(service_installer_exports, {
|
|
|
26426
26681
|
uninstallService: () => uninstallService
|
|
26427
26682
|
});
|
|
26428
26683
|
import { execSync as execSync5 } from "child_process";
|
|
26429
|
-
import { existsSync as
|
|
26684
|
+
import { existsSync as existsSync55, mkdirSync as mkdirSync19, rmSync as rmSync8, writeFileSync as writeFileSync20 } from "fs";
|
|
26430
26685
|
import { homedir as homedir21 } from "os";
|
|
26431
26686
|
import { join as join59 } from "path";
|
|
26432
26687
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -26459,7 +26714,7 @@ function isServiceRunning() {
|
|
|
26459
26714
|
}
|
|
26460
26715
|
function installService() {
|
|
26461
26716
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
26462
|
-
|
|
26717
|
+
mkdirSync19(dataDir, { recursive: true });
|
|
26463
26718
|
if (process.platform === "linux") {
|
|
26464
26719
|
return installSystemd(watchJs, node, logFile);
|
|
26465
26720
|
}
|
|
@@ -26478,8 +26733,8 @@ function installSystemd(watchJs, node, logFile) {
|
|
|
26478
26733
|
const unitDir = join59(homedir21(), ".config", "systemd", "user");
|
|
26479
26734
|
const unitPath = join59(unitDir, "chat-recall-watch.service");
|
|
26480
26735
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
26481
|
-
|
|
26482
|
-
|
|
26736
|
+
mkdirSync19(unitDir, { recursive: true });
|
|
26737
|
+
writeFileSync20(unitPath, unit);
|
|
26483
26738
|
try {
|
|
26484
26739
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
26485
26740
|
try {
|
|
@@ -26526,8 +26781,8 @@ function installLaunchd(watchJs, node, logFile) {
|
|
|
26526
26781
|
const plistDir = join59(homedir21(), "Library", "LaunchAgents");
|
|
26527
26782
|
const plistPath = join59(plistDir, `${label}.plist`);
|
|
26528
26783
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
26529
|
-
|
|
26530
|
-
|
|
26784
|
+
mkdirSync19(plistDir, { recursive: true });
|
|
26785
|
+
writeFileSync20(plistPath, plist);
|
|
26531
26786
|
try {
|
|
26532
26787
|
try {
|
|
26533
26788
|
execSync5(`launchctl unload "${plistPath}"`, { stdio: "ignore" });
|
|
@@ -26581,7 +26836,7 @@ function uninstallService() {
|
|
|
26581
26836
|
} catch {
|
|
26582
26837
|
}
|
|
26583
26838
|
const unitPath = join59(homedir21(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
26584
|
-
if (
|
|
26839
|
+
if (existsSync55(unitPath)) {
|
|
26585
26840
|
rmSync8(unitPath, { force: true });
|
|
26586
26841
|
removed = true;
|
|
26587
26842
|
}
|
|
@@ -26598,7 +26853,7 @@ function uninstallService() {
|
|
|
26598
26853
|
} catch {
|
|
26599
26854
|
}
|
|
26600
26855
|
let removed = false;
|
|
26601
|
-
if (
|
|
26856
|
+
if (existsSync55(plistPath)) {
|
|
26602
26857
|
rmSync8(plistPath, { force: true });
|
|
26603
26858
|
removed = true;
|
|
26604
26859
|
}
|
|
@@ -26815,9 +27070,9 @@ init_project_resolver();
|
|
|
26815
27070
|
import { config } from "dotenv";
|
|
26816
27071
|
import { Command } from "commander";
|
|
26817
27072
|
import chalk from "chalk";
|
|
26818
|
-
import { existsSync as
|
|
27073
|
+
import { existsSync as existsSync56, readFileSync as readFileSync48, writeFileSync as writeFileSync21, realpathSync as realpathSync5 } from "fs";
|
|
26819
27074
|
import { homedir as homedir22 } from "os";
|
|
26820
|
-
import { join as join60, resolve as resolve2, dirname as
|
|
27075
|
+
import { join as join60, resolve as resolve2, dirname as dirname26, basename as basename28 } from "path";
|
|
26821
27076
|
|
|
26822
27077
|
// ../engine/dist/core/score-tier.js
|
|
26823
27078
|
var STRONG_RATIO = 0.85;
|
|
@@ -26864,7 +27119,7 @@ function claudeHookConfigFiles() {
|
|
|
26864
27119
|
const out = [];
|
|
26865
27120
|
const seen = /* @__PURE__ */ new Set();
|
|
26866
27121
|
for (const home of claudeHomeDirs()) {
|
|
26867
|
-
if (!
|
|
27122
|
+
if (!existsSync56(join60(home, "projects"))) continue;
|
|
26868
27123
|
const file = join60(home, "hooks.json");
|
|
26869
27124
|
let key2;
|
|
26870
27125
|
try {
|
|
@@ -27002,7 +27257,9 @@ var DEFAULT_ALLOW = [
|
|
|
27002
27257
|
"recall_code_findings",
|
|
27003
27258
|
"recall_code_actions",
|
|
27004
27259
|
"recall_claude_suggestions",
|
|
27005
|
-
"recall_improvements"
|
|
27260
|
+
"recall_improvements",
|
|
27261
|
+
"recall_toolkit_status",
|
|
27262
|
+
"recall_toolkit_sync"
|
|
27006
27263
|
];
|
|
27007
27264
|
var SELF_HOST_DOCS = "https://github.com/munhq/chat-recall/blob/main/docs/SELF_HOSTING.md";
|
|
27008
27265
|
var program = new Command();
|
|
@@ -27554,7 +27811,7 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
|
|
|
27554
27811
|
try {
|
|
27555
27812
|
const identityFile = getIdentityFilePath();
|
|
27556
27813
|
let identity = "AI coding assistant";
|
|
27557
|
-
if (
|
|
27814
|
+
if (existsSync56(identityFile)) {
|
|
27558
27815
|
identity = readFileSync48(identityFile, "utf-8").trim();
|
|
27559
27816
|
}
|
|
27560
27817
|
const lines = [
|
|
@@ -27612,7 +27869,7 @@ program.command("escalate [sessionId]").description("Escalate a finished session
|
|
|
27612
27869
|
}
|
|
27613
27870
|
});
|
|
27614
27871
|
program.command("doctor").description("Quick health check across login, server, credentials, hooks, MCP server, and codeindex").option("--purge-local", "Remove the legacy local index (cache.db + vector/KG files) left by pre-thin-collector versions \u2014 storage is server-side now. Requires login; keeps credentials, sync ledger, identity, and the audit log.").action(async (opts) => {
|
|
27615
|
-
const { existsSync:
|
|
27872
|
+
const { existsSync: existsSync57, readFileSync: readFileSync49, statSync: statSync46 } = await import("fs");
|
|
27616
27873
|
const { execSync: execSync6 } = await import("child_process");
|
|
27617
27874
|
const rows = [];
|
|
27618
27875
|
const note = (ok, label, detail) => rows.push({ ok, label, detail });
|
|
@@ -27676,7 +27933,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27676
27933
|
}
|
|
27677
27934
|
}
|
|
27678
27935
|
const credFile = join60(getDataDir(), "credentials.json");
|
|
27679
|
-
if (!
|
|
27936
|
+
if (!existsSync57(credFile)) {
|
|
27680
27937
|
note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
|
|
27681
27938
|
} else {
|
|
27682
27939
|
try {
|
|
@@ -27689,15 +27946,15 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27689
27946
|
}
|
|
27690
27947
|
}
|
|
27691
27948
|
for (const hooksJson of claudeHookConfigFiles()) {
|
|
27692
|
-
const profile = basename28(
|
|
27949
|
+
const profile = basename28(dirname26(hooksJson));
|
|
27693
27950
|
const label = `Claude hooks (${profile})`;
|
|
27694
|
-
if (!
|
|
27951
|
+
if (!existsSync57(hooksJson)) {
|
|
27695
27952
|
note(false, label, `no ${hooksJson} \u2014 run \`chat-recall install-hooks\``);
|
|
27696
27953
|
continue;
|
|
27697
27954
|
}
|
|
27698
27955
|
try {
|
|
27699
27956
|
const readHooks = (file) => {
|
|
27700
|
-
if (!
|
|
27957
|
+
if (!existsSync57(file)) return {};
|
|
27701
27958
|
try {
|
|
27702
27959
|
return JSON.parse(readFileSync49(file, "utf-8")).hooks || {};
|
|
27703
27960
|
} catch {
|
|
@@ -27705,7 +27962,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27705
27962
|
}
|
|
27706
27963
|
};
|
|
27707
27964
|
const cfg = readHooks(hooksJson);
|
|
27708
|
-
const settings2 = readHooks(join60(
|
|
27965
|
+
const settings2 = readHooks(join60(dirname26(hooksJson), "settings.json"));
|
|
27709
27966
|
const all = ["SessionStart", "UserPromptSubmit", "Stop", "PreCompact", "SessionEnd"];
|
|
27710
27967
|
const hits = [];
|
|
27711
27968
|
for (const ev of all) {
|
|
@@ -27729,7 +27986,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27729
27986
|
const want = bundledSkillNames2().length;
|
|
27730
27987
|
for (const t of skillTargets2()) {
|
|
27731
27988
|
if (!t.available) continue;
|
|
27732
|
-
const have = want === 0 ? 0 : bundledSkillNames2().filter((n) =>
|
|
27989
|
+
const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync57(join60(t.dir, n, ".chat-recall-managed"))).length;
|
|
27733
27990
|
note(
|
|
27734
27991
|
have === want,
|
|
27735
27992
|
`Skills \u2014 ${t.label}`,
|
|
@@ -27811,7 +28068,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27811
28068
|
join60(dataDir, "index", "knowledge_graph.db"),
|
|
27812
28069
|
join60(dataDir, "index", "metadata.db")
|
|
27813
28070
|
];
|
|
27814
|
-
const legacyPresent = legacyPaths.filter((p) =>
|
|
28071
|
+
const legacyPresent = legacyPaths.filter((p) => existsSync57(p));
|
|
27815
28072
|
if (opts.purgeLocal) {
|
|
27816
28073
|
if (!target) {
|
|
27817
28074
|
note(false, "Purge legacy index", "refused \u2014 log in and `chat-recall sync` first, so your history is on the server before removing local copies");
|
|
@@ -28457,10 +28714,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
28457
28714
|
try {
|
|
28458
28715
|
const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
|
|
28459
28716
|
const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
28460
|
-
const { writeFileSync:
|
|
28717
|
+
const { writeFileSync: writeFileSync22, readFileSync: readFileSync49, existsSync: existsSync57 } = await import("node:fs");
|
|
28461
28718
|
const { join: join61 } = await import("node:path");
|
|
28462
28719
|
const file = join61(cwd, "TEAM_TASKS.md");
|
|
28463
|
-
if (!opts.force &&
|
|
28720
|
+
if (!opts.force && existsSync57(file) && parseTeamTasksFile2(readFileSync49(file, "utf8")).length > 0) {
|
|
28464
28721
|
console.error(chalk.red("TEAM_TASKS.md has unpushed edits."), "Run", chalk.bold("chat-recall tasks push"), "first, or", chalk.bold("tasks pull --force"), "to discard.");
|
|
28465
28722
|
process.exit(1);
|
|
28466
28723
|
}
|
|
@@ -28468,7 +28725,7 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
28468
28725
|
const pid = resolved && resolved.source !== "ignored" ? resolved.id : "";
|
|
28469
28726
|
const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
|
|
28470
28727
|
const mine = tasks2.filter((t) => !pid || !t.projectId || t.projectId === pid);
|
|
28471
|
-
|
|
28728
|
+
writeFileSync22(file, renderTeamTasksMd2(mine));
|
|
28472
28729
|
console.log(chalk.green("\u2713 wrote"), "TEAM_TASKS.md", chalk.gray(`(${mine.length} task(s))`), "\u2014 edit, then", chalk.bold("chat-recall tasks push"));
|
|
28473
28730
|
} catch (e) {
|
|
28474
28731
|
console.error(chalk.red(e instanceof Error ? e.message : String(e)));
|
|
@@ -28479,10 +28736,10 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
|
|
|
28479
28736
|
const cwd = dir || process.cwd();
|
|
28480
28737
|
try {
|
|
28481
28738
|
const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
28482
|
-
const { readFileSync: readFileSync49, existsSync:
|
|
28739
|
+
const { readFileSync: readFileSync49, existsSync: existsSync57 } = await import("node:fs");
|
|
28483
28740
|
const { join: join61 } = await import("node:path");
|
|
28484
28741
|
const file = join61(cwd, "TEAM_TASKS.md");
|
|
28485
|
-
if (!
|
|
28742
|
+
if (!existsSync57(file)) {
|
|
28486
28743
|
console.error(chalk.red("no TEAM_TASKS.md here \u2014"), "run", chalk.bold("chat-recall tasks pull"), "first");
|
|
28487
28744
|
process.exit(1);
|
|
28488
28745
|
}
|
|
@@ -28780,7 +29037,7 @@ vault.command("forget").description("Remove the stored passphrase from this mach
|
|
|
28780
29037
|
console.log(keyringDelete2() ? chalk.green("\u2713 Passphrase removed from the OS keyring.") : chalk.dim("Nothing stored in the OS keyring."));
|
|
28781
29038
|
}));
|
|
28782
29039
|
program.command("install-hooks").description("Install Claude Code hooks (Stop + PreCompact + UserPromptSubmit + SessionEnd + SessionStart) into every Claude profile").option("--uninstall", "Remove hooks instead of installing them").option("--no-resume-hint", "Don't install the UserPromptSubmit resume-hint hook").option("--no-escalate", "Don't install the SessionEnd learnings-escalation hook").option("--no-wakeup", "Don't install the SessionStart wake-up hook").action(async (opts) => {
|
|
28783
|
-
const { mkdirSync:
|
|
29040
|
+
const { mkdirSync: mkdirSync20, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync57, readFileSync: readFileSync49, writeFileSync: writeFileSync22, statSync: statSync46 } = await import("fs");
|
|
28784
29041
|
const { fileURLToPath: fileURLToPath5 } = await import("url");
|
|
28785
29042
|
const here = fileURLToPath5(new URL(".", import.meta.url));
|
|
28786
29043
|
const findHook = (name) => {
|
|
@@ -28788,7 +29045,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28788
29045
|
join60(here, "..", "hooks", name),
|
|
28789
29046
|
join60(here, "..", "..", "hooks", name)
|
|
28790
29047
|
];
|
|
28791
|
-
return candidates2.find((p) =>
|
|
29048
|
+
return candidates2.find((p) => existsSync57(p));
|
|
28792
29049
|
};
|
|
28793
29050
|
const sourceSaveHook = findHook("chat_recall_save_hook.sh");
|
|
28794
29051
|
const sourceResumeHook = findHook("chat_recall_resume_hook.sh");
|
|
@@ -28805,7 +29062,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28805
29062
|
const installedWakeupHook = join60(hooksDir, "chat_recall_wakeup_hook.sh");
|
|
28806
29063
|
const wakeupWiredInSettings = (home) => {
|
|
28807
29064
|
const settings2 = join60(home, "settings.json");
|
|
28808
|
-
if (!
|
|
29065
|
+
if (!existsSync57(settings2)) return false;
|
|
28809
29066
|
try {
|
|
28810
29067
|
const cfg = JSON.parse(readFileSync49(settings2, "utf-8"));
|
|
28811
29068
|
const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
|
|
@@ -28816,7 +29073,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28816
29073
|
};
|
|
28817
29074
|
const hookConfigFiles = claudeHookConfigFiles();
|
|
28818
29075
|
const readHookConfig = (file) => {
|
|
28819
|
-
if (!
|
|
29076
|
+
if (!existsSync57(file)) return { hooks: {} };
|
|
28820
29077
|
try {
|
|
28821
29078
|
const c = JSON.parse(readFileSync49(file, "utf-8"));
|
|
28822
29079
|
if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
|
|
@@ -28844,8 +29101,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28844
29101
|
if (filtered.length) config2.hooks[event] = filtered;
|
|
28845
29102
|
else delete config2.hooks[event];
|
|
28846
29103
|
}
|
|
28847
|
-
if (removed === 0 && !
|
|
28848
|
-
|
|
29104
|
+
if (removed === 0 && !existsSync57(hooksJson)) continue;
|
|
29105
|
+
writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
28849
29106
|
total += removed;
|
|
28850
29107
|
console.log(chalk.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
|
|
28851
29108
|
}
|
|
@@ -28866,7 +29123,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28866
29123
|
console.log(chalk.dim(" Under WSL, run this from inside the WSL shell and it installs normally."));
|
|
28867
29124
|
return;
|
|
28868
29125
|
}
|
|
28869
|
-
|
|
29126
|
+
mkdirSync20(hooksDir, { recursive: true });
|
|
28870
29127
|
copyFileSync4(sourceSaveHook, installedSaveHook);
|
|
28871
29128
|
chmodSync5(installedSaveHook, 493);
|
|
28872
29129
|
const installResume = opts.resumeHint !== false && !!sourceResumeHook;
|
|
@@ -28898,7 +29155,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28898
29155
|
const wakeupSkipped = [];
|
|
28899
29156
|
for (const hooksJson of hookConfigFiles) {
|
|
28900
29157
|
const config2 = readHookConfig(hooksJson);
|
|
28901
|
-
const home =
|
|
29158
|
+
const home = dirname26(hooksJson);
|
|
28902
29159
|
const alreadyWired = wakeupWiredInSettings(home);
|
|
28903
29160
|
if (alreadyWired) wakeupSkipped.push(join60(home, "settings.json"));
|
|
28904
29161
|
const perProfile = installWakeup && !alreadyWired ? [...events, ["SessionStart", wakeupEntry]] : events;
|
|
@@ -28910,8 +29167,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28910
29167
|
if (without.length) config2.hooks[event] = without;
|
|
28911
29168
|
else delete config2.hooks[event];
|
|
28912
29169
|
}
|
|
28913
|
-
|
|
28914
|
-
|
|
29170
|
+
mkdirSync20(dirname26(hooksJson), { recursive: true });
|
|
29171
|
+
writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
28915
29172
|
}
|
|
28916
29173
|
const saveSz = statSync46(installedSaveHook).size;
|
|
28917
29174
|
console.log(chalk.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
|
|
@@ -28956,7 +29213,7 @@ program.command("dossier <project>").description("Generate a project dossier (ov
|
|
|
28956
29213
|
);
|
|
28957
29214
|
const md = dossier.markdown;
|
|
28958
29215
|
if (options.out) {
|
|
28959
|
-
|
|
29216
|
+
writeFileSync21(options.out, md);
|
|
28960
29217
|
console.log(chalk.green(`Wrote dossier to ${options.out} (${md.length} chars)`));
|
|
28961
29218
|
} else {
|
|
28962
29219
|
console.log(md);
|