@totalreclaw/totalreclaw 3.3.12-rc.9 → 3.3.12
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/SKILL.md +33 -27
- package/api-client.ts +17 -9
- package/batch-gate.ts +42 -0
- package/billing-cache.ts +72 -23
- package/claims-helper.ts +2 -1
- package/config.ts +95 -13
- package/consolidation.ts +6 -13
- package/contradiction-sync.ts +19 -14
- package/credential-provider.ts +184 -0
- package/crypto.ts +27 -160
- package/dist/api-client.js +17 -9
- package/dist/batch-gate.js +40 -0
- package/dist/billing-cache.js +54 -24
- package/dist/claims-helper.js +2 -1
- package/dist/config.js +91 -13
- package/dist/consolidation.js +6 -15
- package/dist/contradiction-sync.js +15 -15
- package/dist/credential-provider.js +145 -0
- package/dist/crypto.js +17 -137
- package/dist/download-ux.js +11 -7
- package/dist/embedder-loader.js +266 -0
- package/dist/embedding.js +36 -3
- package/dist/entry.js +123 -0
- package/dist/fs-helpers.js +75 -379
- package/dist/import-adapters/gemini-adapter.js +29 -159
- package/dist/index.js +864 -2631
- package/dist/memory-runtime.js +459 -0
- package/dist/native-memory.js +123 -0
- package/dist/onboarding-cli.js +4 -8
- package/dist/pair-cli-relay.js +1 -8
- package/dist/pair-cli.js +1 -1
- package/dist/pair-crypto.js +16 -358
- package/dist/pair-http.js +147 -4
- package/dist/relay.js +140 -0
- package/dist/reranker.js +13 -8
- package/dist/semantic-dedup.js +5 -7
- package/dist/skill-register.js +97 -0
- package/dist/subgraph-search.js +3 -1
- package/dist/subgraph-store.js +348 -290
- package/dist/tool-gating.js +39 -26
- package/dist/tools.js +367 -0
- package/dist/tr-cli-export-helper.js +3 -3
- package/dist/tr-cli.js +65 -156
- package/dist/trajectory-poller.js +155 -9
- package/dist/vault-crypto.js +551 -0
- package/download-ux.ts +12 -6
- package/embedder-loader.ts +293 -1
- package/embedding.ts +43 -3
- package/entry.ts +132 -0
- package/fs-helpers.ts +93 -458
- package/import-adapters/gemini-adapter.ts +38 -183
- package/index.ts +912 -2917
- package/memory-runtime.ts +723 -0
- package/native-memory.ts +196 -0
- package/onboarding-cli.ts +3 -9
- package/openclaw.plugin.json +5 -17
- package/package.json +6 -3
- package/pair-cli-relay.ts +0 -9
- package/pair-cli.ts +1 -1
- package/pair-crypto.ts +41 -483
- package/pair-http.ts +194 -5
- package/postinstall.mjs +138 -0
- package/relay.ts +172 -0
- package/reranker.ts +13 -8
- package/semantic-dedup.ts +5 -6
- package/skill-register.ts +146 -0
- package/skill.json +1 -1
- package/subgraph-search.ts +3 -1
- package/subgraph-store.ts +367 -307
- package/tool-gating.ts +39 -26
- package/tools.ts +499 -0
- package/tr-cli-export-helper.ts +3 -3
- package/tr-cli.ts +69 -182
- package/trajectory-poller.ts +162 -10
- package/vault-crypto.ts +705 -0
- package/auto-pair-on-load.ts +0 -308
- package/dist/auto-pair-on-load.js +0 -197
- package/dist/pair-pending-injection.js +0 -125
- package/pair-pending-injection.ts +0 -205
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pair-pending-injection — `before_agent_start` hook that surfaces the
|
|
3
|
-
* pending pair URL + PIN to the chat agent verbatim, so the agent can NOT
|
|
4
|
-
* hallucinate either value.
|
|
5
|
-
*
|
|
6
|
-
* Background
|
|
7
|
-
* ----------
|
|
8
|
-
* Companion to `auto-pair-on-load.ts`. When the plugin loads without
|
|
9
|
-
* credentials, the auto-pair flow writes `~/.totalreclaw/.pair-pending.json`
|
|
10
|
-
* with the exact URL + PIN the user must use. This hook reads that file on
|
|
11
|
-
* every agent start and, when present, prepends a context block that tells
|
|
12
|
-
* the agent EXACTLY what to say.
|
|
13
|
-
*
|
|
14
|
-
* No agent-generated string ever appears in the URL or PIN that reaches
|
|
15
|
-
* the user.
|
|
16
|
-
*
|
|
17
|
-
* Phrase safety
|
|
18
|
-
* -------------
|
|
19
|
-
* The sentinel does NOT contain the recovery phrase. The injected context
|
|
20
|
-
* deliberately warns the agent NOT to attempt to display, generate, or
|
|
21
|
-
* relay any phrase. That instruction is reinforced via the staging-banner
|
|
22
|
-
* hook + the SKILL.md phrase-safety section.
|
|
23
|
-
*
|
|
24
|
-
* Scanner scope
|
|
25
|
-
* -------------
|
|
26
|
-
* Pure-logic file — no `node:fs` imports, no `process.env` reads, no
|
|
27
|
-
* subprocess module usage. Disk I/O is delegated to `fs-helpers.ts`.
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
import {
|
|
31
|
-
defaultPairPendingPath,
|
|
32
|
-
deletePairPendingFile,
|
|
33
|
-
loadPairPendingFile,
|
|
34
|
-
type PairPendingFile,
|
|
35
|
-
} from './fs-helpers.js';
|
|
36
|
-
import { maybeStartAutoPair, type AutoPairDeps } from './auto-pair-on-load.js';
|
|
37
|
-
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
// Types
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
/** Minimal OpenClaw plugin-api surface this module needs. */
|
|
43
|
-
export interface PairInjectionApi {
|
|
44
|
-
logger: {
|
|
45
|
-
info(...args: unknown[]): void;
|
|
46
|
-
warn(...args: unknown[]): void;
|
|
47
|
-
error(...args: unknown[]): void;
|
|
48
|
-
};
|
|
49
|
-
on(
|
|
50
|
-
hookName: string,
|
|
51
|
-
handler: (...args: unknown[]) => unknown,
|
|
52
|
-
opts?: { priority?: number },
|
|
53
|
-
): void;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Dependencies — injected so tests + production can share the same logic. */
|
|
57
|
-
export interface PairInjectionDeps {
|
|
58
|
-
/** Credentials path used to derive the default pending sentinel path. */
|
|
59
|
-
credentialsPath: string;
|
|
60
|
-
/** Optional explicit sentinel path. Overrides `defaultPairPendingPath`. */
|
|
61
|
-
pendingPath?: string;
|
|
62
|
-
/**
|
|
63
|
-
* Factory that produces the deps the hook will pass to maybeStartAutoPair
|
|
64
|
-
* if it detects an expired sentinel and needs to re-create one. Returning
|
|
65
|
-
* `null` disables auto re-create (the hook will just clean up + log).
|
|
66
|
-
*/
|
|
67
|
-
autoPairDepsFactory?: () => AutoPairDeps | null;
|
|
68
|
-
/**
|
|
69
|
-
* Test injection — override `Date.now()` so the expiry decision is
|
|
70
|
-
* deterministic.
|
|
71
|
-
*/
|
|
72
|
-
now?: () => number;
|
|
73
|
-
/**
|
|
74
|
-
* Test injection — substitute a custom auto-pair runner. Receives the
|
|
75
|
-
* same deps the production path would use.
|
|
76
|
-
*/
|
|
77
|
-
startAutoPair?: (deps: AutoPairDeps) => Promise<unknown>;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Shape the hook returns to OpenClaw — only `prependContext` is used here. */
|
|
81
|
-
export interface BeforeAgentStartReturn {
|
|
82
|
-
prependContext?: string;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
// Hook body (exposed for unit tests)
|
|
87
|
-
// ---------------------------------------------------------------------------
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Pure-async body of the hook. Test-callable.
|
|
91
|
-
*
|
|
92
|
-
* - sentinel missing -> no-op (return `undefined`)
|
|
93
|
-
* - sentinel valid + non-expired -> return `{ prependContext: <block> }`
|
|
94
|
-
* - sentinel expired -> delete + try re-create via maybeStartAutoPair; if
|
|
95
|
-
* re-create returns a fresh `pending`, inject context for the NEW URL/PIN;
|
|
96
|
-
* else return `undefined`
|
|
97
|
-
*/
|
|
98
|
-
export async function runPairPendingInjection(
|
|
99
|
-
deps: PairInjectionDeps,
|
|
100
|
-
logger: PairInjectionApi['logger'],
|
|
101
|
-
): Promise<BeforeAgentStartReturn | undefined> {
|
|
102
|
-
const now = deps.now ?? Date.now;
|
|
103
|
-
const pendingPath = deps.pendingPath ?? defaultPairPendingPath(deps.credentialsPath);
|
|
104
|
-
|
|
105
|
-
const existing = loadPairPendingFile(pendingPath);
|
|
106
|
-
|
|
107
|
-
// No sentinel — nothing to inject.
|
|
108
|
-
if (!existing) return undefined;
|
|
109
|
-
|
|
110
|
-
// Valid + non-expired sentinel — inject context with verbatim values.
|
|
111
|
-
if (existing.expires_at_ms > now()) {
|
|
112
|
-
return { prependContext: buildPrependContext(existing) };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Expired sentinel. Clean it up and optionally re-create.
|
|
116
|
-
logger.info('pair-pending-injection: sentinel expired, cleaning up');
|
|
117
|
-
deletePairPendingFile(pendingPath);
|
|
118
|
-
|
|
119
|
-
const apFactory = deps.autoPairDepsFactory;
|
|
120
|
-
if (!apFactory) return undefined;
|
|
121
|
-
|
|
122
|
-
const apDeps = apFactory();
|
|
123
|
-
if (!apDeps) return undefined;
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const runner = deps.startAutoPair ?? maybeStartAutoPair;
|
|
127
|
-
const result = (await runner(apDeps)) as
|
|
128
|
-
| { status: 'started'; pending: PairPendingFile }
|
|
129
|
-
| { status: 'pending_reused'; pending: PairPendingFile }
|
|
130
|
-
| { status: 'failed'; error: string }
|
|
131
|
-
| { status: 'creds_exist' }
|
|
132
|
-
| undefined;
|
|
133
|
-
if (
|
|
134
|
-
result
|
|
135
|
-
&& typeof result === 'object'
|
|
136
|
-
&& (result.status === 'started' || result.status === 'pending_reused')
|
|
137
|
-
) {
|
|
138
|
-
return { prependContext: buildPrependContext(result.pending) };
|
|
139
|
-
}
|
|
140
|
-
} catch (err) {
|
|
141
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
142
|
-
logger.warn(`pair-pending-injection: re-create failed: ${msg}`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return undefined;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
// Wire-up
|
|
150
|
-
// ---------------------------------------------------------------------------
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Register the before_agent_start hook on the OpenClaw plugin API. Wraps
|
|
154
|
-
* the hook body in try/catch so any error path returns `undefined` (i.e.
|
|
155
|
-
* silently skip the injection — never block session start).
|
|
156
|
-
*/
|
|
157
|
-
export function installBeforeAgentStartHook(
|
|
158
|
-
api: PairInjectionApi,
|
|
159
|
-
deps: PairInjectionDeps,
|
|
160
|
-
): void {
|
|
161
|
-
api.on(
|
|
162
|
-
'before_agent_start',
|
|
163
|
-
async (_event: unknown): Promise<BeforeAgentStartReturn | undefined> => {
|
|
164
|
-
try {
|
|
165
|
-
return await runPairPendingInjection(deps, api.logger);
|
|
166
|
-
} catch (err) {
|
|
167
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
168
|
-
api.logger.warn(`pair-pending-injection: hook failed: ${msg}`);
|
|
169
|
-
return undefined;
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
// Priority chosen lower than the staging-banner / memory-recall hook
|
|
173
|
-
// (which uses default priority) so the pair-pending block lands BEFORE
|
|
174
|
-
// those — the URL + PIN is the highest-priority action for a fresh user.
|
|
175
|
-
{ priority: 100 },
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// ---------------------------------------------------------------------------
|
|
180
|
-
// Context-block builder (exported for tests)
|
|
181
|
-
// ---------------------------------------------------------------------------
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Build the prepend block. URL + PIN are inlined VERBATIM from the
|
|
185
|
-
* sentinel — there is no template substitution or string manipulation on
|
|
186
|
-
* either value. The agent is told explicitly to read the file as the
|
|
187
|
-
* source of truth.
|
|
188
|
-
*/
|
|
189
|
-
export function buildPrependContext(pending: PairPendingFile): string {
|
|
190
|
-
return (
|
|
191
|
-
'[TotalReclaw setup pending — read this carefully]\n\n'
|
|
192
|
-
+ 'The user has TotalReclaw installed but no recovery phrase yet. To complete setup, '
|
|
193
|
-
+ 'tell the user EXACTLY these two values (do NOT invent or modify them — read directly '
|
|
194
|
-
+ 'from ~/.totalreclaw/.pair-pending.json):\n\n'
|
|
195
|
-
+ `Open this URL in your browser: ${pending.url}\n`
|
|
196
|
-
+ `Enter this 6-digit PIN: ${pending.pin}\n\n`
|
|
197
|
-
+ 'The browser page lets the user either generate a fresh 12-word recovery phrase or '
|
|
198
|
-
+ 'import an existing one. The phrase is delivered to the gateway end-to-end encrypted; '
|
|
199
|
-
+ 'it never touches you (the agent) or any server in plaintext.\n\n'
|
|
200
|
-
+ 'After the user confirms "done", check ~/.totalreclaw/credentials.json — if present, '
|
|
201
|
-
+ 'setup is complete.\n\n'
|
|
202
|
-
+ 'CRITICAL: do NOT make up these values. The file ~/.totalreclaw/.pair-pending.json IS '
|
|
203
|
-
+ 'the source of truth. If the file is missing, run `tr pair --json` instead.\n\n'
|
|
204
|
-
);
|
|
205
|
-
}
|