@cleocode/caamp 2026.4.9 → 2026.4.11

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.
@@ -760,19 +760,25 @@ var PiHarness = class {
760
760
  return scope.kind === "global" ? join5(getPiAgentDir2(), "AGENTS.md") : join5(scope.projectDir, "AGENTS.md");
761
761
  }
762
762
  // ── Skills ──────────────────────────────────────────────────────────
763
- /** {@inheritDoc Harness.installSkill} */
763
+ /**
764
+ * Install a skill directory into the resolved Pi skills location.
765
+ */
764
766
  async installSkill(sourcePath, skillName, scope) {
765
767
  const targetDir = join5(this.skillsDir(scope), skillName);
766
768
  await rm3(targetDir, { recursive: true, force: true });
767
769
  await mkdir3(dirname2(targetDir), { recursive: true });
768
770
  await cp3(sourcePath, targetDir, { recursive: true });
769
771
  }
770
- /** {@inheritDoc Harness.removeSkill} */
772
+ /**
773
+ * Remove a skill directory from the resolved Pi skills location.
774
+ */
771
775
  async removeSkill(skillName, scope) {
772
776
  const targetDir = join5(this.skillsDir(scope), skillName);
773
777
  await rm3(targetDir, { recursive: true, force: true });
774
778
  }
775
- /** {@inheritDoc Harness.listSkills} */
779
+ /**
780
+ * List the installed skill directories at the given scope.
781
+ */
776
782
  async listSkills(scope) {
777
783
  const dir = this.skillsDir(scope);
778
784
  if (!existsSync4(dir)) return [];
@@ -780,7 +786,10 @@ var PiHarness = class {
780
786
  return entries.filter((e) => e.isDirectory()).map((e) => e.name);
781
787
  }
782
788
  // ── Instructions ────────────────────────────────────────────────────
783
- /** {@inheritDoc Harness.injectInstructions} */
789
+ /**
790
+ * Inject or replace a CAAMP-managed instruction block inside the Pi
791
+ * `AGENTS.md` file for the resolved scope.
792
+ */
784
793
  async injectInstructions(content, scope) {
785
794
  const filePath = this.agentsMdPath(scope);
786
795
  await mkdir3(dirname2(filePath), { recursive: true });
@@ -804,7 +813,10 @@ ${MARKER_END}`;
804
813
  }
805
814
  await writeFile(filePath, updated, "utf8");
806
815
  }
807
- /** {@inheritDoc Harness.removeInstructions} */
816
+ /**
817
+ * Remove the CAAMP-managed instruction block from the Pi `AGENTS.md`
818
+ * file at the resolved scope.
819
+ */
808
820
  async removeInstructions(scope) {
809
821
  const filePath = this.agentsMdPath(scope);
810
822
  if (!existsSync4(filePath)) return;
@@ -1204,7 +1216,9 @@ ${MARKER_END}`;
1204
1216
  });
1205
1217
  }
1206
1218
  // ── Settings ────────────────────────────────────────────────────────
1207
- /** {@inheritDoc Harness.readSettings} */
1219
+ /**
1220
+ * Read the Pi `settings.json` file for the resolved scope.
1221
+ */
1208
1222
  async readSettings(scope) {
1209
1223
  const filePath = this.settingsPath(scope);
1210
1224
  if (!existsSync4(filePath)) return {};
@@ -1215,7 +1229,10 @@ ${MARKER_END}`;
1215
1229
  return {};
1216
1230
  }
1217
1231
  }
1218
- /** {@inheritDoc Harness.writeSettings} */
1232
+ /**
1233
+ * Merge a partial patch into the Pi `settings.json` file for the
1234
+ * resolved scope using an atomic write.
1235
+ */
1219
1236
  async writeSettings(patch, scope) {
1220
1237
  const filePath = this.settingsPath(scope);
1221
1238
  const current = await this.readSettings(scope);
@@ -1223,7 +1240,10 @@ ${MARKER_END}`;
1223
1240
  const merged = deepMerge(currentObj, patch);
1224
1241
  await atomicWriteJson(filePath, merged);
1225
1242
  }
1226
- /** {@inheritDoc Harness.configureModels} */
1243
+ /**
1244
+ * Persist the supplied model-name patterns into `settings.enabledModels`
1245
+ * at the resolved scope.
1246
+ */
1227
1247
  async configureModels(modelPatterns, scope) {
1228
1248
  await this.writeSettings({ enabledModels: modelPatterns }, scope);
1229
1249
  }
@@ -1248,7 +1268,10 @@ ${MARKER_END}`;
1248
1268
  return join5(getPiAgentDir2(), "sessions");
1249
1269
  }
1250
1270
  // ── Extensions (Wave-1, T263) ───────────────────────────────────────
1251
- /** {@inheritDoc Harness.installExtension} */
1271
+ /**
1272
+ * Install a Pi extension `.ts` source file into the resolved tier's
1273
+ * extensions directory, validating that it has a default export.
1274
+ */
1252
1275
  async installExtension(sourcePath, name, tier, projectDir, opts) {
1253
1276
  if (!existsSync4(sourcePath)) {
1254
1277
  throw new Error(`installExtension: source file does not exist: ${sourcePath}`);
@@ -1280,7 +1303,9 @@ ${MARKER_END}`;
1280
1303
  await writeFile(targetPath, contents, "utf8");
1281
1304
  return { targetPath, tier };
1282
1305
  }
1283
- /** {@inheritDoc Harness.removeExtension} */
1306
+ /**
1307
+ * Remove a Pi extension `.ts` source file from the resolved tier.
1308
+ */
1284
1309
  async removeExtension(name, tier, projectDir) {
1285
1310
  const dir = resolveTierDir({ tier, kind: "extensions", projectDir });
1286
1311
  const targetPath = join5(dir, `${name}.ts`);
@@ -1288,7 +1313,10 @@ ${MARKER_END}`;
1288
1313
  await rm3(targetPath, { force: true });
1289
1314
  return true;
1290
1315
  }
1291
- /** {@inheritDoc Harness.listExtensions} */
1316
+ /**
1317
+ * List Pi extension files across every tier in precedence order,
1318
+ * flagging shadowed entries from lower tiers.
1319
+ */
1292
1320
  async listExtensions(projectDir) {
1293
1321
  const tiers = resolveAllTiers("extensions", projectDir);
1294
1322
  const out = [];
@@ -1319,7 +1347,10 @@ ${MARKER_END}`;
1319
1347
  return out;
1320
1348
  }
1321
1349
  // ── Sessions (Wave-1, T264) ─────────────────────────────────────────
1322
- /** {@inheritDoc Harness.listSessions} */
1350
+ /**
1351
+ * List Pi session JSONL files (including subagent children when
1352
+ * requested), summarising only the header line per file.
1353
+ */
1323
1354
  async listSessions(opts) {
1324
1355
  const rootDir = this.sessionsDir();
1325
1356
  if (!existsSync4(rootDir)) return [];
@@ -1359,7 +1390,9 @@ ${MARKER_END}`;
1359
1390
  summaries.sort((a, b) => b.mtimeMs - a.mtimeMs);
1360
1391
  return summaries;
1361
1392
  }
1362
- /** {@inheritDoc Harness.showSession} */
1393
+ /**
1394
+ * Show the full entries of a single Pi session by id.
1395
+ */
1363
1396
  async showSession(id) {
1364
1397
  const summaries = await this.listSessions({ includeSubagents: true });
1365
1398
  const match = summaries.find((s) => s.id === id);
@@ -1375,7 +1408,10 @@ ${MARKER_END}`;
1375
1408
  return { summary: match, entries };
1376
1409
  }
1377
1410
  // ── Models (Wave-1, T265) ───────────────────────────────────────────
1378
- /** {@inheritDoc Harness.readModelsConfig} */
1411
+ /**
1412
+ * Read the Pi `models.json` file for the resolved scope, tolerating
1413
+ * missing or malformed files by returning an empty provider map.
1414
+ */
1379
1415
  async readModelsConfig(scope) {
1380
1416
  const filePath = this.modelsConfigPath(scope);
1381
1417
  if (!existsSync4(filePath)) return { providers: {} };
@@ -1401,12 +1437,18 @@ ${MARKER_END}`;
1401
1437
  return { providers: {} };
1402
1438
  }
1403
1439
  }
1404
- /** {@inheritDoc Harness.writeModelsConfig} */
1440
+ /**
1441
+ * Write the Pi `models.json` file for the resolved scope via an atomic
1442
+ * tmp-then-rename sequence.
1443
+ */
1405
1444
  async writeModelsConfig(config, scope) {
1406
1445
  const filePath = this.modelsConfigPath(scope);
1407
1446
  await atomicWriteJson(filePath, config);
1408
1447
  }
1409
- /** {@inheritDoc Harness.listModels} */
1448
+ /**
1449
+ * Compose a flat `ModelListEntry` list from `models.json` plus the
1450
+ * `enabledModels` and default-model hints in `settings.json`.
1451
+ */
1410
1452
  async listModels(scope) {
1411
1453
  const models = await this.readModelsConfig(scope);
1412
1454
  const settings = await this.readSettings(scope);
@@ -1468,7 +1510,10 @@ ${MARKER_END}`;
1468
1510
  return out;
1469
1511
  }
1470
1512
  // ── Prompts (Wave-1, T266) ──────────────────────────────────────────
1471
- /** {@inheritDoc Harness.installPrompt} */
1513
+ /**
1514
+ * Install a Pi prompt directory (containing `prompt.md`) into the
1515
+ * resolved tier's prompts directory.
1516
+ */
1472
1517
  async installPrompt(sourceDir, name, tier, projectDir, opts) {
1473
1518
  if (!existsSync4(sourceDir)) {
1474
1519
  throw new Error(`installPrompt: source directory does not exist: ${sourceDir}`);
@@ -1494,7 +1539,10 @@ ${MARKER_END}`;
1494
1539
  await cp3(sourceDir, targetPath, { recursive: true });
1495
1540
  return { targetPath, tier };
1496
1541
  }
1497
- /** {@inheritDoc Harness.listPrompts} */
1542
+ /**
1543
+ * List Pi prompt directories across every tier in precedence order,
1544
+ * flagging shadowed entries from lower tiers.
1545
+ */
1498
1546
  async listPrompts(projectDir) {
1499
1547
  const tiers = resolveAllTiers("prompts", projectDir);
1500
1548
  const out = [];
@@ -1522,7 +1570,9 @@ ${MARKER_END}`;
1522
1570
  }
1523
1571
  return out;
1524
1572
  }
1525
- /** {@inheritDoc Harness.removePrompt} */
1573
+ /**
1574
+ * Remove a Pi prompt directory from the resolved tier.
1575
+ */
1526
1576
  async removePrompt(name, tier, projectDir) {
1527
1577
  const dir = resolveTierDir({ tier, kind: "prompts", projectDir });
1528
1578
  const targetPath = join5(dir, name);
@@ -1531,7 +1581,11 @@ ${MARKER_END}`;
1531
1581
  return true;
1532
1582
  }
1533
1583
  // ── Themes (Wave-1, T267) ───────────────────────────────────────────
1534
- /** {@inheritDoc Harness.installTheme} */
1584
+ /**
1585
+ * Install a Pi theme file (`.ts`/`.tsx`/`.mts`/`.json`) into the
1586
+ * resolved tier's themes directory, blocking same-stem conflicts
1587
+ * unless `--force` is supplied.
1588
+ */
1535
1589
  async installTheme(sourceFile, name, tier, projectDir, opts) {
1536
1590
  if (!existsSync4(sourceFile)) {
1537
1591
  throw new Error(`installTheme: source file does not exist: ${sourceFile}`);
@@ -1570,7 +1624,10 @@ ${MARKER_END}`;
1570
1624
  await writeFile(targetPath, contents);
1571
1625
  return { targetPath, tier };
1572
1626
  }
1573
- /** {@inheritDoc Harness.listThemes} */
1627
+ /**
1628
+ * List Pi theme files across every tier in precedence order, flagging
1629
+ * shadowed entries from lower tiers.
1630
+ */
1574
1631
  async listThemes(projectDir) {
1575
1632
  const tiers = resolveAllTiers("themes", projectDir);
1576
1633
  const out = [];
@@ -1602,7 +1659,10 @@ ${MARKER_END}`;
1602
1659
  }
1603
1660
  return out;
1604
1661
  }
1605
- /** {@inheritDoc Harness.removeTheme} */
1662
+ /**
1663
+ * Remove a Pi theme from the resolved tier, matching any of the
1664
+ * supported theme extensions for the given name stem.
1665
+ */
1606
1666
  async removeTheme(name, tier, projectDir) {
1607
1667
  const dir = resolveTierDir({ tier, kind: "themes", projectDir });
1608
1668
  let removed = false;
@@ -1617,14 +1677,14 @@ ${MARKER_END}`;
1617
1677
  }
1618
1678
  // ── CANT profiles (Wave-1, T276) ────────────────────────────────────
1619
1679
  /**
1620
- * {@inheritDoc Harness.installCantProfile}
1680
+ * Install a `.cant` profile into the resolved tier after passing it
1681
+ * through the cant-core validator.
1621
1682
  *
1622
- * @remarks
1623
- * Validates the source via {@link validateCantProfile} before copying so
1624
- * we never persist a `.cant` file the runtime bridge cannot load. The
1625
- * target layout is `<tier-root>/cant/<name>.cant`, resolved through
1626
- * {@link resolveTierDir} so the project/user/global hierarchy stays
1627
- * consistent with the other Wave-1 verbs.
1683
+ * Validates the source via {@link PiHarness.validateCantProfile}
1684
+ * before copying so we never persist a `.cant` file the runtime bridge
1685
+ * cannot load. The target layout is `<tier-root>/cant/<name>.cant`,
1686
+ * resolved through `resolveTierDir` so the project/user/global
1687
+ * hierarchy stays consistent with the other Wave-1 verbs.
1628
1688
  */
1629
1689
  async installCantProfile(sourcePath, name, tier, projectDir, opts) {
1630
1690
  if (!existsSync4(sourcePath)) {
@@ -1658,7 +1718,9 @@ ${MARKER_END}`;
1658
1718
  await writeFile(targetPath, contents);
1659
1719
  return { targetPath, tier, counts: validation.counts };
1660
1720
  }
1661
- /** {@inheritDoc Harness.removeCantProfile} */
1721
+ /**
1722
+ * Remove a `.cant` profile from the resolved tier.
1723
+ */
1662
1724
  async removeCantProfile(name, tier, projectDir) {
1663
1725
  const dir = resolveTierDir({ tier, kind: "cant", projectDir });
1664
1726
  const targetPath = join5(dir, `${name}.cant`);
@@ -1667,10 +1729,10 @@ ${MARKER_END}`;
1667
1729
  return true;
1668
1730
  }
1669
1731
  /**
1670
- * {@inheritDoc Harness.listCantProfiles}
1732
+ * List installed `.cant` profiles across every tier in precedence
1733
+ * order, parsing each file to extract section counts.
1671
1734
  *
1672
- * @remarks
1673
- * Walks every tier in {@link TIER_PRECEDENCE} order, parsing each
1735
+ * Walks every tier in `TIER_PRECEDENCE` order, parsing each
1674
1736
  * discovered `.cant` file via cant-core to extract a
1675
1737
  * {@link CantProfileCounts} bag. Higher-precedence tiers shadow
1676
1738
  * lower-precedence entries with the same name; shadowed entries
@@ -1714,9 +1776,9 @@ ${MARKER_END}`;
1714
1776
  return out;
1715
1777
  }
1716
1778
  /**
1717
- * {@inheritDoc Harness.validateCantProfile}
1779
+ * Validate a `.cant` source file against cant-core's parser and
1780
+ * 42-rule linter, returning section counts and per-diagnostic detail.
1718
1781
  *
1719
- * @remarks
1720
1782
  * Pure validator. Reads the file, runs `parseDocument` to derive
1721
1783
  * counts (when parsing succeeds) and `validateDocument` to collect
1722
1784
  * the 42-rule diagnostic feed. The two calls are kept independent so
@@ -4624,4 +4686,4 @@ export {
4624
4686
  discoverSkillsMulti,
4625
4687
  validateSkill
4626
4688
  };
4627
- //# sourceMappingURL=chunk-JC77OAHA.js.map
4689
+ //# sourceMappingURL=chunk-XVZT7K6F.js.map