@pulsemcp/air-sdk 0.0.40 → 0.0.41

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,54 @@
1
+ import { type DiscoveryResult, type DiscoveredCatalog, type DiscoveredLooseIndex, type DiscoveredAirJson } from "./discover-indexes.js";
2
+ import { type EditAirJsonResult } from "./edit-air-json.js";
3
+ export interface FindOfferableOptions {
4
+ /** Working directory to anchor discovery. Defaults to process.cwd(). */
5
+ cwd?: string;
6
+ /** Path to air.json. Defaults to AIR_CONFIG env or ~/.air/air.json. */
7
+ configPath?: string;
8
+ /** Override preferences path (for testing). */
9
+ preferencesPath?: string;
10
+ }
11
+ export interface OfferableDiscoveryResult {
12
+ /** The raw result from `discoverIndexes`. */
13
+ raw: DiscoveryResult;
14
+ /** Catalogs not yet in air.json and not dismissed. */
15
+ catalogs: DiscoveredCatalog[];
16
+ /** Loose indexes not yet in air.json and not dismissed. */
17
+ looseIndexes: DiscoveredLooseIndex[];
18
+ /** Nested air.json files not yet in air.json and not dismissed. */
19
+ airJsons: DiscoveredAirJson[];
20
+ /** True if there is anything to offer the user. */
21
+ hasOffers: boolean;
22
+ /**
23
+ * Resolved absolute path to the air.json we'll target on accept. Honors
24
+ * `options.configPath`, then `AIR_CONFIG`, then `~/.air/air.json`. Unlike
25
+ * `getAirJsonPath()`, this is populated even when the file does not yet
26
+ * exist so accept-flow scaffolding writes to the right location.
27
+ */
28
+ resolvedConfigPath: string;
29
+ }
30
+ /**
31
+ * Run discovery, drop anything already in `~/.air/air.json`, drop anything
32
+ * the user has asked AIR not to offer again. The caller decides what to do
33
+ * with the survivors (prompt, auto-accept, etc.).
34
+ */
35
+ export declare function findOfferableIndexes(options?: FindOfferableOptions): OfferableDiscoveryResult;
36
+ export interface AcceptDiscoveryOptions {
37
+ /** Override the air.json path. */
38
+ configPath?: string;
39
+ }
40
+ /**
41
+ * Accept all offers by writing them into air.json.
42
+ */
43
+ export declare function acceptOffers(offers: OfferableDiscoveryResult, options?: AcceptDiscoveryOptions): EditAirJsonResult;
44
+ export interface DismissDiscoveryOptions {
45
+ /** Override the preferences path (for testing). */
46
+ preferencesPath?: string;
47
+ }
48
+ /**
49
+ * Mark every current offer as dismissed so it is never surfaced again.
50
+ * Uses (repoRoot=anchor, indexPath=relative) granularity — new files added
51
+ * later still get offered.
52
+ */
53
+ export declare function dismissOffers(offers: OfferableDiscoveryResult, options?: DismissDiscoveryOptions): void;
54
+ //# sourceMappingURL=auto-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-discovery.d.ts","sourceRoot":"","sources":["../src/auto-discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,6CAA6C;IAC7C,GAAG,EAAE,eAAe,CAAC;IACrB,sDAAsD;IACtD,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,2DAA2D;IAC3D,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,mEAAmE;IACnE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAYD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,wBAAwB,CA4C1B;AAED,MAAM,WAAW,sBAAsB;IACrC,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,wBAAwB,EAChC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,iBAAiB,CAanB;AAED,MAAM,WAAW,uBAAuB;IACtC,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,wBAAwB,EAChC,OAAO,CAAC,EAAE,uBAAuB,GAChC,IAAI,CAcN"}
@@ -0,0 +1,99 @@
1
+ import { resolve } from "path";
2
+ import { getDefaultAirJsonPath } from "@pulsemcp/air-core";
3
+ import { discoverIndexes, } from "./discover-indexes.js";
4
+ import { loadPreferences, isDismissed, addDismissed, } from "./preferences.js";
5
+ import { addDiscoveredToAirJson, buildRegisteredChecker, } from "./edit-air-json.js";
6
+ /**
7
+ * Resolve the target air.json path consistently across discovery and accept.
8
+ * `getAirJsonPath()` returns null for missing files, which loses the user's
9
+ * `AIR_CONFIG` preference on a first-time scaffold — so we do our own
10
+ * resolution that always returns a real path.
11
+ */
12
+ function resolveTargetConfigPath(explicit) {
13
+ return explicit ?? process.env.AIR_CONFIG ?? getDefaultAirJsonPath();
14
+ }
15
+ /**
16
+ * Run discovery, drop anything already in `~/.air/air.json`, drop anything
17
+ * the user has asked AIR not to offer again. The caller decides what to do
18
+ * with the survivors (prompt, auto-accept, etc.).
19
+ */
20
+ export function findOfferableIndexes(options) {
21
+ const cwd = options?.cwd ?? process.cwd();
22
+ const resolvedConfigPath = resolveTargetConfigPath(options?.configPath);
23
+ const raw = discoverIndexes(cwd);
24
+ // buildRegisteredChecker tolerates a missing file (returns no-op), so we
25
+ // can pass the resolved path even if the air.json doesn't exist yet.
26
+ const registered = buildRegisteredChecker(resolvedConfigPath);
27
+ const prefs = loadPreferences(options?.preferencesPath);
28
+ const asDismissed = (indexPath) => ({
29
+ repoRoot: raw.anchor,
30
+ indexPath,
31
+ });
32
+ const catalogs = raw.catalogs.filter((c) => {
33
+ if (registered.catalog(c.path))
34
+ return false;
35
+ if (isDismissed(prefs, asDismissed(c.relPath)))
36
+ return false;
37
+ return true;
38
+ });
39
+ const looseIndexes = raw.looseIndexes.filter((l) => {
40
+ if (registered.loose(l.type, l.path))
41
+ return false;
42
+ if (isDismissed(prefs, asDismissed(l.relPath)))
43
+ return false;
44
+ return true;
45
+ });
46
+ const airJsons = raw.airJsons.filter((a) => {
47
+ if (registered.airJson(a.path))
48
+ return false;
49
+ if (isDismissed(prefs, asDismissed(a.relPath)))
50
+ return false;
51
+ return true;
52
+ });
53
+ return {
54
+ raw,
55
+ catalogs,
56
+ looseIndexes,
57
+ airJsons,
58
+ hasOffers: catalogs.length > 0 ||
59
+ looseIndexes.length > 0 ||
60
+ airJsons.length > 0,
61
+ resolvedConfigPath,
62
+ };
63
+ }
64
+ /**
65
+ * Accept all offers by writing them into air.json.
66
+ */
67
+ export function acceptOffers(offers, options) {
68
+ // An explicit override wins; otherwise use the path the discovery already
69
+ // resolved. This preserves AIR_CONFIG even when the file didn't exist at
70
+ // discovery time and is about to be scaffolded.
71
+ const configPath = options?.configPath ?? offers.resolvedConfigPath;
72
+ return addDiscoveredToAirJson({
73
+ catalogs: offers.catalogs,
74
+ looseIndexes: offers.looseIndexes,
75
+ airJsons: offers.airJsons,
76
+ }, { path: configPath });
77
+ }
78
+ /**
79
+ * Mark every current offer as dismissed so it is never surfaced again.
80
+ * Uses (repoRoot=anchor, indexPath=relative) granularity — new files added
81
+ * later still get offered.
82
+ */
83
+ export function dismissOffers(offers, options) {
84
+ const { anchor } = offers.raw;
85
+ const entries = [];
86
+ for (const c of offers.catalogs) {
87
+ entries.push({ repoRoot: resolve(anchor), indexPath: c.relPath });
88
+ }
89
+ for (const l of offers.looseIndexes) {
90
+ entries.push({ repoRoot: resolve(anchor), indexPath: l.relPath });
91
+ }
92
+ for (const a of offers.airJsons) {
93
+ entries.push({ repoRoot: resolve(anchor), indexPath: a.relPath });
94
+ }
95
+ if (entries.length === 0)
96
+ return;
97
+ addDismissed(entries, options?.preferencesPath);
98
+ }
99
+ //# sourceMappingURL=auto-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-discovery.js","sourceRoot":"","sources":["../src/auto-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /** Artifact-index types that map to a catalog layout directory. */
2
+ declare const CATALOG_TYPES: readonly ["skills", "references", "mcp", "plugins", "roots", "hooks"];
3
+ type CatalogType = (typeof CATALOG_TYPES)[number];
4
+ export interface DiscoveredCatalog {
5
+ /** Absolute path to the catalog directory. */
6
+ path: string;
7
+ /** Path relative to the discovery anchor. */
8
+ relPath: string;
9
+ /** Artifact types found under the catalog that match the `<type>/<type>.json` layout. */
10
+ types: CatalogType[];
11
+ /** Count of entries per discovered type, for prompt summaries. */
12
+ entryCounts: Partial<Record<CatalogType, number>>;
13
+ }
14
+ export interface DiscoveredLooseIndex {
15
+ /** Artifact type inferred from the filename and/or `$schema`. */
16
+ type: CatalogType;
17
+ /** Absolute path to the index file. */
18
+ path: string;
19
+ /** Path relative to the discovery anchor. */
20
+ relPath: string;
21
+ /** Count of top-level entries in the index (excluding `$schema`). */
22
+ entryCount: number;
23
+ }
24
+ export interface DiscoveredAirJson {
25
+ /** Absolute path to the air.json file. */
26
+ path: string;
27
+ /** Path relative to the discovery anchor. */
28
+ relPath: string;
29
+ }
30
+ export interface DiscoveryResult {
31
+ /** Absolute path to the directory discovery was anchored at (git root or fallback). */
32
+ anchor: string;
33
+ /** Whether the anchor was determined via `git rev-parse` (true) or a cwd fallback (false). */
34
+ anchorIsGitRoot: boolean;
35
+ /** Catalog directories — `<anchor>/<type>/<type>.json` layouts. */
36
+ catalogs: DiscoveredCatalog[];
37
+ /** Bare artifact index files that are not part of a full catalog layout. */
38
+ looseIndexes: DiscoveredLooseIndex[];
39
+ /** Nested `air.json` files. */
40
+ airJsons: DiscoveredAirJson[];
41
+ }
42
+ export interface DiscoverIndexesOptions {
43
+ /** Maximum walk depth below the anchor. Default: 3. */
44
+ maxDepth?: number;
45
+ /** Override the skiplist. Default: common build/output dirs + node_modules/.git. */
46
+ skipDirs?: Set<string>;
47
+ }
48
+ /**
49
+ * Resolve the discovery anchor for a target directory.
50
+ * Returns the git root when inside a repo, otherwise the target itself.
51
+ */
52
+ export declare function resolveAnchor(targetDir: string): {
53
+ anchor: string;
54
+ isGitRoot: boolean;
55
+ };
56
+ /**
57
+ * Discover AIR index files and `air.json` configs under `targetDir`.
58
+ *
59
+ * Anchor is the enclosing git root (via `git rev-parse --show-toplevel`)
60
+ * if one exists, else `targetDir` itself. Walks up to `maxDepth` levels
61
+ * deep, skipping `node_modules/`, `.git/`, build output dirs, and anything
62
+ * starting with `.`. Every candidate file is validated via filename-based
63
+ * schema detection plus optional `$schema` cross-check; unparseable or
64
+ * non-AIR JSON files are silently skipped.
65
+ *
66
+ * Files found via a catalog layout are excluded from `looseIndexes` — the
67
+ * catalog entry already covers them.
68
+ */
69
+ export declare function discoverIndexes(targetDir: string, options?: DiscoverIndexesOptions): DiscoveryResult;
70
+ export type { CatalogType };
71
+ export { CATALOG_TYPES };
72
+ //# sourceMappingURL=discover-indexes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-indexes.d.ts","sourceRoot":"","sources":["../src/discover-indexes.ts"],"names":[],"mappings":"AASA,mEAAmE;AACnE,QAAA,MAAM,aAAa,uEAOuC,CAAC;AAE3D,KAAK,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAkBlD,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,kEAAkE;IAClE,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,IAAI,EAAE,WAAW,CAAC;IAClB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,eAAe,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,4EAA4E;IAC5E,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,+BAA+B;IAC/B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB,CAcA;AAqLD;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,eAAe,CAmEjB;AAED,YAAY,EAAE,WAAW,EAAE,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,309 @@
1
+ import { execFileSync } from "child_process";
2
+ import { readFileSync, readdirSync, existsSync } from "fs";
3
+ import { resolve, relative, sep, basename } from "path";
4
+ import { detectSchemaType, detectSchemaFromValue, } from "@pulsemcp/air-core";
5
+ /** Artifact-index types that map to a catalog layout directory. */
6
+ const CATALOG_TYPES = [
7
+ "skills",
8
+ "references",
9
+ "mcp",
10
+ "plugins",
11
+ "roots",
12
+ "hooks",
13
+ ];
14
+ /** Directories never descended into during discovery. */
15
+ const SKIP_DIRS = new Set([
16
+ "node_modules",
17
+ ".git",
18
+ "dist",
19
+ "build",
20
+ "coverage",
21
+ ".next",
22
+ ".turbo",
23
+ "target",
24
+ "vendor",
25
+ ]);
26
+ /** Maximum directory depth walked under the anchor (anchor itself is depth 0). */
27
+ const MAX_DEPTH = 3;
28
+ /**
29
+ * Resolve the discovery anchor for a target directory.
30
+ * Returns the git root when inside a repo, otherwise the target itself.
31
+ */
32
+ export function resolveAnchor(targetDir) {
33
+ try {
34
+ const root = execFileSync("git", ["rev-parse", "--show-toplevel"], {
35
+ cwd: targetDir,
36
+ stdio: ["pipe", "pipe", "pipe"],
37
+ encoding: "utf-8",
38
+ }).trim();
39
+ if (root) {
40
+ return { anchor: resolve(root), isGitRoot: true };
41
+ }
42
+ }
43
+ catch {
44
+ // Not a git repo or git not installed — fall through.
45
+ }
46
+ return { anchor: resolve(targetDir), isGitRoot: false };
47
+ }
48
+ /**
49
+ * Read a JSON file and verify it is (a) parseable, (b) an object, and
50
+ * (c) plausibly an AIR artifact index of the expected type.
51
+ *
52
+ * Validation rules:
53
+ * - The file must parse as a JSON object (not array/primitive/null).
54
+ * - A missing `$schema` is allowed — filename-based detection is sufficient.
55
+ * - When `$schema` is present, it must resolve to the expected artifact type;
56
+ * a contradictory or non-AIR schema causes the file to be skipped.
57
+ *
58
+ * Returns the parsed data when valid, or `null` to signal "skip this file".
59
+ */
60
+ function readAndValidateIndex(filePath, expectedType) {
61
+ let content;
62
+ try {
63
+ content = readFileSync(filePath, "utf-8");
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ let data;
69
+ try {
70
+ data = JSON.parse(content);
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ if (typeof data !== "object" ||
76
+ data === null ||
77
+ Array.isArray(data)) {
78
+ return null;
79
+ }
80
+ const obj = data;
81
+ if (typeof obj.$schema === "string") {
82
+ const schemaType = detectSchemaFromValue(obj.$schema);
83
+ if (schemaType === null)
84
+ return null;
85
+ if (schemaType !== expectedType)
86
+ return null;
87
+ }
88
+ return obj;
89
+ }
90
+ /** Count top-level artifact entries in a validated index (excludes `$schema`). */
91
+ function countEntries(data) {
92
+ let count = 0;
93
+ for (const key of Object.keys(data)) {
94
+ if (key === "$schema")
95
+ continue;
96
+ count++;
97
+ }
98
+ return count;
99
+ }
100
+ function readAirJson(filePath) {
101
+ let content;
102
+ try {
103
+ content = readFileSync(filePath, "utf-8");
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ let data;
109
+ try {
110
+ data = JSON.parse(content);
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
116
+ return false;
117
+ }
118
+ const obj = data;
119
+ if (typeof obj.name !== "string")
120
+ return false;
121
+ if (typeof obj.$schema === "string") {
122
+ const schemaType = detectSchemaFromValue(obj.$schema);
123
+ if (schemaType !== null && schemaType !== "air")
124
+ return false;
125
+ }
126
+ return true;
127
+ }
128
+ /**
129
+ * Walk `anchor` up to `maxDepth` levels, yielding all files that might be
130
+ * AIR index candidates. Skips hidden directories and the configured skiplist.
131
+ * Hidden files (e.g. `.somefile.json`) are skipped. `.claude/skills/` is
132
+ * intentionally NOT scanned — local `.claude/` skills are adapter-owned and
133
+ * not managed through AIR discovery.
134
+ */
135
+ function* walkJsonFiles(anchor, maxDepth, skipDirs) {
136
+ function* recurse(dir, depth) {
137
+ let entries;
138
+ try {
139
+ entries = readdirSync(dir, { withFileTypes: true });
140
+ }
141
+ catch {
142
+ return;
143
+ }
144
+ for (const entry of entries) {
145
+ const name = entry.name;
146
+ if (name.startsWith("."))
147
+ continue;
148
+ const full = resolve(dir, name);
149
+ if (entry.isDirectory()) {
150
+ if (skipDirs.has(name))
151
+ continue;
152
+ if (depth + 1 > maxDepth)
153
+ continue;
154
+ yield* recurse(full, depth + 1);
155
+ }
156
+ else if (entry.isFile()) {
157
+ if (name.endsWith(".json")) {
158
+ yield full;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ yield* recurse(anchor, 0);
164
+ }
165
+ /**
166
+ * Find catalog layouts under the anchor.
167
+ *
168
+ * A catalog is a directory D such that `D/<type>/<type>.json` exists for at
169
+ * least one of the six artifact types. The catalog's position is D itself
170
+ * (so `air.json`'s `catalogs[]` receives a single entry for D, not six
171
+ * per-type paths).
172
+ *
173
+ * Catalog detection is conservative — `D/skills/skills.json` must look like
174
+ * a valid AIR skills index (parseable JSON object with a matching `$schema`
175
+ * if declared) before D is considered a catalog.
176
+ */
177
+ function findCatalogs(anchor) {
178
+ // Map of catalog absolute path → set of types detected under it.
179
+ const catalogs = new Map();
180
+ function tryCatalogAt(dirPath) {
181
+ if (catalogs.has(dirPath))
182
+ return;
183
+ const entryCounts = {};
184
+ const types = [];
185
+ for (const type of CATALOG_TYPES) {
186
+ const candidate = resolve(dirPath, type, `${type}.json`);
187
+ if (!existsSync(candidate))
188
+ continue;
189
+ const data = readAndValidateIndex(candidate, type);
190
+ if (!data)
191
+ continue;
192
+ types.push(type);
193
+ entryCounts[type] = countEntries(data);
194
+ }
195
+ if (types.length === 0)
196
+ return;
197
+ catalogs.set(dirPath, {
198
+ path: dirPath,
199
+ relPath: relative(anchor, dirPath) || ".",
200
+ types,
201
+ entryCounts,
202
+ });
203
+ }
204
+ // The anchor itself is always a candidate root.
205
+ tryCatalogAt(anchor);
206
+ // Also scan subdirectories one level deep — this catches layouts where the
207
+ // catalog lives under e.g. `config/` or `air/` rather than at the repo root.
208
+ let entries;
209
+ try {
210
+ entries = readdirSync(anchor, { withFileTypes: true });
211
+ }
212
+ catch {
213
+ return [...catalogs.values()];
214
+ }
215
+ for (const entry of entries) {
216
+ if (!entry.isDirectory())
217
+ continue;
218
+ const name = entry.name;
219
+ if (name.startsWith("."))
220
+ continue;
221
+ if (SKIP_DIRS.has(name))
222
+ continue;
223
+ // Per-type directories like `skills/` are themselves part of a catalog
224
+ // *rooted at the anchor*, not a catalog on their own. They don't
225
+ // contain `<type>/<type>.json` layouts inside themselves anyway, so
226
+ // `tryCatalogAt` will quietly return. No special-case needed.
227
+ tryCatalogAt(resolve(anchor, name));
228
+ }
229
+ return [...catalogs.values()];
230
+ }
231
+ /**
232
+ * Discover AIR index files and `air.json` configs under `targetDir`.
233
+ *
234
+ * Anchor is the enclosing git root (via `git rev-parse --show-toplevel`)
235
+ * if one exists, else `targetDir` itself. Walks up to `maxDepth` levels
236
+ * deep, skipping `node_modules/`, `.git/`, build output dirs, and anything
237
+ * starting with `.`. Every candidate file is validated via filename-based
238
+ * schema detection plus optional `$schema` cross-check; unparseable or
239
+ * non-AIR JSON files are silently skipped.
240
+ *
241
+ * Files found via a catalog layout are excluded from `looseIndexes` — the
242
+ * catalog entry already covers them.
243
+ */
244
+ export function discoverIndexes(targetDir, options) {
245
+ const { anchor, isGitRoot } = resolveAnchor(targetDir);
246
+ const maxDepth = options?.maxDepth ?? MAX_DEPTH;
247
+ const skipDirs = options?.skipDirs ?? SKIP_DIRS;
248
+ const catalogs = findCatalogs(anchor);
249
+ // Build a set of file paths already covered by a catalog so we don't
250
+ // double-count them as loose indexes.
251
+ const catalogCovered = new Set();
252
+ for (const cat of catalogs) {
253
+ for (const type of cat.types) {
254
+ catalogCovered.add(resolve(cat.path, type, `${type}.json`));
255
+ }
256
+ }
257
+ const looseIndexes = [];
258
+ const airJsons = [];
259
+ for (const file of walkJsonFiles(anchor, maxDepth, skipDirs)) {
260
+ if (catalogCovered.has(file))
261
+ continue;
262
+ const name = basename(file);
263
+ // End-with `.schema.json` is excluded by detectSchemaType.
264
+ const type = detectSchemaType(name);
265
+ if (!type)
266
+ continue;
267
+ if (type === "air") {
268
+ if (readAirJson(file)) {
269
+ airJsons.push({
270
+ path: file,
271
+ relPath: relative(anchor, file),
272
+ });
273
+ }
274
+ continue;
275
+ }
276
+ if (!CATALOG_TYPES.includes(type))
277
+ continue;
278
+ const data = readAndValidateIndex(file, type);
279
+ if (!data)
280
+ continue;
281
+ looseIndexes.push({
282
+ type: type,
283
+ path: file,
284
+ relPath: relative(anchor, file),
285
+ entryCount: countEntries(data),
286
+ });
287
+ }
288
+ // Stable ordering: shallowest first, then alphabetic. Makes test assertions
289
+ // deterministic and produces predictable prompt output.
290
+ const byPath = (a, b) => {
291
+ const da = a.relPath.split(sep).length;
292
+ const db = b.relPath.split(sep).length;
293
+ if (da !== db)
294
+ return da - db;
295
+ return a.relPath.localeCompare(b.relPath);
296
+ };
297
+ catalogs.sort(byPath);
298
+ looseIndexes.sort(byPath);
299
+ airJsons.sort(byPath);
300
+ return {
301
+ anchor,
302
+ anchorIsGitRoot: isGitRoot,
303
+ catalogs,
304
+ looseIndexes,
305
+ airJsons,
306
+ };
307
+ }
308
+ export { CATALOG_TYPES };
309
+ //# sourceMappingURL=discover-indexes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-indexes.js","sourceRoot":"","sources":["../src/discover-indexes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { DiscoveredCatalog, DiscoveredLooseIndex, DiscoveredAirJson, CatalogType } from "./discover-indexes.js";
2
+ /** Shape of the entries we write — loose indexes get a type, catalogs get the catalogs[] slot. */
3
+ export interface AirJsonAddition {
4
+ kind: "catalog" | "loose" | "airJson";
5
+ /** Path or URI string written to air.json. */
6
+ value: string;
7
+ /** For loose/airJson entries, the artifact type slot the value was written to. */
8
+ type?: CatalogType;
9
+ /** Short human-readable summary used by the acceptance output. */
10
+ label: string;
11
+ }
12
+ export interface EditAirJsonOptions {
13
+ /** Override the default air.json path. */
14
+ path?: string;
15
+ /** Entries already persisted into air.json become no-ops. Default: true. */
16
+ idempotent?: boolean;
17
+ }
18
+ export interface EditAirJsonResult {
19
+ /** Absolute path to the air.json that was read/written. */
20
+ airJsonPath: string;
21
+ /** Entries that were newly added. */
22
+ added: AirJsonAddition[];
23
+ /** Entries that were already present and therefore skipped. */
24
+ skipped: AirJsonAddition[];
25
+ /** True if the scaffold was created because no air.json existed. */
26
+ createdScaffold: boolean;
27
+ }
28
+ /**
29
+ * Check whether `candidate` (an absolute path or URI) is already present in the
30
+ * given list of air.json entries. Performs path normalization so absolute,
31
+ * `./relative`, and `../relative` forms of the same file all collide.
32
+ */
33
+ export declare function entryAlreadyListed(candidateAbsOrUri: string, list: string[] | undefined, airJsonDir: string): boolean;
34
+ export interface AddDiscoveredEntries {
35
+ catalogs?: DiscoveredCatalog[];
36
+ looseIndexes?: DiscoveredLooseIndex[];
37
+ airJsons?: DiscoveredAirJson[];
38
+ }
39
+ /**
40
+ * Add discovered entries to the user's air.json.
41
+ *
42
+ * Catalogs go into `catalogs[]`. Loose indexes go into the matching per-type
43
+ * array (`skills[]`, `mcp[]`, …). Nested `air.json` files land in
44
+ * `catalogs[]` because they describe a full composition at their location —
45
+ * the user can further edit the reference later. All additions are
46
+ * idempotent: an entry already present in air.json is not duplicated.
47
+ *
48
+ * If the target air.json does not exist, a minimal scaffold is written
49
+ * (no local index files — for a full workspace scaffold use `initConfig`).
50
+ */
51
+ export declare function addDiscoveredToAirJson(entries: AddDiscoveredEntries, options?: EditAirJsonOptions): EditAirJsonResult;
52
+ /**
53
+ * Inspect whether a discovered candidate is already registered in air.json.
54
+ * Used by the discovery filter to drop items that are already composed.
55
+ */
56
+ export interface RegisteredChecker {
57
+ catalog(absPath: string): boolean;
58
+ loose(type: CatalogType, absPath: string): boolean;
59
+ airJson(absPath: string): boolean;
60
+ }
61
+ export declare function buildRegisteredChecker(airJsonPath: string | null): RegisteredChecker;
62
+ //# sourceMappingURL=edit-air-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-air-json.d.ts","sourceRoot":"","sources":["../src/edit-air-json.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACZ,MAAM,uBAAuB,CAAC;AAc/B,kGAAkG;AAClG,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACtC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,+DAA+D;IAC/D,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,oEAAoE;IACpE,eAAe,EAAE,OAAO,CAAC;CAC1B;AA2DD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,iBAAiB,EAAE,MAAM,EACzB,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,EAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAYT;AA+CD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,iBAAiB,CAkFnB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACnD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,iBAAiB,CAiCnB"}
@@ -0,0 +1,227 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
+ import { resolve, dirname, relative, isAbsolute } from "path";
3
+ import { getDefaultAirJsonPath } from "@pulsemcp/air-core";
4
+ const SCHEMA_BASE_URL = "https://raw.githubusercontent.com/pulsemcp/air/main/schemas";
5
+ const CATALOG_TYPES = [
6
+ "skills",
7
+ "references",
8
+ "mcp",
9
+ "plugins",
10
+ "roots",
11
+ "hooks",
12
+ ];
13
+ function loadOrScaffold(airJsonPath) {
14
+ if (!existsSync(airJsonPath)) {
15
+ mkdirSync(dirname(airJsonPath), { recursive: true });
16
+ const scaffold = {
17
+ $schema: `${SCHEMA_BASE_URL}/air.schema.json`,
18
+ name: "my-config",
19
+ description: "Personal AIR configuration",
20
+ };
21
+ return { data: scaffold, created: true };
22
+ }
23
+ const raw = readFileSync(airJsonPath, "utf-8");
24
+ const parsed = JSON.parse(raw);
25
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
26
+ throw new Error(`${airJsonPath} is not a JSON object — refusing to edit.`);
27
+ }
28
+ return { data: parsed, created: false };
29
+ }
30
+ /**
31
+ * Normalize a path string for comparison against air.json entries. Entries
32
+ * in air.json may be:
33
+ * - absolute (`/abs/path/to/skills.json`)
34
+ * - relative to the air.json directory (`./skills/skills.json`, `../foo/skills.json`)
35
+ * - a URI (`github://…`) — passed through untouched
36
+ *
37
+ * We compare by absolute path when possible so "./skills/skills.json" and its
38
+ * fully-resolved absolute twin are recognized as the same entry.
39
+ */
40
+ function normalizeToAbsolute(entry, airJsonDir) {
41
+ if (/^[a-zA-Z][a-zA-Z0-9+\-.]*:\/\//.test(entry))
42
+ return entry;
43
+ if (isAbsolute(entry))
44
+ return resolve(entry);
45
+ return resolve(airJsonDir, entry);
46
+ }
47
+ /**
48
+ * Check whether `candidate` (an absolute path or URI) is already present in the
49
+ * given list of air.json entries. Performs path normalization so absolute,
50
+ * `./relative`, and `../relative` forms of the same file all collide.
51
+ */
52
+ export function entryAlreadyListed(candidateAbsOrUri, list, airJsonDir) {
53
+ if (!list || list.length === 0)
54
+ return false;
55
+ const isUri = /^[a-zA-Z][a-zA-Z0-9+\-.]*:\/\//.test(candidateAbsOrUri);
56
+ if (isUri) {
57
+ return list.includes(candidateAbsOrUri);
58
+ }
59
+ const candidateAbs = resolve(candidateAbsOrUri);
60
+ for (const entry of list) {
61
+ const normalized = normalizeToAbsolute(entry, airJsonDir);
62
+ if (normalized === candidateAbs)
63
+ return true;
64
+ }
65
+ return false;
66
+ }
67
+ /**
68
+ * Produce the relative path written to air.json for an absolute target.
69
+ *
70
+ * We emit `./` or `../`-prefixed relative paths for targets that live under
71
+ * or above the air.json directory respectively. Targets on an entirely
72
+ * different volume (uncommon) fall back to the absolute path.
73
+ */
74
+ function toAirJsonRelPath(absTarget, airJsonDir) {
75
+ const rel = relative(airJsonDir, absTarget);
76
+ if (!rel)
77
+ return "./";
78
+ if (rel.startsWith(".."))
79
+ return rel;
80
+ if (isAbsolute(rel))
81
+ return rel;
82
+ return "./" + rel;
83
+ }
84
+ /**
85
+ * Return all artifact-type entry arrays that are already present in the
86
+ * air.json, defaulting each to `[]` if absent so callers can push without
87
+ * pre-existence checks.
88
+ */
89
+ function ensureArray(data, key) {
90
+ if (!data[key])
91
+ data[key] = [];
92
+ return data[key];
93
+ }
94
+ function formatLabel(kind, target, type) {
95
+ if (kind === "catalog")
96
+ return `catalog '${target}'`;
97
+ if (kind === "airJson")
98
+ return `air.json '${target}'`;
99
+ return `${type} '${target}'`;
100
+ }
101
+ /**
102
+ * Add discovered entries to the user's air.json.
103
+ *
104
+ * Catalogs go into `catalogs[]`. Loose indexes go into the matching per-type
105
+ * array (`skills[]`, `mcp[]`, …). Nested `air.json` files land in
106
+ * `catalogs[]` because they describe a full composition at their location —
107
+ * the user can further edit the reference later. All additions are
108
+ * idempotent: an entry already present in air.json is not duplicated.
109
+ *
110
+ * If the target air.json does not exist, a minimal scaffold is written
111
+ * (no local index files — for a full workspace scaffold use `initConfig`).
112
+ */
113
+ export function addDiscoveredToAirJson(entries, options) {
114
+ const airJsonPath = options?.path ?? getDefaultAirJsonPath();
115
+ const airJsonDir = dirname(resolve(airJsonPath));
116
+ const { data, created } = loadOrScaffold(airJsonPath);
117
+ const added = [];
118
+ const skipped = [];
119
+ for (const catalog of entries.catalogs ?? []) {
120
+ const value = toAirJsonRelPath(catalog.path, airJsonDir);
121
+ const list = ensureArray(data, "catalogs");
122
+ if (entryAlreadyListed(catalog.path, list, airJsonDir)) {
123
+ skipped.push({
124
+ kind: "catalog",
125
+ value,
126
+ label: formatLabel("catalog", value),
127
+ });
128
+ continue;
129
+ }
130
+ list.push(value);
131
+ added.push({
132
+ kind: "catalog",
133
+ value,
134
+ label: formatLabel("catalog", value),
135
+ });
136
+ }
137
+ for (const airJson of entries.airJsons ?? []) {
138
+ // A nested air.json is semantically a catalog reference — the directory
139
+ // containing it typically follows the standard layout.
140
+ const catalogDir = dirname(airJson.path);
141
+ const value = toAirJsonRelPath(catalogDir, airJsonDir);
142
+ const list = ensureArray(data, "catalogs");
143
+ if (entryAlreadyListed(catalogDir, list, airJsonDir)) {
144
+ skipped.push({
145
+ kind: "airJson",
146
+ value,
147
+ label: formatLabel("airJson", value),
148
+ });
149
+ continue;
150
+ }
151
+ list.push(value);
152
+ added.push({
153
+ kind: "airJson",
154
+ value,
155
+ label: formatLabel("airJson", value),
156
+ });
157
+ }
158
+ for (const loose of entries.looseIndexes ?? []) {
159
+ if (!CATALOG_TYPES.includes(loose.type))
160
+ continue;
161
+ const value = toAirJsonRelPath(loose.path, airJsonDir);
162
+ const list = ensureArray(data, loose.type);
163
+ if (entryAlreadyListed(loose.path, list, airJsonDir)) {
164
+ skipped.push({
165
+ kind: "loose",
166
+ value,
167
+ type: loose.type,
168
+ label: formatLabel("loose", value, loose.type),
169
+ });
170
+ continue;
171
+ }
172
+ list.push(value);
173
+ added.push({
174
+ kind: "loose",
175
+ value,
176
+ type: loose.type,
177
+ label: formatLabel("loose", value, loose.type),
178
+ });
179
+ }
180
+ if (added.length > 0 || created) {
181
+ mkdirSync(dirname(airJsonPath), { recursive: true });
182
+ writeFileSync(airJsonPath, JSON.stringify(data, null, 2) + "\n");
183
+ }
184
+ return {
185
+ airJsonPath,
186
+ added,
187
+ skipped,
188
+ createdScaffold: created,
189
+ };
190
+ }
191
+ export function buildRegisteredChecker(airJsonPath) {
192
+ if (!airJsonPath || !existsSync(airJsonPath)) {
193
+ return {
194
+ catalog: () => false,
195
+ loose: () => false,
196
+ airJson: () => false,
197
+ };
198
+ }
199
+ let data;
200
+ try {
201
+ data = JSON.parse(readFileSync(airJsonPath, "utf-8"));
202
+ }
203
+ catch {
204
+ return {
205
+ catalog: () => false,
206
+ loose: () => false,
207
+ airJson: () => false,
208
+ };
209
+ }
210
+ const airJsonDir = dirname(resolve(airJsonPath));
211
+ return {
212
+ catalog(absPath) {
213
+ return entryAlreadyListed(absPath, data.catalogs, airJsonDir);
214
+ },
215
+ loose(type, absPath) {
216
+ const list = data[type];
217
+ if (entryAlreadyListed(absPath, list, airJsonDir))
218
+ return true;
219
+ return entryAlreadyListed(absPath, data.catalogs, airJsonDir);
220
+ },
221
+ airJson(absPath) {
222
+ const catalogDir = dirname(absPath);
223
+ return entryAlreadyListed(catalogDir, data.catalogs, airJsonDir);
224
+ },
225
+ };
226
+ }
227
+ //# sourceMappingURL=edit-air-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-air-json.js","sourceRoot":"","sources":["../src/edit-air-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAQ3D,MAAM,eAAe,GACnB,6DAA6D,CAAC;AAEhE,MAAM,aAAa,GAA2B;IAC5C,QAAQ;IACR,YAAY;IACZ,KAAK;IACL,SAAS;IACT,OAAO;IACP,OAAO;CACR,CAAC;AA8CF,SAAS,cAAc,CAAC,WAAmB;IAIzC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAiB;YAC7B,OAAO,EAAE,GAAG,eAAe,kBAAkB;YAC7C,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,4BAA4B;SAC1C,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;IACD,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CACb,GAAG,WAAW,2CAA2C,CAC1D,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAsB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,mBAAmB,CAC1B,KAAa,EACb,UAAkB;IAElB,IAAI,gCAAgC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,iBAAyB,EACzB,IAA0B,EAC1B,UAAkB;IAElB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,MAAM,KAAK,GAAG,gCAAgC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACvE,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChD,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,mBAAmB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC1D,IAAI,UAAU,KAAK,YAAY;YAAE,OAAO,IAAI,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,SAAiB,EAAE,UAAkB;IAC7D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACrC,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAChC,OAAO,IAAI,GAAG,GAAG,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAClB,IAAkB,EAClB,GAOW;IAEX,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAC/B,OAAO,IAAI,CAAC,GAAG,CAAa,CAAC;AAC/B,CAAC;AAED,SAAS,WAAW,CAClB,IAA6B,EAC7B,MAAc,EACd,IAAkB;IAElB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,YAAY,MAAM,GAAG,CAAC;IACrD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,aAAa,MAAM,GAAG,CAAC;IACtD,OAAO,GAAG,IAAI,KAAK,MAAM,GAAG,CAAC;AAC/B,CAAC;AAQD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA6B,EAC7B,OAA4B;IAE5B,MAAM,WAAW,GAAG,OAAO,EAAE,IAAI,IAAI,qBAAqB,EAAE,CAAC;IAC7D,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACjD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAEtD,MAAM,KAAK,GAAsB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,kBAAkB,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,SAAS;gBACf,KAAK;gBACL,KAAK,EAAE,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC;aACrC,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,SAAS;YACf,KAAK;YACL,KAAK,EAAE,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC7C,wEAAwE;QACxE,uDAAuD;QACvD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,kBAAkB,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,SAAS;gBACf,KAAK;gBACL,KAAK,EAAE,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC;aACrC,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,SAAS;YACf,KAAK;YACL,KAAK,EAAE,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;QAC/C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,OAAO;gBACb,KAAK;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;aAC/C,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,OAAO;YACb,KAAK;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;QAChC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACnE,CAAC;IAED,OAAO;QACL,WAAW;QACX,KAAK;QACL,OAAO;QACP,eAAe,EAAE,OAAO;KACzB,CAAC;AACJ,CAAC;AAYD,MAAM,UAAU,sBAAsB,CACpC,WAA0B;IAE1B,IAAI,CAAC,WAAW,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7C,OAAO;YACL,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;YACpB,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;YAClB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;SACrB,CAAC;IACJ,CAAC;IACD,IAAI,IAAkB,CAAC;IACvB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;YACpB,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;YAClB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;SACrB,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACjD,OAAO;QACL,OAAO,CAAC,OAAe;YACrB,OAAO,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAChE,CAAC;QACD,KAAK,CAAC,IAAiB,EAAE,OAAe;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAyB,CAAC;YAChD,IAAI,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC/D,OAAO,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,CAAC,OAAe;YACrB,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YACpC,OAAO,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { loadAirConfig, getDefaultAirJsonPath, getAirJsonPath, resolveArtifacts, mergeArtifacts, expandPlugins, 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, CacheFreshnessWarning, CacheRefreshResult, AirExtension, PrepareTransform, PluginEmitter, BuildMarketplaceOptions, BuiltPlugin, BuiltMarketplace, McpConfig, TransformContext, ExtensionCliOption, AgentSessionConfig, StartCommand, PrepareSessionOptions as CorePrepareSessionOptions, PreparedSession, LocalArtifacts, LocalSkillEntry, ValidationResult, ValidationError, ResolveOptions, SchemaType, } from "@pulsemcp/air-core";
1
+ export { loadAirConfig, getDefaultAirJsonPath, getAirJsonPath, resolveArtifacts, mergeArtifacts, expandPlugins, emptyArtifacts, validateJson, getSchemasDir, getSchemaPath, loadSchema, detectSchemaType, detectSchemaFromValue, getAllSchemaTypes, isValidSchemaType, MANIFEST_VERSION, getDefaultAirHome, getManifestPath, loadManifest, writeManifest, buildManifest, diffManifest, } from "@pulsemcp/air-core";
2
+ export type { AirConfig, ResolvedArtifacts, SkillEntry, ReferenceEntry, McpOAuthConfig, McpServerEntry, PluginAuthor, PluginEntry, RootEntry, HookEntry, AgentAdapter, CatalogProvider, CacheFreshnessWarning, CacheRefreshResult, AirExtension, PrepareTransform, PluginEmitter, BuildMarketplaceOptions, BuiltPlugin, BuiltMarketplace, McpConfig, TransformContext, ExtensionCliOption, AgentSessionConfig, StartCommand, PrepareSessionOptions as CorePrepareSessionOptions, PreparedSession, LocalArtifacts, LocalSkillEntry, ValidationResult, ValidationError, ResolveOptions, SchemaType, Manifest, ManifestSelection, ManifestDiff, } from "@pulsemcp/air-core";
3
3
  export { findAdapter, listAvailableAdapters, type FindAdapterOptions, } from "./adapter-registry.js";
4
4
  export { normalizeGitUrl, detectRoot } from "./root-detection.js";
5
5
  export { validateFile } from "./validate.js";
@@ -28,4 +28,12 @@ export { updateProviderCaches } from "./update.js";
28
28
  export type { UpdateProviderCachesOptions, UpdateProviderCachesResult, } from "./update.js";
29
29
  export { checkProviderFreshness } from "./cache-freshness.js";
30
30
  export { findUnresolvedVars, findUnresolvedHookVars, validateNoUnresolvedVars, unresolvedVarsMessage, } from "./validate-config.js";
31
+ export { discoverIndexes, resolveAnchor, CATALOG_TYPES, } from "./discover-indexes.js";
32
+ export type { DiscoveryResult, DiscoveredCatalog, DiscoveredLooseIndex, DiscoveredAirJson, DiscoverIndexesOptions, CatalogType, } from "./discover-indexes.js";
33
+ export { loadPreferences, savePreferences, addDismissed, isDismissed, getDefaultPreferencesPath, } from "./preferences.js";
34
+ export type { AirPreferences, DismissedDiscovery } from "./preferences.js";
35
+ export { addDiscoveredToAirJson, buildRegisteredChecker, entryAlreadyListed, } from "./edit-air-json.js";
36
+ export type { AirJsonAddition, EditAirJsonOptions, EditAirJsonResult, AddDiscoveredEntries, RegisteredChecker, } from "./edit-air-json.js";
37
+ export { findOfferableIndexes, acceptOffers, dismissOffers, } from "./auto-discovery.js";
38
+ export type { FindOfferableOptions, OfferableDiscoveryResult, AcceptDiscoveryOptions, DismissDiscoveryOptions, } from "./auto-discovery.js";
31
39
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,7 +5,9 @@ loadAirConfig, getDefaultAirJsonPath, getAirJsonPath, resolveArtifacts, mergeArt
5
5
  // Validation
6
6
  validateJson,
7
7
  // Schemas
8
- getSchemasDir, getSchemaPath, loadSchema, detectSchemaType, detectSchemaFromValue, getAllSchemaTypes, isValidSchemaType, } from "@pulsemcp/air-core";
8
+ getSchemasDir, getSchemaPath, loadSchema, detectSchemaType, detectSchemaFromValue, getAllSchemaTypes, isValidSchemaType,
9
+ // Manifest
10
+ MANIFEST_VERSION, getDefaultAirHome, getManifestPath, loadManifest, writeManifest, buildManifest, diffManifest, } from "@pulsemcp/air-core";
9
11
  // Adapter registry
10
12
  export { findAdapter, listAvailableAdapters, } from "./adapter-registry.js";
11
13
  // Root detection
@@ -31,4 +33,12 @@ export { updateProviderCaches } from "./update.js";
31
33
  export { checkProviderFreshness } from "./cache-freshness.js";
32
34
  // Config validation
33
35
  export { findUnresolvedVars, findUnresolvedHookVars, validateNoUnresolvedVars, unresolvedVarsMessage, } from "./validate-config.js";
36
+ // Repo-level index discovery (for `air start` / `air prepare` auto-registration)
37
+ export { discoverIndexes, resolveAnchor, CATALOG_TYPES, } from "./discover-indexes.js";
38
+ // User preferences (auto-discovery dismiss-set lives here)
39
+ export { loadPreferences, savePreferences, addDismissed, isDismissed, getDefaultPreferencesPath, } from "./preferences.js";
40
+ // air.json editing (adds discovered entries)
41
+ export { addDiscoveredToAirJson, buildRegisteredChecker, entryAlreadyListed, } from "./edit-air-json.js";
42
+ // Auto-discovery orchestration (used by `air start` / `air prepare`)
43
+ export { findOfferableIndexes, acceptOffers, dismissOffers, } from "./auto-discovery.js";
34
44
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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,aAAa,EACb,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;AA4C5B,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,qBAAqB,GAEtB,MAAM,uBAAuB,CAAC;AAE/B,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;AAOvC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AASjF,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGhE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAOtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAM5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpD,sBAAsB;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAMjD,mBAAmB;AACnB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,mBAAmB;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,4BAA4B;AAC5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAMnD,2BAA2B;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,oBAAoB;AACpB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
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,aAAa,EACb,cAAc;AACd,aAAa;AACb,YAAY;AACZ,UAAU;AACV,aAAa,EACb,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB;AACjB,WAAW;AACX,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,oBAAoB,CAAC;AAgD5B,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,qBAAqB,GAEtB,MAAM,uBAAuB,CAAC;AAE/B,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;AAOvC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AASjF,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGhE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAOtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAM5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpD,sBAAsB;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAMjD,mBAAmB;AACnB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,mBAAmB;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,4BAA4B;AAC5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAMnD,2BAA2B;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,oBAAoB;AACpB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,iFAAiF;AACjF,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,uBAAuB,CAAC;AAU/B,2DAA2D;AAC3D,OAAO,EACL,eAAe,EACf,eAAe,EACf,YAAY,EACZ,WAAW,EACX,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAG1B,6CAA6C;AAC7C,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAS5B,qEAAqE;AACrE,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,31 @@
1
+ export interface DismissedDiscovery {
2
+ /** Absolute path to the discovery anchor at the time of dismissal. */
3
+ repoRoot: string;
4
+ /** Path relative to `repoRoot` for the specific index file dismissed. */
5
+ indexPath: string;
6
+ }
7
+ export interface AirPreferences {
8
+ $schema?: string;
9
+ autoDiscovery?: {
10
+ dismissed?: DismissedDiscovery[];
11
+ };
12
+ }
13
+ /** Default location: `~/.air/preferences.json`, sibling to `air.json`. */
14
+ export declare function getDefaultPreferencesPath(): string;
15
+ /**
16
+ * Read the preferences file. Returns a structurally complete default when the
17
+ * file is missing or malformed so callers never need to null-check.
18
+ */
19
+ export declare function loadPreferences(path?: string): AirPreferences;
20
+ /** Write preferences to disk with 2-space indentation and trailing newline. */
21
+ export declare function savePreferences(prefs: AirPreferences, path?: string): void;
22
+ /**
23
+ * Add one or more (repoRoot, indexPath) entries to the dismissed-set.
24
+ * Idempotent — entries already present are not duplicated.
25
+ */
26
+ export declare function addDismissed(entries: DismissedDiscovery[], path?: string): AirPreferences;
27
+ /**
28
+ * True if the given (repoRoot, indexPath) pair is in the dismissed-set.
29
+ */
30
+ export declare function isDismissed(prefs: AirPreferences, entry: DismissedDiscovery): boolean;
31
+ //# sourceMappingURL=preferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../src/preferences.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE;QACd,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;KAClC,CAAC;CACH;AAED,0EAA0E;AAC1E,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AASD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CA4B7D;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAI1E;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,IAAI,CAAC,EAAE,MAAM,GACZ,cAAc,CAYhB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAKT"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preferences.js","sourceRoot":"","sources":["../src/preferences.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulsemcp/air-sdk",
3
- "version": "0.0.40",
3
+ "version": "0.0.41",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,7 +29,7 @@
29
29
  "lint": "tsc --noEmit"
30
30
  },
31
31
  "dependencies": {
32
- "@pulsemcp/air-core": "0.0.40"
32
+ "@pulsemcp/air-core": "0.0.41"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^22.10.0",