chat-recall 0.5.7 → 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 +412 -111
- 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 +272 -18
- 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 +2501 -2032
- 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;
|
|
@@ -18264,18 +18314,27 @@ function reconstructionSpec(cfg) {
|
|
|
18264
18314
|
type: cfg.type || (cfg.url ? "remote" : "local"),
|
|
18265
18315
|
enabled: cfg.enabled !== false
|
|
18266
18316
|
};
|
|
18317
|
+
let hidSecret = false;
|
|
18318
|
+
const clean = (v) => {
|
|
18319
|
+
const r = redactInlineSecrets(v);
|
|
18320
|
+
if (r.redacted)
|
|
18321
|
+
hidSecret = true;
|
|
18322
|
+
return r.text;
|
|
18323
|
+
};
|
|
18267
18324
|
if (typeof cfg.url === "string" && cfg.url)
|
|
18268
|
-
out.url = cfg.url;
|
|
18325
|
+
out.url = clean(cfg.url);
|
|
18269
18326
|
if (Array.isArray(cfg.command))
|
|
18270
|
-
out.command = cfg.command;
|
|
18327
|
+
out.command = cfg.command.map(clean);
|
|
18271
18328
|
else if (typeof cfg.command === "string")
|
|
18272
|
-
out.command = cfg.command;
|
|
18329
|
+
out.command = clean(cfg.command);
|
|
18273
18330
|
if (Array.isArray(cfg.args))
|
|
18274
|
-
out.args = cfg.args;
|
|
18331
|
+
out.args = cfg.args.map((a) => clean(String(a)));
|
|
18275
18332
|
if (Array.isArray(cfg.alwaysAllow))
|
|
18276
18333
|
out.alwaysAllow = cfg.alwaysAllow;
|
|
18277
18334
|
if (cfg.env && typeof cfg.env === "object")
|
|
18278
18335
|
out.envKeys = Object.keys(cfg.env).sort();
|
|
18336
|
+
if (hidSecret)
|
|
18337
|
+
out.secretsRedacted = true;
|
|
18279
18338
|
return out;
|
|
18280
18339
|
}
|
|
18281
18340
|
var McpsSource;
|
|
@@ -18286,6 +18345,7 @@ var init_mcps_source = __esm({
|
|
|
18286
18345
|
init_codex2();
|
|
18287
18346
|
init_settings();
|
|
18288
18347
|
init_tool_paths();
|
|
18348
|
+
init_redact_inline();
|
|
18289
18349
|
McpsSource = class {
|
|
18290
18350
|
sourceType = "mcp";
|
|
18291
18351
|
async *discover() {
|
|
@@ -18358,7 +18418,7 @@ var init_mcps_source = __esm({
|
|
|
18358
18418
|
}
|
|
18359
18419
|
for (const [name, cfgRaw] of Object.entries(obj)) {
|
|
18360
18420
|
const cfg = cfgRaw || {};
|
|
18361
|
-
const cmd = commandPreview(cfg);
|
|
18421
|
+
const cmd = redactInlineSecrets(commandPreview(cfg)).text;
|
|
18362
18422
|
const allow = Array.isArray(cfg.alwaysAllow) ? cfg.alwaysAllow.slice(0, 8) : [];
|
|
18363
18423
|
const spec = reconstructionSpec(cfg);
|
|
18364
18424
|
yield {
|
|
@@ -18564,6 +18624,19 @@ var init_toolkit_format = __esm({
|
|
|
18564
18624
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
18565
18625
|
import { existsSync as existsSync37, readdirSync as readdirSync28, readFileSync as readFileSync27, statSync as statSync33 } from "fs";
|
|
18566
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
|
+
}
|
|
18567
18640
|
function parseCommand(content, fallbackName, format) {
|
|
18568
18641
|
if (format === "toml") {
|
|
18569
18642
|
const t = parseScalarToml(content);
|
|
@@ -18580,7 +18653,7 @@ function parseCommand(content, fallbackName, format) {
|
|
|
18580
18653
|
body: body.trim()
|
|
18581
18654
|
};
|
|
18582
18655
|
}
|
|
18583
|
-
var MAX_CHUNK_CHARS13, SlashCommandsSource;
|
|
18656
|
+
var MAX_CHUNK_CHARS13, MAX_BODY_CHARS2, SlashCommandsSource;
|
|
18584
18657
|
var init_slash_commands_source = __esm({
|
|
18585
18658
|
"../engine/dist/parsers/slash-commands-source.js"() {
|
|
18586
18659
|
"use strict";
|
|
@@ -18592,7 +18665,9 @@ var init_slash_commands_source = __esm({
|
|
|
18592
18665
|
init_tool_paths();
|
|
18593
18666
|
init_toolkit_format();
|
|
18594
18667
|
init_project_dir_name();
|
|
18668
|
+
init_redact_inline();
|
|
18595
18669
|
MAX_CHUNK_CHARS13 = 2e3;
|
|
18670
|
+
MAX_BODY_CHARS2 = 512 * 1024;
|
|
18596
18671
|
SlashCommandsSource = class {
|
|
18597
18672
|
sourceType = "command";
|
|
18598
18673
|
roots() {
|
|
@@ -18656,7 +18731,10 @@ var init_slash_commands_source = __esm({
|
|
|
18656
18731
|
commandName: parsed.name,
|
|
18657
18732
|
description: parsed.description,
|
|
18658
18733
|
scope: root.scope,
|
|
18659
|
-
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)
|
|
18660
18738
|
}
|
|
18661
18739
|
};
|
|
18662
18740
|
} catch {
|
|
@@ -18692,6 +18770,19 @@ var init_slash_commands_source = __esm({
|
|
|
18692
18770
|
// ../engine/dist/parsers/subagents-source.js
|
|
18693
18771
|
import { existsSync as existsSync38, readdirSync as readdirSync29, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
|
|
18694
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
|
+
}
|
|
18695
18786
|
function parseAgent(content, fallbackName, format) {
|
|
18696
18787
|
if (format === "toml") {
|
|
18697
18788
|
const t = parseScalarToml(content);
|
|
@@ -18710,7 +18801,7 @@ function parseAgent(content, fallbackName, format) {
|
|
|
18710
18801
|
body: body.trim()
|
|
18711
18802
|
};
|
|
18712
18803
|
}
|
|
18713
|
-
var MAX_CHUNK_CHARS14, SubagentsSource;
|
|
18804
|
+
var MAX_CHUNK_CHARS14, MAX_BODY_CHARS3, SubagentsSource;
|
|
18714
18805
|
var init_subagents_source = __esm({
|
|
18715
18806
|
"../engine/dist/parsers/subagents-source.js"() {
|
|
18716
18807
|
"use strict";
|
|
@@ -18722,7 +18813,9 @@ var init_subagents_source = __esm({
|
|
|
18722
18813
|
init_tool_paths();
|
|
18723
18814
|
init_toolkit_format();
|
|
18724
18815
|
init_project_dir_name();
|
|
18816
|
+
init_redact_inline();
|
|
18725
18817
|
MAX_CHUNK_CHARS14 = 2e3;
|
|
18818
|
+
MAX_BODY_CHARS3 = 512 * 1024;
|
|
18726
18819
|
SubagentsSource = class {
|
|
18727
18820
|
sourceType = "agent";
|
|
18728
18821
|
roots() {
|
|
@@ -18787,7 +18880,10 @@ var init_subagents_source = __esm({
|
|
|
18787
18880
|
description: parsed.description,
|
|
18788
18881
|
tools: parsed.tools,
|
|
18789
18882
|
scope: root.scope,
|
|
18790
|
-
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)
|
|
18791
18887
|
}
|
|
18792
18888
|
};
|
|
18793
18889
|
} catch {
|
|
@@ -19176,6 +19272,9 @@ var init_all_sources = __esm({
|
|
|
19176
19272
|
});
|
|
19177
19273
|
|
|
19178
19274
|
// ../engine/dist/core/extractor-version.js
|
|
19275
|
+
function extractorVersionForItem(id, sourceType) {
|
|
19276
|
+
return extractorVersionForTool(toolOfId(id)) + (ITEM_SOURCE_BUMP[sourceType] ?? 0);
|
|
19277
|
+
}
|
|
19179
19278
|
function toolOfId(id) {
|
|
19180
19279
|
if (id.startsWith("agy_"))
|
|
19181
19280
|
return "agy";
|
|
@@ -19195,11 +19294,17 @@ function extractorVersionForTool(tool) {
|
|
|
19195
19294
|
function extractorVersionForId(id) {
|
|
19196
19295
|
return extractorVersionForTool(toolOfId(id));
|
|
19197
19296
|
}
|
|
19198
|
-
var BASE_EXTRACTOR_VERSION, TOOL_EXTRACTOR_BUMP, EXTRACTOR_VERSION;
|
|
19297
|
+
var BASE_EXTRACTOR_VERSION, ITEM_SOURCE_BUMP, TOOL_EXTRACTOR_BUMP, EXTRACTOR_VERSION;
|
|
19199
19298
|
var init_extractor_version = __esm({
|
|
19200
19299
|
"../engine/dist/core/extractor-version.js"() {
|
|
19201
19300
|
"use strict";
|
|
19202
19301
|
BASE_EXTRACTOR_VERSION = 2;
|
|
19302
|
+
ITEM_SOURCE_BUMP = {
|
|
19303
|
+
mcp: 1,
|
|
19304
|
+
skill: 1,
|
|
19305
|
+
agent: 1,
|
|
19306
|
+
command: 1
|
|
19307
|
+
};
|
|
19203
19308
|
TOOL_EXTRACTOR_BUMP = {
|
|
19204
19309
|
agy: 2,
|
|
19205
19310
|
claude: 1,
|
|
@@ -19589,7 +19694,7 @@ var init_http = __esm({
|
|
|
19589
19694
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19590
19695
|
} catch {
|
|
19591
19696
|
try {
|
|
19592
|
-
if (true) CLI_VERSION = "0.5.
|
|
19697
|
+
if (true) CLI_VERSION = "0.5.9";
|
|
19593
19698
|
} catch {
|
|
19594
19699
|
}
|
|
19595
19700
|
}
|
|
@@ -20101,7 +20206,7 @@ var init_telemetry = __esm({
|
|
|
20101
20206
|
init_sync_client();
|
|
20102
20207
|
cliVersion2 = () => {
|
|
20103
20208
|
try {
|
|
20104
|
-
return true ? "0.5.
|
|
20209
|
+
return true ? "0.5.9" : "dev";
|
|
20105
20210
|
} catch {
|
|
20106
20211
|
return "dev";
|
|
20107
20212
|
}
|
|
@@ -21333,6 +21438,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21333
21438
|
}
|
|
21334
21439
|
const itemVersions = loadItemVersions(base2);
|
|
21335
21440
|
const seenTools = /* @__PURE__ */ new Set();
|
|
21441
|
+
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
21336
21442
|
const registry = buildSourceRegistry();
|
|
21337
21443
|
for (const sourceType of registry.getRegisteredTypes()) {
|
|
21338
21444
|
if (sourceType === "session") continue;
|
|
@@ -21347,7 +21453,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21347
21453
|
for await (const item of discovered) {
|
|
21348
21454
|
const itemTool = toolOfId(item.id);
|
|
21349
21455
|
seenTools.add(itemTool);
|
|
21350
|
-
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);
|
|
21351
21459
|
if ((item.mtime || 0) < (opts.sinceMs ?? 0) && !versionStale) continue;
|
|
21352
21460
|
if (excluded(item.projectPath || "")) continue;
|
|
21353
21461
|
if (!includedProject(item.projectPath || "")) continue;
|
|
@@ -21430,6 +21538,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21430
21538
|
try {
|
|
21431
21539
|
const rec = {};
|
|
21432
21540
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
21541
|
+
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
21433
21542
|
saveItemVersions(base2, rec);
|
|
21434
21543
|
} catch {
|
|
21435
21544
|
}
|
|
@@ -21869,7 +21978,7 @@ var init_sync_client = __esm({
|
|
|
21869
21978
|
ownVersion = JSON.parse(readFileSync36(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21870
21979
|
} catch {
|
|
21871
21980
|
try {
|
|
21872
|
-
if (true) ownVersion = "0.5.
|
|
21981
|
+
if (true) ownVersion = "0.5.9";
|
|
21873
21982
|
} catch {
|
|
21874
21983
|
}
|
|
21875
21984
|
}
|
|
@@ -22685,27 +22794,31 @@ var init_install_skills = __esm({
|
|
|
22685
22794
|
import { readFileSync as readFileSync41 } from "fs";
|
|
22686
22795
|
import { join as join50 } from "path";
|
|
22687
22796
|
import { homedir as homedir17 } from "os";
|
|
22688
|
-
function
|
|
22689
|
-
const content = readFileSync41(filePath, "utf-8");
|
|
22797
|
+
function parseCommandText(content, format, fallbackName) {
|
|
22690
22798
|
if (format === "toml") {
|
|
22691
22799
|
const t = parseScalarToml(content);
|
|
22692
|
-
return { name: t.name ||
|
|
22800
|
+
return { name: t.name || fallbackName, description: t.description || "", body: t.prompt || "" };
|
|
22693
22801
|
}
|
|
22694
22802
|
const { fm, body } = parseFrontmatter4(content);
|
|
22695
|
-
return { name: fm.name ||
|
|
22803
|
+
return { name: fm.name || fallbackName, description: fm.description || "", body: body.trim() };
|
|
22696
22804
|
}
|
|
22697
|
-
function
|
|
22698
|
-
const content = readFileSync41(filePath, "utf-8");
|
|
22805
|
+
function parseAgentText(content, format, fallbackName) {
|
|
22699
22806
|
if (format === "toml") {
|
|
22700
22807
|
const t = parseScalarToml(content);
|
|
22701
22808
|
return {
|
|
22702
|
-
name: t.name ||
|
|
22809
|
+
name: t.name || fallbackName,
|
|
22703
22810
|
description: t.description || "",
|
|
22704
22811
|
body: t.developer_instructions || t.instructions || ""
|
|
22705
22812
|
};
|
|
22706
22813
|
}
|
|
22707
22814
|
const { fm, body } = parseFrontmatter4(content);
|
|
22708
|
-
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));
|
|
22709
22822
|
}
|
|
22710
22823
|
function readInstructions(filePath, name) {
|
|
22711
22824
|
const content = readFileSync41(filePath, "utf-8");
|
|
@@ -23298,8 +23411,8 @@ __export(toolkit_pull_exports, {
|
|
|
23298
23411
|
planPull: () => planPull,
|
|
23299
23412
|
portableCommand: () => portableCommand
|
|
23300
23413
|
});
|
|
23301
|
-
import { statSync as statSync42 } from "node:fs";
|
|
23302
|
-
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";
|
|
23303
23416
|
function isExecutableFile(p) {
|
|
23304
23417
|
try {
|
|
23305
23418
|
return statSync42(p).isFile();
|
|
@@ -23359,8 +23472,58 @@ function planPull(rows, opts = {}) {
|
|
|
23359
23472
|
const wanted = opts.types;
|
|
23360
23473
|
const seenUnsupported = /* @__PURE__ */ new Map();
|
|
23361
23474
|
const byName = /* @__PURE__ */ new Map();
|
|
23475
|
+
const skillsByName = /* @__PURE__ */ new Map();
|
|
23476
|
+
const agentsByName = /* @__PURE__ */ new Map();
|
|
23477
|
+
const commandsByName = /* @__PURE__ */ new Map();
|
|
23362
23478
|
for (const row of rows) {
|
|
23363
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
|
+
}
|
|
23364
23527
|
if (type !== "mcp") {
|
|
23365
23528
|
if (NOT_REBUILDABLE[type])
|
|
23366
23529
|
seenUnsupported.set(type, (seenUnsupported.get(type) || 0) + 1);
|
|
@@ -23382,16 +23545,93 @@ function planPull(rows, opts = {}) {
|
|
|
23382
23545
|
}
|
|
23383
23546
|
const targets = SUPPORTED_TARGETS.mcp;
|
|
23384
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
|
+
}));
|
|
23385
23555
|
const unsupported = [...seenUnsupported.entries()].map(([type, count]) => ({
|
|
23386
23556
|
type,
|
|
23387
23557
|
rows: count,
|
|
23388
|
-
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"
|
|
23389
23559
|
}));
|
|
23390
|
-
|
|
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 };
|
|
23391
23565
|
}
|
|
23392
23566
|
function executePull(rows, opts = {}) {
|
|
23393
|
-
const { mcps, unsupported } = planPull(rows, opts);
|
|
23567
|
+
const { mcps, skills, codecs, unsupported } = planPull(rows, opts);
|
|
23394
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
|
+
}
|
|
23395
23635
|
for (const { name, spec, tools } of mcps) {
|
|
23396
23636
|
const built = entryFromSpec(spec);
|
|
23397
23637
|
for (const tool of tools) {
|
|
@@ -23403,6 +23643,16 @@ function executePull(rows, opts = {}) {
|
|
|
23403
23643
|
outcomes.push({ type: "mcp", name, tool, status: "present" });
|
|
23404
23644
|
continue;
|
|
23405
23645
|
}
|
|
23646
|
+
if (spec.secretsRedacted) {
|
|
23647
|
+
outcomes.push({
|
|
23648
|
+
type: "mcp",
|
|
23649
|
+
name,
|
|
23650
|
+
tool,
|
|
23651
|
+
status: "skipped",
|
|
23652
|
+
reason: "its command contains a secret, which is never uploaded \u2014 register this one by hand"
|
|
23653
|
+
});
|
|
23654
|
+
continue;
|
|
23655
|
+
}
|
|
23406
23656
|
const entry = { ...built.entry };
|
|
23407
23657
|
let rewrittenCommand;
|
|
23408
23658
|
if (!entry.url) {
|
|
@@ -23440,11 +23690,12 @@ var init_toolkit_pull = __esm({
|
|
|
23440
23690
|
"../engine/dist/core/toolkit-pull.js"() {
|
|
23441
23691
|
"use strict";
|
|
23442
23692
|
init_toolkit_sync();
|
|
23693
|
+
init_artifact_codec();
|
|
23443
23694
|
NOT_REBUILDABLE = {
|
|
23444
|
-
|
|
23445
|
-
|
|
23446
|
-
|
|
23447
|
-
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"
|
|
23448
23699
|
};
|
|
23449
23700
|
}
|
|
23450
23701
|
});
|
|
@@ -23940,11 +24191,11 @@ var verify_repair_exports = {};
|
|
|
23940
24191
|
__export(verify_repair_exports, {
|
|
23941
24192
|
forceFullResync: () => forceFullResync
|
|
23942
24193
|
});
|
|
23943
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
24194
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync49 } from "fs";
|
|
23944
24195
|
function forceFullResync(server, sessionIds) {
|
|
23945
24196
|
if (sessionIds.length === 0) return 0;
|
|
23946
24197
|
const path = ledgerFilePath();
|
|
23947
|
-
if (
|
|
24198
|
+
if (existsSync49(path)) {
|
|
23948
24199
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
23949
24200
|
try {
|
|
23950
24201
|
copyFileSync3(path, `${path}.bak-${stamp}`);
|
|
@@ -25019,8 +25270,8 @@ __export(project_tasks_exports, {
|
|
|
25019
25270
|
pushProjectTaskStatuses: () => pushProjectTaskStatuses,
|
|
25020
25271
|
renderTeamTasksMd: () => renderTeamTasksMd
|
|
25021
25272
|
});
|
|
25022
|
-
import { existsSync as
|
|
25023
|
-
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";
|
|
25024
25275
|
import { homedir as homedir19 } from "node:os";
|
|
25025
25276
|
function isTeamTaskStatus(v) {
|
|
25026
25277
|
return !!v && TEAM_STATUSES.has(v);
|
|
@@ -25082,11 +25333,11 @@ function readLedger() {
|
|
|
25082
25333
|
}
|
|
25083
25334
|
function writeLedger(l) {
|
|
25084
25335
|
try {
|
|
25085
|
-
|
|
25336
|
+
mkdirSync15(dirname22(ledgerPath2()), { recursive: true });
|
|
25086
25337
|
} catch {
|
|
25087
25338
|
}
|
|
25088
25339
|
try {
|
|
25089
|
-
|
|
25340
|
+
writeFileSync16(ledgerPath2(), JSON.stringify(l));
|
|
25090
25341
|
} catch {
|
|
25091
25342
|
}
|
|
25092
25343
|
}
|
|
@@ -25105,7 +25356,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
25105
25356
|
}
|
|
25106
25357
|
for (const project of projects) {
|
|
25107
25358
|
const file = join54(project, fk.filename);
|
|
25108
|
-
if (!
|
|
25359
|
+
if (!existsSync50(file)) continue;
|
|
25109
25360
|
let mtime;
|
|
25110
25361
|
try {
|
|
25111
25362
|
mtime = statSync43(file).mtimeMs;
|
|
@@ -25185,18 +25436,18 @@ var intent_drain_exports = {};
|
|
|
25185
25436
|
__export(intent_drain_exports, {
|
|
25186
25437
|
drainSyncIntents: () => drainSyncIntents
|
|
25187
25438
|
});
|
|
25188
|
-
import { existsSync as
|
|
25439
|
+
import { existsSync as existsSync51, readFileSync as readFileSync45, writeFileSync as writeFileSync17, appendFileSync, mkdirSync as mkdirSync16 } from "node:fs";
|
|
25189
25440
|
import { join as join55 } from "node:path";
|
|
25190
25441
|
import { homedir as homedir20 } from "node:os";
|
|
25191
25442
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
25192
|
-
import { dirname as
|
|
25443
|
+
import { dirname as dirname23 } from "node:path";
|
|
25193
25444
|
function applyCodeRecommendation(intent) {
|
|
25194
25445
|
try {
|
|
25195
25446
|
const meta = JSON.parse(intent.name || "{}");
|
|
25196
25447
|
if (intent.artifact_type === "write_tasks_file") {
|
|
25197
25448
|
if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
|
|
25198
25449
|
const file = join55(meta.rootPath, meta.filename || "CODE_TASKS.md");
|
|
25199
|
-
|
|
25450
|
+
writeFileSync17(file, meta.content);
|
|
25200
25451
|
return { status: "done", result: JSON.stringify({ wrote: file }) };
|
|
25201
25452
|
}
|
|
25202
25453
|
if (intent.artifact_type === "append_claude_md") {
|
|
@@ -25207,7 +25458,7 @@ function applyCodeRecommendation(intent) {
|
|
|
25207
25458
|
if (isGlobal) {
|
|
25208
25459
|
const dir = join55(homedir20(), ".claude");
|
|
25209
25460
|
try {
|
|
25210
|
-
|
|
25461
|
+
mkdirSync16(dir, { recursive: true });
|
|
25211
25462
|
} catch {
|
|
25212
25463
|
}
|
|
25213
25464
|
file = join55(dir, "CLAUDE.md");
|
|
@@ -25215,14 +25466,14 @@ function applyCodeRecommendation(intent) {
|
|
|
25215
25466
|
if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
|
|
25216
25467
|
file = join55(meta.rootPath, "CLAUDE.md");
|
|
25217
25468
|
}
|
|
25218
|
-
const existing =
|
|
25469
|
+
const existing = existsSync51(file) ? readFileSync45(file, "utf8") : "";
|
|
25219
25470
|
if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
|
|
25220
25471
|
const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
|
|
25221
25472
|
## Rule (added by chat-recall recommendation)
|
|
25222
25473
|
${text}
|
|
25223
25474
|
`;
|
|
25224
25475
|
if (existing) appendFileSync(file, block);
|
|
25225
|
-
else
|
|
25476
|
+
else writeFileSync17(file, `# ${meta.rootPath?.split("/").pop() || "Global"} instructions
|
|
25226
25477
|
${block}`);
|
|
25227
25478
|
return { status: "done", result: JSON.stringify({ appended: file }) };
|
|
25228
25479
|
}
|
|
@@ -25231,6 +25482,46 @@ ${block}`);
|
|
|
25231
25482
|
return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
|
|
25232
25483
|
}
|
|
25233
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
|
+
}
|
|
25234
25525
|
async function runIntent(intent, ctx) {
|
|
25235
25526
|
try {
|
|
25236
25527
|
if (intent.kind === "recheck_session") {
|
|
@@ -25243,6 +25534,14 @@ async function runIntent(intent, ctx) {
|
|
|
25243
25534
|
if (intent.kind === "code_apply") {
|
|
25244
25535
|
return applyCodeRecommendation(intent);
|
|
25245
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
|
+
}
|
|
25246
25545
|
if (intent.kind === "sync_all") {
|
|
25247
25546
|
const report = await executeSyncAll();
|
|
25248
25547
|
const status2 = report.failed.length > 0 ? "error" : "done";
|
|
@@ -25286,7 +25585,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
25286
25585
|
if (status === "done") out.done++;
|
|
25287
25586
|
else out.errored++;
|
|
25288
25587
|
if (opts.verbose) {
|
|
25289
|
-
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}`;
|
|
25290
25589
|
console.error(`[sync-intent] ${label}: ${status}`);
|
|
25291
25590
|
}
|
|
25292
25591
|
try {
|
|
@@ -25321,11 +25620,11 @@ var init_intent_drain = __esm({
|
|
|
25321
25620
|
init_project_tasks();
|
|
25322
25621
|
ownVersion2 = "0.0.0";
|
|
25323
25622
|
try {
|
|
25324
|
-
const dir =
|
|
25623
|
+
const dir = dirname23(fileURLToPath3(import.meta.url));
|
|
25325
25624
|
ownVersion2 = JSON.parse(readFileSync45(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25326
25625
|
} catch {
|
|
25327
25626
|
try {
|
|
25328
|
-
if (true) ownVersion2 = "0.5.
|
|
25627
|
+
if (true) ownVersion2 = "0.5.9";
|
|
25329
25628
|
} catch {
|
|
25330
25629
|
}
|
|
25331
25630
|
}
|
|
@@ -25526,8 +25825,8 @@ var team_merge_exports = {};
|
|
|
25526
25825
|
__export(team_merge_exports, {
|
|
25527
25826
|
mergePullResult: () => mergePullResult
|
|
25528
25827
|
});
|
|
25529
|
-
import { existsSync as
|
|
25530
|
-
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";
|
|
25531
25830
|
import { createHash as createHash17 } from "crypto";
|
|
25532
25831
|
function installPathFor(art, tool) {
|
|
25533
25832
|
switch (art.type) {
|
|
@@ -25620,8 +25919,8 @@ async function mergePullResult(opts) {
|
|
|
25620
25919
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
25621
25920
|
continue;
|
|
25622
25921
|
}
|
|
25623
|
-
|
|
25624
|
-
|
|
25922
|
+
mkdirSync17(dirname24(path), { recursive: true });
|
|
25923
|
+
writeFileSync18(path, body);
|
|
25625
25924
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
25626
25925
|
report.written.push({ artifactId: a.id, path });
|
|
25627
25926
|
} catch (err) {
|
|
@@ -25642,7 +25941,7 @@ async function mergePullResult(opts) {
|
|
|
25642
25941
|
if (!path)
|
|
25643
25942
|
continue;
|
|
25644
25943
|
try {
|
|
25645
|
-
if (
|
|
25944
|
+
if (existsSync52(path))
|
|
25646
25945
|
rmSync7(path, { force: true });
|
|
25647
25946
|
await teamInstallsForget(id, row.tool);
|
|
25648
25947
|
report.removed.push({ artifactId: id, path });
|
|
@@ -25660,7 +25959,7 @@ async function mergePullResult(opts) {
|
|
|
25660
25959
|
}
|
|
25661
25960
|
function readFileIfExists(path) {
|
|
25662
25961
|
try {
|
|
25663
|
-
if (!
|
|
25962
|
+
if (!existsSync52(path))
|
|
25664
25963
|
return null;
|
|
25665
25964
|
const s = statSync44(path);
|
|
25666
25965
|
if (!s.isFile())
|
|
@@ -25747,7 +26046,7 @@ var init_vault_crypto = __esm({
|
|
|
25747
26046
|
});
|
|
25748
26047
|
|
|
25749
26048
|
// ../engine/dist/core/vault-source.js
|
|
25750
|
-
import { existsSync as
|
|
26049
|
+
import { existsSync as existsSync53, readdirSync as readdirSync34, statSync as statSync45 } from "fs";
|
|
25751
26050
|
import { extname, join as join57 } from "path";
|
|
25752
26051
|
function* walkVaultSources() {
|
|
25753
26052
|
const t = loadSettings().team.vault;
|
|
@@ -25775,7 +26074,7 @@ function safeStat(path) {
|
|
|
25775
26074
|
}
|
|
25776
26075
|
function* walkClaude() {
|
|
25777
26076
|
const root = claudeBackend.projectsDir();
|
|
25778
|
-
if (!
|
|
26077
|
+
if (!existsSync53(root))
|
|
25779
26078
|
return;
|
|
25780
26079
|
let projectDirs = [];
|
|
25781
26080
|
try {
|
|
@@ -25808,7 +26107,7 @@ function* walkClaude() {
|
|
|
25808
26107
|
}
|
|
25809
26108
|
function* walkGemini() {
|
|
25810
26109
|
const tmp = geminiBackend.tmpDir();
|
|
25811
|
-
if (!
|
|
26110
|
+
if (!existsSync53(tmp))
|
|
25812
26111
|
return;
|
|
25813
26112
|
let hashDirs = [];
|
|
25814
26113
|
try {
|
|
@@ -25818,7 +26117,7 @@ function* walkGemini() {
|
|
|
25818
26117
|
}
|
|
25819
26118
|
for (const hash of hashDirs) {
|
|
25820
26119
|
const chatsDir = join57(tmp, hash, "chats");
|
|
25821
|
-
if (!
|
|
26120
|
+
if (!existsSync53(chatsDir))
|
|
25822
26121
|
continue;
|
|
25823
26122
|
let entries = [];
|
|
25824
26123
|
try {
|
|
@@ -25861,7 +26160,7 @@ function* walkCursor() {
|
|
|
25861
26160
|
}
|
|
25862
26161
|
function* walkCodex() {
|
|
25863
26162
|
const sessionsRoot = join57(codexBackend.homeDir(), "sessions");
|
|
25864
|
-
if (!
|
|
26163
|
+
if (!existsSync53(sessionsRoot))
|
|
25865
26164
|
return;
|
|
25866
26165
|
const stack = [sessionsRoot];
|
|
25867
26166
|
while (stack.length) {
|
|
@@ -25890,7 +26189,7 @@ function* walkCodex() {
|
|
|
25890
26189
|
}
|
|
25891
26190
|
function* walkAgy() {
|
|
25892
26191
|
const brainDir = join57(agyBackend.homeDir(), "brain");
|
|
25893
|
-
if (!
|
|
26192
|
+
if (!existsSync53(brainDir))
|
|
25894
26193
|
return;
|
|
25895
26194
|
let sessionDirs = [];
|
|
25896
26195
|
try {
|
|
@@ -25907,10 +26206,10 @@ function* walkAgy() {
|
|
|
25907
26206
|
continue;
|
|
25908
26207
|
}
|
|
25909
26208
|
let filePath = join57(sessionPath, ".system_generated", "logs", "transcript.jsonl");
|
|
25910
|
-
if (!
|
|
26209
|
+
if (!existsSync53(filePath)) {
|
|
25911
26210
|
filePath = join57(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
|
|
25912
26211
|
}
|
|
25913
|
-
if (!
|
|
26212
|
+
if (!existsSync53(filePath))
|
|
25914
26213
|
continue;
|
|
25915
26214
|
const s = safeStat(filePath);
|
|
25916
26215
|
if (!s)
|
|
@@ -25947,8 +26246,8 @@ __export(vault_client_exports, {
|
|
|
25947
26246
|
vaultStatus: () => vaultStatus,
|
|
25948
26247
|
vaultSync: () => vaultSync
|
|
25949
26248
|
});
|
|
25950
|
-
import { mkdirSync as
|
|
25951
|
-
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";
|
|
25952
26251
|
function context2() {
|
|
25953
26252
|
const s = loadSettings().team;
|
|
25954
26253
|
if (!s.enabled)
|
|
@@ -26160,7 +26459,7 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
26160
26459
|
}
|
|
26161
26460
|
try {
|
|
26162
26461
|
const path = importedPathFor(blob.tool, blob.sessionId);
|
|
26163
|
-
if (
|
|
26462
|
+
if (existsSync54(path)) {
|
|
26164
26463
|
const localStat = await import("fs").then((m) => m.statSync(path));
|
|
26165
26464
|
if (Math.abs(localStat.mtimeMs - blob.mtimeSourceMs) < 1) {
|
|
26166
26465
|
report.skipped.push({ sessionId: blob.sessionId, tool: blob.tool, reason: "unchanged" });
|
|
@@ -26176,8 +26475,8 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
26176
26475
|
throw new Error("cipher integrity check failed");
|
|
26177
26476
|
}
|
|
26178
26477
|
const plaintext = decryptBlob(key2, cipher);
|
|
26179
|
-
|
|
26180
|
-
|
|
26478
|
+
mkdirSync18(dirname25(path), { recursive: true });
|
|
26479
|
+
writeFileSync19(path, Buffer.from(plaintext));
|
|
26181
26480
|
const { utimesSync } = await import("fs");
|
|
26182
26481
|
const t = blob.mtimeSourceMs / 1e3;
|
|
26183
26482
|
utimesSync(path, t, t);
|
|
@@ -26382,7 +26681,7 @@ __export(service_installer_exports, {
|
|
|
26382
26681
|
uninstallService: () => uninstallService
|
|
26383
26682
|
});
|
|
26384
26683
|
import { execSync as execSync5 } from "child_process";
|
|
26385
|
-
import { existsSync as
|
|
26684
|
+
import { existsSync as existsSync55, mkdirSync as mkdirSync19, rmSync as rmSync8, writeFileSync as writeFileSync20 } from "fs";
|
|
26386
26685
|
import { homedir as homedir21 } from "os";
|
|
26387
26686
|
import { join as join59 } from "path";
|
|
26388
26687
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -26415,7 +26714,7 @@ function isServiceRunning() {
|
|
|
26415
26714
|
}
|
|
26416
26715
|
function installService() {
|
|
26417
26716
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
26418
|
-
|
|
26717
|
+
mkdirSync19(dataDir, { recursive: true });
|
|
26419
26718
|
if (process.platform === "linux") {
|
|
26420
26719
|
return installSystemd(watchJs, node, logFile);
|
|
26421
26720
|
}
|
|
@@ -26434,8 +26733,8 @@ function installSystemd(watchJs, node, logFile) {
|
|
|
26434
26733
|
const unitDir = join59(homedir21(), ".config", "systemd", "user");
|
|
26435
26734
|
const unitPath = join59(unitDir, "chat-recall-watch.service");
|
|
26436
26735
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
26437
|
-
|
|
26438
|
-
|
|
26736
|
+
mkdirSync19(unitDir, { recursive: true });
|
|
26737
|
+
writeFileSync20(unitPath, unit);
|
|
26439
26738
|
try {
|
|
26440
26739
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
26441
26740
|
try {
|
|
@@ -26482,8 +26781,8 @@ function installLaunchd(watchJs, node, logFile) {
|
|
|
26482
26781
|
const plistDir = join59(homedir21(), "Library", "LaunchAgents");
|
|
26483
26782
|
const plistPath = join59(plistDir, `${label}.plist`);
|
|
26484
26783
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
26485
|
-
|
|
26486
|
-
|
|
26784
|
+
mkdirSync19(plistDir, { recursive: true });
|
|
26785
|
+
writeFileSync20(plistPath, plist);
|
|
26487
26786
|
try {
|
|
26488
26787
|
try {
|
|
26489
26788
|
execSync5(`launchctl unload "${plistPath}"`, { stdio: "ignore" });
|
|
@@ -26537,7 +26836,7 @@ function uninstallService() {
|
|
|
26537
26836
|
} catch {
|
|
26538
26837
|
}
|
|
26539
26838
|
const unitPath = join59(homedir21(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
26540
|
-
if (
|
|
26839
|
+
if (existsSync55(unitPath)) {
|
|
26541
26840
|
rmSync8(unitPath, { force: true });
|
|
26542
26841
|
removed = true;
|
|
26543
26842
|
}
|
|
@@ -26554,7 +26853,7 @@ function uninstallService() {
|
|
|
26554
26853
|
} catch {
|
|
26555
26854
|
}
|
|
26556
26855
|
let removed = false;
|
|
26557
|
-
if (
|
|
26856
|
+
if (existsSync55(plistPath)) {
|
|
26558
26857
|
rmSync8(plistPath, { force: true });
|
|
26559
26858
|
removed = true;
|
|
26560
26859
|
}
|
|
@@ -26771,9 +27070,9 @@ init_project_resolver();
|
|
|
26771
27070
|
import { config } from "dotenv";
|
|
26772
27071
|
import { Command } from "commander";
|
|
26773
27072
|
import chalk from "chalk";
|
|
26774
|
-
import { existsSync as
|
|
27073
|
+
import { existsSync as existsSync56, readFileSync as readFileSync48, writeFileSync as writeFileSync21, realpathSync as realpathSync5 } from "fs";
|
|
26775
27074
|
import { homedir as homedir22 } from "os";
|
|
26776
|
-
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";
|
|
26777
27076
|
|
|
26778
27077
|
// ../engine/dist/core/score-tier.js
|
|
26779
27078
|
var STRONG_RATIO = 0.85;
|
|
@@ -26820,7 +27119,7 @@ function claudeHookConfigFiles() {
|
|
|
26820
27119
|
const out = [];
|
|
26821
27120
|
const seen = /* @__PURE__ */ new Set();
|
|
26822
27121
|
for (const home of claudeHomeDirs()) {
|
|
26823
|
-
if (!
|
|
27122
|
+
if (!existsSync56(join60(home, "projects"))) continue;
|
|
26824
27123
|
const file = join60(home, "hooks.json");
|
|
26825
27124
|
let key2;
|
|
26826
27125
|
try {
|
|
@@ -26958,7 +27257,9 @@ var DEFAULT_ALLOW = [
|
|
|
26958
27257
|
"recall_code_findings",
|
|
26959
27258
|
"recall_code_actions",
|
|
26960
27259
|
"recall_claude_suggestions",
|
|
26961
|
-
"recall_improvements"
|
|
27260
|
+
"recall_improvements",
|
|
27261
|
+
"recall_toolkit_status",
|
|
27262
|
+
"recall_toolkit_sync"
|
|
26962
27263
|
];
|
|
26963
27264
|
var SELF_HOST_DOCS = "https://github.com/munhq/chat-recall/blob/main/docs/SELF_HOSTING.md";
|
|
26964
27265
|
var program = new Command();
|
|
@@ -27510,7 +27811,7 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
|
|
|
27510
27811
|
try {
|
|
27511
27812
|
const identityFile = getIdentityFilePath();
|
|
27512
27813
|
let identity = "AI coding assistant";
|
|
27513
|
-
if (
|
|
27814
|
+
if (existsSync56(identityFile)) {
|
|
27514
27815
|
identity = readFileSync48(identityFile, "utf-8").trim();
|
|
27515
27816
|
}
|
|
27516
27817
|
const lines = [
|
|
@@ -27568,7 +27869,7 @@ program.command("escalate [sessionId]").description("Escalate a finished session
|
|
|
27568
27869
|
}
|
|
27569
27870
|
});
|
|
27570
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) => {
|
|
27571
|
-
const { existsSync:
|
|
27872
|
+
const { existsSync: existsSync57, readFileSync: readFileSync49, statSync: statSync46 } = await import("fs");
|
|
27572
27873
|
const { execSync: execSync6 } = await import("child_process");
|
|
27573
27874
|
const rows = [];
|
|
27574
27875
|
const note = (ok, label, detail) => rows.push({ ok, label, detail });
|
|
@@ -27632,7 +27933,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27632
27933
|
}
|
|
27633
27934
|
}
|
|
27634
27935
|
const credFile = join60(getDataDir(), "credentials.json");
|
|
27635
|
-
if (!
|
|
27936
|
+
if (!existsSync57(credFile)) {
|
|
27636
27937
|
note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
|
|
27637
27938
|
} else {
|
|
27638
27939
|
try {
|
|
@@ -27645,15 +27946,15 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27645
27946
|
}
|
|
27646
27947
|
}
|
|
27647
27948
|
for (const hooksJson of claudeHookConfigFiles()) {
|
|
27648
|
-
const profile = basename28(
|
|
27949
|
+
const profile = basename28(dirname26(hooksJson));
|
|
27649
27950
|
const label = `Claude hooks (${profile})`;
|
|
27650
|
-
if (!
|
|
27951
|
+
if (!existsSync57(hooksJson)) {
|
|
27651
27952
|
note(false, label, `no ${hooksJson} \u2014 run \`chat-recall install-hooks\``);
|
|
27652
27953
|
continue;
|
|
27653
27954
|
}
|
|
27654
27955
|
try {
|
|
27655
27956
|
const readHooks = (file) => {
|
|
27656
|
-
if (!
|
|
27957
|
+
if (!existsSync57(file)) return {};
|
|
27657
27958
|
try {
|
|
27658
27959
|
return JSON.parse(readFileSync49(file, "utf-8")).hooks || {};
|
|
27659
27960
|
} catch {
|
|
@@ -27661,7 +27962,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27661
27962
|
}
|
|
27662
27963
|
};
|
|
27663
27964
|
const cfg = readHooks(hooksJson);
|
|
27664
|
-
const settings2 = readHooks(join60(
|
|
27965
|
+
const settings2 = readHooks(join60(dirname26(hooksJson), "settings.json"));
|
|
27665
27966
|
const all = ["SessionStart", "UserPromptSubmit", "Stop", "PreCompact", "SessionEnd"];
|
|
27666
27967
|
const hits = [];
|
|
27667
27968
|
for (const ev of all) {
|
|
@@ -27685,7 +27986,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27685
27986
|
const want = bundledSkillNames2().length;
|
|
27686
27987
|
for (const t of skillTargets2()) {
|
|
27687
27988
|
if (!t.available) continue;
|
|
27688
|
-
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;
|
|
27689
27990
|
note(
|
|
27690
27991
|
have === want,
|
|
27691
27992
|
`Skills \u2014 ${t.label}`,
|
|
@@ -27767,7 +28068,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
27767
28068
|
join60(dataDir, "index", "knowledge_graph.db"),
|
|
27768
28069
|
join60(dataDir, "index", "metadata.db")
|
|
27769
28070
|
];
|
|
27770
|
-
const legacyPresent = legacyPaths.filter((p) =>
|
|
28071
|
+
const legacyPresent = legacyPaths.filter((p) => existsSync57(p));
|
|
27771
28072
|
if (opts.purgeLocal) {
|
|
27772
28073
|
if (!target) {
|
|
27773
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");
|
|
@@ -28413,10 +28714,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
28413
28714
|
try {
|
|
28414
28715
|
const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
|
|
28415
28716
|
const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
28416
|
-
const { writeFileSync:
|
|
28717
|
+
const { writeFileSync: writeFileSync22, readFileSync: readFileSync49, existsSync: existsSync57 } = await import("node:fs");
|
|
28417
28718
|
const { join: join61 } = await import("node:path");
|
|
28418
28719
|
const file = join61(cwd, "TEAM_TASKS.md");
|
|
28419
|
-
if (!opts.force &&
|
|
28720
|
+
if (!opts.force && existsSync57(file) && parseTeamTasksFile2(readFileSync49(file, "utf8")).length > 0) {
|
|
28420
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.");
|
|
28421
28722
|
process.exit(1);
|
|
28422
28723
|
}
|
|
@@ -28424,7 +28725,7 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
28424
28725
|
const pid = resolved && resolved.source !== "ignored" ? resolved.id : "";
|
|
28425
28726
|
const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
|
|
28426
28727
|
const mine = tasks2.filter((t) => !pid || !t.projectId || t.projectId === pid);
|
|
28427
|
-
|
|
28728
|
+
writeFileSync22(file, renderTeamTasksMd2(mine));
|
|
28428
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"));
|
|
28429
28730
|
} catch (e) {
|
|
28430
28731
|
console.error(chalk.red(e instanceof Error ? e.message : String(e)));
|
|
@@ -28435,10 +28736,10 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
|
|
|
28435
28736
|
const cwd = dir || process.cwd();
|
|
28436
28737
|
try {
|
|
28437
28738
|
const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
28438
|
-
const { readFileSync: readFileSync49, existsSync:
|
|
28739
|
+
const { readFileSync: readFileSync49, existsSync: existsSync57 } = await import("node:fs");
|
|
28439
28740
|
const { join: join61 } = await import("node:path");
|
|
28440
28741
|
const file = join61(cwd, "TEAM_TASKS.md");
|
|
28441
|
-
if (!
|
|
28742
|
+
if (!existsSync57(file)) {
|
|
28442
28743
|
console.error(chalk.red("no TEAM_TASKS.md here \u2014"), "run", chalk.bold("chat-recall tasks pull"), "first");
|
|
28443
28744
|
process.exit(1);
|
|
28444
28745
|
}
|
|
@@ -28736,7 +29037,7 @@ vault.command("forget").description("Remove the stored passphrase from this mach
|
|
|
28736
29037
|
console.log(keyringDelete2() ? chalk.green("\u2713 Passphrase removed from the OS keyring.") : chalk.dim("Nothing stored in the OS keyring."));
|
|
28737
29038
|
}));
|
|
28738
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) => {
|
|
28739
|
-
const { mkdirSync:
|
|
29040
|
+
const { mkdirSync: mkdirSync20, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync57, readFileSync: readFileSync49, writeFileSync: writeFileSync22, statSync: statSync46 } = await import("fs");
|
|
28740
29041
|
const { fileURLToPath: fileURLToPath5 } = await import("url");
|
|
28741
29042
|
const here = fileURLToPath5(new URL(".", import.meta.url));
|
|
28742
29043
|
const findHook = (name) => {
|
|
@@ -28744,7 +29045,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28744
29045
|
join60(here, "..", "hooks", name),
|
|
28745
29046
|
join60(here, "..", "..", "hooks", name)
|
|
28746
29047
|
];
|
|
28747
|
-
return candidates2.find((p) =>
|
|
29048
|
+
return candidates2.find((p) => existsSync57(p));
|
|
28748
29049
|
};
|
|
28749
29050
|
const sourceSaveHook = findHook("chat_recall_save_hook.sh");
|
|
28750
29051
|
const sourceResumeHook = findHook("chat_recall_resume_hook.sh");
|
|
@@ -28761,7 +29062,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28761
29062
|
const installedWakeupHook = join60(hooksDir, "chat_recall_wakeup_hook.sh");
|
|
28762
29063
|
const wakeupWiredInSettings = (home) => {
|
|
28763
29064
|
const settings2 = join60(home, "settings.json");
|
|
28764
|
-
if (!
|
|
29065
|
+
if (!existsSync57(settings2)) return false;
|
|
28765
29066
|
try {
|
|
28766
29067
|
const cfg = JSON.parse(readFileSync49(settings2, "utf-8"));
|
|
28767
29068
|
const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
|
|
@@ -28772,7 +29073,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28772
29073
|
};
|
|
28773
29074
|
const hookConfigFiles = claudeHookConfigFiles();
|
|
28774
29075
|
const readHookConfig = (file) => {
|
|
28775
|
-
if (!
|
|
29076
|
+
if (!existsSync57(file)) return { hooks: {} };
|
|
28776
29077
|
try {
|
|
28777
29078
|
const c = JSON.parse(readFileSync49(file, "utf-8"));
|
|
28778
29079
|
if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
|
|
@@ -28800,8 +29101,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28800
29101
|
if (filtered.length) config2.hooks[event] = filtered;
|
|
28801
29102
|
else delete config2.hooks[event];
|
|
28802
29103
|
}
|
|
28803
|
-
if (removed === 0 && !
|
|
28804
|
-
|
|
29104
|
+
if (removed === 0 && !existsSync57(hooksJson)) continue;
|
|
29105
|
+
writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
28805
29106
|
total += removed;
|
|
28806
29107
|
console.log(chalk.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
|
|
28807
29108
|
}
|
|
@@ -28822,7 +29123,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28822
29123
|
console.log(chalk.dim(" Under WSL, run this from inside the WSL shell and it installs normally."));
|
|
28823
29124
|
return;
|
|
28824
29125
|
}
|
|
28825
|
-
|
|
29126
|
+
mkdirSync20(hooksDir, { recursive: true });
|
|
28826
29127
|
copyFileSync4(sourceSaveHook, installedSaveHook);
|
|
28827
29128
|
chmodSync5(installedSaveHook, 493);
|
|
28828
29129
|
const installResume = opts.resumeHint !== false && !!sourceResumeHook;
|
|
@@ -28854,7 +29155,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28854
29155
|
const wakeupSkipped = [];
|
|
28855
29156
|
for (const hooksJson of hookConfigFiles) {
|
|
28856
29157
|
const config2 = readHookConfig(hooksJson);
|
|
28857
|
-
const home =
|
|
29158
|
+
const home = dirname26(hooksJson);
|
|
28858
29159
|
const alreadyWired = wakeupWiredInSettings(home);
|
|
28859
29160
|
if (alreadyWired) wakeupSkipped.push(join60(home, "settings.json"));
|
|
28860
29161
|
const perProfile = installWakeup && !alreadyWired ? [...events, ["SessionStart", wakeupEntry]] : events;
|
|
@@ -28866,8 +29167,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
28866
29167
|
if (without.length) config2.hooks[event] = without;
|
|
28867
29168
|
else delete config2.hooks[event];
|
|
28868
29169
|
}
|
|
28869
|
-
|
|
28870
|
-
|
|
29170
|
+
mkdirSync20(dirname26(hooksJson), { recursive: true });
|
|
29171
|
+
writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
28871
29172
|
}
|
|
28872
29173
|
const saveSz = statSync46(installedSaveHook).size;
|
|
28873
29174
|
console.log(chalk.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
|
|
@@ -28912,7 +29213,7 @@ program.command("dossier <project>").description("Generate a project dossier (ov
|
|
|
28912
29213
|
);
|
|
28913
29214
|
const md = dossier.markdown;
|
|
28914
29215
|
if (options.out) {
|
|
28915
|
-
|
|
29216
|
+
writeFileSync21(options.out, md);
|
|
28916
29217
|
console.log(chalk.green(`Wrote dossier to ${options.out} (${md.length} chars)`));
|
|
28917
29218
|
} else {
|
|
28918
29219
|
console.log(md);
|