@cleocode/caamp 2026.5.84 → 2026.5.86

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/cli.js CHANGED
@@ -44,6 +44,7 @@ import {
44
44
  recommendSkills,
45
45
  recordSkillInstall,
46
46
  registerDoctorBridge,
47
+ registerSkillsDoctorAdopt,
47
48
  removeMcpServer,
48
49
  removeMcpServerFromAll,
49
50
  removeSkillFromLock,
@@ -60,7 +61,7 @@ import {
60
61
  tokenizeCriteriaValue,
61
62
  updateInstructionsSingleOperation,
62
63
  validateSkill
63
- } from "./chunk-QSJSM57K.js";
64
+ } from "./chunk-WXL7RPS4.js";
64
65
  import {
65
66
  buildSkillsMap,
66
67
  checkAllInjections,
@@ -4394,6 +4395,76 @@ Show example inputs and expected outputs.
4394
4395
  // src/commands/skills/install.ts
4395
4396
  import { existsSync as existsSync12 } from "fs";
4396
4397
  import pc12 from "picocolors";
4398
+
4399
+ // src/core/skills/trust-gate-adapter.ts
4400
+ var cachedCore;
4401
+ async function resolveCore() {
4402
+ if (cachedCore !== void 0) return cachedCore;
4403
+ try {
4404
+ const mod = await import("@cleocode/core");
4405
+ cachedCore = mod;
4406
+ } catch {
4407
+ cachedCore = null;
4408
+ process.stderr.write(
4409
+ "[caamp] WARNING: @cleocode/core unavailable \u2014 skipping trust gate (skill installs not security-checked)\n"
4410
+ );
4411
+ }
4412
+ return cachedCore;
4413
+ }
4414
+ async function evaluateSkillTrustGate(localPath, source, force = false) {
4415
+ const core = await resolveCore();
4416
+ if (!core) {
4417
+ return {
4418
+ decision: "allow",
4419
+ reason: "Trust gate skipped \u2014 @cleocode/core not available",
4420
+ scan: {
4421
+ skillName: localPath.split("/").filter(Boolean).pop() ?? localPath,
4422
+ source,
4423
+ trustLevel: "community",
4424
+ verdict: "safe",
4425
+ findings: [],
4426
+ scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
4427
+ summary: "core-unavailable"
4428
+ }
4429
+ };
4430
+ }
4431
+ const scan = core.scanSkill(localPath, source);
4432
+ const gate = core.shouldAllowInstall(scan, force);
4433
+ return { decision: gate.decision, reason: gate.reason, scan };
4434
+ }
4435
+ async function evaluateFederationGate(source, opts = {}) {
4436
+ const core = await resolveCore();
4437
+ if (!core) {
4438
+ return {
4439
+ decision: "allow",
4440
+ reason: "Federation gate skipped \u2014 @cleocode/core not available",
4441
+ peer: null,
4442
+ isFederationSource: false,
4443
+ computedChecksum: null,
4444
+ expectedChecksum: null
4445
+ };
4446
+ }
4447
+ return core.evaluateFederationInstallGate({
4448
+ source,
4449
+ artefactPath: opts.artefactPath,
4450
+ expectedChecksum: opts.expectedChecksum,
4451
+ approveNewSource: opts.approveNewSource
4452
+ });
4453
+ }
4454
+ async function recordSkillTrustBypass(scan, reason = null) {
4455
+ const core = await resolveCore();
4456
+ if (!core) return;
4457
+ try {
4458
+ core.recordTrustBypass(scan, reason);
4459
+ } catch (err) {
4460
+ process.stderr.write(
4461
+ `[caamp] WARNING: failed to record trust-bypass audit row: ${err instanceof Error ? err.message : String(err)}
4462
+ `
4463
+ );
4464
+ }
4465
+ }
4466
+
4467
+ // src/commands/skills/install.ts
4397
4468
  function registerSkillsInstall(parent) {
4398
4469
  parent.command("install").description("Install a skill from GitHub, URL, marketplace, or registered skill library").argument("[source]", "Skill source (GitHub URL, owner/repo, @author/name, skill-name)").option(
4399
4470
  "-a, --agent <name>",
@@ -4403,6 +4474,12 @@ function registerSkillsInstall(parent) {
4403
4474
  ).option("-g, --global", "Install globally").option("-y, --yes", "Skip confirmation").option("--all", "Install to all detected agents").option(
4404
4475
  "--profile <name>",
4405
4476
  "Install a skill library profile (minimal, core, recommended, full)"
4477
+ ).option(
4478
+ "--force",
4479
+ "Override trust-gate block decisions (audited to .cleo/audit/skill-trust-bypass.jsonl)"
4480
+ ).option(
4481
+ "--allow-new-source",
4482
+ "Bypass first-install confirmation prompt for unknown federation sources (non-TTY safe)"
4406
4483
  ).option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(
4407
4484
  async (source, opts) => {
4408
4485
  const operation = "skills.install";
@@ -4629,6 +4706,100 @@ function registerSkillsInstall(parent) {
4629
4706
  console.error(pc12.red(message));
4630
4707
  process.exit(1);
4631
4708
  }
4709
+ if (sourceType !== "library" && sourceType !== "package") {
4710
+ const fedGate = await evaluateFederationGate(sourceValue, {
4711
+ artefactPath: localPath,
4712
+ approveNewSource: opts.allowNewSource === true
4713
+ });
4714
+ if (fedGate.decision === "block-checksum") {
4715
+ const message = `Federation install blocked: ${fedGate.reason}`;
4716
+ if (format === "json") {
4717
+ emitJsonError(
4718
+ operation,
4719
+ mvi,
4720
+ ErrorCodes.FEDERATION_CHECKSUM_MISMATCH,
4721
+ message,
4722
+ ErrorCategories.VALIDATION,
4723
+ {
4724
+ expectedChecksum: fedGate.expectedChecksum,
4725
+ computedChecksum: fedGate.computedChecksum
4726
+ }
4727
+ );
4728
+ }
4729
+ console.error(pc12.red(message));
4730
+ process.exit(1);
4731
+ }
4732
+ if (fedGate.decision === "prompt-first-install") {
4733
+ const message = `${fedGate.reason} Use --allow-new-source to approve in non-interactive contexts.`;
4734
+ if (format === "json") {
4735
+ emitJsonError(
4736
+ operation,
4737
+ mvi,
4738
+ ErrorCodes.FEDERATION_UNKNOWN_SOURCE_INTERACTIVE_REQUIRED,
4739
+ message,
4740
+ ErrorCategories.VALIDATION,
4741
+ { peer: fedGate.peer?.url ?? null }
4742
+ );
4743
+ }
4744
+ console.error(pc12.yellow(message));
4745
+ process.exit(1);
4746
+ }
4747
+ }
4748
+ if (sourceType !== "library" && sourceType !== "package") {
4749
+ const gate = await evaluateSkillTrustGate(localPath, sourceValue, opts.force ?? false);
4750
+ if (gate.decision === "block") {
4751
+ const message = `Trust gate blocked install: ${gate.reason}`;
4752
+ if (format === "json") {
4753
+ const envelope = buildEnvelope(
4754
+ operation,
4755
+ mvi,
4756
+ { scan: gate.scan },
4757
+ {
4758
+ code: ErrorCodes.SKILL_TRUST_GATE_BLOCKED,
4759
+ message,
4760
+ category: ErrorCategories.VALIDATION,
4761
+ retryable: false,
4762
+ retryAfterMs: null,
4763
+ details: {
4764
+ verdict: gate.scan.verdict,
4765
+ trustLevel: gate.scan.trustLevel,
4766
+ findingsCount: gate.scan.findings.length
4767
+ }
4768
+ }
4769
+ );
4770
+ console.error(JSON.stringify(envelope, null, 2));
4771
+ } else {
4772
+ console.error(pc12.red(`
4773
+ ${message}`));
4774
+ for (const f of gate.scan.findings.slice(0, 5)) {
4775
+ console.error(
4776
+ pc12.dim(
4777
+ ` [${f.severity}] ${f.category} ${f.file}:${f.line} \u2014 ${f.description}`
4778
+ )
4779
+ );
4780
+ }
4781
+ console.error(pc12.yellow(" Use --force to override (audited)."));
4782
+ }
4783
+ process.exit(1);
4784
+ }
4785
+ if (gate.decision === "ask") {
4786
+ const message = `Trust gate requires confirmation: ${gate.reason}`;
4787
+ if (format === "json") {
4788
+ emitJsonError(
4789
+ operation,
4790
+ mvi,
4791
+ ErrorCodes.SKILL_TRUST_GATE_BLOCKED,
4792
+ message,
4793
+ ErrorCategories.VALIDATION
4794
+ );
4795
+ }
4796
+ console.error(pc12.red(message));
4797
+ process.exit(1);
4798
+ }
4799
+ if (opts.force === true && gate.scan.verdict !== "safe") {
4800
+ await recordSkillTrustBypass(gate.scan, "operator --force on caamp skills install");
4801
+ }
4802
+ }
4632
4803
  const result = await dispatchInstallSkillAcrossProviders(
4633
4804
  localPath,
4634
4805
  skillName,
@@ -5411,6 +5582,7 @@ function registerSkillsCommands(program2) {
5411
5582
  registerSkillsValidate(skills);
5412
5583
  registerSkillsDoctorMigrate(skills);
5413
5584
  registerSkillsDoctor(skills);
5585
+ registerSkillsDoctorAdopt(skills);
5414
5586
  }
5415
5587
 
5416
5588
  // src/cli.ts