@cleocode/caamp 2026.4.6 → 2026.4.9
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 +9 -8
- package/dist/{chunk-43GULI6J.js → chunk-JC77OAHA.js} +1766 -400
- package/dist/chunk-JC77OAHA.js.map +1 -0
- package/dist/cli.js +1420 -71
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1860 -293
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-43GULI6J.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1488,328 +1488,501 @@ interface InstructionUpdateSummary {
|
|
|
1488
1488
|
declare function updateInstructionsSingleOperation(providers: Provider[], content: string, scope?: Scope, projectDir?: string): Promise<InstructionUpdateSummary>;
|
|
1489
1489
|
|
|
1490
1490
|
/**
|
|
1491
|
-
*
|
|
1492
|
-
*/
|
|
1493
|
-
/**
|
|
1494
|
-
* Deep merge two objects, with `source` values winning on conflict.
|
|
1495
|
-
*
|
|
1496
|
-
* Recursively merges nested plain objects. Arrays and non-object values from
|
|
1497
|
-
* `source` overwrite `target` values.
|
|
1498
|
-
*
|
|
1499
|
-
* @param target - Base object to merge into
|
|
1500
|
-
* @param source - Object with values that take precedence
|
|
1501
|
-
* @returns A new merged object (does not mutate inputs)
|
|
1491
|
+
* Three-tier scope helper for Pi harness operations.
|
|
1502
1492
|
*
|
|
1503
1493
|
* @remarks
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
1508
|
-
* ```typescript
|
|
1509
|
-
* const merged = deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
|
|
1510
|
-
* // { a: 1, b: { c: 2, d: 3 } }
|
|
1511
|
-
* ```
|
|
1494
|
+
* Per ADR-035 §D1, CAAMP wraps Pi's native two-tier extension model
|
|
1495
|
+
* (project-local `.pi/extensions/` → global `~/.pi/agent/extensions/`)
|
|
1496
|
+
* with a third tier for the CleoOS-managed cross-project hub. The
|
|
1497
|
+
* resulting hierarchy, in precedence order on reads:
|
|
1512
1498
|
*
|
|
1513
|
-
*
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
*
|
|
1499
|
+
* | Tier | Path | Who owns it |
|
|
1500
|
+
* | --------- | ---------------------------------------------- | ------------------------ |
|
|
1501
|
+
* | `project` | `<cwd>/.pi/<asset>/` | repository |
|
|
1502
|
+
* | `user` | `$PI_CODING_AGENT_DIR` or `~/.pi/agent/<asset>`| Pi itself |
|
|
1503
|
+
* | `global` | `$CLEO_HOME/pi-<asset>/` | CleoOS (this wrapper) |
|
|
1518
1504
|
*
|
|
1519
|
-
*
|
|
1520
|
-
*
|
|
1521
|
-
*
|
|
1505
|
+
* Pi's own discovery loader is NOT modified. The `global` tier is either
|
|
1506
|
+
* copied or symlinked into the `user` tier on first use (lazy
|
|
1507
|
+
* materialization), so Pi's native two-tier loader picks extensions up
|
|
1508
|
+
* from the familiar location without needing a patch.
|
|
1522
1509
|
*
|
|
1523
|
-
* @
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1510
|
+
* This helper intentionally lives next to {@link ../harness/pi.ts} rather
|
|
1511
|
+
* than being exported at a higher level — three-tier scope is a Pi
|
|
1512
|
+
* concept today, and other harnesses (if any ever land) will want their
|
|
1513
|
+
* own mapping.
|
|
1526
1514
|
*
|
|
1527
|
-
* @
|
|
1528
|
-
* ```typescript
|
|
1529
|
-
* getNestedValue({ a: { b: { c: 42 } } }, "a.b.c"); // 42
|
|
1530
|
-
* getNestedValue({ a: 1 }, "a.b"); // undefined
|
|
1531
|
-
* ```
|
|
1515
|
+
* @see ADR-035 §D1 (Three-tier scope hierarchy with explicit precedence)
|
|
1532
1516
|
*
|
|
1533
|
-
* @
|
|
1517
|
+
* @packageDocumentation
|
|
1534
1518
|
*/
|
|
1535
|
-
declare function getNestedValue(obj: Record<string, unknown>, keyPath: string): unknown;
|
|
1536
1519
|
/**
|
|
1537
|
-
*
|
|
1538
|
-
*
|
|
1539
|
-
* Creates directories recursively if they do not exist.
|
|
1540
|
-
*
|
|
1541
|
-
* @param filePath - Absolute path to a file (parent directories will be created)
|
|
1520
|
+
* Three-tier scope identifier for Pi harness operations.
|
|
1542
1521
|
*
|
|
1543
1522
|
* @remarks
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1546
|
-
* @
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1549
|
-
* // /path/to/new/dir/ now exists
|
|
1550
|
-
* ```
|
|
1523
|
+
* Each tier maps to a distinct root directory; see the module overview
|
|
1524
|
+
* for the precedence and resolution rules. This is distinct from (and
|
|
1525
|
+
* coexists with) the legacy {@link HarnessScope} discriminated union,
|
|
1526
|
+
* which only supports two tiers (`global`/`project`) and is preserved
|
|
1527
|
+
* for back-compat with existing skill/instruction installers.
|
|
1551
1528
|
*
|
|
1552
1529
|
* @public
|
|
1553
1530
|
*/
|
|
1554
|
-
|
|
1531
|
+
type HarnessTier = 'project' | 'user' | 'global';
|
|
1555
1532
|
|
|
1556
1533
|
/**
|
|
1557
|
-
*
|
|
1558
|
-
*
|
|
1559
|
-
*
|
|
1534
|
+
* Harness layer type definitions.
|
|
1535
|
+
*
|
|
1536
|
+
* @remarks
|
|
1537
|
+
* Defines the contract every first-class CAAMP harness must implement.
|
|
1538
|
+
* A harness is a provider that CAAMP treats natively — not through the
|
|
1539
|
+
* generic MCP-config-file path. Pi is the first (and currently only)
|
|
1540
|
+
* harness. The interface is intentionally generic so future harnesses
|
|
1541
|
+
* (Goose, OpenCode, ...) can slot in without shape churn.
|
|
1542
|
+
*
|
|
1543
|
+
* All methods are async even when they could be sync, so implementations
|
|
1544
|
+
* that need I/O (filesystem, child process) are not forced to lie about
|
|
1545
|
+
* their return types.
|
|
1560
1546
|
*
|
|
1561
1547
|
* @packageDocumentation
|
|
1562
1548
|
*/
|
|
1563
1549
|
|
|
1564
1550
|
/**
|
|
1565
|
-
*
|
|
1566
|
-
*
|
|
1567
|
-
* Dispatches to the appropriate format handler (JSON/JSONC, YAML, or TOML).
|
|
1568
|
-
*
|
|
1569
|
-
* @param filePath - Absolute path to the config file
|
|
1570
|
-
* @param format - Config file format
|
|
1571
|
-
* @returns Parsed config object
|
|
1572
|
-
* @throws If the file cannot be read or the format is unsupported
|
|
1551
|
+
* Scope at which a harness operation should be performed.
|
|
1573
1552
|
*
|
|
1574
1553
|
* @remarks
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1554
|
+
* Harness operations target either the user's global state root (e.g.
|
|
1555
|
+
* `~/.pi/agent/`) or a specific project directory. Project scope requires
|
|
1556
|
+
* the caller to provide the absolute project directory path — the harness
|
|
1557
|
+
* does not infer cwd.
|
|
1577
1558
|
*
|
|
1578
|
-
*
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1559
|
+
* This two-tier scope is the legacy shape used by the skill and
|
|
1560
|
+
* instructions install paths. Pi-specific Wave-1 verbs (extensions,
|
|
1561
|
+
* sessions, models, prompts, themes) use the three-tier
|
|
1562
|
+
* {@link HarnessTier} hierarchy introduced in ADR-035 §D1 alongside this
|
|
1563
|
+
* type — the two coexist and neither replaces the other.
|
|
1582
1564
|
*
|
|
1583
1565
|
* @public
|
|
1584
1566
|
*/
|
|
1585
|
-
|
|
1567
|
+
type HarnessScope = {
|
|
1568
|
+
kind: 'global';
|
|
1569
|
+
} | {
|
|
1570
|
+
kind: 'project';
|
|
1571
|
+
projectDir: string;
|
|
1572
|
+
};
|
|
1586
1573
|
/**
|
|
1587
|
-
*
|
|
1588
|
-
*
|
|
1589
|
-
* Dispatches to the appropriate format handler. For JSONC files, comments are
|
|
1590
|
-
* preserved using `jsonc-parser`.
|
|
1591
|
-
*
|
|
1592
|
-
* @param filePath - Absolute path to the config file
|
|
1593
|
-
* @param format - Config file format
|
|
1594
|
-
* @param key - Dot-notation key path to the servers section (e.g. `"mcpServers"`)
|
|
1595
|
-
* @param serverName - Name/key for the server entry
|
|
1596
|
-
* @param serverConfig - Server configuration object to write
|
|
1597
|
-
* @throws If the format is unsupported
|
|
1574
|
+
* Options accepted by `resolveDefaultTargetProviders` (defined in
|
|
1575
|
+
* `./index.ts`).
|
|
1598
1576
|
*
|
|
1599
1577
|
* @remarks
|
|
1600
|
-
*
|
|
1601
|
-
*
|
|
1578
|
+
* Both fields are optional. When the entire options object is omitted the
|
|
1579
|
+
* helper behaves exactly as it did pre-ADR-035 §D7 in `auto` mode with Pi
|
|
1580
|
+
* installed — the no-regression contract for existing callers.
|
|
1602
1581
|
*
|
|
1603
|
-
*
|
|
1604
|
-
*
|
|
1605
|
-
*
|
|
1606
|
-
* ```
|
|
1582
|
+
* Lives here in `types.ts` rather than next to the function so that
|
|
1583
|
+
* downstream packages can `import type { ResolveDefaultTargetProvidersOptions }`
|
|
1584
|
+
* without pulling in the harness dispatcher's runtime imports.
|
|
1607
1585
|
*
|
|
1608
1586
|
* @public
|
|
1609
1587
|
*/
|
|
1610
|
-
|
|
1588
|
+
interface ResolveDefaultTargetProvidersOptions {
|
|
1589
|
+
/**
|
|
1590
|
+
* Explicit list of providers requested by the user (e.g. via `--agent`).
|
|
1591
|
+
*
|
|
1592
|
+
* @remarks
|
|
1593
|
+
* When supplied, this list signals that the caller is honouring an
|
|
1594
|
+
* explicit user selection rather than asking for the implicit default.
|
|
1595
|
+
* In `auto` mode, an explicit list that excludes Pi while Pi is installed
|
|
1596
|
+
* triggers a one-time deprecation warning per process. In `force-pi`
|
|
1597
|
+
* mode the explicit list is ignored if it does not contain Pi (Pi is
|
|
1598
|
+
* still required). In `legacy` mode the list is returned verbatim with
|
|
1599
|
+
* no warning.
|
|
1600
|
+
*
|
|
1601
|
+
* Pass `undefined` (or omit entirely) to request the implicit default
|
|
1602
|
+
* resolution.
|
|
1603
|
+
*
|
|
1604
|
+
* @defaultValue undefined
|
|
1605
|
+
*/
|
|
1606
|
+
explicit?: Provider[];
|
|
1607
|
+
}
|
|
1611
1608
|
/**
|
|
1612
|
-
*
|
|
1613
|
-
*
|
|
1614
|
-
* @param filePath - Absolute path to the config file
|
|
1615
|
-
* @param format - Config file format
|
|
1616
|
-
* @param key - Dot-notation key path to the servers section
|
|
1617
|
-
* @param serverName - Name/key of the server entry to remove
|
|
1618
|
-
* @returns `true` if the entry was removed, `false` otherwise
|
|
1619
|
-
* @throws If the format is unsupported
|
|
1609
|
+
* Controls how `resolveDefaultTargetProviders` (defined in `./index.ts`)
|
|
1610
|
+
* selects target providers at runtime invocation time.
|
|
1620
1611
|
*
|
|
1621
1612
|
* @remarks
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1613
|
+
* Introduced by ADR-035 §D7 ("v3 exclusivity") to give users an explicit
|
|
1614
|
+
* knob over how aggressively CAAMP routes runtime commands through Pi
|
|
1615
|
+
* versus other installed providers.
|
|
1624
1616
|
*
|
|
1625
|
-
*
|
|
1626
|
-
*
|
|
1627
|
-
*
|
|
1628
|
-
*
|
|
1617
|
+
* - `'auto'` (default) — Pi is preferred when installed; explicit
|
|
1618
|
+
* `--agent <non-pi>` selections are still honoured but emit a one-time
|
|
1619
|
+
* deprecation warning per process. Behaviourally identical to v2026.4.5
|
|
1620
|
+
* when no explicit non-Pi target is supplied.
|
|
1621
|
+
* - `'force-pi'` — Pi is required at runtime invocation. The dispatcher
|
|
1622
|
+
* throws with an `E_NOT_FOUND_RESOURCE`-shaped error when Pi is not
|
|
1623
|
+
* installed; callers decide whether to surface this as an exit code 4
|
|
1624
|
+
* or render a remediation hint.
|
|
1625
|
+
* - `'legacy'` — Pre-exclusivity behaviour. No deprecation warnings, no
|
|
1626
|
+
* hard requirement on Pi. Matches the resolution order CAAMP shipped
|
|
1627
|
+
* before ADR-035 §D7 landed; preserved so users with brittle scripts
|
|
1628
|
+
* can pin until they migrate.
|
|
1629
|
+
*
|
|
1630
|
+
* **Important**: this setting affects RUNTIME INVOCATION paths only. Skill
|
|
1631
|
+
* and instruction install paths
|
|
1632
|
+
* (e.g. {@link dispatchInstallSkillAcrossProviders} and friends) are
|
|
1633
|
+
* UNAFFECTED and continue to dispatch to multiple providers regardless of
|
|
1634
|
+
* mode. See ADR-035 §D7 for the full design rationale.
|
|
1629
1635
|
*
|
|
1630
1636
|
* @public
|
|
1631
1637
|
*/
|
|
1632
|
-
|
|
1633
|
-
|
|
1638
|
+
type ExclusivityMode = 'auto' | 'force-pi' | 'legacy';
|
|
1634
1639
|
/**
|
|
1635
|
-
*
|
|
1640
|
+
* Metadata describing a Pi extension discovered on disk.
|
|
1636
1641
|
*
|
|
1637
|
-
*
|
|
1638
|
-
*
|
|
1642
|
+
* @remarks
|
|
1643
|
+
* Returned by {@link Harness.listExtensions}. The `tier` records which
|
|
1644
|
+
* tier the extension lives at so that callers can surface the
|
|
1645
|
+
* precedence story in their output.
|
|
1646
|
+
*
|
|
1647
|
+
* @public
|
|
1639
1648
|
*/
|
|
1640
|
-
|
|
1649
|
+
interface ExtensionEntry {
|
|
1650
|
+
/** Extension name (file basename without the `.ts` extension). */
|
|
1651
|
+
name: string;
|
|
1652
|
+
/** Tier at which this entry lives. */
|
|
1653
|
+
tier: HarnessTier;
|
|
1654
|
+
/** Absolute on-disk path to the extension file. */
|
|
1655
|
+
path: string;
|
|
1656
|
+
/**
|
|
1657
|
+
* When `true`, this entry is shadowed by a higher-precedence entry
|
|
1658
|
+
* with the same name. Exposed so list output can warn about
|
|
1659
|
+
* cross-tier name collisions per ADR-035 §D1.
|
|
1660
|
+
* @defaultValue false
|
|
1661
|
+
*/
|
|
1662
|
+
shadowed?: boolean;
|
|
1663
|
+
}
|
|
1641
1664
|
/**
|
|
1642
|
-
*
|
|
1665
|
+
* Metadata describing a Pi prompt directory discovered on disk.
|
|
1643
1666
|
*
|
|
1644
|
-
* @
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1649
|
-
* console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
|
|
1650
|
-
* }
|
|
1651
|
-
* ```
|
|
1667
|
+
* @remarks
|
|
1668
|
+
* Returned by {@link Harness.listPrompts}. Prompts are directories
|
|
1669
|
+
* containing a `prompt.md` plus optional metadata. The list operation
|
|
1670
|
+
* reads only the directory listing — never the prompt bodies — to keep
|
|
1671
|
+
* token usage minimal per ADR-035 §D1.
|
|
1652
1672
|
*
|
|
1653
1673
|
* @public
|
|
1654
1674
|
*/
|
|
1655
|
-
interface
|
|
1656
|
-
/**
|
|
1675
|
+
interface PromptEntry {
|
|
1676
|
+
/** Prompt name (directory basename). */
|
|
1657
1677
|
name: string;
|
|
1658
|
-
/**
|
|
1659
|
-
|
|
1660
|
-
/**
|
|
1661
|
-
|
|
1662
|
-
/**
|
|
1663
|
-
|
|
1664
|
-
/** Whether at least one agent was successfully linked. */
|
|
1665
|
-
success: boolean;
|
|
1678
|
+
/** Tier at which this entry lives. */
|
|
1679
|
+
tier: HarnessTier;
|
|
1680
|
+
/** Absolute on-disk path to the prompt directory. */
|
|
1681
|
+
path: string;
|
|
1682
|
+
/** See {@link ExtensionEntry.shadowed}. @defaultValue false */
|
|
1683
|
+
shadowed?: boolean;
|
|
1666
1684
|
}
|
|
1667
1685
|
/**
|
|
1668
|
-
*
|
|
1686
|
+
* Metadata describing a Pi theme discovered on disk.
|
|
1669
1687
|
*
|
|
1670
1688
|
* @remarks
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
*
|
|
1674
|
-
* @param sourcePath - Local path to the skill directory to install
|
|
1675
|
-
* @param skillName - Name for the installed skill
|
|
1676
|
-
* @param providers - Target providers to link the skill to
|
|
1677
|
-
* @param isGlobal - Whether to link to global or project skill directories
|
|
1678
|
-
* @param projectDir - Project directory (defaults to `process.cwd()`)
|
|
1679
|
-
* @returns Install result with linked agents and any errors
|
|
1689
|
+
* Returned by {@link Harness.listThemes}. Themes are single `.ts` or
|
|
1690
|
+
* `.json` files matching Pi's native theme module shape.
|
|
1680
1691
|
*
|
|
1681
|
-
* @
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1692
|
+
* @public
|
|
1693
|
+
*/
|
|
1694
|
+
interface ThemeEntry {
|
|
1695
|
+
/** Theme name (file basename without the extension). */
|
|
1696
|
+
name: string;
|
|
1697
|
+
/** Tier at which this entry lives. */
|
|
1698
|
+
tier: HarnessTier;
|
|
1699
|
+
/** Absolute on-disk path to the theme file. */
|
|
1700
|
+
path: string;
|
|
1701
|
+
/** File extension of the theme file (e.g. `".ts"`, `".json"`). */
|
|
1702
|
+
fileExt: string;
|
|
1703
|
+
/** See {@link ExtensionEntry.shadowed}. @defaultValue false */
|
|
1704
|
+
shadowed?: boolean;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Options accepted by the Pi install verbs (extensions, prompts, themes).
|
|
1688
1708
|
*
|
|
1689
1709
|
* @public
|
|
1690
1710
|
*/
|
|
1691
|
-
|
|
1711
|
+
interface HarnessInstallOptions {
|
|
1712
|
+
/**
|
|
1713
|
+
* When `true`, overwrite an existing file at the target tier. When
|
|
1714
|
+
* `false` (the default) the install verb throws if the target exists.
|
|
1715
|
+
* @defaultValue false
|
|
1716
|
+
*/
|
|
1717
|
+
force?: boolean;
|
|
1718
|
+
}
|
|
1692
1719
|
/**
|
|
1693
|
-
*
|
|
1720
|
+
* Counts of top-level CANT sections discovered in a `.cant` file.
|
|
1694
1721
|
*
|
|
1695
1722
|
* @remarks
|
|
1696
|
-
*
|
|
1697
|
-
*
|
|
1723
|
+
* Returned by {@link Harness.listCantProfiles} and
|
|
1724
|
+
* {@link Harness.validateCantProfile} so that callers can surface a
|
|
1725
|
+
* concise summary of every profile (agents, workflows, pipelines,
|
|
1726
|
+
* top-level hooks, and skill references declared by an agent's
|
|
1727
|
+
* `skills:` property) without reading the full document body.
|
|
1698
1728
|
*
|
|
1699
|
-
*
|
|
1700
|
-
*
|
|
1701
|
-
*
|
|
1702
|
-
*
|
|
1703
|
-
*
|
|
1704
|
-
*
|
|
1705
|
-
*
|
|
1706
|
-
* ```typescript
|
|
1707
|
-
* const { removed, errors } = await removeSkill("my-skill", providers, true, "/my/project");
|
|
1708
|
-
* console.log(`Removed from: ${removed.join(", ")}`);
|
|
1709
|
-
* ```
|
|
1729
|
+
* The cant-core AST tags every section as a single-key wrapper
|
|
1730
|
+
* (`{ Agent: { ... } }`, `{ Workflow: { ... } }`, etc.), so these
|
|
1731
|
+
* counters are derived by walking `document.sections` and bucketing
|
|
1732
|
+
* by tag. `skillCount` aggregates the unique skill names declared
|
|
1733
|
+
* across every Agent section's `skills:` property — it is NOT a
|
|
1734
|
+
* count of standalone `skill { ... }` blocks because cant-core does
|
|
1735
|
+
* not currently expose those at the document level.
|
|
1710
1736
|
*
|
|
1711
1737
|
* @public
|
|
1712
1738
|
*/
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
}
|
|
1739
|
+
interface CantProfileCounts {
|
|
1740
|
+
/** Number of `agent { ... }` sections in the document. */
|
|
1741
|
+
agentCount: number;
|
|
1742
|
+
/** Number of `workflow { ... }` sections in the document. */
|
|
1743
|
+
workflowCount: number;
|
|
1744
|
+
/** Number of `pipeline { ... }` sections in the document. */
|
|
1745
|
+
pipelineCount: number;
|
|
1746
|
+
/**
|
|
1747
|
+
* Number of hook bodies discovered. Top-level `Hook` sections plus
|
|
1748
|
+
* the `hooks` array nested inside every Agent section are summed.
|
|
1749
|
+
*/
|
|
1750
|
+
hookCount: number;
|
|
1751
|
+
/**
|
|
1752
|
+
* Number of distinct skill names referenced via an Agent section's
|
|
1753
|
+
* `skills:` property (e.g. `skills: ["ct-cleo", "ct-task-executor"]`).
|
|
1754
|
+
* The count is de-duplicated across agents within a single document.
|
|
1755
|
+
*/
|
|
1756
|
+
skillCount: number;
|
|
1757
|
+
}
|
|
1717
1758
|
/**
|
|
1718
|
-
*
|
|
1759
|
+
* Metadata describing a `.cant` profile installed at one of the three
|
|
1760
|
+
* Pi harness tiers.
|
|
1719
1761
|
*
|
|
1720
1762
|
* @remarks
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
*
|
|
1724
|
-
*
|
|
1725
|
-
*
|
|
1726
|
-
* @example
|
|
1727
|
-
* ```typescript
|
|
1728
|
-
* const skills = await listCanonicalSkills();
|
|
1729
|
-
* // ["my-skill", "another-skill"]
|
|
1730
|
-
* ```
|
|
1763
|
+
* Returned by {@link Harness.listCantProfiles}. Mirrors the shape of
|
|
1764
|
+
* {@link ExtensionEntry} so consumers can render both with the same
|
|
1765
|
+
* UI primitives, but adds a {@link counts} bag with parsed AST stats
|
|
1766
|
+
* so the list output can summarise each profile without forcing the
|
|
1767
|
+
* caller to re-parse every file.
|
|
1731
1768
|
*
|
|
1732
1769
|
* @public
|
|
1733
1770
|
*/
|
|
1734
|
-
|
|
1735
|
-
|
|
1771
|
+
interface CantProfileEntry {
|
|
1772
|
+
/** Profile name (basename of the `.cant` file without the extension). */
|
|
1773
|
+
name: string;
|
|
1774
|
+
/** Tier at which this entry lives. */
|
|
1775
|
+
tier: HarnessTier;
|
|
1776
|
+
/** Absolute on-disk path to the `.cant` file. */
|
|
1777
|
+
sourcePath: string;
|
|
1778
|
+
/** Parsed section counts for the profile. */
|
|
1779
|
+
counts: CantProfileCounts;
|
|
1780
|
+
/**
|
|
1781
|
+
* When `true`, this entry is shadowed by a higher-precedence entry
|
|
1782
|
+
* with the same name. Mirrors the shadow flag emitted by
|
|
1783
|
+
* {@link Harness.listExtensions} so the same UI logic applies.
|
|
1784
|
+
* @defaultValue false
|
|
1785
|
+
*/
|
|
1786
|
+
shadowedByHigherTier?: boolean;
|
|
1787
|
+
}
|
|
1736
1788
|
/**
|
|
1737
|
-
*
|
|
1789
|
+
* Diagnostic emitted by the cant-core 42-rule validator, normalised to
|
|
1790
|
+
* the harness layer's vocabulary.
|
|
1738
1791
|
*
|
|
1739
1792
|
* @remarks
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
1743
|
-
*
|
|
1744
|
-
* (Goose, OpenCode, ...) can slot in without shape churn.
|
|
1745
|
-
*
|
|
1746
|
-
* All methods are async even when they could be sync, so implementations
|
|
1747
|
-
* that need I/O (filesystem, child process) are not forced to lie about
|
|
1748
|
-
* their return types.
|
|
1793
|
+
* Mirrors the `NativeDiagnostic` shape exported by `@cleocode/cant`'s
|
|
1794
|
+
* native loader. Captured here as a first-class harness type so callers
|
|
1795
|
+
* never have to import from `@cleocode/cant` directly to consume
|
|
1796
|
+
* {@link Harness.validateCantProfile} results.
|
|
1749
1797
|
*
|
|
1750
|
-
* @
|
|
1798
|
+
* @public
|
|
1751
1799
|
*/
|
|
1752
|
-
|
|
1800
|
+
interface CantValidationDiagnostic {
|
|
1801
|
+
/** Cant-core rule id (`PARSE`, `S01`, `P06`, ...). */
|
|
1802
|
+
ruleId: string;
|
|
1803
|
+
/** Human-readable diagnostic message. */
|
|
1804
|
+
message: string;
|
|
1805
|
+
/** 1-based line number where the diagnostic was emitted. */
|
|
1806
|
+
line: number;
|
|
1807
|
+
/** 1-based column number where the diagnostic was emitted. */
|
|
1808
|
+
col: number;
|
|
1809
|
+
/** Severity bucket from cant-core (`error`, `warning`, `info`, `hint`). */
|
|
1810
|
+
severity: 'error' | 'warning' | 'info' | 'hint';
|
|
1811
|
+
}
|
|
1753
1812
|
/**
|
|
1754
|
-
*
|
|
1813
|
+
* Result of validating a `.cant` profile via the cant-core 42-rule
|
|
1814
|
+
* engine.
|
|
1755
1815
|
*
|
|
1756
1816
|
* @remarks
|
|
1757
|
-
*
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1817
|
+
* Returned by {@link Harness.validateCantProfile}. The `valid` flag is
|
|
1818
|
+
* `true` only when no error-severity diagnostics were emitted (warnings
|
|
1819
|
+
* are tolerated, matching cant-core's own definition). The
|
|
1820
|
+
* {@link counts} bag is populated only when parsing succeeded — when
|
|
1821
|
+
* the file is so broken cant-core cannot produce a document, every
|
|
1822
|
+
* counter is `0` and the diagnostics array carries the parse errors.
|
|
1761
1823
|
*
|
|
1762
1824
|
* @public
|
|
1763
1825
|
*/
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1826
|
+
interface ValidateCantProfileResult {
|
|
1827
|
+
/** Whether validation passed (no error-severity diagnostics). */
|
|
1828
|
+
valid: boolean;
|
|
1829
|
+
/** All diagnostics emitted by the 42-rule engine, in source order. */
|
|
1830
|
+
errors: CantValidationDiagnostic[];
|
|
1831
|
+
/** Section counts for the profile (zero when parsing failed). */
|
|
1832
|
+
counts: CantProfileCounts;
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Summary header extracted from the first line of a Pi session JSONL file.
|
|
1836
|
+
*
|
|
1837
|
+
* @remarks
|
|
1838
|
+
* Per ADR-035 §D2, `list`-style session operations read only line 1 of
|
|
1839
|
+
* each `*.jsonl` file — never the full body — so this shape is what
|
|
1840
|
+
* callers consume when enumerating sessions. The full session loader
|
|
1841
|
+
* returns raw JSONL line strings as a separate type
|
|
1842
|
+
* ({@link SessionDocument}).
|
|
1843
|
+
*
|
|
1844
|
+
* @public
|
|
1845
|
+
*/
|
|
1846
|
+
interface SessionSummary {
|
|
1847
|
+
/** Session identifier as recorded in the line-1 header. */
|
|
1848
|
+
id: string;
|
|
1849
|
+
/** Session version as recorded in the line-1 header (e.g. `3`). */
|
|
1850
|
+
version: number;
|
|
1851
|
+
/** ISO-8601 timestamp from the line-1 header, or `null` when absent. */
|
|
1852
|
+
timestamp: string | null;
|
|
1853
|
+
/** Working directory recorded when the session was created. */
|
|
1854
|
+
cwd: string | null;
|
|
1855
|
+
/** Parent session id, if this session was forked from another. */
|
|
1856
|
+
parentSession: string | null;
|
|
1857
|
+
/** Absolute path to the session JSONL file on disk. */
|
|
1858
|
+
filePath: string;
|
|
1859
|
+
/** File modification time in milliseconds since the epoch. */
|
|
1860
|
+
mtimeMs: number;
|
|
1861
|
+
}
|
|
1770
1862
|
/**
|
|
1771
|
-
*
|
|
1772
|
-
* harness's native extension mechanism.
|
|
1863
|
+
* Raw content of a Pi session JSONL file, preserved line-by-line.
|
|
1773
1864
|
*
|
|
1774
1865
|
* @remarks
|
|
1775
|
-
*
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1866
|
+
* Returned by {@link Harness.showSession} when a caller needs the full
|
|
1867
|
+
* body. Each element is one JSONL line as a string (empty trailing
|
|
1868
|
+
* lines are stripped). Callers that need typed entries parse each line
|
|
1869
|
+
* themselves; the harness does not impose a type on entry bodies
|
|
1870
|
+
* because Pi's own entry schema is open-ended (`message`, `thinking`,
|
|
1871
|
+
* `custom`, etc.) and we do not want to fall behind Pi's schema
|
|
1872
|
+
* evolution.
|
|
1873
|
+
*
|
|
1874
|
+
* @public
|
|
1875
|
+
*/
|
|
1876
|
+
interface SessionDocument {
|
|
1877
|
+
/** Header summary (same shape as {@link SessionSummary}). */
|
|
1878
|
+
summary: SessionSummary;
|
|
1879
|
+
/** Raw JSONL lines in file order, excluding the line-1 header. */
|
|
1880
|
+
entries: string[];
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Pi model definition as recorded under `models.json:providers[].models`.
|
|
1779
1884
|
*
|
|
1780
|
-
*
|
|
1781
|
-
* the
|
|
1885
|
+
* @remarks
|
|
1886
|
+
* Mirrors the `ModelDefinition` schema in
|
|
1887
|
+
* `@mariozechner/pi-coding-agent`'s model-registry. Fields are typed
|
|
1888
|
+
* loosely because Pi's schema is evolving (see ADR-035 §D3); the keys
|
|
1889
|
+
* captured here are the minimum a CAAMP verb needs to reason about.
|
|
1782
1890
|
*
|
|
1783
1891
|
* @public
|
|
1784
1892
|
*/
|
|
1785
|
-
interface
|
|
1786
|
-
/**
|
|
1893
|
+
interface PiModelDefinition {
|
|
1894
|
+
/** Model id within the provider (e.g. `"claude-opus-4-20250514"`). */
|
|
1895
|
+
id: string;
|
|
1896
|
+
/** Human-readable model name. */
|
|
1787
1897
|
name: string;
|
|
1788
1898
|
/**
|
|
1789
|
-
*
|
|
1899
|
+
* Whether the model supports reasoning/thinking tokens.
|
|
1790
1900
|
* @defaultValue undefined
|
|
1791
1901
|
*/
|
|
1792
|
-
|
|
1902
|
+
reasoning?: boolean;
|
|
1793
1903
|
/**
|
|
1794
|
-
*
|
|
1904
|
+
* Allowed input modalities (e.g. `["text"]`, `["text", "image"]`).
|
|
1795
1905
|
* @defaultValue undefined
|
|
1796
1906
|
*/
|
|
1797
|
-
|
|
1907
|
+
input?: Array<'text' | 'image'>;
|
|
1798
1908
|
/**
|
|
1799
|
-
*
|
|
1909
|
+
* Context window size in tokens.
|
|
1800
1910
|
* @defaultValue undefined
|
|
1801
1911
|
*/
|
|
1802
|
-
|
|
1912
|
+
contextWindow?: number;
|
|
1803
1913
|
/**
|
|
1804
|
-
*
|
|
1914
|
+
* Maximum output tokens.
|
|
1805
1915
|
* @defaultValue undefined
|
|
1806
1916
|
*/
|
|
1807
|
-
|
|
1917
|
+
maxTokens?: number;
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* Pi provider block as recorded under `models.json:providers[id]`.
|
|
1921
|
+
*
|
|
1922
|
+
* @remarks
|
|
1923
|
+
* Mirrors the `ProviderConfig` schema in Pi's model-registry.
|
|
1924
|
+
*
|
|
1925
|
+
* @public
|
|
1926
|
+
*/
|
|
1927
|
+
interface PiModelProvider {
|
|
1808
1928
|
/**
|
|
1809
|
-
*
|
|
1929
|
+
* Custom base URL for the provider (overrides default).
|
|
1810
1930
|
* @defaultValue undefined
|
|
1811
1931
|
*/
|
|
1812
|
-
|
|
1932
|
+
baseUrl?: string;
|
|
1933
|
+
/**
|
|
1934
|
+
* API key or `$ENV_VAR` reference.
|
|
1935
|
+
* @defaultValue undefined
|
|
1936
|
+
*/
|
|
1937
|
+
apiKey?: string;
|
|
1938
|
+
/**
|
|
1939
|
+
* Custom model definitions declared by the user.
|
|
1940
|
+
* @defaultValue undefined
|
|
1941
|
+
*/
|
|
1942
|
+
models?: PiModelDefinition[];
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Entire `models.json` document shape used by Pi.
|
|
1946
|
+
*
|
|
1947
|
+
* @remarks
|
|
1948
|
+
* Mirrors the `ModelsConfig` schema in Pi's model-registry. CAAMP reads
|
|
1949
|
+
* and writes this file through {@link Harness.readModelsConfig} /
|
|
1950
|
+
* {@link Harness.writeModelsConfig}.
|
|
1951
|
+
*
|
|
1952
|
+
* @public
|
|
1953
|
+
*/
|
|
1954
|
+
interface PiModelsConfig {
|
|
1955
|
+
/** Map of provider id → provider block. */
|
|
1956
|
+
providers: Record<string, PiModelProvider>;
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* A model entry as surfaced by {@link Harness.listModels}.
|
|
1960
|
+
*
|
|
1961
|
+
* @remarks
|
|
1962
|
+
* Models are reported as a union of `models.json`-defined custom models
|
|
1963
|
+
* and `settings.json:enabledModels` selections, with flags that record
|
|
1964
|
+
* whether each entry is currently enabled and whether it is the
|
|
1965
|
+
* configured default.
|
|
1966
|
+
*
|
|
1967
|
+
* @public
|
|
1968
|
+
*/
|
|
1969
|
+
interface ModelListEntry {
|
|
1970
|
+
/** Provider id (e.g. `"anthropic"`). */
|
|
1971
|
+
provider: string;
|
|
1972
|
+
/** Model id within the provider. */
|
|
1973
|
+
id: string;
|
|
1974
|
+
/** Human-readable name, from `models.json` when available. */
|
|
1975
|
+
name: string | null;
|
|
1976
|
+
/** `true` when the model is present in `settings.json:enabledModels`. */
|
|
1977
|
+
enabled: boolean;
|
|
1978
|
+
/** `true` when the model is the configured default. */
|
|
1979
|
+
isDefault: boolean;
|
|
1980
|
+
/**
|
|
1981
|
+
* `true` when this model is defined in `models.json` (custom). When
|
|
1982
|
+
* `false`, the entry originates from `settings.json:enabledModels`
|
|
1983
|
+
* only and is assumed to resolve against Pi's built-in registry.
|
|
1984
|
+
*/
|
|
1985
|
+
custom: boolean;
|
|
1813
1986
|
}
|
|
1814
1987
|
/**
|
|
1815
1988
|
* Description of a subagent task to be spawned under a harness.
|
|
@@ -1820,6 +1993,12 @@ interface McpServerSpec {
|
|
|
1820
1993
|
* is a routing hint passed to the harness; concrete harnesses may use it
|
|
1821
1994
|
* to select an inner agent or simply record it for observability.
|
|
1822
1995
|
*
|
|
1996
|
+
* Per ADR-035 §D6, every spawn has a stable {@link taskId} and is
|
|
1997
|
+
* attributed to a parent session via {@link parentSessionId}. When the
|
|
1998
|
+
* caller provides {@link parentSessionPath}, the harness records a
|
|
1999
|
+
* `subagent_link` custom entry into that file so listing the parent
|
|
2000
|
+
* session surfaces its children automatically.
|
|
2001
|
+
*
|
|
1823
2002
|
* @public
|
|
1824
2003
|
*/
|
|
1825
2004
|
interface SubagentTask {
|
|
@@ -1827,6 +2006,42 @@ interface SubagentTask {
|
|
|
1827
2006
|
targetProviderId: string;
|
|
1828
2007
|
/** The prompt / instruction to give the spawned agent. */
|
|
1829
2008
|
prompt: string;
|
|
2009
|
+
/**
|
|
2010
|
+
* Stable task identifier used to derive the child session filename and
|
|
2011
|
+
* to correlate streamed events with their originating task.
|
|
2012
|
+
*
|
|
2013
|
+
* @remarks
|
|
2014
|
+
* When omitted, the harness generates a short id at spawn time so
|
|
2015
|
+
* legacy callers (pre-ADR-035 §D6) keep working. New callers SHOULD
|
|
2016
|
+
* always supply a deterministic value.
|
|
2017
|
+
*
|
|
2018
|
+
* @defaultValue undefined
|
|
2019
|
+
*/
|
|
2020
|
+
taskId?: string;
|
|
2021
|
+
/**
|
|
2022
|
+
* Identifier of the parent session that owns this subagent.
|
|
2023
|
+
*
|
|
2024
|
+
* @remarks
|
|
2025
|
+
* Used to compose the child session filename
|
|
2026
|
+
* (`subagent-{parentSessionId}-{taskId}.jsonl`) per ADR-035 §D6.
|
|
2027
|
+
* When omitted, the harness substitutes `"orphan"` so legacy callers
|
|
2028
|
+
* still produce a well-formed file path.
|
|
2029
|
+
*
|
|
2030
|
+
* @defaultValue undefined
|
|
2031
|
+
*/
|
|
2032
|
+
parentSessionId?: string;
|
|
2033
|
+
/**
|
|
2034
|
+
* Absolute path to the parent session JSONL file.
|
|
2035
|
+
*
|
|
2036
|
+
* @remarks
|
|
2037
|
+
* When supplied, the harness appends a {@link SubagentLinkEntry} as
|
|
2038
|
+
* a `custom` entry to this file at spawn time so listing the parent
|
|
2039
|
+
* surfaces its children automatically. When omitted, no link entry
|
|
2040
|
+
* is written and the parent session is not modified.
|
|
2041
|
+
*
|
|
2042
|
+
* @defaultValue undefined
|
|
2043
|
+
*/
|
|
2044
|
+
parentSessionPath?: string;
|
|
1830
2045
|
/**
|
|
1831
2046
|
* Working directory for the spawned agent.
|
|
1832
2047
|
* @defaultValue undefined
|
|
@@ -1838,18 +2053,136 @@ interface SubagentTask {
|
|
|
1838
2053
|
*/
|
|
1839
2054
|
env?: Record<string, string>;
|
|
1840
2055
|
/**
|
|
1841
|
-
* Abort signal. When it aborts, the harness will terminate the subagent
|
|
2056
|
+
* Abort signal. When it aborts, the harness will terminate the subagent
|
|
2057
|
+
* via the configured SIGTERM-then-SIGKILL cleanup sequence.
|
|
1842
2058
|
* @defaultValue undefined
|
|
1843
2059
|
*/
|
|
1844
2060
|
signal?: AbortSignal;
|
|
1845
2061
|
}
|
|
1846
2062
|
/**
|
|
1847
|
-
*
|
|
2063
|
+
* Per-call options that override harness-wide spawn defaults.
|
|
1848
2064
|
*
|
|
1849
2065
|
* @remarks
|
|
1850
|
-
*
|
|
1851
|
-
*
|
|
1852
|
-
*
|
|
2066
|
+
* Introduced for ADR-035 §D6 streaming + cleanup semantics. Every field
|
|
2067
|
+
* is optional so callers that just want default behaviour can omit the
|
|
2068
|
+
* second argument entirely.
|
|
2069
|
+
*
|
|
2070
|
+
* @public
|
|
2071
|
+
*/
|
|
2072
|
+
interface SubagentSpawnOptions {
|
|
2073
|
+
/**
|
|
2074
|
+
* Streaming callback invoked once per parsed event from the child.
|
|
2075
|
+
*
|
|
2076
|
+
* @remarks
|
|
2077
|
+
* The harness fires this for every line of stdout (parsed as JSON when
|
|
2078
|
+
* possible), every line of stderr, the final exit, and the
|
|
2079
|
+
* `subagent_link` write. Callbacks are best-effort: throwing from the
|
|
2080
|
+
* callback is caught and recorded as a stderr line so the spawn loop
|
|
2081
|
+
* is never aborted by user code.
|
|
2082
|
+
*
|
|
2083
|
+
* @defaultValue undefined
|
|
2084
|
+
*/
|
|
2085
|
+
onStream?: (event: SubagentStreamEvent) => void;
|
|
2086
|
+
/**
|
|
2087
|
+
* Override the SIGTERM grace window before SIGKILL fires.
|
|
2088
|
+
*
|
|
2089
|
+
* @remarks
|
|
2090
|
+
* When omitted, the harness reads
|
|
2091
|
+
* `settings.json:pi.subagent.terminateGraceMs` (global scope) and
|
|
2092
|
+
* falls back to `5000` ms if absent or invalid. Tests use very small
|
|
2093
|
+
* values to keep cleanup checks fast.
|
|
2094
|
+
*
|
|
2095
|
+
* @defaultValue undefined
|
|
2096
|
+
*/
|
|
2097
|
+
terminateGraceMs?: number;
|
|
2098
|
+
/**
|
|
2099
|
+
* Environment variable overrides layered atop the task-level env.
|
|
2100
|
+
*
|
|
2101
|
+
* @remarks
|
|
2102
|
+
* Convenience hook for per-call secrets that should not live on the
|
|
2103
|
+
* task object itself. Merged after {@link SubagentTask.env} so
|
|
2104
|
+
* call-site keys win.
|
|
2105
|
+
*
|
|
2106
|
+
* @defaultValue undefined
|
|
2107
|
+
*/
|
|
2108
|
+
env?: Record<string, string>;
|
|
2109
|
+
/**
|
|
2110
|
+
* Working directory override that wins over {@link SubagentTask.cwd}.
|
|
2111
|
+
*
|
|
2112
|
+
* @remarks
|
|
2113
|
+
* Useful when the same task description is reused across multiple
|
|
2114
|
+
* working directories.
|
|
2115
|
+
*
|
|
2116
|
+
* @defaultValue undefined
|
|
2117
|
+
*/
|
|
2118
|
+
cwd?: string;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* One streaming event surfaced through {@link SubagentSpawnOptions.onStream}.
|
|
2122
|
+
*
|
|
2123
|
+
* @remarks
|
|
2124
|
+
* Discriminated by {@link kind}:
|
|
2125
|
+
*
|
|
2126
|
+
* - `"message"` — a successfully parsed JSON line from the child's
|
|
2127
|
+
* stdout. {@link payload} is the parsed object and {@link lineNumber}
|
|
2128
|
+
* is the 1-based line index within the child's stdout stream.
|
|
2129
|
+
* - `"stderr"` — a single line from the child's stderr stream. The
|
|
2130
|
+
* {@link payload} is `{ line: string }`. The harness NEVER injects
|
|
2131
|
+
* stderr into the parent LLM context per ADR-035 §D6.
|
|
2132
|
+
* - `"exit"` — the child has exited. {@link payload} is a
|
|
2133
|
+
* {@link SubagentExitResult}.
|
|
2134
|
+
* - `"link"` — the harness wrote a `subagent_link` custom entry to the
|
|
2135
|
+
* parent session. {@link payload} is the {@link SubagentLinkEntry}.
|
|
2136
|
+
*
|
|
2137
|
+
* @public
|
|
2138
|
+
*/
|
|
2139
|
+
interface SubagentStreamEvent {
|
|
2140
|
+
/** Event kind discriminator. */
|
|
2141
|
+
kind: 'message' | 'stderr' | 'exit' | 'link';
|
|
2142
|
+
/** Subagent identifier (matches {@link SubagentHandle.subagentId}). */
|
|
2143
|
+
subagentId: string;
|
|
2144
|
+
/**
|
|
2145
|
+
* 1-based line number within the child's stdout stream. Only set for
|
|
2146
|
+
* `"message"` events that originated from a parsed stdout line.
|
|
2147
|
+
* @defaultValue undefined
|
|
2148
|
+
*/
|
|
2149
|
+
lineNumber?: number;
|
|
2150
|
+
/** Event payload, shaped according to {@link kind}. */
|
|
2151
|
+
payload: unknown;
|
|
2152
|
+
}
|
|
2153
|
+
/**
|
|
2154
|
+
* Resolution value of {@link SubagentHandle.exitPromise}.
|
|
2155
|
+
*
|
|
2156
|
+
* @remarks
|
|
2157
|
+
* Captured exactly once when the child process exits. The promise NEVER
|
|
2158
|
+
* rejects — failure is encoded by a non-zero {@link code}, a non-null
|
|
2159
|
+
* {@link signal}, or partial output preserved in the child session file
|
|
2160
|
+
* at {@link childSessionPath}.
|
|
2161
|
+
*
|
|
2162
|
+
* @public
|
|
2163
|
+
*/
|
|
2164
|
+
interface SubagentExitResult {
|
|
2165
|
+
/**
|
|
2166
|
+
* Process exit code, or `null` when the child was terminated by a
|
|
2167
|
+
* signal before exiting normally.
|
|
2168
|
+
*/
|
|
2169
|
+
code: number | null;
|
|
2170
|
+
/** Terminating signal, or `null` when the child exited normally. */
|
|
2171
|
+
signal: NodeJS.Signals | null;
|
|
2172
|
+
/** Absolute path to the child session JSONL file on disk. */
|
|
2173
|
+
childSessionPath: string;
|
|
2174
|
+
/** Wall-clock duration from spawn to exit, in milliseconds. */
|
|
2175
|
+
durationMs: number;
|
|
2176
|
+
}
|
|
2177
|
+
/**
|
|
2178
|
+
* Final result of a subagent's execution (legacy v1 shape).
|
|
2179
|
+
*
|
|
2180
|
+
* @remarks
|
|
2181
|
+
* Preserved for back-compat with pre-ADR-035 §D6 callers. New code
|
|
2182
|
+
* SHOULD await {@link SubagentHandle.exitPromise} (which resolves with
|
|
2183
|
+
* a richer {@link SubagentExitResult}) instead. The harness still
|
|
2184
|
+
* populates this field on every spawn so existing tests and callers
|
|
2185
|
+
* keep working.
|
|
1853
2186
|
*
|
|
1854
2187
|
* @public
|
|
1855
2188
|
*/
|
|
@@ -1872,18 +2205,87 @@ interface SubagentResult {
|
|
|
1872
2205
|
*
|
|
1873
2206
|
* @remarks
|
|
1874
2207
|
* Returned synchronously from {@link Harness.spawnSubagent}. The caller
|
|
1875
|
-
* may
|
|
1876
|
-
*
|
|
2208
|
+
* may:
|
|
2209
|
+
*
|
|
2210
|
+
* - Await {@link exitPromise} to collect the rich {@link SubagentExitResult}
|
|
2211
|
+
* (preferred path, ADR-035 §D6).
|
|
2212
|
+
* - Await {@link result} to collect the legacy {@link SubagentResult}
|
|
2213
|
+
* (preserved for back-compat).
|
|
2214
|
+
* - Invoke {@link terminate} (preferred) or {@link abort} (legacy) to
|
|
2215
|
+
* stop the child early via the configured SIGTERM-then-SIGKILL
|
|
2216
|
+
* cleanup sequence.
|
|
2217
|
+
* - Inspect {@link recentStderr} for the most recent stderr lines
|
|
2218
|
+
* captured by the harness — useful for post-mortem diagnostics
|
|
2219
|
+
* without injecting stderr into the parent LLM context.
|
|
1877
2220
|
*
|
|
1878
2221
|
* @public
|
|
1879
2222
|
*/
|
|
1880
2223
|
interface SubagentHandle {
|
|
2224
|
+
/**
|
|
2225
|
+
* Stable subagent identifier generated at spawn time.
|
|
2226
|
+
*
|
|
2227
|
+
* @remarks
|
|
2228
|
+
* Format: `sub-{taskId}-{shortRandom}`. Used to correlate
|
|
2229
|
+
* {@link SubagentStreamEvent} entries and `subagent_link` records
|
|
2230
|
+
* with this handle. Always defined (the harness never returns a
|
|
2231
|
+
* handle without one).
|
|
2232
|
+
*/
|
|
2233
|
+
subagentId: string;
|
|
2234
|
+
/** Task identifier from {@link SubagentTask.taskId} (or generated default). */
|
|
2235
|
+
taskId: string;
|
|
2236
|
+
/** Absolute path to the child session JSONL file on disk. */
|
|
2237
|
+
childSessionPath: string;
|
|
1881
2238
|
/** PID of the spawned process, or `null` if spawning did not yield one. */
|
|
1882
2239
|
pid: number | null;
|
|
1883
|
-
/**
|
|
2240
|
+
/** Wall-clock timestamp captured immediately after spawn. */
|
|
2241
|
+
startedAt: Date;
|
|
2242
|
+
/**
|
|
2243
|
+
* Promise resolving to the rich exit result once the child process
|
|
2244
|
+
* has fully terminated. NEVER rejects — failures are encoded in the
|
|
2245
|
+
* resolved value (non-zero code, non-null signal, partial output in
|
|
2246
|
+
* the session file).
|
|
2247
|
+
*/
|
|
2248
|
+
exitPromise: Promise<SubagentExitResult>;
|
|
2249
|
+
/**
|
|
2250
|
+
* Promise resolving to the legacy {@link SubagentResult} shape.
|
|
2251
|
+
*
|
|
2252
|
+
* @remarks
|
|
2253
|
+
* Preserved for back-compat. Resolves to the same exit code as
|
|
2254
|
+
* {@link exitPromise} plus the full captured stdout / stderr buffers
|
|
2255
|
+
* and a best-effort `parsed` field for callers that emit a single
|
|
2256
|
+
* JSON document.
|
|
2257
|
+
*/
|
|
1884
2258
|
result: Promise<SubagentResult>;
|
|
1885
|
-
/**
|
|
2259
|
+
/**
|
|
2260
|
+
* Terminate the subagent gracefully.
|
|
2261
|
+
*
|
|
2262
|
+
* @remarks
|
|
2263
|
+
* Sends SIGTERM, waits for the configured grace window, then sends
|
|
2264
|
+
* SIGKILL if the child is still alive. Idempotent — subsequent calls
|
|
2265
|
+
* after the first are no-ops. Returns once the cleanup sequence has
|
|
2266
|
+
* fully resolved.
|
|
2267
|
+
*/
|
|
2268
|
+
terminate(): Promise<void>;
|
|
2269
|
+
/**
|
|
2270
|
+
* Synchronously trigger the cleanup sequence (legacy v1 alias for
|
|
2271
|
+
* {@link terminate}).
|
|
2272
|
+
*
|
|
2273
|
+
* @remarks
|
|
2274
|
+
* Preserved so existing callers that use `handle.abort()` keep
|
|
2275
|
+
* working. Internally enqueues the same SIGTERM-then-SIGKILL flow as
|
|
2276
|
+
* {@link terminate} but does not return the resulting promise.
|
|
2277
|
+
*/
|
|
1886
2278
|
abort: () => void;
|
|
2279
|
+
/**
|
|
2280
|
+
* Snapshot of the most recent stderr lines captured for this child.
|
|
2281
|
+
*
|
|
2282
|
+
* @remarks
|
|
2283
|
+
* Bounded ring buffer (last 100 lines) so memory cannot grow without
|
|
2284
|
+
* bound under chatty stderr. Stderr is NEVER injected into the
|
|
2285
|
+
* parent LLM context — this accessor is intended for diagnostics and
|
|
2286
|
+
* post-mortem inspection only.
|
|
2287
|
+
*/
|
|
2288
|
+
recentStderr(): string[];
|
|
1887
2289
|
}
|
|
1888
2290
|
/**
|
|
1889
2291
|
* Contract every first-class harness must implement.
|
|
@@ -1895,9 +2297,9 @@ interface SubagentHandle {
|
|
|
1895
2297
|
* harness; the interface is shaped so future harnesses (Goose, OpenCode, ...)
|
|
1896
2298
|
* can be added without changing any caller code.
|
|
1897
2299
|
*
|
|
1898
|
-
* Optional methods ({@link
|
|
1899
|
-
*
|
|
1900
|
-
*
|
|
2300
|
+
* Optional methods ({@link spawnSubagent}, {@link configureModels}) may be
|
|
2301
|
+
* omitted by harnesses that cannot support them. Callers MUST feature-check
|
|
2302
|
+
* before invoking.
|
|
1901
2303
|
*
|
|
1902
2304
|
* @public
|
|
1903
2305
|
*/
|
|
@@ -1965,38 +2367,31 @@ interface Harness {
|
|
|
1965
2367
|
* @param scope - Instruction file scope.
|
|
1966
2368
|
*/
|
|
1967
2369
|
removeInstructions(scope: HarnessScope): Promise<void>;
|
|
1968
|
-
/**
|
|
1969
|
-
* Install an MCP server as a harness extension.
|
|
1970
|
-
*
|
|
1971
|
-
* @remarks
|
|
1972
|
-
* For legacy providers with a native MCP config file, this is a
|
|
1973
|
-
* passthrough. For Pi it generates a TypeScript extension file under
|
|
1974
|
-
* `extensions/` that wraps the MCP server as a Pi tool via
|
|
1975
|
-
* `pi.registerTool()`.
|
|
1976
|
-
*
|
|
1977
|
-
* Optional — harnesses that cannot host MCP bridges should omit this
|
|
1978
|
-
* method. Callers MUST feature-check before invoking.
|
|
1979
|
-
*
|
|
1980
|
-
* @param server - Server spec to bridge.
|
|
1981
|
-
* @param scope - Install scope.
|
|
1982
|
-
*/
|
|
1983
|
-
installMcpAsExtension?(server: McpServerSpec, scope: HarnessScope): Promise<void>;
|
|
1984
2370
|
/**
|
|
1985
2371
|
* Spawn a subagent under this harness's control.
|
|
1986
2372
|
*
|
|
1987
2373
|
* @remarks
|
|
1988
2374
|
* For Pi: invokes `child_process.spawn` with the provider's configured
|
|
1989
2375
|
* `capabilities.spawn.spawnCommand`, appending the task prompt as a
|
|
1990
|
-
* trailing positional argument. The returned handle lets the caller
|
|
1991
|
-
* completion
|
|
2376
|
+
* trailing positional argument. The returned handle lets the caller
|
|
2377
|
+
* await completion ({@link SubagentHandle.exitPromise}), terminate the
|
|
2378
|
+
* child via the SIGTERM-then-SIGKILL cleanup sequence
|
|
2379
|
+
* ({@link SubagentHandle.terminate}), and inspect recent stderr for
|
|
2380
|
+
* post-mortem diagnostics ({@link SubagentHandle.recentStderr}).
|
|
2381
|
+
*
|
|
2382
|
+
* Per ADR-035 §D6, this is the **only** canonical subagent spawn path
|
|
2383
|
+
* in CLEO. New callers MUST go through the harness instead of calling
|
|
2384
|
+
* `child_process.spawn` directly so session attribution, streaming,
|
|
2385
|
+
* and cleanup remain uniform.
|
|
1992
2386
|
*
|
|
1993
2387
|
* Optional — harnesses that cannot spawn other agents should omit this
|
|
1994
2388
|
* method. Callers MUST feature-check before invoking.
|
|
1995
2389
|
*
|
|
1996
2390
|
* @param task - Subagent task specification.
|
|
2391
|
+
* @param opts - Per-call streaming and cleanup overrides.
|
|
1997
2392
|
* @returns A live subagent handle.
|
|
1998
2393
|
*/
|
|
1999
|
-
spawnSubagent?(task: SubagentTask): Promise<SubagentHandle>;
|
|
2394
|
+
spawnSubagent?(task: SubagentTask, opts?: SubagentSpawnOptions): Promise<SubagentHandle>;
|
|
2000
2395
|
/**
|
|
2001
2396
|
* Configure which models are available in the harness's model picker.
|
|
2002
2397
|
*
|
|
@@ -2031,7 +2426,636 @@ interface Harness {
|
|
|
2031
2426
|
* @param scope - Settings scope.
|
|
2032
2427
|
*/
|
|
2033
2428
|
writeSettings(patch: Record<string, unknown>, scope: HarnessScope): Promise<void>;
|
|
2429
|
+
/**
|
|
2430
|
+
* Install a Pi extension TypeScript file from a local source path into
|
|
2431
|
+
* the given tier.
|
|
2432
|
+
*
|
|
2433
|
+
* @remarks
|
|
2434
|
+
* Per ADR-035 §D1 and the spec hook for T263, install verbs:
|
|
2435
|
+
* - Validate that the source is a `.ts` file with an `export default`.
|
|
2436
|
+
* - Copy (not symlink) the file into the target tier's extensions dir.
|
|
2437
|
+
* - Error by default when the target already exists; the caller may
|
|
2438
|
+
* pass `opts.force = true` to enable overwrite.
|
|
2439
|
+
*
|
|
2440
|
+
* Optional on the interface because only first-class harnesses with a
|
|
2441
|
+
* native extension mechanism support this verb.
|
|
2442
|
+
*
|
|
2443
|
+
* @param sourcePath - Absolute path to the source `.ts` file on disk.
|
|
2444
|
+
* @param name - Extension name (used as the target file basename).
|
|
2445
|
+
* @param tier - Target tier (`project`/`user`/`global`).
|
|
2446
|
+
* @param projectDir - Project directory (required when `tier='project'`).
|
|
2447
|
+
* @param opts - Install options (see {@link HarnessInstallOptions}).
|
|
2448
|
+
*/
|
|
2449
|
+
installExtension?(sourcePath: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
2450
|
+
targetPath: string;
|
|
2451
|
+
tier: HarnessTier;
|
|
2452
|
+
}>;
|
|
2453
|
+
/**
|
|
2454
|
+
* Remove a Pi extension by name from the given tier.
|
|
2455
|
+
*
|
|
2456
|
+
* @remarks
|
|
2457
|
+
* Missing files are tolerated silently so the verb is usable as an
|
|
2458
|
+
* idempotent "ensure absent" operation.
|
|
2459
|
+
*
|
|
2460
|
+
* @param name - Extension name (basename without `.ts`).
|
|
2461
|
+
* @param tier - Target tier to remove from.
|
|
2462
|
+
* @param projectDir - Project directory (required when `tier='project'`).
|
|
2463
|
+
* @returns `true` when a file was removed, `false` when none existed.
|
|
2464
|
+
*/
|
|
2465
|
+
removeExtension?(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
2466
|
+
/**
|
|
2467
|
+
* List Pi extensions across all tiers, precedence-ordered.
|
|
2468
|
+
*
|
|
2469
|
+
* @remarks
|
|
2470
|
+
* Entries are returned in precedence order (project → user → global).
|
|
2471
|
+
* Higher-precedence tiers shadow lower-precedence entries with the
|
|
2472
|
+
* same name; the returned {@link ExtensionEntry.shadowed} flag
|
|
2473
|
+
* indicates shadowed copies so the caller can surface cross-tier name
|
|
2474
|
+
* collisions per ADR-035 §D1.
|
|
2475
|
+
*
|
|
2476
|
+
* @param projectDir - Project directory for the `project` tier. When
|
|
2477
|
+
* omitted the `project` tier is skipped rather than failing.
|
|
2478
|
+
*/
|
|
2479
|
+
listExtensions?(projectDir?: string): Promise<ExtensionEntry[]>;
|
|
2480
|
+
/**
|
|
2481
|
+
* List Pi sessions from the user-tier sessions directory.
|
|
2482
|
+
*
|
|
2483
|
+
* @remarks
|
|
2484
|
+
* Per ADR-035 §D2, MUST read only line 1 of each `*.jsonl` file. The
|
|
2485
|
+
* result is sorted by `mtimeMs` descending so the most recent
|
|
2486
|
+
* sessions appear first.
|
|
2487
|
+
*
|
|
2488
|
+
* @param opts - Options controlling which directories to scan.
|
|
2489
|
+
*/
|
|
2490
|
+
listSessions?(opts?: {
|
|
2491
|
+
includeSubagents?: boolean;
|
|
2492
|
+
}): Promise<SessionSummary[]>;
|
|
2493
|
+
/**
|
|
2494
|
+
* Load a Pi session's full body by id.
|
|
2495
|
+
*
|
|
2496
|
+
* @remarks
|
|
2497
|
+
* Reads the entire file as-is. The caller is responsible for
|
|
2498
|
+
* formatting / filtering; the harness only guarantees that the
|
|
2499
|
+
* returned `entries` are the raw JSONL lines in file order.
|
|
2500
|
+
*
|
|
2501
|
+
* @param id - Session id as recorded in the line-1 header.
|
|
2502
|
+
*/
|
|
2503
|
+
showSession?(id: string): Promise<SessionDocument>;
|
|
2504
|
+
/**
|
|
2505
|
+
* List every model known to Pi — both custom (`models.json`) and
|
|
2506
|
+
* enabled selections (`settings.json:enabledModels`).
|
|
2507
|
+
*
|
|
2508
|
+
* @remarks
|
|
2509
|
+
* Per ADR-035 §D3, this is a read-only union with per-entry flags.
|
|
2510
|
+
* Mutation verbs (`add`, `remove`, `enable`, `disable`, `default`)
|
|
2511
|
+
* are separate methods to preserve the dual-file authority model.
|
|
2512
|
+
*
|
|
2513
|
+
* @param scope - Legacy two-tier scope (global/project) that
|
|
2514
|
+
* determines which `models.json` and `settings.json` files to read.
|
|
2515
|
+
*/
|
|
2516
|
+
listModels?(scope: HarnessScope): Promise<ModelListEntry[]>;
|
|
2517
|
+
/**
|
|
2518
|
+
* Read `models.json` for the given scope.
|
|
2519
|
+
*
|
|
2520
|
+
* @remarks
|
|
2521
|
+
* Missing files resolve to `{ providers: {} }`. Malformed JSON also
|
|
2522
|
+
* resolves to the empty config rather than throwing, matching
|
|
2523
|
+
* {@link Harness.readSettings}'s tolerant contract.
|
|
2524
|
+
*/
|
|
2525
|
+
readModelsConfig?(scope: HarnessScope): Promise<PiModelsConfig>;
|
|
2526
|
+
/**
|
|
2527
|
+
* Write `models.json` for the given scope atomically.
|
|
2528
|
+
*
|
|
2529
|
+
* @remarks
|
|
2530
|
+
* The full config is written, not merged. Callers should read, patch,
|
|
2531
|
+
* then write. Uses an atomic tmp-then-rename sequence so a crash
|
|
2532
|
+
* mid-write cannot corrupt the file.
|
|
2533
|
+
*/
|
|
2534
|
+
writeModelsConfig?(config: PiModelsConfig, scope: HarnessScope): Promise<void>;
|
|
2535
|
+
/**
|
|
2536
|
+
* Install a Pi prompt from a source directory into the given tier.
|
|
2537
|
+
*
|
|
2538
|
+
* @remarks
|
|
2539
|
+
* Per ADR-035 §D1 and the spec hook for T266, the source is a
|
|
2540
|
+
* directory containing `prompt.md` plus optional metadata. The
|
|
2541
|
+
* directory is copied recursively into the target tier. Conflict
|
|
2542
|
+
* handling mirrors {@link installExtension}.
|
|
2543
|
+
*/
|
|
2544
|
+
installPrompt?(sourceDir: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
2545
|
+
targetPath: string;
|
|
2546
|
+
tier: HarnessTier;
|
|
2547
|
+
}>;
|
|
2548
|
+
/** List Pi prompts across all tiers. */
|
|
2549
|
+
listPrompts?(projectDir?: string): Promise<PromptEntry[]>;
|
|
2550
|
+
/** Remove a Pi prompt by name from the given tier. */
|
|
2551
|
+
removePrompt?(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
2552
|
+
/**
|
|
2553
|
+
* Install a Pi theme from a source file into the given tier.
|
|
2554
|
+
*
|
|
2555
|
+
* @remarks
|
|
2556
|
+
* Per ADR-035 §D1 and the spec hook for T267. The source may be a
|
|
2557
|
+
* `.ts` TypeScript theme module or a `.json` theme file; the file
|
|
2558
|
+
* extension is preserved so Pi picks the right loader.
|
|
2559
|
+
*/
|
|
2560
|
+
installTheme?(sourceFile: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
2561
|
+
targetPath: string;
|
|
2562
|
+
tier: HarnessTier;
|
|
2563
|
+
}>;
|
|
2564
|
+
/** List Pi themes across all tiers. */
|
|
2565
|
+
listThemes?(projectDir?: string): Promise<ThemeEntry[]>;
|
|
2566
|
+
/** Remove a Pi theme by name from the given tier. */
|
|
2567
|
+
removeTheme?(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
2568
|
+
/**
|
|
2569
|
+
* Install a CANT profile (`.cant` file) into the given tier.
|
|
2570
|
+
*
|
|
2571
|
+
* @remarks
|
|
2572
|
+
* Per ADR-035 §D5 (CANT single engine), CANT profiles are first-class
|
|
2573
|
+
* Pi assets consumed by the canonical `cant-bridge.ts` extension via
|
|
2574
|
+
* `/cant:load <file>` at runtime. This verb copies a source `.cant`
|
|
2575
|
+
* file into the requested tier so the bridge can discover it.
|
|
2576
|
+
*
|
|
2577
|
+
* Implementations MUST validate the source via cant-core's 42-rule
|
|
2578
|
+
* engine before copying — invalid `.cant` files are rejected. The
|
|
2579
|
+
* conflict-on-write rule from §D1 cross-cutting concerns applies:
|
|
2580
|
+
* existing targets cause an error unless `opts.force` is set.
|
|
2581
|
+
*
|
|
2582
|
+
* Optional on the interface because only first-class harnesses with a
|
|
2583
|
+
* native CANT bridge support this verb.
|
|
2584
|
+
*
|
|
2585
|
+
* @param sourcePath - Absolute path to the source `.cant` file on disk.
|
|
2586
|
+
* @param name - Profile name (used as the target file basename).
|
|
2587
|
+
* @param tier - Target tier (`project`/`user`/`global`).
|
|
2588
|
+
* @param projectDir - Project directory (required when `tier='project'`).
|
|
2589
|
+
* @param opts - Install options (see {@link HarnessInstallOptions}).
|
|
2590
|
+
*/
|
|
2591
|
+
installCantProfile?(sourcePath: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
2592
|
+
targetPath: string;
|
|
2593
|
+
tier: HarnessTier;
|
|
2594
|
+
counts: CantProfileCounts;
|
|
2595
|
+
}>;
|
|
2596
|
+
/**
|
|
2597
|
+
* Remove a CANT profile by name from the given tier.
|
|
2598
|
+
*
|
|
2599
|
+
* @remarks
|
|
2600
|
+
* Missing files are tolerated silently so the verb is usable as an
|
|
2601
|
+
* idempotent "ensure absent" operation.
|
|
2602
|
+
*
|
|
2603
|
+
* @param name - Profile name (basename without `.cant`).
|
|
2604
|
+
* @param tier - Target tier to remove from.
|
|
2605
|
+
* @param projectDir - Project directory (required when `tier='project'`).
|
|
2606
|
+
* @returns `true` when a file was removed, `false` when none existed.
|
|
2607
|
+
*/
|
|
2608
|
+
removeCantProfile?(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
2609
|
+
/**
|
|
2610
|
+
* List CANT profiles across all tiers, precedence-ordered.
|
|
2611
|
+
*
|
|
2612
|
+
* @remarks
|
|
2613
|
+
* Walks every tier in {@link HarnessTier} precedence order
|
|
2614
|
+
* (project → user → global) and parses each `.cant` file to extract
|
|
2615
|
+
* its section counts. Higher-precedence tiers shadow lower-precedence
|
|
2616
|
+
* entries with the same name; the {@link CantProfileEntry.shadowedByHigherTier}
|
|
2617
|
+
* flag indicates shadowed copies so callers can warn about
|
|
2618
|
+
* cross-tier name collisions per ADR-035 §D1.
|
|
2619
|
+
*
|
|
2620
|
+
* @param projectDir - Project directory for the `project` tier. When
|
|
2621
|
+
* omitted the `project` tier is skipped rather than failing.
|
|
2622
|
+
*/
|
|
2623
|
+
listCantProfiles?(projectDir?: string): Promise<CantProfileEntry[]>;
|
|
2624
|
+
/**
|
|
2625
|
+
* Validate a `.cant` file via cant-core's 42-rule engine without
|
|
2626
|
+
* installing anything.
|
|
2627
|
+
*
|
|
2628
|
+
* @remarks
|
|
2629
|
+
* Pure helper used by `caamp pi cant validate <path>`. Reads the file,
|
|
2630
|
+
* parses it, runs the validator, and returns a structured
|
|
2631
|
+
* {@link ValidateCantProfileResult}. Never mutates state on disk.
|
|
2632
|
+
*
|
|
2633
|
+
* @param sourcePath - Absolute path to the `.cant` file on disk.
|
|
2634
|
+
*/
|
|
2635
|
+
validateCantProfile?(sourcePath: string): Promise<ValidateCantProfileResult>;
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
/**
|
|
2639
|
+
* CAAMP-wide configuration accessors.
|
|
2640
|
+
*
|
|
2641
|
+
* @remarks
|
|
2642
|
+
* This module is the single source of truth for CAAMP configuration values
|
|
2643
|
+
* that affect runtime behaviour across the package. Today it carries one
|
|
2644
|
+
* setting — {@link ExclusivityMode} — introduced by ADR-035 §D7 to control
|
|
2645
|
+
* how `resolveDefaultTargetProviders()` selects target providers at runtime
|
|
2646
|
+
* invocation time.
|
|
2647
|
+
*
|
|
2648
|
+
* The accessor pattern intentionally uses a layered resolution order so the
|
|
2649
|
+
* setting can be overridden by tests, by environment variables in CI, and by
|
|
2650
|
+
* future programmatic callers (e.g. a `caamp config set` subcommand) without
|
|
2651
|
+
* any of those layers needing to know about the others:
|
|
2652
|
+
*
|
|
2653
|
+
* 1. Programmatic override via {@link setExclusivityMode} (highest priority).
|
|
2654
|
+
* 2. Environment variable `CAAMP_EXCLUSIVITY_MODE`.
|
|
2655
|
+
* 3. Default value `'auto'`.
|
|
2656
|
+
*
|
|
2657
|
+
* The programmatic override exists primarily for tests and for future
|
|
2658
|
+
* `caamp config set` integration; production code should prefer the
|
|
2659
|
+
* environment variable when wiring CI or shell sessions.
|
|
2660
|
+
*
|
|
2661
|
+
* @packageDocumentation
|
|
2662
|
+
*/
|
|
2663
|
+
|
|
2664
|
+
/**
|
|
2665
|
+
* Default exclusivity mode used when no override is configured.
|
|
2666
|
+
*
|
|
2667
|
+
* @remarks
|
|
2668
|
+
* `auto` mirrors the v2026.4.5+ behaviour: Pi is preferred when installed,
|
|
2669
|
+
* but explicit non-Pi targets remain functional. This is the value the
|
|
2670
|
+
* accessor returns when neither {@link setExclusivityMode} nor the
|
|
2671
|
+
* `CAAMP_EXCLUSIVITY_MODE` environment variable is set.
|
|
2672
|
+
*
|
|
2673
|
+
* @public
|
|
2674
|
+
*/
|
|
2675
|
+
declare const DEFAULT_EXCLUSIVITY_MODE: ExclusivityMode;
|
|
2676
|
+
/**
|
|
2677
|
+
* Environment variable name read by {@link getExclusivityMode} when no
|
|
2678
|
+
* programmatic override is active.
|
|
2679
|
+
*
|
|
2680
|
+
* @remarks
|
|
2681
|
+
* Exported as a constant so tests and downstream tooling can refer to the
|
|
2682
|
+
* canonical name without typo risk. The variable accepts the same three
|
|
2683
|
+
* literal values as the {@link ExclusivityMode} type.
|
|
2684
|
+
*
|
|
2685
|
+
* @public
|
|
2686
|
+
*/
|
|
2687
|
+
declare const EXCLUSIVITY_MODE_ENV_VAR = "CAAMP_EXCLUSIVITY_MODE";
|
|
2688
|
+
/**
|
|
2689
|
+
* Error raised when {@link getExclusivityMode} resolves to `'force-pi'` but
|
|
2690
|
+
* Pi is not installed at the moment a runtime dispatch is requested.
|
|
2691
|
+
*
|
|
2692
|
+
* @remarks
|
|
2693
|
+
* Carries an `E_NOT_FOUND_RESOURCE`-shaped `code` so command-layer error
|
|
2694
|
+
* envelopes (LAFS) can map it to a stable category. Callers decide whether
|
|
2695
|
+
* to surface this as a process exit (typically code 4) or as a structured
|
|
2696
|
+
* envelope; the harness layer never calls `process.exit` itself.
|
|
2697
|
+
*
|
|
2698
|
+
* Lives next to the configuration accessor rather than in the harness
|
|
2699
|
+
* dispatcher so consumers that import the mode also pick up the matching
|
|
2700
|
+
* error type without a second module hop.
|
|
2701
|
+
*
|
|
2702
|
+
* @example
|
|
2703
|
+
* ```typescript
|
|
2704
|
+
* try {
|
|
2705
|
+
* const targets = resolveDefaultTargetProviders();
|
|
2706
|
+
* } catch (err) {
|
|
2707
|
+
* if (err instanceof PiRequiredError) {
|
|
2708
|
+
* process.exit(4);
|
|
2709
|
+
* }
|
|
2710
|
+
* throw err;
|
|
2711
|
+
* }
|
|
2712
|
+
* ```
|
|
2713
|
+
*
|
|
2714
|
+
* @public
|
|
2715
|
+
*/
|
|
2716
|
+
declare class PiRequiredError extends Error {
|
|
2717
|
+
/** LAFS-stable error code identifying this failure mode. */
|
|
2718
|
+
readonly code: "E_NOT_FOUND_RESOURCE";
|
|
2719
|
+
/**
|
|
2720
|
+
* Construct a new {@link PiRequiredError}.
|
|
2721
|
+
*
|
|
2722
|
+
* @param message - Human-readable failure description; defaults to a
|
|
2723
|
+
* stable string suitable for direct CLI display.
|
|
2724
|
+
*/
|
|
2725
|
+
constructor(message?: string);
|
|
2034
2726
|
}
|
|
2727
|
+
/**
|
|
2728
|
+
* Type guard that narrows an arbitrary string to {@link ExclusivityMode}.
|
|
2729
|
+
*
|
|
2730
|
+
* @remarks
|
|
2731
|
+
* Used both internally and by callers that need to validate untrusted input
|
|
2732
|
+
* (e.g. CLI flag parsers, env var readers) before passing it through to
|
|
2733
|
+
* {@link setExclusivityMode}.
|
|
2734
|
+
*
|
|
2735
|
+
* @param value - Candidate value to validate.
|
|
2736
|
+
* @returns `true` when `value` is one of `'auto'`, `'force-pi'`, `'legacy'`.
|
|
2737
|
+
*
|
|
2738
|
+
* @example
|
|
2739
|
+
* ```typescript
|
|
2740
|
+
* if (isExclusivityMode(userInput)) {
|
|
2741
|
+
* setExclusivityMode(userInput);
|
|
2742
|
+
* }
|
|
2743
|
+
* ```
|
|
2744
|
+
*
|
|
2745
|
+
* @public
|
|
2746
|
+
*/
|
|
2747
|
+
declare function isExclusivityMode(value: string): value is ExclusivityMode;
|
|
2748
|
+
/**
|
|
2749
|
+
* Resolve the active CAAMP exclusivity mode using the layered precedence
|
|
2750
|
+
* documented in {@link DEFAULT_EXCLUSIVITY_MODE}.
|
|
2751
|
+
*
|
|
2752
|
+
* @remarks
|
|
2753
|
+
* Resolution order:
|
|
2754
|
+
*
|
|
2755
|
+
* 1. Programmatic override (set via {@link setExclusivityMode}).
|
|
2756
|
+
* 2. Environment variable `CAAMP_EXCLUSIVITY_MODE`.
|
|
2757
|
+
* 3. {@link DEFAULT_EXCLUSIVITY_MODE} (`'auto'`).
|
|
2758
|
+
*
|
|
2759
|
+
* Invalid environment variable values are silently ignored (resolution
|
|
2760
|
+
* falls through to the default) so a typo in CI does not crash the CLI.
|
|
2761
|
+
* The value is never cached — every call re-reads the environment so tests
|
|
2762
|
+
* that mutate `process.env` see consistent results without needing to
|
|
2763
|
+
* reset module state.
|
|
2764
|
+
*
|
|
2765
|
+
* @returns The currently effective exclusivity mode.
|
|
2766
|
+
*
|
|
2767
|
+
* @example
|
|
2768
|
+
* ```typescript
|
|
2769
|
+
* const mode = getExclusivityMode();
|
|
2770
|
+
* if (mode === 'force-pi') {
|
|
2771
|
+
* // ...
|
|
2772
|
+
* }
|
|
2773
|
+
* ```
|
|
2774
|
+
*
|
|
2775
|
+
* @public
|
|
2776
|
+
*/
|
|
2777
|
+
declare function getExclusivityMode(): ExclusivityMode;
|
|
2778
|
+
/**
|
|
2779
|
+
* Install a programmatic override for the exclusivity mode.
|
|
2780
|
+
*
|
|
2781
|
+
* @remarks
|
|
2782
|
+
* The override takes precedence over the environment variable for the
|
|
2783
|
+
* remainder of the process or until {@link resetExclusivityModeOverride}
|
|
2784
|
+
* is called. Intended for tests, for future `caamp config set` wiring, and
|
|
2785
|
+
* for short-lived runtime adjustments (e.g. a one-shot CLI flag).
|
|
2786
|
+
*
|
|
2787
|
+
* @param mode - Mode to install.
|
|
2788
|
+
*
|
|
2789
|
+
* @example
|
|
2790
|
+
* ```typescript
|
|
2791
|
+
* setExclusivityMode('force-pi');
|
|
2792
|
+
* try {
|
|
2793
|
+
* await runCommand();
|
|
2794
|
+
* } finally {
|
|
2795
|
+
* resetExclusivityModeOverride();
|
|
2796
|
+
* }
|
|
2797
|
+
* ```
|
|
2798
|
+
*
|
|
2799
|
+
* @public
|
|
2800
|
+
*/
|
|
2801
|
+
declare function setExclusivityMode(mode: ExclusivityMode): void;
|
|
2802
|
+
/**
|
|
2803
|
+
* Clear any programmatic override installed by {@link setExclusivityMode}.
|
|
2804
|
+
*
|
|
2805
|
+
* @remarks
|
|
2806
|
+
* After calling this, {@link getExclusivityMode} resumes reading from the
|
|
2807
|
+
* environment variable (and falls back to the default when the env var is
|
|
2808
|
+
* unset or invalid). Idempotent — safe to call when no override is active.
|
|
2809
|
+
*
|
|
2810
|
+
* @public
|
|
2811
|
+
*/
|
|
2812
|
+
declare function resetExclusivityModeOverride(): void;
|
|
2813
|
+
|
|
2814
|
+
/**
|
|
2815
|
+
* Format utility functions
|
|
2816
|
+
*/
|
|
2817
|
+
/**
|
|
2818
|
+
* Deep merge two objects, with `source` values winning on conflict.
|
|
2819
|
+
*
|
|
2820
|
+
* Recursively merges nested plain objects. Arrays and non-object values from
|
|
2821
|
+
* `source` overwrite `target` values.
|
|
2822
|
+
*
|
|
2823
|
+
* @param target - Base object to merge into
|
|
2824
|
+
* @param source - Object with values that take precedence
|
|
2825
|
+
* @returns A new merged object (does not mutate inputs)
|
|
2826
|
+
*
|
|
2827
|
+
* @remarks
|
|
2828
|
+
* Only plain objects are recursively merged. Arrays and primitive values from
|
|
2829
|
+
* `source` replace `target` values outright. Neither input is mutated.
|
|
2830
|
+
*
|
|
2831
|
+
* @example
|
|
2832
|
+
* ```typescript
|
|
2833
|
+
* const merged = deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
|
|
2834
|
+
* // { a: 1, b: { c: 2, d: 3 } }
|
|
2835
|
+
* ```
|
|
2836
|
+
*
|
|
2837
|
+
* @public
|
|
2838
|
+
*/
|
|
2839
|
+
declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
|
|
2840
|
+
/**
|
|
2841
|
+
* Get a nested value from an object using a dot-notation key path.
|
|
2842
|
+
*
|
|
2843
|
+
* @param obj - Object to traverse
|
|
2844
|
+
* @param keyPath - Dot-separated key path (e.g. `"mcpServers"` or `"a.b.c"`)
|
|
2845
|
+
* @returns The value at the key path, or `undefined` if not found
|
|
2846
|
+
*
|
|
2847
|
+
* @remarks
|
|
2848
|
+
* Splits the key path on `.` and walks the object tree. Returns `undefined`
|
|
2849
|
+
* at the first missing or non-object segment.
|
|
2850
|
+
*
|
|
2851
|
+
* @example
|
|
2852
|
+
* ```typescript
|
|
2853
|
+
* getNestedValue({ a: { b: { c: 42 } } }, "a.b.c"); // 42
|
|
2854
|
+
* getNestedValue({ a: 1 }, "a.b"); // undefined
|
|
2855
|
+
* ```
|
|
2856
|
+
*
|
|
2857
|
+
* @public
|
|
2858
|
+
*/
|
|
2859
|
+
declare function getNestedValue(obj: Record<string, unknown>, keyPath: string): unknown;
|
|
2860
|
+
/**
|
|
2861
|
+
* Ensure that the parent directories of a file path exist.
|
|
2862
|
+
*
|
|
2863
|
+
* Creates directories recursively if they do not exist.
|
|
2864
|
+
*
|
|
2865
|
+
* @param filePath - Absolute path to a file (parent directories will be created)
|
|
2866
|
+
*
|
|
2867
|
+
* @remarks
|
|
2868
|
+
* Uses `mkdir` with `recursive: true` so existing directories are not an error.
|
|
2869
|
+
*
|
|
2870
|
+
* @example
|
|
2871
|
+
* ```typescript
|
|
2872
|
+
* await ensureDir("/path/to/new/dir/file.json");
|
|
2873
|
+
* // /path/to/new/dir/ now exists
|
|
2874
|
+
* ```
|
|
2875
|
+
*
|
|
2876
|
+
* @public
|
|
2877
|
+
*/
|
|
2878
|
+
declare function ensureDir(filePath: string): Promise<void>;
|
|
2879
|
+
|
|
2880
|
+
/**
|
|
2881
|
+
* Provides format-agnostic config read, write, and remove operations that
|
|
2882
|
+
* dispatch to JSON/JSONC, YAML, or TOML handlers based on the specified
|
|
2883
|
+
* format.
|
|
2884
|
+
*
|
|
2885
|
+
* @packageDocumentation
|
|
2886
|
+
*/
|
|
2887
|
+
|
|
2888
|
+
/**
|
|
2889
|
+
* Read and parse a config file in the specified format.
|
|
2890
|
+
*
|
|
2891
|
+
* Dispatches to the appropriate format handler (JSON/JSONC, YAML, or TOML).
|
|
2892
|
+
*
|
|
2893
|
+
* @param filePath - Absolute path to the config file
|
|
2894
|
+
* @param format - Config file format
|
|
2895
|
+
* @returns Parsed config object
|
|
2896
|
+
* @throws If the file cannot be read or the format is unsupported
|
|
2897
|
+
*
|
|
2898
|
+
* @remarks
|
|
2899
|
+
* Supported formats: `"json"`, `"jsonc"`, `"yaml"`, `"toml"`. Throws for
|
|
2900
|
+
* any unrecognized format string.
|
|
2901
|
+
*
|
|
2902
|
+
* @example
|
|
2903
|
+
* ```typescript
|
|
2904
|
+
* const config = await readConfig("/path/to/config.json", "jsonc");
|
|
2905
|
+
* ```
|
|
2906
|
+
*
|
|
2907
|
+
* @public
|
|
2908
|
+
*/
|
|
2909
|
+
declare function readConfig(filePath: string, format: ConfigFormat): Promise<Record<string, unknown>>;
|
|
2910
|
+
/**
|
|
2911
|
+
* Write a server entry to a config file, preserving existing content.
|
|
2912
|
+
*
|
|
2913
|
+
* Dispatches to the appropriate format handler. For JSONC files, comments are
|
|
2914
|
+
* preserved using `jsonc-parser`.
|
|
2915
|
+
*
|
|
2916
|
+
* @param filePath - Absolute path to the config file
|
|
2917
|
+
* @param format - Config file format
|
|
2918
|
+
* @param key - Dot-notation key path to the servers section (e.g. `"mcpServers"`)
|
|
2919
|
+
* @param serverName - Name/key for the server entry
|
|
2920
|
+
* @param serverConfig - Server configuration object to write
|
|
2921
|
+
* @throws If the format is unsupported
|
|
2922
|
+
*
|
|
2923
|
+
* @remarks
|
|
2924
|
+
* For JSONC files, comments and formatting are preserved using `jsonc-parser`.
|
|
2925
|
+
* For YAML and TOML, the file is fully re-serialized after deep-merging.
|
|
2926
|
+
*
|
|
2927
|
+
* @example
|
|
2928
|
+
* ```typescript
|
|
2929
|
+
* await writeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server", config);
|
|
2930
|
+
* ```
|
|
2931
|
+
*
|
|
2932
|
+
* @public
|
|
2933
|
+
*/
|
|
2934
|
+
declare function writeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string, serverConfig: unknown): Promise<void>;
|
|
2935
|
+
/**
|
|
2936
|
+
* Remove a server entry from a config file in the specified format.
|
|
2937
|
+
*
|
|
2938
|
+
* @param filePath - Absolute path to the config file
|
|
2939
|
+
* @param format - Config file format
|
|
2940
|
+
* @param key - Dot-notation key path to the servers section
|
|
2941
|
+
* @param serverName - Name/key of the server entry to remove
|
|
2942
|
+
* @returns `true` if the entry was removed, `false` otherwise
|
|
2943
|
+
* @throws If the format is unsupported
|
|
2944
|
+
*
|
|
2945
|
+
* @remarks
|
|
2946
|
+
* Delegates to the format-specific removal function. Returns `false` when the
|
|
2947
|
+
* file does not exist or the entry is not found.
|
|
2948
|
+
*
|
|
2949
|
+
* @example
|
|
2950
|
+
* ```typescript
|
|
2951
|
+
* const removed = await removeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server");
|
|
2952
|
+
* ```
|
|
2953
|
+
*
|
|
2954
|
+
* @public
|
|
2955
|
+
*/
|
|
2956
|
+
declare function removeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string): Promise<boolean>;
|
|
2957
|
+
|
|
2958
|
+
/**
|
|
2959
|
+
* Skill installer - canonical + symlink model
|
|
2960
|
+
*
|
|
2961
|
+
* Skills are stored once in a canonical location (.agents/skills/<name>/)
|
|
2962
|
+
* and symlinked to each target agent's skills directory.
|
|
2963
|
+
*/
|
|
2964
|
+
|
|
2965
|
+
/**
|
|
2966
|
+
* Result of installing a skill to the canonical location and linking to agents.
|
|
2967
|
+
*
|
|
2968
|
+
* @example
|
|
2969
|
+
* ```typescript
|
|
2970
|
+
* const result = await installSkill(sourcePath, "my-skill", providers, true);
|
|
2971
|
+
* if (result.success) {
|
|
2972
|
+
* console.log(`Installed to ${result.canonicalPath}`);
|
|
2973
|
+
* console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
|
|
2974
|
+
* }
|
|
2975
|
+
* ```
|
|
2976
|
+
*
|
|
2977
|
+
* @public
|
|
2978
|
+
*/
|
|
2979
|
+
interface SkillInstallResult {
|
|
2980
|
+
/** Skill name. */
|
|
2981
|
+
name: string;
|
|
2982
|
+
/** Absolute path to the canonical installation directory. */
|
|
2983
|
+
canonicalPath: string;
|
|
2984
|
+
/** Provider IDs that were successfully linked. */
|
|
2985
|
+
linkedAgents: string[];
|
|
2986
|
+
/** Error messages from failed link operations. */
|
|
2987
|
+
errors: string[];
|
|
2988
|
+
/** Whether at least one agent was successfully linked. */
|
|
2989
|
+
success: boolean;
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* Install a skill from a local path to the canonical location and link to agents.
|
|
2993
|
+
*
|
|
2994
|
+
* @remarks
|
|
2995
|
+
* Copies the skill directory to the canonical skills directory and creates symlinks
|
|
2996
|
+
* (or copies on Windows) from each provider's skills directory to the canonical path.
|
|
2997
|
+
*
|
|
2998
|
+
* @param sourcePath - Local path to the skill directory to install
|
|
2999
|
+
* @param skillName - Name for the installed skill
|
|
3000
|
+
* @param providers - Target providers to link the skill to
|
|
3001
|
+
* @param isGlobal - Whether to link to global or project skill directories
|
|
3002
|
+
* @param projectDir - Project directory (defaults to `process.cwd()`)
|
|
3003
|
+
* @returns Install result with linked agents and any errors
|
|
3004
|
+
*
|
|
3005
|
+
* @example
|
|
3006
|
+
* ```typescript
|
|
3007
|
+
* const result = await installSkill("/tmp/my-skill", "my-skill", providers, true, "/my/project");
|
|
3008
|
+
* if (result.success) {
|
|
3009
|
+
* console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
|
|
3010
|
+
* }
|
|
3011
|
+
* ```
|
|
3012
|
+
*
|
|
3013
|
+
* @public
|
|
3014
|
+
*/
|
|
3015
|
+
declare function installSkill(sourcePath: string, skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string): Promise<SkillInstallResult>;
|
|
3016
|
+
/**
|
|
3017
|
+
* Remove a skill from the canonical location and all agent symlinks.
|
|
3018
|
+
*
|
|
3019
|
+
* @remarks
|
|
3020
|
+
* Removes symlinks from each provider's skills directory and then removes the
|
|
3021
|
+
* canonical copy from the centralized canonical skills directory.
|
|
3022
|
+
*
|
|
3023
|
+
* @param skillName - Name of the skill to remove
|
|
3024
|
+
* @param providers - Providers to unlink the skill from
|
|
3025
|
+
* @param isGlobal - Whether to target global or project skill directories
|
|
3026
|
+
* @param projectDir - Project directory (defaults to `process.cwd()`)
|
|
3027
|
+
* @returns Object with arrays of successfully removed provider IDs and error messages
|
|
3028
|
+
*
|
|
3029
|
+
* @example
|
|
3030
|
+
* ```typescript
|
|
3031
|
+
* const { removed, errors } = await removeSkill("my-skill", providers, true, "/my/project");
|
|
3032
|
+
* console.log(`Removed from: ${removed.join(", ")}`);
|
|
3033
|
+
* ```
|
|
3034
|
+
*
|
|
3035
|
+
* @public
|
|
3036
|
+
*/
|
|
3037
|
+
declare function removeSkill(skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string): Promise<{
|
|
3038
|
+
removed: string[];
|
|
3039
|
+
errors: string[];
|
|
3040
|
+
}>;
|
|
3041
|
+
/**
|
|
3042
|
+
* List all skills installed in the canonical skills directory.
|
|
3043
|
+
*
|
|
3044
|
+
* @remarks
|
|
3045
|
+
* Returns the directory names of all skills, which correspond to skill names.
|
|
3046
|
+
* Includes both regular directories and symlinks in the canonical location.
|
|
3047
|
+
*
|
|
3048
|
+
* @returns Array of skill names
|
|
3049
|
+
*
|
|
3050
|
+
* @example
|
|
3051
|
+
* ```typescript
|
|
3052
|
+
* const skills = await listCanonicalSkills();
|
|
3053
|
+
* // ["my-skill", "another-skill"]
|
|
3054
|
+
* ```
|
|
3055
|
+
*
|
|
3056
|
+
* @public
|
|
3057
|
+
*/
|
|
3058
|
+
declare function listCanonicalSkills(): Promise<string[]>;
|
|
2035
3059
|
|
|
2036
3060
|
/**
|
|
2037
3061
|
* Pi coding agent harness.
|
|
@@ -2085,10 +3109,6 @@ declare class PiHarness implements Harness {
|
|
|
2085
3109
|
* Resolve the skills directory for a given scope.
|
|
2086
3110
|
*/
|
|
2087
3111
|
private skillsDir;
|
|
2088
|
-
/**
|
|
2089
|
-
* Resolve the extensions directory for a given scope.
|
|
2090
|
-
*/
|
|
2091
|
-
private extensionsDir;
|
|
2092
3112
|
/**
|
|
2093
3113
|
* Resolve the settings.json path for a given scope.
|
|
2094
3114
|
*/
|
|
@@ -2113,38 +3133,219 @@ declare class PiHarness implements Harness {
|
|
|
2113
3133
|
/** {@inheritDoc Harness.removeInstructions} */
|
|
2114
3134
|
removeInstructions(scope: HarnessScope): Promise<void>;
|
|
2115
3135
|
/**
|
|
2116
|
-
*
|
|
3136
|
+
* Spawn a subagent through Pi's configured `spawnCommand` and return a
|
|
3137
|
+
* live handle bound to the canonical streaming, attribution, and
|
|
3138
|
+
* cleanup contract.
|
|
3139
|
+
*
|
|
3140
|
+
* @remarks
|
|
3141
|
+
* Per ADR-035 §D6 this is the **only** sanctioned subagent spawn path
|
|
3142
|
+
* in CLEO. All historical direct `child_process.spawn` callers in
|
|
3143
|
+
* subagent contexts (including the `cant-bridge.ts` Pi extension and
|
|
3144
|
+
* the legacy CLEO orchestrator paths) MUST migrate to this method so
|
|
3145
|
+
* the contract below holds uniformly. A custom biome rule banning
|
|
3146
|
+
* raw `spawn()` from subagent code is planned for v3 cleanup but is
|
|
3147
|
+
* intentionally NOT enforced in v2 to keep the migration incremental.
|
|
3148
|
+
*
|
|
3149
|
+
* **Streaming semantics** — Pi's `--mode json` produces line-delimited
|
|
3150
|
+
* JSON on stdout. The harness:
|
|
3151
|
+
*
|
|
3152
|
+
* - Line-buffers stdout, parses each line as JSON, and forwards a
|
|
3153
|
+
* `{ kind: 'message', subagentId, lineNumber, payload }`
|
|
3154
|
+
* {@link SubagentStreamEvent} via {@link SubagentSpawnOptions.onStream}.
|
|
3155
|
+
* Non-parseable lines increment a warning counter (recorded in the
|
|
3156
|
+
* child session as `{ type: 'raw' }`) but never crash the loop.
|
|
3157
|
+
* - Line-buffers stderr separately, forwards each line as
|
|
3158
|
+
* `{ kind: 'stderr', subagentId, payload: { line } }`, and stores
|
|
3159
|
+
* it in a 100-line ring buffer accessible via
|
|
3160
|
+
* {@link SubagentHandle.recentStderr}. Stderr is **never** injected
|
|
3161
|
+
* into the parent LLM context per ADR-035 §D6.
|
|
3162
|
+
* - Emits a final `{ kind: 'exit', subagentId, payload: SubagentExitResult }`
|
|
3163
|
+
* when the child terminates.
|
|
3164
|
+
*
|
|
3165
|
+
* **Session attribution** — Every spawn produces a child session JSONL
|
|
3166
|
+
* file at
|
|
3167
|
+
* `~/.pi/agent/sessions/subagents/subagent-{parentSessionId}-{taskId}.jsonl`.
|
|
3168
|
+
* The header line records the subagentId, taskId, and parent linkage.
|
|
3169
|
+
* When {@link SubagentTask.parentSessionPath} is supplied, a
|
|
3170
|
+
* {@link SubagentLinkEntry} is appended to the parent session file as
|
|
3171
|
+
* a JSONL line so listing the parent surfaces its children.
|
|
3172
|
+
*
|
|
3173
|
+
* **Exit propagation** — {@link SubagentHandle.exitPromise} resolves
|
|
3174
|
+
* with `{ code, signal, childSessionPath, durationMs }` exactly once
|
|
3175
|
+
* when the child exits. The promise NEVER rejects: failure is
|
|
3176
|
+
* encoded by a non-zero `code`, a non-null `signal`, or partial
|
|
3177
|
+
* output preserved in the child session file.
|
|
3178
|
+
*
|
|
3179
|
+
* **Cleanup** — {@link SubagentHandle.terminate} sends SIGTERM, waits
|
|
3180
|
+
* the configured grace window, then sends SIGKILL if the child is
|
|
3181
|
+
* still alive. The grace window is sourced from
|
|
3182
|
+
* {@link SubagentSpawnOptions.terminateGraceMs} when supplied,
|
|
3183
|
+
* otherwise from `settings.json:pi.subagent.terminateGraceMs`,
|
|
3184
|
+
* otherwise from {@link DEFAULT_TERMINATE_GRACE_MS}. A
|
|
3185
|
+
* `subagent_exit` entry with reason `terminated` is appended to the
|
|
3186
|
+
* child session file when cleanup runs.
|
|
3187
|
+
*
|
|
3188
|
+
* **Concurrency** — Use the static helpers
|
|
3189
|
+
* {@link PiHarness.raceSubagents} and
|
|
3190
|
+
* {@link PiHarness.settleAllSubagents} to compose `parallel: race`
|
|
3191
|
+
* and `parallel: settle` constructs from CANT workflows over multiple
|
|
3192
|
+
* handles.
|
|
3193
|
+
*
|
|
3194
|
+
* **Orphan handling** — On the first spawn the harness registers a
|
|
3195
|
+
* process-wide `'exit'` handler that terminates every still-active
|
|
3196
|
+
* subagent so a parent crash never strands children.
|
|
3197
|
+
*
|
|
3198
|
+
* Throws immediately when the provider entry is missing a
|
|
3199
|
+
* `spawnCommand` so callers see configuration errors early rather
|
|
3200
|
+
* than at child-exit time.
|
|
3201
|
+
*
|
|
3202
|
+
* @param task - Subagent task specification.
|
|
3203
|
+
* @param opts - Per-call streaming and cleanup overrides.
|
|
3204
|
+
* @returns A live subagent handle.
|
|
3205
|
+
*/
|
|
3206
|
+
spawnSubagent(task: SubagentTask, opts?: SubagentSpawnOptions): Promise<SubagentHandle>;
|
|
3207
|
+
/**
|
|
3208
|
+
* Race a set of subagent handles, returning the first one that exits.
|
|
2117
3209
|
*
|
|
2118
3210
|
* @remarks
|
|
2119
|
-
*
|
|
2120
|
-
*
|
|
2121
|
-
*
|
|
2122
|
-
*
|
|
2123
|
-
*
|
|
2124
|
-
*
|
|
2125
|
-
*
|
|
3211
|
+
* Maps CANT's `parallel: race` construct (per ADR-035 §D6) onto the
|
|
3212
|
+
* canonical {@link spawnSubagent} contract. The losing handles are
|
|
3213
|
+
* gracefully terminated via {@link SubagentHandle.terminate} once the
|
|
3214
|
+
* first settles so no straggler children outlive the race.
|
|
3215
|
+
*
|
|
3216
|
+
* @param handles - Subagent handles to race.
|
|
3217
|
+
* @returns The {@link SubagentExitResult} of the first child to exit.
|
|
3218
|
+
* @throws When `handles` is empty (caller bug — a race over zero
|
|
3219
|
+
* children has no winner).
|
|
2126
3220
|
*/
|
|
2127
|
-
|
|
3221
|
+
static raceSubagents(handles: SubagentHandle[]): Promise<SubagentExitResult>;
|
|
2128
3222
|
/**
|
|
2129
|
-
*
|
|
3223
|
+
* Settle a set of subagent handles, returning a parallel array of
|
|
3224
|
+
* results.
|
|
2130
3225
|
*
|
|
2131
3226
|
* @remarks
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
2134
|
-
*
|
|
2135
|
-
*
|
|
2136
|
-
*
|
|
3227
|
+
* Maps CANT's `parallel: settle` construct (per ADR-035 §D6) onto the
|
|
3228
|
+
* canonical {@link spawnSubagent} contract. Because
|
|
3229
|
+
* {@link SubagentHandle.exitPromise} never rejects, every entry in
|
|
3230
|
+
* the returned array is `{ status: 'fulfilled', value: ... }` under
|
|
3231
|
+
* normal operation; the `PromiseSettledResult` shape is preserved
|
|
3232
|
+
* for forward compatibility with future failure modes.
|
|
3233
|
+
*
|
|
3234
|
+
* @param handles - Subagent handles to settle.
|
|
3235
|
+
* @returns Parallel array of settled exit results, one per input.
|
|
3236
|
+
*/
|
|
3237
|
+
static settleAllSubagents(handles: SubagentHandle[]): Promise<PromiseSettledResult<SubagentExitResult>[]>;
|
|
3238
|
+
/**
|
|
3239
|
+
* Per-line stdout dispatcher used by the streaming buffer flusher.
|
|
2137
3240
|
*
|
|
2138
|
-
*
|
|
2139
|
-
*
|
|
3241
|
+
* @remarks
|
|
3242
|
+
* Extracted as a private method so the line-handling logic stays
|
|
3243
|
+
* close to {@link spawnSubagent} but does not bloat the parent
|
|
3244
|
+
* function. Skips empty lines (a leading newline produces a zero-
|
|
3245
|
+
* length entry that has no semantic meaning).
|
|
2140
3246
|
*/
|
|
2141
|
-
|
|
3247
|
+
private handleStdoutLine;
|
|
2142
3248
|
/** {@inheritDoc Harness.readSettings} */
|
|
2143
3249
|
readSettings(scope: HarnessScope): Promise<unknown>;
|
|
2144
3250
|
/** {@inheritDoc Harness.writeSettings} */
|
|
2145
3251
|
writeSettings(patch: Record<string, unknown>, scope: HarnessScope): Promise<void>;
|
|
2146
3252
|
/** {@inheritDoc Harness.configureModels} */
|
|
2147
3253
|
configureModels(modelPatterns: string[], scope: HarnessScope): Promise<void>;
|
|
3254
|
+
/**
|
|
3255
|
+
* Resolve the `models.json` path for a given legacy two-tier scope.
|
|
3256
|
+
*
|
|
3257
|
+
* @remarks
|
|
3258
|
+
* Lives next to `settings.json`. Global scope uses the Pi state root,
|
|
3259
|
+
* project scope uses the project's `.pi/` directory, matching the
|
|
3260
|
+
* dual-file authority model documented in ADR-035 §D3.
|
|
3261
|
+
*/
|
|
3262
|
+
private modelsConfigPath;
|
|
3263
|
+
/**
|
|
3264
|
+
* Resolve the sessions directory — always user-tier because Pi owns
|
|
3265
|
+
* session storage and the three-tier model folds session listings to
|
|
3266
|
+
* the single authoritative location per ADR-035 §D2.
|
|
3267
|
+
*/
|
|
3268
|
+
private sessionsDir;
|
|
3269
|
+
/** {@inheritDoc Harness.installExtension} */
|
|
3270
|
+
installExtension(sourcePath: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
3271
|
+
targetPath: string;
|
|
3272
|
+
tier: HarnessTier;
|
|
3273
|
+
}>;
|
|
3274
|
+
/** {@inheritDoc Harness.removeExtension} */
|
|
3275
|
+
removeExtension(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
3276
|
+
/** {@inheritDoc Harness.listExtensions} */
|
|
3277
|
+
listExtensions(projectDir?: string): Promise<ExtensionEntry[]>;
|
|
3278
|
+
/** {@inheritDoc Harness.listSessions} */
|
|
3279
|
+
listSessions(opts?: {
|
|
3280
|
+
includeSubagents?: boolean;
|
|
3281
|
+
}): Promise<SessionSummary[]>;
|
|
3282
|
+
/** {@inheritDoc Harness.showSession} */
|
|
3283
|
+
showSession(id: string): Promise<SessionDocument>;
|
|
3284
|
+
/** {@inheritDoc Harness.readModelsConfig} */
|
|
3285
|
+
readModelsConfig(scope: HarnessScope): Promise<PiModelsConfig>;
|
|
3286
|
+
/** {@inheritDoc Harness.writeModelsConfig} */
|
|
3287
|
+
writeModelsConfig(config: PiModelsConfig, scope: HarnessScope): Promise<void>;
|
|
3288
|
+
/** {@inheritDoc Harness.listModels} */
|
|
3289
|
+
listModels(scope: HarnessScope): Promise<ModelListEntry[]>;
|
|
3290
|
+
/** {@inheritDoc Harness.installPrompt} */
|
|
3291
|
+
installPrompt(sourceDir: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
3292
|
+
targetPath: string;
|
|
3293
|
+
tier: HarnessTier;
|
|
3294
|
+
}>;
|
|
3295
|
+
/** {@inheritDoc Harness.listPrompts} */
|
|
3296
|
+
listPrompts(projectDir?: string): Promise<PromptEntry[]>;
|
|
3297
|
+
/** {@inheritDoc Harness.removePrompt} */
|
|
3298
|
+
removePrompt(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
3299
|
+
/** {@inheritDoc Harness.installTheme} */
|
|
3300
|
+
installTheme(sourceFile: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
3301
|
+
targetPath: string;
|
|
3302
|
+
tier: HarnessTier;
|
|
3303
|
+
}>;
|
|
3304
|
+
/** {@inheritDoc Harness.listThemes} */
|
|
3305
|
+
listThemes(projectDir?: string): Promise<ThemeEntry[]>;
|
|
3306
|
+
/** {@inheritDoc Harness.removeTheme} */
|
|
3307
|
+
removeTheme(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
3308
|
+
/**
|
|
3309
|
+
* {@inheritDoc Harness.installCantProfile}
|
|
3310
|
+
*
|
|
3311
|
+
* @remarks
|
|
3312
|
+
* Validates the source via {@link validateCantProfile} before copying so
|
|
3313
|
+
* we never persist a `.cant` file the runtime bridge cannot load. The
|
|
3314
|
+
* target layout is `<tier-root>/cant/<name>.cant`, resolved through
|
|
3315
|
+
* {@link resolveTierDir} so the project/user/global hierarchy stays
|
|
3316
|
+
* consistent with the other Wave-1 verbs.
|
|
3317
|
+
*/
|
|
3318
|
+
installCantProfile(sourcePath: string, name: string, tier: HarnessTier, projectDir?: string, opts?: HarnessInstallOptions): Promise<{
|
|
3319
|
+
targetPath: string;
|
|
3320
|
+
tier: HarnessTier;
|
|
3321
|
+
counts: CantProfileCounts;
|
|
3322
|
+
}>;
|
|
3323
|
+
/** {@inheritDoc Harness.removeCantProfile} */
|
|
3324
|
+
removeCantProfile(name: string, tier: HarnessTier, projectDir?: string): Promise<boolean>;
|
|
3325
|
+
/**
|
|
3326
|
+
* {@inheritDoc Harness.listCantProfiles}
|
|
3327
|
+
*
|
|
3328
|
+
* @remarks
|
|
3329
|
+
* Walks every tier in {@link TIER_PRECEDENCE} order, parsing each
|
|
3330
|
+
* discovered `.cant` file via cant-core to extract a
|
|
3331
|
+
* {@link CantProfileCounts} bag. Higher-precedence tiers shadow
|
|
3332
|
+
* lower-precedence entries with the same name; shadowed entries
|
|
3333
|
+
* still appear in the result but carry the
|
|
3334
|
+
* `shadowedByHigherTier` flag so callers can render the precedence
|
|
3335
|
+
* story without losing visibility of the duplicate.
|
|
3336
|
+
*/
|
|
3337
|
+
listCantProfiles(projectDir?: string): Promise<CantProfileEntry[]>;
|
|
3338
|
+
/**
|
|
3339
|
+
* {@inheritDoc Harness.validateCantProfile}
|
|
3340
|
+
*
|
|
3341
|
+
* @remarks
|
|
3342
|
+
* Pure validator. Reads the file, runs `parseDocument` to derive
|
|
3343
|
+
* counts (when parsing succeeds) and `validateDocument` to collect
|
|
3344
|
+
* the 42-rule diagnostic feed. The two calls are kept independent so
|
|
3345
|
+
* we can still report counts for files that pass parsing but fail a
|
|
3346
|
+
* lint rule.
|
|
3347
|
+
*/
|
|
3348
|
+
validateCantProfile(sourcePath: string): Promise<ValidateCantProfileResult>;
|
|
2148
3349
|
}
|
|
2149
3350
|
|
|
2150
3351
|
/**
|
|
@@ -2226,42 +3427,52 @@ declare function getPrimaryHarness(): Harness | null;
|
|
|
2226
3427
|
declare function getAllHarnesses(): Harness[];
|
|
2227
3428
|
/**
|
|
2228
3429
|
* Resolve the default set of target providers when the user has not passed
|
|
2229
|
-
* `--agent
|
|
3430
|
+
* `--agent`, honouring the active {@link ExclusivityMode}.
|
|
2230
3431
|
*
|
|
2231
3432
|
* @remarks
|
|
2232
|
-
* Resolution policy
|
|
3433
|
+
* Resolution policy is layered. The active {@link ExclusivityMode} (read
|
|
3434
|
+
* via {@link getExclusivityMode}) selects which branch of the matrix runs:
|
|
3435
|
+
*
|
|
3436
|
+
* | Mode | Pi installed | Pi absent |
|
|
3437
|
+
* |---|---|---|
|
|
3438
|
+
* | `'auto'` (default) | Returns `[piProvider]`. Explicit non-Pi targets emit a one-time deprecation warning per process. | Falls back to installed primary/high-tier providers (legacy v2026.4.5 behaviour) and emits a one-time boot warning. |
|
|
3439
|
+
* | `'force-pi'` | Returns `[piProvider]`. | Throws {@link PiRequiredError}. |
|
|
3440
|
+
* | `'legacy'` | Returns the full installed provider list in priority order (matches pre-exclusivity behaviour). | Same. |
|
|
2233
3441
|
*
|
|
2234
|
-
*
|
|
2235
|
-
*
|
|
2236
|
-
*
|
|
2237
|
-
*
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2240
|
-
*
|
|
2241
|
-
* harness is available.
|
|
2242
|
-
* 3. If the priority filter yields an empty list (e.g. in tests that stub
|
|
2243
|
-
* providers without a `priority` field, or in fresh installs with only
|
|
2244
|
-
* medium/low-tier providers detected), fall back to the full installed
|
|
2245
|
-
* provider list so that commands retain a valid target.
|
|
3442
|
+
* **Install paths are unaffected.** Per ADR-035 §D7, this helper governs
|
|
3443
|
+
* RUNTIME INVOCATION dispatch only. Skill and instruction install
|
|
3444
|
+
* dispatchers ({@link dispatchInstallSkillAcrossProviders},
|
|
3445
|
+
* {@link dispatchRemoveSkillAcrossProviders}) intentionally do not call
|
|
3446
|
+
* this function — they target every requested provider directly so that
|
|
3447
|
+
* users in `force-pi` mode can still `caamp skills install foo --agent
|
|
3448
|
+
* claude-code` while Pi is being installed.
|
|
2246
3449
|
*
|
|
2247
|
-
*
|
|
2248
|
-
*
|
|
2249
|
-
*
|
|
2250
|
-
* sensibly.
|
|
3450
|
+
* The helper is intentionally defensive: registry/detection exceptions
|
|
3451
|
+
* are caught and treated as "Pi unknown" so stubbed test environments
|
|
3452
|
+
* that do not wire the full registry still behave sensibly.
|
|
2251
3453
|
*
|
|
3454
|
+
* @param options - Optional explicit provider selection (e.g. from
|
|
3455
|
+
* `--agent`) used by `auto`-mode deprecation warning detection. Omit to
|
|
3456
|
+
* request the implicit default resolution.
|
|
2252
3457
|
* @returns Ordered list of providers to target by default.
|
|
3458
|
+
* @throws {@link PiRequiredError} when mode is `'force-pi'` and Pi is not
|
|
3459
|
+
* installed.
|
|
2253
3460
|
*
|
|
2254
3461
|
* @example
|
|
2255
3462
|
* ```typescript
|
|
3463
|
+
* // Implicit default — used by `caamp skills list` and friends.
|
|
2256
3464
|
* const targets = resolveDefaultTargetProviders();
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
3465
|
+
*
|
|
3466
|
+
* // Explicit user selection — emits a deprecation warning in `auto` mode
|
|
3467
|
+
* // when the selection excludes Pi and Pi is installed.
|
|
3468
|
+
* const explicit = resolveDefaultTargetProviders({
|
|
3469
|
+
* explicit: [getProvider('claude-code')!],
|
|
3470
|
+
* });
|
|
2260
3471
|
* ```
|
|
2261
3472
|
*
|
|
2262
3473
|
* @public
|
|
2263
3474
|
*/
|
|
2264
|
-
declare function resolveDefaultTargetProviders(): Provider[];
|
|
3475
|
+
declare function resolveDefaultTargetProviders(options?: ResolveDefaultTargetProvidersOptions): Provider[];
|
|
2265
3476
|
|
|
2266
3477
|
/**
|
|
2267
3478
|
* All hook event categories (8 total).
|
|
@@ -3572,6 +4783,362 @@ declare class MarketplaceClient {
|
|
|
3572
4783
|
getSkill(scopedName: string): Promise<MarketplaceResult | null>;
|
|
3573
4784
|
}
|
|
3574
4785
|
|
|
4786
|
+
/**
|
|
4787
|
+
* MCP server config reader.
|
|
4788
|
+
*
|
|
4789
|
+
* @remarks
|
|
4790
|
+
* Reads MCP server entries from a provider's per-agent config file using
|
|
4791
|
+
* the format-agnostic {@link readConfig} substrate from `core/formats`.
|
|
4792
|
+
* The provider's `capabilities.mcp` block is the single source of truth
|
|
4793
|
+
* for the file path, format, and dot-notation key — this module never
|
|
4794
|
+
* hard-codes provider-specific layout.
|
|
4795
|
+
*
|
|
4796
|
+
* Three operations are exported:
|
|
4797
|
+
*
|
|
4798
|
+
* - {@link listMcpServers} — enumerate every server entry on a single
|
|
4799
|
+
* provider's config file at a given scope.
|
|
4800
|
+
* - {@link listAllMcpServers} — fan out across every MCP-capable
|
|
4801
|
+
* provider in the registry, returning a map keyed by provider id.
|
|
4802
|
+
* - {@link detectMcpInstallations} — lighter-weight scan that just
|
|
4803
|
+
* reports which providers currently have any MCP config files on
|
|
4804
|
+
* disk (used by `caamp mcp detect`).
|
|
4805
|
+
*
|
|
4806
|
+
* @packageDocumentation
|
|
4807
|
+
*/
|
|
4808
|
+
|
|
4809
|
+
/**
|
|
4810
|
+
* Scope identifier for MCP config file resolution.
|
|
4811
|
+
*
|
|
4812
|
+
* @remarks
|
|
4813
|
+
* Mirrors the two-tier scope model the underlying provider config files
|
|
4814
|
+
* already use: `project` reads `<projectDir>/<provider.configPathProject>`
|
|
4815
|
+
* and `global` reads the absolute `provider.configPathGlobal` path. The
|
|
4816
|
+
* three-tier {@link HarnessTier} model used by the Pi extensions
|
|
4817
|
+
* verbs is intentionally not adopted here — MCP config files are owned
|
|
4818
|
+
* by individual tools and live on those tools' two-tier hierarchy, not
|
|
4819
|
+
* on a CleoOS-managed hub.
|
|
4820
|
+
*
|
|
4821
|
+
* @public
|
|
4822
|
+
*/
|
|
4823
|
+
type McpScope = 'project' | 'global';
|
|
4824
|
+
/**
|
|
4825
|
+
* Result of a single provider's MCP installation probe.
|
|
4826
|
+
*
|
|
4827
|
+
* @remarks
|
|
4828
|
+
* Returned by {@link detectMcpInstallations} for each provider that
|
|
4829
|
+
* declares an MCP capability in the registry. The `configPath` field
|
|
4830
|
+
* is the resolved file path the probe inspected; `exists` indicates
|
|
4831
|
+
* whether the file is present on disk; `serverCount` is `null` when
|
|
4832
|
+
* the file is missing or unparseable, otherwise the number of server
|
|
4833
|
+
* entries found at the dot-notation key.
|
|
4834
|
+
*
|
|
4835
|
+
* @public
|
|
4836
|
+
*/
|
|
4837
|
+
interface McpDetectionEntry {
|
|
4838
|
+
/** Provider id (e.g. `"claude-code"`). */
|
|
4839
|
+
providerId: string;
|
|
4840
|
+
/** Human-readable provider name. */
|
|
4841
|
+
providerName: string;
|
|
4842
|
+
/** Resolved scope of the probed config file. */
|
|
4843
|
+
scope: McpScope;
|
|
4844
|
+
/** Absolute path to the provider's MCP config file. */
|
|
4845
|
+
configPath: string;
|
|
4846
|
+
/** Whether the config file exists on disk. */
|
|
4847
|
+
exists: boolean;
|
|
4848
|
+
/** Number of server entries found, or `null` when the file is missing/unparseable. */
|
|
4849
|
+
serverCount: number | null;
|
|
4850
|
+
/** ISO 8601 timestamp of the file's last modification, or `null` when the file is missing. */
|
|
4851
|
+
lastModified: string | null;
|
|
4852
|
+
}
|
|
4853
|
+
/**
|
|
4854
|
+
* Resolve a provider's MCP config file path for the given scope, or
|
|
4855
|
+
* `null` if the provider does not declare an MCP capability or the
|
|
4856
|
+
* scope is unsupported.
|
|
4857
|
+
*
|
|
4858
|
+
* @remarks
|
|
4859
|
+
* Thin wrapper over {@link resolveProviderConfigPath} that filters out
|
|
4860
|
+
* providers without an MCP capability up front so callers can use a
|
|
4861
|
+
* single null check rather than two.
|
|
4862
|
+
*
|
|
4863
|
+
* @param provider - Provider to resolve a config path for.
|
|
4864
|
+
* @param scope - Scope to resolve.
|
|
4865
|
+
* @param projectDir - Project directory used for the `project` scope.
|
|
4866
|
+
* @returns The absolute config file path, or `null` when unavailable.
|
|
4867
|
+
*
|
|
4868
|
+
* @public
|
|
4869
|
+
*/
|
|
4870
|
+
declare function resolveMcpConfigPath(provider: Provider, scope: McpScope, projectDir?: string): string | null;
|
|
4871
|
+
/**
|
|
4872
|
+
* List MCP server entries declared in a single provider's config file.
|
|
4873
|
+
*
|
|
4874
|
+
* @remarks
|
|
4875
|
+
* Reads the provider's MCP config file using the format-agnostic
|
|
4876
|
+
* {@link readConfig} substrate, walks the dot-notation
|
|
4877
|
+
* `provider.capabilities.mcp.configKey` to find the servers section,
|
|
4878
|
+
* and returns one {@link McpServerEntry} per child key.
|
|
4879
|
+
*
|
|
4880
|
+
* Returns an empty array (not an error) when:
|
|
4881
|
+
*
|
|
4882
|
+
* - the provider does not declare an MCP capability,
|
|
4883
|
+
* - the resolved config path is unavailable for the requested scope,
|
|
4884
|
+
* - the config file does not exist on disk,
|
|
4885
|
+
* - the config file is empty or unparseable,
|
|
4886
|
+
* - the config file exists but has no MCP servers section.
|
|
4887
|
+
*
|
|
4888
|
+
* "No file" is a normal state for an uninstalled tool, so callers
|
|
4889
|
+
* should treat the empty array as success and only escalate to an
|
|
4890
|
+
* error envelope when the user explicitly asked about a missing
|
|
4891
|
+
* provider.
|
|
4892
|
+
*
|
|
4893
|
+
* @param provider - Provider whose config file to read.
|
|
4894
|
+
* @param scope - Scope to resolve (project|global).
|
|
4895
|
+
* @param projectDir - Project directory used for the `project` scope
|
|
4896
|
+
* (defaults to `process.cwd()`).
|
|
4897
|
+
* @returns Array of MCP server entries, or `[]` when nothing was found.
|
|
4898
|
+
*
|
|
4899
|
+
* @public
|
|
4900
|
+
*/
|
|
4901
|
+
declare function listMcpServers(provider: Provider, scope: McpScope, projectDir?: string): Promise<McpServerEntry[]>;
|
|
4902
|
+
/**
|
|
4903
|
+
* Map of provider id → MCP server entries for that provider.
|
|
4904
|
+
*
|
|
4905
|
+
* @remarks
|
|
4906
|
+
* Return shape of {@link listAllMcpServers}. Providers without an MCP
|
|
4907
|
+
* capability are intentionally absent from the map (rather than mapped
|
|
4908
|
+
* to an empty array) so callers can iterate the result and immediately
|
|
4909
|
+
* know which providers were probed.
|
|
4910
|
+
*
|
|
4911
|
+
* @public
|
|
4912
|
+
*/
|
|
4913
|
+
type McpServerEntriesByProvider = Map<string, McpServerEntry[]>;
|
|
4914
|
+
/**
|
|
4915
|
+
* List MCP server entries for every MCP-capable provider in the
|
|
4916
|
+
* registry at the given scope.
|
|
4917
|
+
*
|
|
4918
|
+
* @remarks
|
|
4919
|
+
* Iterates {@link getAllProviders}, filters to those with a
|
|
4920
|
+
* `capabilities.mcp` block, calls {@link listMcpServers} on each, and
|
|
4921
|
+
* collects the results into a map keyed by provider id.
|
|
4922
|
+
*
|
|
4923
|
+
* Each provider is probed independently — a parse failure on one
|
|
4924
|
+
* provider will not affect the others. The result map only contains
|
|
4925
|
+
* entries for providers that were actually probed (i.e. had an MCP
|
|
4926
|
+
* capability), so consumers can iterate `result.entries()` without
|
|
4927
|
+
* skipping non-MCP providers.
|
|
4928
|
+
*
|
|
4929
|
+
* @param scope - Scope to resolve for every provider.
|
|
4930
|
+
* @param projectDir - Project directory used for the `project` scope.
|
|
4931
|
+
* @returns Map of provider id → server entries.
|
|
4932
|
+
*
|
|
4933
|
+
* @public
|
|
4934
|
+
*/
|
|
4935
|
+
declare function listAllMcpServers(scope: McpScope, projectDir?: string): Promise<McpServerEntriesByProvider>;
|
|
4936
|
+
/**
|
|
4937
|
+
* Probe every MCP-capable provider in the registry to determine which
|
|
4938
|
+
* ones have a config file on disk and how many servers are configured.
|
|
4939
|
+
*
|
|
4940
|
+
* @remarks
|
|
4941
|
+
* Lightweight detection used by `caamp mcp detect`. Unlike
|
|
4942
|
+
* {@link listAllMcpServers} this does not return individual server
|
|
4943
|
+
* entries — it just reports a count plus the file mtime so callers can
|
|
4944
|
+
* answer "which tools on my machine already have MCP configured?"
|
|
4945
|
+
* without paying the cost of materialising every server entry.
|
|
4946
|
+
*
|
|
4947
|
+
* @param scope - Scope to probe.
|
|
4948
|
+
* @param projectDir - Project directory used for the `project` scope.
|
|
4949
|
+
* @returns Array of detection entries, one per MCP-capable provider.
|
|
4950
|
+
*
|
|
4951
|
+
* @public
|
|
4952
|
+
*/
|
|
4953
|
+
declare function detectMcpInstallations(scope: McpScope, projectDir?: string): Promise<McpDetectionEntry[]>;
|
|
4954
|
+
|
|
4955
|
+
/**
|
|
4956
|
+
* MCP server config installer.
|
|
4957
|
+
*
|
|
4958
|
+
* @remarks
|
|
4959
|
+
* Writes a single MCP server entry into a provider's config file using
|
|
4960
|
+
* the format-agnostic {@link writeConfig} substrate from `core/formats`.
|
|
4961
|
+
* The provider's `capabilities.mcp` block is the single source of
|
|
4962
|
+
* truth for the file path, format, and dot-notation key.
|
|
4963
|
+
*
|
|
4964
|
+
* Conflict-on-write semantics:
|
|
4965
|
+
*
|
|
4966
|
+
* - When the target server name does not yet exist in the file, the
|
|
4967
|
+
* write succeeds and {@link InstallMcpServerResult.conflicted} is
|
|
4968
|
+
* `false`.
|
|
4969
|
+
* - When the target server name already exists in the file and `force`
|
|
4970
|
+
* is `false`, the installer DOES NOT write — it returns
|
|
4971
|
+
* `installed: false, conflicted: true` so the caller can emit a
|
|
4972
|
+
* typed conflict error envelope.
|
|
4973
|
+
* - When `force` is `true`, an existing entry is overwritten and the
|
|
4974
|
+
* result reports `installed: true, conflicted: true` so the caller
|
|
4975
|
+
* can surface the overwrite in its envelope.
|
|
4976
|
+
*
|
|
4977
|
+
* Parent directories of the resolved config path are created lazily on
|
|
4978
|
+
* write — see {@link writeConfig} for the per-format details.
|
|
4979
|
+
*
|
|
4980
|
+
* @packageDocumentation
|
|
4981
|
+
*/
|
|
4982
|
+
|
|
4983
|
+
/**
|
|
4984
|
+
* Options accepted by {@link installMcpServer}.
|
|
4985
|
+
*
|
|
4986
|
+
* @public
|
|
4987
|
+
*/
|
|
4988
|
+
interface InstallMcpServerOptions {
|
|
4989
|
+
/** Scope to write to (project|global). */
|
|
4990
|
+
scope: McpScope;
|
|
4991
|
+
/** When `true`, overwrite an existing server entry instead of failing. */
|
|
4992
|
+
force?: boolean;
|
|
4993
|
+
/** Project directory used for the `project` scope. */
|
|
4994
|
+
projectDir?: string;
|
|
4995
|
+
}
|
|
4996
|
+
/**
|
|
4997
|
+
* Result of an {@link installMcpServer} call.
|
|
4998
|
+
*
|
|
4999
|
+
* @remarks
|
|
5000
|
+
* `installed` is `true` only when the file was actually written.
|
|
5001
|
+
* `conflicted` is `true` whenever the target server name was already
|
|
5002
|
+
* present, regardless of whether the write went through (force was
|
|
5003
|
+
* supplied) or was suppressed (force was withheld).
|
|
5004
|
+
*
|
|
5005
|
+
* @public
|
|
5006
|
+
*/
|
|
5007
|
+
interface InstallMcpServerResult {
|
|
5008
|
+
/** Whether the entry was written to the config file. */
|
|
5009
|
+
installed: boolean;
|
|
5010
|
+
/** Whether the target server name already existed before the call. */
|
|
5011
|
+
conflicted: boolean;
|
|
5012
|
+
/** Absolute path to the config file that was (or would have been) written. */
|
|
5013
|
+
sourcePath: string;
|
|
5014
|
+
/** Provider id the entry was written for. */
|
|
5015
|
+
providerId: string;
|
|
5016
|
+
/** Server name that was written. */
|
|
5017
|
+
serverName: string;
|
|
5018
|
+
}
|
|
5019
|
+
/**
|
|
5020
|
+
* Install an MCP server entry into a single provider's config file.
|
|
5021
|
+
*
|
|
5022
|
+
* @remarks
|
|
5023
|
+
* Resolves the provider's MCP config path for the requested scope,
|
|
5024
|
+
* checks for an existing entry with the same server name, and either
|
|
5025
|
+
* writes the new config (when no conflict, or when `force` is set) or
|
|
5026
|
+
* returns a non-installed conflict result.
|
|
5027
|
+
*
|
|
5028
|
+
* Throws a plain `Error` (not a `LAFSCommandError`) when the provider
|
|
5029
|
+
* has no MCP capability or no config path for the requested scope —
|
|
5030
|
+
* those are caller-side validation failures and should be caught and
|
|
5031
|
+
* re-thrown as typed `LAFSCommandError`s in the command layer.
|
|
5032
|
+
*
|
|
5033
|
+
* @param provider - Target provider.
|
|
5034
|
+
* @param serverName - Name/key for the new server entry.
|
|
5035
|
+
* @param config - Canonical {@link McpServerConfig} payload to write.
|
|
5036
|
+
* @param opts - Install options (scope, force, projectDir).
|
|
5037
|
+
* @returns Structured install result describing what happened.
|
|
5038
|
+
* @throws `Error` when the provider has no MCP capability or no
|
|
5039
|
+
* project-scoped config path is available.
|
|
5040
|
+
*
|
|
5041
|
+
* @public
|
|
5042
|
+
*/
|
|
5043
|
+
declare function installMcpServer(provider: Provider, serverName: string, config: McpServerConfig, opts: InstallMcpServerOptions): Promise<InstallMcpServerResult>;
|
|
5044
|
+
|
|
5045
|
+
/**
|
|
5046
|
+
* MCP server config remover.
|
|
5047
|
+
*
|
|
5048
|
+
* @remarks
|
|
5049
|
+
* Removes a single MCP server entry from a provider's config file
|
|
5050
|
+
* using the format-agnostic {@link removeConfig} substrate from
|
|
5051
|
+
* `core/formats`. The provider's `capabilities.mcp` block is the
|
|
5052
|
+
* single source of truth for the file path, format, and dot-notation
|
|
5053
|
+
* key.
|
|
5054
|
+
*
|
|
5055
|
+
* Both single-provider and all-providers variants are exported. Both
|
|
5056
|
+
* are idempotent: removing a server that does not exist returns
|
|
5057
|
+
* `removed: false` rather than throwing.
|
|
5058
|
+
*
|
|
5059
|
+
* @packageDocumentation
|
|
5060
|
+
*/
|
|
5061
|
+
|
|
5062
|
+
/**
|
|
5063
|
+
* Options accepted by {@link removeMcpServer} and
|
|
5064
|
+
* {@link removeMcpServerFromAll}.
|
|
5065
|
+
*
|
|
5066
|
+
* @public
|
|
5067
|
+
*/
|
|
5068
|
+
interface RemoveMcpServerOptions {
|
|
5069
|
+
/** Scope to target (project|global). */
|
|
5070
|
+
scope: McpScope;
|
|
5071
|
+
/** Project directory used for the `project` scope. */
|
|
5072
|
+
projectDir?: string;
|
|
5073
|
+
}
|
|
5074
|
+
/**
|
|
5075
|
+
* Result of a single-provider {@link removeMcpServer} call.
|
|
5076
|
+
*
|
|
5077
|
+
* @remarks
|
|
5078
|
+
* `removed` is `true` only when an entry was actually deleted from
|
|
5079
|
+
* the file. The `reason` field carries an optional discriminator when
|
|
5080
|
+
* the call was a no-op so the command layer can surface a precise
|
|
5081
|
+
* envelope (e.g. "no config file" vs "entry not present").
|
|
5082
|
+
*
|
|
5083
|
+
* @public
|
|
5084
|
+
*/
|
|
5085
|
+
interface RemoveMcpServerResult {
|
|
5086
|
+
/** Provider id the call targeted. */
|
|
5087
|
+
providerId: string;
|
|
5088
|
+
/** Server name the call targeted. */
|
|
5089
|
+
serverName: string;
|
|
5090
|
+
/** Resolved config file path, or `null` when the provider had no MCP capability. */
|
|
5091
|
+
sourcePath: string | null;
|
|
5092
|
+
/** Whether an entry was actually deleted. */
|
|
5093
|
+
removed: boolean;
|
|
5094
|
+
/**
|
|
5095
|
+
* Diagnostic discriminator when `removed` is `false`.
|
|
5096
|
+
*
|
|
5097
|
+
* - `"no-mcp-capability"` — provider does not consume MCP servers
|
|
5098
|
+
* - `"no-config-path"` — provider has no config path for the scope
|
|
5099
|
+
* - `"file-missing"` — config file does not exist on disk
|
|
5100
|
+
* - `"entry-missing"` — config file exists but had no matching entry
|
|
5101
|
+
*
|
|
5102
|
+
* Set to `null` when `removed` is `true`.
|
|
5103
|
+
*/
|
|
5104
|
+
reason: 'no-mcp-capability' | 'no-config-path' | 'file-missing' | 'entry-missing' | null;
|
|
5105
|
+
}
|
|
5106
|
+
/**
|
|
5107
|
+
* Remove an MCP server entry from a single provider's config file.
|
|
5108
|
+
*
|
|
5109
|
+
* @remarks
|
|
5110
|
+
* Idempotent: when the entry is not present (or the file is missing
|
|
5111
|
+
* entirely) the call returns `removed: false` with a structured
|
|
5112
|
+
* `reason` rather than throwing.
|
|
5113
|
+
*
|
|
5114
|
+
* @param provider - Provider whose config file to modify.
|
|
5115
|
+
* @param serverName - Server name/key to remove.
|
|
5116
|
+
* @param opts - Removal options.
|
|
5117
|
+
* @returns Structured result describing whether the entry was removed.
|
|
5118
|
+
*
|
|
5119
|
+
* @public
|
|
5120
|
+
*/
|
|
5121
|
+
declare function removeMcpServer(provider: Provider, serverName: string, opts: RemoveMcpServerOptions): Promise<RemoveMcpServerResult>;
|
|
5122
|
+
/**
|
|
5123
|
+
* Remove an MCP server entry from every MCP-capable provider in the
|
|
5124
|
+
* registry that currently has it configured.
|
|
5125
|
+
*
|
|
5126
|
+
* @remarks
|
|
5127
|
+
* Iterates {@link getAllProviders}, calls {@link removeMcpServer} on
|
|
5128
|
+
* each MCP-capable provider, and collects the per-provider results.
|
|
5129
|
+
* Each provider is processed independently — a failure on one does
|
|
5130
|
+
* not abort the others. The result array contains one entry per
|
|
5131
|
+
* MCP-capable provider, even when the entry was not present (so
|
|
5132
|
+
* callers can render a complete report).
|
|
5133
|
+
*
|
|
5134
|
+
* @param serverName - Server name/key to remove from every provider.
|
|
5135
|
+
* @param opts - Removal options applied uniformly to every provider.
|
|
5136
|
+
* @returns Array of per-provider removal results.
|
|
5137
|
+
*
|
|
5138
|
+
* @public
|
|
5139
|
+
*/
|
|
5140
|
+
declare function removeMcpServerFromAll(serverName: string, opts: RemoveMcpServerOptions): Promise<RemoveMcpServerResult[]>;
|
|
5141
|
+
|
|
3575
5142
|
/**
|
|
3576
5143
|
* Scope for path resolution, either global (user home) or project-local.
|
|
3577
5144
|
*
|
|
@@ -6345,4 +7912,4 @@ declare function parseSource(input: string): ParsedSource;
|
|
|
6345
7912
|
*/
|
|
6346
7913
|
declare function isMarketplaceScoped(input: string): boolean;
|
|
6347
7914
|
|
|
6348
|
-
export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, CANONICAL_HOOK_EVENTS, type CaampLockFile, type CanonicalEventDefinition, type CanonicalHookEvent, type ConfigFormat, type CrossProviderMatrix, type CtDispatchMatrix, type CtManifest, type CtManifestSkill, type CtProfileDefinition, type CtSkillEntry, type CtValidationIssue, type CtValidationResult, type DetectionCacheOptions, type DetectionResult, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type GlobalOptions, HOOK_CATEGORIES, type Harness, type HarnessScope, type HookCategory, type HookEvent, type HookHandlerType, type HookMapping, type HookSupportResult, type HookSystemType, type InjectionCheckResult, type InjectionStatus, type InjectionTemplate, type InstructionUpdateSummary, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpConfigFormat, type McpServerConfig, type
|
|
7915
|
+
export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, CANONICAL_HOOK_EVENTS, type CaampLockFile, type CanonicalEventDefinition, type CanonicalHookEvent, type CantProfileCounts, type CantProfileEntry, type CantValidationDiagnostic, type ConfigFormat, type CrossProviderMatrix, type CtDispatchMatrix, type CtManifest, type CtManifestSkill, type CtProfileDefinition, type CtSkillEntry, type CtValidationIssue, type CtValidationResult, DEFAULT_EXCLUSIVITY_MODE, type DetectionCacheOptions, type DetectionResult, EXCLUSIVITY_MODE_ENV_VAR, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type ExclusivityMode, type GlobalOptions, HOOK_CATEGORIES, type Harness, type HarnessScope, type HookCategory, type HookEvent, type HookHandlerType, type HookMapping, type HookSupportResult, type HookSystemType, type InjectionCheckResult, type InjectionStatus, type InjectionTemplate, type InstallMcpServerOptions, type InstallMcpServerResult, type InstructionUpdateSummary, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpConfigFormat, type McpDetectionEntry, type McpScope, type McpServerConfig, type McpServerEntriesByProvider, type McpServerEntry, type McpTransportType, type NormalizedHookEvent, type NormalizedRecommendationCriteria, type ParsedSource, PiHarness, PiRequiredError, type PlatformPaths, type Provider, type ProviderCapabilities, type ProviderHarnessCapability, type ProviderHookProfile, type ProviderHookSummary, type ProviderHooksCapability, type ProviderMcpCapability, type ProviderPriority, type ProviderSkillsCapability, type ProviderSpawnCapability, type ProviderStatus, RECOMMENDATION_ERROR_CODES, type RankedSkillRecommendation, type RecommendSkillsResult, type RecommendationCriteriaInput, type RecommendationErrorCode, type RecommendationOptions, type RecommendationReason, type RecommendationReasonCode, type RecommendationScoreBreakdown, type RecommendationValidationIssue, type RecommendationValidationResult, type RecommendationWeights, type RegistryHarnessKind, type RegistryHookCatalog, type RegistryHookFormat, type RemoveMcpServerOptions, type RemoveMcpServerResult, type ResolveDefaultTargetProvidersOptions, type SkillBatchOperation, type SkillEntry, type SkillInstallResult, type SkillIntegrityResult, type SkillIntegrityStatus, type SkillLibrary, type SkillLibraryDispatchMatrix, type SkillLibraryEntry, type SkillLibraryManifest, type SkillLibraryManifestSkill, type SkillLibraryProfile, type SkillLibraryValidationIssue, type SkillLibraryValidationResult, type SkillMetadata, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SubagentHandle, type SubagentResult, type SubagentTask, type SystemInfo, type TransportType, type ValidateCantProfileResult, type ValidationIssue, type ValidationResult, _resetPlatformPathsCache, buildHookMatrix, buildInjectionContent, buildLibraryFromFiles, buildSkillsMap, catalog, checkAllInjections, checkAllSkillIntegrity, checkAllSkillUpdates, checkInjection, checkSkillIntegrity, checkSkillUpdate, clearRegisteredLibrary, deepMerge, detectAllProviders, detectMcpInstallations, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, formatSkillRecommendations, generateInjectionContent, generateSkillsSection, getAgentsConfigPath, getAgentsHome, getAgentsInstructFile, getAgentsLinksDir, getAgentsMcpDir, getAgentsMcpServersPath, getAgentsSpecDir, getAgentsWikiDir, getAllCanonicalEvents, getAllHarnesses, getAllProviders, getCanonicalEvent, getCanonicalEventsByCategory, getCanonicalSkillsDir, getCommonEvents, getCommonHookEvents, getEffectiveSkillsPaths, getExclusivityMode, getHarnessFor, getHookConfigPath, getHookMappingsVersion, getHookSupport, getHookSystemType, getInstalledProviders, getInstructionFiles, getLockFilePath, getMappedProviderIds, getNestedValue, getPlatformLocations, getPlatformPaths, getPrimaryHarness, getPrimaryProvider, getProjectAgentsDir, getProvider, getProviderCapabilities, getProviderCount, getProviderHookProfile, getProviderOnlyEvents, getProviderSummary, getProvidersByHookEvent, getProvidersByInstructFile, getProvidersByPriority, getProvidersBySkillsPrecedence, getProvidersBySpawnCapability, getProvidersByStatus, getProvidersForEvent, getRegistryVersion, getSpawnCapableProviders, getSupportedEvents, getSystemInfo, getTrackedSkills, getUnsupportedEvents, groupByInstructFile, inject, injectAll, installBatchWithRollback, installMcpServer, installSkill, isCaampOwnedSkill, isExclusivityMode, isMarketplaceScoped, isQuiet, isVerbose, listAllMcpServers, listCanonicalSkills, listMcpServers, loadLibraryFromModule, normalizeRecommendationCriteria, parseInjectionContent, parseSkillFile, parseSource, providerSupports, providerSupportsById, rankSkills, readConfig, recommendSkills, recordSkillInstall, registerSkillLibrary, registerSkillLibraryFromPath, removeConfig, removeInjection, removeMcpServer, removeMcpServerFromAll, removeSkill, removeSkillFromLock, resetDetectionCache, resetExclusivityModeOverride, resolveAlias, resolveDefaultTargetProviders, resolveMcpConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setExclusivityMode, setQuiet, setVerbose, shouldOverrideSkill, supportsHook, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, validateInstructionIntegrity, validateRecommendationCriteria, validateSkill, writeConfig };
|