@contextecf/guardian-cli 0.1.1 → 0.1.3

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.
@@ -16275,7 +16275,7 @@ function cloneList(values) {
16275
16275
  }
16276
16276
 
16277
16277
  // packages/guardian-cli/src/runtime.ts
16278
- var GUARDIAN_CLI_VERSION = "0.1.1";
16278
+ var GUARDIAN_CLI_VERSION = "0.1.3";
16279
16279
  var GUARDIAN_PROFILE_SCHEMA_VERSION = "contextecf/project-guardian-profile/v1";
16280
16280
  var GUARDIAN_NPM_PACKAGE_NAME = "@contextecf/guardian-cli";
16281
16281
  var GUARDIAN_GLOBAL_INSTALL_COMMAND = `npm install -g ${GUARDIAN_NPM_PACKAGE_NAME}`;
@@ -17286,6 +17286,15 @@ async function statusGuardian(flags, options) {
17286
17286
  const releaseEvidence = await buildGuardianReleaseEvidenceStatus(home);
17287
17287
  const serviceSupervision = await buildGuardianServiceSupervisionStatus(home);
17288
17288
  const osKeyStorage = await buildGuardianOsKeyStorageStatus(home);
17289
+ const privacy = {
17290
+ rawContentCaptureEnabled: profile?.privacy.raw_content_capture_enabled ?? false,
17291
+ cloudSyncEnabled: profile?.privacy.cloud_sync_enabled ?? false,
17292
+ localAppAutopilotEnabled: profile?.privacy.local_app_autopilot_enabled ?? false
17293
+ };
17294
+ const nextCommands = buildGuardianStatusNextCommands({
17295
+ installed: profile !== void 0,
17296
+ daemonStatus: daemonHealth.daemon.status
17297
+ });
17289
17298
  const result = {
17290
17299
  schema_version: "contextecf/project-guardian-status/v1",
17291
17300
  cli_version: GUARDIAN_CLI_VERSION,
@@ -17299,11 +17308,7 @@ async function statusGuardian(flags, options) {
17299
17308
  controlTowerUrl: daemonHealth.controlTowerUrl,
17300
17309
  controlTowerUrlSource: profile?.control_tower?.source ?? "default_loopback",
17301
17310
  daemon: daemonHealth.daemon,
17302
- privacy: {
17303
- rawContentCaptureEnabled: profile?.privacy.raw_content_capture_enabled ?? false,
17304
- cloudSyncEnabled: profile?.privacy.cloud_sync_enabled ?? false,
17305
- localAppAutopilotEnabled: profile?.privacy.local_app_autopilot_enabled ?? false
17306
- },
17311
+ privacy,
17307
17312
  preferences: {
17308
17313
  promptCoachMode: profile?.prompt_coach_mode ?? "not_installed",
17309
17314
  learningGraphEnabled: profile?.learning_graph.enabled ?? false
@@ -17322,7 +17327,8 @@ async function statusGuardian(flags, options) {
17322
17327
  releaseEvidence,
17323
17328
  serviceSupervision,
17324
17329
  osKeyStorage,
17325
- notProvenProductionGates: GUARDIAN_NOT_PROVEN_PRODUCTION_GATES
17330
+ notProvenProductionGates: GUARDIAN_NOT_PROVEN_PRODUCTION_GATES,
17331
+ nextCommands
17326
17332
  };
17327
17333
  if (flags.has("json")) {
17328
17334
  return `${JSON.stringify(result, null, 2)}
@@ -17345,11 +17351,36 @@ async function statusGuardian(flags, options) {
17345
17351
  `Service supervision: ${result.serviceSupervision.status}`,
17346
17352
  `OS key storage: ${result.osKeyStorage.status}`,
17347
17353
  `Not-proven production gates: ${result.notProvenProductionGates.length}`,
17348
- "Privacy: raw capture off, cloud sync off, local app autopilot off",
17349
- result.installed ? "Next: guardian launch" : "Next: guardian install"
17354
+ formatGuardianPrivacyStatus(result.privacy),
17355
+ `Next: ${result.nextCommands.join("; ")}`
17350
17356
  ].filter(Boolean).join("\n")}
17351
17357
  `;
17352
17358
  }
17359
+ function buildGuardianStatusNextCommands(input) {
17360
+ if (!input.installed) {
17361
+ return ["guardian install"];
17362
+ }
17363
+ if (input.daemonStatus === "reachable") {
17364
+ return ["guardian open", "guardian readiness", "guardian extension open-setup"];
17365
+ }
17366
+ if (input.daemonStatus === "unauthorized") {
17367
+ return ["guardian stop", "guardian launch --port=4322", "guardian status"];
17368
+ }
17369
+ if (input.daemonStatus === "token_missing" || input.daemonStatus === "invalid_control_tower_url") {
17370
+ return ["guardian setup", "guardian launch", "guardian status"];
17371
+ }
17372
+ return ["guardian launch", "guardian status"];
17373
+ }
17374
+ function formatGuardianPrivacyStatus(input) {
17375
+ return [
17376
+ `Privacy: raw capture ${formatOnOff(input.rawContentCaptureEnabled)}`,
17377
+ `cloud sync ${formatOnOff(input.cloudSyncEnabled)}`,
17378
+ `local app autopilot ${formatOnOff(input.localAppAutopilotEnabled)}`
17379
+ ].join(", ");
17380
+ }
17381
+ function formatOnOff(enabled) {
17382
+ return enabled ? "on" : "off";
17383
+ }
17353
17384
  async function runControlTowerOpenCommand(flags, options) {
17354
17385
  const stdout = options.stdout ?? process.stdout;
17355
17386
  const stderr = options.stderr ?? process.stderr;
@@ -17436,7 +17467,7 @@ async function runStartCommand(flags, options) {
17436
17467
  const home = resolveGuardianHome(options.env, options.platform);
17437
17468
  const profile = await readProfile(home);
17438
17469
  if (!profile) {
17439
- write(stderr, "Guardian is not installed. Run guardian install first.\n");
17470
+ write(stderr, "Guardian is not installed. Run guardian setup first.\n");
17440
17471
  return 1;
17441
17472
  }
17442
17473
  const host = stringFlag(flags, "host") ?? "127.0.0.1";
@@ -17444,10 +17475,8 @@ async function runStartCommand(flags, options) {
17444
17475
  write(stderr, "Guardian start only accepts loopback hosts: 127.0.0.1, localhost, or ::1.\n");
17445
17476
  return 1;
17446
17477
  }
17447
- const port = numberFlag(flags, "port") ?? 4317;
17448
- const requestedDaemonUrl = formatDaemonBaseUrl(host, port);
17449
- const requestedControlTowerUrl = `${requestedDaemonUrl}/control-tower`;
17450
- const controlTowerSource = host === "127.0.0.1" && port === 4317 ? "default_loopback" : "env_or_flag";
17478
+ const explicitPort = numberFlag(flags, "port");
17479
+ const port = explicitPort ?? 4317;
17451
17480
  let token;
17452
17481
  try {
17453
17482
  token = await readRuntimeToken(home);
@@ -17459,14 +17488,66 @@ async function runStartCommand(flags, options) {
17459
17488
  );
17460
17489
  return 1;
17461
17490
  }
17462
- const healthUrl = resolveDaemonHealthUrl(requestedControlTowerUrl);
17463
- if (!healthUrl.ok) {
17464
- write(stderr, `${healthUrl.error}
17491
+ const healthChecker = options.healthDaemon ?? requestGuardianDaemonHealth;
17492
+ const candidates = explicitPort ? [explicitPort] : Array.from({ length: 8 }, (_, index) => port + index);
17493
+ let selected;
17494
+ let firstTokenMismatch;
17495
+ for (const candidatePort of candidates) {
17496
+ const requestedDaemonUrl2 = formatDaemonBaseUrl(host, candidatePort);
17497
+ const requestedControlTowerUrl2 = `${requestedDaemonUrl2}/control-tower`;
17498
+ const controlTowerSource2 = host === "127.0.0.1" && candidatePort === 4317 ? "default_loopback" : "env_or_flag";
17499
+ const healthUrl2 = resolveDaemonHealthUrl(requestedControlTowerUrl2);
17500
+ if (!healthUrl2.ok) {
17501
+ write(stderr, `${healthUrl2.error}
17465
17502
  `);
17503
+ return 1;
17504
+ }
17505
+ const existing2 = await healthChecker({ url: healthUrl2.url, token });
17506
+ if (existing2.ok && existing2.reachable) {
17507
+ selected = {
17508
+ port: candidatePort,
17509
+ requestedDaemonUrl: requestedDaemonUrl2,
17510
+ requestedControlTowerUrl: requestedControlTowerUrl2,
17511
+ healthUrl: healthUrl2.url,
17512
+ controlTowerSource: controlTowerSource2,
17513
+ existing: existing2
17514
+ };
17515
+ break;
17516
+ }
17517
+ if (existing2.statusCode === 401) {
17518
+ firstTokenMismatch ??= {
17519
+ requestedDaemonUrl: requestedDaemonUrl2,
17520
+ port: candidatePort,
17521
+ healthUrl: healthUrl2.url,
17522
+ existing: existing2
17523
+ };
17524
+ if (explicitPort) {
17525
+ write(stderr, renderDaemonTokenMismatchMessage(requestedDaemonUrl2, candidatePort));
17526
+ return 1;
17527
+ }
17528
+ continue;
17529
+ }
17530
+ selected = {
17531
+ port: candidatePort,
17532
+ requestedDaemonUrl: requestedDaemonUrl2,
17533
+ requestedControlTowerUrl: requestedControlTowerUrl2,
17534
+ healthUrl: healthUrl2.url,
17535
+ controlTowerSource: controlTowerSource2,
17536
+ existing: existing2
17537
+ };
17538
+ break;
17539
+ }
17540
+ if (!selected) {
17541
+ const mismatch = firstTokenMismatch ?? {
17542
+ requestedDaemonUrl: formatDaemonBaseUrl(host, port),
17543
+ port,
17544
+ healthUrl: `${formatDaemonBaseUrl(host, port)}/v1/guardian/admin/health`,
17545
+ existing: { ok: false, reachable: false, statusCode: 401, error: "unauthorized" }
17546
+ };
17547
+ write(stderr, renderDaemonTokenMismatchMessage(mismatch.requestedDaemonUrl, mismatch.port));
17466
17548
  return 1;
17467
17549
  }
17468
- const healthChecker = options.healthDaemon ?? requestGuardianDaemonHealth;
17469
- const existing = await healthChecker({ url: healthUrl.url, token });
17550
+ const { requestedDaemonUrl, requestedControlTowerUrl, healthUrl, controlTowerSource, existing } = selected;
17470
17551
  if (existing.ok && existing.reachable) {
17471
17552
  profile.runtime.daemon_status = "start_requested";
17472
17553
  profile.control_tower = {
@@ -17480,7 +17561,7 @@ async function runStartCommand(flags, options) {
17480
17561
  daemonStatus: profile.runtime.daemon_status,
17481
17562
  daemonUrl: requestedDaemonUrl,
17482
17563
  controlTowerUrl: requestedControlTowerUrl,
17483
- healthUrl: healthUrl.url,
17564
+ healthUrl,
17484
17565
  healthStatus: "reachable",
17485
17566
  nextCommands: ["guardian open", "guardian status", "guardian daemon pair --json"]
17486
17567
  };
@@ -17497,20 +17578,12 @@ async function runStartCommand(flags, options) {
17497
17578
  );
17498
17579
  return 0;
17499
17580
  }
17500
- if (existing.statusCode === 401) {
17501
- write(
17502
- stderr,
17503
- `Guardian daemon at ${requestedDaemonUrl} rejected the local runtime token. Run guardian status or guardian stop before starting another daemon.
17504
- `
17505
- );
17506
- return 1;
17507
- }
17508
17581
  if (!options.startDetachedDaemon) {
17509
17582
  write(stderr, "Guardian detached daemon launcher is unavailable in this runtime.\n");
17510
17583
  return 1;
17511
17584
  }
17512
- const started = await options.startDetachedDaemon({ home, host, port });
17513
- const daemonUrl = normalizeDaemonBaseUrl(started.url, host, port);
17585
+ const started = await options.startDetachedDaemon({ home, host, port: selected.port });
17586
+ const daemonUrl = normalizeDaemonBaseUrl(started.url, host, selected.port);
17514
17587
  const controlTowerUrl = `${daemonUrl}/control-tower`;
17515
17588
  profile.runtime.daemon_status = "start_requested";
17516
17589
  profile.control_tower = {
@@ -17525,7 +17598,7 @@ async function runStartCommand(flags, options) {
17525
17598
  daemonUrl,
17526
17599
  controlTowerUrl,
17527
17600
  pid: started.pid,
17528
- healthUrl: healthUrl.url,
17601
+ healthUrl,
17529
17602
  healthStatus: existing.error ? "unreachable" : "not_reachable",
17530
17603
  nextCommands: ["guardian open", "guardian status", "guardian daemon pair --json"]
17531
17604
  };
@@ -17543,6 +17616,15 @@ async function runStartCommand(flags, options) {
17543
17616
  );
17544
17617
  return 0;
17545
17618
  }
17619
+ function renderDaemonTokenMismatchMessage(requestedDaemonUrl, port) {
17620
+ return [
17621
+ `Guardian found another daemon or container at ${requestedDaemonUrl}, but it rejected this profile's local runtime token.`,
17622
+ "This usually means an older Guardian daemon or Docker demo is still using the port.",
17623
+ `Recovery: stop the other process/container, or run Guardian on a different port with guardian launch --port=${port + 1}.`,
17624
+ `Diagnostics: guardian status; docker ps --filter publish=${port}`,
17625
+ ""
17626
+ ].join("\n");
17627
+ }
17546
17628
  async function runStopCommand(flags, options) {
17547
17629
  const stdout = options.stdout ?? process.stdout;
17548
17630
  const stderr = options.stderr ?? process.stderr;
@@ -1,7 +1,7 @@
1
1
  import type { Writable } from 'node:stream';
2
2
  import { type PolicyPackMarketplaceManifest } from '@contextecf/personal-fabric-contracts';
3
3
  import { SQLitePersonalFabricStore, type PersonalFabricDataImportResult, type PersonalFabricMutableDataDeleteResult, type SQLitePersonalFabricBackupResult } from '@contextecf/personal-fabric-store';
4
- export declare const GUARDIAN_CLI_VERSION = "0.1.1";
4
+ export declare const GUARDIAN_CLI_VERSION = "0.1.3";
5
5
  export declare const GUARDIAN_PROFILE_SCHEMA_VERSION = "contextecf/project-guardian-profile/v1";
6
6
  export declare const GUARDIAN_NPM_PACKAGE_NAME = "@contextecf/guardian-cli";
7
7
  export declare const GUARDIAN_GLOBAL_INSTALL_COMMAND = "npm install -g @contextecf/guardian-cli";
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@contextecf/guardian-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Project Guardian local-first Personal Context Fabric CLI",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "main": "dist/packages/guardian-cli/src/index.js",
8
8
  "types": "dist/packages/guardian-cli/src/index.d.ts",
9
9
  "engines": {
10
- "node": ">=22"
10
+ "node": ">=20.20.0"
11
11
  },
12
12
  "files": [
13
13
  "dist/packages/guardian-cli/src/bin.d.ts",