clawvault 1.10.2 → 1.11.0

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/README.md CHANGED
@@ -106,32 +106,6 @@ clawvault context "what decisions were made" --budget 2000
106
106
  # → fits within token budget, 🔴 items first
107
107
  ```
108
108
 
109
- ## ClawVault Cloud
110
-
111
- ClawVault Cloud extends local memory with org-linked decision traces. The local vault stays your source of truth, and cloud sync adds cross-agent visibility plus centralized audit trails.
112
-
113
- - **Local-first writes** - `trace emit` always appends locally before sync attempts.
114
- - **Queued and retryable sync** - traces are buffered and sent with `clawvault sync`.
115
- - **Org-linked vault identity** - each vault can be linked once, then monitored with status checks.
116
- - **Backwards-compatible sync command** - `clawvault sync <target>` still syncs vault files to a folder.
117
-
118
- Quick setup:
119
-
120
- ```bash
121
- # 1) Save your cloud API key
122
- clawvault config --cloud-key cvk_xxx
123
-
124
- # 2) Link this local vault to your org
125
- clawvault org link --vault ~/memory
126
-
127
- # 3) Verify cloud + org link state
128
- clawvault org status
129
-
130
- # 4) Emit trace events and sync queued traces
131
- clawvault trace emit --summary "Approved 20% discount for ACME"
132
- clawvault sync
133
- ```
134
-
135
109
  ## Search
136
110
 
137
111
  Use `clawvault search` / `qmd` for vault search — it indexes the **entire vault** (decisions/, people/, lessons/, observations/, etc.).
@@ -217,29 +191,6 @@ clawvault recap --brief # Token-efficient recap
217
191
  clawvault doctor
218
192
  ```
219
193
 
220
- ### Cloud Sync
221
-
222
- ```bash
223
- # Configure cloud API access
224
- clawvault config --cloud-key cvk_xxx
225
- clawvault config --cloud-api-url https://api.clawvault.dev # optional override
226
-
227
- # Link local vault to cloud org/vault ID
228
- clawvault org link --vault ~/memory
229
- clawvault org status
230
-
231
- # Emit decision traces (summary-only or JSON payload)
232
- clawvault trace emit --summary "Approved 20% discount for ACME"
233
- clawvault trace emit --trace-file ./trace.json
234
-
235
- # Sync queued cloud traces (no target argument)
236
- clawvault sync
237
- clawvault sync --all
238
- clawvault sync --limit 25
239
-
240
- # Existing file sync still works when target is provided
241
- clawvault sync ./obsidian # existing file sync to target folder
242
- ```
243
194
 
244
195
  ## Agent Setup (AGENTS.md)
245
196
 
package/bin/clawvault.js CHANGED
@@ -103,16 +103,6 @@ function printQmdMissing() {
103
103
  console.log(chalk.dim(`Install: ${QMD_INSTALL_COMMAND}`));
104
104
  }
105
105
 
106
- function cloudSkipReasonText(reason) {
107
- const map = {
108
- 'empty-queue': 'No pending traces to sync.',
109
- 'cloud-not-configured': 'Cloud not fully configured (need API key and linked vault).',
110
- 'sync-disabled': 'Cloud sync disabled for this trace emit.',
111
- 'sync-failed': 'Cloud sync failed; traces remain queued.'
112
- };
113
- return map[reason] || `Skipped: ${reason}`;
114
- }
115
-
116
106
  function parseBooleanInput(value, defaultValue = true) {
117
107
  const normalized = value.trim().toLowerCase();
118
108
  if (!normalized) {
@@ -127,125 +117,6 @@ function parseBooleanInput(value, defaultValue = true) {
127
117
  return null;
128
118
  }
129
119
 
130
- async function promptDecisionTrace(initialSummary) {
131
- const rl = createInterface({ input: process.stdin, output: process.stdout });
132
-
133
- const ask = async (label, defaultValue = '') => {
134
- const suffix = defaultValue ? ` [${defaultValue}]` : '';
135
- const answer = await rl.question(`${label}${suffix}: `);
136
- const trimmed = answer.trim();
137
- return trimmed || defaultValue;
138
- };
139
-
140
- const askRequired = async (label, defaultValue = '') => {
141
- while (true) {
142
- const value = await ask(label, defaultValue);
143
- if (value.trim()) {
144
- return value.trim();
145
- }
146
- console.log(chalk.yellow(`${label} is required.`));
147
- }
148
- };
149
-
150
- const askBoolean = async (label, defaultValue = true) => {
151
- while (true) {
152
- const defaultText = defaultValue ? 'Y/n' : 'y/N';
153
- const answer = await rl.question(`${label} (${defaultText}): `);
154
- const parsed = parseBooleanInput(answer, defaultValue);
155
- if (parsed !== null) {
156
- return parsed;
157
- }
158
- console.log(chalk.yellow('Please answer yes or no.'));
159
- }
160
- };
161
-
162
- const askOptionalObject = async (label) => {
163
- while (true) {
164
- const raw = await rl.question(`${label} (JSON object, leave blank for none): `);
165
- const trimmed = raw.trim();
166
- if (!trimmed) {
167
- return undefined;
168
- }
169
- try {
170
- const parsed = JSON.parse(trimmed);
171
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
172
- console.log(chalk.yellow('Please enter a JSON object (e.g. {"key":"value"}).'));
173
- continue;
174
- }
175
- return parsed;
176
- } catch {
177
- console.log(chalk.yellow('Invalid JSON. Try again.'));
178
- }
179
- }
180
- };
181
-
182
- const collectInputs = async () => {
183
- const inputs = [];
184
- let index = 1;
185
- while (await askBoolean(`Add input #${index}?`, index === 1)) {
186
- const source = await askRequired(' input.source');
187
- const type = await askRequired(' input.type');
188
- const id = await askRequired(' input.id');
189
- const data = await askOptionalObject(' input.data');
190
- inputs.push(data ? { source, type, id, data } : { source, type, id });
191
- index += 1;
192
- }
193
- return inputs;
194
- };
195
-
196
- const collectPolicies = async () => {
197
- const policies = [];
198
- let index = 1;
199
- while (await askBoolean(`Add policy #${index}?`, index === 1)) {
200
- const id = await askRequired(' policy.id');
201
- const name = await askRequired(' policy.name');
202
- const version = await askRequired(' policy.version', '1.0');
203
- const rule = await askRequired(' policy.rule');
204
- const result = await askRequired(' policy.result');
205
- policies.push({ id, name, version, rule, result });
206
- index += 1;
207
- }
208
- return policies;
209
- };
210
-
211
- const collectExceptions = async () => {
212
- const exceptions = [];
213
- let index = 1;
214
- while (await askBoolean(`Add exception #${index}?`, false)) {
215
- const policyId = await askRequired(' exception.policyId');
216
- const reason = await askRequired(' exception.reason');
217
- const approvedBy = await ask(' exception.approvedBy');
218
- exceptions.push(approvedBy ? { policyId, reason, approvedBy } : { policyId, reason });
219
- index += 1;
220
- }
221
- return exceptions;
222
- };
223
-
224
- try {
225
- console.log(chalk.cyan('\nTrace emit interactive mode\n'));
226
- const summary = await askRequired('summary', initialSummary);
227
- const inputs = await collectInputs();
228
- const policies = await collectPolicies();
229
- const exceptions = await collectExceptions();
230
-
231
- console.log(chalk.cyan('\nOutcome\n'));
232
- const action = await askRequired(' outcome.action');
233
- const target = await askRequired(' outcome.target');
234
- const success = await askBoolean(' outcome.success', true);
235
- const data = await askOptionalObject(' outcome.data');
236
-
237
- return {
238
- summary,
239
- inputs,
240
- policies,
241
- exceptions,
242
- outcome: data ? { action, target, success, data } : { action, target, success }
243
- };
244
- } finally {
245
- rl.close();
246
- }
247
- }
248
-
249
120
  program
250
121
  .name('clawvault')
251
122
  .description('🐘 An elephant never forgets. Structured memory for AI agents.')
@@ -314,164 +185,6 @@ program
314
185
  }
315
186
  });
316
187
 
317
- // === CONFIG ===
318
- program
319
- .command('config')
320
- .description('Manage ClawVault cloud configuration')
321
- .option('--cloud-key <key>', 'Set cloud API key')
322
- .option('--cloud-api-url <url>', 'Set cloud API base URL')
323
- .option('--json', 'Output as JSON')
324
- .action(async (options) => {
325
- try {
326
- const { cloudConfigCommand } = await import('../dist/commands/cloud.js');
327
- const status = await cloudConfigCommand({
328
- cloudKey: options.cloudKey,
329
- cloudApiUrl: options.cloudApiUrl
330
- });
331
-
332
- if (options.json) {
333
- console.log(JSON.stringify(status, null, 2));
334
- return;
335
- }
336
-
337
- console.log(chalk.cyan('\n☁️ Cloud Config\n'));
338
- console.log(chalk.dim(`API key: ${status.cloudApiKeyMasked}`));
339
- console.log(chalk.dim(`Vault ID: ${status.cloudVaultId || '(not linked)'}`));
340
- console.log(chalk.dim(`Org slug: ${status.cloudOrgSlug || '(not set)'}`));
341
- console.log(chalk.dim(`Queue depth: ${status.queueDepth}`));
342
- console.log(chalk.dim(`Configured: ${status.configured ? 'yes' : 'no'}`));
343
- console.log();
344
- } catch (err) {
345
- console.error(chalk.red(`Error: ${err.message}`));
346
- process.exit(1);
347
- }
348
- });
349
-
350
- // === ORG ===
351
- const org = program
352
- .command('org')
353
- .description('Manage cloud organization link');
354
-
355
- org
356
- .command('link')
357
- .description('Link this vault to cloud org')
358
- .option('-v, --vault <path>', 'Vault path')
359
- .option('-a, --agent-id <id>', 'Agent ID (default: OPENCLAW_AGENT_ID or agent-local)')
360
- .option('--org-slug <slug>', 'Org slug override')
361
- .option('--json', 'Output as JSON')
362
- .action(async (options) => {
363
- try {
364
- const vaultPath = resolveVaultPath(options.vault);
365
- const { orgLinkCommand } = await import('../dist/commands/cloud.js');
366
- const result = await orgLinkCommand({
367
- vaultPath,
368
- agentId: options.agentId,
369
- orgSlug: options.orgSlug
370
- });
371
-
372
- if (options.json) {
373
- console.log(JSON.stringify(result, null, 2));
374
- return;
375
- }
376
-
377
- console.log(chalk.green(`✓ Cloud vault linked: ${result.vaultId}`));
378
- console.log(chalk.dim(` Vault: ${result.vaultName}`));
379
- if (result.orgSlug) {
380
- console.log(chalk.dim(` Org: ${result.orgSlug}`));
381
- }
382
- } catch (err) {
383
- console.error(chalk.red(`Error: ${err.message}`));
384
- process.exit(1);
385
- }
386
- });
387
-
388
- org
389
- .command('status')
390
- .description('Show cloud org link status')
391
- .option('--json', 'Output as JSON')
392
- .action(async (options) => {
393
- try {
394
- const { orgStatusCommand } = await import('../dist/commands/cloud.js');
395
- const status = await orgStatusCommand();
396
-
397
- if (options.json) {
398
- console.log(JSON.stringify(status, null, 2));
399
- return;
400
- }
401
-
402
- console.log(chalk.cyan('\n☁️ Org Status\n'));
403
- console.log(chalk.dim(`Configured: ${status.configured ? 'yes' : 'no'}`));
404
- console.log(chalk.dim(`API key set: ${status.apiKeySet ? 'yes' : 'no'}`));
405
- console.log(chalk.dim(`Vault linked: ${status.vaultIdSet ? 'yes' : 'no'}`));
406
- console.log(chalk.dim(`Org slug: ${status.orgSlug || '(not set)'}`));
407
- console.log(chalk.dim(`Queue depth: ${status.queueDepth}`));
408
- if (status.cloudApiUrl) {
409
- console.log(chalk.dim(`API URL: ${status.cloudApiUrl}`));
410
- }
411
- console.log();
412
- } catch (err) {
413
- console.error(chalk.red(`Error: ${err.message}`));
414
- process.exit(1);
415
- }
416
- });
417
-
418
- // === TRACE ===
419
- const trace = program
420
- .command('trace')
421
- .description('Manage decision traces');
422
-
423
- trace
424
- .command('emit')
425
- .description('Emit decision trace (interactive, local + cloud queue)')
426
- .option('--summary <text>', 'Decision summary')
427
- .option('--trace-json <json>', 'Decision trace JSON payload')
428
- .option('--trace-file <path>', 'Path to JSON trace payload')
429
- .option('--stdin', 'Read JSON trace payload from stdin')
430
- .option('--no-sync', 'Skip immediate cloud sync attempt')
431
- .option('--json', 'Output as JSON')
432
- .action(async (options) => {
433
- try {
434
- const { traceEmitCommand } = await import('../dist/commands/cloud.js');
435
- const hasPayloadInput = Boolean(options.traceJson || options.traceFile || options.stdin);
436
-
437
- let tracePayload;
438
- if (!hasPayloadInput) {
439
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
440
- throw new Error(
441
- 'Interactive trace emit requires a TTY. Use --trace-json, --trace-file, or --stdin for non-interactive mode.'
442
- );
443
- }
444
- tracePayload = await promptDecisionTrace(options.summary);
445
- }
446
-
447
- const result = await traceEmitCommand({
448
- summary: options.summary,
449
- traceJson: options.traceJson,
450
- traceFile: options.traceFile,
451
- stdin: options.stdin,
452
- sync: options.sync,
453
- trace: tracePayload
454
- });
455
-
456
- if (options.json) {
457
- console.log(JSON.stringify(result, null, 2));
458
- return;
459
- }
460
-
461
- console.log(chalk.green(`✓ Trace emitted: ${result.trace.localTraceId}`));
462
- console.log(chalk.dim(` Summary: ${result.trace.summary}`));
463
- console.log(chalk.dim(` Queue depth: ${result.queueDepth}`));
464
- if (result.sync.skippedReason) {
465
- console.log(chalk.yellow(` Cloud sync: ${cloudSkipReasonText(result.sync.skippedReason)}`));
466
- } else {
467
- console.log(chalk.dim(` Cloud sync: sent ${result.sync.synced}, remaining ${result.sync.remaining}`));
468
- }
469
- } catch (err) {
470
- console.error(chalk.red(`Error: ${err.message}`));
471
- process.exit(1);
472
- }
473
- });
474
-
475
188
  // === STORE ===
476
189
  program
477
190
  .command('store')
@@ -539,16 +252,6 @@ program
539
252
  const collection = vault.getQmdCollection();
540
253
  await runQmd(collection ? ['update', '-c', collection] : ['update']);
541
254
  }
542
-
543
- const { autoSyncHandoffCommand } = await import('../dist/commands/cloud.js');
544
- const cloudSync = await autoSyncHandoffCommand();
545
- if (!options.json) {
546
- if (cloudSync.skippedReason) {
547
- console.log(chalk.dim(` Cloud sync: ${cloudSkipReasonText(cloudSync.skippedReason)}`));
548
- } else {
549
- console.log(chalk.dim(` Cloud sync: sent ${cloudSync.synced}, remaining ${cloudSync.remaining}`));
550
- }
551
- }
552
255
  } catch (err) {
553
256
  console.error(chalk.red(`Error: ${err.message}`));
554
257
  process.exit(1);
@@ -882,33 +585,15 @@ program
882
585
  }
883
586
  });
884
587
 
885
- // === SYNC ===
588
+ // === SYNC (vault file sync only) ===
886
589
  program
887
- .command('sync [target]')
888
- .description('Sync traces to cloud (or vault files to target path)')
590
+ .command('sync <target>')
591
+ .description('Sync vault files to target path')
889
592
  .option('--delete', 'Delete orphan files in target')
890
593
  .option('--dry-run', "Show what would be synced without syncing")
891
- .option('--all', 'For cloud sync, send all queued traces')
892
- .option('--limit <n>', 'For cloud sync, max traces to send')
893
594
  .option('-v, --vault <path>', 'Vault path')
894
595
  .action(async (target, options) => {
895
596
  try {
896
- if (!target) {
897
- const { cloudSyncCommand } = await import('../dist/commands/cloud.js');
898
- const cloudResult = await cloudSyncCommand({
899
- all: options.all,
900
- limit: options.limit ? parseInt(options.limit, 10) : undefined
901
- });
902
-
903
- if (cloudResult.skippedReason) {
904
- console.log(chalk.yellow(cloudSkipReasonText(cloudResult.skippedReason)));
905
- } else {
906
- console.log(chalk.green(`✓ Synced ${cloudResult.synced} trace(s) to cloud`));
907
- console.log(chalk.dim(` Remaining queued: ${cloudResult.remaining}`));
908
- }
909
- return;
910
- }
911
-
912
597
  const vault = await getVault(options.vault);
913
598
 
914
599
  console.log(chalk.cyan(`\n🔄 Syncing to ${target}...\n`));
@@ -1128,13 +813,6 @@ program
1128
813
  console.log(chalk.dim(' Git: commit skipped'));
1129
814
  }
1130
815
  }
1131
- if (result.cloudSync) {
1132
- if (result.cloudSync.skippedReason) {
1133
- console.log(chalk.dim(` Cloud sync: ${cloudSkipReasonText(result.cloudSync.skippedReason)}`));
1134
- } else {
1135
- console.log(chalk.dim(` Cloud sync: sent ${result.cloudSync.synced}, remaining ${result.cloudSync.remaining}`));
1136
- }
1137
- }
1138
816
  if (result.observationRoutingSummary) {
1139
817
  console.log(chalk.dim(` Observe: ${result.observationRoutingSummary}`));
1140
818
  }
@@ -1177,7 +855,6 @@ program
1177
855
  };
1178
856
 
1179
857
  const doc = await vault.createHandoff(handoff);
1180
- let cloudSync;
1181
858
 
1182
859
  if (!options.json) {
1183
860
  console.log(chalk.green(`✓ Handoff created: ${doc.id}`));
@@ -1190,15 +867,8 @@ program
1190
867
  await runQmd(collection ? ['update', '-c', collection] : ['update']);
1191
868
  }
1192
869
 
1193
- const { autoSyncHandoffCommand } = await import('../dist/commands/cloud.js');
1194
- cloudSync = await autoSyncHandoffCommand();
1195
-
1196
870
  if (options.json) {
1197
- console.log(JSON.stringify({ id: doc.id, path: doc.path, handoff, cloudSync }, null, 2));
1198
- } else if (cloudSync.skippedReason) {
1199
- console.log(chalk.dim(` Cloud sync: ${cloudSkipReasonText(cloudSync.skippedReason)}`));
1200
- } else {
1201
- console.log(chalk.dim(` Cloud sync: sent ${cloudSync.synced}, remaining ${cloudSync.remaining}`));
871
+ console.log(JSON.stringify({ id: doc.id, path: doc.path, handoff }, null, 2));
1202
872
  }
1203
873
  } catch (err) {
1204
874
  console.error(chalk.red(`Error: ${err.message}`));
@@ -1442,11 +1112,9 @@ program
1442
1112
  blocked: options.blocked,
1443
1113
  urgent: options.urgent
1444
1114
  });
1445
- const { autoSyncCheckpointCommand } = await import('../dist/commands/cloud.js');
1446
- const cloudSync = await autoSyncCheckpointCommand();
1447
1115
 
1448
1116
  if (options.json) {
1449
- console.log(JSON.stringify({ ...data, cloudSync }, null, 2));
1117
+ console.log(JSON.stringify(data, null, 2));
1450
1118
  } else {
1451
1119
  console.log(chalk.green('✓ Checkpoint saved'));
1452
1120
  console.log(chalk.dim(` Timestamp: ${data.timestamp}`));
@@ -1454,11 +1122,6 @@ program
1454
1122
  if (data.focus) console.log(chalk.dim(` Focus: ${data.focus}`));
1455
1123
  if (data.blocked) console.log(chalk.dim(` Blocked: ${data.blocked}`));
1456
1124
  if (data.urgent) console.log(chalk.dim(' Urgent: yes'));
1457
- if (cloudSync.skippedReason) {
1458
- console.log(chalk.dim(` Cloud sync: ${cloudSkipReasonText(cloudSync.skippedReason)}`));
1459
- } else {
1460
- console.log(chalk.dim(` Cloud sync: sent ${cloudSync.synced}, remaining ${cloudSync.remaining}`));
1461
- }
1462
1125
  }
1463
1126
  } catch (err) {
1464
1127
  console.error(chalk.red(`Error: ${err.message}`));
@@ -1621,4 +1284,4 @@ program
1621
1284
  });
1622
1285
 
1623
1286
  // Parse and run
1624
- program.parse();
1287
+ program.parse();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Observer,
3
3
  parseSessionFile
4
- } from "./chunk-CC7IJJ32.js";
4
+ } from "./chunk-RPMQZZPE.js";
5
5
 
6
6
  // src/commands/observe.ts
7
7
  import * as fs2 from "fs";
@@ -534,12 +534,29 @@ var Router = class {
534
534
  }
535
535
  return null;
536
536
  }
537
+ normalizeForDedup(content) {
538
+ return content.replace(/^\d{2}:\d{2}\s+/, "").replace(/\[\[[^\]]*\]\]/g, (m) => m.replace(/\[\[|\]\]/g, "")).replace(/\s+/g, " ").trim().toLowerCase();
539
+ }
537
540
  appendToCategory(category, item) {
538
541
  const categoryDir = path.join(this.vaultPath, category);
539
542
  fs.mkdirSync(categoryDir, { recursive: true });
540
543
  const filePath = path.join(categoryDir, `${item.date}.md`);
541
544
  const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8").trim() : "";
542
- if (existing.includes(item.content)) return;
545
+ const normalizedNew = this.normalizeForDedup(item.content);
546
+ const existingLines = existing.split(/\r?\n/);
547
+ for (const line of existingLines) {
548
+ const lineContent = line.replace(/^-\s*(?:🔴|🟡|🟢)\s*/, "");
549
+ if (this.normalizeForDedup(lineContent) === normalizedNew) return;
550
+ }
551
+ for (const line of existingLines) {
552
+ const lineContent = line.replace(/^-\s*(?:🔴|🟡|🟢)\s*/, "");
553
+ const normalizedExisting = this.normalizeForDedup(lineContent);
554
+ if (normalizedExisting.length > 10 && normalizedNew.length > 10) {
555
+ const shorter = normalizedNew.length < normalizedExisting.length ? normalizedNew : normalizedExisting;
556
+ const longer = normalizedNew.length >= normalizedExisting.length ? normalizedNew : normalizedExisting;
557
+ if (longer.includes(shorter) || this.similarity(normalizedNew, normalizedExisting) > 0.8) return;
558
+ }
559
+ }
543
560
  const linkedContent = this.addWikiLinks(item.content);
544
561
  const entry = `- ${item.priority} ${linkedContent}`;
545
562
  const header = existing ? "" : `# ${category} \u2014 ${item.date}
@@ -705,6 +722,23 @@ ${entry}
705
722
  return match;
706
723
  });
707
724
  }
725
+ /**
726
+ * Jaccard similarity on word bigrams — cheap approximation.
727
+ */
728
+ similarity(a, b) {
729
+ const bigrams = (s) => {
730
+ const words = s.split(" ");
731
+ const bg = /* @__PURE__ */ new Set();
732
+ for (let i = 0; i < words.length - 1; i++) bg.add(`${words[i]} ${words[i + 1]}`);
733
+ return bg;
734
+ };
735
+ const setA = bigrams(a);
736
+ const setB = bigrams(b);
737
+ if (setA.size === 0 || setB.size === 0) return 0;
738
+ let intersection = 0;
739
+ for (const bg of setA) if (setB.has(bg)) intersection++;
740
+ return intersection / (setA.size + setB.size - intersection);
741
+ }
708
742
  buildSummary(routed) {
709
743
  if (routed.length === 0) return "No items routed to vault categories.";
710
744
  const byCat = /* @__PURE__ */ new Map();
@@ -1,6 +1,3 @@
1
- import {
2
- formatAge
3
- } from "../chunk-7ZRP733D.js";
4
1
  import {
5
2
  ClawVault,
6
3
  findVault
@@ -12,6 +9,9 @@ import {
12
9
  scanVaultLinks
13
10
  } from "../chunk-4VQTUVH7.js";
14
11
  import "../chunk-J7ZWCI2C.js";
12
+ import {
13
+ formatAge
14
+ } from "../chunk-7ZRP733D.js";
15
15
 
16
16
  // src/commands/doctor.ts
17
17
  import * as fs from "fs";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  observeCommand,
3
3
  registerObserveCommand
4
- } from "../chunk-GENGXU34.js";
5
- import "../chunk-CC7IJJ32.js";
4
+ } from "../chunk-5VYRT2XZ.js";
5
+ import "../chunk-RPMQZZPE.js";
6
6
  export {
7
7
  observeCommand,
8
8
  registerObserveCommand
@@ -1,5 +1,4 @@
1
1
  import { H as HandoffDocument, D as Document } from '../types-DMU3SuAV.js';
2
- import { C as CloudSyncResult } from '../types-CilEQY9w.js';
3
2
 
4
3
  type PromptFn = (question: string) => Promise<string>;
5
4
  interface SleepOptions {
@@ -28,7 +27,6 @@ interface SleepResult {
28
27
  handoff: HandoffDocument;
29
28
  document: Document;
30
29
  git?: GitCommitResult;
31
- cloudSync?: CloudSyncResult;
32
30
  observationRoutingSummary?: string;
33
31
  }
34
32
  declare function sleep(options: SleepOptions): Promise<SleepResult>;
@@ -1,9 +1,3 @@
1
- import {
2
- clearDirtyFlag
3
- } from "../chunk-MZZJLQNQ.js";
4
- import {
5
- autoSyncOnHandoff
6
- } from "../chunk-BBPSJL6H.js";
7
1
  import {
8
2
  ClawVault
9
3
  } from "../chunk-3HFB7EMU.js";
@@ -13,7 +7,10 @@ import {
13
7
  import {
14
8
  Observer,
15
9
  parseSessionFile
16
- } from "../chunk-CC7IJJ32.js";
10
+ } from "../chunk-RPMQZZPE.js";
11
+ import {
12
+ clearDirtyFlag
13
+ } from "../chunk-MZZJLQNQ.js";
17
14
 
18
15
  // src/commands/sleep.ts
19
16
  import * as fs from "fs";
@@ -173,7 +170,6 @@ async function sleep(options) {
173
170
  cwd: options.cwd ?? process.cwd(),
174
171
  interactive
175
172
  });
176
- const cloudSync = await autoSyncOnHandoff();
177
173
  let observationRoutingSummary;
178
174
  try {
179
175
  const transcriptPath = resolveSessionTranscriptPath(options.sessionTranscript);
@@ -186,7 +182,7 @@ async function sleep(options) {
186
182
  }
187
183
  } catch {
188
184
  }
189
- return { handoff, document, git, cloudSync, observationRoutingSummary };
185
+ return { handoff, document, git, observationRoutingSummary };
190
186
  }
191
187
  export {
192
188
  sleep
@@ -1,6 +1,3 @@
1
- import {
2
- formatAge
3
- } from "../chunk-7ZRP733D.js";
4
1
  import {
5
2
  ClawVault
6
3
  } from "../chunk-3HFB7EMU.js";
@@ -12,6 +9,9 @@ import {
12
9
  scanVaultLinks
13
10
  } from "../chunk-4VQTUVH7.js";
14
11
  import "../chunk-J7ZWCI2C.js";
12
+ import {
13
+ formatAge
14
+ } from "../chunk-7ZRP733D.js";
15
15
 
16
16
  // src/commands/status.ts
17
17
  import * as fs from "fs";
@@ -1,3 +1,7 @@
1
+ import {
2
+ ClawVault
3
+ } from "../chunk-3HFB7EMU.js";
4
+ import "../chunk-MIIXBNO3.js";
1
5
  import {
2
6
  recover
3
7
  } from "../chunk-MILVYUPK.js";
@@ -5,10 +9,6 @@ import {
5
9
  clearDirtyFlag
6
10
  } from "../chunk-MZZJLQNQ.js";
7
11
  import "../chunk-7ZRP733D.js";
8
- import {
9
- ClawVault
10
- } from "../chunk-3HFB7EMU.js";
11
- import "../chunk-MIIXBNO3.js";
12
12
 
13
13
  // src/commands/wake.ts
14
14
  import * as fs from "fs";
package/dist/index.js CHANGED
@@ -41,13 +41,13 @@ import {
41
41
  SessionWatcher,
42
42
  observeCommand,
43
43
  registerObserveCommand
44
- } from "./chunk-GENGXU34.js";
44
+ } from "./chunk-5VYRT2XZ.js";
45
45
  import {
46
46
  Compressor,
47
47
  Observer,
48
48
  Reflector,
49
49
  parseSessionFile
50
- } from "./chunk-CC7IJJ32.js";
50
+ } from "./chunk-RPMQZZPE.js";
51
51
 
52
52
  // src/index.ts
53
53
  import * as fs from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawvault",
3
- "version": "1.10.2",
3
+ "version": "1.11.0",
4
4
  "description": "ClawVault™ - 🐘 An elephant never forgets. Structured memory for OpenClaw agents. Context death resilience, Obsidian-compatible markdown, local semantic search.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -29,7 +29,7 @@
29
29
  ]
30
30
  },
31
31
  "scripts": {
32
- "build": "tsup src/index.ts src/commands/entities.ts src/commands/link.ts src/commands/checkpoint.ts src/commands/recover.ts src/commands/status.ts src/commands/template.ts src/commands/setup.ts src/commands/context.ts src/commands/observe.ts src/commands/session-recap.ts src/commands/wake.ts src/commands/sleep.ts src/commands/doctor.ts src/commands/shell-init.ts src/commands/repair-session.ts src/commands/cloud.ts src/lib/entity-index.ts src/lib/auto-linker.ts src/lib/config.ts src/lib/template-engine.ts src/lib/session-utils.ts src/lib/session-repair.ts --format esm --dts --clean",
32
+ "build": "tsup src/index.ts src/commands/entities.ts src/commands/link.ts src/commands/checkpoint.ts src/commands/recover.ts src/commands/status.ts src/commands/template.ts src/commands/setup.ts src/commands/context.ts src/commands/observe.ts src/commands/session-recap.ts src/commands/wake.ts src/commands/sleep.ts src/commands/doctor.ts src/commands/shell-init.ts src/commands/repair-session.ts src/lib/entity-index.ts src/lib/auto-linker.ts src/lib/config.ts src/lib/template-engine.ts src/lib/session-utils.ts src/lib/session-repair.ts --format esm --dts --clean",
33
33
  "dev": "tsup src/index.ts src/commands/*.ts src/lib/*.ts --format esm --dts --watch",
34
34
  "lint": "eslint src",
35
35
  "typecheck": "tsc --noEmit",
@@ -1,375 +0,0 @@
1
- // src/cloud/config.ts
2
- import * as fs from "fs";
3
-
4
- // src/cloud/paths.ts
5
- import * as os from "os";
6
- import * as path from "path";
7
- var DEFAULT_HOME_DIR = ".clawvault";
8
- var CONFIG_FILE = "config.json";
9
- var SYNC_QUEUE_FILE = "sync-queue.json";
10
- var TRACE_LOG_FILE = "traces.ndjson";
11
- function getClawVaultHomeDir() {
12
- const override = process.env.CLAWVAULT_HOME?.trim();
13
- if (override) {
14
- return path.resolve(override);
15
- }
16
- return path.join(os.homedir(), DEFAULT_HOME_DIR);
17
- }
18
- function getCloudConfigPath() {
19
- return path.join(getClawVaultHomeDir(), CONFIG_FILE);
20
- }
21
- function getSyncQueuePath() {
22
- return path.join(getClawVaultHomeDir(), SYNC_QUEUE_FILE);
23
- }
24
- function getTraceLogPath() {
25
- return path.join(getClawVaultHomeDir(), TRACE_LOG_FILE);
26
- }
27
-
28
- // src/cloud/config.ts
29
- function ensureCloudDir() {
30
- const dir = getClawVaultHomeDir();
31
- if (!fs.existsSync(dir)) {
32
- fs.mkdirSync(dir, { recursive: true });
33
- }
34
- }
35
- function readCloudConfig() {
36
- const configPath = getCloudConfigPath();
37
- if (!fs.existsSync(configPath)) {
38
- return {};
39
- }
40
- try {
41
- const raw = fs.readFileSync(configPath, "utf-8");
42
- const parsed = JSON.parse(raw);
43
- return parsed ?? {};
44
- } catch {
45
- return {};
46
- }
47
- }
48
- function writeCloudConfig(config) {
49
- ensureCloudDir();
50
- const configPath = getCloudConfigPath();
51
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
52
- return config;
53
- }
54
- function updateCloudConfig(patch) {
55
- const current = readCloudConfig();
56
- const next = { ...current, ...patch };
57
- return writeCloudConfig(next);
58
- }
59
- function maskApiKey(apiKey) {
60
- if (!apiKey) return "(not set)";
61
- if (apiKey.length <= 8) return "***";
62
- const start = apiKey.slice(0, 4);
63
- const end = apiKey.slice(-4);
64
- return `${start}${"*".repeat(Math.max(4, apiKey.length - 8))}${end}`;
65
- }
66
- function getConfiguredCloudApiUrl(config) {
67
- const value = config?.cloudApiUrl || process.env.CLAWVAULT_CLOUD_API_URL;
68
- if (value && value.trim()) {
69
- return value.trim().replace(/\/+$/, "");
70
- }
71
- if (process.env.NODE_ENV === "development") {
72
- return "http://localhost:4000";
73
- }
74
- return "https://api.clawvault.io";
75
- }
76
-
77
- // src/cloud/service.ts
78
- import { randomUUID } from "crypto";
79
-
80
- // src/cloud/client.ts
81
- var CloudApiError = class extends Error {
82
- status;
83
- responseBody;
84
- };
85
- function parseRegisterResponse(payload) {
86
- const vaultId = payload?.vaultId ?? payload?.id ?? payload?.vault?.id;
87
- const orgSlug = payload?.orgSlug ?? payload?.org?.slug;
88
- if (!vaultId || typeof vaultId !== "string") {
89
- throw new Error("Cloud register response missing vault ID.");
90
- }
91
- return {
92
- vaultId,
93
- orgSlug: typeof orgSlug === "string" ? orgSlug : void 0,
94
- raw: payload
95
- };
96
- }
97
- async function requestJson(options, config) {
98
- const baseUrl = getConfiguredCloudApiUrl(config);
99
- const url = `${baseUrl}${options.path.startsWith("/") ? options.path : `/${options.path}`}`;
100
- const timeoutMs = options.timeoutMs ?? 1e4;
101
- const controller = new AbortController();
102
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
103
- try {
104
- const response = await fetch(url, {
105
- method: options.method,
106
- headers: {
107
- "Content-Type": "application/json",
108
- "X-API-Key": options.apiKey
109
- },
110
- body: options.body ? JSON.stringify(options.body) : void 0,
111
- signal: controller.signal
112
- });
113
- if (!response.ok) {
114
- const body = await response.text();
115
- const err = new CloudApiError(
116
- `Cloud API request failed (${response.status}) at ${options.path}`
117
- );
118
- err.status = response.status;
119
- err.responseBody = body;
120
- throw err;
121
- }
122
- const text = await response.text();
123
- if (!text.trim()) {
124
- return {};
125
- }
126
- return JSON.parse(text);
127
- } catch (err) {
128
- if (err?.name === "AbortError") {
129
- throw new Error(`Cloud API request timed out after ${timeoutMs}ms.`);
130
- }
131
- throw err;
132
- } finally {
133
- clearTimeout(timeout);
134
- }
135
- }
136
- function createCloudClient(config) {
137
- if (!config.cloudApiKey) {
138
- throw new Error("Cloud API key not configured. Run `clawvault config --cloud-key <key>`.");
139
- }
140
- return {
141
- async registerVault(input) {
142
- const payload = await requestJson({
143
- method: "POST",
144
- path: "/vaults/register",
145
- apiKey: config.cloudApiKey,
146
- body: {
147
- name: input.name,
148
- agentId: input.agentId
149
- }
150
- }, config);
151
- return parseRegisterResponse(payload);
152
- },
153
- async syncTraces(vaultId, traces) {
154
- return requestJson({
155
- method: "POST",
156
- path: `/vaults/${encodeURIComponent(vaultId)}/sync`,
157
- apiKey: config.cloudApiKey,
158
- body: { traces }
159
- }, config);
160
- }
161
- };
162
- }
163
-
164
- // src/cloud/queue.ts
165
- import * as fs2 from "fs";
166
- var EMPTY_QUEUE = {
167
- traces: [],
168
- updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
169
- };
170
- function ensureCloudDir2() {
171
- const dir = getClawVaultHomeDir();
172
- if (!fs2.existsSync(dir)) {
173
- fs2.mkdirSync(dir, { recursive: true });
174
- }
175
- }
176
- function readQueue() {
177
- const queuePath = getSyncQueuePath();
178
- if (!fs2.existsSync(queuePath)) {
179
- return { ...EMPTY_QUEUE };
180
- }
181
- try {
182
- const raw = fs2.readFileSync(queuePath, "utf-8");
183
- const parsed = JSON.parse(raw);
184
- if (!parsed || !Array.isArray(parsed.traces)) {
185
- return { ...EMPTY_QUEUE };
186
- }
187
- return {
188
- traces: parsed.traces,
189
- updatedAt: parsed.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
190
- };
191
- } catch {
192
- return { ...EMPTY_QUEUE };
193
- }
194
- }
195
- function writeQueue(traces) {
196
- ensureCloudDir2();
197
- const next = {
198
- traces,
199
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
200
- };
201
- fs2.writeFileSync(getSyncQueuePath(), JSON.stringify(next, null, 2));
202
- return next;
203
- }
204
- function enqueueTrace(trace) {
205
- const queue = readQueue();
206
- queue.traces.push(trace);
207
- return writeQueue(queue.traces);
208
- }
209
- function appendTraceLog(trace) {
210
- ensureCloudDir2();
211
- fs2.appendFileSync(getTraceLogPath(), `${JSON.stringify(trace)}
212
- `);
213
- }
214
-
215
- // src/cloud/service.ts
216
- function normalizeTrace(input) {
217
- return {
218
- localTraceId: input.localTraceId || randomUUID(),
219
- timestamp: input.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
220
- summary: input.summary,
221
- inputs: Array.isArray(input.inputs) ? input.inputs : [],
222
- policies: Array.isArray(input.policies) ? input.policies : [],
223
- exceptions: Array.isArray(input.exceptions) ? input.exceptions : [],
224
- outcome: input.outcome || {
225
- action: "unspecified",
226
- target: "unspecified",
227
- success: true,
228
- data: {}
229
- },
230
- entityRefs: Array.isArray(input.entityRefs) ? input.entityRefs : []
231
- };
232
- }
233
- function getSyncWindow(traces, options) {
234
- if (options.all) {
235
- return traces;
236
- }
237
- const limit = Math.max(1, options.limit ?? 10);
238
- return traces.slice(0, limit);
239
- }
240
- function setCloudApiKey(cloudKey) {
241
- const clean = cloudKey.trim();
242
- if (!clean) {
243
- throw new Error("Cloud API key cannot be empty.");
244
- }
245
- updateCloudConfig({ cloudApiKey: clean });
246
- return getCloudStatus();
247
- }
248
- function getCloudStatus() {
249
- const config = readCloudConfig();
250
- const queue = readQueue();
251
- const configured = Boolean(config.cloudApiKey && config.cloudVaultId);
252
- return {
253
- configured,
254
- cloudApiKeyMasked: maskApiKey(config.cloudApiKey),
255
- cloudVaultId: config.cloudVaultId,
256
- cloudOrgSlug: config.cloudOrgSlug,
257
- cloudApiUrl: getConfiguredCloudApiUrl(config),
258
- queueDepth: queue.traces.length
259
- };
260
- }
261
- async function linkVaultToOrg(options) {
262
- if (!options.vaultName.trim()) {
263
- throw new Error("Vault name is required for org link.");
264
- }
265
- if (!options.agentId.trim()) {
266
- throw new Error("Agent ID is required for org link.");
267
- }
268
- const config = readCloudConfig();
269
- const client = createCloudClient(config);
270
- const result = await client.registerVault({
271
- name: options.vaultName.trim(),
272
- agentId: options.agentId.trim()
273
- });
274
- updateCloudConfig({
275
- cloudVaultId: result.vaultId,
276
- cloudOrgSlug: options.orgSlug || result.orgSlug || config.cloudOrgSlug
277
- });
278
- return result;
279
- }
280
- async function syncQueuedTraces(options = {}) {
281
- const queue = readQueue();
282
- const config = readCloudConfig();
283
- const attemptedWindow = getSyncWindow(queue.traces, options);
284
- if (attemptedWindow.length === 0) {
285
- return {
286
- attempted: 0,
287
- synced: 0,
288
- remaining: 0,
289
- skippedReason: "empty-queue"
290
- };
291
- }
292
- if (!config.cloudApiKey || !config.cloudVaultId) {
293
- return {
294
- attempted: attemptedWindow.length,
295
- synced: 0,
296
- remaining: queue.traces.length,
297
- skippedReason: "cloud-not-configured"
298
- };
299
- }
300
- const client = createCloudClient(config);
301
- await client.syncTraces(config.cloudVaultId, attemptedWindow);
302
- const remaining = queue.traces.slice(attemptedWindow.length);
303
- writeQueue(remaining);
304
- return {
305
- attempted: attemptedWindow.length,
306
- synced: attemptedWindow.length,
307
- remaining: remaining.length
308
- };
309
- }
310
- async function emitTrace(input, syncNow = true) {
311
- const trace = normalizeTrace(input);
312
- appendTraceLog(trace);
313
- const queue = enqueueTrace(trace);
314
- let syncResult = {
315
- attempted: 0,
316
- synced: 0,
317
- remaining: queue.traces.length,
318
- skippedReason: "sync-disabled"
319
- };
320
- if (syncNow) {
321
- try {
322
- syncResult = await syncQueuedTraces({ all: false, limit: 25 });
323
- } catch {
324
- syncResult = {
325
- attempted: 0,
326
- synced: 0,
327
- remaining: readQueue().traces.length,
328
- skippedReason: "sync-failed"
329
- };
330
- }
331
- }
332
- return {
333
- trace,
334
- queueDepth: readQueue().traces.length,
335
- sync: syncResult
336
- };
337
- }
338
- async function autoSyncOnCheckpoint() {
339
- try {
340
- return await syncQueuedTraces({ all: false, limit: 10 });
341
- } catch {
342
- const remaining = readQueue().traces.length;
343
- return {
344
- attempted: 0,
345
- synced: 0,
346
- remaining,
347
- skippedReason: "sync-failed"
348
- };
349
- }
350
- }
351
- async function autoSyncOnHandoff() {
352
- try {
353
- return await syncQueuedTraces({ all: true });
354
- } catch {
355
- const remaining = readQueue().traces.length;
356
- return {
357
- attempted: 0,
358
- synced: 0,
359
- remaining,
360
- skippedReason: "sync-failed"
361
- };
362
- }
363
- }
364
-
365
- export {
366
- readCloudConfig,
367
- updateCloudConfig,
368
- setCloudApiKey,
369
- getCloudStatus,
370
- linkVaultToOrg,
371
- syncQueuedTraces,
372
- emitTrace,
373
- autoSyncOnCheckpoint,
374
- autoSyncOnHandoff
375
- };
@@ -1,63 +0,0 @@
1
- import { C as CloudSyncResult, D as DecisionTraceInput, a as DecisionTrace } from '../types-CilEQY9w.js';
2
-
3
- interface CloudStatus {
4
- configured: boolean;
5
- cloudApiKeyMasked: string;
6
- cloudVaultId?: string;
7
- cloudOrgSlug?: string;
8
- cloudApiUrl?: string;
9
- queueDepth: number;
10
- }
11
- interface EmitTraceResult {
12
- trace: DecisionTrace;
13
- queueDepth: number;
14
- sync: CloudSyncResult;
15
- }
16
- declare function getCloudStatus(): CloudStatus;
17
- declare function syncQueuedTraces(options?: {
18
- all?: boolean;
19
- limit?: number;
20
- }): Promise<CloudSyncResult>;
21
- declare function emitTrace(input: DecisionTraceInput, syncNow?: boolean): Promise<EmitTraceResult>;
22
- declare function autoSyncOnCheckpoint(): Promise<CloudSyncResult>;
23
- declare function autoSyncOnHandoff(): Promise<CloudSyncResult>;
24
-
25
- interface OrgLinkOptions {
26
- vaultPath: string;
27
- agentId?: string;
28
- orgSlug?: string;
29
- }
30
- interface TraceEmitOptions {
31
- summary?: string;
32
- traceFile?: string;
33
- traceJson?: string;
34
- stdin?: boolean;
35
- sync?: boolean;
36
- trace?: DecisionTraceInput;
37
- }
38
- declare function cloudConfigCommand(options: {
39
- cloudKey?: string;
40
- cloudApiUrl?: string;
41
- }): Promise<ReturnType<typeof getCloudStatus>>;
42
- declare function orgLinkCommand(options: OrgLinkOptions): Promise<{
43
- vaultName: string;
44
- vaultId: string;
45
- orgSlug?: string;
46
- }>;
47
- declare function orgStatusCommand(): Promise<{
48
- configured: boolean;
49
- apiKeySet: boolean;
50
- vaultIdSet: boolean;
51
- orgSlug?: string;
52
- queueDepth: number;
53
- cloudApiUrl?: string;
54
- }>;
55
- declare function cloudSyncCommand(options?: {
56
- all?: boolean;
57
- limit?: number;
58
- }): Promise<Awaited<ReturnType<typeof syncQueuedTraces>>>;
59
- declare function traceEmitCommand(options: TraceEmitOptions): Promise<Awaited<ReturnType<typeof emitTrace>>>;
60
- declare function autoSyncCheckpointCommand(): Promise<Awaited<ReturnType<typeof autoSyncOnCheckpoint>>>;
61
- declare function autoSyncHandoffCommand(): Promise<Awaited<ReturnType<typeof autoSyncOnHandoff>>>;
62
-
63
- export { autoSyncCheckpointCommand, autoSyncHandoffCommand, cloudConfigCommand, cloudSyncCommand, orgLinkCommand, orgStatusCommand, traceEmitCommand };
@@ -1,117 +0,0 @@
1
- import {
2
- autoSyncOnCheckpoint,
3
- autoSyncOnHandoff,
4
- emitTrace,
5
- getCloudStatus,
6
- linkVaultToOrg,
7
- readCloudConfig,
8
- setCloudApiKey,
9
- syncQueuedTraces,
10
- updateCloudConfig
11
- } from "../chunk-BBPSJL6H.js";
12
-
13
- // src/commands/cloud.ts
14
- import * as fs from "fs";
15
- import * as path from "path";
16
- function resolveVaultName(vaultPath) {
17
- const resolved = path.resolve(vaultPath);
18
- const configPath = path.join(resolved, ".clawvault.json");
19
- if (!fs.existsSync(configPath)) {
20
- return path.basename(resolved);
21
- }
22
- try {
23
- const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
24
- return parsed.name || path.basename(resolved);
25
- } catch {
26
- return path.basename(resolved);
27
- }
28
- }
29
- function parseTracePayload(options) {
30
- let payload = null;
31
- if (options.trace) {
32
- payload = options.trace;
33
- } else if (options.traceJson) {
34
- payload = JSON.parse(options.traceJson);
35
- } else if (options.traceFile) {
36
- payload = JSON.parse(fs.readFileSync(options.traceFile, "utf-8"));
37
- } else if (options.stdin) {
38
- const raw = fs.readFileSync(0, "utf-8");
39
- payload = JSON.parse(raw);
40
- }
41
- if (!payload) {
42
- if (!options.summary) {
43
- throw new Error("Trace summary is required (use --summary, --trace-json, --trace-file, or --stdin).");
44
- }
45
- return { summary: options.summary };
46
- }
47
- if (!payload.summary && options.summary) {
48
- payload.summary = options.summary;
49
- }
50
- if (!payload.summary) {
51
- throw new Error("Trace payload must include summary.");
52
- }
53
- return payload;
54
- }
55
- async function cloudConfigCommand(options) {
56
- if (!options.cloudKey && !options.cloudApiUrl) {
57
- return getCloudStatus();
58
- }
59
- if (options.cloudKey) {
60
- setCloudApiKey(options.cloudKey);
61
- }
62
- if (options.cloudApiUrl) {
63
- updateCloudConfig({ cloudApiUrl: options.cloudApiUrl.trim() });
64
- }
65
- return getCloudStatus();
66
- }
67
- async function orgLinkCommand(options) {
68
- const vaultName = resolveVaultName(options.vaultPath);
69
- const agentId = options.agentId || process.env.OPENCLAW_AGENT_ID || "agent-local";
70
- const result = await linkVaultToOrg({
71
- vaultName,
72
- agentId,
73
- orgSlug: options.orgSlug
74
- });
75
- return {
76
- vaultName,
77
- vaultId: result.vaultId,
78
- orgSlug: options.orgSlug || result.orgSlug
79
- };
80
- }
81
- async function orgStatusCommand() {
82
- const status = getCloudStatus();
83
- const config = readCloudConfig();
84
- return {
85
- configured: status.configured,
86
- apiKeySet: Boolean(config.cloudApiKey),
87
- vaultIdSet: Boolean(config.cloudVaultId),
88
- orgSlug: config.cloudOrgSlug,
89
- queueDepth: status.queueDepth,
90
- cloudApiUrl: status.cloudApiUrl
91
- };
92
- }
93
- async function cloudSyncCommand(options = {}) {
94
- return syncQueuedTraces({
95
- all: options.all,
96
- limit: options.limit
97
- });
98
- }
99
- async function traceEmitCommand(options) {
100
- const payload = parseTracePayload(options);
101
- return emitTrace(payload, options.sync !== false);
102
- }
103
- async function autoSyncCheckpointCommand() {
104
- return autoSyncOnCheckpoint();
105
- }
106
- async function autoSyncHandoffCommand() {
107
- return autoSyncOnHandoff();
108
- }
109
- export {
110
- autoSyncCheckpointCommand,
111
- autoSyncHandoffCommand,
112
- cloudConfigCommand,
113
- cloudSyncCommand,
114
- orgLinkCommand,
115
- orgStatusCommand,
116
- traceEmitCommand
117
- };
@@ -1,51 +0,0 @@
1
- interface DecisionTraceInputSource {
2
- source: string;
3
- type: string;
4
- id: string;
5
- data?: Record<string, unknown>;
6
- }
7
- interface DecisionTracePolicy {
8
- id: string;
9
- name: string;
10
- version: string;
11
- rule: string;
12
- result: string;
13
- }
14
- interface DecisionTraceException {
15
- policyId: string;
16
- reason: string;
17
- approvedBy?: string;
18
- }
19
- interface DecisionTraceOutcome {
20
- action: string;
21
- target: string;
22
- data?: Record<string, unknown>;
23
- success: boolean;
24
- }
25
- interface DecisionTraceEntityRef {
26
- type: string;
27
- id: string;
28
- name?: string;
29
- role?: string;
30
- }
31
- interface DecisionTrace {
32
- localTraceId: string;
33
- timestamp: string;
34
- summary: string;
35
- inputs: DecisionTraceInputSource[];
36
- policies: DecisionTracePolicy[];
37
- exceptions: DecisionTraceException[];
38
- outcome: DecisionTraceOutcome;
39
- entityRefs: DecisionTraceEntityRef[];
40
- }
41
- interface DecisionTraceInput extends Partial<DecisionTrace> {
42
- summary: string;
43
- }
44
- interface CloudSyncResult {
45
- attempted: number;
46
- synced: number;
47
- remaining: number;
48
- skippedReason?: string;
49
- }
50
-
51
- export type { CloudSyncResult as C, DecisionTraceInput as D, DecisionTrace as a };