@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.
Files changed (79) hide show
  1. package/SKILL.md +33 -27
  2. package/api-client.ts +17 -9
  3. package/batch-gate.ts +42 -0
  4. package/billing-cache.ts +72 -23
  5. package/claims-helper.ts +2 -1
  6. package/config.ts +95 -13
  7. package/consolidation.ts +6 -13
  8. package/contradiction-sync.ts +19 -14
  9. package/credential-provider.ts +184 -0
  10. package/crypto.ts +27 -160
  11. package/dist/api-client.js +17 -9
  12. package/dist/batch-gate.js +40 -0
  13. package/dist/billing-cache.js +54 -24
  14. package/dist/claims-helper.js +2 -1
  15. package/dist/config.js +91 -13
  16. package/dist/consolidation.js +6 -15
  17. package/dist/contradiction-sync.js +15 -15
  18. package/dist/credential-provider.js +145 -0
  19. package/dist/crypto.js +17 -137
  20. package/dist/download-ux.js +11 -7
  21. package/dist/embedder-loader.js +266 -0
  22. package/dist/embedding.js +36 -3
  23. package/dist/entry.js +123 -0
  24. package/dist/fs-helpers.js +75 -379
  25. package/dist/import-adapters/gemini-adapter.js +29 -159
  26. package/dist/index.js +864 -2631
  27. package/dist/memory-runtime.js +459 -0
  28. package/dist/native-memory.js +123 -0
  29. package/dist/onboarding-cli.js +4 -8
  30. package/dist/pair-cli-relay.js +1 -8
  31. package/dist/pair-cli.js +1 -1
  32. package/dist/pair-crypto.js +16 -358
  33. package/dist/pair-http.js +147 -4
  34. package/dist/relay.js +140 -0
  35. package/dist/reranker.js +13 -8
  36. package/dist/semantic-dedup.js +5 -7
  37. package/dist/skill-register.js +97 -0
  38. package/dist/subgraph-search.js +3 -1
  39. package/dist/subgraph-store.js +348 -290
  40. package/dist/tool-gating.js +39 -26
  41. package/dist/tools.js +367 -0
  42. package/dist/tr-cli-export-helper.js +3 -3
  43. package/dist/tr-cli.js +65 -156
  44. package/dist/trajectory-poller.js +155 -9
  45. package/dist/vault-crypto.js +551 -0
  46. package/download-ux.ts +12 -6
  47. package/embedder-loader.ts +293 -1
  48. package/embedding.ts +43 -3
  49. package/entry.ts +132 -0
  50. package/fs-helpers.ts +93 -458
  51. package/import-adapters/gemini-adapter.ts +38 -183
  52. package/index.ts +912 -2917
  53. package/memory-runtime.ts +723 -0
  54. package/native-memory.ts +196 -0
  55. package/onboarding-cli.ts +3 -9
  56. package/openclaw.plugin.json +5 -17
  57. package/package.json +6 -3
  58. package/pair-cli-relay.ts +0 -9
  59. package/pair-cli.ts +1 -1
  60. package/pair-crypto.ts +41 -483
  61. package/pair-http.ts +194 -5
  62. package/postinstall.mjs +138 -0
  63. package/relay.ts +172 -0
  64. package/reranker.ts +13 -8
  65. package/semantic-dedup.ts +5 -6
  66. package/skill-register.ts +146 -0
  67. package/skill.json +1 -1
  68. package/subgraph-search.ts +3 -1
  69. package/subgraph-store.ts +367 -307
  70. package/tool-gating.ts +39 -26
  71. package/tools.ts +499 -0
  72. package/tr-cli-export-helper.ts +3 -3
  73. package/tr-cli.ts +69 -182
  74. package/trajectory-poller.ts +162 -10
  75. package/vault-crypto.ts +705 -0
  76. package/auto-pair-on-load.ts +0 -308
  77. package/dist/auto-pair-on-load.js +0 -197
  78. package/dist/pair-pending-injection.js +0 -125
  79. 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
- }