@principles/pd-cli 1.128.1 → 1.129.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/dist/commands/mvp-smoke.js +1 -1
- package/dist/commands/mvp-smoke.js.map +1 -1
- package/dist/commands/rulecode.js +1 -1
- package/dist/commands/rulecode.js.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.js +61 -7
- package/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/dist/commands/runtime.js +1 -1
- package/dist/commands/runtime.js.map +1 -1
- package/dist/index.js +67 -34
- package/dist/index.js.map +1 -1
- package/dist/services/__tests__/rulehost-readiness.test.d.ts +2 -0
- package/dist/services/__tests__/rulehost-readiness.test.d.ts.map +1 -0
- package/dist/services/__tests__/rulehost-readiness.test.js +314 -0
- package/dist/services/__tests__/rulehost-readiness.test.js.map +1 -0
- package/dist/services/rulehost-readiness.d.ts +62 -0
- package/dist/services/rulehost-readiness.d.ts.map +1 -0
- package/dist/services/rulehost-readiness.js +214 -0
- package/dist/services/rulehost-readiness.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/mvp-smoke.ts +1 -1
- package/src/commands/rulecode.ts +1 -1
- package/src/commands/runtime-internalization-run-rulehost.ts +68 -6
- package/src/commands/runtime.ts +1 -1
- package/src/index.ts +73 -36
- package/src/services/__tests__/rulehost-readiness.test.ts +366 -0
- package/src/services/rulehost-readiness.ts +326 -0
- package/tests/commands/cli-command-tree.test.ts +2 -2
- package/tests/commands/cli-help-snapshot.test.ts +135 -0
- package/tests/commands/cli-skill-contract.test.ts +121 -0
- package/tests/commands/run-rulehost-handler.test.ts +277 -0
- package/tests/commands/runtime-internalization.test.ts +2 -2
- package/tests/services/rulehost-pipeline-e2e.test.ts +71 -61
- package/dist/commands/central-sync.d.ts +0 -10
- package/dist/commands/central-sync.d.ts.map +0 -1
- package/dist/commands/central-sync.js +0 -32
- package/dist/commands/central-sync.js.map +0 -1
- package/src/commands/central-sync.ts +0 -44
|
@@ -52,6 +52,18 @@ function writeConfig(workspaceDir: string, content: object): void {
|
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/** Type guard: narrows `unknown` to `Record<string, unknown>` without `as`. */
|
|
56
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
57
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function requireRecord(value: unknown, label: string): Record<string, unknown> {
|
|
61
|
+
if (!isRecord(value)) {
|
|
62
|
+
throw new Error(`${label} is not a record`);
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
/** Config with both artificer+evaluator enabled, pi-ai profile, API key env set. */
|
|
56
68
|
function makeCapabilityOnConfig(workspaceDir: string): object {
|
|
57
69
|
return {
|
|
@@ -90,17 +102,19 @@ function makeCapabilityOnConfig(workspaceDir: string): object {
|
|
|
90
102
|
|
|
91
103
|
/** Config with artificer disabled (capability must be OFF). */
|
|
92
104
|
function makeArtificerDisabledConfig(workspaceDir: string): object {
|
|
93
|
-
const cfg = makeCapabilityOnConfig(workspaceDir)
|
|
94
|
-
const internalAgents = cfg
|
|
95
|
-
|
|
105
|
+
const cfg = makeCapabilityOnConfig(workspaceDir);
|
|
106
|
+
const internalAgents = requireRecord(Reflect.get(cfg, 'internalAgents'), 'internalAgents');
|
|
107
|
+
const agents = requireRecord(Reflect.get(internalAgents, 'agents'), 'internalAgents.agents');
|
|
108
|
+
Reflect.set(agents, 'artificer', { enabled: false });
|
|
96
109
|
return cfg;
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
/** Config with evaluator disabled (capability must be OFF). */
|
|
100
113
|
function makeEvaluatorDisabledConfig(workspaceDir: string): object {
|
|
101
|
-
const cfg = makeCapabilityOnConfig(workspaceDir)
|
|
102
|
-
const internalAgents = cfg
|
|
103
|
-
|
|
114
|
+
const cfg = makeCapabilityOnConfig(workspaceDir);
|
|
115
|
+
const internalAgents = requireRecord(Reflect.get(cfg, 'internalAgents'), 'internalAgents');
|
|
116
|
+
const agents = requireRecord(Reflect.get(internalAgents, 'agents'), 'internalAgents.agents');
|
|
117
|
+
Reflect.set(agents, 'evaluator', { enabled: false });
|
|
104
118
|
return cfg;
|
|
105
119
|
}
|
|
106
120
|
|
|
@@ -158,10 +172,11 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
/** Extract the single JSON object written to stdout. Fails if not exactly one write. */
|
|
161
|
-
function parseJsonOutput(): unknown {
|
|
175
|
+
function parseJsonOutput(): Record<string, unknown> {
|
|
162
176
|
expect(stdoutSpy).toHaveBeenCalledTimes(1);
|
|
163
177
|
const raw = stdoutSpy.mock.calls[0][0] as string;
|
|
164
|
-
|
|
178
|
+
const parsed: unknown = JSON.parse(raw);
|
|
179
|
+
return requireRecord(parsed, 'stdout JSON');
|
|
165
180
|
}
|
|
166
181
|
|
|
167
182
|
// ── Capability ON: both agents enabled, API key set ──────────────────────
|
|
@@ -178,14 +193,11 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
178
193
|
});
|
|
179
194
|
|
|
180
195
|
const output = parseJsonOutput();
|
|
181
|
-
|
|
182
|
-
expect(output).
|
|
183
|
-
|
|
184
|
-
expect(
|
|
185
|
-
expect(
|
|
186
|
-
expect(obj.codeRuleCapability?.enabled).toBe(true);
|
|
187
|
-
expect(obj.codeRuleCapability?.disabledReason).toBeUndefined();
|
|
188
|
-
expect(obj.capabilityStatus).toContain('ON');
|
|
196
|
+
const codeRuleCapability = requireRecord(output.codeRuleCapability, 'codeRuleCapability');
|
|
197
|
+
expect(output.status).toBe('dry_run');
|
|
198
|
+
expect(codeRuleCapability.enabled).toBe(true);
|
|
199
|
+
expect(codeRuleCapability.disabledReason).toBeUndefined();
|
|
200
|
+
expect(String(output.capabilityStatus)).toContain('ON');
|
|
189
201
|
// exitCode must NOT be set for dry_run success
|
|
190
202
|
expect(process.exitCode).toBeUndefined();
|
|
191
203
|
});
|
|
@@ -203,16 +215,13 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
203
215
|
await handleRunRuleHost({ workspace, painId: 'pain-flag-default', dryRun: true, json: true });
|
|
204
216
|
|
|
205
217
|
const output = parseJsonOutput();
|
|
206
|
-
|
|
207
|
-
expect(
|
|
208
|
-
expect(output).not.toBeNull();
|
|
209
|
-
const obj = output as { status: string; codeRuleCapability?: { enabled: boolean; disabledReason?: string }; capabilityStatus?: string };
|
|
210
|
-
expect(obj.status).toBe('dry_run');
|
|
218
|
+
const codeRuleCapability = requireRecord(output.codeRuleCapability, 'codeRuleCapability');
|
|
219
|
+
expect(output.status).toBe('dry_run');
|
|
211
220
|
// PRI-435: code_rule_capability is now a core flag — defaults ON even when omitted from config.
|
|
212
221
|
// It cannot be disabled by config. The capability is ON when artificer+evaluator are configured.
|
|
213
|
-
expect(
|
|
214
|
-
expect(
|
|
215
|
-
expect(String(
|
|
222
|
+
expect(codeRuleCapability).toEqual(expect.objectContaining({ enabled: true }));
|
|
223
|
+
expect(codeRuleCapability.disabledReason).toBeUndefined();
|
|
224
|
+
expect(String(output.capabilityStatus)).toContain('ON');
|
|
216
225
|
});
|
|
217
226
|
|
|
218
227
|
it('PRI-435: explicit emergency disable via code_rule_capability.enabled=false is observable', async () => {
|
|
@@ -229,16 +238,13 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
229
238
|
await handleRunRuleHost({ workspace, painId: 'pain-emergency-disable', dryRun: true, json: true });
|
|
230
239
|
|
|
231
240
|
const output = parseJsonOutput();
|
|
232
|
-
|
|
233
|
-
expect(
|
|
234
|
-
expect(output).not.toBeNull();
|
|
235
|
-
const obj = output as { status: string; codeRuleCapability?: { enabled: boolean; disabledReason?: string }; capabilityStatus?: string };
|
|
236
|
-
expect(obj.status).toBe('dry_run');
|
|
241
|
+
const codeRuleCapability = requireRecord(output.codeRuleCapability, 'codeRuleCapability');
|
|
242
|
+
expect(output.status).toBe('dry_run');
|
|
237
243
|
// PRI-435: Emergency disable via code_rule_capability.enabled=false is preserved.
|
|
238
244
|
// The capability is OFF with a structured reason.
|
|
239
|
-
expect(
|
|
240
|
-
expect(String(
|
|
241
|
-
expect(String(
|
|
245
|
+
expect(codeRuleCapability).toEqual(expect.objectContaining({ enabled: false }));
|
|
246
|
+
expect(String(codeRuleCapability.disabledReason)).toContain('feature flag');
|
|
247
|
+
expect(String(output.capabilityStatus)).toContain('OFF');
|
|
242
248
|
});
|
|
243
249
|
|
|
244
250
|
it('reports the resolved runtime profile for every executed agent', async () => {
|
|
@@ -271,10 +277,17 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
271
277
|
|
|
272
278
|
await handleRunRuleHost({ workspace, painId: 'pain-disabled-philosopher', confirm: true, json: true });
|
|
273
279
|
|
|
280
|
+
// PRI-461: readiness gate catches disabled required agents BEFORE adapter
|
|
281
|
+
// construction, returning status='refused' with a structured reason instead
|
|
282
|
+
// of the old opaque 'agent_runtime_resolution_failed' error.
|
|
274
283
|
const output = parseJsonOutput();
|
|
275
|
-
expect(output
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
expect(isRecord(output)).toBe(true);
|
|
285
|
+
if (!isRecord(output)) {
|
|
286
|
+
throw new Error('output is not a record');
|
|
287
|
+
}
|
|
288
|
+
expect(output.status).toBe('refused');
|
|
289
|
+
expect(String(output.reason)).toContain('philosopher');
|
|
290
|
+
expect(typeof output.nextAction).toBe('string');
|
|
278
291
|
expect(process.exitCode).toBe(1);
|
|
279
292
|
expect(fs.existsSync(path.join(workspace, '.state', 'runtime-v2.sqlite'))).toBe(false);
|
|
280
293
|
});
|
|
@@ -308,10 +321,10 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
308
321
|
});
|
|
309
322
|
|
|
310
323
|
const output = parseJsonOutput();
|
|
311
|
-
const
|
|
312
|
-
expect(
|
|
313
|
-
expect(
|
|
314
|
-
expect(
|
|
324
|
+
const codeRuleCapability = requireRecord(output.codeRuleCapability, 'codeRuleCapability');
|
|
325
|
+
expect(output.status).toBe('dry_run');
|
|
326
|
+
expect(codeRuleCapability.enabled).toBe(false);
|
|
327
|
+
expect(String(codeRuleCapability.disabledReason)).toContain('artificer');
|
|
315
328
|
});
|
|
316
329
|
|
|
317
330
|
// ── Capability OFF: evaluator disabled ───────────────────────────────────
|
|
@@ -328,10 +341,10 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
328
341
|
});
|
|
329
342
|
|
|
330
343
|
const output = parseJsonOutput();
|
|
331
|
-
const
|
|
332
|
-
expect(
|
|
333
|
-
expect(
|
|
334
|
-
expect(
|
|
344
|
+
const codeRuleCapability = requireRecord(output.codeRuleCapability, 'codeRuleCapability');
|
|
345
|
+
expect(output.status).toBe('dry_run');
|
|
346
|
+
expect(codeRuleCapability.enabled).toBe(false);
|
|
347
|
+
expect(String(codeRuleCapability.disabledReason)).toContain('evaluator');
|
|
335
348
|
});
|
|
336
349
|
|
|
337
350
|
// ── Capability OFF: API key not set ──────────────────────────────────────
|
|
@@ -393,10 +406,11 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
393
406
|
});
|
|
394
407
|
|
|
395
408
|
const output = parseJsonOutput();
|
|
396
|
-
const
|
|
397
|
-
expect(
|
|
398
|
-
expect(
|
|
399
|
-
expect(
|
|
409
|
+
const codeRuleCapability = requireRecord(output.codeRuleCapability, 'codeRuleCapability');
|
|
410
|
+
expect(output.status).toBe('dry_run');
|
|
411
|
+
expect(codeRuleCapability.enabled).toBe(false);
|
|
412
|
+
expect(String(codeRuleCapability.disabledReason)).toContain('TEST_RULEHOST_ARTIFICER_KEY');
|
|
413
|
+
expect(String(codeRuleCapability.disabledReason)).toContain('not set');
|
|
400
414
|
});
|
|
401
415
|
|
|
402
416
|
// ── CLI gate: mutual exclusivity ─────────────────────────────────────────
|
|
@@ -414,10 +428,9 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
414
428
|
});
|
|
415
429
|
|
|
416
430
|
const output = parseJsonOutput();
|
|
417
|
-
|
|
418
|
-
expect(
|
|
419
|
-
expect(
|
|
420
|
-
expect(obj.nextAction).toBeTruthy();
|
|
431
|
+
expect(output.status).toBe('failed');
|
|
432
|
+
expect(String(output.reason)).toContain('mutually exclusive');
|
|
433
|
+
expect(output.nextAction).toBeTruthy();
|
|
421
434
|
expect(process.exitCode).toBe(1);
|
|
422
435
|
});
|
|
423
436
|
|
|
@@ -435,10 +448,9 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
435
448
|
});
|
|
436
449
|
|
|
437
450
|
const output = parseJsonOutput();
|
|
438
|
-
|
|
439
|
-
expect(
|
|
440
|
-
expect(
|
|
441
|
-
expect(obj.nextAction).toBeTruthy();
|
|
451
|
+
expect(output.status).toBe('failed');
|
|
452
|
+
expect(String(output.reason)).toContain('painId');
|
|
453
|
+
expect(output.nextAction).toBeTruthy();
|
|
442
454
|
expect(process.exitCode).toBe(1);
|
|
443
455
|
});
|
|
444
456
|
|
|
@@ -480,8 +492,7 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
480
492
|
});
|
|
481
493
|
|
|
482
494
|
const output = parseJsonOutput();
|
|
483
|
-
|
|
484
|
-
expect(obj.status).toBe('dry_run');
|
|
495
|
+
expect(output.status).toBe('dry_run');
|
|
485
496
|
// Must NOT set exitCode for dry_run
|
|
486
497
|
expect(process.exitCode).toBeUndefined();
|
|
487
498
|
});
|
|
@@ -501,10 +512,9 @@ describe('runRuleHost production-wiring (PRI-429) — deterministic, no LLM', ()
|
|
|
501
512
|
});
|
|
502
513
|
|
|
503
514
|
const output = parseJsonOutput();
|
|
504
|
-
|
|
505
|
-
expect(
|
|
506
|
-
expect(
|
|
507
|
-
expect(obj.nextAction).toBeTruthy();
|
|
515
|
+
expect(output.status).toBe('failed');
|
|
516
|
+
expect(String(output.reason)).toContain('unsupported channel');
|
|
517
|
+
expect(output.nextAction).toBeTruthy();
|
|
508
518
|
expect(process.exitCode).toBe(1);
|
|
509
519
|
});
|
|
510
520
|
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pd central sync command implementation.
|
|
3
|
-
*
|
|
4
|
-
* Usage: pd central sync
|
|
5
|
-
*
|
|
6
|
-
* Triggers a sync cycle via CentralDatabase.syncAll() and reports
|
|
7
|
-
* per-workspace sync results with exit code 0 on success, non-zero on failure.
|
|
8
|
-
*/
|
|
9
|
-
export declare function handleCentralSync(): Promise<void>;
|
|
10
|
-
//# sourceMappingURL=central-sync.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"central-sync.d.ts","sourceRoot":"","sources":["../../src/commands/central-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBvD"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pd central sync command implementation.
|
|
3
|
-
*
|
|
4
|
-
* Usage: pd central sync
|
|
5
|
-
*
|
|
6
|
-
* Triggers a sync cycle via CentralDatabase.syncAll() and reports
|
|
7
|
-
* per-workspace sync results with exit code 0 on success, non-zero on failure.
|
|
8
|
-
*/
|
|
9
|
-
async function loadCentralDatabase() {
|
|
10
|
-
const importModule = Function('specifier', 'return import(specifier)');
|
|
11
|
-
return importModule('../../../openclaw-plugin/src/service/central-database.js');
|
|
12
|
-
}
|
|
13
|
-
export async function handleCentralSync() {
|
|
14
|
-
try {
|
|
15
|
-
const { CentralDatabase } = await loadCentralDatabase();
|
|
16
|
-
const centralDb = new CentralDatabase();
|
|
17
|
-
const results = centralDb.syncAll();
|
|
18
|
-
const totalRecords = Array.from(results.values()).reduce((sum, count) => sum + count, 0);
|
|
19
|
-
const workspaceCount = results.size;
|
|
20
|
-
console.log(`Sync complete — ${totalRecords} records across ${workspaceCount} workspace(s).`);
|
|
21
|
-
for (const [workspaceName, count] of results.entries()) {
|
|
22
|
-
console.log(` ${workspaceName}: ${count} records`);
|
|
23
|
-
}
|
|
24
|
-
centralDb.dispose();
|
|
25
|
-
}
|
|
26
|
-
catch (err) {
|
|
27
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
28
|
-
console.error(`Error: Sync failed — ${message}`);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=central-sync.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"central-sync.js","sourceRoot":"","sources":["../../src/commands/central-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,KAAK,UAAU,mBAAmB;IAIhC,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAKnE,CAAC;IACH,OAAO,YAAY,CAAC,0DAA0D,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC;QACH,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;QACxD,MAAM,SAAS,GAAG,IAAI,eAAe,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QAEpC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;QACzF,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;QAEpC,OAAO,CAAC,GAAG,CAAC,mBAAmB,YAAY,mBAAmB,cAAc,gBAAgB,CAAC,CAAC;QAE9F,KAAK,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,KAAK,aAAa,KAAK,KAAK,UAAU,CAAC,CAAC;QACtD,CAAC;QAED,SAAS,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pd central sync command implementation.
|
|
3
|
-
*
|
|
4
|
-
* Usage: pd central sync
|
|
5
|
-
*
|
|
6
|
-
* Triggers a sync cycle via CentralDatabase.syncAll() and reports
|
|
7
|
-
* per-workspace sync results with exit code 0 on success, non-zero on failure.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
async function loadCentralDatabase(): Promise<{ CentralDatabase: new () => {
|
|
11
|
-
syncAll(): Map<string, number>;
|
|
12
|
-
dispose(): void;
|
|
13
|
-
} }> {
|
|
14
|
-
const importModule = Function('specifier', 'return import(specifier)') as (specifier: string) => Promise<{
|
|
15
|
-
CentralDatabase: new () => {
|
|
16
|
-
syncAll(): Map<string, number>;
|
|
17
|
-
dispose(): void;
|
|
18
|
-
};
|
|
19
|
-
}>;
|
|
20
|
-
return importModule('../../../openclaw-plugin/src/service/central-database.js');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function handleCentralSync(): Promise<void> {
|
|
24
|
-
try {
|
|
25
|
-
const { CentralDatabase } = await loadCentralDatabase();
|
|
26
|
-
const centralDb = new CentralDatabase();
|
|
27
|
-
const results = centralDb.syncAll();
|
|
28
|
-
|
|
29
|
-
const totalRecords = Array.from(results.values()).reduce((sum, count) => sum + count, 0);
|
|
30
|
-
const workspaceCount = results.size;
|
|
31
|
-
|
|
32
|
-
console.log(`Sync complete — ${totalRecords} records across ${workspaceCount} workspace(s).`);
|
|
33
|
-
|
|
34
|
-
for (const [workspaceName, count] of results.entries()) {
|
|
35
|
-
console.log(` ${workspaceName}: ${count} records`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
centralDb.dispose();
|
|
39
|
-
} catch (err) {
|
|
40
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
-
console.error(`Error: Sync failed — ${message}`);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
}
|