@pulsemcp/air-sdk 0.0.3

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.
@@ -0,0 +1,11 @@
1
+ import type { AgentAdapter } from "@pulsemcp/air-core";
2
+ /**
3
+ * Find an adapter by agent name.
4
+ * Returns null if the adapter package isn't installed.
5
+ */
6
+ export declare function findAdapter(name: string): Promise<AgentAdapter | null>;
7
+ /**
8
+ * List all available adapter names (installed packages only).
9
+ */
10
+ export declare function listAvailableAdapters(): Promise<string[]>;
11
+ //# sourceMappingURL=adapter-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.d.ts","sourceRoot":"","sources":["../src/adapter-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,oBAAoB,CAAC;AAUrE;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAsB9B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAW/D"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Known adapter packages. The SDK tries to dynamically import each one.
3
+ * If the package is installed, its adapter is available. If not, it's skipped.
4
+ */
5
+ const KNOWN_ADAPTERS = [
6
+ { name: "claude", packageName: "@pulsemcp/air-adapter-claude" },
7
+ ];
8
+ /**
9
+ * Find an adapter by agent name.
10
+ * Returns null if the adapter package isn't installed.
11
+ */
12
+ export async function findAdapter(name) {
13
+ // Check known adapters first
14
+ for (const known of KNOWN_ADAPTERS) {
15
+ if (known.name === name) {
16
+ try {
17
+ const mod = await import(known.packageName);
18
+ const ext = mod.default;
19
+ return ext?.adapter ?? null;
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ }
26
+ // Try convention-based package name: @pulsemcp/air-adapter-{name}
27
+ try {
28
+ const mod = await import(`@pulsemcp/air-adapter-${name}`);
29
+ const ext = mod.default;
30
+ return ext?.adapter ?? null;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * List all available adapter names (installed packages only).
38
+ */
39
+ export async function listAvailableAdapters() {
40
+ const available = [];
41
+ for (const known of KNOWN_ADAPTERS) {
42
+ try {
43
+ await import(known.packageName);
44
+ available.push(known.name);
45
+ }
46
+ catch {
47
+ // Not installed
48
+ }
49
+ }
50
+ return available;
51
+ }
52
+ //# sourceMappingURL=adapter-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.js","sourceRoot":"","sources":["../src/adapter-registry.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,cAAc,GAA4C;IAC9D,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8BAA8B,EAAE;CAChE,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY;IAEZ,6BAA6B;IAC7B,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;gBAC5C,MAAM,GAAG,GAAG,GAAG,CAAC,OAAmC,CAAC;gBACpD,OAAO,GAAG,EAAE,OAAO,IAAI,IAAI,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,OAAmC,CAAC;QACpD,OAAO,GAAG,EAAE,OAAO,IAAI,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAChC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,15 @@
1
+ export { loadAirConfig, getDefaultAirJsonPath, getAirJsonPath, resolveArtifacts, mergeArtifacts, emptyArtifacts, validateJson, getSchemasDir, getSchemaPath, loadSchema, detectSchemaType, detectSchemaFromValue, getAllSchemaTypes, isValidSchemaType, } from "@pulsemcp/air-core";
2
+ export type { AirConfig, ResolvedArtifacts, SkillEntry, ReferenceEntry, McpOAuthConfig, McpServerEntry, PluginAuthor, PluginEntry, RootEntry, HookEntry, AgentAdapter, CatalogProvider, SecretResolver, AirExtension, AgentSessionConfig, StartCommand, PrepareSessionOptions as CorePrepareSessionOptions, PreparedSession, ValidationResult, ValidationError, ResolveOptions, SchemaType, } from "@pulsemcp/air-core";
3
+ export { findAdapter, listAvailableAdapters } from "./adapter-registry.js";
4
+ export { normalizeGitUrl, detectRoot } from "./root-detection.js";
5
+ export { validateFile } from "./validate.js";
6
+ export type { ValidateFileOptions, ValidateFileResult } from "./validate.js";
7
+ export { initConfig } from "./init.js";
8
+ export type { InitConfigOptions, InitConfigResult } from "./init.js";
9
+ export { listArtifacts, VALID_ARTIFACT_TYPES } from "./list.js";
10
+ export type { ArtifactType, ListArtifactsOptions, ListArtifactsResult } from "./list.js";
11
+ export { startSession } from "./start.js";
12
+ export type { StartSessionOptions, StartSessionResult } from "./start.js";
13
+ export { prepareSession } from "./prepare.js";
14
+ export type { PrepareSessionOptions, PrepareSessionResult, } from "./prepare.js";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,cAAc,EAEd,YAAY,EAEZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAEV,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,YAAY,EACZ,WAAW,EACX,SAAS,EACT,SAAS,EAET,YAAY,EACZ,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,qBAAqB,IAAI,yBAAyB,EAClD,eAAe,EAEf,gBAAgB,EAChB,eAAe,EAEf,cAAc,EAEd,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG3E,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAE7E,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEzF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EACV,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // Re-export everything from core for convenience
2
+ export {
3
+ // Config resolution
4
+ loadAirConfig, getDefaultAirJsonPath, getAirJsonPath, resolveArtifacts, mergeArtifacts, emptyArtifacts,
5
+ // Validation
6
+ validateJson,
7
+ // Schemas
8
+ getSchemasDir, getSchemaPath, loadSchema, detectSchemaType, detectSchemaFromValue, getAllSchemaTypes, isValidSchemaType, } from "@pulsemcp/air-core";
9
+ // Adapter registry
10
+ export { findAdapter, listAvailableAdapters } from "./adapter-registry.js";
11
+ // Root detection
12
+ export { normalizeGitUrl, detectRoot } from "./root-detection.js";
13
+ // High-level operations
14
+ export { validateFile } from "./validate.js";
15
+ export { initConfig } from "./init.js";
16
+ export { listArtifacts, VALID_ARTIFACT_TYPES } from "./list.js";
17
+ export { startSession } from "./start.js";
18
+ export { prepareSession } from "./prepare.js";
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,OAAO;AACL,oBAAoB;AACpB,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,cAAc;AACd,aAAa;AACb,YAAY;AACZ,UAAU;AACV,aAAa,EACb,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAiC5B,mBAAmB;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE3E,iBAAiB;AACjB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAElE,wBAAwB;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGhE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
package/dist/init.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ export interface InitConfigOptions {
2
+ /** Override the default air.json path (~/.air/air.json). */
3
+ path?: string;
4
+ }
5
+ export interface InitConfigResult {
6
+ /** Absolute path to the created air.json. */
7
+ airJsonPath: string;
8
+ /** Absolute path to the AIR config directory. */
9
+ airDir: string;
10
+ /** List of files in the config directory (relative to airDir). */
11
+ files: string[];
12
+ }
13
+ /**
14
+ * Initialize a new AIR configuration directory.
15
+ *
16
+ * Creates air.json and empty artifact index files at the specified
17
+ * path (defaults to ~/.air/).
18
+ *
19
+ * @throws Error if air.json already exists at the target path.
20
+ */
21
+ export declare function initConfig(options?: InitConfigOptions): InitConfigResult;
22
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,gBAAgB,CA8CxE"}
package/dist/init.js ADDED
@@ -0,0 +1,50 @@
1
+ import { writeFileSync, existsSync, mkdirSync } from "fs";
2
+ import { resolve, dirname } from "path";
3
+ import { getDefaultAirJsonPath } from "@pulsemcp/air-core";
4
+ /**
5
+ * Initialize a new AIR configuration directory.
6
+ *
7
+ * Creates air.json and empty artifact index files at the specified
8
+ * path (defaults to ~/.air/).
9
+ *
10
+ * @throws Error if air.json already exists at the target path.
11
+ */
12
+ export function initConfig(options) {
13
+ const airJsonPath = options?.path ?? getDefaultAirJsonPath();
14
+ const airDir = dirname(airJsonPath);
15
+ if (existsSync(airJsonPath)) {
16
+ throw new Error(`${airJsonPath} already exists.`);
17
+ }
18
+ mkdirSync(airDir, { recursive: true });
19
+ const airJson = {
20
+ name: "my-config",
21
+ description: "",
22
+ skills: ["./skills/skills.json"],
23
+ references: ["./references/references.json"],
24
+ mcp: ["./mcp/mcp.json"],
25
+ plugins: ["./plugins/plugins.json"],
26
+ roots: ["./roots/roots.json"],
27
+ hooks: ["./hooks/hooks.json"],
28
+ };
29
+ const emptyIndex = () => "{}\n";
30
+ writeFileSync(airJsonPath, JSON.stringify(airJson, null, 2) + "\n");
31
+ const indexFiles = [
32
+ ["skills/skills.json", emptyIndex()],
33
+ ["references/references.json", emptyIndex()],
34
+ ["mcp/mcp.json", emptyIndex()],
35
+ ["plugins/plugins.json", emptyIndex()],
36
+ ["roots/roots.json", emptyIndex()],
37
+ ["hooks/hooks.json", emptyIndex()],
38
+ ];
39
+ const files = ["air.json"];
40
+ for (const [filename, content] of indexFiles) {
41
+ const filePath = resolve(airDir, filename);
42
+ mkdirSync(dirname(filePath), { recursive: true });
43
+ if (!existsSync(filePath)) {
44
+ writeFileSync(filePath, content);
45
+ }
46
+ files.push(filename);
47
+ }
48
+ return { airJsonPath, airDir, files };
49
+ }
50
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAgB3D;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,OAA2B;IACpD,MAAM,WAAW,GAAG,OAAO,EAAE,IAAI,IAAI,qBAAqB,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpC,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,kBAAkB,CAAC,CAAC;IACpD,CAAC;IAED,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,EAAE;QACf,MAAM,EAAE,CAAC,sBAAsB,CAAC;QAChC,UAAU,EAAE,CAAC,8BAA8B,CAAC;QAC5C,GAAG,EAAE,CAAC,gBAAgB,CAAC;QACvB,OAAO,EAAE,CAAC,wBAAwB,CAAC;QACnC,KAAK,EAAE,CAAC,oBAAoB,CAAC;QAC7B,KAAK,EAAE,CAAC,oBAAoB,CAAC;KAC9B,CAAC;IAEF,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;IAEhC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEpE,MAAM,UAAU,GAAuB;QACrC,CAAC,oBAAoB,EAAE,UAAU,EAAE,CAAC;QACpC,CAAC,4BAA4B,EAAE,UAAU,EAAE,CAAC;QAC5C,CAAC,cAAc,EAAE,UAAU,EAAE,CAAC;QAC9B,CAAC,sBAAsB,EAAE,UAAU,EAAE,CAAC;QACtC,CAAC,kBAAkB,EAAE,UAAU,EAAE,CAAC;QAClC,CAAC,kBAAkB,EAAE,UAAU,EAAE,CAAC;KACnC,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC;IAE3B,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,UAAU,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACxC,CAAC"}
package/dist/list.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { type ResolvedArtifacts } from "@pulsemcp/air-core";
2
+ export type ArtifactType = "skills" | "mcp" | "plugins" | "roots" | "hooks" | "references";
3
+ export declare const VALID_ARTIFACT_TYPES: readonly ArtifactType[];
4
+ export interface ListArtifactsOptions {
5
+ /** Path to air.json. Uses AIR_CONFIG env or ~/.air/air.json if not set. */
6
+ config?: string;
7
+ }
8
+ export interface ListArtifactsResult {
9
+ /** The requested artifact type. */
10
+ type: ArtifactType;
11
+ /** Entries of the requested type, keyed by ID. */
12
+ entries: Record<string, unknown>;
13
+ /** The full resolved artifacts (for consumers that need cross-type access). */
14
+ artifacts: ResolvedArtifacts;
15
+ }
16
+ /**
17
+ * Resolve artifacts and return the entries for a specific artifact type.
18
+ *
19
+ * @throws Error if the artifact type is invalid.
20
+ */
21
+ export declare function listArtifacts(type: string, options?: ListArtifactsOptions): Promise<ListArtifactsResult>;
22
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,KAAK,GACL,SAAS,GACT,OAAO,GACP,OAAO,GACP,YAAY,CAAC;AAEjB,eAAO,MAAM,oBAAoB,EAAE,SAAS,YAAY,EAO9C,CAAC;AAEX,MAAM,WAAW,oBAAoB;IACnC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,mCAAmC;IACnC,IAAI,EAAE,YAAY,CAAC;IACnB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,+EAA+E;IAC/E,SAAS,EAAE,iBAAiB,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAmB9B"}
package/dist/list.js ADDED
@@ -0,0 +1,30 @@
1
+ import { getAirJsonPath, resolveArtifacts, emptyArtifacts, } from "@pulsemcp/air-core";
2
+ export const VALID_ARTIFACT_TYPES = [
3
+ "skills",
4
+ "mcp",
5
+ "plugins",
6
+ "roots",
7
+ "hooks",
8
+ "references",
9
+ ];
10
+ /**
11
+ * Resolve artifacts and return the entries for a specific artifact type.
12
+ *
13
+ * @throws Error if the artifact type is invalid.
14
+ */
15
+ export async function listArtifacts(type, options) {
16
+ if (!VALID_ARTIFACT_TYPES.includes(type)) {
17
+ throw new Error(`Unknown artifact type "${type}". Valid types: ${VALID_ARTIFACT_TYPES.join(", ")}`);
18
+ }
19
+ const airJsonPath = options?.config || getAirJsonPath();
20
+ const artifacts = airJsonPath
21
+ ? await resolveArtifacts(airJsonPath)
22
+ : emptyArtifacts();
23
+ const artifactType = type;
24
+ return {
25
+ type: artifactType,
26
+ entries: artifacts[artifactType],
27
+ artifacts,
28
+ };
29
+ }
30
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,cAAc,GAEf,MAAM,oBAAoB,CAAC;AAU5B,MAAM,CAAC,MAAM,oBAAoB,GAA4B;IAC3D,QAAQ;IACR,KAAK;IACL,SAAS;IACT,OAAO;IACP,OAAO;IACP,YAAY;CACJ,CAAC;AAgBX;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,OAA8B;IAE9B,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,IAAoB,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,0BAA0B,IAAI,mBAAmB,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnF,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC;IACxD,MAAM,SAAS,GAAG,WAAW;QAC3B,CAAC,CAAC,MAAM,gBAAgB,CAAC,WAAW,CAAC;QACrC,CAAC,CAAC,cAAc,EAAE,CAAC;IAErB,MAAM,YAAY,GAAG,IAAoB,CAAC;IAE1C,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,SAAS,CAAC,YAAY,CAAC;QAChC,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type RootEntry, type PreparedSession } from "@pulsemcp/air-core";
2
+ export interface PrepareSessionOptions {
3
+ /** Path to air.json. Uses AIR_CONFIG env or ~/.air/air.json if not set. */
4
+ config?: string;
5
+ /** Root to activate by name. Auto-detected from targetDir's git context if omitted. */
6
+ root?: string;
7
+ /** Target directory to prepare. Defaults to process.cwd(). */
8
+ target?: string;
9
+ /** Agent adapter name. Defaults to "claude". */
10
+ adapter?: string;
11
+ /** Skill IDs to activate (overrides root defaults). */
12
+ skills?: string[];
13
+ /** MCP server IDs to activate (overrides root defaults). */
14
+ mcpServers?: string[];
15
+ }
16
+ export interface PrepareSessionResult {
17
+ /** The prepared session result from the adapter. */
18
+ session: PreparedSession;
19
+ /** The auto-detected or specified root, if any. */
20
+ root?: RootEntry;
21
+ /** Whether the root was auto-detected (true) or explicitly specified (false/undefined). */
22
+ rootAutoDetected?: boolean;
23
+ }
24
+ /**
25
+ * Prepare a target directory for an agent session.
26
+ *
27
+ * Resolves artifacts, finds/auto-detects the root, and delegates to the adapter's
28
+ * prepareSession() to write .mcp.json, inject skills, etc.
29
+ *
30
+ * @throws Error if the adapter is not found, air.json is not found, or the specified root doesn't exist.
31
+ */
32
+ export declare function prepareSession(options?: PrepareSessionOptions): Promise<PrepareSessionResult>;
33
+ //# sourceMappingURL=prepare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare.d.ts","sourceRoot":"","sources":["../src/prepare.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,OAAO,EAAE,eAAe,CAAC;IACzB,mDAAmD;IACnD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAoD/B"}
@@ -0,0 +1,50 @@
1
+ import { resolve } from "path";
2
+ import { getAirJsonPath, resolveArtifacts, } from "@pulsemcp/air-core";
3
+ import { findAdapter, listAvailableAdapters } from "./adapter-registry.js";
4
+ import { detectRoot } from "./root-detection.js";
5
+ /**
6
+ * Prepare a target directory for an agent session.
7
+ *
8
+ * Resolves artifacts, finds/auto-detects the root, and delegates to the adapter's
9
+ * prepareSession() to write .mcp.json, inject skills, etc.
10
+ *
11
+ * @throws Error if the adapter is not found, air.json is not found, or the specified root doesn't exist.
12
+ */
13
+ export async function prepareSession(options) {
14
+ const adapterName = options?.adapter ?? "claude";
15
+ const adapter = await findAdapter(adapterName);
16
+ if (!adapter) {
17
+ const available = await listAvailableAdapters();
18
+ const availableMsg = available.length > 0
19
+ ? `Available: ${available.join(", ")}`
20
+ : "No adapters installed";
21
+ throw new Error(`No adapter found for "${adapterName}". ${availableMsg}.`);
22
+ }
23
+ const airJsonPath = options?.config || getAirJsonPath();
24
+ if (!airJsonPath) {
25
+ throw new Error("No air.json found. Specify a config path or set AIR_CONFIG env var.");
26
+ }
27
+ const artifacts = await resolveArtifacts(airJsonPath);
28
+ let root;
29
+ let rootAutoDetected = false;
30
+ if (options?.root) {
31
+ root = artifacts.roots[options.root];
32
+ if (!root) {
33
+ throw new Error(`Root "${options.root}" not found. Available roots: ${Object.keys(artifacts.roots).join(", ") || "(none)"}`);
34
+ }
35
+ }
36
+ else {
37
+ const targetDir = resolve(options?.target ?? process.cwd());
38
+ root = detectRoot(artifacts.roots, targetDir);
39
+ if (root) {
40
+ rootAutoDetected = true;
41
+ }
42
+ }
43
+ const session = await adapter.prepareSession(artifacts, options?.target ?? process.cwd(), {
44
+ root,
45
+ skillOverrides: options?.skills,
46
+ mcpServerOverrides: options?.mcpServers,
47
+ });
48
+ return { session, root, rootAutoDetected };
49
+ }
50
+ //# sourceMappingURL=prepare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare.js","sourceRoot":"","sources":["../src/prepare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,gBAAgB,GAGjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA0BjD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA+B;IAE/B,MAAM,WAAW,GAAG,OAAO,EAAE,OAAO,IAAI,QAAQ,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,qBAAqB,EAAE,CAAC;QAChD,MAAM,YAAY,GAChB,SAAS,CAAC,MAAM,GAAG,CAAC;YAClB,CAAC,CAAC,cAAc,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACtC,CAAC,CAAC,uBAAuB,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,yBAAyB,WAAW,MAAM,YAAY,GAAG,CAC1D,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC;IACxD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,qEAAqE,CACtE,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAEtD,IAAI,IAA2B,CAAC;IAChC,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,SAAS,OAAO,CAAC,IAAI,iCAAiC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE,CAC5G,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAC9C,IAAI,IAAI,EAAE,CAAC;YACT,gBAAgB,GAAG,IAAI,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,cAAc,CAC1C,SAAS,EACT,OAAO,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,EAChC;QACE,IAAI;QACJ,cAAc,EAAE,OAAO,EAAE,MAAM;QAC/B,kBAAkB,EAAE,OAAO,EAAE,UAAU;KACxC,CACF,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { RootEntry } from "@pulsemcp/air-core";
2
+ /**
3
+ * Normalize a git remote URL to a comparable form: "github.com/owner/repo"
4
+ * Handles HTTPS, SSH (git@), and trailing .git.
5
+ */
6
+ export declare function normalizeGitUrl(url: string): string;
7
+ /**
8
+ * Detect which root matches the current git repository and subdirectory.
9
+ *
10
+ * Algorithm:
11
+ * 1. Get the git remote URL and relative subdirectory from targetDir
12
+ * 2. Normalize the URL and compare against all root URLs
13
+ * 3. Among roots with matching URLs, pick the best subdirectory match:
14
+ * - Exact match (root.subdirectory === current subdirectory)
15
+ * - Longest prefix match
16
+ * - Root-level (no subdirectory / empty subdirectory)
17
+ */
18
+ export declare function detectRoot(roots: Record<string, RootEntry>, targetDir: string): RootEntry | undefined;
19
+ //# sourceMappingURL=root-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-detection.d.ts","sourceRoot":"","sources":["../src/root-detection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBnD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,SAAS,GAAG,SAAS,CAkEvB"}
@@ -0,0 +1,98 @@
1
+ import { execSync } from "child_process";
2
+ /**
3
+ * Normalize a git remote URL to a comparable form: "github.com/owner/repo"
4
+ * Handles HTTPS, SSH (git@), and trailing .git.
5
+ */
6
+ export function normalizeGitUrl(url) {
7
+ let normalized = url.trim();
8
+ // SSH format: git@github.com:owner/repo.git → github.com/owner/repo
9
+ const sshMatch = normalized.match(/^git@([^:]+):(.+)$/);
10
+ if (sshMatch) {
11
+ normalized = `${sshMatch[1]}/${sshMatch[2]}`;
12
+ }
13
+ else {
14
+ // HTTPS format: https://github.com/owner/repo.git → github.com/owner/repo
15
+ normalized = normalized.replace(/^https?:\/\//, "");
16
+ }
17
+ // Strip trailing .git
18
+ normalized = normalized.replace(/\.git$/, "");
19
+ // Strip trailing slash
20
+ normalized = normalized.replace(/\/$/, "");
21
+ return normalized;
22
+ }
23
+ /**
24
+ * Detect which root matches the current git repository and subdirectory.
25
+ *
26
+ * Algorithm:
27
+ * 1. Get the git remote URL and relative subdirectory from targetDir
28
+ * 2. Normalize the URL and compare against all root URLs
29
+ * 3. Among roots with matching URLs, pick the best subdirectory match:
30
+ * - Exact match (root.subdirectory === current subdirectory)
31
+ * - Longest prefix match
32
+ * - Root-level (no subdirectory / empty subdirectory)
33
+ */
34
+ export function detectRoot(roots, targetDir) {
35
+ let remoteUrl;
36
+ let relativeDir;
37
+ try {
38
+ remoteUrl = execSync("git remote get-url origin", {
39
+ cwd: targetDir,
40
+ stdio: ["pipe", "pipe", "pipe"],
41
+ encoding: "utf-8",
42
+ }).trim();
43
+ }
44
+ catch {
45
+ // Not in a git repo or no remote — can't auto-detect
46
+ return undefined;
47
+ }
48
+ try {
49
+ relativeDir = execSync("git rev-parse --show-prefix", {
50
+ cwd: targetDir,
51
+ stdio: ["pipe", "pipe", "pipe"],
52
+ encoding: "utf-8",
53
+ }).trim();
54
+ // Remove trailing slash
55
+ relativeDir = relativeDir.replace(/\/$/, "");
56
+ }
57
+ catch {
58
+ relativeDir = "";
59
+ }
60
+ const normalizedRemote = normalizeGitUrl(remoteUrl);
61
+ // Find all roots whose URL matches this repo
62
+ const matchingRoots = [];
63
+ for (const root of Object.values(roots)) {
64
+ if (!root.url)
65
+ continue;
66
+ const normalizedRootUrl = normalizeGitUrl(root.url);
67
+ if (normalizedRemote === normalizedRootUrl) {
68
+ matchingRoots.push(root);
69
+ }
70
+ }
71
+ if (matchingRoots.length === 0)
72
+ return undefined;
73
+ // Find best subdirectory match
74
+ // Priority: exact match → longest prefix → root-level (no/empty subdirectory)
75
+ const rootSubdir = (r) => (r.subdirectory || "").replace(/\/$/, "");
76
+ // 1. Exact match
77
+ const exact = matchingRoots.find((r) => rootSubdir(r) === relativeDir);
78
+ if (exact)
79
+ return exact;
80
+ // 2. Longest prefix match (current dir is within root's subdirectory)
81
+ const prefixMatches = matchingRoots
82
+ .filter((r) => {
83
+ const sub = rootSubdir(r);
84
+ if (!sub)
85
+ return false;
86
+ return relativeDir.startsWith(sub + "/") || relativeDir === sub;
87
+ })
88
+ .sort((a, b) => rootSubdir(b).length - rootSubdir(a).length);
89
+ if (prefixMatches.length > 0)
90
+ return prefixMatches[0];
91
+ // 3. Root-level fallback (root with no subdirectory)
92
+ const rootLevel = matchingRoots.find((r) => !rootSubdir(r));
93
+ if (rootLevel)
94
+ return rootLevel;
95
+ // 4. Any matching root as last resort
96
+ return matchingRoots[0];
97
+ }
98
+ //# sourceMappingURL=root-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-detection.js","sourceRoot":"","sources":["../src/root-detection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE5B,oEAAoE;IACpE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAI,QAAQ,EAAE,CAAC;QACb,UAAU,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,0EAA0E;QAC1E,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,sBAAsB;IACtB,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC9C,uBAAuB;IACvB,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE3C,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACxB,KAAgC,EAChC,SAAiB;IAEjB,IAAI,SAAiB,CAAC;IACtB,IAAI,WAAmB,CAAC;IAExB,IAAI,CAAC;QACH,SAAS,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YAChD,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,qDAAqD;QACrD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,WAAW,GAAG,QAAQ,CAAC,6BAA6B,EAAE;YACpD,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,wBAAwB;QACxB,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,EAAE,CAAC;IACnB,CAAC;IAED,MAAM,gBAAgB,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAEpD,6CAA6C;IAC7C,MAAM,aAAa,GAAgB,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,SAAS;QACxB,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpD,IAAI,gBAAgB,KAAK,iBAAiB,EAAE,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEjD,+BAA+B;IAC/B,8EAA8E;IAC9E,MAAM,UAAU,GAAG,CAAC,CAAY,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE/E,iBAAiB;IACjB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC;IACvE,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,sEAAsE;IACtE,MAAM,aAAa,GAAG,aAAa;SAChC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACZ,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,OAAO,WAAW,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,WAAW,KAAK,GAAG,CAAC;IAClE,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAE/D,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;IAEtD,qDAAqD;IACrD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhC,sCAAsC;IACtC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type ResolvedArtifacts, type RootEntry, type AgentSessionConfig, type StartCommand } from "@pulsemcp/air-core";
2
+ export interface StartSessionOptions {
3
+ /** Root to activate by name. */
4
+ root?: string;
5
+ /** Path to air.json. Uses AIR_CONFIG env or ~/.air/air.json if not set. */
6
+ config?: string;
7
+ /** Check whether the agent CLI is installed. Defaults to true. */
8
+ checkAvailability?: boolean;
9
+ }
10
+ export interface StartSessionResult {
11
+ /** The resolved artifacts. */
12
+ artifacts: ResolvedArtifacts;
13
+ /** The matched root, if any. */
14
+ root?: RootEntry;
15
+ /** The generated session config. */
16
+ sessionConfig: AgentSessionConfig;
17
+ /** Whether the agent CLI is available on PATH. Undefined if checkAvailability was false. */
18
+ agentAvailable: boolean | undefined;
19
+ /** The command to start the agent. */
20
+ startCommand: StartCommand;
21
+ /** The agent adapter display name. */
22
+ adapterDisplayName: string;
23
+ }
24
+ /**
25
+ * Prepare to start an agent session.
26
+ *
27
+ * Resolves artifacts, finds the adapter, generates config, checks availability,
28
+ * and builds the start command. Does NOT actually execute the agent.
29
+ *
30
+ * @throws Error if the adapter is not found or the specified root doesn't exist.
31
+ */
32
+ export declare function startSession(agent: string, options?: StartSessionOptions): Promise<StartSessionResult>;
33
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,mBAAmB;IAClC,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,gCAAgC;IAChC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,oCAAoC;IACpC,aAAa,EAAE,kBAAkB,CAAC;IAClC,4FAA4F;IAC5F,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B,sCAAsC;IACtC,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CA2C7B"}
package/dist/start.js ADDED
@@ -0,0 +1,46 @@
1
+ import { getAirJsonPath, resolveArtifacts, emptyArtifacts, } from "@pulsemcp/air-core";
2
+ import { findAdapter, listAvailableAdapters } from "./adapter-registry.js";
3
+ /**
4
+ * Prepare to start an agent session.
5
+ *
6
+ * Resolves artifacts, finds the adapter, generates config, checks availability,
7
+ * and builds the start command. Does NOT actually execute the agent.
8
+ *
9
+ * @throws Error if the adapter is not found or the specified root doesn't exist.
10
+ */
11
+ export async function startSession(agent, options) {
12
+ const adapter = await findAdapter(agent);
13
+ if (!adapter) {
14
+ const available = await listAvailableAdapters();
15
+ const availableMsg = available.length > 0
16
+ ? `Available: ${available.join(", ")}`
17
+ : "No adapters installed";
18
+ throw new Error(`No adapter found for "${agent}". ${availableMsg}.\n` +
19
+ `Install an adapter: npm install @pulsemcp/air-adapter-${agent}`);
20
+ }
21
+ const airJsonPath = options?.config || getAirJsonPath();
22
+ const artifacts = airJsonPath
23
+ ? await resolveArtifacts(airJsonPath)
24
+ : emptyArtifacts();
25
+ let root;
26
+ if (options?.root) {
27
+ root = artifacts.roots[options.root];
28
+ if (!root) {
29
+ throw new Error(`Root "${options.root}" not found. Available roots: ${Object.keys(artifacts.roots).join(", ") || "(none)"}`);
30
+ }
31
+ }
32
+ const sessionConfig = adapter.generateConfig(artifacts, root);
33
+ const agentAvailable = (options?.checkAvailability ?? true)
34
+ ? await adapter.isAvailable()
35
+ : undefined;
36
+ const startCommand = adapter.buildStartCommand(sessionConfig);
37
+ return {
38
+ artifacts,
39
+ root,
40
+ sessionConfig,
41
+ agentAvailable,
42
+ startCommand,
43
+ adapterDisplayName: adapter.displayName,
44
+ };
45
+ }
46
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,cAAc,GAKf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AA0B3E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,OAA6B;IAE7B,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,qBAAqB,EAAE,CAAC;QAChD,MAAM,YAAY,GAChB,SAAS,CAAC,MAAM,GAAG,CAAC;YAClB,CAAC,CAAC,cAAc,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACtC,CAAC,CAAC,uBAAuB,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,yBAAyB,KAAK,MAAM,YAAY,KAAK;YACnD,yDAAyD,KAAK,EAAE,CACnE,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC;IACxD,MAAM,SAAS,GAAG,WAAW;QAC3B,CAAC,CAAC,MAAM,gBAAgB,CAAC,WAAW,CAAC;QACrC,CAAC,CAAC,cAAc,EAAE,CAAC;IAErB,IAAI,IAA2B,CAAC;IAChC,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,SAAS,OAAO,CAAC,IAAI,iCAAiC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE,CAC5G,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,iBAAiB,IAAI,IAAI,CAAC;QACzD,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE;QAC7B,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAE9D,OAAO;QACL,SAAS;QACT,IAAI;QACJ,aAAa;QACb,cAAc;QACd,YAAY;QACZ,kBAAkB,EAAE,OAAO,CAAC,WAAW;KACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { type SchemaType, type ValidationResult } from "@pulsemcp/air-core";
2
+ export interface ValidateFileOptions {
3
+ /** Override schema type detection. */
4
+ schema?: string;
5
+ /** Base directory for resolving relative file paths. Defaults to process.cwd(). */
6
+ cwd?: string;
7
+ }
8
+ export interface ValidateFileResult {
9
+ /** Whether the file is valid against the detected/specified schema. */
10
+ valid: boolean;
11
+ /** The schema type used for validation. */
12
+ schemaType: SchemaType;
13
+ /** Validation result from core (includes errors if invalid). */
14
+ validation: ValidationResult;
15
+ }
16
+ /**
17
+ * Validate a JSON file against its AIR schema.
18
+ *
19
+ * Schema detection order:
20
+ * 1. Explicit `options.schema` override
21
+ * 2. `$schema` field in the JSON content
22
+ * 3. Filename substring matching
23
+ *
24
+ * @throws Error if the file cannot be read/parsed, schema type is invalid, or schema cannot be detected.
25
+ */
26
+ export declare function validateFile(file: string, options?: ValidateFileOptions): ValidateFileResult;
27
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,KAAK,EAAE,OAAO,CAAC;IACf,2CAA2C;IAC3C,UAAU,EAAE,UAAU,CAAC;IACvB,gEAAgE;IAChE,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,mBAAmB,GAC5B,kBAAkB,CAsDpB"}
@@ -0,0 +1,56 @@
1
+ import { readFileSync } from "fs";
2
+ import { resolve } from "path";
3
+ import { detectSchemaType, detectSchemaFromValue, isValidSchemaType, validateJson, } from "@pulsemcp/air-core";
4
+ /**
5
+ * Validate a JSON file against its AIR schema.
6
+ *
7
+ * Schema detection order:
8
+ * 1. Explicit `options.schema` override
9
+ * 2. `$schema` field in the JSON content
10
+ * 3. Filename substring matching
11
+ *
12
+ * @throws Error if the file cannot be read/parsed, schema type is invalid, or schema cannot be detected.
13
+ */
14
+ export function validateFile(file, options) {
15
+ const cwd = options?.cwd ?? process.cwd();
16
+ const filePath = resolve(cwd, file);
17
+ let data;
18
+ try {
19
+ const content = readFileSync(filePath, "utf-8");
20
+ data = JSON.parse(content);
21
+ }
22
+ catch (err) {
23
+ const message = err instanceof Error ? err.message : "Unknown error";
24
+ throw new Error(`Could not read or parse "${file}": ${message}`);
25
+ }
26
+ // Determine schema type: explicit option > $schema in JSON > filename substring
27
+ let schemaType = null;
28
+ if (options?.schema) {
29
+ if (!isValidSchemaType(options.schema)) {
30
+ throw new Error(`Unknown schema type "${options.schema}". Valid types: air, skills, references, mcp, plugins, roots, hooks`);
31
+ }
32
+ schemaType = options.schema;
33
+ }
34
+ if (!schemaType &&
35
+ data &&
36
+ typeof data === "object" &&
37
+ !Array.isArray(data)) {
38
+ const schemaValue = data.$schema;
39
+ if (typeof schemaValue === "string") {
40
+ schemaType = detectSchemaFromValue(schemaValue);
41
+ }
42
+ }
43
+ if (!schemaType) {
44
+ schemaType = detectSchemaType(file);
45
+ }
46
+ if (!schemaType) {
47
+ throw new Error(`Could not detect schema type for "${file}". Specify a schema type explicitly.`);
48
+ }
49
+ const validation = validateJson(data, schemaType);
50
+ return {
51
+ valid: validation.valid,
52
+ schemaType,
53
+ validation,
54
+ };
55
+ }
56
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,GAGb,MAAM,oBAAoB,CAAC;AAkB5B;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,OAA6B;IAE7B,MAAM,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEpC,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,gFAAgF;IAChF,IAAI,UAAU,GAAsB,IAAI,CAAC;IAEzC,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,wBAAwB,OAAO,CAAC,MAAM,qEAAqE,CAC5G,CAAC;QACJ,CAAC;QACD,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,CAAC;IAED,IACE,CAAC,UAAU;QACX,IAAI;QACJ,OAAO,IAAI,KAAK,QAAQ;QACxB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EACpB,CAAC;QACD,MAAM,WAAW,GAAI,IAAgC,CAAC,OAAO,CAAC;QAC9D,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACpC,UAAU,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,qCAAqC,IAAI,sCAAsC,CAChF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAElD,OAAO;QACL,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,UAAU;QACV,UAAU;KACX,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@pulsemcp/air-sdk",
3
+ "version": "0.0.3",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/pulsemcp/air.git",
10
+ "directory": "packages/sdk"
11
+ },
12
+ "description": "AIR SDK — programmatic API for the Agent Infrastructure Repository framework",
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.0.3"
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
+ }