@macroscope/cli 0.0.0 → 0.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/version.ts","../../../contracts/src/version.ts","../../../contracts/src/fs.ts","../../../contracts/src/manifest.ts","../../../contracts/src/payload.ts","../../../contracts/src/search.ts","../../../contracts/src/api.ts","../../../contracts/src/error.ts","../../src/core/manifest.ts","../../src/core/handler.ts","../../src/core/project.ts","../../src/core/blueprints.ts","../../src/core/scanner.ts"],"sourcesContent":["export const VERSION = '0.0.0';\n","/**\n * Wire-format version for cloud-side documents (MeilisearchDoc). Bumped when\n * the doc shape changes in a way that requires reindexing. The catch-up scan\n * watches for a mismatch with the server-reported version and triggers a full\n * re-push (see `catchup.ts`).\n */\nexport const SCHEMA_VERSION = 1 as const;\nexport type SchemaVersion = typeof SCHEMA_VERSION;\n","/**\n * Filesystem paths macroscope reads and writes. Two roots:\n *\n * user — under `~/.macroscope/`; survives across projects.\n * project — under `<project>/.macroscope/`; specific to a worktree.\n *\n * Paths are POSIX-style and relative to their root. Callers resolve them\n * against the relevant base directory (`os.homedir()` or the project root).\n */\nexport const FILESYSTEM_LAYOUT = {\n user: {\n /** `~/.macroscope/` */\n rootDir: '.macroscope',\n /** `~/.macroscope/credentials` — OAuth token store, mode 0600. */\n credentialsFile: '.macroscope/credentials',\n /** `~/.macroscope/machine-id` — stable per-install identifier. */\n machineIdFile: '.macroscope/machine-id',\n },\n project: {\n /** `<project>/.macroscope/` */\n rootDir: '.macroscope',\n /** `<project>/.macroscope/blueprints/` — one folder per kind. */\n blueprintsDir: '.macroscope/blueprints',\n /** `<project>/.macroscope/cache/` */\n cacheDir: '.macroscope/cache',\n /** `<project>/.macroscope/cache/hashes.json` — content-hash cache used by catch-up scan. */\n hashesFile: '.macroscope/cache/hashes.json',\n /** `<project>/.macroscope/cache/queue.json` — watcher push queue, survives restart. */\n queueFile: '.macroscope/cache/queue.json',\n },\n} as const;\n\nexport type FilesystemLayout = typeof FILESYSTEM_LAYOUT;\n","import { z } from 'zod';\n\n/**\n * The on-disk `macroscope.yaml` manifest. Substrate-level fields are listed\n * explicitly; blueprints may attach additional kind-specific fields, which\n * pass through unchanged (`.passthrough()`).\n */\nexport const BlockManifestSchema = z\n .object({\n /** Must reference a registered blueprint's `kind`. */\n kind: z.string().min(1),\n /** Optional override for the auto-derived block id (POSIX relative path). */\n id: z.string().optional(),\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n source: z.string().optional(),\n preview: z.string().optional(),\n docs: z.string().optional(),\n tests: z.union([z.string(), z.array(z.string())]).optional(),\n })\n .passthrough();\n\nexport type BlockManifest = z.infer<typeof BlockManifestSchema>;\n","import { z } from 'zod';\n\n/**\n * One exported symbol from a block's source files. Extracted by the TS\n * compiler API. `signature` is the rendered TypeScript signature string\n * (e.g. `function foo(x: string): number`); the exact rendering is the\n * extractor's responsibility (see T5).\n */\nexport const SymbolSignatureSchema = z.object({\n name: z.string().min(1),\n kind: z.string().min(1),\n signature: z.string(),\n});\nexport type SymbolSignature = z.infer<typeof SymbolSignatureSchema>;\n\n/**\n * What the watcher pushes to the cloud per block. The cloud combines this\n * with cloud-side fields (repo, worktreeId, path, lastActiveAt, contentHash)\n * to form the `MeilisearchDoc` that lands in the user's index.\n */\nexport const UploadPayloadSchema = z.object({\n /** Stable block id (POSIX relative path or manifest `id` override). */\n blockId: z.string().min(1),\n kind: z.string().min(1),\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n /** Exported symbols extracted from the block's source files. */\n symbols: z.array(SymbolSignatureSchema),\n /** First ~500 chars of the README, if any. */\n readmeExcerpt: z.string().optional(),\n});\nexport type UploadPayload = z.infer<typeof UploadPayloadSchema>;\n\n/**\n * The doc shape stored in Meilisearch. Identity is the tuple\n * (repo, worktreeId, blockId): two worktrees of the same repo produce\n * distinct docs and filter independently.\n */\nexport const MeilisearchDocSchema = UploadPayloadSchema.extend({\n /** SHA-256 over the canonical JSON of the UploadPayload (see T6). */\n contentHash: z.string().min(1),\n /** Git remote URL (normalised) or local repo name when no remote exists. */\n repo: z.string().min(1),\n /** hash(machineUuid + absolutePath) — see ARCHITECTURE.md. */\n worktreeId: z.string().min(1),\n /** POSIX path from the worktree root to the block folder. */\n path: z.string().min(1),\n /** Unix epoch milliseconds. Refreshed on every push and by `/scope/touch`. */\n lastActiveAt: z.number().int().nonnegative(),\n});\nexport type MeilisearchDoc = z.infer<typeof MeilisearchDocSchema>;\n","import { z } from 'zod';\n\n/**\n * One cloud-side search result. Returned by `GET /search`. Carries enough\n * to render a result row without a second fetch.\n */\nexport const BlockHitSchema = z.object({\n blockId: z.string().min(1),\n kind: z.string().min(1),\n name: z.string().optional(),\n description: z.string().optional(),\n repo: z.string().min(1),\n worktreeId: z.string().min(1),\n path: z.string().min(1),\n /** Relevance score from Meilisearch hybrid ranking. Larger = more relevant. */\n score: z.number(),\n});\nexport type BlockHit = z.infer<typeof BlockHitSchema>;\n\n/**\n * One local-side code search result. Produced by `git grep` (T10). Lives in\n * contracts so the UI's merged-results view can speak one type.\n */\nexport const CodeMatchSchema = z.object({\n /** POSIX path from the worktree root. */\n file: z.string().min(1),\n /** 1-based line number. */\n line: z.number().int().positive(),\n /** 1-based column number, when available. */\n column: z.number().int().positive().optional(),\n /** A single line of source text containing the match. */\n preview: z.string(),\n});\nexport type CodeMatch = z.infer<typeof CodeMatchSchema>;\n","import { z } from 'zod';\nimport { MeilisearchDocSchema } from './payload.js';\nimport { BlockHitSchema } from './search.js';\n\n/* ------------------------------ POST /index/batch ------------------------------ */\n\nexport const IndexBatchRequestSchema = z.object({\n /** Per-block docs to upsert. The cloud routes these to the user's Meilisearch index. */\n upserts: z.array(MeilisearchDocSchema),\n /** Block ids to delete. Empty array is valid (upsert-only batch). */\n deletes: z.array(z.string().min(1)),\n});\nexport type IndexBatchRequest = z.infer<typeof IndexBatchRequestSchema>;\n\nexport const IndexBatchResponseSchema = z.object({\n /** Unix epoch ms of server-side acknowledgement. */\n acceptedAt: z.number().int().nonnegative(),\n /** Number of upserts accepted (deletes excluded). */\n accepted: z.number().int().nonnegative(),\n});\nexport type IndexBatchResponse = z.infer<typeof IndexBatchResponseSchema>;\n\n/* --------------------------------- GET /search --------------------------------- */\n\nexport const SearchRequestSchema = z.object({\n q: z.string().min(1),\n /** Restrict to one worktree. Omit to search across all of the user's worktrees. */\n worktreeId: z.string().optional(),\n /** Restrict to one repo. */\n repo: z.string().optional(),\n /** Restrict to one block kind. */\n kind: z.string().optional(),\n /** Cap on returned hits. Server enforces an upper bound. */\n limit: z.number().int().positive().optional(),\n});\nexport type SearchRequest = z.infer<typeof SearchRequestSchema>;\n\nexport const SearchResponseSchema = z.object({\n hits: z.array(BlockHitSchema),\n /** Approximate total match count from Meilisearch (estimated, not exact). */\n totalEstimated: z.number().int().nonnegative(),\n});\nexport type SearchResponse = z.infer<typeof SearchResponseSchema>;\n\n/* --------------------------------- DELETE /index -------------------------------- */\n\nexport const DeleteIndexResponseSchema = z.object({\n deletedAt: z.number().int().nonnegative(),\n});\nexport type DeleteIndexResponse = z.infer<typeof DeleteIndexResponseSchema>;\n\n/* ------------------------------ POST /scope/touch ------------------------------ */\n\nexport const ScopeTouchRequestSchema = z.object({\n worktreeId: z.string().min(1),\n repo: z.string().min(1),\n});\nexport type ScopeTouchRequest = z.infer<typeof ScopeTouchRequestSchema>;\n\nexport const ScopeTouchResponseSchema = z.object({\n touchedAt: z.number().int().nonnegative(),\n});\nexport type ScopeTouchResponse = z.infer<typeof ScopeTouchResponseSchema>;\n\n/* --------------------------------- GET /health --------------------------------- */\n\nexport const HealthResponseSchema = z.object({\n status: z.literal('ok'),\n schemaVersion: z.number().int().positive(),\n});\nexport type HealthResponse = z.infer<typeof HealthResponseSchema>;\n\n/**\n * Endpoint manifest. One row per route, suitable for type-checking a server\n * router and a typed client against a single source of truth.\n *\n * Serialization convention: for `method: 'GET'` endpoints the request schema's\n * fields are sent as URL query parameters (never a body). For `POST`/`DELETE`\n * the request schema is the JSON body. `request: null` means the endpoint\n * takes no request payload at all.\n */\nexport const API_ENDPOINTS = {\n indexBatch: {\n method: 'POST',\n path: '/index/batch',\n request: IndexBatchRequestSchema,\n response: IndexBatchResponseSchema,\n },\n search: {\n method: 'GET',\n path: '/search',\n request: SearchRequestSchema,\n response: SearchResponseSchema,\n },\n deleteIndex: {\n method: 'DELETE',\n path: '/index',\n request: null,\n response: DeleteIndexResponseSchema,\n },\n scopeTouch: {\n method: 'POST',\n path: '/scope/touch',\n request: ScopeTouchRequestSchema,\n response: ScopeTouchResponseSchema,\n },\n health: {\n method: 'GET',\n path: '/health',\n request: null,\n response: HealthResponseSchema,\n },\n} as const;\n\nexport type ApiEndpoints = typeof API_ENDPOINTS;\n","import { z } from 'zod';\n\n/**\n * The uniform error shape returned by every API endpoint on failure. Per the\n * CLAUDE.md invariant: errors name the file path and the broken field where\n * applicable.\n */\nexport const ErrorEnvelopeSchema = z.object({\n error: z.object({\n /** Stable machine-readable code (e.g. `unauthorized`, `validation_failed`). */\n code: z.string().min(1),\n /** Human-readable message. */\n message: z.string().min(1),\n /** Source file path when the error originates from parsing a manifest or other on-disk artifact. Set by the CLI side (see `ScanError`) and by the cloud when validating uploaded manifests. */\n file: z.string().optional(),\n /** Path of the offending field when the error is validation-related. */\n field: z.string().optional(),\n /** Server-assigned request id for log correlation. */\n requestId: z.string().optional(),\n }),\n});\n\nexport type ErrorEnvelope = z.infer<typeof ErrorEnvelopeSchema>;\n","import { type BlockManifest, BlockManifestSchema } from '@macroscope/contracts';\n\nexport const manifestSchema = BlockManifestSchema;\nexport type Manifest = BlockManifest;\n","/**\n * The locked substrate contract. The v1 control layer extends this interface;\n * it never bypasses it.\n *\n * A `Handler` is what a blueprint exports. It declares a `kind` and zero or more\n * optional async operations. Each operation returns data — never side effects —\n * and never throws \"not implemented\"; missing methods simply mean the operation\n * isn't supported for that kind.\n *\n * No top-level side effects on import. Importing a handler must not spawn\n * processes, open ports, or read files. Side effects belong inside methods.\n *\n * Trust model: blueprints are USER-AUTHORED CODE in the user's own project.\n * The loader imports them via jiti and runs them at full process privilege.\n * This is the same trust model as a `package.json` postinstall script, an\n * ESLint plugin, a Storybook addon, or a vite.config.ts — code in your repo\n * runs as you. There is no sandbox. If you do not trust a blueprint, do not\n * put it in your project.\n */\nexport interface Handler {\n /** Required. Must match the blueprint folder name. */\n kind: string;\n /** Named views shown as tabs in the block-detail page. v1 ships iframe + terminal types. */\n views?: Record<string, ViewSpec>;\n /** Produce something the UI/CLI/MCP can display for this block. */\n render?: (block: Block) => Promise<RenderResult>;\n /** Run whatever counts as a test for this kind. */\n test?: (block: Block) => Promise<TestResult>;\n /** Produce build artifacts for this kind. */\n build?: (block: Block) => Promise<BuildResult>;\n /** Create a new block of this kind in `targetDir` with the given name. */\n scaffold?: (targetDir: string, name: string) => Promise<void>;\n /** Generate a free-form textual description of a block, used by semantic search. */\n describe?: (block: Block) => Promise<string>;\n}\n\n/**\n * A block is an instance of a kind: a folder somewhere in the user's project\n * with a `macroscope.yaml`. Handlers receive these as input.\n *\n * For M0 (this PR) we don't actually load blocks yet — this type exists so the\n * Handler interface can be locked.\n */\nexport interface Block {\n /** Stable identifier. POSIX relative path from project root by default; overridable via the manifest `id` field. */\n id: string;\n /** Absolute path to the block's folder. */\n path: string;\n /** Parsed and validated manifest. */\n manifest: BlockManifest;\n}\n\n/**\n * The manifest is the data side of a block (the `macroscope.yaml`). The shape\n * here is the substrate's view of it; individual blueprints may require\n * additional fields under their own `kind`.\n */\nexport interface BlockManifest {\n /** Must reference a registered blueprint's `kind`. */\n kind: string;\n /** Optional override for the auto-derived block id. */\n id?: string;\n name?: string;\n description?: string;\n tags?: string[];\n source?: string;\n preview?: string;\n docs?: string;\n tests?: string | string[];\n /** Unknown fields pass through to handlers per the v0 spec — never errors. */\n [field: string]: unknown;\n}\n\n/**\n * A view is one tab in the block-detail page. Three view types exist:\n * - iframe: embed any URL the blueprint resolves.\n * - terminal: spawn the resolved command server-side and stream its\n * stdin/stdout/stderr to a browser xterm.js terminal.\n * - hybrid: combine a static artifact (iframe URL) with an on-demand\n * command (terminal). UI shows the URL by default and a Run button\n * that switches to the terminal and spawns the command.\n */\nexport type ViewSpec = IframeViewSpec | TerminalViewSpec | HybridViewSpec;\n\nexport interface IframeViewSpec {\n type: 'iframe';\n url: string | ((block: Block) => string | Promise<string>);\n /** Optional backing service. macroscope spawns this on demand the first time the\n * view is opened in the UI, polls readyWhen.url, and only loads the iframe\n * once the service responds. */\n service?: ServiceSpec;\n}\n\nexport interface ServiceSpec {\n /** Human-readable label shown in the \"starting…\" state. Defaults to command[0]. */\n name?: string;\n /** argv-style command. Function form is resolved server-side per block. */\n command: string[] | ((block: Block) => string[] | Promise<string[]>);\n /** Working directory. Defaults to project root. */\n cwd?: string | ((block: Block) => string | Promise<string>);\n /** Service is ready when this URL responds with any non-5xx status. */\n readyWhen: { url: string };\n /** Max ms to wait for readiness before declaring failure. Default: 30_000. */\n startupTimeoutMs?: number;\n}\n\nexport interface TerminalViewSpec {\n type: 'terminal';\n /** argv-style: ['vitest', 'run', '<file>']. Function form is resolved server-side per block. */\n command: string[] | ((block: Block) => string[] | Promise<string[]>);\n}\n\n/**\n * A hybrid view shows a static artifact (e.g. test source code) by default and\n * lets the user switch to a terminal that runs an on-demand command (e.g.\n * `vitest run`) via a Run button. Useful for \"read code → press button → see\n * what happens → toggle back\" workflows.\n */\nexport interface HybridViewSpec {\n type: 'hybrid';\n /** Static artifact URL. Same semantics as IframeViewSpec.url. */\n url: string | ((block: Block) => string | Promise<string>);\n /** On-demand command. Same semantics as TerminalViewSpec.command. */\n command: string[] | ((block: Block) => string[] | Promise<string[]>);\n /** Label for the Run button. Default: \"Run\". */\n runLabel?: string;\n /** Label for the code-side toggle. Default: \"Code\". */\n codeLabel?: string;\n /** Label for the terminal-side toggle. Default: \"Terminal\". */\n terminalLabel?: string;\n}\n\nexport type RenderResult =\n | { type: 'iframe'; entry: string }\n | { type: 'html'; html: string }\n | { type: 'markdown'; source: string }\n | { type: 'image'; src: string }\n | { type: 'error'; message: string }\n | { type: 'none'; reason: string };\n\nexport type TestResult =\n | { type: 'pass'; output?: string }\n | { type: 'fail'; output: string }\n | { type: 'error'; message: string }\n | { type: 'none'; reason: string };\n\nexport type BuildResult =\n | { type: 'ok'; artifacts?: string[] }\n | { type: 'error'; message: string }\n | { type: 'none'; reason: string };\n\n/**\n * Convenience type guard for runtime validation. Used by the blueprint loader\n * to verify that a default export looks like a Handler before accepting it.\n */\nexport function isHandler(value: unknown): value is Handler {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n if (typeof v.kind !== 'string' || v.kind.length === 0) return false;\n for (const method of ['render', 'test', 'build', 'scaffold', 'describe'] as const) {\n if (v[method] !== undefined && typeof v[method] !== 'function') return false;\n }\n if (v.views !== undefined) {\n if (typeof v.views !== 'object' || v.views === null) return false;\n for (const [, spec] of Object.entries(v.views as Record<string, unknown>)) {\n if (!isViewSpec(spec)) return false;\n }\n }\n return true;\n}\n\nfunction isViewSpec(value: unknown): value is ViewSpec {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n switch (v.type) {\n case 'iframe':\n if (typeof v.url !== 'string' && typeof v.url !== 'function') return false;\n if (v.service !== undefined && !isServiceSpec(v.service)) return false;\n return true;\n case 'terminal':\n return (\n typeof v.command === 'function' ||\n (Array.isArray(v.command) && v.command.every((c) => typeof c === 'string'))\n );\n case 'hybrid': {\n const urlOk = typeof v.url === 'string' || typeof v.url === 'function';\n const commandOk =\n typeof v.command === 'function' ||\n (Array.isArray(v.command) && v.command.every((c) => typeof c === 'string'));\n if (!urlOk || !commandOk) return false;\n for (const key of ['runLabel', 'codeLabel', 'terminalLabel'] as const) {\n if (v[key] !== undefined && typeof v[key] !== 'string') return false;\n }\n return true;\n }\n default:\n return false;\n }\n}\n\nfunction isServiceSpec(value: unknown): value is ServiceSpec {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n const commandOk =\n typeof v.command === 'function' ||\n (Array.isArray(v.command) && v.command.every((c) => typeof c === 'string'));\n if (!commandOk) return false;\n if (typeof v.readyWhen !== 'object' || v.readyWhen === null) return false;\n const ready = v.readyWhen as Record<string, unknown>;\n if (typeof ready.url !== 'string') return false;\n if (v.name !== undefined && typeof v.name !== 'string') return false;\n if (v.cwd !== undefined && typeof v.cwd !== 'string' && typeof v.cwd !== 'function') {\n return false;\n }\n if (v.startupTimeoutMs !== undefined && typeof v.startupTimeoutMs !== 'number') return false;\n return true;\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { z } from 'zod';\n\nexport const projectConfigSchema = z.object({\n scanRoots: z.array(z.string()).default(['.']),\n ignore: z.array(z.string()).default(['node_modules', '.git', 'dist', '.macroscope']),\n});\n\nexport type ProjectConfig = z.infer<typeof projectConfigSchema>;\n\nexport interface Project {\n /** Absolute path to the project root (the directory containing .macroscope/). */\n root: string;\n /** Parsed .macroscope/config.yaml, with defaults filled in. */\n config: ProjectConfig;\n}\n\nexport class ProjectNotFoundError extends Error {\n constructor(startedFrom: string) {\n super(\n `No macroscope project found. Walked up from ${startedFrom} looking for a .macroscope/ directory but reached the filesystem root. Run \\`npm create macroscope\\` to scaffold one, or cd into an existing project.`,\n );\n this.name = 'ProjectNotFoundError';\n }\n}\n\n/**\n * Find the project root by walking up from `cwd` looking for a `.macroscope/`\n * directory. The macroscope root is the directory that *contains* `.macroscope`.\n * If config.yaml is present inside, it is parsed; otherwise defaults are used.\n */\nexport async function findProject(cwd: string = process.cwd()): Promise<Project> {\n const startedFrom = resolve(cwd);\n let current = startedFrom;\n while (true) {\n if (existsSync(join(current, '.macroscope'))) {\n return { root: current, config: await loadConfig(current) };\n }\n const parent = dirname(current);\n if (parent === current) {\n throw new ProjectNotFoundError(startedFrom);\n }\n current = parent;\n }\n}\n\nasync function loadConfig(root: string): Promise<ProjectConfig> {\n const configPath = join(root, '.macroscope', 'config.yaml');\n if (!existsSync(configPath)) {\n return projectConfigSchema.parse({});\n }\n const raw = await readFile(configPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = parseYaml(raw) ?? {};\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse ${configPath}: ${msg}`);\n }\n const result = projectConfigSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('\\n');\n throw new Error(`Invalid project config at ${configPath}:\\n${issues}`);\n }\n return result.data;\n}\n","import { type Dirent, existsSync } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createJiti } from 'jiti';\nimport { type Handler, isHandler } from './handler.js';\nimport type { Project } from './project.js';\n\n/** Filenames tried, in order. First match wins. */\nconst HANDLER_FILENAMES = ['handler.ts', 'handler.mjs', 'handler.js'] as const;\n\n/** Optional operation methods on Handler. Order = preferred display order. */\nconst OPERATION_NAMES = ['render', 'test', 'build', 'scaffold', 'describe'] as const;\nexport type HandlerCapability = (typeof OPERATION_NAMES)[number];\n\nexport interface LoadedBlueprint {\n /** Kind name. Equal to the folder basename AND handler.kind (enforced at load time). */\n kind: string;\n /** Absolute path to the blueprint folder. */\n folder: string;\n /** Absolute path to the loaded handler file. */\n file: string;\n /** The validated Handler default export. */\n handler: Handler;\n /** Which optional operations this handler supports. */\n capabilities: HandlerCapability[];\n}\n\nexport type BlueprintLoadCause =\n | 'no-handler-file'\n | 'import-failed'\n | 'no-default-export'\n | 'invalid-handler-shape'\n | 'kind-mismatch';\n\nexport interface BlueprintLoadError {\n /** Absolute path to the blueprint folder. */\n folder: string;\n /** The folder basename — used to identify the failed blueprint even if its declared kind is wrong. */\n kind: string;\n /** Tagged cause for programmatic handling. */\n cause: BlueprintLoadCause;\n /** Human-readable message naming the file and what is wrong. */\n message: string;\n}\n\nexport interface BlueprintLoadResult {\n blueprints: LoadedBlueprint[];\n errors: BlueprintLoadError[];\n}\n\n/**\n * Discover and load every blueprint under `<project.root>/.macroscope/blueprints/`.\n *\n * Each subfolder is one blueprint. We look for `handler.ts | .mjs | .js` inside\n * it, import the default export via jiti (so users can write plain TypeScript\n * with no build step), and validate the shape against the Handler interface.\n *\n * Per-blueprint failures are collected in `errors` instead of thrown. A single\n * broken handler does not blind the rest of the catalog.\n */\nexport async function loadBlueprints(project: Project): Promise<BlueprintLoadResult> {\n const blueprintsDir = join(project.root, '.macroscope', 'blueprints');\n if (!existsSync(blueprintsDir)) {\n return { blueprints: [], errors: [] };\n }\n\n let entries: Dirent<string>[];\n try {\n entries = await readdir(blueprintsDir, { withFileTypes: true, encoding: 'utf8' });\n } catch {\n return { blueprints: [], errors: [] };\n }\n\n const blueprints: LoadedBlueprint[] = [];\n const errors: BlueprintLoadError[] = [];\n const jiti = createJiti(import.meta.url);\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const folder = join(blueprintsDir, entry.name);\n // Normalize to NFC. macOS HFS+/APFS may return NFD-decomposed names from\n // readdir; user handler code typically declares `kind` in NFC. Comparing\n // raw bytes would silently fail for blueprints with non-ASCII names.\n const kind = entry.name.normalize('NFC');\n const result = await loadOne(folder, kind, jiti);\n if (result.ok) {\n blueprints.push(result.blueprint);\n } else {\n errors.push(result.error);\n }\n }\n\n blueprints.sort((a, b) => (a.kind < b.kind ? -1 : 1));\n errors.sort((a, b) => (a.kind < b.kind ? -1 : 1));\n return { blueprints, errors };\n}\n\ntype LoadOutcome =\n | { ok: true; blueprint: LoadedBlueprint }\n | { ok: false; error: BlueprintLoadError };\n\nasync function loadOne(\n folder: string,\n kind: string,\n jiti: ReturnType<typeof createJiti>,\n): Promise<LoadOutcome> {\n let file: string | null = null;\n for (const filename of HANDLER_FILENAMES) {\n const candidate = join(folder, filename);\n if (existsSync(candidate)) {\n file = candidate;\n break;\n }\n }\n\n if (!file) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'no-handler-file',\n message: `Blueprint folder ${folder} has no handler file. Expected one of: ${HANDLER_FILENAMES.join(', ')}.`,\n },\n };\n }\n\n let mod: unknown;\n try {\n mod = await jiti.import(file);\n } catch (err) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'import-failed',\n message: `Failed to import ${file}: ${(err as Error).message}`,\n },\n };\n }\n\n const def = extractDefault(mod);\n if (def === undefined) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'no-default-export',\n message: `Blueprint at ${file} has no default export. Use \\`export default { kind: '${kind}', ... } satisfies Handler\\`.`,\n },\n };\n }\n\n if (!isHandler(def)) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'invalid-handler-shape',\n message: `Default export of ${file} is not a valid Handler. It must be an object with a non-empty string \\`kind\\` field and optional async methods (render, test, build, scaffold, describe).`,\n },\n };\n }\n\n if (def.kind !== kind) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'kind-mismatch',\n message: `Blueprint at ${file} declares \\`kind: '${def.kind}'\\` but lives in folder \\`${kind}/\\`. The kind field must match the folder name.`,\n },\n };\n }\n\n const handlerRecord = def as unknown as Record<string, unknown>;\n const capabilities = OPERATION_NAMES.filter((op) => typeof handlerRecord[op] === 'function');\n\n return {\n ok: true,\n blueprint: { kind: def.kind, folder, file, handler: def, capabilities },\n };\n}\n\nfunction extractDefault(mod: unknown): unknown {\n if (mod === null || mod === undefined) return undefined;\n if (typeof mod !== 'object') return mod;\n // jiti wraps the namespace in a Proxy that returns the namespace itself when\n // `.default` is accessed but no default export exists. Use hasOwnProperty so\n // we don't mistake a Proxy fallback for a real default.\n if (!Object.prototype.hasOwnProperty.call(mod, 'default')) return undefined;\n return (mod as Record<string, unknown>).default;\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { dirname, join, relative, sep } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport type { ZodError } from 'zod';\nimport type { Block, BlockManifest } from './handler.js';\nimport { manifestSchema } from './manifest.js';\nimport type { Project } from './project.js';\n\nexport interface ScannedBlock extends Block {\n /** SHA-256 over the manifest text. Used later by the index for change detection. */\n contentHash: string;\n}\n\nexport interface ScanError {\n file: string;\n kind: 'parse' | 'validation' | 'io';\n message: string;\n field?: string;\n}\n\nexport interface ScanResult {\n blocks: ScannedBlock[];\n errors: ScanError[];\n}\n\nexport async function scan(project: Project): Promise<ScanResult> {\n const blocks: ScannedBlock[] = [];\n const errors: ScanError[] = [];\n const ignore = new Set(project.config.ignore);\n const seenIds = new Set<string>();\n\n for (const root of project.config.scanRoots) {\n const start = join(project.root, root);\n if (!existsSync(start)) continue;\n for await (const manifestPath of findManifests(start, ignore)) {\n const result = await parseBlock(manifestPath, project.root);\n if (result.kind === 'ok') {\n if (seenIds.has(result.block.id)) {\n errors.push({\n file: manifestPath,\n kind: 'validation',\n message: `Duplicate block id \"${result.block.id}\" at ${manifestPath}. Set an explicit \\`id:\\` field to disambiguate.`,\n field: 'id',\n });\n } else {\n seenIds.add(result.block.id);\n blocks.push(result.block);\n }\n } else {\n errors.push(result.error);\n }\n }\n }\n\n blocks.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n return { blocks, errors };\n}\n\nasync function* findManifests(dir: string, ignore: Set<string>): AsyncGenerator<string> {\n let entries: import('node:fs').Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isFile() && entry.name === 'macroscope.yaml') {\n yield join(dir, entry.name);\n }\n }\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (ignore.has(entry.name)) continue;\n yield* findManifests(join(dir, entry.name), ignore);\n }\n}\n\ntype ParseOutcome = { kind: 'ok'; block: ScannedBlock } | { kind: 'err'; error: ScanError };\n\nasync function parseBlock(manifestPath: string, projectRoot: string): Promise<ParseOutcome> {\n let raw: string;\n try {\n raw = await readFile(manifestPath, 'utf8');\n } catch (err) {\n return {\n kind: 'err',\n error: {\n file: manifestPath,\n kind: 'io',\n message: `Failed to read manifest at ${manifestPath}: ${(err as Error).message}`,\n },\n };\n }\n\n let yamlValue: unknown;\n try {\n yamlValue = parseYaml(raw);\n } catch (err) {\n return {\n kind: 'err',\n error: {\n file: manifestPath,\n kind: 'parse',\n message: `Invalid YAML in ${manifestPath}: ${(err as Error).message}`,\n },\n };\n }\n\n const parsed = manifestSchema.safeParse(yamlValue);\n if (!parsed.success) {\n const first = firstZodIssue(parsed.error);\n return {\n kind: 'err',\n error: {\n file: manifestPath,\n kind: 'validation',\n message: `Manifest at ${manifestPath} is invalid: field \\`${first.fieldPath}\\` ${first.message}.`,\n field: first.fieldPath,\n },\n };\n }\n\n const manifest = parsed.data as BlockManifest;\n const blockDir = dirname(manifestPath);\n const defaultId = toPosix(relative(projectRoot, blockDir));\n const id = manifest.id ?? defaultId;\n const contentHash = createHash('sha256').update(raw).digest('hex');\n\n return {\n kind: 'ok',\n block: { id, path: blockDir, manifest, contentHash },\n };\n}\n\nfunction firstZodIssue(err: ZodError): { fieldPath: string; message: string } {\n const issue = err.issues[0];\n if (!issue) return { fieldPath: '(root)', message: 'unknown validation error' };\n const fieldPath = issue.path.length ? issue.path.join('.') : '(root)';\n return { fieldPath, message: issue.message.toLowerCase() };\n}\n\nfunction toPosix(p: string): string {\n return p.split(sep).join('/');\n}\n"],"mappings":"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","names":["z","z","z","z","existsSync","join","join","existsSync","existsSync","readFile","readdir","dirname","join","parseYaml","join","existsSync","readdir","readFile","parseYaml","dirname"]}
1
+ {"version":3,"sources":["../../src/core/version.ts","../../../contracts/src/version.ts","../../../contracts/src/fs.ts","../../../contracts/src/manifest.ts","../../../contracts/src/payload.ts","../../../contracts/src/search.ts","../../../contracts/src/api.ts","../../../contracts/src/error.ts","../../../contracts/src/auth.ts","../../src/core/manifest.ts","../../src/core/handler.ts","../../src/core/project.ts","../../src/core/blueprints.ts","../../src/core/scanner.ts","../../src/core/extractor.ts","../../src/core/hasher.ts"],"sourcesContent":["export const VERSION = '0.0.0';\n","/**\n * Wire-format version for cloud-side documents (MeilisearchDoc). Bumped when\n * the doc shape changes in a way that requires reindexing. The catch-up scan\n * watches for a mismatch with the server-reported version and triggers a full\n * re-push (see `catchup.ts`).\n */\nexport const SCHEMA_VERSION = 1 as const;\nexport type SchemaVersion = typeof SCHEMA_VERSION;\n","/**\n * Filesystem paths macroscope reads and writes. Two roots:\n *\n * user — under `~/.macroscope/`; survives across projects.\n * project — under `<project>/.macroscope/`; specific to a worktree.\n *\n * Paths are POSIX-style and relative to their root. Callers resolve them\n * against the relevant base directory (`os.homedir()` or the project root).\n */\nexport const FILESYSTEM_LAYOUT = {\n user: {\n /** `~/.macroscope/` */\n rootDir: '.macroscope',\n /** `~/.macroscope/credentials` — OAuth token store, mode 0600. */\n credentialsFile: '.macroscope/credentials',\n /** `~/.macroscope/machine-id` — stable per-install identifier. */\n machineIdFile: '.macroscope/machine-id',\n },\n project: {\n /** `<project>/.macroscope/` */\n rootDir: '.macroscope',\n /** `<project>/.macroscope/blueprints/` — one folder per kind. */\n blueprintsDir: '.macroscope/blueprints',\n /** `<project>/.macroscope/cache/` */\n cacheDir: '.macroscope/cache',\n /** `<project>/.macroscope/cache/hashes.json` — content-hash cache used by catch-up scan. */\n hashesFile: '.macroscope/cache/hashes.json',\n /** `<project>/.macroscope/cache/queue.json` — watcher push queue, survives restart. */\n queueFile: '.macroscope/cache/queue.json',\n },\n} as const;\n\nexport type FilesystemLayout = typeof FILESYSTEM_LAYOUT;\n","import { z } from 'zod';\n\n/**\n * The on-disk `macroscope.yaml` manifest. Substrate-level fields are listed\n * explicitly; blueprints may attach additional kind-specific fields, which\n * pass through unchanged (`.passthrough()`).\n */\nexport const BlockManifestSchema = z\n .object({\n /** Must reference a registered blueprint's `kind`. */\n kind: z.string().min(1),\n /** Optional override for the auto-derived block id (POSIX relative path). */\n id: z.string().optional(),\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n source: z.string().optional(),\n preview: z.string().optional(),\n docs: z.string().optional(),\n tests: z.union([z.string(), z.array(z.string())]).optional(),\n })\n .passthrough();\n\nexport type BlockManifest = z.infer<typeof BlockManifestSchema>;\n","import { z } from 'zod';\n\n/**\n * One exported symbol from a block's source files. Extracted by the TS\n * compiler API. `signature` is the rendered TypeScript signature string\n * (e.g. `function foo(x: string): number`); the exact rendering is the\n * extractor's responsibility (see T5).\n */\nexport const SymbolSignatureSchema = z.object({\n name: z.string().min(1),\n kind: z.string().min(1),\n signature: z.string(),\n});\nexport type SymbolSignature = z.infer<typeof SymbolSignatureSchema>;\n\n/**\n * What the watcher pushes to the cloud per block. The cloud combines this\n * with cloud-side fields (repo, worktreeId, path, lastActiveAt, contentHash)\n * to form the `MeilisearchDoc` that lands in the user's index.\n */\nexport const UploadPayloadSchema = z.object({\n /** Stable block id (POSIX relative path or manifest `id` override). */\n blockId: z.string().min(1),\n kind: z.string().min(1),\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n /** Exported symbols extracted from the block's source files. */\n symbols: z.array(SymbolSignatureSchema),\n /** First ~500 chars of the README, if any. */\n readmeExcerpt: z.string().optional(),\n});\nexport type UploadPayload = z.infer<typeof UploadPayloadSchema>;\n\n/**\n * The doc shape stored in Meilisearch. Identity is the tuple\n * (repo, worktreeId, blockId): two worktrees of the same repo produce\n * distinct docs and filter independently.\n */\nexport const MeilisearchDocSchema = UploadPayloadSchema.extend({\n /** SHA-256 over the canonical JSON of the UploadPayload (see T6). */\n contentHash: z.string().min(1),\n /** Git remote URL (normalised) or local repo name when no remote exists. */\n repo: z.string().min(1),\n /** hash(machineUuid + absolutePath) — see ARCHITECTURE.md. */\n worktreeId: z.string().min(1),\n /** POSIX path from the worktree root to the block folder. */\n path: z.string().min(1),\n /** Unix epoch milliseconds. Refreshed on every push and by `/scope/touch`. */\n lastActiveAt: z.number().int().nonnegative(),\n});\nexport type MeilisearchDoc = z.infer<typeof MeilisearchDocSchema>;\n","import { z } from 'zod';\n\n/**\n * One cloud-side search result. Returned by `GET /search`. Carries enough\n * to render a result row without a second fetch.\n */\nexport const BlockHitSchema = z.object({\n blockId: z.string().min(1),\n kind: z.string().min(1),\n name: z.string().optional(),\n description: z.string().optional(),\n repo: z.string().min(1),\n worktreeId: z.string().min(1),\n path: z.string().min(1),\n /** Relevance score from Meilisearch hybrid ranking. Larger = more relevant. */\n score: z.number(),\n});\nexport type BlockHit = z.infer<typeof BlockHitSchema>;\n\n/**\n * One local-side code search result. Produced by `git grep` (T10). Lives in\n * contracts so the UI's merged-results view can speak one type.\n */\nexport const CodeMatchSchema = z.object({\n /** POSIX path from the worktree root. */\n file: z.string().min(1),\n /** 1-based line number. */\n line: z.number().int().positive(),\n /** 1-based column number, when available. */\n column: z.number().int().positive().optional(),\n /** A single line of source text containing the match. */\n preview: z.string(),\n});\nexport type CodeMatch = z.infer<typeof CodeMatchSchema>;\n","import { z } from 'zod';\nimport { MeilisearchDocSchema } from './payload.js';\nimport { BlockHitSchema } from './search.js';\n\n/* ------------------------------ POST /index/batch ------------------------------ */\n\nexport const IndexBatchRequestSchema = z.object({\n /** Per-block docs to upsert. The cloud routes these to the user's Meilisearch index. */\n upserts: z.array(MeilisearchDocSchema),\n /** Block ids to delete. Empty array is valid (upsert-only batch). */\n deletes: z.array(z.string().min(1)),\n});\nexport type IndexBatchRequest = z.infer<typeof IndexBatchRequestSchema>;\n\nexport const IndexBatchResponseSchema = z.object({\n /** Unix epoch ms of server-side acknowledgement. */\n acceptedAt: z.number().int().nonnegative(),\n /** Number of upserts accepted (deletes excluded). */\n accepted: z.number().int().nonnegative(),\n});\nexport type IndexBatchResponse = z.infer<typeof IndexBatchResponseSchema>;\n\n/* --------------------------------- GET /search --------------------------------- */\n\nexport const SearchRequestSchema = z.object({\n q: z.string().min(1),\n /** Restrict to one worktree. Omit to search across all of the user's worktrees. */\n worktreeId: z.string().optional(),\n /** Restrict to one repo. */\n repo: z.string().optional(),\n /** Restrict to one block kind. */\n kind: z.string().optional(),\n /** Cap on returned hits. Server enforces an upper bound. */\n limit: z.number().int().positive().optional(),\n});\nexport type SearchRequest = z.infer<typeof SearchRequestSchema>;\n\nexport const SearchResponseSchema = z.object({\n hits: z.array(BlockHitSchema),\n /** Approximate total match count from Meilisearch (estimated, not exact). */\n totalEstimated: z.number().int().nonnegative(),\n});\nexport type SearchResponse = z.infer<typeof SearchResponseSchema>;\n\n/* --------------------------------- DELETE /index -------------------------------- */\n\nexport const DeleteIndexResponseSchema = z.object({\n deletedAt: z.number().int().nonnegative(),\n});\nexport type DeleteIndexResponse = z.infer<typeof DeleteIndexResponseSchema>;\n\n/* ------------------------------ POST /scope/touch ------------------------------ */\n\nexport const ScopeTouchRequestSchema = z.object({\n worktreeId: z.string().min(1),\n repo: z.string().min(1),\n});\nexport type ScopeTouchRequest = z.infer<typeof ScopeTouchRequestSchema>;\n\nexport const ScopeTouchResponseSchema = z.object({\n touchedAt: z.number().int().nonnegative(),\n});\nexport type ScopeTouchResponse = z.infer<typeof ScopeTouchResponseSchema>;\n\n/* --------------------------------- GET /health --------------------------------- */\n\nexport const HealthResponseSchema = z.object({\n status: z.literal('ok'),\n schemaVersion: z.number().int().positive(),\n});\nexport type HealthResponse = z.infer<typeof HealthResponseSchema>;\n\n/**\n * Endpoint manifest. One row per route, suitable for type-checking a server\n * router and a typed client against a single source of truth.\n *\n * Serialization convention: for `method: 'GET'` endpoints the request schema's\n * fields are sent as URL query parameters (never a body). For `POST`/`DELETE`\n * the request schema is the JSON body. `request: null` means the endpoint\n * takes no request payload at all.\n */\nexport const API_ENDPOINTS = {\n indexBatch: {\n method: 'POST',\n path: '/index/batch',\n request: IndexBatchRequestSchema,\n response: IndexBatchResponseSchema,\n },\n search: {\n method: 'GET',\n path: '/search',\n request: SearchRequestSchema,\n response: SearchResponseSchema,\n },\n deleteIndex: {\n method: 'DELETE',\n path: '/index',\n request: null,\n response: DeleteIndexResponseSchema,\n },\n scopeTouch: {\n method: 'POST',\n path: '/scope/touch',\n request: ScopeTouchRequestSchema,\n response: ScopeTouchResponseSchema,\n },\n health: {\n method: 'GET',\n path: '/health',\n request: null,\n response: HealthResponseSchema,\n },\n} as const;\n\nexport type ApiEndpoints = typeof API_ENDPOINTS;\n","import { z } from 'zod';\n\n/**\n * The uniform error shape returned by every API endpoint on failure. Per the\n * CLAUDE.md invariant: errors name the file path and the broken field where\n * applicable.\n */\nexport const ErrorEnvelopeSchema = z.object({\n error: z.object({\n /** Stable machine-readable code (e.g. `unauthorized`, `validation_failed`). */\n code: z.string().min(1),\n /** Human-readable message. */\n message: z.string().min(1),\n /** Source file path when the error originates from parsing a manifest or other on-disk artifact. Set by the CLI side (see `ScanError`) and by the cloud when validating uploaded manifests. */\n file: z.string().optional(),\n /** Path of the offending field when the error is validation-related. */\n field: z.string().optional(),\n /** Server-assigned request id for log correlation. */\n requestId: z.string().optional(),\n }),\n});\n\nexport type ErrorEnvelope = z.infer<typeof ErrorEnvelopeSchema>;\n","import { z } from 'zod';\n\n/**\n * Supported Git host identity providers. v1 ships GitHub and GitLab. Other\n * providers (Bitbucket, Gitea, self-hosted GitLab) are deferred to v1.1; see\n * TODOS.md.\n */\nexport const ProviderSchema = z.enum(['github', 'gitlab']);\nexport type Provider = z.infer<typeof ProviderSchema>;\n\n/**\n * On-disk shape of `~/.macroscope/credentials` (file mode 0600). Written by\n * `macroscope login` (T9) and read by the local proxy (T11) when forwarding\n * the bearer token to the cloud API. Refresh-token and expiry are optional —\n * not every provider issues a refresh token, and some access tokens have no\n * explicit expiry.\n */\nexport const OAuthCredentialsSchema = z.object({\n provider: ProviderSchema,\n accessToken: z.string().min(1),\n refreshToken: z.string().min(1).optional(),\n /** Unix epoch milliseconds at which `accessToken` expires. */\n expiresAt: z.number().int().nonnegative().optional(),\n /** Provider-side user id (e.g. GitHub `id`, GitLab `id`). Optional — useful\n * for UI display (\"logged in as alexspdlr on github\") and for the CLI to\n * short-circuit redundant `/user` lookups. */\n providerUserId: z.string().min(1).optional(),\n});\nexport type OAuthCredentials = z.infer<typeof OAuthCredentialsSchema>;\n\n/**\n * The authenticated-request context the OAuth validation middleware (T12)\n * attaches to every request after verifying the bearer token. Downstream\n * handlers read these fields to scope queries to the right user index.\n *\n * Identity derivation (per ARCHITECTURE.md):\n * userId = hash(provider + \":\" + providerUserId)\n * indexName = \"user_\" + userId\n *\n * Same human on different providers ⇒ different userId. Intentional — keeps\n * cross-provider identity confusion impossible at the storage layer.\n */\nexport const UserContextSchema = z.object({\n userId: z.string().min(1),\n indexName: z.string().min(1),\n provider: ProviderSchema,\n});\nexport type UserContext = z.infer<typeof UserContextSchema>;\n","import { type BlockManifest, BlockManifestSchema } from '@macroscope/contracts';\n\nexport const manifestSchema = BlockManifestSchema;\nexport type Manifest = BlockManifest;\n","/**\n * The locked substrate contract. The v1 control layer extends this interface;\n * it never bypasses it.\n *\n * A `Handler` is what a blueprint exports. It declares a `kind` and zero or more\n * optional async operations. Each operation returns data — never side effects —\n * and never throws \"not implemented\"; missing methods simply mean the operation\n * isn't supported for that kind.\n *\n * No top-level side effects on import. Importing a handler must not spawn\n * processes, open ports, or read files. Side effects belong inside methods.\n *\n * Trust model: blueprints are USER-AUTHORED CODE in the user's own project.\n * The loader imports them via jiti and runs them at full process privilege.\n * This is the same trust model as a `package.json` postinstall script, an\n * ESLint plugin, a Storybook addon, or a vite.config.ts — code in your repo\n * runs as you. There is no sandbox. If you do not trust a blueprint, do not\n * put it in your project.\n */\nexport interface Handler {\n /** Required. Must match the blueprint folder name. */\n kind: string;\n /** Named views shown as tabs in the block-detail page. v1 ships iframe + terminal types. */\n views?: Record<string, ViewSpec>;\n /** Produce something the UI/CLI/MCP can display for this block. */\n render?: (block: Block) => Promise<RenderResult>;\n /** Run whatever counts as a test for this kind. */\n test?: (block: Block) => Promise<TestResult>;\n /** Produce build artifacts for this kind. */\n build?: (block: Block) => Promise<BuildResult>;\n /** Create a new block of this kind in `targetDir` with the given name. */\n scaffold?: (targetDir: string, name: string) => Promise<void>;\n /** Generate a free-form textual description of a block, used by semantic search. */\n describe?: (block: Block) => Promise<string>;\n}\n\n/**\n * A block is an instance of a kind: a folder somewhere in the user's project\n * with a `macroscope.yaml`. Handlers receive these as input.\n *\n * For M0 (this PR) we don't actually load blocks yet — this type exists so the\n * Handler interface can be locked.\n */\nexport interface Block {\n /** Stable identifier. POSIX relative path from project root by default; overridable via the manifest `id` field. */\n id: string;\n /** Absolute path to the block's folder. */\n path: string;\n /** Parsed and validated manifest. */\n manifest: BlockManifest;\n}\n\n/**\n * The manifest is the data side of a block (the `macroscope.yaml`). The shape\n * here is the substrate's view of it; individual blueprints may require\n * additional fields under their own `kind`.\n */\nexport interface BlockManifest {\n /** Must reference a registered blueprint's `kind`. */\n kind: string;\n /** Optional override for the auto-derived block id. */\n id?: string;\n name?: string;\n description?: string;\n tags?: string[];\n source?: string;\n preview?: string;\n docs?: string;\n tests?: string | string[];\n /** Unknown fields pass through to handlers per the v0 spec — never errors. */\n [field: string]: unknown;\n}\n\n/**\n * A view is one tab in the block-detail page. Three view types exist:\n * - iframe: embed any URL the blueprint resolves.\n * - terminal: spawn the resolved command server-side and stream its\n * stdin/stdout/stderr to a browser xterm.js terminal.\n * - hybrid: combine a static artifact (iframe URL) with an on-demand\n * command (terminal). UI shows the URL by default and a Run button\n * that switches to the terminal and spawns the command.\n */\nexport type ViewSpec = IframeViewSpec | TerminalViewSpec | HybridViewSpec;\n\nexport interface IframeViewSpec {\n type: 'iframe';\n url: string | ((block: Block) => string | Promise<string>);\n /** Optional backing service. macroscope spawns this on demand the first time the\n * view is opened in the UI, polls readyWhen.url, and only loads the iframe\n * once the service responds. */\n service?: ServiceSpec;\n}\n\nexport interface ServiceSpec {\n /** Human-readable label shown in the \"starting…\" state. Defaults to command[0]. */\n name?: string;\n /** argv-style command. Function form is resolved server-side per block. */\n command: string[] | ((block: Block) => string[] | Promise<string[]>);\n /** Working directory. Defaults to project root. */\n cwd?: string | ((block: Block) => string | Promise<string>);\n /** Service is ready when this URL responds with any non-5xx status. */\n readyWhen: { url: string };\n /** Max ms to wait for readiness before declaring failure. Default: 30_000. */\n startupTimeoutMs?: number;\n}\n\nexport interface TerminalViewSpec {\n type: 'terminal';\n /** argv-style: ['vitest', 'run', '<file>']. Function form is resolved server-side per block. */\n command: string[] | ((block: Block) => string[] | Promise<string[]>);\n}\n\n/**\n * A hybrid view shows a static artifact (e.g. test source code) by default and\n * lets the user switch to a terminal that runs an on-demand command (e.g.\n * `vitest run`) via a Run button. Useful for \"read code → press button → see\n * what happens → toggle back\" workflows.\n */\nexport interface HybridViewSpec {\n type: 'hybrid';\n /** Static artifact URL. Same semantics as IframeViewSpec.url. */\n url: string | ((block: Block) => string | Promise<string>);\n /** On-demand command. Same semantics as TerminalViewSpec.command. */\n command: string[] | ((block: Block) => string[] | Promise<string[]>);\n /** Label for the Run button. Default: \"Run\". */\n runLabel?: string;\n /** Label for the code-side toggle. Default: \"Code\". */\n codeLabel?: string;\n /** Label for the terminal-side toggle. Default: \"Terminal\". */\n terminalLabel?: string;\n}\n\nexport type RenderResult =\n | { type: 'iframe'; entry: string }\n | { type: 'html'; html: string }\n | { type: 'markdown'; source: string }\n | { type: 'image'; src: string }\n | { type: 'error'; message: string }\n | { type: 'none'; reason: string };\n\nexport type TestResult =\n | { type: 'pass'; output?: string }\n | { type: 'fail'; output: string }\n | { type: 'error'; message: string }\n | { type: 'none'; reason: string };\n\nexport type BuildResult =\n | { type: 'ok'; artifacts?: string[] }\n | { type: 'error'; message: string }\n | { type: 'none'; reason: string };\n\n/**\n * Convenience type guard for runtime validation. Used by the blueprint loader\n * to verify that a default export looks like a Handler before accepting it.\n */\nexport function isHandler(value: unknown): value is Handler {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n if (typeof v.kind !== 'string' || v.kind.length === 0) return false;\n for (const method of ['render', 'test', 'build', 'scaffold', 'describe'] as const) {\n if (v[method] !== undefined && typeof v[method] !== 'function') return false;\n }\n if (v.views !== undefined) {\n if (typeof v.views !== 'object' || v.views === null) return false;\n for (const [, spec] of Object.entries(v.views as Record<string, unknown>)) {\n if (!isViewSpec(spec)) return false;\n }\n }\n return true;\n}\n\nfunction isViewSpec(value: unknown): value is ViewSpec {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n switch (v.type) {\n case 'iframe':\n if (typeof v.url !== 'string' && typeof v.url !== 'function') return false;\n if (v.service !== undefined && !isServiceSpec(v.service)) return false;\n return true;\n case 'terminal':\n return (\n typeof v.command === 'function' ||\n (Array.isArray(v.command) && v.command.every((c) => typeof c === 'string'))\n );\n case 'hybrid': {\n const urlOk = typeof v.url === 'string' || typeof v.url === 'function';\n const commandOk =\n typeof v.command === 'function' ||\n (Array.isArray(v.command) && v.command.every((c) => typeof c === 'string'));\n if (!urlOk || !commandOk) return false;\n for (const key of ['runLabel', 'codeLabel', 'terminalLabel'] as const) {\n if (v[key] !== undefined && typeof v[key] !== 'string') return false;\n }\n return true;\n }\n default:\n return false;\n }\n}\n\nfunction isServiceSpec(value: unknown): value is ServiceSpec {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n const commandOk =\n typeof v.command === 'function' ||\n (Array.isArray(v.command) && v.command.every((c) => typeof c === 'string'));\n if (!commandOk) return false;\n if (typeof v.readyWhen !== 'object' || v.readyWhen === null) return false;\n const ready = v.readyWhen as Record<string, unknown>;\n if (typeof ready.url !== 'string') return false;\n if (v.name !== undefined && typeof v.name !== 'string') return false;\n if (v.cwd !== undefined && typeof v.cwd !== 'string' && typeof v.cwd !== 'function') {\n return false;\n }\n if (v.startupTimeoutMs !== undefined && typeof v.startupTimeoutMs !== 'number') return false;\n return true;\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { z } from 'zod';\n\nexport const projectConfigSchema = z.object({\n scanRoots: z.array(z.string()).default(['.']),\n ignore: z.array(z.string()).default(['node_modules', '.git', 'dist', '.macroscope']),\n});\n\nexport type ProjectConfig = z.infer<typeof projectConfigSchema>;\n\nexport interface Project {\n /** Absolute path to the project root (the directory containing .macroscope/). */\n root: string;\n /** Parsed .macroscope/config.yaml, with defaults filled in. */\n config: ProjectConfig;\n}\n\nexport class ProjectNotFoundError extends Error {\n constructor(startedFrom: string) {\n super(\n `No macroscope project found. Walked up from ${startedFrom} looking for a .macroscope/ directory but reached the filesystem root. Run \\`npm create macroscope\\` to scaffold one, or cd into an existing project.`,\n );\n this.name = 'ProjectNotFoundError';\n }\n}\n\n/**\n * Find the project root by walking up from `cwd` looking for a `.macroscope/`\n * directory. The macroscope root is the directory that *contains* `.macroscope`.\n * If config.yaml is present inside, it is parsed; otherwise defaults are used.\n */\nexport async function findProject(cwd: string = process.cwd()): Promise<Project> {\n const startedFrom = resolve(cwd);\n let current = startedFrom;\n while (true) {\n if (existsSync(join(current, '.macroscope'))) {\n return { root: current, config: await loadConfig(current) };\n }\n const parent = dirname(current);\n if (parent === current) {\n throw new ProjectNotFoundError(startedFrom);\n }\n current = parent;\n }\n}\n\nasync function loadConfig(root: string): Promise<ProjectConfig> {\n const configPath = join(root, '.macroscope', 'config.yaml');\n if (!existsSync(configPath)) {\n return projectConfigSchema.parse({});\n }\n const raw = await readFile(configPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = parseYaml(raw) ?? {};\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse ${configPath}: ${msg}`);\n }\n const result = projectConfigSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('\\n');\n throw new Error(`Invalid project config at ${configPath}:\\n${issues}`);\n }\n return result.data;\n}\n","import { type Dirent, existsSync } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createJiti } from 'jiti';\nimport { type Handler, isHandler } from './handler.js';\nimport type { Project } from './project.js';\n\n/** Filenames tried, in order. First match wins. */\nconst HANDLER_FILENAMES = ['handler.ts', 'handler.mjs', 'handler.js'] as const;\n\n/** Optional operation methods on Handler. Order = preferred display order. */\nconst OPERATION_NAMES = ['render', 'test', 'build', 'scaffold', 'describe'] as const;\nexport type HandlerCapability = (typeof OPERATION_NAMES)[number];\n\nexport interface LoadedBlueprint {\n /** Kind name. Equal to the folder basename AND handler.kind (enforced at load time). */\n kind: string;\n /** Absolute path to the blueprint folder. */\n folder: string;\n /** Absolute path to the loaded handler file. */\n file: string;\n /** The validated Handler default export. */\n handler: Handler;\n /** Which optional operations this handler supports. */\n capabilities: HandlerCapability[];\n}\n\nexport type BlueprintLoadCause =\n | 'no-handler-file'\n | 'import-failed'\n | 'no-default-export'\n | 'invalid-handler-shape'\n | 'kind-mismatch';\n\nexport interface BlueprintLoadError {\n /** Absolute path to the blueprint folder. */\n folder: string;\n /** The folder basename — used to identify the failed blueprint even if its declared kind is wrong. */\n kind: string;\n /** Tagged cause for programmatic handling. */\n cause: BlueprintLoadCause;\n /** Human-readable message naming the file and what is wrong. */\n message: string;\n}\n\nexport interface BlueprintLoadResult {\n blueprints: LoadedBlueprint[];\n errors: BlueprintLoadError[];\n}\n\n/**\n * Discover and load every blueprint under `<project.root>/.macroscope/blueprints/`.\n *\n * Each subfolder is one blueprint. We look for `handler.ts | .mjs | .js` inside\n * it, import the default export via jiti (so users can write plain TypeScript\n * with no build step), and validate the shape against the Handler interface.\n *\n * Per-blueprint failures are collected in `errors` instead of thrown. A single\n * broken handler does not blind the rest of the catalog.\n */\nexport async function loadBlueprints(project: Project): Promise<BlueprintLoadResult> {\n const blueprintsDir = join(project.root, '.macroscope', 'blueprints');\n if (!existsSync(blueprintsDir)) {\n return { blueprints: [], errors: [] };\n }\n\n let entries: Dirent<string>[];\n try {\n entries = await readdir(blueprintsDir, { withFileTypes: true, encoding: 'utf8' });\n } catch {\n return { blueprints: [], errors: [] };\n }\n\n const blueprints: LoadedBlueprint[] = [];\n const errors: BlueprintLoadError[] = [];\n const jiti = createJiti(import.meta.url);\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const folder = join(blueprintsDir, entry.name);\n // Normalize to NFC. macOS HFS+/APFS may return NFD-decomposed names from\n // readdir; user handler code typically declares `kind` in NFC. Comparing\n // raw bytes would silently fail for blueprints with non-ASCII names.\n const kind = entry.name.normalize('NFC');\n const result = await loadOne(folder, kind, jiti);\n if (result.ok) {\n blueprints.push(result.blueprint);\n } else {\n errors.push(result.error);\n }\n }\n\n blueprints.sort((a, b) => (a.kind < b.kind ? -1 : 1));\n errors.sort((a, b) => (a.kind < b.kind ? -1 : 1));\n return { blueprints, errors };\n}\n\ntype LoadOutcome =\n | { ok: true; blueprint: LoadedBlueprint }\n | { ok: false; error: BlueprintLoadError };\n\nasync function loadOne(\n folder: string,\n kind: string,\n jiti: ReturnType<typeof createJiti>,\n): Promise<LoadOutcome> {\n let file: string | null = null;\n for (const filename of HANDLER_FILENAMES) {\n const candidate = join(folder, filename);\n if (existsSync(candidate)) {\n file = candidate;\n break;\n }\n }\n\n if (!file) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'no-handler-file',\n message: `Blueprint folder ${folder} has no handler file. Expected one of: ${HANDLER_FILENAMES.join(', ')}.`,\n },\n };\n }\n\n let mod: unknown;\n try {\n mod = await jiti.import(file);\n } catch (err) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'import-failed',\n message: `Failed to import ${file}: ${(err as Error).message}`,\n },\n };\n }\n\n const def = extractDefault(mod);\n if (def === undefined) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'no-default-export',\n message: `Blueprint at ${file} has no default export. Use \\`export default { kind: '${kind}', ... } satisfies Handler\\`.`,\n },\n };\n }\n\n if (!isHandler(def)) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'invalid-handler-shape',\n message: `Default export of ${file} is not a valid Handler. It must be an object with a non-empty string \\`kind\\` field and optional async methods (render, test, build, scaffold, describe).`,\n },\n };\n }\n\n if (def.kind !== kind) {\n return {\n ok: false,\n error: {\n folder,\n kind,\n cause: 'kind-mismatch',\n message: `Blueprint at ${file} declares \\`kind: '${def.kind}'\\` but lives in folder \\`${kind}/\\`. The kind field must match the folder name.`,\n },\n };\n }\n\n const handlerRecord = def as unknown as Record<string, unknown>;\n const capabilities = OPERATION_NAMES.filter((op) => typeof handlerRecord[op] === 'function');\n\n return {\n ok: true,\n blueprint: { kind: def.kind, folder, file, handler: def, capabilities },\n };\n}\n\nfunction extractDefault(mod: unknown): unknown {\n if (mod === null || mod === undefined) return undefined;\n if (typeof mod !== 'object') return mod;\n // jiti wraps the namespace in a Proxy that returns the namespace itself when\n // `.default` is accessed but no default export exists. Use hasOwnProperty so\n // we don't mistake a Proxy fallback for a real default.\n if (!Object.prototype.hasOwnProperty.call(mod, 'default')) return undefined;\n return (mod as Record<string, unknown>).default;\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { dirname, join, relative, resolve, sep } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport type { ZodError } from 'zod';\nimport type { Block, BlockManifest } from './handler.js';\nimport { manifestSchema } from './manifest.js';\nimport type { Project } from './project.js';\n\nexport interface ResolvedPaths {\n source?: string;\n docs?: string;\n preview?: string;\n tests?: string[];\n}\n\nexport interface ScannedBlock extends Block {\n /** SHA-256 over the manifest text. Used later by the index for change detection. */\n contentHash: string;\n /**\n * Absolute paths to manifest-referenced files, when present and inside the project.\n * If `manifest.source` is set but the file is missing or outside the project,\n * `resolvedPaths.source` is absent and a corresponding `io` or `validation`\n * ScanError is in `errors[]`. T5 (extractor) should treat a missing\n * `resolvedPaths.source` as a no-op, not an error.\n */\n resolvedPaths?: ResolvedPaths;\n}\n\nexport interface ScanError {\n file: string;\n kind: 'parse' | 'validation' | 'io';\n message: string;\n field?: string;\n}\n\nexport interface ScanResult {\n blocks: ScannedBlock[];\n errors: ScanError[];\n}\n\nexport async function scan(project: Project): Promise<ScanResult> {\n const blocks: ScannedBlock[] = [];\n const errors: ScanError[] = [];\n const ignore = new Set(project.config.ignore);\n const seenIds = new Set<string>();\n\n for (const root of project.config.scanRoots) {\n const start = join(project.root, root);\n if (!existsSync(start)) continue;\n for await (const manifestPath of findManifests(start, ignore)) {\n const result = await parseBlock(manifestPath, project.root);\n if (result.kind === 'ok') {\n errors.push(...result.errors);\n if (seenIds.has(result.block.id)) {\n errors.push({\n file: manifestPath,\n kind: 'validation',\n message: `Duplicate block id \"${result.block.id}\" at ${manifestPath}. Set an explicit \\`id:\\` field to disambiguate.`,\n field: 'id',\n });\n } else {\n seenIds.add(result.block.id);\n blocks.push(result.block);\n }\n } else {\n errors.push(result.error);\n }\n }\n }\n\n blocks.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n return { blocks, errors };\n}\n\nasync function* findManifests(dir: string, ignore: Set<string>): AsyncGenerator<string> {\n let entries: import('node:fs').Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isFile() && entry.name === 'macroscope.yaml') {\n yield join(dir, entry.name);\n }\n }\n // Symlinks are skipped. readdir({ withFileTypes: true }) classifies them\n // distinctly from directories (DT_LNK on POSIX), so the isDirectory() check\n // already excludes them. The explicit isSymbolicLink() guard is defence-in-depth\n // in case readdir semantics differ on some platform/filesystem.\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (entry.isSymbolicLink()) continue;\n if (ignore.has(entry.name)) continue;\n yield* findManifests(join(dir, entry.name), ignore);\n }\n}\n\ntype ParseOutcome =\n | { kind: 'ok'; block: ScannedBlock; errors: ScanError[] }\n | { kind: 'err'; error: ScanError };\n\nasync function parseBlock(manifestPath: string, projectRoot: string): Promise<ParseOutcome> {\n let raw: string;\n try {\n raw = await readFile(manifestPath, 'utf8');\n } catch (err) {\n return {\n kind: 'err',\n error: {\n file: manifestPath,\n kind: 'io',\n message: `Failed to read manifest at ${manifestPath}: ${(err as Error).message}`,\n },\n };\n }\n\n let yamlValue: unknown;\n try {\n yamlValue = parseYaml(raw);\n } catch (err) {\n return {\n kind: 'err',\n error: {\n file: manifestPath,\n kind: 'parse',\n message: `Invalid YAML in ${manifestPath}: ${(err as Error).message}`,\n },\n };\n }\n\n const parsed = manifestSchema.safeParse(yamlValue);\n if (!parsed.success) {\n const first = firstZodIssue(parsed.error);\n return {\n kind: 'err',\n error: {\n file: manifestPath,\n kind: 'validation',\n message: `Manifest at ${manifestPath} is invalid: field \\`${first.fieldPath}\\` ${first.message}.`,\n field: first.fieldPath,\n },\n };\n }\n\n const manifest = parsed.data as BlockManifest;\n const blockDir = dirname(manifestPath);\n const defaultId = toPosix(relative(projectRoot, blockDir));\n const id = manifest.id ?? defaultId;\n const contentHash = createHash('sha256').update(raw).digest('hex');\n\n const fileErrors: ScanError[] = [];\n const resolvedPaths = resolveManifestPaths(\n manifest,\n blockDir,\n projectRoot,\n manifestPath,\n fileErrors,\n );\n\n return {\n kind: 'ok',\n block: { id, path: blockDir, manifest, contentHash, resolvedPaths },\n errors: fileErrors,\n };\n}\n\nconst FILE_FIELDS = ['source', 'docs', 'preview'] as const;\n\nfunction resolveManifestPaths(\n manifest: BlockManifest,\n blockDir: string,\n projectRoot: string,\n manifestPath: string,\n errors: ScanError[],\n): ResolvedPaths | undefined {\n const testsRaw = manifest.tests;\n const testsArray =\n testsRaw == null ? undefined : typeof testsRaw === 'string' ? [testsRaw] : testsRaw;\n\n const hasAnyField = FILE_FIELDS.some((f) => manifest[f] != null) || testsArray != null;\n if (!hasAnyField) return undefined;\n\n const resolved: ResolvedPaths = {};\n\n for (const field of FILE_FIELDS) {\n const value = manifest[field] as string | undefined;\n if (value == null) continue;\n const abs = resolve(blockDir, value);\n if (!isInsideProject(abs, projectRoot)) {\n errors.push({\n file: manifestPath,\n kind: 'validation',\n field,\n message: `Field \\`${field}\\` in ${manifestPath} resolves to ${abs}, which is outside the project root ${projectRoot}.`,\n });\n continue;\n }\n if (!existsSync(abs)) {\n errors.push({\n file: manifestPath,\n kind: 'io',\n field,\n message: `Field \\`${field}\\` in ${manifestPath} references ${abs}, which does not exist.`,\n });\n continue;\n }\n resolved[field] = abs;\n }\n\n if (testsArray) {\n const resolvedTests: string[] = [];\n for (const t of testsArray) {\n const abs = resolve(blockDir, t);\n if (!isInsideProject(abs, projectRoot)) {\n errors.push({\n file: manifestPath,\n kind: 'validation',\n field: 'tests',\n message: `Field \\`tests\\` in ${manifestPath} resolves to ${abs}, which is outside the project root ${projectRoot}.`,\n });\n continue;\n }\n if (!existsSync(abs)) {\n errors.push({\n file: manifestPath,\n kind: 'io',\n field: 'tests',\n message: `Field \\`tests\\` in ${manifestPath} references ${abs}, which does not exist.`,\n });\n continue;\n }\n resolvedTests.push(abs);\n }\n if (resolvedTests.length > 0) {\n resolved.tests = resolvedTests;\n }\n }\n\n return Object.keys(resolved).length > 0 ? resolved : undefined;\n}\n\nfunction isInsideProject(absPath: string, projectRoot: string): boolean {\n const normalized = resolve(absPath);\n return normalized === projectRoot || normalized.startsWith(projectRoot + sep);\n}\n\nfunction firstZodIssue(err: ZodError): { fieldPath: string; message: string } {\n const issue = err.issues[0];\n if (!issue) return { fieldPath: '(root)', message: 'unknown validation error' };\n const fieldPath = issue.path.length ? issue.path.join('.') : '(root)';\n return { fieldPath, message: issue.message.toLowerCase() };\n}\n\nfunction toPosix(p: string): string {\n return p.split(sep).join('/');\n}\n","import { readFile } from 'node:fs/promises';\nimport type { SymbolSignature, UploadPayload } from '@macroscope/contracts';\nimport ts from 'typescript';\nimport type { ScannedBlock } from './scanner.js';\n\nconst DEFAULT_README_EXCERPT_MAX = 500;\n\n/** Source file extensions whose symbols we know how to extract. */\nconst TS_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);\n\nexport interface ExtractorOptions {\n /** Cap on README excerpt characters. Default 500. */\n readmeExcerptMax?: number;\n /** Test seam — inject a TS Program factory. Defaults to the real ts.createProgram. */\n programFactory?: (sourceFiles: string[]) => ts.Program;\n}\n\nexport interface ExtractionError {\n blockId: string;\n kind: 'parse' | 'io' | 'symbol';\n message: string;\n}\n\nexport interface ExtractionResult {\n /** One payload per block that had a valid `kind` (the only required manifest field). */\n payloads: UploadPayload[];\n /** Errors collected during extraction. NEVER thrown — bad blocks are skipped. */\n errors: ExtractionError[];\n}\n\nconst DEFAULT_COMPILER_OPTIONS: ts.CompilerOptions = {\n target: ts.ScriptTarget.ES2022,\n module: ts.ModuleKind.ESNext,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n jsx: ts.JsxEmit.ReactJSX,\n allowJs: false,\n noEmit: true,\n skipLibCheck: true,\n esModuleInterop: true,\n allowSyntheticDefaultImports: true,\n strict: false,\n isolatedModules: true,\n};\n\nfunction defaultProgramFactory(rootFiles: string[]): ts.Program {\n return ts.createProgram(rootFiles, DEFAULT_COMPILER_OPTIONS);\n}\n\nexport async function extractAll(\n blocks: ScannedBlock[],\n opts: ExtractorOptions = {},\n): Promise<ExtractionResult> {\n const readmeMax = opts.readmeExcerptMax ?? DEFAULT_README_EXCERPT_MAX;\n const payloads: UploadPayload[] = [];\n const errors: ExtractionError[] = [];\n\n const sourcesToBlocks = new Map<string, ScannedBlock>();\n for (const block of blocks) {\n if (!block.manifest?.kind) continue;\n const src = block.resolvedPaths?.source;\n if (src && isTsSource(src)) {\n sourcesToBlocks.set(src, block);\n }\n }\n\n // Build one TS Program covering every TS source we'll extract from. This is\n // the difference between 100ms and 30s for a 100-block scan. We let TS load\n // transitive .d.ts files from node_modules for *type resolution* — without\n // them, signatureToString renders worse output — but we iterate ONLY the\n // root files when extracting symbols (see processBlock below).\n let program: ts.Program | undefined;\n let checker: ts.TypeChecker | undefined;\n if (sourcesToBlocks.size > 0) {\n const rootFiles = Array.from(sourcesToBlocks.keys());\n const factory = opts.programFactory ?? defaultProgramFactory;\n program = factory(rootFiles);\n checker = program.getTypeChecker();\n }\n\n for (const block of blocks) {\n if (!block.manifest?.kind) continue;\n\n const payload: UploadPayload = {\n blockId: block.id,\n kind: block.manifest.kind,\n symbols: [],\n };\n\n const { name, description, tags } = block.manifest;\n if (typeof name === 'string') payload.name = name;\n if (typeof description === 'string') payload.description = description;\n if (Array.isArray(tags)) payload.tags = tags;\n\n const sourcePath = block.resolvedPaths?.source;\n if (sourcePath && isTsSource(sourcePath) && program && checker) {\n const sourceFile = program.getSourceFile(sourcePath);\n if (!sourceFile) {\n errors.push({\n blockId: block.id,\n kind: 'parse',\n message: `TS Program did not load ${sourcePath} (parse error or missing file)`,\n });\n } else if (hasFatalSyntaxErrors(program, sourceFile)) {\n errors.push({\n blockId: block.id,\n kind: 'parse',\n message: `Source file ${sourcePath} has syntax errors; skipping symbol extraction`,\n });\n } else {\n payload.symbols = extractSymbols(sourceFile, checker);\n }\n }\n\n const docsPath = block.resolvedPaths?.docs;\n if (docsPath) {\n try {\n const raw = await readFile(docsPath, 'utf8');\n payload.readmeExcerpt = formatReadmeExcerpt(raw, readmeMax);\n } catch (err) {\n errors.push({\n blockId: block.id,\n kind: 'io',\n message: `Failed to read docs at ${docsPath}: ${(err as Error).message}`,\n });\n }\n }\n\n payloads.push(payload);\n }\n\n return { payloads, errors };\n}\n\nfunction isTsSource(path: string): boolean {\n const dot = path.lastIndexOf('.');\n if (dot < 0) return false;\n return TS_EXTENSIONS.has(path.slice(dot).toLowerCase());\n}\n\nfunction hasFatalSyntaxErrors(program: ts.Program, sourceFile: ts.SourceFile): boolean {\n const diagnostics = program.getSyntacticDiagnostics(sourceFile);\n return diagnostics.length > 0;\n}\n\nfunction extractSymbols(sourceFile: ts.SourceFile, checker: ts.TypeChecker): SymbolSignature[] {\n const symbols: SymbolSignature[] = [];\n\n for (const statement of sourceFile.statements) {\n visitTopLevel(statement, sourceFile, checker, symbols);\n }\n\n // Dedupe by (name, kind) — re-exports can otherwise show up twice if the\n // local file also names them.\n const seen = new Set<string>();\n return symbols.filter((s) => {\n const key = `${s.kind}\\0${s.name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nfunction visitTopLevel(\n node: ts.Node,\n sourceFile: ts.SourceFile,\n checker: ts.TypeChecker,\n out: SymbolSignature[],\n): void {\n // `export default ...`\n if (ts.isExportAssignment(node)) {\n out.push(extractDefaultExport(node, sourceFile, checker));\n return;\n }\n\n // `export { foo, bar } [from './x']`\n if (ts.isExportDeclaration(node)) {\n extractExportDeclaration(node, sourceFile, checker, out);\n return;\n }\n\n if (!hasExportModifier(node)) return;\n\n const isDefault = hasDefaultModifier(node);\n\n if (ts.isFunctionDeclaration(node)) {\n const name = node.name?.text ?? (isDefault ? 'default' : undefined);\n if (!name) return;\n out.push({\n name,\n kind: 'function',\n signature: renderFunctionSignature(node, name, sourceFile, checker),\n });\n return;\n }\n\n if (ts.isClassDeclaration(node)) {\n const name = node.name?.text ?? (isDefault ? 'default' : undefined);\n if (!name) return;\n out.push({ name, kind: 'class', signature: `class ${name}` });\n return;\n }\n\n if (ts.isInterfaceDeclaration(node)) {\n out.push({\n name: node.name.text,\n kind: 'interface',\n signature: oneLineDeclaration(node, sourceFile, `interface ${node.name.text}`),\n });\n return;\n }\n\n if (ts.isTypeAliasDeclaration(node)) {\n out.push({\n name: node.name.text,\n kind: 'type',\n signature: oneLineDeclaration(node, sourceFile, `type ${node.name.text}`),\n });\n return;\n }\n\n if (ts.isEnumDeclaration(node)) {\n out.push({ name: node.name.text, kind: 'enum', signature: `enum ${node.name.text}` });\n return;\n }\n\n if (ts.isVariableStatement(node)) {\n for (const decl of node.declarationList.declarations) {\n if (!ts.isIdentifier(decl.name)) continue;\n const name = decl.name.text;\n out.push({\n name,\n kind: 'const',\n signature: renderVariableSignature(decl, name, checker),\n });\n }\n return;\n }\n}\n\nfunction extractDefaultExport(\n node: ts.ExportAssignment,\n sourceFile: ts.SourceFile,\n checker: ts.TypeChecker,\n): SymbolSignature {\n const expr = node.expression;\n if (ts.isIdentifier(expr)) {\n const sym = checker.getSymbolAtLocation(expr);\n const type = sym ? checker.getTypeOfSymbolAtLocation(sym, expr) : undefined;\n const signature = type ? checker.typeToString(type) : 'default';\n return { name: 'default', kind: 'const', signature };\n }\n return { name: 'default', kind: 'const', signature: expr.getText(sourceFile) };\n}\n\nfunction extractExportDeclaration(\n node: ts.ExportDeclaration,\n sourceFile: ts.SourceFile,\n checker: ts.TypeChecker,\n out: SymbolSignature[],\n): void {\n // `export * from './other'` — expand via the type checker, if possible.\n if (!node.exportClause && node.moduleSpecifier) {\n const moduleSymbol = checker.getSymbolAtLocation(node.moduleSpecifier);\n if (moduleSymbol) {\n for (const exp of checker.getExportsOfModule(moduleSymbol)) {\n out.push(renderExportedSymbol(exp.name, exp, checker, sourceFile));\n }\n }\n return;\n }\n\n if (node.exportClause && ts.isNamedExports(node.exportClause)) {\n for (const spec of node.exportClause.elements) {\n const name = (spec.name as ts.Identifier).text;\n const sym = checker.getSymbolAtLocation(spec.name);\n out.push(renderExportedSymbol(name, sym, checker, sourceFile));\n }\n }\n}\n\nfunction renderExportedSymbol(\n name: string,\n symbol: ts.Symbol | undefined,\n checker: ts.TypeChecker,\n sourceFile: ts.SourceFile,\n): SymbolSignature {\n if (!symbol) return { name, kind: 'const', signature: name };\n const aliased =\n (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;\n const decl = aliased.declarations?.[0];\n if (decl) {\n if (ts.isFunctionDeclaration(decl) || ts.isMethodDeclaration(decl)) {\n return {\n name,\n kind: 'function',\n signature: renderFunctionSignature(decl, name, sourceFile, checker),\n };\n }\n if (ts.isClassDeclaration(decl)) return { name, kind: 'class', signature: `class ${name}` };\n if (ts.isInterfaceDeclaration(decl)) {\n return {\n name,\n kind: 'interface',\n signature: oneLineDeclaration(decl, decl.getSourceFile(), `interface ${name}`),\n };\n }\n if (ts.isTypeAliasDeclaration(decl)) {\n return {\n name,\n kind: 'type',\n signature: oneLineDeclaration(decl, decl.getSourceFile(), `type ${name}`),\n };\n }\n if (ts.isEnumDeclaration(decl)) return { name, kind: 'enum', signature: `enum ${name}` };\n }\n const type = checker.getTypeOfSymbolAtLocation(aliased, sourceFile);\n return { name, kind: 'const', signature: checker.typeToString(type) };\n}\n\nfunction renderFunctionSignature(\n node: ts.FunctionDeclaration | ts.MethodDeclaration,\n name: string,\n _sourceFile: ts.SourceFile,\n checker: ts.TypeChecker,\n): string {\n const signature = checker.getSignatureFromDeclaration(node);\n if (!signature) return `function ${name}()`;\n return `function ${name}${checker.signatureToString(signature)}`;\n}\n\nfunction renderVariableSignature(\n decl: ts.VariableDeclaration,\n name: string,\n checker: ts.TypeChecker,\n): string {\n const type = checker.getTypeAtLocation(decl);\n return `const ${name}: ${checker.typeToString(type)}`;\n}\n\nfunction oneLineDeclaration(node: ts.Node, sourceFile: ts.SourceFile, fallback: string): string {\n try {\n const text = node.getText(sourceFile);\n const collapsed = text.replace(/\\s+/g, ' ').trim();\n return collapsed.length > 0 ? collapsed : fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction hasExportModifier(node: ts.Node): boolean {\n return (ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export) !== 0;\n}\n\nfunction hasDefaultModifier(node: ts.Node): boolean {\n return (ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Default) !== 0;\n}\n\n/**\n * Turn raw markdown/text into a bounded excerpt safe for embedding similarity:\n * collapse whitespace, strip the markdown formatting that confuses semantic search\n * (`#`, `*`, backticks), and truncate at a word boundary.\n */\nexport function formatReadmeExcerpt(raw: string, max: number): string {\n // Strip formatting characters that distort embedding similarity but keep the words.\n const stripped = raw.replace(/[#*`_~>]/g, '');\n // Collapse runs of any whitespace (incl. newlines/tabs) to single spaces.\n const collapsed = stripped.replace(/\\s+/g, ' ').trim();\n if (collapsed.length <= max) return collapsed;\n\n // Word-boundary truncate: keep the slice if it already ends on a word boundary\n // (i.e. the next char is whitespace), otherwise step back to the last space so\n // we don't break mid-word.\n const slice = collapsed.slice(0, max);\n const nextChar = collapsed.charAt(max);\n if (nextChar === '' || /\\s/.test(nextChar)) return slice;\n const lastSpace = slice.lastIndexOf(' ');\n if (lastSpace > 0) return slice.slice(0, lastSpace);\n return slice;\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, rename, stat, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { FILESYSTEM_LAYOUT, SCHEMA_VERSION, type UploadPayload } from '@macroscope/contracts';\nimport type { ScannedBlock } from './scanner.js';\n\n/**\n * T6 — content hasher + local cache.\n *\n * Substrate for the watcher (T14) and catch-up scan (T15): a deterministic\n * SHA-256 over the UploadPayload, plus a small on-disk cache keyed by blockId.\n *\n * DO NOT change the canonical-JSON algorithm without bumping a cache schema\n * version. Doing so silently invalidates every user's local hash cache AND\n * orphans every `contentHash` on cloud-side MeilisearchDoc records. The\n * fixed-vector test in `test/hasher.test.ts` pins the algorithm.\n */\n\n/**\n * Canonicalise a JSON-serialisable value into a deterministic string.\n *\n * Rules (wire-locked — see hasher.test.ts):\n * - Object keys sorted in code-unit (UTF-16) order, recursively.\n * - Keys with `undefined` values are omitted entirely.\n * - Arrays preserve insertion order.\n * - Strings are NFC-normalised before serialisation so composed vs\n * decomposed unicode produce the same byte output.\n * - Standard JSON escapes only (`\"`, `\\\\`, control chars). Non-ASCII\n * codepoints are emitted raw as UTF-8 — we rely on V8's RFC-8259\n * behaviour for `JSON.stringify` to do this for us.\n *\n * @internal Exposed for direct test access only; not part of the public API.\n * Public callers should use {@link hashPayload}. The canonical form is an\n * implementation detail of the hash and may move under a different name\n * without a major version bump.\n */\nexport function canonicalJSON(value: unknown): string {\n return stringify(value);\n}\n\nfunction stringify(value: unknown): string {\n if (value === null) return 'null';\n if (typeof value === 'string') return JSON.stringify(value.normalize('NFC'));\n if (typeof value === 'number' || typeof value === 'boolean') return JSON.stringify(value);\n if (Array.isArray(value)) {\n const parts = value.map((v) => (v === undefined ? 'null' : stringify(v)));\n return `[${parts.join(',')}]`;\n }\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj)\n .filter((k) => obj[k] !== undefined)\n .sort();\n const parts = keys.map((k) => `${JSON.stringify(k)}:${stringify(obj[k])}`);\n return `{${parts.join(',')}}`;\n }\n // undefined / function / symbol — UploadPayloadSchema rules these out, so\n // throw loudly if one shows up so tests catch it.\n throw new TypeError(`canonicalJSON: unsupported value type ${typeof value}`);\n}\n\n/**\n * Deterministic SHA-256 over the canonical-JSON serialisation of the payload.\n * Returns 64-character lowercase hex.\n */\nexport function hashPayload(payload: UploadPayload): string {\n const canonical = canonicalJSON(payload);\n return createHash('sha256').update(canonical, 'utf8').digest('hex');\n}\n\nexport interface HasherOptions {\n /** Override the workspace root for tests. Defaults to `process.cwd()`. */\n workspaceRoot?: string;\n}\n\nexport interface CacheEntry {\n /** SHA-256 hex of the canonical-JSON serialisation of the UploadPayload. */\n hash: string;\n /** Max(mtime ms) of the block's manifest + source + docs at hash time. */\n mtime: number;\n}\n\nexport type HashCache = Record<string, CacheEntry>;\n\n/**\n * On-disk envelope. Written as `{ schemaVersion, entries }` from T15 onward;\n * older deployments wrote the bare `HashCache` object. Both shapes are read\n * back into a `HashCache` by {@link loadHashCache}. T15's\n * {@link readSchemaVersion} returns `undefined` for the old flat shape, which\n * the catch-up scan treats as a schema mismatch (forced full re-push).\n */\ninterface HashCacheFile {\n schemaVersion: number;\n entries: HashCache;\n}\n\nfunction resolveHashesPath(opts?: HasherOptions): string {\n const root = opts?.workspaceRoot ?? process.cwd();\n return join(root, FILESYSTEM_LAYOUT.project.hashesFile);\n}\n\nasync function readCacheFile(\n opts?: HasherOptions,\n): Promise<{ schemaVersion: number | undefined; entries: HashCache } | null> {\n const path = resolveHashesPath(opts);\n let raw: string;\n try {\n raw = await readFile(path, 'utf8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n console.warn(`[macroscope] failed to read hash cache at ${path}: ${(err as Error).message}`);\n }\n return null;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n console.warn(`[macroscope] hash cache at ${path} is not valid JSON: ${(err as Error).message}`);\n return null;\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n console.warn(`[macroscope] hash cache at ${path} has unexpected shape; ignoring`);\n return null;\n }\n const obj = parsed as Record<string, unknown>;\n // Wrapped format detection: top-level `schemaVersion` (number) AND `entries`\n // (object). Anything else is the old flat shape that T6/T14 originally wrote.\n if (\n typeof obj.schemaVersion === 'number' &&\n obj.entries &&\n typeof obj.entries === 'object' &&\n !Array.isArray(obj.entries)\n ) {\n return { schemaVersion: obj.schemaVersion, entries: obj.entries as HashCache };\n }\n return { schemaVersion: undefined, entries: obj as HashCache };\n}\n\n/**\n * Load the cache from disk. NEVER throws: missing file or malformed JSON\n * return `{}` so the watcher can recover by re-hashing everything. Transparently\n * handles both the wrapped `{ schemaVersion, entries }` shape and the legacy\n * flat shape, returning entries either way.\n */\nexport async function loadHashCache(opts?: HasherOptions): Promise<HashCache> {\n const file = await readCacheFile(opts);\n return file?.entries ?? {};\n}\n\n/**\n * Read the persisted schemaVersion. Returns `undefined` for a missing file,\n * malformed JSON, or the legacy flat shape — all of which T15 treats as a\n * schema mismatch (forces a full re-push). Used by the catch-up scan.\n */\nexport async function readSchemaVersion(opts?: HasherOptions): Promise<number | undefined> {\n const file = await readCacheFile(opts);\n return file?.schemaVersion;\n}\n\n/**\n * Atomically write the cache to disk: write to a sibling `.tmp` file then\n * rename. Same-directory rename is atomic on POSIX filesystems. Throws on\n * real I/O failure — callers (watcher loop) decide whether to surface or\n * swallow the error.\n *\n * The on-disk shape is the wrapped envelope (`schemaVersion` + `entries`);\n * `schemaVersion` defaults to the current `SCHEMA_VERSION` from\n * `@macroscope/contracts` so T14's existing callsites transparently persist it.\n */\nexport async function saveHashCache(\n cache: HashCache,\n opts?: HasherOptions & { schemaVersion?: number },\n): Promise<void> {\n const path = resolveHashesPath(opts);\n const dir = dirname(path);\n await mkdir(dir, { recursive: true });\n const tmp = `${path}.tmp`;\n const envelope: HashCacheFile = {\n schemaVersion: opts?.schemaVersion ?? SCHEMA_VERSION,\n entries: cache,\n };\n const body = `${JSON.stringify(envelope, null, 2)}\\n`;\n await writeFile(tmp, body, 'utf8');\n await rename(tmp, path);\n}\n\n/**\n * Return the subset of blocks whose manifest, source, or docs files have an\n * mtime strictly greater than the cached entry's recorded mtime. Blocks\n * with no cache entry are always returned (first-time extraction needs them).\n *\n * Missing files (e.g. deleted between scan and stat) are treated as \"changed\"\n * — safer to re-process than silently drop. The watcher reconciles deletions\n * separately via \"in cache but not in scan\" diffing.\n */\nexport async function filterChangedBlocks(\n blocks: ScannedBlock[],\n cache: HashCache,\n): Promise<ScannedBlock[]> {\n const changed: ScannedBlock[] = [];\n for (const block of blocks) {\n const cached = cache[block.id];\n if (!cached) {\n changed.push(block);\n continue;\n }\n const maxMtime = await maxFileMtime(block);\n if (maxMtime === undefined || maxMtime > cached.mtime) {\n changed.push(block);\n }\n }\n return changed;\n}\n\nasync function maxFileMtime(block: ScannedBlock): Promise<number | undefined> {\n const paths: string[] = [join(block.path, 'macroscope.yaml')];\n if (block.resolvedPaths?.source) paths.push(block.resolvedPaths.source);\n if (block.resolvedPaths?.docs) paths.push(block.resolvedPaths.docs);\n\n let max: number | undefined;\n for (const p of paths) {\n try {\n const s = await stat(p);\n const m = s.mtimeMs;\n if (max === undefined || m > max) max = m;\n } catch {\n return undefined;\n }\n }\n return max;\n}\n"],"mappings":"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","names":["z","z","z","existsSync","join","join","existsSync","existsSync","readFile","readdir","dirname","join","resolve","parseYaml","join","existsSync","readdir","readFile","parseYaml","dirname","resolve","readFile","createHash","readFile","dirname","join","createHash","join","readFile","dirname","join"]}
package/dist/index.d.ts CHANGED
@@ -1 +1,29 @@
1
- export { B as Block, a as BlockManifest, b as BuildResult, H as Handler, R as RenderResult, T as TestResult, V as VERSION } from './index-BTDioymD.js';
1
+ import { ErrorEnvelope, HealthResponse, SearchRequest, SearchResponse, IndexBatchRequest, IndexBatchResponse, ScopeTouchRequest, ScopeTouchResponse, DeleteIndexResponse } from '@macroscope/contracts';
2
+ export { B as Block, a as BlockManifest, b as BuildResult, H as Handler, R as RenderResult, T as TestResult, V as VERSION } from './version-BTDioymD.js';
3
+
4
+ type Result<T> = {
5
+ kind: 'ok';
6
+ data: T;
7
+ } | {
8
+ kind: 'error';
9
+ envelope: ErrorEnvelope;
10
+ status: number;
11
+ };
12
+ interface CloudClientOptions {
13
+ /** Override the cloud base URL. Defaults to env MACROSCOPE_CLOUD_URL, then http://localhost:3001. */
14
+ baseUrl?: string;
15
+ /** Override the credentials path. Defaults to FILESYSTEM_LAYOUT.user.credentialsFile under os.homedir(). */
16
+ credentialsPath?: string;
17
+ /** Test seam — inject a fetch implementation. Defaults to globalThis.fetch. */
18
+ fetchImpl?: typeof fetch;
19
+ }
20
+ interface CloudClient {
21
+ health(): Promise<Result<HealthResponse>>;
22
+ search(req: SearchRequest): Promise<Result<SearchResponse>>;
23
+ indexBatch(req: IndexBatchRequest): Promise<Result<IndexBatchResponse>>;
24
+ scopeTouch(req: ScopeTouchRequest): Promise<Result<ScopeTouchResponse>>;
25
+ deleteIndex(): Promise<Result<DeleteIndexResponse>>;
26
+ }
27
+ declare function createCloudClient(opts?: CloudClientOptions): CloudClient;
28
+
29
+ export { type CloudClient, type CloudClientOptions, type Result, createCloudClient };