ios-agent-mcp 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +74 -7
  2. package/data/knowledge.json +1 -0
  3. package/dist/analyzers/memory.d.ts +12 -0
  4. package/dist/analyzers/memory.js +81 -0
  5. package/dist/analyzers/memory.js.map +1 -0
  6. package/dist/analyzers/performance.d.ts +10 -0
  7. package/dist/analyzers/performance.js +106 -0
  8. package/dist/analyzers/performance.js.map +1 -0
  9. package/dist/analyzers/security.d.ts +2 -0
  10. package/dist/analyzers/security.js +82 -0
  11. package/dist/analyzers/security.js.map +1 -0
  12. package/dist/analyzers/skill.d.ts +34 -0
  13. package/dist/analyzers/skill.js +483 -0
  14. package/dist/analyzers/skill.js.map +1 -0
  15. package/dist/analyzers/testing.d.ts +16 -0
  16. package/dist/analyzers/testing.js +135 -0
  17. package/dist/analyzers/testing.js.map +1 -0
  18. package/dist/analyzers/types.d.ts +19 -1
  19. package/dist/analyzers/types.js +65 -3
  20. package/dist/analyzers/types.js.map +1 -1
  21. package/dist/index.js +162 -5
  22. package/dist/index.js.map +1 -1
  23. package/dist/knowledge-server.d.ts +2 -0
  24. package/dist/knowledge-server.js +44 -0
  25. package/dist/knowledge-server.js.map +1 -0
  26. package/dist/knowledge.d.ts +78 -0
  27. package/dist/knowledge.js +69 -0
  28. package/dist/knowledge.js.map +1 -0
  29. package/dist/report.d.ts +10 -0
  30. package/dist/report.js +40 -0
  31. package/dist/report.js.map +1 -1
  32. package/dist/resources.d.ts +67 -0
  33. package/dist/resources.js +222 -0
  34. package/dist/resources.js.map +1 -0
  35. package/dist/result.d.ts +203 -0
  36. package/dist/result.js +135 -0
  37. package/dist/result.js.map +1 -0
  38. package/dist/scan.d.ts +9 -0
  39. package/dist/scan.js +110 -0
  40. package/dist/scan.js.map +1 -1
  41. package/dist/version.d.ts +1 -0
  42. package/dist/version.js +4 -0
  43. package/dist/version.js.map +1 -0
  44. package/mcp.json +76 -11
  45. package/package.json +19 -10
@@ -0,0 +1,69 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { z } from 'zod';
4
+ import { VERSION } from './version.js';
5
+ const bundle = JSON.parse(readFileSync(new URL('../data/knowledge.json', import.meta.url), 'utf8'));
6
+ const hints = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
7
+ const result = (value) => ({ content: [{ type: 'text', text: JSON.stringify(value) }] });
8
+ const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, '');
9
+ export function searchTechnologies(query, limit) {
10
+ const q = query.toLowerCase();
11
+ return bundle.catalog.technologies.map(t => ({ t, score: normalize(t.name) === normalize(query) ? 100 :
12
+ t.name.toLowerCase().includes(q) ? 50 : (t.summary + ' ' + t.categories.join(' ')).toLowerCase().includes(q) ? 10 : 0 }))
13
+ .filter(r => r.score > 0).sort((a, b) => b.score - a.score || a.t.name.localeCompare(b.t.name))
14
+ .slice(0, limit).map(({ t }) => ({ name: t.name, id: t.slug, url: t.url, summary: t.summary, categories: t.categories }));
15
+ }
16
+ export function lookupTechnology(id) {
17
+ const t = bundle.catalog.technologies.find(t => t.slug === id || normalize(t.name) === normalize(id));
18
+ if (!t)
19
+ return { error: 'Technology not found. Use search_apple_technologies first.' };
20
+ return { ...t, checkedAt: bundle.catalog.checkedAt, guideText: bundle.guides[t.guide],
21
+ evidence: 'Source snapshot and authored/reference guidance; not proof of runtime or compilation.' };
22
+ }
23
+ export function lookupUpdates(query, limit) {
24
+ const q = query.toLowerCase();
25
+ return { checkedAt: bundle.updates.checkedAt, results: bundle.updates.entries.filter(r => !q || r.title.toLowerCase().includes(q) || r.topics.some(t => t.title.toLowerCase().includes(q))).slice(0, limit),
26
+ evidence: 'Dated landing-page topic maps. Open version-specific Apple links for exact changes and current known issues.' };
27
+ }
28
+ export function validAppName(name) {
29
+ return /^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(name) && !/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i.test(name);
30
+ }
31
+ export function appPlan(name, brief) {
32
+ if (!validAppName(name))
33
+ throw new Error('Use a Swift-safe app name.');
34
+ return { name, brief, status: 'Implementation brief, not an app already built',
35
+ scaffold: { executable: 'npx', args: ['-y', '@nagarjuna2002/ios-agent@0.2.0', 'new', name, '--brief', brief, '--xcodegen'] },
36
+ phases: ['Turn the brief into screens, user flows, data models, and acceptance criteria.',
37
+ 'Use scaffold executable/args as an argument array; never interpolate the brief into a shell command.',
38
+ 'Implement the app with injected services, preview data, persistent state and explicit errors.',
39
+ 'Create separate Icon Composer SVG layers and import them as groups.',
40
+ 'Generate the Xcode project from App/project.yml, then build and test with the installed SDK.',
41
+ 'Inspect simulator screens and accessibility; iterate until the requested flows pass.'],
42
+ workflow: bundle.appWorkflow };
43
+ }
44
+ export function iconPlan(appName, concept) {
45
+ return { appName, concept, status: 'Layer specification; import and verify in Icon Composer',
46
+ background: { kind: 'native fill', note: 'Choose a solid color or gradient in Icon Composer; keep imported backgrounds full-bleed and opaque.' },
47
+ groups: [{ order: 1, name: '01-base', purpose: 'Large supporting silhouette', file: '01-base.svg' },
48
+ { order: 2, name: '02-symbol', purpose: 'Recognizable primary app symbol', file: '02-symbol.svg' },
49
+ { order: 3, name: '03-accent', purpose: 'Small distinguishing detail', file: '03-accent.svg' }],
50
+ checks: ['Separate editable SVG/PNG layers on a shared canvas', 'Maximum four foreground groups',
51
+ 'No baked-in system highlights, shadows, or icon corner mask', 'Preview Default, Dark, and Mono appearances',
52
+ 'Save and reopen the .icon document in Icon Composer; verify Xcode target assignment'],
53
+ guidance: bundle.iconGuide };
54
+ }
55
+ export function createKnowledgeServer() {
56
+ const server = new McpServer({ name: 'ios-agent-knowledge', version: VERSION }, { instructions: 'Look up Apple technologies and updates before implementation. This server reads only bundled public reference data; it cannot access local projects, write files, build, or publish apps. Use a local coding agent and CLI for implementation.' });
57
+ server.registerTool('search_apple_technologies', { title: 'Search Apple technologies', description: 'Find Apple frameworks, tools, services and legacy technologies in the bundled 405-entry source snapshot.',
58
+ inputSchema: { query: z.string().min(1).max(200), limit: z.number().int().min(1).max(30).default(10) }, annotations: hints }, async ({ query, limit }) => result({ checkedAt: bundle.catalog.checkedAt, results: searchTechnologies(query, limit) }));
59
+ server.registerTool('get_apple_technology', { title: 'Read Apple technology guide', description: 'Read a catalog technology, its local engineering guide, availability metadata and API topic links by exact name or returned id.',
60
+ inputSchema: { id: z.string().min(1).max(200) }, annotations: hints }, async ({ id }) => result(lookupTechnology(id)));
61
+ server.registerTool('get_apple_updates', { title: 'Find Apple updates and release notes', description: 'Search dated Apple update and release-note landing pages with version-specific source links. Does not claim live results.',
62
+ inputSchema: { query: z.string().max(200).default(''), limit: z.number().int().min(1).max(30).default(10) }, annotations: hints }, async ({ query, limit }) => result(lookupUpdates(query, limit)));
63
+ server.registerTool('plan_ios_app', { title: 'Plan an iOS app from a brief', description: 'Return an implementation workflow and safe CLI argument array for a named app. No files are created and no build is claimed.',
64
+ inputSchema: { name: z.string().max(64).refine(validAppName, 'Use a non-reserved Swift-safe app name'), brief: z.string().min(5).max(8000) }, annotations: hints }, async ({ name, brief }) => result(appPlan(name, brief)));
65
+ server.registerTool('plan_app_icon', { title: 'Plan layered Icon Composer artwork', description: 'Return a separate-layer icon specification, Apple workflow and appearance checks. Does not fabricate a native .icon document.',
66
+ inputSchema: { appName: z.string().min(1).max(100), concept: z.string().min(3).max(2000) }, annotations: hints }, async ({ appName, concept }) => result(iconPlan(appName, concept)));
67
+ return server;
68
+ }
69
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../src/knowledge.ts"],"names":[],"mappings":"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"}
package/dist/report.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Finding } from "./analyzers/types.js";
2
+ import { SkillLintResult } from "./analyzers/skill.js";
2
3
  /**
3
4
  * Render findings as readable markdown.
4
5
  *
@@ -9,3 +10,12 @@ import { Finding } from "./analyzers/types.js";
9
10
  export declare function renderFindings(title: string, findings: Finding[], scanned: number, options?: {
10
11
  limit?: number;
11
12
  }): string;
13
+ /**
14
+ * Render a skill-repository lint as markdown.
15
+ *
16
+ * Separate from `renderFindings` because the locations are markdown and YAML
17
+ * files — rendering a `tools:` line inside a `swift` fence would be a lie about
18
+ * what was inspected. The "Checked" section is not decoration: an empty report
19
+ * with no statement of scope is indistinguishable from a check that never ran.
20
+ */
21
+ export declare function renderSkillLint(result: SkillLintResult): string;
package/dist/report.js CHANGED
@@ -38,4 +38,44 @@ export function renderFindings(title, findings, scanned, options = {}) {
38
38
  "run `swift build` and `swift test` for that._");
39
39
  return lines.join("\n");
40
40
  }
41
+ const SEVERITY_RANK = { blocker: 0, serious: 1, minor: 2 };
42
+ /**
43
+ * Render a skill-repository lint as markdown.
44
+ *
45
+ * Separate from `renderFindings` because the locations are markdown and YAML
46
+ * files — rendering a `tools:` line inside a `swift` fence would be a lie about
47
+ * what was inspected. The "Checked" section is not decoration: an empty report
48
+ * with no statement of scope is indistinguishable from a check that never ran.
49
+ */
50
+ export function renderSkillLint(result) {
51
+ const { findings, checked } = result;
52
+ const sorted = [...findings].sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] ||
53
+ a.file.localeCompare(b.file) ||
54
+ a.line - b.line);
55
+ const lines = ["# Skill Repository Lint", "", "## Checked", ""];
56
+ lines.push(`- **SKILL.md:** ${checked.skillFile ? "found" : "**not found**"}`, `- **Subagent definitions:** ${checked.agentCount}`, checked.mirrorCheckSkipped
57
+ ? "- **Mirrors:** skipped — no file matches SKILL.md's body, so this repository does not use the generated-mirror pattern"
58
+ : `- **Mirrors compared:** ${checked.mirrorsCompared}`, `- **Referenced paths resolved:** ${checked.referencedPaths}`, "");
59
+ if (sorted.length === 0) {
60
+ lines.push("**No findings.** Frontmatter, agent tool permissions, mirror sync, and doc references all pass.", "", "_Metadata only. This does not check that the instructions are correct, only that they are well-formed and internally consistent._");
61
+ return lines.join("\n");
62
+ }
63
+ const counts = {
64
+ blocker: sorted.filter((f) => f.severity === "blocker").length,
65
+ serious: sorted.filter((f) => f.severity === "serious").length,
66
+ minor: sorted.filter((f) => f.severity === "minor").length,
67
+ };
68
+ lines.push(`## ${sorted.length} finding${sorted.length === 1 ? "" : "s"}`, "", `🔴 ${counts.blocker} blocker · 🟠 ${counts.serious} serious · 🟡 ${counts.minor} minor`, "");
69
+ for (const finding of sorted) {
70
+ const location = finding.line > 0 ? `${finding.file}:${finding.line}` : finding.file;
71
+ lines.push(`### ${ICON[finding.severity]} ${location} — ${finding.message}`, "");
72
+ if (finding.excerpt) {
73
+ lines.push("```", finding.excerpt, "```", "");
74
+ }
75
+ lines.push(`**Why it matters:** ${finding.consequence}`, "", `**Fix:** ${finding.fix}`, "", `_Rule \`${finding.rule}\`_`, "");
76
+ }
77
+ lines.push("---", "", "_Metadata only. This does not check that the instructions are correct, only " +
78
+ "that they are well-formed and internally consistent._");
79
+ return lines.join("\n");
80
+ }
41
81
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,IAAI,GAAwC;IAChD,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;CACZ,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,QAAmB,EACnB,OAAe,EACf,UAA8B,EAAE;IAEhC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,KAAK,GAAa,CAAC,KAAK,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IAE3C,KAAK,CAAC,IAAI,CACR,aAAa,OAAO,gBAAgB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,EAC/D,EAAE,CACH,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CACR,sDAAsD,EACtD,EAAE,EACF,kGAAkG,CACnG,CAAC;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM;QAC9D,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM;QAC9D,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;KAC3D,CAAC;IAEF,KAAK,CAAC,IAAI,CACR,KAAK,MAAM,CAAC,MAAM,WAAW,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO;QAChE,MAAM,MAAM,CAAC,OAAO,iBAAiB,MAAM,CAAC,OAAO,iBAAiB,MAAM,CAAC,KAAK,QAAQ,EAC1F,EAAE,CACH,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrC,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CACR,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE,EACpF,EAAE,EACF,UAAU,EACV,OAAO,CAAC,OAAO,EACf,KAAK,EACL,EAAE,EACF,uBAAuB,OAAO,CAAC,WAAW,EAAE,EAC5C,EAAE,EACF,YAAY,OAAO,CAAC,GAAG,EAAE,EACzB,EAAE,EACF,WAAW,OAAO,CAAC,IAAI,cAAc,OAAO,CAAC,GAAG,KAAK,EACrD,EAAE,CACH,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CACR,UAAU,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,oDAAoD,EAC1F,EAAE,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CACR,KAAK,EACL,EAAE,EACF,+EAA+E;QAC7E,+CAA+C,CAClD,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Resource-backed project state.
3
+ *
4
+ * Tools are verbs the model chooses to call. Resources are nouns a client can
5
+ * read without being asked — so `ios://project/info` lets a client attach the
6
+ * project's shape to context up front, instead of the model having to think to
7
+ * run an analysis first.
8
+ *
9
+ * WHY THERE IS A CONFIGURED ROOT
10
+ *
11
+ * Resources are addressed by a fixed URI with no arguments, so `ios://project/…`
12
+ * only means something if the server knows which project it is. MCP clients
13
+ * already configure servers per project — `.cursor/mcp.json` lives in the
14
+ * repository, `claude mcp add` is run from it — so a root passed at launch fits
15
+ * how the server is actually deployed.
16
+ *
17
+ * WHY THERE IS NO ios://project/build-status
18
+ *
19
+ * It would have to run `xcodebuild`. That needs macOS and Xcode, and it breaks
20
+ * the `filesystem: read, network: none` contract that lets this package install
21
+ * anywhere in ~26 KB. Build and simulator state belong in the separate package
22
+ * that already requires a full toolchain — see ROADMAP.md.
23
+ */
24
+ /**
25
+ * The directory `ios-agent` keeps its internal files in.
26
+ *
27
+ * Read-only here: this server never creates it. Its presence is used purely as
28
+ * a project-root marker, the same way git treats `.git` — which is what lets
29
+ * the CLI and this server agree on a root without either configuring the other.
30
+ */
31
+ export declare const INTERNAL_DIR = ".ios-agent";
32
+ /**
33
+ * Walk up from `start` looking for a directory containing `.ios-agent/`.
34
+ *
35
+ * Returns `undefined` rather than a fallback, so the caller decides what an
36
+ * absent marker means. Guessing here is how a server ends up analyzing a user's
37
+ * home directory because it was launched from the wrong place.
38
+ */
39
+ export declare function findProjectRootUpwards(start: string): string | undefined;
40
+ export type RootSource = "flag" | "environment" | "marker" | "cwd";
41
+ export interface ResolvedRoot {
42
+ readonly root: string;
43
+ readonly source: RootSource;
44
+ }
45
+ /**
46
+ * Resolve the project root, and say how.
47
+ *
48
+ * Order: `--project`, then `IOS_AGENT_PROJECT`, then the nearest ancestor with
49
+ * a `.ios-agent/` marker, then cwd. The marker step is what makes the server
50
+ * work when a client spawns it from a nested directory — previously that
51
+ * silently analyzed whatever subtree it happened to land in.
52
+ *
53
+ * The `source` travels with the root because an implicit root is unfalsifiable:
54
+ * an empty result looks identical whether the project has no Swift or the
55
+ * server is pointed somewhere else entirely.
56
+ */
57
+ export declare function resolveRootFrom(argv: string[], env: NodeJS.ProcessEnv): ResolvedRoot;
58
+ /** Resolve the project root from an explicit flag, the environment, a marker, or cwd. */
59
+ export declare function projectRootFrom(argv: string[], env: NodeJS.ProcessEnv): string;
60
+ export interface ResourcePayload {
61
+ uri: string;
62
+ mimeType: string;
63
+ text: string;
64
+ }
65
+ export declare function projectInfoResource(uri: string, root: string, source?: RootSource): Promise<ResourcePayload>;
66
+ export declare function projectDependenciesResource(uri: string, root: string): Promise<ResourcePayload>;
67
+ export declare function projectIssuesResource(uri: string, root: string): Promise<ResourcePayload>;
@@ -0,0 +1,222 @@
1
+ import { realpathSync, statSync } from "node:fs";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { analyzeConcurrency } from "./analyzers/concurrency.js";
4
+ import { analyzeArchitecture } from "./analyzers/architecture.js";
5
+ import { analyzeSwiftUI } from "./analyzers/swiftui.js";
6
+ import { analyzeAvailability } from "./analyzers/availability.js";
7
+ import { analyzeAppStore, analyzeProjectLevelAppStore } from "./analyzers/appstore.js";
8
+ import { analyzeMemory } from "./analyzers/memory.js";
9
+ import { analyzeSecurity } from "./analyzers/security.js";
10
+ import { analyzeTesting, analyzeTestCoverage } from "./analyzers/testing.js";
11
+ import { analyzePerformance } from "./analyzers/performance.js";
12
+ import { sortFindings } from "./analyzers/types.js";
13
+ import { readProjectContext, readSwiftFiles, resolveProjectRoot, summarizeProject, } from "./scan.js";
14
+ /**
15
+ * Resource-backed project state.
16
+ *
17
+ * Tools are verbs the model chooses to call. Resources are nouns a client can
18
+ * read without being asked — so `ios://project/info` lets a client attach the
19
+ * project's shape to context up front, instead of the model having to think to
20
+ * run an analysis first.
21
+ *
22
+ * WHY THERE IS A CONFIGURED ROOT
23
+ *
24
+ * Resources are addressed by a fixed URI with no arguments, so `ios://project/…`
25
+ * only means something if the server knows which project it is. MCP clients
26
+ * already configure servers per project — `.cursor/mcp.json` lives in the
27
+ * repository, `claude mcp add` is run from it — so a root passed at launch fits
28
+ * how the server is actually deployed.
29
+ *
30
+ * WHY THERE IS NO ios://project/build-status
31
+ *
32
+ * It would have to run `xcodebuild`. That needs macOS and Xcode, and it breaks
33
+ * the `filesystem: read, network: none` contract that lets this package install
34
+ * anywhere in ~26 KB. Build and simulator state belong in the separate package
35
+ * that already requires a full toolchain — see ROADMAP.md.
36
+ */
37
+ /**
38
+ * The directory `ios-agent` keeps its internal files in.
39
+ *
40
+ * Read-only here: this server never creates it. Its presence is used purely as
41
+ * a project-root marker, the same way git treats `.git` — which is what lets
42
+ * the CLI and this server agree on a root without either configuring the other.
43
+ */
44
+ export const INTERNAL_DIR = ".ios-agent";
45
+ /** How far up the tree to look. Guards against a symlink loop. */
46
+ const MAX_ASCENT = 64;
47
+ /**
48
+ * Walk up from `start` looking for a directory containing `.ios-agent/`.
49
+ *
50
+ * Returns `undefined` rather than a fallback, so the caller decides what an
51
+ * absent marker means. Guessing here is how a server ends up analyzing a user's
52
+ * home directory because it was launched from the wrong place.
53
+ */
54
+ export function findProjectRootUpwards(start) {
55
+ let current = resolve(start);
56
+ for (let step = 0; step < MAX_ASCENT; step += 1) {
57
+ try {
58
+ if (statSync(join(current, INTERNAL_DIR)).isDirectory())
59
+ return realpathSync(current);
60
+ }
61
+ catch {
62
+ // Not here; keep walking.
63
+ }
64
+ const parent = dirname(current);
65
+ if (parent === current)
66
+ return undefined;
67
+ current = parent;
68
+ }
69
+ return undefined;
70
+ }
71
+ /**
72
+ * Resolve the project root, and say how.
73
+ *
74
+ * Order: `--project`, then `IOS_AGENT_PROJECT`, then the nearest ancestor with
75
+ * a `.ios-agent/` marker, then cwd. The marker step is what makes the server
76
+ * work when a client spawns it from a nested directory — previously that
77
+ * silently analyzed whatever subtree it happened to land in.
78
+ *
79
+ * The `source` travels with the root because an implicit root is unfalsifiable:
80
+ * an empty result looks identical whether the project has no Swift or the
81
+ * server is pointed somewhere else entirely.
82
+ */
83
+ export function resolveRootFrom(argv, env) {
84
+ const flagIndex = argv.indexOf("--project");
85
+ if (flagIndex !== -1 && argv[flagIndex + 1]) {
86
+ return { root: resolve(argv[flagIndex + 1]), source: "flag" };
87
+ }
88
+ if (env.IOS_AGENT_PROJECT) {
89
+ return { root: resolve(env.IOS_AGENT_PROJECT), source: "environment" };
90
+ }
91
+ const cwd = resolve(env.PWD ?? process.cwd());
92
+ const marker = findProjectRootUpwards(cwd);
93
+ if (marker)
94
+ return { root: marker, source: "marker" };
95
+ return { root: cwd, source: "cwd" };
96
+ }
97
+ /** Resolve the project root from an explicit flag, the environment, a marker, or cwd. */
98
+ export function projectRootFrom(argv, env) {
99
+ return resolveRootFrom(argv, env).root;
100
+ }
101
+ /**
102
+ * Every resource states the root it used.
103
+ *
104
+ * The root is implicit — it comes from a flag, the environment, or the working
105
+ * directory the client happened to spawn the server in. A reader who cannot see
106
+ * which of those won has no way to tell an empty project from a wrong path.
107
+ */
108
+ function payload(uri, body) {
109
+ return {
110
+ uri,
111
+ mimeType: "application/json",
112
+ text: `${JSON.stringify(body, null, 2)}\n`,
113
+ };
114
+ }
115
+ function unavailable(uri, root, reason) {
116
+ return payload(uri, {
117
+ project_root: root,
118
+ available: false,
119
+ reason,
120
+ fix: "Launch the server with `--project /path/to/project`, set IOS_AGENT_PROJECT, or run it from a directory under one holding a `.ios-agent/` marker. MCP clients usually set this in the per-project config file.",
121
+ });
122
+ }
123
+ /** Scan once; every resource in a read is served from the same snapshot. */
124
+ async function snapshot(root) {
125
+ const resolved = await resolveProjectRoot(root);
126
+ const [files, context] = await Promise.all([
127
+ readSwiftFiles(resolved),
128
+ readProjectContext(resolved),
129
+ ]);
130
+ return { resolved, files, context };
131
+ }
132
+ export async function projectInfoResource(uri, root, source) {
133
+ try {
134
+ const { resolved, files } = await snapshot(root);
135
+ if (files.length === 0) {
136
+ return unavailable(uri, resolved, "No Swift files found under this path.");
137
+ }
138
+ const summary = await summarizeProject(resolved, files);
139
+ return payload(uri, {
140
+ project_root: resolved,
141
+ resolved_from: source ?? "cwd",
142
+ available: true,
143
+ swift_files: summary.swiftFileCount,
144
+ lines: summary.lineCount,
145
+ deployment_target: summary.deploymentTarget,
146
+ swift_tools_version: summary.swiftToolsVersion,
147
+ ui_framework: summary.uiFramework,
148
+ architecture: summary.architecture,
149
+ // The evidence ships with the verdict. "MVVM" alone is a guess presented
150
+ // as a fact; the reader must be able to check it.
151
+ architecture_evidence: summary.architectureEvidence,
152
+ uses_dependency_injection: summary.usesDependencyInjection,
153
+ has_tests: summary.hasTests,
154
+ has_package_swift: summary.hasPackageSwift,
155
+ has_xcode_project: summary.hasXcodeProject,
156
+ frameworks: summary.frameworks,
157
+ });
158
+ }
159
+ catch (error) {
160
+ return unavailable(uri, root, error instanceof Error ? error.message : String(error));
161
+ }
162
+ }
163
+ export async function projectDependenciesResource(uri, root) {
164
+ try {
165
+ const { resolved, files } = await snapshot(root);
166
+ const summary = await summarizeProject(resolved, files);
167
+ return payload(uri, {
168
+ project_root: resolved,
169
+ available: true,
170
+ third_party: summary.dependencies,
171
+ // Apple frameworks are not dependencies you manage, but they are the
172
+ // best available signal for what the app actually does.
173
+ apple_frameworks: summary.frameworks,
174
+ });
175
+ }
176
+ catch (error) {
177
+ return unavailable(uri, root, error instanceof Error ? error.message : String(error));
178
+ }
179
+ }
180
+ export async function projectIssuesResource(uri, root) {
181
+ try {
182
+ const { resolved, files, context } = await snapshot(root);
183
+ if (files.length === 0) {
184
+ return unavailable(uri, resolved, "No Swift files found under this path.");
185
+ }
186
+ const categories = {
187
+ concurrency: files.flatMap(analyzeConcurrency),
188
+ architecture: files.flatMap(analyzeArchitecture),
189
+ swiftui: files.flatMap(analyzeSwiftUI),
190
+ availability: files.flatMap(analyzeAvailability),
191
+ memory: files.flatMap(analyzeMemory),
192
+ security: files.flatMap(analyzeSecurity),
193
+ performance: files.flatMap(analyzePerformance),
194
+ testing: [...analyzeTestCoverage(files), ...files.flatMap(analyzeTesting)],
195
+ app_store: [
196
+ ...analyzeProjectLevelAppStore(context),
197
+ ...files.flatMap((file) => analyzeAppStore(file, context)),
198
+ ],
199
+ };
200
+ const all = sortFindings(Object.values(categories).flat());
201
+ return payload(uri, {
202
+ project_root: resolved,
203
+ available: true,
204
+ files_checked: files.length,
205
+ counts: {
206
+ blocker: all.filter((f) => f.severity === "blocker").length,
207
+ serious: all.filter((f) => f.severity === "serious").length,
208
+ minor: all.filter((f) => f.severity === "minor").length,
209
+ total: all.length,
210
+ },
211
+ by_category: Object.fromEntries(Object.entries(categories).map(([name, found]) => [name, found.length])),
212
+ // Capped: a resource is attached to context wholesale, so an unbounded
213
+ // list would crowd out the conversation it is meant to inform.
214
+ issues: all.slice(0, 100),
215
+ truncated: all.length > 100 ? all.length - 100 : 0,
216
+ });
217
+ }
218
+ catch (error) {
219
+ return unavailable(uri, root, error instanceof Error ? error.message : String(error));
220
+ }
221
+ }
222
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}