@pulsemcp/air-adapter-pi 0.7.0

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 ADDED
@@ -0,0 +1,70 @@
1
+ # @pulsemcp/air-adapter-pi
2
+
3
+ AIR adapter extension for the [Pi coding agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) (`pi`). Injects AIR skills into Pi's native skills location and prepares working directories for agent sessions.
4
+
5
+ > **Scope: skills only.** Pi does not ship with pre-baked MCP servers, hooks, references, or plugins, so this adapter translates *only* skills. MCP servers, hooks, and standalone references are intentionally not translated (see [Known gaps](#known-gaps)).
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @pulsemcp/air-adapter-pi
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### With the AIR CLI
16
+
17
+ ```bash
18
+ # Install the adapter globally alongside the CLI
19
+ npm install -g @pulsemcp/air-cli @pulsemcp/air-adapter-pi
20
+
21
+ # Start a Pi session
22
+ air start pi --root web-app
23
+ ```
24
+
25
+ ### Programmatic
26
+
27
+ ```typescript
28
+ import { resolveArtifacts } from "@pulsemcp/air-core";
29
+ import { PiAdapter } from "@pulsemcp/air-adapter-pi";
30
+
31
+ const artifacts = await resolveArtifacts("./air.json");
32
+ const adapter = new PiAdapter();
33
+
34
+ // Prepare a working directory for a Pi session
35
+ const session = await adapter.prepareSession(artifacts, "./my-project", {
36
+ root: artifacts.roots["web-app"],
37
+ });
38
+
39
+ // session.configFiles — [] (Pi discovers skills from the filesystem)
40
+ // session.skillPaths — skill dirs created in .pi/skills/
41
+ // session.hookPaths — [] (Pi is skills-only)
42
+ // session.startCommand — { command: "pi", args: [], cwd: "..." }
43
+ ```
44
+
45
+ ## What `prepareSession()` does
46
+
47
+ 1. **Injects skills** — copies `SKILL.md` files and associated content into `.pi/skills/{name}/`, where Pi auto-discovers them. Any directory containing a `SKILL.md` is treated by Pi as a skill root.
48
+ 2. **Copies references** — attaches a skill's referenced documents into `<skill>/references/`, so they travel with the self-contained skill directory.
49
+ 3. **Reconciles via the manifest** — re-runs remove skills that are no longer activated before injecting the current set, keeping `air clean` and re-`prepare` idempotent.
50
+ 4. **Respects local priority** — if a skill directory already exists in the target, it is not overwritten.
51
+
52
+ No config file is written: Pi loads `.pi/skills/` directly from the filesystem, so `prepareSession()` returns an **empty `configFiles` array**.
53
+
54
+ ## Translation Details
55
+
56
+ | AIR Format | Pi Format |
57
+ |------------|-----------|
58
+ | Skills (`SKILL.md` + content) | `.pi/skills/{name}/` (auto-discovered as a project skill) |
59
+ | Skill-owned references | `.pi/skills/{name}/references/` |
60
+ | Plugin-declared skills | merged into the skill activation set (composition sugar) |
61
+
62
+ ## Known gaps
63
+
64
+ These AIR features are intentionally **not** translated, because Pi is a skills-only target for AIR:
65
+
66
+ - **MCP servers** — Pi does not ship with an AIR-translatable MCP server registry. MCP server entries are ignored; the manifest records `mcpServers: []`.
67
+ - **Hooks** — Pi has no AIR-translatable hook lifecycle. Hook entries are ignored; the manifest records `hooks: []` and `prepareSession()` returns an empty `hookPaths` array.
68
+ - **Standalone references** — only skill-*owned* references are copied (alongside the skill). There is no standalone reference materialization.
69
+ - **Plugins** — honored only as composition sugar: a plugin's declared *skills* are merged into the activation set; its MCP servers and hooks are ignored.
70
+ - **Subagent context** — this adapter does not wire an AIR-driven system-prompt flag, so subagent-root context is returned to the caller via `PreparedSession.subagentContext` rather than passed to the CLI.
@@ -0,0 +1,5 @@
1
+ import type { AirExtension } from "@pulsemcp/air-core";
2
+ export { PiAdapter } from "./pi-adapter.js";
3
+ declare const extension: AirExtension;
4
+ export default extension;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,QAAA,MAAM,SAAS,EAAE,YAGhB,CAAC;AAEF,eAAe,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { PiAdapter } from "./pi-adapter.js";
2
+ export { PiAdapter } from "./pi-adapter.js";
3
+ const extension = {
4
+ name: "pi",
5
+ adapter: new PiAdapter(),
6
+ };
7
+ export default extension;
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,SAAS,GAAiB;IAC9B,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,IAAI,SAAS,EAAE;CACzB,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -0,0 +1,114 @@
1
+ import type { AgentAdapter, AgentSessionConfig, StartCommand, ResolvedArtifacts, RootEntry, PrepareSessionOptions, PreparedSession, CleanSessionOptions, CleanSessionResult, LocalArtifacts } from "@pulsemcp/air-core";
2
+ /**
3
+ * AIR adapter for the Pi coding agent (`pi`, https://www.npmjs.com/package/@earendil-works/pi-coding-agent).
4
+ *
5
+ * Scope: SKILLS ONLY. Pi does not ship with pre-baked MCP servers, hooks,
6
+ * references, or plugins the way a fuller agent runtime might, so this adapter
7
+ * translates only skills. MCP servers, hooks, and standalone references are
8
+ * intentionally not translated — see `generateConfig` and `prepareSession`.
9
+ *
10
+ * Pi auto-discovers project skills from `<cwd>/.pi/skills/`: any directory
11
+ * containing a `SKILL.md` is treated as a skill root (Pi stops recursing into
12
+ * it, so bundled reference files are safe). This adapter materializes activated
13
+ * skills into `.pi/skills/<name>/` — purely filesystem placement, no config
14
+ * file is written or required for Pi to load them.
15
+ */
16
+ export declare class PiAdapter implements AgentAdapter {
17
+ name: string;
18
+ displayName: string;
19
+ isAvailable(): Promise<boolean>;
20
+ /**
21
+ * Translate resolved AIR artifacts into a Pi session config.
22
+ *
23
+ * Skills only: plugin-declared skills are merged into the root's default
24
+ * skills (additive), since AIR plugins are composition sugar. A plugin's
25
+ * MCP servers and hooks are intentionally ignored — Pi is skills-only.
26
+ */
27
+ generateConfig(artifacts: ResolvedArtifacts, root?: RootEntry, _workDir?: string): AgentSessionConfig;
28
+ buildStartCommand(config: AgentSessionConfig): StartCommand;
29
+ /**
30
+ * Prepare a working directory for a Pi session.
31
+ *
32
+ * Injects activated skills + their references into `.pi/skills/<name>/`,
33
+ * reconciling against the per-target manifest so re-runs and `air clean`
34
+ * are idempotent. No config file is written: Pi auto-discovers `.pi/skills/`
35
+ * by walking the filesystem, so there is nothing for AIR's JSON transform
36
+ * pipeline to post-process — `configFiles` is returned empty.
37
+ *
38
+ * Inputs to the skill activation list (root defaults, overrides, subagent
39
+ * roots, plugin-declared skills) are accepted as either qualified (`@scope/id`)
40
+ * or short form; ambiguous short forms are rejected. Filesystem
41
+ * materialization uses shortnames — `.pi/skills/` and the manifest are
42
+ * scope-naive. Two activated qualified IDs that share a shortname hard-fail
43
+ * with a clear "add one to exclude" message.
44
+ *
45
+ * MCP servers, hooks, and standalone references are intentionally NOT
46
+ * translated: Pi is skills-only. The manifest records skills only
47
+ * (`hooks: []`, `mcpServers: []`).
48
+ */
49
+ prepareSession(artifacts: ResolvedArtifacts, targetDir: string, options?: PrepareSessionOptions): Promise<PreparedSession>;
50
+ /**
51
+ * Enumerate skills checked into `<targetDir>/.pi/skills/`. Pi loads these
52
+ * directly from the filesystem regardless of AIR's involvement, so they're
53
+ * always active and must not be overwritten or removed. The TUI uses this
54
+ * list to surface them as read-only entries.
55
+ */
56
+ listLocalArtifacts(targetDir: string): Promise<LocalArtifacts>;
57
+ /**
58
+ * Remove every skill AIR has previously written into `targetDir`.
59
+ *
60
+ * Reads the per-target manifest and deletes each tracked skill directory
61
+ * under `.pi/skills/`. Pi is skills-only, so there are no hooks, MCP servers,
62
+ * or settings files to prune. When skills are cleaned (the only category that
63
+ * can hold entries), the manifest itself is deleted; a partial clean
64
+ * (`keepSkills`) updates the manifest with the kept entries instead.
65
+ *
66
+ * Items in the manifest that no longer exist on disk are silently skipped —
67
+ * the manifest can drift if a user removed files manually between runs.
68
+ */
69
+ cleanSession(targetDir: string, options?: CleanSessionOptions): Promise<CleanSessionResult>;
70
+ /**
71
+ * Resolve subagent roots from the root's default_subagent_roots.
72
+ * IDs are already qualified after composition-time canonicalization.
73
+ */
74
+ private resolveSubagentRoots;
75
+ /**
76
+ * Merge subagent roots' default_skills into the parent's activated skills
77
+ * (union, preserving order with parent first). MCP servers are not merged —
78
+ * Pi is skills-only.
79
+ */
80
+ private mergeSubagentSkills;
81
+ /**
82
+ * Build a system prompt section describing the subagent root dependencies.
83
+ * Skills-scoped: MCP servers are not surfaced because Pi is skills-only.
84
+ */
85
+ private buildSubagentContext;
86
+ /**
87
+ * Resolve a list of activation IDs (each qualified or short) into qualified
88
+ * IDs paired with shortnames suitable for filesystem materialization.
89
+ *
90
+ * Throws on:
91
+ * - unknown IDs (after attempting both qualified and short-form lookup)
92
+ * - ambiguous short references (multiple scopes contribute the shortname)
93
+ * - shortname collisions in the activation set itself (two qualified IDs
94
+ * with the same shortname can't share a single materialization dir)
95
+ */
96
+ private resolveActivations;
97
+ /**
98
+ * Build the warning emitted when a registered skill's `path` does not exist
99
+ * on disk at materialization time. The qualified ID encodes the declaring
100
+ * catalog's scope, so a reviewer can trace the offending entry back to its
101
+ * index file. Materialization is skipped for this skill and the rest of the
102
+ * session proceeds.
103
+ */
104
+ private missingSourceDirMessage;
105
+ private formatPoolKeys;
106
+ /**
107
+ * Copy referenced documents into a references/ subdirectory of the skill.
108
+ * `refIds` are qualified IDs (post-canonicalization). Pi treats the skill
109
+ * directory as a self-contained root, so bundled references travel with it.
110
+ */
111
+ private copyReferences;
112
+ private copyDirRecursive;
113
+ }
114
+ //# sourceMappingURL=pi-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-adapter.d.ts","sourceRoot":"","sources":["../src/pi-adapter.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,SAAS,EAET,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EAEf,MAAM,oBAAoB,CAAC;AAsB5B;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAU,YAAW,YAAY;IAC5C,IAAI,SAAQ;IACZ,WAAW,SAAQ;IAEb,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC;;;;;;OAMG;IACH,cAAc,CACZ,SAAS,EAAE,iBAAiB,EAC5B,IAAI,CAAC,EAAE,SAAS,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,kBAAkB;IA+BrB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY;IAY3D;;;;;;;;;;;;;;;;;;;OAmBG;IACG,cAAc,CAClB,SAAS,EAAE,iBAAiB,EAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,eAAe,CAAC;IAyH3B;;;;;OAKG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAIpE;;;;;;;;;;;OAWG;IACG,YAAY,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC;IAsE9B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAyB5B;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IAgD1B;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,cAAc;IAStB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,gBAAgB;CAYzB"}
@@ -0,0 +1,444 @@
1
+ import { execSync } from "child_process";
2
+ import { existsSync, mkdirSync, readdirSync, copyFileSync, rmSync, statSync, } from "fs";
3
+ import { join, dirname } from "path";
4
+ import { buildManifest, deleteManifest, diffManifest, getManifestPath, loadManifest, writeManifest, parseQualifiedId, resolveReference, } from "@pulsemcp/air-core";
5
+ import { scanLocalSkills } from "./scan-local-skills.js";
6
+ /**
7
+ * AIR adapter for the Pi coding agent (`pi`, https://www.npmjs.com/package/@earendil-works/pi-coding-agent).
8
+ *
9
+ * Scope: SKILLS ONLY. Pi does not ship with pre-baked MCP servers, hooks,
10
+ * references, or plugins the way a fuller agent runtime might, so this adapter
11
+ * translates only skills. MCP servers, hooks, and standalone references are
12
+ * intentionally not translated — see `generateConfig` and `prepareSession`.
13
+ *
14
+ * Pi auto-discovers project skills from `<cwd>/.pi/skills/`: any directory
15
+ * containing a `SKILL.md` is treated as a skill root (Pi stops recursing into
16
+ * it, so bundled reference files are safe). This adapter materializes activated
17
+ * skills into `.pi/skills/<name>/` — purely filesystem placement, no config
18
+ * file is written or required for Pi to load them.
19
+ */
20
+ export class PiAdapter {
21
+ name = "pi";
22
+ displayName = "Pi";
23
+ async isAvailable() {
24
+ try {
25
+ execSync("which pi", { stdio: "pipe" });
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ /**
33
+ * Translate resolved AIR artifacts into a Pi session config.
34
+ *
35
+ * Skills only: plugin-declared skills are merged into the root's default
36
+ * skills (additive), since AIR plugins are composition sugar. A plugin's
37
+ * MCP servers and hooks are intentionally ignored — Pi is skills-only.
38
+ */
39
+ generateConfig(artifacts, root, _workDir) {
40
+ const pluginActivations = root?.default_plugins
41
+ ? this.resolveActivations(artifacts.plugins, root.default_plugins, "plugin")
42
+ : [];
43
+ const plugins = {};
44
+ for (const a of pluginActivations)
45
+ plugins[a.qualified] = artifacts.plugins[a.qualified];
46
+ // Merge plugin-declared skills into root defaults (additive). All incoming
47
+ // IDs are qualified (post-canonicalization at composition time), so we
48
+ // deduplicate on qualified IDs.
49
+ const skillQualSet = new Set(root?.default_skills ?? []);
50
+ for (const plugin of Object.values(plugins)) {
51
+ if (plugin.skills) {
52
+ for (const id of plugin.skills)
53
+ skillQualSet.add(id);
54
+ }
55
+ }
56
+ const skillActivations = this.resolveActivations(artifacts.skills, [...skillQualSet], "skill");
57
+ const skillPaths = skillActivations.map((a) => artifacts.skills[a.qualified].path);
58
+ return {
59
+ agent: "pi",
60
+ skillPaths,
61
+ env: {},
62
+ };
63
+ }
64
+ buildStartCommand(config) {
65
+ // Pi auto-discovers `.pi/skills/` relative to its working directory.
66
+ // Pointing the working directory at the prepared directory loads the
67
+ // injected skills; no extra flags are required.
68
+ return {
69
+ command: "pi",
70
+ args: [],
71
+ env: config.env,
72
+ cwd: config.workDir,
73
+ };
74
+ }
75
+ /**
76
+ * Prepare a working directory for a Pi session.
77
+ *
78
+ * Injects activated skills + their references into `.pi/skills/<name>/`,
79
+ * reconciling against the per-target manifest so re-runs and `air clean`
80
+ * are idempotent. No config file is written: Pi auto-discovers `.pi/skills/`
81
+ * by walking the filesystem, so there is nothing for AIR's JSON transform
82
+ * pipeline to post-process — `configFiles` is returned empty.
83
+ *
84
+ * Inputs to the skill activation list (root defaults, overrides, subagent
85
+ * roots, plugin-declared skills) are accepted as either qualified (`@scope/id`)
86
+ * or short form; ambiguous short forms are rejected. Filesystem
87
+ * materialization uses shortnames — `.pi/skills/` and the manifest are
88
+ * scope-naive. Two activated qualified IDs that share a shortname hard-fail
89
+ * with a clear "add one to exclude" message.
90
+ *
91
+ * MCP servers, hooks, and standalone references are intentionally NOT
92
+ * translated: Pi is skills-only. The manifest records skills only
93
+ * (`hooks: []`, `mcpServers: []`).
94
+ */
95
+ async prepareSession(artifacts, targetDir, options) {
96
+ const root = options?.root;
97
+ const skillPaths = [];
98
+ const prevManifest = loadManifest(targetDir);
99
+ // 1. Resolve which skills to activate (overrides take precedence over root defaults).
100
+ let skillIds = options?.skillOverrides ?? root?.default_skills ?? [];
101
+ // 1b. Merge subagent roots' skills if applicable.
102
+ const subagentRoots = this.resolveSubagentRoots(root, artifacts, options);
103
+ if (subagentRoots.length > 0 && !options?.skillOverrides) {
104
+ skillIds = this.mergeSubagentSkills(subagentRoots, skillIds);
105
+ }
106
+ // 1c. Resolve plugins and merge their declared skills (additive). A plugin's
107
+ // MCP servers and hooks are intentionally ignored — Pi is skills-only.
108
+ const pluginIds = options?.pluginOverrides ?? root?.default_plugins ?? undefined;
109
+ const pluginActivations = pluginIds?.length
110
+ ? this.resolveActivations(artifacts.plugins, pluginIds, "plugin")
111
+ : [];
112
+ const skillSet = new Set(skillIds);
113
+ for (const a of pluginActivations) {
114
+ const plugin = artifacts.plugins[a.qualified];
115
+ if (plugin.skills)
116
+ for (const id of plugin.skills)
117
+ skillSet.add(id);
118
+ }
119
+ skillIds = [...skillSet];
120
+ // 2. Resolve activations: qualified ID + shortname per skill.
121
+ // Throws on unknown IDs, ambiguous shortnames, and shortname collisions.
122
+ const skillActs = this.resolveActivations(artifacts.skills, skillIds, "skill");
123
+ const skillShortIds = skillActs.map((a) => a.short);
124
+ // 3. Reconcile against prior manifest using shortnames — those are the keys
125
+ // used for filesystem materialization and stored in the manifest.
126
+ const diff = diffManifest(prevManifest, {
127
+ skills: skillShortIds,
128
+ hooks: [],
129
+ mcpServers: [],
130
+ });
131
+ for (const staleSkillId of diff.staleSkills) {
132
+ const staleDir = join(targetDir, ".pi", "skills", staleSkillId);
133
+ if (existsSync(staleDir)) {
134
+ rmSync(staleDir, { recursive: true, force: true });
135
+ }
136
+ }
137
+ // 4. Inject skills + references into .pi/skills/<short>/.
138
+ const materializedSkillShortIds = [];
139
+ for (const a of skillActs) {
140
+ const skill = artifacts.skills[a.qualified];
141
+ const skillTargetDir = join(targetDir, ".pi", "skills", a.short);
142
+ if (existsSync(skillTargetDir)) {
143
+ materializedSkillShortIds.push(a.short);
144
+ continue;
145
+ }
146
+ const skillSourceDir = skill.path;
147
+ if (!existsSync(skillSourceDir)) {
148
+ console.warn(this.missingSourceDirMessage("skill", a.qualified, skillSourceDir));
149
+ continue;
150
+ }
151
+ this.copyDirRecursive(skillSourceDir, skillTargetDir);
152
+ skillPaths.push(skillTargetDir);
153
+ materializedSkillShortIds.push(a.short);
154
+ if (skill.references && skill.references.length > 0) {
155
+ this.copyReferences(skill.references, skillTargetDir, artifacts);
156
+ }
157
+ }
158
+ // 5. Persist the updated manifest (shortnames — keyed by filesystem dir).
159
+ // Only record skills that were actually materialized so the manifest
160
+ // does not claim ownership of artifacts AIR skipped (e.g. a missing
161
+ // source dir). Hooks and MCP servers are always empty for Pi.
162
+ writeManifest(buildManifest(targetDir, {
163
+ adapter: this.name,
164
+ skills: materializedSkillShortIds,
165
+ hooks: [],
166
+ mcpServers: [],
167
+ }));
168
+ // 6. Generate ephemeral subagent context for the session. Pi loads skills
169
+ // from the filesystem and has no AIR-driven system-prompt flag wired by
170
+ // this adapter, so subagent context is surfaced to the caller via
171
+ // `subagentContext` rather than the start command.
172
+ let subagentContext;
173
+ if (subagentRoots.length > 0) {
174
+ subagentContext = this.buildSubagentContext(subagentRoots);
175
+ }
176
+ // 7. Build start command (working directory = prepared directory).
177
+ // `root` is passed as `undefined` here on purpose: skill activation
178
+ // (root defaults + overrides + subagent + plugin skills) was already
179
+ // resolved and materialized above, so we only need `generateConfig` for
180
+ // the agent name + env that `buildStartCommand` consumes. Passing `root`
181
+ // would redundantly re-resolve skill paths from defaults alone, ignoring
182
+ // the overrides applied in this call.
183
+ const config = this.generateConfig(artifacts, undefined, targetDir);
184
+ const startCommand = this.buildStartCommand({
185
+ ...config,
186
+ workDir: targetDir,
187
+ });
188
+ return {
189
+ // Empty by design — Pi discovers `.pi/skills/` from the filesystem, so
190
+ // there is no JSON config file for AIR's transform pipeline to process.
191
+ configFiles: [],
192
+ skillPaths,
193
+ // Pi is skills-only: no hooks are ever materialized.
194
+ hookPaths: [],
195
+ startCommand,
196
+ subagentContext,
197
+ };
198
+ }
199
+ /**
200
+ * Enumerate skills checked into `<targetDir>/.pi/skills/`. Pi loads these
201
+ * directly from the filesystem regardless of AIR's involvement, so they're
202
+ * always active and must not be overwritten or removed. The TUI uses this
203
+ * list to surface them as read-only entries.
204
+ */
205
+ async listLocalArtifacts(targetDir) {
206
+ return { skills: scanLocalSkills(targetDir) };
207
+ }
208
+ /**
209
+ * Remove every skill AIR has previously written into `targetDir`.
210
+ *
211
+ * Reads the per-target manifest and deletes each tracked skill directory
212
+ * under `.pi/skills/`. Pi is skills-only, so there are no hooks, MCP servers,
213
+ * or settings files to prune. When skills are cleaned (the only category that
214
+ * can hold entries), the manifest itself is deleted; a partial clean
215
+ * (`keepSkills`) updates the manifest with the kept entries instead.
216
+ *
217
+ * Items in the manifest that no longer exist on disk are silently skipped —
218
+ * the manifest can drift if a user removed files manually between runs.
219
+ */
220
+ async cleanSession(targetDir, options) {
221
+ const dryRun = options?.dryRun ?? false;
222
+ const cleanSkills = !(options?.keepSkills ?? false);
223
+ const cleanHooks = !(options?.keepHooks ?? false);
224
+ const cleanMcpServers = !(options?.keepMcpServers ?? false);
225
+ // Pi only ever tracks skills, but honor the same "full clean" predicate as
226
+ // other adapters so a caller that keeps any category preserves the manifest.
227
+ const fullClean = cleanSkills && cleanHooks && cleanMcpServers;
228
+ const manifestPath = getManifestPath(targetDir);
229
+ const manifestFileExists = existsSync(manifestPath);
230
+ const manifest = loadManifest(targetDir);
231
+ if (!manifest) {
232
+ let corruptManifestRemoved = false;
233
+ if (manifestFileExists && fullClean && !dryRun) {
234
+ corruptManifestRemoved = deleteManifest(targetDir);
235
+ }
236
+ return {
237
+ removedSkills: [],
238
+ removedHooks: [],
239
+ removedMcpServers: [],
240
+ mcpConfigPath: null,
241
+ settingsPath: null,
242
+ manifestPath,
243
+ manifestExisted: manifestFileExists,
244
+ manifestRemoved: corruptManifestRemoved,
245
+ };
246
+ }
247
+ const removedSkills = [];
248
+ if (cleanSkills) {
249
+ for (const id of manifest.skills) {
250
+ const dir = join(targetDir, ".pi", "skills", id);
251
+ if (!existsSync(dir))
252
+ continue;
253
+ if (!dryRun)
254
+ rmSync(dir, { recursive: true, force: true });
255
+ removedSkills.push(id);
256
+ }
257
+ }
258
+ let manifestRemoved = false;
259
+ if (fullClean) {
260
+ if (!dryRun) {
261
+ manifestRemoved = deleteManifest(targetDir);
262
+ }
263
+ else {
264
+ manifestRemoved = manifestFileExists;
265
+ }
266
+ }
267
+ else if (!dryRun) {
268
+ writeManifest(buildManifest(targetDir, {
269
+ adapter: manifest.adapter ?? this.name,
270
+ skills: cleanSkills ? [] : manifest.skills,
271
+ hooks: [],
272
+ mcpServers: [],
273
+ }));
274
+ }
275
+ return {
276
+ removedSkills,
277
+ // Pi is skills-only: hooks and MCP servers are never materialized.
278
+ removedHooks: [],
279
+ removedMcpServers: [],
280
+ mcpConfigPath: null,
281
+ settingsPath: null,
282
+ manifestPath,
283
+ manifestExisted: true,
284
+ manifestRemoved,
285
+ };
286
+ }
287
+ /**
288
+ * Resolve subagent roots from the root's default_subagent_roots.
289
+ * IDs are already qualified after composition-time canonicalization.
290
+ */
291
+ resolveSubagentRoots(root, artifacts, options) {
292
+ if (options?.skipSubagentMerge)
293
+ return [];
294
+ if (!root?.default_subagent_roots?.length)
295
+ return [];
296
+ const resolved = [];
297
+ for (const id of root.default_subagent_roots) {
298
+ const res = resolveReference(artifacts.roots, id, undefined);
299
+ if (res.status === "ok") {
300
+ resolved.push(artifacts.roots[res.qualified]);
301
+ }
302
+ }
303
+ return resolved;
304
+ }
305
+ /**
306
+ * Merge subagent roots' default_skills into the parent's activated skills
307
+ * (union, preserving order with parent first). MCP servers are not merged —
308
+ * Pi is skills-only.
309
+ */
310
+ mergeSubagentSkills(subagentRoots, parentSkillIds) {
311
+ const skillSet = new Set(parentSkillIds);
312
+ for (const sub of subagentRoots) {
313
+ if (sub.default_skills) {
314
+ for (const id of sub.default_skills)
315
+ skillSet.add(id);
316
+ }
317
+ }
318
+ return [...skillSet];
319
+ }
320
+ /**
321
+ * Build a system prompt section describing the subagent root dependencies.
322
+ * Skills-scoped: MCP servers are not surfaced because Pi is skills-only.
323
+ */
324
+ buildSubagentContext(subagentRoots) {
325
+ const lines = [
326
+ "## Subagent Root Dependencies",
327
+ "",
328
+ "This session includes capabilities from the following subagent roots.",
329
+ "Their skills have been merged into your session.",
330
+ "",
331
+ ];
332
+ for (const sub of subagentRoots) {
333
+ lines.push(`### ${sub.display_name || "Subagent"}`);
334
+ lines.push("");
335
+ lines.push(`**Description**: ${sub.description}`);
336
+ if (sub.default_skills?.length) {
337
+ lines.push(`**Skills**: ${sub.default_skills.join(", ")}`);
338
+ }
339
+ if (sub.subdirectory) {
340
+ lines.push(`**Subdirectory**: ${sub.subdirectory}`);
341
+ }
342
+ lines.push("");
343
+ }
344
+ return lines.join("\n");
345
+ }
346
+ /**
347
+ * Resolve a list of activation IDs (each qualified or short) into qualified
348
+ * IDs paired with shortnames suitable for filesystem materialization.
349
+ *
350
+ * Throws on:
351
+ * - unknown IDs (after attempting both qualified and short-form lookup)
352
+ * - ambiguous short references (multiple scopes contribute the shortname)
353
+ * - shortname collisions in the activation set itself (two qualified IDs
354
+ * with the same shortname can't share a single materialization dir)
355
+ */
356
+ resolveActivations(pool, ids, artifactType) {
357
+ const acts = [];
358
+ const errors = [];
359
+ const shortToQualified = new Map();
360
+ for (const id of ids) {
361
+ const res = resolveReference(pool, id, undefined);
362
+ if (res.status === "missing") {
363
+ errors.push(`Unknown ${artifactType} ID "${id}". Available: ${this.formatPoolKeys(pool)}.`);
364
+ continue;
365
+ }
366
+ if (res.status === "ambiguous") {
367
+ errors.push(`${artifactType} reference "${id}" is ambiguous — candidates: ` +
368
+ `${res.candidates.join(", ")}. Use the qualified form to disambiguate.`);
369
+ continue;
370
+ }
371
+ const qualified = res.qualified;
372
+ const { id: short } = parseQualifiedId(qualified);
373
+ const prior = shortToQualified.get(short);
374
+ if (prior !== undefined && prior !== qualified) {
375
+ errors.push(`${artifactType} shortname collision: both "${prior}" and "${qualified}" ` +
376
+ `are activated and would write to the same target name "${short}". ` +
377
+ `Add one to air.json#exclude or activate only one of them.`);
378
+ continue;
379
+ }
380
+ if (prior === qualified)
381
+ continue; // dedup
382
+ shortToQualified.set(short, qualified);
383
+ acts.push({ qualified, short });
384
+ }
385
+ if (errors.length > 0) {
386
+ throw new Error(errors.length === 1 ? errors[0] : `Activation errors:\n - ${errors.join("\n - ")}`);
387
+ }
388
+ return acts;
389
+ }
390
+ /**
391
+ * Build the warning emitted when a registered skill's `path` does not exist
392
+ * on disk at materialization time. The qualified ID encodes the declaring
393
+ * catalog's scope, so a reviewer can trace the offending entry back to its
394
+ * index file. Materialization is skipped for this skill and the rest of the
395
+ * session proceeds.
396
+ */
397
+ missingSourceDirMessage(artifactType, qualified, resolvedPath) {
398
+ return (`warning: ${artifactType} "${qualified}" declares path "${resolvedPath}" but that directory does not exist — skipping. ` +
399
+ `The catalog that contributed "${qualified}" registered a path AIR cannot materialize. ` +
400
+ `Fix the \`path\` field in the catalog's index file (or exclude the artifact in air.json) to restore the ${artifactType}.`);
401
+ }
402
+ formatPoolKeys(pool) {
403
+ const keys = Object.keys(pool);
404
+ if (keys.length === 0)
405
+ return "(none)";
406
+ if (keys.length > 8) {
407
+ return `${keys.slice(0, 8).join(", ")}, … (${keys.length} total)`;
408
+ }
409
+ return keys.join(", ");
410
+ }
411
+ /**
412
+ * Copy referenced documents into a references/ subdirectory of the skill.
413
+ * `refIds` are qualified IDs (post-canonicalization). Pi treats the skill
414
+ * directory as a self-contained root, so bundled references travel with it.
415
+ */
416
+ copyReferences(refIds, targetDir, artifacts) {
417
+ const refsTargetDir = join(targetDir, "references");
418
+ for (const refId of refIds) {
419
+ const ref = artifacts.references[refId];
420
+ if (!ref)
421
+ continue;
422
+ const refSourcePath = ref.path;
423
+ if (existsSync(refSourcePath)) {
424
+ const refTargetPath = join(refsTargetDir, ref.path.split("/").pop() || ref.path);
425
+ mkdirSync(dirname(refTargetPath), { recursive: true });
426
+ copyFileSync(refSourcePath, refTargetPath);
427
+ }
428
+ }
429
+ }
430
+ copyDirRecursive(src, dest) {
431
+ mkdirSync(dest, { recursive: true });
432
+ for (const entry of readdirSync(src)) {
433
+ const srcPath = join(src, entry);
434
+ const destPath = join(dest, entry);
435
+ if (statSync(srcPath).isDirectory()) {
436
+ this.copyDirRecursive(srcPath, destPath);
437
+ }
438
+ else {
439
+ copyFileSync(srcPath, destPath);
440
+ }
441
+ }
442
+ }
443
+ }
444
+ //# sourceMappingURL=pi-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-adapter.js","sourceRoot":"","sources":["../src/pi-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { LocalSkillEntry } from "@pulsemcp/air-core";
2
+ /**
3
+ * Scan `<targetDir>/.pi/skills/` for user-managed skills and return one entry
4
+ * per directory containing a `SKILL.md`. Pi auto-discovers project skills from
5
+ * `.pi/skills/` (a directory containing `SKILL.md` is treated as a skill root),
6
+ * so these are always active regardless of AIR's involvement — the TUI surfaces
7
+ * them as read-only entries. Missing or unreadable directories yield an empty
8
+ * list — this is a best-effort informational scan, not validation.
9
+ */
10
+ export declare function scanLocalSkills(targetDir: string): LocalSkillEntry[];
11
+ //# sourceMappingURL=scan-local-skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-local-skills.d.ts","sourceRoot":"","sources":["../src/scan-local-skills.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CA2CpE"}
@@ -0,0 +1,92 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "fs";
2
+ import { join } from "path";
3
+ /**
4
+ * Scan `<targetDir>/.pi/skills/` for user-managed skills and return one entry
5
+ * per directory containing a `SKILL.md`. Pi auto-discovers project skills from
6
+ * `.pi/skills/` (a directory containing `SKILL.md` is treated as a skill root),
7
+ * so these are always active regardless of AIR's involvement — the TUI surfaces
8
+ * them as read-only entries. Missing or unreadable directories yield an empty
9
+ * list — this is a best-effort informational scan, not validation.
10
+ */
11
+ export function scanLocalSkills(targetDir) {
12
+ const skillsDir = join(targetDir, ".pi", "skills");
13
+ if (!existsSync(skillsDir))
14
+ return [];
15
+ let entries;
16
+ try {
17
+ entries = readdirSync(skillsDir);
18
+ }
19
+ catch {
20
+ return [];
21
+ }
22
+ const skills = [];
23
+ for (const name of entries) {
24
+ if (name.startsWith("."))
25
+ continue;
26
+ const skillDir = join(skillsDir, name);
27
+ let isDir = false;
28
+ try {
29
+ isDir = statSync(skillDir).isDirectory();
30
+ }
31
+ catch {
32
+ continue;
33
+ }
34
+ if (!isDir)
35
+ continue;
36
+ const skillMdPath = join(skillDir, "SKILL.md");
37
+ if (!existsSync(skillMdPath))
38
+ continue;
39
+ const frontmatter = readFrontmatter(skillMdPath);
40
+ const description = pickString(frontmatter, "description") ?? "(local skill — no description)";
41
+ const title = pickString(frontmatter, "title") ?? pickString(frontmatter, "name");
42
+ skills.push({
43
+ id: name,
44
+ description,
45
+ title,
46
+ path: skillDir,
47
+ });
48
+ }
49
+ skills.sort((a, b) => a.id.localeCompare(b.id));
50
+ return skills;
51
+ }
52
+ /**
53
+ * Minimal YAML frontmatter reader — parses a leading block delimited by
54
+ * `---` lines into a flat key/value map. Only handles top-level
55
+ * `key: value` scalars, which is all SKILL.md frontmatter needs in
56
+ * practice. Unquoted values have surrounding whitespace trimmed and
57
+ * matching single/double quotes stripped.
58
+ */
59
+ function readFrontmatter(path) {
60
+ let content;
61
+ try {
62
+ content = readFileSync(path, "utf-8");
63
+ }
64
+ catch {
65
+ return {};
66
+ }
67
+ const lines = content.split(/\r?\n/);
68
+ if (lines[0]?.trim() !== "---")
69
+ return {};
70
+ const result = {};
71
+ for (let i = 1; i < lines.length; i++) {
72
+ const line = lines[i];
73
+ if (line.trim() === "---")
74
+ return result;
75
+ const match = line.match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);
76
+ if (!match)
77
+ continue;
78
+ const key = match[1];
79
+ let value = match[2].trim();
80
+ if ((value.startsWith('"') && value.endsWith('"')) ||
81
+ (value.startsWith("'") && value.endsWith("'"))) {
82
+ value = value.slice(1, -1);
83
+ }
84
+ result[key] = value;
85
+ }
86
+ return result;
87
+ }
88
+ function pickString(obj, key) {
89
+ const v = obj[key];
90
+ return typeof v === "string" && v.length > 0 ? v : undefined;
91
+ }
92
+ //# sourceMappingURL=scan-local-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-local-skills.js","sourceRoot":"","sources":["../src/scan-local-skills.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@pulsemcp/air-adapter-pi",
3
+ "version": "0.7.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/pulsemcp/air.git",
10
+ "directory": "packages/extensions/adapter-pi"
11
+ },
12
+ "description": "AIR adapter for the Pi coding agent — injects AIR skills into Pi's native skills location",
13
+ "type": "module",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist/"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "lint": "tsc --noEmit"
30
+ },
31
+ "dependencies": {
32
+ "@pulsemcp/air-core": "0.7.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.10.0",
36
+ "typescript": "^5.7.0",
37
+ "vitest": "^2.1.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ }
42
+ }