chat-recall 0.0.1 → 0.4.8
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/LICENSE +93 -0
- package/dist/auto-update.d.ts +52 -0
- package/dist/auto-update.d.ts.map +1 -0
- package/dist/auto-update.js +157 -0
- package/dist/auto-update.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +26102 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-events.d.ts +11 -0
- package/dist/client-events.d.ts.map +1 -0
- package/dist/client-events.js +77 -0
- package/dist/client-events.js.map +1 -0
- package/dist/collector-migrate.d.ts +27 -0
- package/dist/collector-migrate.d.ts.map +1 -0
- package/dist/collector-migrate.js +60 -0
- package/dist/collector-migrate.js.map +1 -0
- package/dist/device-auth.d.ts +37 -0
- package/dist/device-auth.d.ts.map +1 -0
- package/dist/device-auth.js +161 -0
- package/dist/device-auth.js.map +1 -0
- package/dist/escalate.d.ts +99 -0
- package/dist/escalate.d.ts.map +1 -0
- package/dist/escalate.js +219 -0
- package/dist/escalate.js.map +1 -0
- package/dist/http.d.ts +14 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +49 -0
- package/dist/http.js.map +1 -0
- package/dist/install-skills.d.ts +51 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +223 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/intent-drain.d.ts +25 -0
- package/dist/intent-drain.d.ts.map +1 -0
- package/dist/intent-drain.js +189 -0
- package/dist/intent-drain.js.map +1 -0
- package/dist/keyring.d.ts +28 -0
- package/dist/keyring.d.ts.map +1 -0
- package/dist/keyring.js +163 -0
- package/dist/keyring.js.map +1 -0
- package/dist/mcp.d.ts +8 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +23665 -0
- package/dist/mcp.js.map +1 -0
- package/dist/project-tasks.d.ts +54 -0
- package/dist/project-tasks.d.ts.map +1 -0
- package/dist/project-tasks.js +204 -0
- package/dist/project-tasks.js.map +1 -0
- package/dist/repair.d.ts +73 -0
- package/dist/repair.d.ts.map +1 -0
- package/dist/repair.js +267 -0
- package/dist/repair.js.map +1 -0
- package/dist/self-restart.d.ts +91 -0
- package/dist/self-restart.d.ts.map +1 -0
- package/dist/self-restart.js +137 -0
- package/dist/self-restart.js.map +1 -0
- package/dist/service-installer.d.ts +32 -0
- package/dist/service-installer.d.ts.map +1 -0
- package/dist/service-installer.js +231 -0
- package/dist/service-installer.js.map +1 -0
- package/dist/sync-client.d.ts +234 -0
- package/dist/sync-client.d.ts.map +1 -0
- package/dist/sync-client.js +1985 -0
- package/dist/sync-client.js.map +1 -0
- package/dist/sync-ledger.d.ts +131 -0
- package/dist/sync-ledger.d.ts.map +1 -0
- package/dist/sync-ledger.js +366 -0
- package/dist/sync-ledger.js.map +1 -0
- package/dist/update-notice.d.ts +16 -0
- package/dist/update-notice.d.ts.map +1 -0
- package/dist/update-notice.js +107 -0
- package/dist/update-notice.js.map +1 -0
- package/dist/verify-deep.d.ts +79 -0
- package/dist/verify-deep.d.ts.map +1 -0
- package/dist/verify-deep.js +97 -0
- package/dist/verify-deep.js.map +1 -0
- package/dist/verify-repair.d.ts +21 -0
- package/dist/verify-repair.d.ts.map +1 -0
- package/dist/verify-repair.js +58 -0
- package/dist/verify-repair.js.map +1 -0
- package/dist/watch.js +21550 -0
- package/hooks/chat_recall_escalate_hook.sh +51 -0
- package/hooks/chat_recall_resume_hook.sh +69 -0
- package/hooks/chat_recall_save_hook.sh +254 -0
- package/hooks/chat_recall_wakeup_hook.sh +39 -0
- package/package.json +38 -4
- package/skills/chat-recall/SKILL.md +76 -0
- package/skills/chat-recall-changes/SKILL.md +50 -0
- package/skills/chat-recall-find/SKILL.md +64 -0
- package/skills/chat-recall-memory/SKILL.md +55 -0
- package/skills/chat-recall-project/SKILL.md +75 -0
- package/skills/chat-recall-resume/SKILL.md +62 -0
- package/README.md +0 -7
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chat-recall verify --deep` — does the server actually hold what this machine
|
|
3
|
+
* has, per session?
|
|
4
|
+
*
|
|
5
|
+
* Every silent-loss incident in this codebase was found by a human asking about
|
|
6
|
+
* one specific session. Nothing reported them, because every symptom looks like
|
|
7
|
+
* healthy operation: `15604 skipped` is what a fully-synced corpus prints too.
|
|
8
|
+
* This is the check that turns "did session X make it?" from an investigation
|
|
9
|
+
* into a command.
|
|
10
|
+
*
|
|
11
|
+
* It compares in the unit the server's shrink guard uses — `gzipContainer().size`
|
|
12
|
+
* of the local union versus the archive's stored `size` — so a difference means
|
|
13
|
+
* the server is genuinely missing records, not that two measurements disagree.
|
|
14
|
+
* Sub-unit noise is ignored via a tolerance.
|
|
15
|
+
*
|
|
16
|
+
* Both sides must be the REDACTED container (see Deps.localContainerSize): the
|
|
17
|
+
* archive stores what was shipped, and what was shipped had its secrets
|
|
18
|
+
* replaced by sentinels.
|
|
19
|
+
*
|
|
20
|
+
* Deliberately NOT an mtime comparison: the server stores the client-sent mtime,
|
|
21
|
+
* which drifts sub-second against the file for essentially every session. An
|
|
22
|
+
* mtime-based version of this check reported 9,975 of 10,032 sessions suspect
|
|
23
|
+
* when the true number was 13.
|
|
24
|
+
*
|
|
25
|
+
* Classification matters as much as detection:
|
|
26
|
+
* pending — the ledger knows there is more to send; it will go on its own
|
|
27
|
+
* STRANDED — the ledger claims complete while the server holds less, so
|
|
28
|
+
* nothing will ever re-ship it. This is the actionable class.
|
|
29
|
+
*/
|
|
30
|
+
import { loadAllCredentials } from './sync-client.js';
|
|
31
|
+
import { getSyncedRows } from './sync-ledger.js';
|
|
32
|
+
/** Below this, a size difference is container-encoding noise rather than
|
|
33
|
+
* missing records. */
|
|
34
|
+
const TOLERANCE_BYTES = 512;
|
|
35
|
+
/**
|
|
36
|
+
* A session written within this window is being TYPED INTO. Its bytes grow
|
|
37
|
+
* between the cursor read and the container build, so `cursor >= fileSize`
|
|
38
|
+
* momentarily holds for a session that is simply mid-flight — and it gets
|
|
39
|
+
* reported as stranded on every run.
|
|
40
|
+
*
|
|
41
|
+
* This is not theoretical: the first real run flagged the live session it was
|
|
42
|
+
* being run from, short by 902 bytes. A checker that always cries wolf about the
|
|
43
|
+
* session you are in is a checker people learn to ignore, so recent writes are
|
|
44
|
+
* classified `pending` regardless of what the cursor says.
|
|
45
|
+
*/
|
|
46
|
+
const LIVE_GRACE_MS = 10 * 60_000;
|
|
47
|
+
/**
|
|
48
|
+
* Pure comparison, injectable so it can be tested without a server or a real
|
|
49
|
+
* transcript corpus.
|
|
50
|
+
*/
|
|
51
|
+
export async function verifyAgainstServer(server, token, sinceMs, deps, now = Date.now()) {
|
|
52
|
+
const serverSize = await deps.serverSizes(server, token);
|
|
53
|
+
const ledger = getSyncedRows(server);
|
|
54
|
+
const report = {
|
|
55
|
+
server, checked: 0, complete: 0, missingArchive: 0, pending: [], stranded: [],
|
|
56
|
+
};
|
|
57
|
+
for (const s of deps.listSessions(sinceMs)) {
|
|
58
|
+
const srv = serverSize.get(s.rawId);
|
|
59
|
+
if (srv === undefined) {
|
|
60
|
+
report.missingArchive++;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const local = deps.localContainerSize(s.rawId);
|
|
64
|
+
if (local === null)
|
|
65
|
+
continue; // unreadable/unparseable — not a finding
|
|
66
|
+
report.checked++;
|
|
67
|
+
const deficit = local - srv;
|
|
68
|
+
if (deficit <= TOLERANCE_BYTES) {
|
|
69
|
+
report.complete++;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// The ledger's `s` is the server's confirmed byte cursor. If it is at or
|
|
73
|
+
// past the local file size, the client believes there is nothing left to
|
|
74
|
+
// send — so this session will never re-ship on its own.
|
|
75
|
+
const row = ledger.get(s.prefixedId) ?? ledger.get(s.rawId);
|
|
76
|
+
const cursor = row?.s ?? 0;
|
|
77
|
+
const live = s.mtime >= now - LIVE_GRACE_MS;
|
|
78
|
+
const stranded = !live && !!row && cursor >= deps.fileSize(s.rawId);
|
|
79
|
+
const finding = {
|
|
80
|
+
sessionId: s.rawId,
|
|
81
|
+
projectPath: s.projectPath || '',
|
|
82
|
+
localSize: local,
|
|
83
|
+
serverSize: srv,
|
|
84
|
+
deficit,
|
|
85
|
+
stranded,
|
|
86
|
+
};
|
|
87
|
+
(stranded ? report.stranded : report.pending).push(finding);
|
|
88
|
+
}
|
|
89
|
+
report.stranded.sort((a, b) => b.deficit - a.deficit);
|
|
90
|
+
report.pending.sort((a, b) => b.deficit - a.deficit);
|
|
91
|
+
return report;
|
|
92
|
+
}
|
|
93
|
+
/** Every configured target, so a multi-server setup is verified as a whole. */
|
|
94
|
+
export function verifyTargets() {
|
|
95
|
+
return loadAllCredentials().map((c) => ({ serverUrl: c.serverUrl.replace(/\/+$/, ''), token: c.token }));
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=verify-deep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-deep.js","sourceRoot":"","sources":["../src/verify-deep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Un-strand sessions found by `chat-recall verify --deep`.
|
|
3
|
+
*
|
|
4
|
+
* A stranded session is one whose ledger cursor says "the server has all of
|
|
5
|
+
* this" while the server demonstrably has less. Nothing re-ships it, because
|
|
6
|
+
* `syncMode` reads that cursor and returns SKIP. Clearing the cursor is what
|
|
7
|
+
* puts it back in the queue — the next sync then re-derives and re-ships from
|
|
8
|
+
* scratch.
|
|
9
|
+
*
|
|
10
|
+
* Only the CURSOR is cleared, not the whole row: per-field coverage (`f`) is
|
|
11
|
+
* owned by field reconciliation and dropping it would make every field re-scan
|
|
12
|
+
* from zero. The mtime is cleared too, since leaving it would let the
|
|
13
|
+
* mtime-unchanged branch SKIP the session straight back out again.
|
|
14
|
+
*
|
|
15
|
+
* Writes a timestamped backup first. This edits the file that decides what gets
|
|
16
|
+
* uploaded, and a bad edit here re-ships a 10k-session corpus.
|
|
17
|
+
*/
|
|
18
|
+
/** Clear the sync cursor for `sessionIds` on `server`. Returns how many rows
|
|
19
|
+
* were actually cleared (ids with no ledger entry need no work). */
|
|
20
|
+
export declare function forceFullResync(server: string, sessionIds: string[]): number;
|
|
21
|
+
//# sourceMappingURL=verify-repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-repair.d.ts","sourceRoot":"","sources":["../src/verify-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH;qEACqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CA6B5E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Un-strand sessions found by `chat-recall verify --deep`.
|
|
3
|
+
*
|
|
4
|
+
* A stranded session is one whose ledger cursor says "the server has all of
|
|
5
|
+
* this" while the server demonstrably has less. Nothing re-ships it, because
|
|
6
|
+
* `syncMode` reads that cursor and returns SKIP. Clearing the cursor is what
|
|
7
|
+
* puts it back in the queue — the next sync then re-derives and re-ships from
|
|
8
|
+
* scratch.
|
|
9
|
+
*
|
|
10
|
+
* Only the CURSOR is cleared, not the whole row: per-field coverage (`f`) is
|
|
11
|
+
* owned by field reconciliation and dropping it would make every field re-scan
|
|
12
|
+
* from zero. The mtime is cleared too, since leaving it would let the
|
|
13
|
+
* mtime-unchanged branch SKIP the session straight back out again.
|
|
14
|
+
*
|
|
15
|
+
* Writes a timestamped backup first. This edits the file that decides what gets
|
|
16
|
+
* uploaded, and a bad edit here re-ships a 10k-session corpus.
|
|
17
|
+
*/
|
|
18
|
+
import { copyFileSync, existsSync } from 'fs';
|
|
19
|
+
import { getLedgerData, persistLedgerData, ledgerFilePath } from './sync-ledger.js';
|
|
20
|
+
/** Clear the sync cursor for `sessionIds` on `server`. Returns how many rows
|
|
21
|
+
* were actually cleared (ids with no ledger entry need no work). */
|
|
22
|
+
export function forceFullResync(server, sessionIds) {
|
|
23
|
+
if (sessionIds.length === 0)
|
|
24
|
+
return 0;
|
|
25
|
+
const path = ledgerFilePath();
|
|
26
|
+
if (existsSync(path)) {
|
|
27
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '').replace(/-/g, '');
|
|
28
|
+
try {
|
|
29
|
+
copyFileSync(path, `${path}.bak-${stamp}`);
|
|
30
|
+
}
|
|
31
|
+
catch { /* backup best-effort */ }
|
|
32
|
+
}
|
|
33
|
+
const data = getLedgerData(server);
|
|
34
|
+
const wanted = new Set(sessionIds);
|
|
35
|
+
let cleared = 0;
|
|
36
|
+
for (const key of Object.keys(data)) {
|
|
37
|
+
// Ledger keys are prefixed ids for non-Claude tools; match either form.
|
|
38
|
+
const bare = key.replace(/^(opencode_|gemini_|codex_|agy_)/, '');
|
|
39
|
+
if (!wanted.has(key) && !wanted.has(bare))
|
|
40
|
+
continue;
|
|
41
|
+
const row = data[key];
|
|
42
|
+
if (typeof row !== 'object' || row === null) {
|
|
43
|
+
delete data[key];
|
|
44
|
+
cleared++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const r = row;
|
|
48
|
+
delete r.o; // byte cursor
|
|
49
|
+
delete r.s; // synced-through size
|
|
50
|
+
delete r.h; // content hash — else the "unchanged" fast path skips again
|
|
51
|
+
delete r.m; // mtime — else the mtime-unchanged branch skips again
|
|
52
|
+
cleared++;
|
|
53
|
+
}
|
|
54
|
+
if (cleared > 0)
|
|
55
|
+
persistLedgerData(server, data);
|
|
56
|
+
return cleared;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=verify-repair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-repair.js","sourceRoot":"","sources":["../src/verify-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEpF;qEACqE;AACrE,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,UAAoB;IAClE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEtC,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC;YAAC,YAAY,CAAC,IAAI,EAAE,GAAG,IAAI,QAAQ,KAAK,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACnC,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,wEAAwE;QACxE,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YAAC,OAAO,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QACvF,MAAM,CAAC,GAAG,GAAyC,CAAC;QACpD,OAAO,CAAC,CAAC,CAAC,CAAC,CAAM,cAAc;QAC/B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAM,sBAAsB;QACvC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAM,4DAA4D;QAC7E,OAAO,CAAC,CAAC,CAAC,CAAC,CAAM,sDAAsD;QACvE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,OAAO,GAAG,CAAC;QAAE,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|