import { mkdirSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; /** * A knowledge surface written from THIS repo, for specs that need one installed. * * ⛔ Three Epic 7 specs seeded their temp workspace by copying the real assets out of * `../hexasync-templates-vscode-ext/assets` — a sibling checkout, from specs registered in no project, so the `unit` * project collected them and **CI ran them with one repository checked out**. Repointing one at an absent directory * reproduced it: 4 failed, `ENOENT`. The guard that exists for exactly this (`corpusCheckout.spec.ts`) missed them * because its `SIBLINGS` list holds ABSOLUTE paths and these used the relative form — the third time that file has * recorded "a check that passes by not looking", this time about itself. * * Registering them was the wrong fix. What they need the sibling FOR is fixture content, and none of their assertions * is about the extension's assets: they assert how the server slices, addresses and refuses. The real index, catalogue * and example set are pinned in the repo that owns them (`test/aiIndex.spec.ts`, `test/goldenAnswers.spec.ts`). So the * fixture moves here, each side asserts what it owns, and these specs keep running on CI — which is where the rule * "a spec that needs no checkout must not be registered" points. */ export function writeSurface(dir: string): string { const surface = join(dir, '.hexasync', 'intellisense'); mkdirSync(join(surface, 'docs'), { recursive: true }); mkdirSync(join(surface, 'connectors'), { recursive: true }); mkdirSync(join(surface, 'docs', 'objects'), { recursive: true }); // A guide, because Story 7.2 AC-1 names one among the addressable documents. writeFileSync( join(surface, 'docs', 'objects', 'object.md'), '# The object model\n\nAn object is the shape a task reads and writes.\n', ); // The Query DSL guide, added 2026-08-20 — `hexasync://guides/query-dsl`. mkdirSync(join(surface, 'docs', 'query-dsl'), { recursive: true }); writeFileSync( join(surface, 'docs', 'query-dsl', 'QUERY-DSL.md'), '# The Query DSL\n\nOne language with several hosts.\n', ); // The routing guide, added 2026-08-20 — `hexasync://guides/routing`. mkdirSync(join(surface, 'docs', 'routing'), { recursive: true }); writeFileSync( join(surface, 'docs', 'routing', 'NEXT.md'), '# `next` — how a step chooses its successor\n\nA `next` names a step by its `key`.\n', ); writeFileSync( join(surface, 'docs', 'AI-INDEX.md'), [ '', '# HexaSync agent index', '', 'Asset bundle 55 · extension 2608.8.1', '', 'A template describes one integration between two systems.', '', 'There are **two runtimes** — worker and frontend — and they must never be mixed.', '', 'Never invent an identity: a connector this platform does not list is a request, not a configuration.', '', '## Collections a project declares', '', '- `pullers` — one puller per entity.', '', '## Worker step types', '', '- `SQL`', '', '## Validation rule ids', '', '`STEP-1`, `REF-1`', '', ].join('\n'), ); writeFileSync( join(surface, 'docs', 'examples.json'), JSON.stringify({ entries: [ { id: 'sapo-v3-misa-amis', kind: 'integration', features: ['pull', 'push'], connectors: ['sapo-v3'], entities: ['order'], summary: 'Pulls orders from Sapo and pushes them to MISA AMIS.', status: 'unknown', }, ], }), ); writeFileSync( join(surface, 'connectors', 'catalog.json'), JSON.stringify([ { systemCode: 'shopify-public-app', name: 'Shopify', systemId: 'shopify', }, { systemCode: 'sapo-v3', name: 'Sapo', systemId: 'sapo' }, { name: 'A System With No Connector' }, ]), ); return dir; }