@totalreclaw/totalreclaw 3.3.12 → 3.3.13
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 +25 -8
- package/{billing-cache.ts → billing/billing-cache.ts} +1 -1
- package/{relay-headers.ts → billing/relay-headers.ts} +1 -1
- package/{tr-cli-export-helper.ts → cli/tr-cli-export-helper.ts} +5 -5
- package/{tr-cli.ts → cli/tr-cli.ts} +20 -20
- package/{contradiction-sync.ts → contradiction/contradiction-sync.ts} +13 -13
- package/{digest-sync.ts → digest/digest-sync.ts} +32 -2
- package/dist/{billing-cache.js → billing/billing-cache.js} +1 -1
- package/dist/{relay-headers.js → billing/relay-headers.js} +1 -1
- package/dist/{tr-cli-export-helper.js → cli/tr-cli-export-helper.js} +5 -5
- package/dist/{tr-cli.js → cli/tr-cli.js} +19 -19
- package/dist/{contradiction-sync.js → contradiction/contradiction-sync.js} +13 -13
- package/dist/{digest-sync.js → digest/digest-sync.js} +32 -2
- package/dist/{download-ux.js → embedding/download-ux.js} +1 -1
- package/dist/{reranker.js → embedding/reranker.js} +13 -4
- package/dist/{claims-helper.js → extraction/claims-helper.js} +54 -58
- package/dist/extraction/consolidation.js +170 -0
- package/dist/{extractor.js → extraction/extractor.js} +17 -17
- package/dist/extraction/importance-filter.js +38 -0
- package/dist/{semantic-dedup.js → extraction/semantic-dedup.js} +2 -2
- package/dist/{batch-gate.js → import/batch-gate.js} +1 -1
- package/dist/import/import-runtime.js +692 -0
- package/dist/import-adapters/chatgpt-adapter.js +7 -7
- package/dist/import-adapters/gemini-adapter.js +13 -13
- package/dist/import-adapters/mem0-adapter.js +10 -10
- package/dist/index.js +111 -1094
- package/dist/{llm-client.js → llm/llm-client.js} +2 -2
- package/dist/{hot-cache-wrapper.js → memory/hot-cache-wrapper.js} +5 -5
- package/dist/{memory-runtime.js → memory/memory-runtime.js} +1 -1
- package/dist/{pin.js → memory/pin.js} +18 -18
- package/dist/{retype-setscope.js → memory/retype-setscope.js} +19 -19
- package/dist/{credential-provider.js → pairing/credential-provider.js} +2 -2
- package/dist/{first-run.js → pairing/first-run.js} +1 -1
- package/dist/{onboarding-cli.js → pairing/onboarding-cli.js} +20 -20
- package/dist/{pair-cli-relay.js → pairing/pair-cli-relay.js} +10 -10
- package/dist/{pair-crypto.js → pairing/pair-crypto.js} +1 -1
- package/dist/{pair-http.js → pairing/pair-http.js} +3 -3
- package/dist/{pair-remote-client.js → pairing/pair-remote-client.js} +10 -10
- package/dist/{pair-session-store.js → pairing/pair-session-store.js} +4 -4
- package/dist/runtime/config-schema.js +59 -0
- package/dist/runtime/format-helpers.js +257 -0
- package/dist/runtime/types.js +11 -0
- package/dist/{confirm-indexed.js → subgraph/confirm-indexed.js} +1 -1
- package/dist/{subgraph-search.js → subgraph/subgraph-search.js} +14 -14
- package/dist/{subgraph-store.js → subgraph/subgraph-store.js} +6 -6
- package/{download-ux.ts → embedding/download-ux.ts} +1 -1
- package/{reranker.ts → embedding/reranker.ts} +13 -4
- package/{claims-helper.ts → extraction/claims-helper.ts} +52 -60
- package/{consolidation.ts → extraction/consolidation.ts} +63 -154
- package/{extractor.ts → extraction/extractor.ts} +18 -17
- package/extraction/importance-filter.ts +50 -0
- package/{semantic-dedup.ts → extraction/semantic-dedup.ts} +2 -2
- package/{batch-gate.ts → import/batch-gate.ts} +1 -1
- package/import/import-runtime.ts +853 -0
- package/import-adapters/chatgpt-adapter.ts +7 -7
- package/import-adapters/gemini-adapter.ts +13 -13
- package/import-adapters/mem0-adapter.ts +10 -10
- package/index.ts +129 -1377
- package/{llm-client.ts → llm/llm-client.ts} +2 -2
- package/{hot-cache-wrapper.ts → memory/hot-cache-wrapper.ts} +5 -5
- package/{memory-runtime.ts → memory/memory-runtime.ts} +1 -1
- package/{pin.ts → memory/pin.ts} +20 -20
- package/{retype-setscope.ts → memory/retype-setscope.ts} +21 -21
- package/{tool-gating.ts → memory/tool-gating.ts} +1 -1
- package/package.json +6 -6
- package/{credential-provider.ts → pairing/credential-provider.ts} +2 -2
- package/{first-run.ts → pairing/first-run.ts} +1 -1
- package/{onboarding-cli.ts → pairing/onboarding-cli.ts} +20 -20
- package/{pair-cli-relay.ts → pairing/pair-cli-relay.ts} +10 -10
- package/{pair-crypto.ts → pairing/pair-crypto.ts} +1 -1
- package/{pair-http.ts → pairing/pair-http.ts} +3 -3
- package/{pair-remote-client.ts → pairing/pair-remote-client.ts} +10 -10
- package/{pair-session-store.ts → pairing/pair-session-store.ts} +4 -4
- package/runtime/config-schema.ts +64 -0
- package/runtime/format-helpers.ts +293 -0
- package/runtime/types.ts +118 -0
- package/skill.json +44 -10
- package/{confirm-indexed.ts → subgraph/confirm-indexed.ts} +1 -1
- package/{subgraph-search.ts → subgraph/subgraph-search.ts} +14 -14
- package/{subgraph-store.ts → subgraph/subgraph-store.ts} +10 -10
- package/dist/consolidation.js +0 -249
- /package/{api-client.ts → billing/api-client.ts} +0 -0
- /package/{gateway-url.ts → billing/gateway-url.ts} +0 -0
- /package/{inbound-user-tracker.ts → billing/inbound-user-tracker.ts} +0 -0
- /package/{relay.ts → billing/relay.ts} +0 -0
- /package/{crypto.ts → crypto/crypto.ts} +0 -0
- /package/{vault-crypto.ts → crypto/vault-crypto.ts} +0 -0
- /package/dist/{api-client.js → billing/api-client.js} +0 -0
- /package/dist/{gateway-url.js → billing/gateway-url.js} +0 -0
- /package/dist/{inbound-user-tracker.js → billing/inbound-user-tracker.js} +0 -0
- /package/dist/{relay.js → billing/relay.js} +0 -0
- /package/dist/{crypto.js → crypto/crypto.js} +0 -0
- /package/dist/{vault-crypto.js → crypto/vault-crypto.js} +0 -0
- /package/dist/{embedder-cache.js → embedding/embedder-cache.js} +0 -0
- /package/dist/{embedder-loader.js → embedding/embedder-loader.js} +0 -0
- /package/dist/{embedder-network.js → embedding/embedder-network.js} +0 -0
- /package/dist/{embedding.js → embedding/embedding.js} +0 -0
- /package/dist/{lsh.js → embedding/lsh.js} +0 -0
- /package/dist/{import-state-manager.js → import/import-state-manager.js} +0 -0
- /package/dist/{llm-profile-reader.js → llm/llm-profile-reader.js} +0 -0
- /package/dist/{native-memory.js → memory/native-memory.js} +0 -0
- /package/dist/{tool-gating.js → memory/tool-gating.js} +0 -0
- /package/dist/{tools.js → memory/tools.js} +0 -0
- /package/dist/{generate-mnemonic.js → pairing/generate-mnemonic.js} +0 -0
- /package/dist/{pair-cli.js → pairing/pair-cli.js} +0 -0
- /package/dist/{pair-page.js → pairing/pair-page.js} +0 -0
- /package/dist/{pair-qr.js → pairing/pair-qr.js} +0 -0
- /package/dist/{restart-auth.js → pairing/restart-auth.js} +0 -0
- /package/dist/{qa-bug-report.js → setup/qa-bug-report.js} +0 -0
- /package/dist/{skill-register.js → setup/skill-register.js} +0 -0
- /package/dist/{trajectory-poller.js → subgraph/trajectory-poller.js} +0 -0
- /package/{embedder-cache.ts → embedding/embedder-cache.ts} +0 -0
- /package/{embedder-loader.ts → embedding/embedder-loader.ts} +0 -0
- /package/{embedder-network.ts → embedding/embedder-network.ts} +0 -0
- /package/{embedding.ts → embedding/embedding.ts} +0 -0
- /package/{lsh.ts → embedding/lsh.ts} +0 -0
- /package/{import-state-manager.ts → import/import-state-manager.ts} +0 -0
- /package/{llm-profile-reader.ts → llm/llm-profile-reader.ts} +0 -0
- /package/{native-memory.ts → memory/native-memory.ts} +0 -0
- /package/{tools.ts → memory/tools.ts} +0 -0
- /package/{generate-mnemonic.ts → pairing/generate-mnemonic.ts} +0 -0
- /package/{pair-cli.ts → pairing/pair-cli.ts} +0 -0
- /package/{pair-page.ts → pairing/pair-page.ts} +0 -0
- /package/{pair-qr.ts → pairing/pair-qr.ts} +0 -0
- /package/{restart-auth.ts → pairing/restart-auth.ts} +0 -0
- /package/{qa-bug-report.ts → setup/qa-bug-report.ts} +0 -0
- /package/{skill-register.ts → setup/skill-register.ts} +0 -0
- /package/{trajectory-poller.ts → subgraph/trajectory-poller.ts} +0 -0
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @huggingface/transformers). No API key needed for embeddings.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { CONFIG } from '
|
|
12
|
+
import { CONFIG } from '../config.js';
|
|
13
13
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// Types
|
|
@@ -991,4 +991,4 @@ export {
|
|
|
991
991
|
configureEmbedder,
|
|
992
992
|
// 3.3.3-rc.1 (#187): pre-pair bundle prefetch
|
|
993
993
|
prefetchEmbedderBundle,
|
|
994
|
-
} from '
|
|
994
|
+
} from '../embedding/embedding.js';
|
|
@@ -96,12 +96,12 @@ export class PluginHotCache {
|
|
|
96
96
|
if (!fs.existsSync(this.cachePath)) return;
|
|
97
97
|
|
|
98
98
|
try {
|
|
99
|
-
const
|
|
100
|
-
if (
|
|
99
|
+
const encryptedFile = fs.readFileSync(this.cachePath);
|
|
100
|
+
if (encryptedFile.length < IV_LENGTH + TAG_LENGTH) return;
|
|
101
101
|
|
|
102
|
-
const iv =
|
|
103
|
-
const tag =
|
|
104
|
-
const ciphertext =
|
|
102
|
+
const iv = encryptedFile.subarray(0, IV_LENGTH);
|
|
103
|
+
const tag = encryptedFile.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH);
|
|
104
|
+
const ciphertext = encryptedFile.subarray(IV_LENGTH + TAG_LENGTH);
|
|
105
105
|
|
|
106
106
|
const decipher = crypto.createDecipheriv('aes-256-gcm', this.key, iv);
|
|
107
107
|
decipher.setAuthTag(tag);
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
// (no OpenClaw type import) so the plugin compiles without depending on
|
|
66
66
|
// OpenClaw's type package.
|
|
67
67
|
// ---------------------------------------------------------------------------
|
|
68
|
-
import { EXTRACTION_SYSTEM_PROMPT } from '
|
|
68
|
+
import { EXTRACTION_SYSTEM_PROMPT } from '../extraction/extractor.js';
|
|
69
69
|
|
|
70
70
|
// ---------------------------------------------------------------------------
|
|
71
71
|
// Types — injected caller shapes. Kept loose (no OpenClaw type import) so
|
package/{pin.ts → memory/pin.ts}
RENAMED
|
@@ -16,17 +16,17 @@ import {
|
|
|
16
16
|
mapTypeToCategory,
|
|
17
17
|
readV1Blob,
|
|
18
18
|
type PinStatus,
|
|
19
|
-
} from '
|
|
19
|
+
} from '../extraction/claims-helper.js';
|
|
20
20
|
import {
|
|
21
21
|
findLoserClaimInDecisionLog,
|
|
22
22
|
maybeWriteFeedbackForPin,
|
|
23
23
|
type ContradictionLogger,
|
|
24
|
-
} from '
|
|
25
|
-
import { isValidMemoryType, V0_TO_V1_TYPE } from '
|
|
26
|
-
import type { MemoryType, MemorySource, MemoryScope, MemoryVolatility } from '
|
|
27
|
-
import { PROTOBUF_VERSION_V4 } from '
|
|
28
|
-
import type { SubgraphSearchFact } from '
|
|
29
|
-
import { confirmIndexed, type ConfirmIndexedOptions } from '
|
|
24
|
+
} from '../contradiction/contradiction-sync.js';
|
|
25
|
+
import { isValidMemoryType, V0_TO_V1_TYPE } from '../extraction/extractor.js';
|
|
26
|
+
import type { MemoryType, MemorySource, MemoryScope, MemoryVolatility } from '../extraction/extractor.js';
|
|
27
|
+
import { PROTOBUF_VERSION_V4 } from '../subgraph/subgraph-store.js';
|
|
28
|
+
import type { SubgraphSearchFact } from '../subgraph/subgraph-search.js';
|
|
29
|
+
import { confirmIndexed, type ConfirmIndexedOptions } from '../subgraph/confirm-indexed.js';
|
|
30
30
|
|
|
31
31
|
// Lazy-load WASM core (mirrors claims-helper.ts pattern — plays nicely under
|
|
32
32
|
// both the OpenClaw runtime (CJS-ish tsx) and bare Node ESM used by tests).
|
|
@@ -151,9 +151,9 @@ export interface ParsedBlob {
|
|
|
151
151
|
|
|
152
152
|
/** Parse a decrypted blob into a canonical mutable Claim + current human status. */
|
|
153
153
|
export function parseBlobForPin(decrypted: string): ParsedBlob {
|
|
154
|
-
let
|
|
154
|
+
let parsed: Record<string, unknown>;
|
|
155
155
|
try {
|
|
156
|
-
|
|
156
|
+
parsed = JSON.parse(decrypted) as Record<string, unknown>;
|
|
157
157
|
} catch {
|
|
158
158
|
const shortClaim = buildCanonicalObjectFromLegacy(decrypted, {});
|
|
159
159
|
return {
|
|
@@ -167,16 +167,16 @@ export function parseBlobForPin(decrypted: string): ParsedBlob {
|
|
|
167
167
|
// v1 payload (plugin v3.0.0+): long-form fields + schema_version "1.x".
|
|
168
168
|
// Preserve the v1 structure so the pin path can emit v1 on output.
|
|
169
169
|
if (
|
|
170
|
-
typeof
|
|
171
|
-
typeof
|
|
172
|
-
typeof
|
|
173
|
-
|
|
170
|
+
typeof parsed.text === 'string' &&
|
|
171
|
+
typeof parsed.type === 'string' &&
|
|
172
|
+
typeof parsed.schema_version === 'string' &&
|
|
173
|
+
parsed.schema_version.startsWith('1.')
|
|
174
174
|
) {
|
|
175
175
|
const v1 = readV1Blob(decrypted);
|
|
176
176
|
if (v1) {
|
|
177
177
|
// Current status = pinStatus if present, else active.
|
|
178
178
|
const human: HumanStatus = v1.pinStatus === 'pinned' ? 'pinned' : 'active';
|
|
179
|
-
const shortProjection = v1ToShortKeyClaim(
|
|
179
|
+
const shortProjection = v1ToShortKeyClaim(parsed);
|
|
180
180
|
return {
|
|
181
181
|
source: {
|
|
182
182
|
kind: 'v1',
|
|
@@ -204,10 +204,10 @@ export function parseBlobForPin(decrypted: string): ParsedBlob {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
// v0 canonical Claim — short keys present.
|
|
207
|
-
if (typeof
|
|
208
|
-
const st = typeof
|
|
207
|
+
if (typeof parsed.t === 'string' && typeof parsed.c === 'string') {
|
|
208
|
+
const st = typeof parsed.st === 'string' ? parsed.st : 'a';
|
|
209
209
|
const human = SHORT_TO_HUMAN[st] ?? 'active';
|
|
210
|
-
const cloned = JSON.parse(JSON.stringify(
|
|
210
|
+
const cloned = JSON.parse(JSON.stringify(parsed)) as Record<string, unknown>;
|
|
211
211
|
return {
|
|
212
212
|
source: { kind: 'v0', claim: cloned },
|
|
213
213
|
claim: cloned,
|
|
@@ -217,9 +217,9 @@ export function parseBlobForPin(decrypted: string): ParsedBlob {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
// Legacy {text, metadata: {importance: 0-1}} shape.
|
|
220
|
-
if (typeof
|
|
221
|
-
const meta = (
|
|
222
|
-
const shortClaim = buildCanonicalObjectFromLegacy(
|
|
220
|
+
if (typeof parsed.text === 'string') {
|
|
221
|
+
const meta = (parsed.metadata as Record<string, unknown>) ?? {};
|
|
222
|
+
const shortClaim = buildCanonicalObjectFromLegacy(parsed.text, meta);
|
|
223
223
|
return {
|
|
224
224
|
source: { kind: 'v0', claim: shortClaim },
|
|
225
225
|
claim: shortClaim,
|
|
@@ -35,21 +35,21 @@ import {
|
|
|
35
35
|
mapTypeToCategory,
|
|
36
36
|
readV1Blob,
|
|
37
37
|
type PinStatus,
|
|
38
|
-
} from '
|
|
38
|
+
} from '../extraction/claims-helper.js';
|
|
39
39
|
import {
|
|
40
40
|
isValidMemoryType,
|
|
41
41
|
VALID_MEMORY_SCOPES,
|
|
42
42
|
V0_TO_V1_TYPE,
|
|
43
|
-
} from '
|
|
43
|
+
} from '../extraction/extractor.js';
|
|
44
44
|
import type {
|
|
45
45
|
MemoryType,
|
|
46
46
|
MemorySource,
|
|
47
47
|
MemoryScope,
|
|
48
48
|
MemoryVolatility,
|
|
49
|
-
} from '
|
|
50
|
-
import { PROTOBUF_VERSION_V4 } from '
|
|
51
|
-
import type { SubgraphSearchFact } from '
|
|
52
|
-
import { confirmIndexed, type ConfirmIndexedOptions } from '
|
|
49
|
+
} from '../extraction/extractor.js';
|
|
50
|
+
import { PROTOBUF_VERSION_V4 } from '../subgraph/subgraph-store.js';
|
|
51
|
+
import type { SubgraphSearchFact } from '../subgraph/subgraph-search.js';
|
|
52
|
+
import { confirmIndexed, type ConfirmIndexedOptions } from '../subgraph/confirm-indexed.js';
|
|
53
53
|
|
|
54
54
|
// Lazy-load WASM core — mirrors pin.ts pattern.
|
|
55
55
|
const requireWasm = createRequire(import.meta.url);
|
|
@@ -163,19 +163,19 @@ interface NormalizedFact {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
function projectFromDecrypted(decrypted: string): NormalizedFact | null {
|
|
166
|
-
let
|
|
166
|
+
let parsed: Record<string, unknown>;
|
|
167
167
|
try {
|
|
168
|
-
|
|
168
|
+
parsed = JSON.parse(decrypted) as Record<string, unknown>;
|
|
169
169
|
} catch {
|
|
170
170
|
return null;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
// v1 blob (schema_version "1.x")
|
|
174
174
|
if (
|
|
175
|
-
typeof
|
|
176
|
-
typeof
|
|
177
|
-
typeof
|
|
178
|
-
|
|
175
|
+
typeof parsed.text === 'string' &&
|
|
176
|
+
typeof parsed.type === 'string' &&
|
|
177
|
+
typeof parsed.schema_version === 'string' &&
|
|
178
|
+
parsed.schema_version.startsWith('1.')
|
|
179
179
|
) {
|
|
180
180
|
const v1 = readV1Blob(decrypted);
|
|
181
181
|
if (v1) {
|
|
@@ -198,20 +198,20 @@ function projectFromDecrypted(decrypted: string): NormalizedFact | null {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
// v0 short-key blob — upgrade to v1 shape.
|
|
201
|
-
if (typeof
|
|
202
|
-
const v0Type = typeof
|
|
201
|
+
if (typeof parsed.t === 'string' && typeof parsed.c === 'string') {
|
|
202
|
+
const v0Type = typeof parsed.c === 'string' ? parsed.c : 'fact';
|
|
203
203
|
const v1Type: MemoryType = (V0_TO_V1_TYPE as Record<string, MemoryType>)[v0Type] ?? 'claim';
|
|
204
|
-
const imp = typeof
|
|
205
|
-
const conf = typeof
|
|
206
|
-
const sa = typeof
|
|
204
|
+
const imp = typeof parsed.i === 'number' ? parsed.i : 5;
|
|
205
|
+
const conf = typeof parsed.cf === 'number' ? parsed.cf : 0.85;
|
|
206
|
+
const sa = typeof parsed.sa === 'string' ? parsed.sa : 'user';
|
|
207
207
|
const validSource: MemorySource = (
|
|
208
208
|
['user', 'user-inferred', 'assistant', 'external', 'derived'] as const
|
|
209
209
|
).includes(sa as MemorySource)
|
|
210
210
|
? (sa as MemorySource)
|
|
211
211
|
: 'user';
|
|
212
|
-
const ea = typeof
|
|
213
|
-
const entities = Array.isArray(
|
|
214
|
-
? (
|
|
212
|
+
const ea = typeof parsed.ea === 'string' ? parsed.ea : new Date().toISOString();
|
|
213
|
+
const entities = Array.isArray(parsed.e)
|
|
214
|
+
? (parsed.e as unknown[])
|
|
215
215
|
.map((e) => {
|
|
216
216
|
if (!e || typeof e !== 'object') return null;
|
|
217
217
|
const entity = e as Record<string, unknown>;
|
|
@@ -224,7 +224,7 @@ function projectFromDecrypted(decrypted: string): NormalizedFact | null {
|
|
|
224
224
|
.filter((e): e is { name: string; type: string; role?: string } => e !== null)
|
|
225
225
|
: undefined;
|
|
226
226
|
return {
|
|
227
|
-
text: typeof
|
|
227
|
+
text: typeof parsed.t === 'string' ? parsed.t : '',
|
|
228
228
|
type: v1Type,
|
|
229
229
|
source: validSource,
|
|
230
230
|
scope: undefined,
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* `resolveOnboardingState` already does; no network; no env reads.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
import type { OnboardingState } from '
|
|
33
|
+
import type { OnboardingState } from '../fs-helpers.js';
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Tool names gated on `state=active`. These are the bundled NATIVE memory
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@totalreclaw/totalreclaw",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.13",
|
|
4
4
|
"description": "End-to-end encrypted, agent-portable memory for OpenClaw and any LLM-agent runtime. XChaCha20-Poly1305 with protobuf v4 + on-chain Memory Taxonomy v1 (claim / preference / directive / commitment / episode / summary).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -34,8 +34,6 @@
|
|
|
34
34
|
"@scure/bip39": "^2.2.0",
|
|
35
35
|
"@totalreclaw/client": "^1.3.0",
|
|
36
36
|
"@totalreclaw/core": "^2.5.3",
|
|
37
|
-
"@types/qrcode": "^1.5.6",
|
|
38
|
-
"@types/ws": "^8.5.12",
|
|
39
37
|
"qrcode": "^1.5.4",
|
|
40
38
|
"qrcode-terminal": "^0.12.0",
|
|
41
39
|
"ws": "^8.18.3"
|
|
@@ -43,17 +41,19 @@
|
|
|
43
41
|
"//": "@huggingface/transformers + onnxruntime-node deliberately omitted from runtime deps. They are heavy native bundles (~700 MB peak install RAM) that OOM-killed the OpenClaw gateway on small VPS during `openclaw plugins install` in rc.21 (issue: 3.7 GB Hetzner host). rc.22 ships them via a lazy GitHub-Releases bundle (`embedder-v1.tar.gz`) downloaded on first call to embed(). See `embedder-network.ts` + `scripts/build-embedder-bundle.mjs`. The dev-deps below are for type-checking + bundle generation only; npm install of the plugin tarball never installs them.",
|
|
44
42
|
"devDependencies": {
|
|
45
43
|
"@huggingface/transformers": "^4.0.1",
|
|
44
|
+
"@types/qrcode": "^1.5.6",
|
|
45
|
+
"@types/ws": "^8.5.12",
|
|
46
46
|
"onnxruntime-node": "^1.24.0",
|
|
47
47
|
"typescript": "^5.5.0"
|
|
48
48
|
},
|
|
49
49
|
"main": "./dist/index.js",
|
|
50
50
|
"types": "./dist/index.d.ts",
|
|
51
51
|
"bin": {
|
|
52
|
-
"tr": "./dist/tr-cli.js"
|
|
52
|
+
"tr": "./dist/cli/tr-cli.js"
|
|
53
53
|
},
|
|
54
54
|
"files": [
|
|
55
55
|
"dist/",
|
|
56
|
-
"
|
|
56
|
+
"**/*.ts",
|
|
57
57
|
"import-adapters/",
|
|
58
58
|
"!**/*.test.ts",
|
|
59
59
|
"!pocv2-e2e-test.ts",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "rm -rf dist && tsc -p tsconfig.json --noCheck",
|
|
70
70
|
"verify-tarball": "node ../scripts/verify-tarball.mjs",
|
|
71
|
-
"test": "
|
|
71
|
+
"test": "node run-tests.mjs",
|
|
72
72
|
"smoke:dist": "npx tsx dist-esm-smoke.test.ts",
|
|
73
73
|
"check-scanner": "node ../scripts/check-scanner.mjs",
|
|
74
74
|
"check-version-drift": "node ../scripts/check-version-drift.mjs",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
|
|
37
37
|
import fs from 'node:fs';
|
|
38
38
|
|
|
39
|
-
import { CONFIG } from '
|
|
39
|
+
import { CONFIG } from '../config.js';
|
|
40
40
|
import {
|
|
41
41
|
loadCredentialsJson,
|
|
42
42
|
writeCredentialsJson,
|
|
43
43
|
deleteCredentialsFile,
|
|
44
44
|
type CredentialsFile,
|
|
45
|
-
} from '
|
|
45
|
+
} from '../fs-helpers.js';
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Provider interface — three methods cover the lifecycle:
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* crypto code for a copy change.
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
|
-
import { loadCredentialsJson, extractBootstrapMnemonic } from '
|
|
40
|
+
import { loadCredentialsJson, extractBootstrapMnemonic } from '../fs-helpers.js';
|
|
41
41
|
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
43
|
// Canonical copy — single source of truth for the welcome-on-first-run UX.
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
writeOnboardingState,
|
|
53
53
|
loadOnboardingState,
|
|
54
54
|
type OnboardingState,
|
|
55
|
-
} from '
|
|
55
|
+
} from '../fs-helpers.js';
|
|
56
56
|
|
|
57
57
|
// ---------------------------------------------------------------------------
|
|
58
58
|
// User-facing strings (centralised so tests can assert on them + localisation
|
|
@@ -665,15 +665,15 @@ export async function runNonInteractiveOnboard(
|
|
|
665
665
|
}
|
|
666
666
|
}
|
|
667
667
|
|
|
668
|
-
const
|
|
668
|
+
const onboardResult: NonInteractiveOnboardResult = {
|
|
669
669
|
ok: true,
|
|
670
670
|
action,
|
|
671
671
|
credentials_path: inputs.credentialsPath,
|
|
672
672
|
};
|
|
673
|
-
if (scopeAddress)
|
|
674
|
-
if (inputs.emitPhrase)
|
|
673
|
+
if (scopeAddress) onboardResult.scope_address = scopeAddress;
|
|
674
|
+
if (inputs.emitPhrase) onboardResult.mnemonic = mnemonic;
|
|
675
675
|
void state; // Touch for clarity — state is persisted via writeCredsAndState.
|
|
676
|
-
return
|
|
676
|
+
return onboardResult;
|
|
677
677
|
}
|
|
678
678
|
|
|
679
679
|
// ---------------------------------------------------------------------------
|
|
@@ -840,7 +840,7 @@ export function registerOnboardingCli(
|
|
|
840
840
|
phrase = await readAllStdin();
|
|
841
841
|
}
|
|
842
842
|
|
|
843
|
-
const
|
|
843
|
+
const onboardResult = await runNonInteractiveOnboard({
|
|
844
844
|
credentialsPath: opts.credentialsPath,
|
|
845
845
|
statePath: opts.statePath,
|
|
846
846
|
mode,
|
|
@@ -854,13 +854,13 @@ export function registerOnboardingCli(
|
|
|
854
854
|
// the JSON payload is about to include the plaintext phrase.
|
|
855
855
|
// stderr is intentional: stdout must remain a single
|
|
856
856
|
// machine-parseable JSON line.
|
|
857
|
-
if (cliOpts.emitPhrase &&
|
|
857
|
+
if (cliOpts.emitPhrase && onboardResult.ok && onboardResult.mnemonic) {
|
|
858
858
|
process.stderr.write(PHRASE_PRINT_DEPRECATION_WARNING);
|
|
859
859
|
}
|
|
860
|
-
process.stdout.write(JSON.stringify(
|
|
860
|
+
process.stdout.write(JSON.stringify(onboardResult) + '\n');
|
|
861
861
|
} else {
|
|
862
|
-
if (
|
|
863
|
-
if (
|
|
862
|
+
if (onboardResult.ok) {
|
|
863
|
+
if (onboardResult.mnemonic) {
|
|
864
864
|
process.stderr.write(PHRASE_PRINT_DEPRECATION_WARNING);
|
|
865
865
|
process.stderr.write(
|
|
866
866
|
'WARNING: --emit-phrase was set. The plaintext recovery phrase was returned.\n' +
|
|
@@ -869,15 +869,15 @@ export function registerOnboardingCli(
|
|
|
869
869
|
);
|
|
870
870
|
}
|
|
871
871
|
process.stdout.write(
|
|
872
|
-
`onboarding: ok action=${
|
|
873
|
-
(
|
|
874
|
-
`credentials=${
|
|
872
|
+
`onboarding: ok action=${onboardResult.action} ` +
|
|
873
|
+
(onboardResult.scope_address ? `scope_address=${onboardResult.scope_address} ` : '') +
|
|
874
|
+
`credentials=${onboardResult.credentials_path}\n`,
|
|
875
875
|
);
|
|
876
876
|
} else {
|
|
877
|
-
process.stderr.write(`onboarding: ${
|
|
877
|
+
process.stderr.write(`onboarding: ${onboardResult.error}: ${onboardResult.error_detail ?? ''}\n`);
|
|
878
878
|
}
|
|
879
879
|
}
|
|
880
|
-
process.exit(
|
|
880
|
+
process.exit(onboardResult.ok ? 0 : 1);
|
|
881
881
|
}
|
|
882
882
|
|
|
883
883
|
if (cliOpts.json) {
|
|
@@ -890,18 +890,18 @@ export function registerOnboardingCli(
|
|
|
890
890
|
// Interactive path — original 3.2.0 behaviour preserved in full.
|
|
891
891
|
const io = buildDefaultIo();
|
|
892
892
|
try {
|
|
893
|
-
const
|
|
893
|
+
const wizardResult = await runOnboardingWizard({
|
|
894
894
|
credentialsPath: opts.credentialsPath,
|
|
895
895
|
statePath: opts.statePath,
|
|
896
896
|
io,
|
|
897
897
|
});
|
|
898
|
-
if (
|
|
899
|
-
opts.logger.warn(`onboarding wizard exited with error: ${
|
|
898
|
+
if (wizardResult.error) {
|
|
899
|
+
opts.logger.warn(`onboarding wizard exited with error: ${wizardResult.error}`);
|
|
900
900
|
io.close();
|
|
901
901
|
process.exit(1);
|
|
902
902
|
}
|
|
903
|
-
if (
|
|
904
|
-
opts.logger.info(`onboarding: state=active createdBy=${
|
|
903
|
+
if (wizardResult.choice === 'generate' || wizardResult.choice === 'import') {
|
|
904
|
+
opts.logger.info(`onboarding: state=active createdBy=${wizardResult.state?.createdBy}`);
|
|
905
905
|
}
|
|
906
906
|
} catch (err) {
|
|
907
907
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -51,15 +51,15 @@ import {
|
|
|
51
51
|
loadCredentialsJson,
|
|
52
52
|
writeCredentialsJson,
|
|
53
53
|
writeOnboardingState,
|
|
54
|
-
} from '
|
|
54
|
+
} from '../fs-helpers.js';
|
|
55
55
|
import {
|
|
56
56
|
awaitPhraseUpload,
|
|
57
57
|
openRemotePairSession,
|
|
58
58
|
} from './pair-remote-client.js';
|
|
59
|
-
import { setRecoveryPhraseOverride } from '
|
|
59
|
+
import { setRecoveryPhraseOverride } from '../config.js';
|
|
60
60
|
import { encodePng, encodeUnicode } from './pair-qr.js';
|
|
61
|
-
import { deriveKeys, computeAuthKeyHash } from '
|
|
62
|
-
import { createApiClient } from '
|
|
61
|
+
import { deriveKeys, computeAuthKeyHash } from '../crypto/crypto.js';
|
|
62
|
+
import { createApiClient } from '../billing/api-client.js';
|
|
63
63
|
import type {
|
|
64
64
|
PairCliIo,
|
|
65
65
|
PairCliJsonPayload,
|
|
@@ -270,7 +270,7 @@ export async function runRelayPairCli(
|
|
|
270
270
|
};
|
|
271
271
|
|
|
272
272
|
try {
|
|
273
|
-
const
|
|
273
|
+
const completion = await awaitPhraseUpload(session, {
|
|
274
274
|
phraseValidator: (p: string) => validateMnemonic(p, wordlist),
|
|
275
275
|
completePairing: async ({ mnemonic }) => {
|
|
276
276
|
try {
|
|
@@ -296,8 +296,8 @@ export async function runRelayPairCli(
|
|
|
296
296
|
// serves both protocols on the same host.
|
|
297
297
|
const httpsBase = opts.relayBaseUrl.replace(/^ws/, 'http').replace(/\/+$/, '');
|
|
298
298
|
const apiClient = createApiClient(httpsBase);
|
|
299
|
-
const
|
|
300
|
-
registeredUserId =
|
|
299
|
+
const registerResult = await apiClient.register(authKeyHash, saltHex);
|
|
300
|
+
registeredUserId = registerResult.user_id;
|
|
301
301
|
opts.logger.info(
|
|
302
302
|
`pair-cli (relay): registered user_id=${registeredUserId} (salt + auth-key persisted)`,
|
|
303
303
|
);
|
|
@@ -361,12 +361,12 @@ export async function runRelayPairCli(
|
|
|
361
361
|
emitStatus('\nCanceled. Pairing session invalidated.\n');
|
|
362
362
|
return { status: 'canceled', sid: session.token };
|
|
363
363
|
}
|
|
364
|
-
if (
|
|
364
|
+
if (completion.state === 'active') {
|
|
365
365
|
emitStatus('\nPairing complete. Account is active.\n');
|
|
366
366
|
return { status: 'completed', sid: session.token };
|
|
367
367
|
}
|
|
368
|
-
emitStatus(`\nPairing failed: ${
|
|
369
|
-
return { status: 'error', sid: session.token, error:
|
|
368
|
+
emitStatus(`\nPairing failed: ${completion.error ?? 'unknown_error'}\n`);
|
|
369
|
+
return { status: 'error', sid: session.token, error: completion.error ?? 'unknown_error' };
|
|
370
370
|
} catch (err) {
|
|
371
371
|
if (canceled) {
|
|
372
372
|
emitStatus('\nCanceled. Pairing session invalidated.\n');
|
|
@@ -542,7 +542,7 @@ export function buildPairRoutes(cfg: PairHttpConfig): PairRouteBundle {
|
|
|
542
542
|
// sid/mode for log correlation.
|
|
543
543
|
void (async (): Promise<void> => {
|
|
544
544
|
try {
|
|
545
|
-
const
|
|
545
|
+
const completion = await awaitPhraseUpload(session, {
|
|
546
546
|
phraseValidator: validate,
|
|
547
547
|
timeoutMs: cfg.initAwaitTimeoutMs,
|
|
548
548
|
completePairing: async ({ mnemonic }) => {
|
|
@@ -557,13 +557,13 @@ export function buildPairRoutes(cfg: PairHttpConfig): PairRouteBundle {
|
|
|
557
557
|
return cfg.completePairing({ mnemonic, session: sessionLike });
|
|
558
558
|
},
|
|
559
559
|
});
|
|
560
|
-
if (
|
|
560
|
+
if (completion.state === 'active') {
|
|
561
561
|
cfg.logger.info(
|
|
562
562
|
`pair-http /init: session ${redactSid(session.token)} completed in-process; onboarding active`,
|
|
563
563
|
);
|
|
564
564
|
} else {
|
|
565
565
|
cfg.logger.warn(
|
|
566
|
-
`pair-http /init: session ${redactSid(session.token)} completion non-active: ${
|
|
566
|
+
`pair-http /init: session ${redactSid(session.token)} completion non-active: ${completion.error ?? 'unknown'}`,
|
|
567
567
|
);
|
|
568
568
|
}
|
|
569
569
|
} catch (err) {
|
|
@@ -259,9 +259,9 @@ export async function openRemotePairSession(
|
|
|
259
259
|
try {
|
|
260
260
|
const text = typeof raw === 'string' ? raw : Buffer.from(raw as ArrayBuffer).toString('utf-8');
|
|
261
261
|
msg = JSON.parse(text);
|
|
262
|
-
} catch {
|
|
262
|
+
} catch (err) {
|
|
263
263
|
safeClose(ws);
|
|
264
|
-
throw new Error('pair-remote-client: opened frame not valid JSON');
|
|
264
|
+
throw new Error('pair-remote-client: opened frame not valid JSON', { cause: err });
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
if (msg.type === 'error') {
|
|
@@ -331,10 +331,10 @@ export async function awaitPhraseUpload(
|
|
|
331
331
|
try {
|
|
332
332
|
const text = typeof raw === 'string' ? raw : Buffer.from(raw as ArrayBuffer).toString('utf-8');
|
|
333
333
|
msg = JSON.parse(text);
|
|
334
|
-
} catch {
|
|
334
|
+
} catch (err) {
|
|
335
335
|
safeSend(ws, { type: 'nack', error: 'bad_json' });
|
|
336
336
|
safeClose(ws);
|
|
337
|
-
throw new Error('pair-remote-client: forward frame not valid JSON');
|
|
337
|
+
throw new Error('pair-remote-client: forward frame not valid JSON', { cause: err });
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
if (msg.type !== 'forward') {
|
|
@@ -395,9 +395,9 @@ export async function awaitPhraseUpload(
|
|
|
395
395
|
|
|
396
396
|
// Hand off to the caller-supplied completion handler. Wrapped in try/finally
|
|
397
397
|
// so we always drop our own reference to the mnemonic.
|
|
398
|
-
let
|
|
398
|
+
let completion: RelayCompletionResult;
|
|
399
399
|
try {
|
|
400
|
-
|
|
400
|
+
completion = await opts.completePairing({ mnemonic, session });
|
|
401
401
|
} catch (err) {
|
|
402
402
|
safeSend(ws, { type: 'nack', error: 'completion_failed' });
|
|
403
403
|
safeClose(ws);
|
|
@@ -408,15 +408,15 @@ export async function awaitPhraseUpload(
|
|
|
408
408
|
mnemonic = '';
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
-
if (
|
|
412
|
-
safeSend(ws, { type: 'nack', error:
|
|
411
|
+
if (completion.state !== 'active') {
|
|
412
|
+
safeSend(ws, { type: 'nack', error: completion.error ?? 'completion_failed' });
|
|
413
413
|
safeClose(ws);
|
|
414
|
-
return
|
|
414
|
+
return completion;
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
safeSend(ws, { type: 'ack' });
|
|
418
418
|
safeClose(ws);
|
|
419
|
-
return
|
|
419
|
+
return completion;
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
/**
|
|
@@ -592,16 +592,16 @@ export async function updatePairSession(
|
|
|
592
592
|
}
|
|
593
593
|
const current = pruned.file.sessions[idx];
|
|
594
594
|
const next = mutate(current);
|
|
595
|
-
let
|
|
595
|
+
let mutatedSession: PairSession | null;
|
|
596
596
|
if (next === null) {
|
|
597
597
|
pruned.file.sessions.splice(idx, 1);
|
|
598
|
-
|
|
598
|
+
mutatedSession = null;
|
|
599
599
|
} else {
|
|
600
600
|
pruned.file.sessions[idx] = next;
|
|
601
|
-
|
|
601
|
+
mutatedSession = next;
|
|
602
602
|
}
|
|
603
603
|
writePairSessionsFileSync(sessionsPath, pruned.file);
|
|
604
|
-
return
|
|
604
|
+
return mutatedSession;
|
|
605
605
|
} finally {
|
|
606
606
|
release();
|
|
607
607
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Plugin configSchema — static JSON-schema for the OpenClaw plugin config.
|
|
3
|
+
// Extracted from index.ts; pure data, no runtime state.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
|
|
6
|
+
export const CONFIG_SCHEMA = {
|
|
7
|
+
type: 'object',
|
|
8
|
+
additionalProperties: false,
|
|
9
|
+
properties: {
|
|
10
|
+
publicUrl: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description:
|
|
13
|
+
"Public gateway URL for QR pairing (e.g. 'https://gateway.example.com:18789'). Overrides the auto-resolution cascade in buildPairingUrl.",
|
|
14
|
+
},
|
|
15
|
+
extraction: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
properties: {
|
|
19
|
+
enabled: {
|
|
20
|
+
type: 'boolean',
|
|
21
|
+
description: 'Enable/disable auto-extraction (default: true)',
|
|
22
|
+
},
|
|
23
|
+
model: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description:
|
|
26
|
+
"Shorthand: override just the extraction model (e.g., 'glm-4.5-flash', 'gpt-4.1-mini'). For a full provider override use extraction.llm.",
|
|
27
|
+
},
|
|
28
|
+
interval: {
|
|
29
|
+
type: 'number',
|
|
30
|
+
description: 'Number of turns between automatic extractions (default: 3)',
|
|
31
|
+
},
|
|
32
|
+
maxFactsPerExtraction: {
|
|
33
|
+
type: 'number',
|
|
34
|
+
description: 'Hard cap on facts extracted per turn (default: 15)',
|
|
35
|
+
},
|
|
36
|
+
llm: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
additionalProperties: false,
|
|
39
|
+
description:
|
|
40
|
+
'Explicit LLM override block. Highest-priority tier in the extraction-provider cascade. Any subset of provider+apiKey is enough to pin a provider.',
|
|
41
|
+
properties: {
|
|
42
|
+
provider: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description:
|
|
45
|
+
"Provider name: zai | openai | anthropic | gemini | google | mistral | groq | deepseek | openrouter | xai | together | cerebras.",
|
|
46
|
+
},
|
|
47
|
+
model: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'Explicit model id. If omitted, deriveCheapModel(provider) picks a sensible default.',
|
|
50
|
+
},
|
|
51
|
+
apiKey: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'API key for the selected provider. Required for the override to take effect.',
|
|
54
|
+
},
|
|
55
|
+
baseUrl: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Override the provider base URL (self-hosted / custom gateway setups).',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
} as const;
|