@totalreclaw/totalreclaw 3.3.12 → 3.3.13-rc.1
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
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Embedding generation has been moved to embedding.ts (local ONNX model via
|
|
9
9
|
* @huggingface/transformers). No API key needed for embeddings.
|
|
10
10
|
*/
|
|
11
|
-
import { CONFIG } from '
|
|
11
|
+
import { CONFIG } from '../config.js';
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Provider mappings
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
@@ -754,4 +754,4 @@ async function chatCompletionAnthropic(config, messages, maxTokens, temperature,
|
|
|
754
754
|
// see embedding.ts + embedder-loader.ts.
|
|
755
755
|
export { generateEmbedding, getEmbeddingDims, getEmbeddingModelId, configureEmbedder,
|
|
756
756
|
// 3.3.3-rc.1 (#187): pre-pair bundle prefetch
|
|
757
|
-
prefetchEmbedderBundle, } from '
|
|
757
|
+
prefetchEmbedderBundle, } from '../embedding/embedding.js';
|
|
@@ -72,12 +72,12 @@ export class PluginHotCache {
|
|
|
72
72
|
if (!fs.existsSync(this.cachePath))
|
|
73
73
|
return;
|
|
74
74
|
try {
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
75
|
+
const encryptedFile = fs.readFileSync(this.cachePath);
|
|
76
|
+
if (encryptedFile.length < IV_LENGTH + TAG_LENGTH)
|
|
77
77
|
return;
|
|
78
|
-
const iv =
|
|
79
|
-
const tag =
|
|
80
|
-
const ciphertext =
|
|
78
|
+
const iv = encryptedFile.subarray(0, IV_LENGTH);
|
|
79
|
+
const tag = encryptedFile.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH);
|
|
80
|
+
const ciphertext = encryptedFile.subarray(IV_LENGTH + TAG_LENGTH);
|
|
81
81
|
const decipher = crypto.createDecipheriv('aes-256-gcm', this.key, iv);
|
|
82
82
|
decipher.setAuthTag(tag);
|
|
83
83
|
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
// (no OpenClaw type import) so the plugin compiles without depending on
|
|
65
65
|
// OpenClaw's type package.
|
|
66
66
|
// ---------------------------------------------------------------------------
|
|
67
|
-
import { EXTRACTION_SYSTEM_PROMPT } from '
|
|
67
|
+
import { EXTRACTION_SYSTEM_PROMPT } from '../extraction/extractor.js';
|
|
68
68
|
// ---------------------------------------------------------------------------
|
|
69
69
|
// Constants
|
|
70
70
|
// ---------------------------------------------------------------------------
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import crypto from 'node:crypto';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
|
-
import { buildV1ClaimBlob, mapTypeToCategory, readV1Blob, } from '
|
|
14
|
-
import { findLoserClaimInDecisionLog, maybeWriteFeedbackForPin, } from '
|
|
15
|
-
import { isValidMemoryType, V0_TO_V1_TYPE } from '
|
|
16
|
-
import { PROTOBUF_VERSION_V4 } from '
|
|
17
|
-
import { confirmIndexed } from '
|
|
13
|
+
import { buildV1ClaimBlob, mapTypeToCategory, readV1Blob, } from '../extraction/claims-helper.js';
|
|
14
|
+
import { findLoserClaimInDecisionLog, maybeWriteFeedbackForPin, } from '../contradiction/contradiction-sync.js';
|
|
15
|
+
import { isValidMemoryType, V0_TO_V1_TYPE } from '../extraction/extractor.js';
|
|
16
|
+
import { PROTOBUF_VERSION_V4 } from '../subgraph/subgraph-store.js';
|
|
17
|
+
import { confirmIndexed } from '../subgraph/confirm-indexed.js';
|
|
18
18
|
// Lazy-load WASM core (mirrors claims-helper.ts pattern — plays nicely under
|
|
19
19
|
// both the OpenClaw runtime (CJS-ish tsx) and bare Node ESM used by tests).
|
|
20
20
|
const requireWasm = createRequire(import.meta.url);
|
|
@@ -64,9 +64,9 @@ const HUMAN_TO_SHORT = {
|
|
|
64
64
|
};
|
|
65
65
|
/** Parse a decrypted blob into a canonical mutable Claim + current human status. */
|
|
66
66
|
export function parseBlobForPin(decrypted) {
|
|
67
|
-
let
|
|
67
|
+
let parsed;
|
|
68
68
|
try {
|
|
69
|
-
|
|
69
|
+
parsed = JSON.parse(decrypted);
|
|
70
70
|
}
|
|
71
71
|
catch {
|
|
72
72
|
const shortClaim = buildCanonicalObjectFromLegacy(decrypted, {});
|
|
@@ -79,15 +79,15 @@ export function parseBlobForPin(decrypted) {
|
|
|
79
79
|
}
|
|
80
80
|
// v1 payload (plugin v3.0.0+): long-form fields + schema_version "1.x".
|
|
81
81
|
// Preserve the v1 structure so the pin path can emit v1 on output.
|
|
82
|
-
if (typeof
|
|
83
|
-
typeof
|
|
84
|
-
typeof
|
|
85
|
-
|
|
82
|
+
if (typeof parsed.text === 'string' &&
|
|
83
|
+
typeof parsed.type === 'string' &&
|
|
84
|
+
typeof parsed.schema_version === 'string' &&
|
|
85
|
+
parsed.schema_version.startsWith('1.')) {
|
|
86
86
|
const v1 = readV1Blob(decrypted);
|
|
87
87
|
if (v1) {
|
|
88
88
|
// Current status = pinStatus if present, else active.
|
|
89
89
|
const human = v1.pinStatus === 'pinned' ? 'pinned' : 'active';
|
|
90
|
-
const shortProjection = v1ToShortKeyClaim(
|
|
90
|
+
const shortProjection = v1ToShortKeyClaim(parsed);
|
|
91
91
|
return {
|
|
92
92
|
source: {
|
|
93
93
|
kind: 'v1',
|
|
@@ -114,10 +114,10 @@ export function parseBlobForPin(decrypted) {
|
|
|
114
114
|
// readV1Blob returned null — fall through to v0 path.
|
|
115
115
|
}
|
|
116
116
|
// v0 canonical Claim — short keys present.
|
|
117
|
-
if (typeof
|
|
118
|
-
const st = typeof
|
|
117
|
+
if (typeof parsed.t === 'string' && typeof parsed.c === 'string') {
|
|
118
|
+
const st = typeof parsed.st === 'string' ? parsed.st : 'a';
|
|
119
119
|
const human = SHORT_TO_HUMAN[st] ?? 'active';
|
|
120
|
-
const cloned = JSON.parse(JSON.stringify(
|
|
120
|
+
const cloned = JSON.parse(JSON.stringify(parsed));
|
|
121
121
|
return {
|
|
122
122
|
source: { kind: 'v0', claim: cloned },
|
|
123
123
|
claim: cloned,
|
|
@@ -126,9 +126,9 @@ export function parseBlobForPin(decrypted) {
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
// Legacy {text, metadata: {importance: 0-1}} shape.
|
|
129
|
-
if (typeof
|
|
130
|
-
const meta =
|
|
131
|
-
const shortClaim = buildCanonicalObjectFromLegacy(
|
|
129
|
+
if (typeof parsed.text === 'string') {
|
|
130
|
+
const meta = parsed.metadata ?? {};
|
|
131
|
+
const shortClaim = buildCanonicalObjectFromLegacy(parsed.text, meta);
|
|
132
132
|
return {
|
|
133
133
|
source: { kind: 'v0', claim: shortClaim },
|
|
134
134
|
claim: shortClaim,
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import crypto from 'node:crypto';
|
|
31
31
|
import { createRequire } from 'node:module';
|
|
32
|
-
import { buildV1ClaimBlob, mapTypeToCategory, readV1Blob, } from '
|
|
33
|
-
import { isValidMemoryType, VALID_MEMORY_SCOPES, V0_TO_V1_TYPE, } from '
|
|
34
|
-
import { PROTOBUF_VERSION_V4 } from '
|
|
35
|
-
import { confirmIndexed } from '
|
|
32
|
+
import { buildV1ClaimBlob, mapTypeToCategory, readV1Blob, } from '../extraction/claims-helper.js';
|
|
33
|
+
import { isValidMemoryType, VALID_MEMORY_SCOPES, V0_TO_V1_TYPE, } from '../extraction/extractor.js';
|
|
34
|
+
import { PROTOBUF_VERSION_V4 } from '../subgraph/subgraph-store.js';
|
|
35
|
+
import { confirmIndexed } from '../subgraph/confirm-indexed.js';
|
|
36
36
|
// Lazy-load WASM core — mirrors pin.ts pattern.
|
|
37
37
|
const requireWasm = createRequire(import.meta.url);
|
|
38
38
|
let _wasm = null;
|
|
@@ -58,18 +58,18 @@ function encodeFactProtobufLocal(fact, version) {
|
|
|
58
58
|
return Buffer.from(getWasm().encodeFactProtobuf(json));
|
|
59
59
|
}
|
|
60
60
|
function projectFromDecrypted(decrypted) {
|
|
61
|
-
let
|
|
61
|
+
let parsed;
|
|
62
62
|
try {
|
|
63
|
-
|
|
63
|
+
parsed = JSON.parse(decrypted);
|
|
64
64
|
}
|
|
65
65
|
catch {
|
|
66
66
|
return null;
|
|
67
67
|
}
|
|
68
68
|
// v1 blob (schema_version "1.x")
|
|
69
|
-
if (typeof
|
|
70
|
-
typeof
|
|
71
|
-
typeof
|
|
72
|
-
|
|
69
|
+
if (typeof parsed.text === 'string' &&
|
|
70
|
+
typeof parsed.type === 'string' &&
|
|
71
|
+
typeof parsed.schema_version === 'string' &&
|
|
72
|
+
parsed.schema_version.startsWith('1.')) {
|
|
73
73
|
const v1 = readV1Blob(decrypted);
|
|
74
74
|
if (v1) {
|
|
75
75
|
return {
|
|
@@ -90,18 +90,18 @@ function projectFromDecrypted(decrypted) {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
// v0 short-key blob — upgrade to v1 shape.
|
|
93
|
-
if (typeof
|
|
94
|
-
const v0Type = typeof
|
|
93
|
+
if (typeof parsed.t === 'string' && typeof parsed.c === 'string') {
|
|
94
|
+
const v0Type = typeof parsed.c === 'string' ? parsed.c : 'fact';
|
|
95
95
|
const v1Type = V0_TO_V1_TYPE[v0Type] ?? 'claim';
|
|
96
|
-
const imp = typeof
|
|
97
|
-
const conf = typeof
|
|
98
|
-
const sa = typeof
|
|
96
|
+
const imp = typeof parsed.i === 'number' ? parsed.i : 5;
|
|
97
|
+
const conf = typeof parsed.cf === 'number' ? parsed.cf : 0.85;
|
|
98
|
+
const sa = typeof parsed.sa === 'string' ? parsed.sa : 'user';
|
|
99
99
|
const validSource = ['user', 'user-inferred', 'assistant', 'external', 'derived'].includes(sa)
|
|
100
100
|
? sa
|
|
101
101
|
: 'user';
|
|
102
|
-
const ea = typeof
|
|
103
|
-
const entities = Array.isArray(
|
|
104
|
-
?
|
|
102
|
+
const ea = typeof parsed.ea === 'string' ? parsed.ea : new Date().toISOString();
|
|
103
|
+
const entities = Array.isArray(parsed.e)
|
|
104
|
+
? parsed.e
|
|
105
105
|
.map((e) => {
|
|
106
106
|
if (!e || typeof e !== 'object')
|
|
107
107
|
return null;
|
|
@@ -116,7 +116,7 @@ function projectFromDecrypted(decrypted) {
|
|
|
116
116
|
.filter((e) => e !== null)
|
|
117
117
|
: undefined;
|
|
118
118
|
return {
|
|
119
|
-
text: typeof
|
|
119
|
+
text: typeof parsed.t === 'string' ? parsed.t : '',
|
|
120
120
|
type: v1Type,
|
|
121
121
|
source: validSource,
|
|
122
122
|
scope: undefined,
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
* the source of truth; writing back would split it.
|
|
35
35
|
*/
|
|
36
36
|
import fs from 'node:fs';
|
|
37
|
-
import { CONFIG } from '
|
|
38
|
-
import { loadCredentialsJson, writeCredentialsJson, deleteCredentialsFile, } from '
|
|
37
|
+
import { CONFIG } from '../config.js';
|
|
38
|
+
import { loadCredentialsJson, writeCredentialsJson, deleteCredentialsFile, } from '../fs-helpers.js';
|
|
39
39
|
/**
|
|
40
40
|
* Default provider — delegates to the existing fs-helpers functions.
|
|
41
41
|
* Behavior is identical to direct `loadCredentialsJson` / `writeCredentialsJson`
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* (`mnemonic`, etc.) are intentionally kept so we do not churn the
|
|
37
37
|
* crypto code for a copy change.
|
|
38
38
|
*/
|
|
39
|
-
import { loadCredentialsJson, extractBootstrapMnemonic } from '
|
|
39
|
+
import { loadCredentialsJson, extractBootstrapMnemonic } from '../fs-helpers.js';
|
|
40
40
|
// ---------------------------------------------------------------------------
|
|
41
41
|
// Canonical copy — single source of truth for the welcome-on-first-run UX.
|
|
42
42
|
// Tests import these constants and assert on exact-match substrings; the
|
|
@@ -43,7 +43,7 @@ import path from 'node:path';
|
|
|
43
43
|
import readline from 'node:readline/promises';
|
|
44
44
|
import { generateMnemonic, validateMnemonic } from '@scure/bip39';
|
|
45
45
|
import { wordlist } from '@scure/bip39/wordlists/english.js';
|
|
46
|
-
import { writeCredentialsJson, loadCredentialsJson, writeOnboardingState, loadOnboardingState, } from '
|
|
46
|
+
import { writeCredentialsJson, loadCredentialsJson, writeOnboardingState, loadOnboardingState, } from '../fs-helpers.js';
|
|
47
47
|
// ---------------------------------------------------------------------------
|
|
48
48
|
// User-facing strings (centralised so tests can assert on them + localisation
|
|
49
49
|
// has one place to grow into later).
|
|
@@ -499,17 +499,17 @@ export async function runNonInteractiveOnboard(inputs) {
|
|
|
499
499
|
scopeAddress = undefined;
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
|
-
const
|
|
502
|
+
const onboardResult = {
|
|
503
503
|
ok: true,
|
|
504
504
|
action,
|
|
505
505
|
credentials_path: inputs.credentialsPath,
|
|
506
506
|
};
|
|
507
507
|
if (scopeAddress)
|
|
508
|
-
|
|
508
|
+
onboardResult.scope_address = scopeAddress;
|
|
509
509
|
if (inputs.emitPhrase)
|
|
510
|
-
|
|
510
|
+
onboardResult.mnemonic = mnemonic;
|
|
511
511
|
void state; // Touch for clarity — state is persisted via writeCredsAndState.
|
|
512
|
-
return
|
|
512
|
+
return onboardResult;
|
|
513
513
|
}
|
|
514
514
|
// ---------------------------------------------------------------------------
|
|
515
515
|
// CLI registration
|
|
@@ -642,7 +642,7 @@ export function registerOnboardingCli(program, opts) {
|
|
|
642
642
|
if (phrase === '-') {
|
|
643
643
|
phrase = await readAllStdin();
|
|
644
644
|
}
|
|
645
|
-
const
|
|
645
|
+
const onboardResult = await runNonInteractiveOnboard({
|
|
646
646
|
credentialsPath: opts.credentialsPath,
|
|
647
647
|
statePath: opts.statePath,
|
|
648
648
|
mode,
|
|
@@ -655,28 +655,28 @@ export function registerOnboardingCli(program, opts) {
|
|
|
655
655
|
// the JSON payload is about to include the plaintext phrase.
|
|
656
656
|
// stderr is intentional: stdout must remain a single
|
|
657
657
|
// machine-parseable JSON line.
|
|
658
|
-
if (cliOpts.emitPhrase &&
|
|
658
|
+
if (cliOpts.emitPhrase && onboardResult.ok && onboardResult.mnemonic) {
|
|
659
659
|
process.stderr.write(PHRASE_PRINT_DEPRECATION_WARNING);
|
|
660
660
|
}
|
|
661
|
-
process.stdout.write(JSON.stringify(
|
|
661
|
+
process.stdout.write(JSON.stringify(onboardResult) + '\n');
|
|
662
662
|
}
|
|
663
663
|
else {
|
|
664
|
-
if (
|
|
665
|
-
if (
|
|
664
|
+
if (onboardResult.ok) {
|
|
665
|
+
if (onboardResult.mnemonic) {
|
|
666
666
|
process.stderr.write(PHRASE_PRINT_DEPRECATION_WARNING);
|
|
667
667
|
process.stderr.write('WARNING: --emit-phrase was set. The plaintext recovery phrase was returned.\n' +
|
|
668
668
|
'For agent-driven flows, prefer reading ~/.totalreclaw/credentials.json directly ' +
|
|
669
669
|
'in the user\'s terminal instead of echoing the phrase.\n');
|
|
670
670
|
}
|
|
671
|
-
process.stdout.write(`onboarding: ok action=${
|
|
672
|
-
(
|
|
673
|
-
`credentials=${
|
|
671
|
+
process.stdout.write(`onboarding: ok action=${onboardResult.action} ` +
|
|
672
|
+
(onboardResult.scope_address ? `scope_address=${onboardResult.scope_address} ` : '') +
|
|
673
|
+
`credentials=${onboardResult.credentials_path}\n`);
|
|
674
674
|
}
|
|
675
675
|
else {
|
|
676
|
-
process.stderr.write(`onboarding: ${
|
|
676
|
+
process.stderr.write(`onboarding: ${onboardResult.error}: ${onboardResult.error_detail ?? ''}\n`);
|
|
677
677
|
}
|
|
678
678
|
}
|
|
679
|
-
process.exit(
|
|
679
|
+
process.exit(onboardResult.ok ? 0 : 1);
|
|
680
680
|
}
|
|
681
681
|
if (cliOpts.json) {
|
|
682
682
|
process.stderr.write('--json requires --non-interactive. Use: openclaw totalreclaw onboard --non-interactive --json --mode generate\n');
|
|
@@ -685,18 +685,18 @@ export function registerOnboardingCli(program, opts) {
|
|
|
685
685
|
// Interactive path — original 3.2.0 behaviour preserved in full.
|
|
686
686
|
const io = buildDefaultIo();
|
|
687
687
|
try {
|
|
688
|
-
const
|
|
688
|
+
const wizardResult = await runOnboardingWizard({
|
|
689
689
|
credentialsPath: opts.credentialsPath,
|
|
690
690
|
statePath: opts.statePath,
|
|
691
691
|
io,
|
|
692
692
|
});
|
|
693
|
-
if (
|
|
694
|
-
opts.logger.warn(`onboarding wizard exited with error: ${
|
|
693
|
+
if (wizardResult.error) {
|
|
694
|
+
opts.logger.warn(`onboarding wizard exited with error: ${wizardResult.error}`);
|
|
695
695
|
io.close();
|
|
696
696
|
process.exit(1);
|
|
697
697
|
}
|
|
698
|
-
if (
|
|
699
|
-
opts.logger.info(`onboarding: state=active createdBy=${
|
|
698
|
+
if (wizardResult.choice === 'generate' || wizardResult.choice === 'import') {
|
|
699
|
+
opts.logger.info(`onboarding: state=active createdBy=${wizardResult.state?.createdBy}`);
|
|
700
700
|
}
|
|
701
701
|
}
|
|
702
702
|
catch (err) {
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
*/
|
|
46
46
|
import { validateMnemonic } from '@scure/bip39';
|
|
47
47
|
import { wordlist } from '@scure/bip39/wordlists/english.js';
|
|
48
|
-
import { loadCredentialsJson, writeCredentialsJson, writeOnboardingState, } from '
|
|
48
|
+
import { loadCredentialsJson, writeCredentialsJson, writeOnboardingState, } from '../fs-helpers.js';
|
|
49
49
|
import { awaitPhraseUpload, openRemotePairSession, } from './pair-remote-client.js';
|
|
50
|
-
import { setRecoveryPhraseOverride } from '
|
|
50
|
+
import { setRecoveryPhraseOverride } from '../config.js';
|
|
51
51
|
import { encodePng, encodeUnicode } from './pair-qr.js';
|
|
52
|
-
import { deriveKeys, computeAuthKeyHash } from '
|
|
53
|
-
import { createApiClient } from '
|
|
52
|
+
import { deriveKeys, computeAuthKeyHash } from '../crypto/crypto.js';
|
|
53
|
+
import { createApiClient } from '../billing/api-client.js';
|
|
54
54
|
/**
|
|
55
55
|
* Run the relay-mode pair CLI. Mirrors `runPairCli`'s exit-code semantics:
|
|
56
56
|
* - `completed` (status 0)
|
|
@@ -214,7 +214,7 @@ export async function runRelayPairCli(mode, opts) {
|
|
|
214
214
|
stdout.write(text);
|
|
215
215
|
};
|
|
216
216
|
try {
|
|
217
|
-
const
|
|
217
|
+
const completion = await awaitPhraseUpload(session, {
|
|
218
218
|
phraseValidator: (p) => validateMnemonic(p, wordlist),
|
|
219
219
|
completePairing: async ({ mnemonic }) => {
|
|
220
220
|
try {
|
|
@@ -239,8 +239,8 @@ export async function runRelayPairCli(mode, opts) {
|
|
|
239
239
|
// serves both protocols on the same host.
|
|
240
240
|
const httpsBase = opts.relayBaseUrl.replace(/^ws/, 'http').replace(/\/+$/, '');
|
|
241
241
|
const apiClient = createApiClient(httpsBase);
|
|
242
|
-
const
|
|
243
|
-
registeredUserId =
|
|
242
|
+
const registerResult = await apiClient.register(authKeyHash, saltHex);
|
|
243
|
+
registeredUserId = registerResult.user_id;
|
|
244
244
|
opts.logger.info(`pair-cli (relay): registered user_id=${registeredUserId} (salt + auth-key persisted)`);
|
|
245
245
|
}
|
|
246
246
|
catch (regErr) {
|
|
@@ -296,12 +296,12 @@ export async function runRelayPairCli(mode, opts) {
|
|
|
296
296
|
emitStatus('\nCanceled. Pairing session invalidated.\n');
|
|
297
297
|
return { status: 'canceled', sid: session.token };
|
|
298
298
|
}
|
|
299
|
-
if (
|
|
299
|
+
if (completion.state === 'active') {
|
|
300
300
|
emitStatus('\nPairing complete. Account is active.\n');
|
|
301
301
|
return { status: 'completed', sid: session.token };
|
|
302
302
|
}
|
|
303
|
-
emitStatus(`\nPairing failed: ${
|
|
304
|
-
return { status: 'error', sid: session.token, error:
|
|
303
|
+
emitStatus(`\nPairing failed: ${completion.error ?? 'unknown_error'}\n`);
|
|
304
|
+
return { status: 'error', sid: session.token, error: completion.error ?? 'unknown_error' };
|
|
305
305
|
}
|
|
306
306
|
catch (err) {
|
|
307
307
|
if (canceled) {
|
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
* material and nonces are passed in by callers. See vault-crypto.ts for
|
|
15
15
|
* the implementation.
|
|
16
16
|
*/
|
|
17
|
-
export { HKDF_INFO, AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, X25519_KEY_BYTES, generateGatewayKeypair, derivePublicFromPrivate, computeSharedSecret, deriveSessionKeys, deriveAeadKeyFromEcdh, aeadDecrypt, decryptPairingPayload, aeadEncryptWithSessionKey, encryptPairingPayload, compareSecondaryCodesCT, } from '
|
|
17
|
+
export { HKDF_INFO, AEAD_KEY_BYTES, AEAD_NONCE_BYTES, AEAD_TAG_BYTES, X25519_KEY_BYTES, generateGatewayKeypair, derivePublicFromPrivate, computeSharedSecret, deriveSessionKeys, deriveAeadKeyFromEcdh, aeadDecrypt, decryptPairingPayload, aeadEncryptWithSessionKey, encryptPairingPayload, compareSecondaryCodesCT, } from '../crypto/vault-crypto.js';
|
|
@@ -381,7 +381,7 @@ export function buildPairRoutes(cfg) {
|
|
|
381
381
|
// sid/mode for log correlation.
|
|
382
382
|
void (async () => {
|
|
383
383
|
try {
|
|
384
|
-
const
|
|
384
|
+
const completion = await awaitPhraseUpload(session, {
|
|
385
385
|
phraseValidator: validate,
|
|
386
386
|
timeoutMs: cfg.initAwaitTimeoutMs,
|
|
387
387
|
completePairing: async ({ mnemonic }) => {
|
|
@@ -396,11 +396,11 @@ export function buildPairRoutes(cfg) {
|
|
|
396
396
|
return cfg.completePairing({ mnemonic, session: sessionLike });
|
|
397
397
|
},
|
|
398
398
|
});
|
|
399
|
-
if (
|
|
399
|
+
if (completion.state === 'active') {
|
|
400
400
|
cfg.logger.info(`pair-http /init: session ${redactSid(session.token)} completed in-process; onboarding active`);
|
|
401
401
|
}
|
|
402
402
|
else {
|
|
403
|
-
cfg.logger.warn(`pair-http /init: session ${redactSid(session.token)} completion non-active: ${
|
|
403
|
+
cfg.logger.warn(`pair-http /init: session ${redactSid(session.token)} completion non-active: ${completion.error ?? 'unknown'}`);
|
|
404
404
|
}
|
|
405
405
|
}
|
|
406
406
|
catch (err) {
|
|
@@ -158,9 +158,9 @@ export async function openRemotePairSession(opts = {}) {
|
|
|
158
158
|
const text = typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf-8');
|
|
159
159
|
msg = JSON.parse(text);
|
|
160
160
|
}
|
|
161
|
-
catch {
|
|
161
|
+
catch (err) {
|
|
162
162
|
safeClose(ws);
|
|
163
|
-
throw new Error('pair-remote-client: opened frame not valid JSON');
|
|
163
|
+
throw new Error('pair-remote-client: opened frame not valid JSON', { cause: err });
|
|
164
164
|
}
|
|
165
165
|
if (msg.type === 'error') {
|
|
166
166
|
const errStr = typeof msg.error === 'string' ? msg.error : 'relay_error';
|
|
@@ -220,10 +220,10 @@ export async function awaitPhraseUpload(session, opts) {
|
|
|
220
220
|
const text = typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf-8');
|
|
221
221
|
msg = JSON.parse(text);
|
|
222
222
|
}
|
|
223
|
-
catch {
|
|
223
|
+
catch (err) {
|
|
224
224
|
safeSend(ws, { type: 'nack', error: 'bad_json' });
|
|
225
225
|
safeClose(ws);
|
|
226
|
-
throw new Error('pair-remote-client: forward frame not valid JSON');
|
|
226
|
+
throw new Error('pair-remote-client: forward frame not valid JSON', { cause: err });
|
|
227
227
|
}
|
|
228
228
|
if (msg.type !== 'forward') {
|
|
229
229
|
safeSend(ws, { type: 'nack', error: 'expected_forward' });
|
|
@@ -281,9 +281,9 @@ export async function awaitPhraseUpload(session, opts) {
|
|
|
281
281
|
}
|
|
282
282
|
// Hand off to the caller-supplied completion handler. Wrapped in try/finally
|
|
283
283
|
// so we always drop our own reference to the mnemonic.
|
|
284
|
-
let
|
|
284
|
+
let completion;
|
|
285
285
|
try {
|
|
286
|
-
|
|
286
|
+
completion = await opts.completePairing({ mnemonic, session });
|
|
287
287
|
}
|
|
288
288
|
catch (err) {
|
|
289
289
|
safeSend(ws, { type: 'nack', error: 'completion_failed' });
|
|
@@ -295,14 +295,14 @@ export async function awaitPhraseUpload(session, opts) {
|
|
|
295
295
|
// rebinding at least drops the reference from this closure.
|
|
296
296
|
mnemonic = '';
|
|
297
297
|
}
|
|
298
|
-
if (
|
|
299
|
-
safeSend(ws, { type: 'nack', error:
|
|
298
|
+
if (completion.state !== 'active') {
|
|
299
|
+
safeSend(ws, { type: 'nack', error: completion.error ?? 'completion_failed' });
|
|
300
300
|
safeClose(ws);
|
|
301
|
-
return
|
|
301
|
+
return completion;
|
|
302
302
|
}
|
|
303
303
|
safeSend(ws, { type: 'ack' });
|
|
304
304
|
safeClose(ws);
|
|
305
|
-
return
|
|
305
|
+
return completion;
|
|
306
306
|
}
|
|
307
307
|
/**
|
|
308
308
|
* One-shot convenience: open session + await phrase upload + run completion.
|
|
@@ -428,17 +428,17 @@ export async function updatePairSession(sessionsPath, sid, mutate, now = Date.no
|
|
|
428
428
|
}
|
|
429
429
|
const current = pruned.file.sessions[idx];
|
|
430
430
|
const next = mutate(current);
|
|
431
|
-
let
|
|
431
|
+
let mutatedSession;
|
|
432
432
|
if (next === null) {
|
|
433
433
|
pruned.file.sessions.splice(idx, 1);
|
|
434
|
-
|
|
434
|
+
mutatedSession = null;
|
|
435
435
|
}
|
|
436
436
|
else {
|
|
437
437
|
pruned.file.sessions[idx] = next;
|
|
438
|
-
|
|
438
|
+
mutatedSession = next;
|
|
439
439
|
}
|
|
440
440
|
writePairSessionsFileSync(sessionsPath, pruned.file);
|
|
441
|
-
return
|
|
441
|
+
return mutatedSession;
|
|
442
442
|
}
|
|
443
443
|
finally {
|
|
444
444
|
release();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Plugin configSchema — static JSON-schema for the OpenClaw plugin config.
|
|
3
|
+
// Extracted from index.ts; pure data, no runtime state.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
export const CONFIG_SCHEMA = {
|
|
6
|
+
type: 'object',
|
|
7
|
+
additionalProperties: false,
|
|
8
|
+
properties: {
|
|
9
|
+
publicUrl: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
description: "Public gateway URL for QR pairing (e.g. 'https://gateway.example.com:18789'). Overrides the auto-resolution cascade in buildPairingUrl.",
|
|
12
|
+
},
|
|
13
|
+
extraction: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
properties: {
|
|
17
|
+
enabled: {
|
|
18
|
+
type: 'boolean',
|
|
19
|
+
description: 'Enable/disable auto-extraction (default: true)',
|
|
20
|
+
},
|
|
21
|
+
model: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: "Shorthand: override just the extraction model (e.g., 'glm-4.5-flash', 'gpt-4.1-mini'). For a full provider override use extraction.llm.",
|
|
24
|
+
},
|
|
25
|
+
interval: {
|
|
26
|
+
type: 'number',
|
|
27
|
+
description: 'Number of turns between automatic extractions (default: 3)',
|
|
28
|
+
},
|
|
29
|
+
maxFactsPerExtraction: {
|
|
30
|
+
type: 'number',
|
|
31
|
+
description: 'Hard cap on facts extracted per turn (default: 15)',
|
|
32
|
+
},
|
|
33
|
+
llm: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
description: 'Explicit LLM override block. Highest-priority tier in the extraction-provider cascade. Any subset of provider+apiKey is enough to pin a provider.',
|
|
37
|
+
properties: {
|
|
38
|
+
provider: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: "Provider name: zai | openai | anthropic | gemini | google | mistral | groq | deepseek | openrouter | xai | together | cerebras.",
|
|
41
|
+
},
|
|
42
|
+
model: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Explicit model id. If omitted, deriveCheapModel(provider) picks a sensible default.',
|
|
45
|
+
},
|
|
46
|
+
apiKey: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'API key for the selected provider. Required for the override to take effect.',
|
|
49
|
+
},
|
|
50
|
+
baseUrl: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Override the provider base URL (self-hosted / custom gateway setups).',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|