@cleocode/caamp 2026.4.7 → 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/dist/index.d.ts CHANGED
@@ -1487,252 +1487,6 @@ interface InstructionUpdateSummary {
1487
1487
  */
1488
1488
  declare function updateInstructionsSingleOperation(providers: Provider[], content: string, scope?: Scope, projectDir?: string): Promise<InstructionUpdateSummary>;
1489
1489
 
1490
- /**
1491
- * Format utility functions
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)
1502
- *
1503
- * @remarks
1504
- * Only plain objects are recursively merged. Arrays and primitive values from
1505
- * `source` replace `target` values outright. Neither input is mutated.
1506
- *
1507
- * @example
1508
- * ```typescript
1509
- * const merged = deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
1510
- * // { a: 1, b: { c: 2, d: 3 } }
1511
- * ```
1512
- *
1513
- * @public
1514
- */
1515
- declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
1516
- /**
1517
- * Get a nested value from an object using a dot-notation key path.
1518
- *
1519
- * @param obj - Object to traverse
1520
- * @param keyPath - Dot-separated key path (e.g. `"mcpServers"` or `"a.b.c"`)
1521
- * @returns The value at the key path, or `undefined` if not found
1522
- *
1523
- * @remarks
1524
- * Splits the key path on `.` and walks the object tree. Returns `undefined`
1525
- * at the first missing or non-object segment.
1526
- *
1527
- * @example
1528
- * ```typescript
1529
- * getNestedValue({ a: { b: { c: 42 } } }, "a.b.c"); // 42
1530
- * getNestedValue({ a: 1 }, "a.b"); // undefined
1531
- * ```
1532
- *
1533
- * @public
1534
- */
1535
- declare function getNestedValue(obj: Record<string, unknown>, keyPath: string): unknown;
1536
- /**
1537
- * Ensure that the parent directories of a file path exist.
1538
- *
1539
- * Creates directories recursively if they do not exist.
1540
- *
1541
- * @param filePath - Absolute path to a file (parent directories will be created)
1542
- *
1543
- * @remarks
1544
- * Uses `mkdir` with `recursive: true` so existing directories are not an error.
1545
- *
1546
- * @example
1547
- * ```typescript
1548
- * await ensureDir("/path/to/new/dir/file.json");
1549
- * // /path/to/new/dir/ now exists
1550
- * ```
1551
- *
1552
- * @public
1553
- */
1554
- declare function ensureDir(filePath: string): Promise<void>;
1555
-
1556
- /**
1557
- * Provides format-agnostic config read, write, and remove operations that
1558
- * dispatch to JSON/JSONC, YAML, or TOML handlers based on the specified
1559
- * format.
1560
- *
1561
- * @packageDocumentation
1562
- */
1563
-
1564
- /**
1565
- * Read and parse a config file in the specified format.
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
1573
- *
1574
- * @remarks
1575
- * Supported formats: `"json"`, `"jsonc"`, `"yaml"`, `"toml"`. Throws for
1576
- * any unrecognized format string.
1577
- *
1578
- * @example
1579
- * ```typescript
1580
- * const config = await readConfig("/path/to/config.json", "jsonc");
1581
- * ```
1582
- *
1583
- * @public
1584
- */
1585
- declare function readConfig(filePath: string, format: ConfigFormat): Promise<Record<string, unknown>>;
1586
- /**
1587
- * Write a server entry to a config file, preserving existing content.
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
1598
- *
1599
- * @remarks
1600
- * For JSONC files, comments and formatting are preserved using `jsonc-parser`.
1601
- * For YAML and TOML, the file is fully re-serialized after deep-merging.
1602
- *
1603
- * @example
1604
- * ```typescript
1605
- * await writeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server", config);
1606
- * ```
1607
- *
1608
- * @public
1609
- */
1610
- declare function writeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string, serverConfig: unknown): Promise<void>;
1611
- /**
1612
- * Remove a server entry from a config file in the specified format.
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
1620
- *
1621
- * @remarks
1622
- * Delegates to the format-specific removal function. Returns `false` when the
1623
- * file does not exist or the entry is not found.
1624
- *
1625
- * @example
1626
- * ```typescript
1627
- * const removed = await removeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server");
1628
- * ```
1629
- *
1630
- * @public
1631
- */
1632
- declare function removeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string): Promise<boolean>;
1633
-
1634
- /**
1635
- * Skill installer - canonical + symlink model
1636
- *
1637
- * Skills are stored once in a canonical location (.agents/skills/<name>/)
1638
- * and symlinked to each target agent's skills directory.
1639
- */
1640
-
1641
- /**
1642
- * Result of installing a skill to the canonical location and linking to agents.
1643
- *
1644
- * @example
1645
- * ```typescript
1646
- * const result = await installSkill(sourcePath, "my-skill", providers, true);
1647
- * if (result.success) {
1648
- * console.log(`Installed to ${result.canonicalPath}`);
1649
- * console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
1650
- * }
1651
- * ```
1652
- *
1653
- * @public
1654
- */
1655
- interface SkillInstallResult {
1656
- /** Skill name. */
1657
- name: string;
1658
- /** Absolute path to the canonical installation directory. */
1659
- canonicalPath: string;
1660
- /** Provider IDs that were successfully linked. */
1661
- linkedAgents: string[];
1662
- /** Error messages from failed link operations. */
1663
- errors: string[];
1664
- /** Whether at least one agent was successfully linked. */
1665
- success: boolean;
1666
- }
1667
- /**
1668
- * Install a skill from a local path to the canonical location and link to agents.
1669
- *
1670
- * @remarks
1671
- * Copies the skill directory to the canonical skills directory and creates symlinks
1672
- * (or copies on Windows) from each provider's skills directory to the canonical path.
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
1680
- *
1681
- * @example
1682
- * ```typescript
1683
- * const result = await installSkill("/tmp/my-skill", "my-skill", providers, true, "/my/project");
1684
- * if (result.success) {
1685
- * console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
1686
- * }
1687
- * ```
1688
- *
1689
- * @public
1690
- */
1691
- declare function installSkill(sourcePath: string, skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string): Promise<SkillInstallResult>;
1692
- /**
1693
- * Remove a skill from the canonical location and all agent symlinks.
1694
- *
1695
- * @remarks
1696
- * Removes symlinks from each provider's skills directory and then removes the
1697
- * canonical copy from the centralized canonical skills directory.
1698
- *
1699
- * @param skillName - Name of the skill to remove
1700
- * @param providers - Providers to unlink the skill from
1701
- * @param isGlobal - Whether to target global or project skill directories
1702
- * @param projectDir - Project directory (defaults to `process.cwd()`)
1703
- * @returns Object with arrays of successfully removed provider IDs and error messages
1704
- *
1705
- * @example
1706
- * ```typescript
1707
- * const { removed, errors } = await removeSkill("my-skill", providers, true, "/my/project");
1708
- * console.log(`Removed from: ${removed.join(", ")}`);
1709
- * ```
1710
- *
1711
- * @public
1712
- */
1713
- declare function removeSkill(skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string): Promise<{
1714
- removed: string[];
1715
- errors: string[];
1716
- }>;
1717
- /**
1718
- * List all skills installed in the canonical skills directory.
1719
- *
1720
- * @remarks
1721
- * Returns the directory names of all skills, which correspond to skill names.
1722
- * Includes both regular directories and symlinks in the canonical location.
1723
- *
1724
- * @returns Array of skill names
1725
- *
1726
- * @example
1727
- * ```typescript
1728
- * const skills = await listCanonicalSkills();
1729
- * // ["my-skill", "another-skill"]
1730
- * ```
1731
- *
1732
- * @public
1733
- */
1734
- declare function listCanonicalSkills(): Promise<string[]>;
1735
-
1736
1490
  /**
1737
1491
  * Three-tier scope helper for Pi harness operations.
1738
1492
  *
@@ -1816,6 +1570,72 @@ type HarnessScope = {
1816
1570
  kind: 'project';
1817
1571
  projectDir: string;
1818
1572
  };
1573
+ /**
1574
+ * Options accepted by `resolveDefaultTargetProviders` (defined in
1575
+ * `./index.ts`).
1576
+ *
1577
+ * @remarks
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.
1581
+ *
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.
1585
+ *
1586
+ * @public
1587
+ */
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
+ }
1608
+ /**
1609
+ * Controls how `resolveDefaultTargetProviders` (defined in `./index.ts`)
1610
+ * selects target providers at runtime invocation time.
1611
+ *
1612
+ * @remarks
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.
1616
+ *
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.
1635
+ *
1636
+ * @public
1637
+ */
1638
+ type ExclusivityMode = 'auto' | 'force-pi' | 'legacy';
1819
1639
  /**
1820
1640
  * Metadata describing a Pi extension discovered on disk.
1821
1641
  *
@@ -1896,6 +1716,121 @@ interface HarnessInstallOptions {
1896
1716
  */
1897
1717
  force?: boolean;
1898
1718
  }
1719
+ /**
1720
+ * Counts of top-level CANT sections discovered in a `.cant` file.
1721
+ *
1722
+ * @remarks
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.
1728
+ *
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.
1736
+ *
1737
+ * @public
1738
+ */
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
+ }
1758
+ /**
1759
+ * Metadata describing a `.cant` profile installed at one of the three
1760
+ * Pi harness tiers.
1761
+ *
1762
+ * @remarks
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.
1768
+ *
1769
+ * @public
1770
+ */
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
+ }
1788
+ /**
1789
+ * Diagnostic emitted by the cant-core 42-rule validator, normalised to
1790
+ * the harness layer's vocabulary.
1791
+ *
1792
+ * @remarks
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.
1797
+ *
1798
+ * @public
1799
+ */
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
+ }
1812
+ /**
1813
+ * Result of validating a `.cant` profile via the cant-core 42-rule
1814
+ * engine.
1815
+ *
1816
+ * @remarks
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.
1823
+ *
1824
+ * @public
1825
+ */
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
+ }
1899
1834
  /**
1900
1835
  * Summary header extracted from the first line of a Pi session JSONL file.
1901
1836
  *
@@ -2058,6 +1993,12 @@ interface ModelListEntry {
2058
1993
  * is a routing hint passed to the harness; concrete harnesses may use it
2059
1994
  * to select an inner agent or simply record it for observability.
2060
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
+ *
2061
2002
  * @public
2062
2003
  */
2063
2004
  interface SubagentTask {
@@ -2065,6 +2006,42 @@ interface SubagentTask {
2065
2006
  targetProviderId: string;
2066
2007
  /** The prompt / instruction to give the spawned agent. */
2067
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;
2068
2045
  /**
2069
2046
  * Working directory for the spawned agent.
2070
2047
  * @defaultValue undefined
@@ -2076,18 +2053,136 @@ interface SubagentTask {
2076
2053
  */
2077
2054
  env?: Record<string, string>;
2078
2055
  /**
2079
- * 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.
2080
2058
  * @defaultValue undefined
2081
2059
  */
2082
2060
  signal?: AbortSignal;
2083
2061
  }
2084
2062
  /**
2085
- * Final result of a subagent's execution.
2063
+ * Per-call options that override harness-wide spawn defaults.
2064
+ *
2065
+ * @remarks
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).
2086
2179
  *
2087
2180
  * @remarks
2088
- * Collected once the child process exits. {@link parsed} is populated
2089
- * on a best-effort basis: if the subagent emits JSON on stdout the
2090
- * harness will parse it, otherwise {@link parsed} is left undefined.
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.
2091
2186
  *
2092
2187
  * @public
2093
2188
  */
@@ -2110,18 +2205,87 @@ interface SubagentResult {
2110
2205
  *
2111
2206
  * @remarks
2112
2207
  * Returned synchronously from {@link Harness.spawnSubagent}. The caller
2113
- * may await {@link result} to collect the final output, or invoke
2114
- * {@link abort} to terminate the child early.
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.
2115
2220
  *
2116
2221
  * @public
2117
2222
  */
2118
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;
2119
2238
  /** PID of the spawned process, or `null` if spawning did not yield one. */
2120
2239
  pid: number | null;
2121
- /** Promise resolving to the subagent's final output once the process exits. */
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
+ */
2122
2258
  result: Promise<SubagentResult>;
2123
- /** Synchronously terminate the subagent. Safe to call after exit. */
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
+ */
2124
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[];
2125
2289
  }
2126
2290
  /**
2127
2291
  * Contract every first-class harness must implement.
@@ -2209,16 +2373,25 @@ interface Harness {
2209
2373
  * @remarks
2210
2374
  * For Pi: invokes `child_process.spawn` with the provider's configured
2211
2375
  * `capabilities.spawn.spawnCommand`, appending the task prompt as a
2212
- * trailing positional argument. The returned handle lets the caller await
2213
- * completion or abort early.
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.
2214
2386
  *
2215
2387
  * Optional — harnesses that cannot spawn other agents should omit this
2216
2388
  * method. Callers MUST feature-check before invoking.
2217
2389
  *
2218
2390
  * @param task - Subagent task specification.
2391
+ * @param opts - Per-call streaming and cleanup overrides.
2219
2392
  * @returns A live subagent handle.
2220
2393
  */
2221
- spawnSubagent?(task: SubagentTask): Promise<SubagentHandle>;
2394
+ spawnSubagent?(task: SubagentTask, opts?: SubagentSpawnOptions): Promise<SubagentHandle>;
2222
2395
  /**
2223
2396
  * Configure which models are available in the harness's model picker.
2224
2397
  *
@@ -2392,7 +2565,497 @@ interface Harness {
2392
2565
  listThemes?(projectDir?: string): Promise<ThemeEntry[]>;
2393
2566
  /** Remove a Pi theme by name from the given tier. */
2394
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);
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;
2395
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[]>;
2396
3059
 
2397
3060
  /**
2398
3061
  * Pi coding agent harness.
@@ -2470,19 +3133,118 @@ declare class PiHarness implements Harness {
2470
3133
  /** {@inheritDoc Harness.removeInstructions} */
2471
3134
  removeInstructions(scope: HarnessScope): Promise<void>;
2472
3135
  /**
2473
- * {@inheritDoc Harness.spawnSubagent}
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.
3209
+ *
3210
+ * @remarks
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).
3220
+ */
3221
+ static raceSubagents(handles: SubagentHandle[]): Promise<SubagentExitResult>;
3222
+ /**
3223
+ * Settle a set of subagent handles, returning a parallel array of
3224
+ * results.
2474
3225
  *
2475
3226
  * @remarks
2476
- * Invokes Pi's configured `spawnCommand` (e.g.
2477
- * `["pi", "--mode", "json", "-p", "--no-session"]`) with the task prompt
2478
- * appended as the trailing positional argument. The {@link SubagentTask.targetProviderId}
2479
- * is a routing hint carried in the prompt stream; Pi's own extension
2480
- * layer dispatches to the correct inner agent.
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.
2481
3240
  *
2482
- * Throws immediately when the provider entry is missing a `spawnCommand`
2483
- * so callers see configuration errors early rather than at child-exit time.
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).
2484
3246
  */
2485
- spawnSubagent(task: SubagentTask): Promise<SubagentHandle>;
3247
+ private handleStdoutLine;
2486
3248
  /** {@inheritDoc Harness.readSettings} */
2487
3249
  readSettings(scope: HarnessScope): Promise<unknown>;
2488
3250
  /** {@inheritDoc Harness.writeSettings} */
@@ -2543,6 +3305,47 @@ declare class PiHarness implements Harness {
2543
3305
  listThemes(projectDir?: string): Promise<ThemeEntry[]>;
2544
3306
  /** {@inheritDoc Harness.removeTheme} */
2545
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>;
2546
3349
  }
2547
3350
 
2548
3351
  /**
@@ -2624,42 +3427,52 @@ declare function getPrimaryHarness(): Harness | null;
2624
3427
  declare function getAllHarnesses(): Harness[];
2625
3428
  /**
2626
3429
  * Resolve the default set of target providers when the user has not passed
2627
- * `--agent`.
3430
+ * `--agent`, honouring the active {@link ExclusivityMode}.
2628
3431
  *
2629
3432
  * @remarks
2630
- * Resolution policy:
3433
+ * Resolution policy is layered. The active {@link ExclusivityMode} (read
3434
+ * via {@link getExclusivityMode}) selects which branch of the matrix runs:
2631
3435
  *
2632
- * 1. If the registry's primary harness (the provider with
2633
- * `priority === "primary"`) is installed on the current system,
2634
- * return `[primaryProvider]` so that commands dispatch to the
2635
- * primary harness by default.
2636
- * 2. Otherwise, return the set of installed providers at priority
2637
- * `"primary"` or `"high"`. This restores the legacy "detected high-tier
2638
- * providers" fallback that CAAMP has always used when no primary
2639
- * harness is available.
2640
- * 3. If the priority filter yields an empty list (e.g. in tests that stub
2641
- * providers without a `priority` field, or in fresh installs with only
2642
- * medium/low-tier providers detected), fall back to the full installed
2643
- * provider list so that commands retain a valid target.
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. |
2644
3441
  *
2645
- * This helper is intentionally defensive: it swallows registry-related
2646
- * exceptions (returning an empty-primary-harness result) so stubbed test
2647
- * environments that do not wire the full provider registry still behave
2648
- * sensibly.
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.
2649
3449
  *
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.
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.
2650
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.
2651
3460
  *
2652
3461
  * @example
2653
3462
  * ```typescript
3463
+ * // Implicit default — used by `caamp skills list` and friends.
2654
3464
  * const targets = resolveDefaultTargetProviders();
2655
- * if (targets.length === 0) {
2656
- * console.error("No target providers found. Use --agent or --all.");
2657
- * }
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
+ * });
2658
3471
  * ```
2659
3472
  *
2660
3473
  * @public
2661
3474
  */
2662
- declare function resolveDefaultTargetProviders(): Provider[];
3475
+ declare function resolveDefaultTargetProviders(options?: ResolveDefaultTargetProvidersOptions): Provider[];
2663
3476
 
2664
3477
  /**
2665
3478
  * All hook event categories (8 total).
@@ -7099,4 +7912,4 @@ declare function parseSource(input: string): ParsedSource;
7099
7912
  */
7100
7913
  declare function isMarketplaceScoped(input: string): boolean;
7101
7914
 
7102
- 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 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, 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 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 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, 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, 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, resolveAlias, resolveDefaultTargetProviders, resolveMcpConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setQuiet, setVerbose, shouldOverrideSkill, supportsHook, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, validateInstructionIntegrity, validateRecommendationCriteria, validateSkill, writeConfig };
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 };