@lssm/bundle.contractspec-workspace 0.0.0-canary-20251217060834 → 0.0.0-canary-20251217072406
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.
- package/dist/_virtual/rolldown_runtime.js +22 -1
- package/dist/adapters/ai.js +82 -1
- package/dist/adapters/factory.js +36 -1
- package/dist/adapters/fs.js +118 -1
- package/dist/adapters/git.js +54 -1
- package/dist/adapters/index.js +7 -1
- package/dist/adapters/logger.js +80 -1
- package/dist/adapters/watcher.js +69 -1
- package/dist/adapters/workspace.js +190 -2
- package/dist/ai/agents/claude-code-agent.js +146 -9
- package/dist/ai/agents/cursor-agent.js +286 -17
- package/dist/ai/agents/index.js +5 -1
- package/dist/ai/agents/openai-codex-agent.js +140 -8
- package/dist/ai/agents/orchestrator.js +142 -1
- package/dist/ai/agents/simple-agent.js +80 -4
- package/dist/ai/client.js +162 -1
- package/dist/ai/index.js +27 -1
- package/dist/ai/prompts/code-generation.js +55 -13
- package/dist/ai/prompts/index.js +12 -1
- package/dist/ai/prompts/spec-creation.js +61 -20
- package/dist/ai/providers.js +40 -1
- package/dist/formatters/index.js +18 -1
- package/dist/formatters/json.js +71 -1
- package/dist/formatters/sarif.js +163 -1
- package/dist/formatters/text.js +208 -2
- package/dist/index.d.ts +0 -3
- package/dist/index.js +81 -1
- package/dist/libs/ai-providers/dist/factory.js +154 -0
- package/dist/libs/ai-providers/dist/index.js +4 -0
- package/dist/libs/ai-providers/dist/legacy.js +72 -0
- package/dist/libs/ai-providers/dist/models.js +287 -0
- package/dist/libs/ai-providers/dist/validation.js +1 -0
- package/dist/libs/contracts/dist/capabilities/openbanking.js +88 -0
- package/dist/libs/contracts/dist/client/index.js +5 -0
- package/dist/libs/contracts/dist/client/react/feature-render.js +2 -0
- package/dist/libs/contracts/dist/client/react/form-render.js +4 -0
- package/dist/libs/contracts/dist/client/react/index.js +4 -0
- package/dist/libs/contracts/dist/contract-registry/index.js +1 -0
- package/dist/libs/contracts/dist/contract-registry/schemas.js +60 -0
- package/dist/libs/contracts/dist/docs/PUBLISHING.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/accessibility_wcag_compliance_specs.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/index.js +29 -0
- package/dist/libs/contracts/dist/docs/presentations.js +71 -0
- package/dist/libs/contracts/dist/docs/registry.js +44 -0
- package/dist/libs/contracts/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/auth/better-auth-nextjs.docblock.js +80 -0
- package/dist/libs/contracts/dist/docs/tech/contracts/openapi-export.docblock.js +57 -0
- package/dist/libs/contracts/dist/docs/tech/lifecycle-stage-system.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/llm/llm-integration.docblock.js +357 -0
- package/dist/libs/contracts/dist/docs/tech/mcp-endpoints.docblock.js +37 -0
- package/dist/libs/contracts/dist/docs/tech/presentation-runtime.docblock.js +16 -0
- package/dist/libs/contracts/dist/docs/tech/schema/README.docblock.js +20 -0
- package/dist/libs/contracts/dist/docs/tech/studio/learning-events.docblock.js +48 -0
- package/dist/libs/contracts/dist/docs/tech/studio/learning-journeys.docblock.js +79 -0
- package/dist/libs/contracts/dist/docs/tech/studio/platform-admin-panel.docblock.js +84 -0
- package/dist/libs/contracts/dist/docs/tech/studio/project-access-teams.docblock.js +45 -0
- package/dist/libs/contracts/dist/docs/tech/studio/project-routing.docblock.js +67 -0
- package/dist/libs/contracts/dist/docs/tech/studio/sandbox-unlogged.docblock.js +40 -0
- package/dist/libs/contracts/dist/docs/tech/studio/team-invitations.docblock.js +69 -0
- package/dist/libs/contracts/dist/docs/tech/studio/workspace-ops.docblock.js +47 -0
- package/dist/libs/contracts/dist/docs/tech/studio/workspaces.docblock.js +62 -0
- package/dist/libs/contracts/dist/docs/tech/telemetry-ingest.docblock.js +155 -0
- package/dist/libs/contracts/dist/docs/tech/templates/runtime.docblock.js +20 -0
- package/dist/libs/contracts/dist/docs/tech/vscode-extension.docblock.js +101 -0
- package/dist/libs/contracts/dist/docs/tech/workflows/overview.docblock.js +20 -0
- package/dist/libs/contracts/dist/events.js +8 -0
- package/dist/libs/contracts/dist/experiments/evaluator.js +1 -0
- package/dist/libs/contracts/dist/index.js +72 -0
- package/dist/libs/contracts/dist/install.js +2 -0
- package/dist/libs/contracts/dist/integrations/contracts.js +377 -0
- package/dist/libs/contracts/dist/integrations/index.js +18 -0
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/accounts.js +228 -0
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/balances.js +159 -0
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/index.js +3 -0
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/transactions.js +210 -0
- package/dist/libs/contracts/dist/integrations/openbanking/models.js +242 -0
- package/dist/libs/contracts/dist/integrations/openbanking/telemetry.js +13 -0
- package/dist/libs/contracts/dist/integrations/providers/elevenlabs.js +52 -0
- package/dist/libs/contracts/dist/integrations/providers/gcs-storage.js +75 -0
- package/dist/libs/contracts/dist/integrations/providers/gmail.js +87 -0
- package/dist/libs/contracts/dist/integrations/providers/google-calendar.js +66 -0
- package/dist/libs/contracts/dist/integrations/providers/index.js +11 -0
- package/dist/libs/contracts/dist/integrations/providers/mistral.js +68 -0
- package/dist/libs/contracts/dist/integrations/providers/postmark.js +68 -0
- package/dist/libs/contracts/dist/integrations/providers/powens.js +116 -0
- package/dist/libs/contracts/dist/integrations/providers/qdrant.js +73 -0
- package/dist/libs/contracts/dist/integrations/providers/registry.js +10 -0
- package/dist/libs/contracts/dist/integrations/providers/stripe.js +83 -0
- package/dist/libs/contracts/dist/integrations/providers/twilio-sms.js +61 -0
- package/dist/libs/contracts/dist/jsonschema.js +24 -0
- package/dist/libs/contracts/dist/knowledge/contracts.js +306 -0
- package/dist/libs/contracts/dist/knowledge/index.js +7 -0
- package/dist/libs/contracts/dist/knowledge/spaces/email-threads.js +34 -0
- package/dist/libs/contracts/dist/knowledge/spaces/financial-docs.js +34 -0
- package/dist/libs/contracts/dist/knowledge/spaces/financial-overview.js +38 -0
- package/dist/libs/contracts/dist/knowledge/spaces/index.js +6 -0
- package/dist/libs/contracts/dist/knowledge/spaces/product-canon.js +34 -0
- package/dist/libs/contracts/dist/knowledge/spaces/support-faq.js +37 -0
- package/dist/libs/contracts/dist/knowledge/spaces/uploaded-docs.js +34 -0
- package/dist/libs/contracts/dist/llm/exporters.js +352 -0
- package/dist/libs/contracts/dist/llm/index.js +2 -0
- package/dist/libs/contracts/dist/llm/prompts.js +211 -0
- package/dist/libs/contracts/dist/onboarding-base.js +196 -0
- package/dist/libs/contracts/dist/openapi.js +75 -0
- package/dist/libs/contracts/dist/ownership.js +21 -0
- package/dist/libs/contracts/dist/presentations.js +1 -0
- package/dist/libs/contracts/dist/presentations.v2.js +11 -0
- package/dist/libs/contracts/dist/prompt.js +1 -0
- package/dist/libs/contracts/dist/promptRegistry.js +1 -0
- package/dist/libs/contracts/dist/regenerator/index.js +2 -0
- package/dist/libs/contracts/dist/regenerator/service.js +92 -0
- package/dist/libs/contracts/dist/regenerator/utils.js +51 -0
- package/dist/libs/contracts/dist/registry.js +208 -0
- package/dist/libs/contracts/dist/resources.js +1 -0
- package/dist/libs/contracts/dist/schema/dist/EnumType.js +2 -0
- package/dist/libs/contracts/dist/schema/dist/FieldType.js +49 -0
- package/dist/libs/contracts/dist/schema/dist/ScalarTypeEnum.js +236 -0
- package/dist/libs/contracts/dist/schema/dist/SchemaModel.js +34 -0
- package/dist/libs/contracts/dist/schema/dist/entity/defineEntity.js +1 -0
- package/dist/libs/contracts/dist/schema/dist/entity/index.js +2 -0
- package/dist/libs/contracts/dist/schema/dist/entity/types.js +1 -0
- package/dist/libs/contracts/dist/schema/dist/index.js +6 -0
- package/dist/libs/contracts/dist/server/graphql-pothos.js +6 -0
- package/dist/libs/contracts/dist/server/index.js +8 -0
- package/dist/libs/contracts/dist/server/mcp/createMcpServer.js +4 -0
- package/dist/libs/contracts/dist/server/mcp/registerPresentations.js +2 -0
- package/dist/libs/contracts/dist/server/mcp/registerPrompts.js +1 -0
- package/dist/libs/contracts/dist/server/mcp/registerResources.js +2 -0
- package/dist/libs/contracts/dist/server/mcp/registerTools.js +1 -0
- package/dist/libs/contracts/dist/server/provider-mcp.js +1 -0
- package/dist/libs/contracts/dist/server/rest-elysia.js +1 -0
- package/dist/libs/contracts/dist/server/rest-express.js +1 -0
- package/dist/libs/contracts/dist/server/rest-generic.js +1 -0
- package/dist/libs/contracts/dist/server/rest-next-app.js +1 -0
- package/dist/libs/contracts/dist/server/rest-next-pages.js +1 -0
- package/dist/libs/contracts/dist/spec.js +35 -0
- package/dist/libs/contracts/dist/telemetry/index.js +1 -0
- package/dist/libs/contracts/dist/telemetry/tracker.js +1 -0
- package/dist/libs/contracts/dist/tests/index.js +1 -0
- package/dist/libs/contracts/dist/tests/runner.js +150 -0
- package/dist/libs/contracts/dist/workflow/index.js +1 -0
- package/dist/libs/contracts/dist/workflow/runner.js +1 -0
- package/dist/libs/contracts-transformers/dist/common/utils.js +47 -0
- package/dist/libs/contracts-transformers/dist/openapi/exporter.js +1 -0
- package/dist/libs/contracts-transformers/dist/openapi/importer.js +255 -0
- package/dist/libs/contracts-transformers/dist/openapi/index.js +4 -0
- package/dist/libs/contracts-transformers/dist/openapi/parser.js +231 -0
- package/dist/libs/contracts-transformers/dist/openapi/schema-converter.js +201 -0
- package/dist/modules/contractspec-workspace/dist/ai/code-generation.js +137 -0
- package/dist/modules/contractspec-workspace/dist/ai/spec-creation.js +101 -0
- package/dist/modules/contractspec-workspace/dist/analysis/deps/graph.js +84 -0
- package/dist/modules/contractspec-workspace/dist/analysis/deps/parse-imports.js +30 -0
- package/dist/modules/contractspec-workspace/dist/analysis/diff/semantic.js +96 -0
- package/dist/modules/contractspec-workspace/dist/analysis/feature-scan.js +151 -0
- package/dist/modules/contractspec-workspace/dist/analysis/spec-scan.js +344 -0
- package/dist/modules/contractspec-workspace/dist/analysis/validate/spec-structure.js +122 -0
- package/dist/modules/contractspec-workspace/dist/templates/app-config.js +105 -0
- package/dist/modules/contractspec-workspace/dist/templates/data-view.js +68 -0
- package/dist/modules/contractspec-workspace/dist/templates/event.js +38 -0
- package/dist/modules/contractspec-workspace/dist/templates/experiment.js +87 -0
- package/dist/modules/contractspec-workspace/dist/templates/handler.js +95 -0
- package/dist/modules/contractspec-workspace/dist/templates/integration-utils.js +104 -0
- package/dist/modules/contractspec-workspace/dist/templates/integration.js +62 -0
- package/dist/modules/contractspec-workspace/dist/templates/knowledge.js +68 -0
- package/dist/modules/contractspec-workspace/dist/templates/migration.js +60 -0
- package/dist/modules/contractspec-workspace/dist/templates/operation.js +100 -0
- package/dist/modules/contractspec-workspace/dist/templates/presentation.js +78 -0
- package/dist/modules/contractspec-workspace/dist/templates/telemetry.js +89 -0
- package/dist/modules/contractspec-workspace/dist/templates/utils.js +38 -0
- package/dist/modules/contractspec-workspace/dist/templates/workflow-runner.js +48 -0
- package/dist/modules/contractspec-workspace/dist/templates/workflow.js +67 -0
- package/dist/modules/contractspec-workspace/dist/types/generation-types.js +20 -0
- package/dist/services/agent-guide/adapters/claude-code.js +144 -3
- package/dist/services/agent-guide/adapters/cursor-cli.js +135 -3
- package/dist/services/agent-guide/adapters/generic-mcp.js +159 -3
- package/dist/services/agent-guide/adapters/index.js +30 -1
- package/dist/services/agent-guide/agent-guide-service.js +148 -1
- package/dist/services/agent-guide/index.js +5 -1
- package/dist/services/build.js +140 -1
- package/dist/services/ci-check/ci-check-service.js +393 -1
- package/dist/services/ci-check/index.js +2 -1
- package/dist/services/ci-check/types.js +28 -1
- package/dist/services/clean.js +71 -1
- package/dist/services/config.js +76 -1
- package/dist/services/deps.js +62 -1
- package/dist/services/diff.js +33 -1
- package/dist/services/doctor/checks/ai.js +118 -2
- package/dist/services/doctor/checks/cli.js +146 -1
- package/dist/services/doctor/checks/config.js +170 -1
- package/dist/services/doctor/checks/deps.js +180 -1
- package/dist/services/doctor/checks/index.js +6 -1
- package/dist/services/doctor/checks/mcp.js +144 -1
- package/dist/services/doctor/checks/workspace.js +243 -1
- package/dist/services/doctor/doctor-service.js +115 -2
- package/dist/services/doctor/index.js +2 -1
- package/dist/services/doctor/types.js +26 -1
- package/dist/services/implementation/discovery.js +143 -2
- package/dist/services/implementation/index.js +2 -1
- package/dist/services/implementation/resolver.js +223 -1
- package/dist/services/index.js +53 -1
- package/dist/services/integrity-diagram.js +274 -6
- package/dist/services/integrity.js +272 -1
- package/dist/services/list.js +35 -1
- package/dist/services/openapi/export-service.js +51 -2
- package/dist/services/openapi/import-service.js +75 -1
- package/dist/services/openapi/index.js +4 -1
- package/dist/services/openapi/sync-service.js +121 -1
- package/dist/services/openapi/validate-service.js +130 -1
- package/dist/services/regenerator.js +23 -1
- package/dist/services/registry.js +73 -1
- package/dist/services/setup/config-generators.js +113 -26
- package/dist/services/setup/file-merger.js +60 -2
- package/dist/services/setup/index.js +4 -1
- package/dist/services/setup/setup-service.js +95 -1
- package/dist/services/setup/targets/agents-md.js +46 -1
- package/dist/services/setup/targets/cli-config.js +59 -1
- package/dist/services/setup/targets/cursor-rules.js +47 -1
- package/dist/services/setup/targets/mcp-claude.js +59 -1
- package/dist/services/setup/targets/mcp-cursor.js +58 -1
- package/dist/services/setup/targets/vscode-settings.js +62 -1
- package/dist/services/setup/types.js +26 -1
- package/dist/services/sync.js +62 -1
- package/dist/services/test.js +30 -1
- package/dist/services/validate-implementation.js +69 -1
- package/dist/services/validate.js +47 -1
- package/dist/services/verification-cache/adapters/filesystem.js +121 -1
- package/dist/services/verification-cache/adapters/in-memory.js +45 -1
- package/dist/services/verification-cache/adapters/index.js +3 -1
- package/dist/services/verification-cache/adapters/workspace-state.js +90 -1
- package/dist/services/verification-cache/cache-service.js +255 -1
- package/dist/services/verification-cache/index.js +6 -1
- package/dist/services/verification-cache/types.js +15 -1
- package/dist/services/verify/ai-verifier.js +336 -9
- package/dist/services/verify/behavior-verifier.js +185 -1
- package/dist/services/verify/index.js +4 -1
- package/dist/services/verify/structure-verifier.js +195 -2
- package/dist/services/verify/verify-service.js +203 -3
- package/dist/services/watch.js +31 -1
- package/dist/services/workspace-info.js +102 -2
- package/dist/templates/app-config.template.js +101 -28
- package/dist/templates/data-view.template.js +42 -27
- package/dist/templates/event.template.js +29 -14
- package/dist/templates/experiment.template.js +77 -51
- package/dist/templates/handler.template.js +53 -17
- package/dist/templates/index.js +36 -1
- package/dist/templates/integration.template.js +134 -50
- package/dist/templates/knowledge.template.js +62 -21
- package/dist/templates/migration.template.js +50 -26
- package/dist/templates/operation.template.js +44 -28
- package/dist/templates/presentation.template.js +46 -20
- package/dist/templates/telemetry.template.js +74 -53
- package/dist/templates/workflow-runner.template.js +12 -6
- package/dist/templates/workflow.template.js +51 -24
- package/package.json +13 -9
- package/dist/adapters/index.d.ts +0 -7
- package/dist/ports/index.d.ts +0 -5
- package/dist/services/agent-guide/index.d.ts +0 -6
- package/dist/services/ci-check/index.d.ts +0 -2
- package/dist/services/doctor/index.d.ts +0 -2
- package/dist/services/implementation/index.d.ts +0 -3
- package/dist/services/index.d.ts +0 -56
- package/dist/services/openapi/index.d.ts +0 -5
- package/dist/services/verification-cache/adapters/index.d.ts +0 -3
- package/dist/services/verification-cache/index.d.ts +0 -6
- package/dist/services/verify/index.d.ts +0 -5
|
@@ -1 +1,75 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { parseOpenApi } from "../../libs/contracts-transformers/dist/openapi/parser.js";
|
|
2
|
+
import { importFromOpenApi } from "../../libs/contracts-transformers/dist/openapi/importer.js";
|
|
3
|
+
import "../../libs/contracts-transformers/dist/openapi/index.js";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
|
|
6
|
+
//#region src/services/openapi/import-service.ts
|
|
7
|
+
/**
|
|
8
|
+
* OpenAPI import service - imports specs from OpenAPI documents.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Import ContractSpec specs from an OpenAPI document.
|
|
12
|
+
*/
|
|
13
|
+
async function importFromOpenApiService(options, adapters) {
|
|
14
|
+
const { fs, logger } = adapters;
|
|
15
|
+
const { source, outputDir, prefix, tags, exclude, defaultStability, defaultOwners, defaultAuth, dryRun = false } = options;
|
|
16
|
+
logger.info(`Importing from OpenAPI: ${source}`);
|
|
17
|
+
const parseResult = await parseOpenApi(source, {
|
|
18
|
+
fetch: globalThis.fetch,
|
|
19
|
+
readFile: (path) => fs.readFile(path)
|
|
20
|
+
});
|
|
21
|
+
if (parseResult.warnings.length > 0) for (const warning of parseResult.warnings) logger.warn(`Parse warning: ${warning}`);
|
|
22
|
+
logger.info(`Parsed ${parseResult.operations.length} operations from ${parseResult.info.title} v${parseResult.info.version}`);
|
|
23
|
+
const importResult = importFromOpenApi(parseResult, {
|
|
24
|
+
prefix,
|
|
25
|
+
tags,
|
|
26
|
+
exclude,
|
|
27
|
+
defaultStability,
|
|
28
|
+
defaultOwners,
|
|
29
|
+
defaultAuth
|
|
30
|
+
});
|
|
31
|
+
logger.info(`Import result: ${importResult.summary.imported} imported, ${importResult.summary.skipped} skipped, ${importResult.summary.errors} errors`);
|
|
32
|
+
const files = [];
|
|
33
|
+
const skippedOperations = [];
|
|
34
|
+
const errorMessages = [];
|
|
35
|
+
for (const spec of importResult.specs) {
|
|
36
|
+
const filePath = join(outputDir, spec.fileName);
|
|
37
|
+
if (dryRun) logger.info(`[DRY RUN] Would create: ${filePath}`);
|
|
38
|
+
else {
|
|
39
|
+
const dir = dirname(filePath);
|
|
40
|
+
await fs.mkdir(dir);
|
|
41
|
+
await fs.writeFile(filePath, spec.code);
|
|
42
|
+
logger.info(`Created: ${filePath}`);
|
|
43
|
+
}
|
|
44
|
+
files.push({
|
|
45
|
+
path: filePath,
|
|
46
|
+
operationId: spec.source.sourceId,
|
|
47
|
+
specName: spec.fileName.replace(".ts", "")
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (const skipped of importResult.skipped) {
|
|
51
|
+
skippedOperations.push({
|
|
52
|
+
operationId: skipped.sourceId,
|
|
53
|
+
reason: skipped.reason
|
|
54
|
+
});
|
|
55
|
+
logger.debug(`Skipped: ${skipped.sourceId} - ${skipped.reason}`);
|
|
56
|
+
}
|
|
57
|
+
for (const error of importResult.errors) {
|
|
58
|
+
errorMessages.push({
|
|
59
|
+
operationId: error.sourceId,
|
|
60
|
+
error: error.error
|
|
61
|
+
});
|
|
62
|
+
logger.error(`Error: ${error.sourceId} - ${error.error}`);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
imported: importResult.summary.imported,
|
|
66
|
+
skipped: importResult.summary.skipped,
|
|
67
|
+
errors: importResult.summary.errors,
|
|
68
|
+
files,
|
|
69
|
+
skippedOperations,
|
|
70
|
+
errorMessages
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { importFromOpenApiService };
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
import{importFromOpenApiService
|
|
1
|
+
import { importFromOpenApiService } from "./import-service.js";
|
|
2
|
+
import { syncWithOpenApiService } from "./sync-service.js";
|
|
3
|
+
import { validateAgainstOpenApiService } from "./validate-service.js";
|
|
4
|
+
import { exportOpenApi } from "./export-service.js";
|
|
@@ -1 +1,121 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { parseOpenApi } from "../../libs/contracts-transformers/dist/openapi/parser.js";
|
|
2
|
+
import { importFromOpenApi } from "../../libs/contracts-transformers/dist/openapi/importer.js";
|
|
3
|
+
import "../../libs/contracts-transformers/dist/openapi/index.js";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
|
|
6
|
+
//#region src/services/openapi/sync-service.ts
|
|
7
|
+
/**
|
|
8
|
+
* OpenAPI sync service - syncs specs with OpenAPI sources.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Sync ContractSpec specs with OpenAPI sources.
|
|
12
|
+
*/
|
|
13
|
+
async function syncWithOpenApiService(options, config, adapters) {
|
|
14
|
+
const { fs, logger } = adapters;
|
|
15
|
+
const { sources: optSources, sourceName, interactive, force, dryRun } = options;
|
|
16
|
+
const { sources: configSources, outputDir } = config;
|
|
17
|
+
let sourcesToSync = optSources ?? configSources ?? [];
|
|
18
|
+
if (sourceName) {
|
|
19
|
+
sourcesToSync = sourcesToSync.filter((s) => s.name === sourceName);
|
|
20
|
+
if (sourcesToSync.length === 0) throw new Error(`Source not found: ${sourceName}`);
|
|
21
|
+
}
|
|
22
|
+
if (sourcesToSync.length === 0) {
|
|
23
|
+
logger.warn("No OpenAPI sources configured. Add sources to .contractsrc.json");
|
|
24
|
+
return {
|
|
25
|
+
added: 0,
|
|
26
|
+
updated: 0,
|
|
27
|
+
unchanged: 0,
|
|
28
|
+
conflicts: 0,
|
|
29
|
+
changes: []
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const result = {
|
|
33
|
+
added: 0,
|
|
34
|
+
updated: 0,
|
|
35
|
+
unchanged: 0,
|
|
36
|
+
conflicts: 0,
|
|
37
|
+
changes: []
|
|
38
|
+
};
|
|
39
|
+
for (const source of sourcesToSync) {
|
|
40
|
+
logger.info(`Syncing with source: ${source.name}`);
|
|
41
|
+
const sourceLocation = source.url ?? source.file;
|
|
42
|
+
if (!sourceLocation) {
|
|
43
|
+
logger.warn(`Source ${source.name} has no url or file configured`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const parseResult = await parseOpenApi(sourceLocation, {
|
|
47
|
+
fetch: globalThis.fetch,
|
|
48
|
+
readFile: (path) => fs.readFile(path)
|
|
49
|
+
});
|
|
50
|
+
logger.info(`Parsed ${parseResult.operations.length} operations from ${source.name}`);
|
|
51
|
+
const importResult = importFromOpenApi(parseResult, {
|
|
52
|
+
prefix: source.prefix,
|
|
53
|
+
tags: source.tags,
|
|
54
|
+
exclude: source.exclude,
|
|
55
|
+
defaultStability: source.defaultStability,
|
|
56
|
+
defaultAuth: source.defaultAuth
|
|
57
|
+
});
|
|
58
|
+
for (const imported of importResult.specs) {
|
|
59
|
+
const filePath = join(outputDir, imported.fileName);
|
|
60
|
+
if (!await fs.exists(filePath)) {
|
|
61
|
+
if (!dryRun) {
|
|
62
|
+
const dir = dirname(filePath);
|
|
63
|
+
await fs.mkdir(dir);
|
|
64
|
+
await fs.writeFile(filePath, imported.code);
|
|
65
|
+
}
|
|
66
|
+
result.added++;
|
|
67
|
+
result.changes.push({
|
|
68
|
+
operationId: imported.source.sourceId,
|
|
69
|
+
action: "added",
|
|
70
|
+
path: filePath
|
|
71
|
+
});
|
|
72
|
+
logger.info(`Added: ${imported.source.sourceId}`);
|
|
73
|
+
} else if (await fs.readFile(filePath) === imported.code) {
|
|
74
|
+
result.unchanged++;
|
|
75
|
+
result.changes.push({
|
|
76
|
+
operationId: imported.source.sourceId,
|
|
77
|
+
action: "unchanged",
|
|
78
|
+
path: filePath
|
|
79
|
+
});
|
|
80
|
+
} else if (force === "openapi") {
|
|
81
|
+
if (!dryRun) await fs.writeFile(filePath, imported.code);
|
|
82
|
+
result.updated++;
|
|
83
|
+
result.changes.push({
|
|
84
|
+
operationId: imported.source.sourceId,
|
|
85
|
+
action: "updated",
|
|
86
|
+
path: filePath
|
|
87
|
+
});
|
|
88
|
+
logger.info(`Updated: ${imported.source.sourceId}`);
|
|
89
|
+
} else if (force === "contractspec") {
|
|
90
|
+
result.unchanged++;
|
|
91
|
+
result.changes.push({
|
|
92
|
+
operationId: imported.source.sourceId,
|
|
93
|
+
action: "unchanged",
|
|
94
|
+
path: filePath
|
|
95
|
+
});
|
|
96
|
+
logger.info(`Kept: ${imported.source.sourceId}`);
|
|
97
|
+
} else if (interactive) {
|
|
98
|
+
result.conflicts++;
|
|
99
|
+
result.changes.push({
|
|
100
|
+
operationId: imported.source.sourceId,
|
|
101
|
+
action: "conflict",
|
|
102
|
+
path: filePath
|
|
103
|
+
});
|
|
104
|
+
logger.warn(`Conflict: ${imported.source.sourceId} - needs resolution`);
|
|
105
|
+
} else {
|
|
106
|
+
result.conflicts++;
|
|
107
|
+
result.changes.push({
|
|
108
|
+
operationId: imported.source.sourceId,
|
|
109
|
+
action: "conflict",
|
|
110
|
+
path: filePath
|
|
111
|
+
});
|
|
112
|
+
logger.warn(`Conflict: ${imported.source.sourceId}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
logger.info(`Sync complete: ${result.added} added, ${result.updated} updated, ${result.unchanged} unchanged, ${result.conflicts} conflicts`);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
export { syncWithOpenApiService };
|
|
@@ -1 +1,130 @@
|
|
|
1
|
-
import{parseOpenApi
|
|
1
|
+
import { parseOpenApi } from "../../libs/contracts-transformers/dist/openapi/parser.js";
|
|
2
|
+
import "../../libs/contracts-transformers/dist/openapi/index.js";
|
|
3
|
+
|
|
4
|
+
//#region src/services/openapi/validate-service.ts
|
|
5
|
+
/**
|
|
6
|
+
* OpenAPI validation service - validates specs against OpenAPI sources.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Validate ContractSpec specs against an OpenAPI source.
|
|
10
|
+
*/
|
|
11
|
+
async function validateAgainstOpenApiService(options, adapters) {
|
|
12
|
+
const { fs, logger } = adapters;
|
|
13
|
+
const { specPath, openApiSource, ignoreDescriptions, ignoreTags, ignoreTransport } = options;
|
|
14
|
+
logger.info(`Validating specs against OpenAPI: ${openApiSource}`);
|
|
15
|
+
const parseResult = await parseOpenApi(openApiSource, {
|
|
16
|
+
fetch: globalThis.fetch,
|
|
17
|
+
readFile: (path) => fs.readFile(path)
|
|
18
|
+
});
|
|
19
|
+
logger.info(`Parsed ${parseResult.operations.length} operations from ${parseResult.info.title}`);
|
|
20
|
+
const operationsMap = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const op of parseResult.operations) operationsMap.set(op.operationId, op);
|
|
22
|
+
const results = [];
|
|
23
|
+
let specsValidated = 0;
|
|
24
|
+
let specsWithDiffs = 0;
|
|
25
|
+
const stat = await fs.stat(specPath);
|
|
26
|
+
const specFiles = [];
|
|
27
|
+
if (stat.isDirectory) {
|
|
28
|
+
const files = await fs.glob({
|
|
29
|
+
pattern: "**/*.ts",
|
|
30
|
+
cwd: specPath,
|
|
31
|
+
ignore: [
|
|
32
|
+
"node_modules/**",
|
|
33
|
+
"dist/**",
|
|
34
|
+
"*.test.ts",
|
|
35
|
+
"*.spec.ts"
|
|
36
|
+
],
|
|
37
|
+
absolute: true
|
|
38
|
+
});
|
|
39
|
+
specFiles.push(...files);
|
|
40
|
+
} else specFiles.push(specPath);
|
|
41
|
+
logger.info(`Found ${specFiles.length} spec files to validate`);
|
|
42
|
+
for (const file of specFiles) try {
|
|
43
|
+
const content = await fs.readFile(file);
|
|
44
|
+
const operationIdMatch = content.match(/operationId:\s*['"]([^'"]+)['"]/) || content.match(/name:\s*['"]([^'"]+)['"]/) || content.match(/export\s+const\s+(\w+)Spec\s*=/);
|
|
45
|
+
if (!operationIdMatch || !operationIdMatch[1]) {
|
|
46
|
+
logger.debug(`Could not extract operationId from ${file}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const specName = operationIdMatch[1];
|
|
50
|
+
specsValidated++;
|
|
51
|
+
let matchingOp;
|
|
52
|
+
matchingOp = operationsMap.get(specName);
|
|
53
|
+
if (!matchingOp) {
|
|
54
|
+
const snakeName = specName.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
55
|
+
matchingOp = operationsMap.get(snakeName);
|
|
56
|
+
}
|
|
57
|
+
if (!matchingOp) {
|
|
58
|
+
for (const [opId, op] of operationsMap) if (opId.toLowerCase().includes(specName.toLowerCase()) || specName.toLowerCase().includes(opId.toLowerCase())) {
|
|
59
|
+
matchingOp = op;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!matchingOp) {
|
|
64
|
+
results.push({
|
|
65
|
+
specPath: file,
|
|
66
|
+
valid: false,
|
|
67
|
+
diffs: [{
|
|
68
|
+
path: "",
|
|
69
|
+
type: "removed",
|
|
70
|
+
description: `No matching operation found in OpenAPI for spec: ${specName}`
|
|
71
|
+
}]
|
|
72
|
+
});
|
|
73
|
+
specsWithDiffs++;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const diffs = [];
|
|
77
|
+
if (matchingOp.deprecated && !content.includes("deprecated")) diffs.push({
|
|
78
|
+
path: "meta.stability",
|
|
79
|
+
type: "modified",
|
|
80
|
+
description: "OpenAPI operation is deprecated but spec does not indicate deprecation"
|
|
81
|
+
});
|
|
82
|
+
if (!ignoreTransport) {
|
|
83
|
+
const pathMatch = content.match(/path:\s*['"]([^'"]+)['"]/);
|
|
84
|
+
if (pathMatch && pathMatch[1] !== matchingOp.path) diffs.push({
|
|
85
|
+
path: "transport.rest.path",
|
|
86
|
+
type: "modified",
|
|
87
|
+
description: `Path mismatch: spec has "${pathMatch[1]}", OpenAPI has "${matchingOp.path}"`
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (!ignoreTransport) {
|
|
91
|
+
const methodMatch = content.match(/method:\s*['"]([^'"]+)['"]/);
|
|
92
|
+
if (methodMatch?.[1] && methodMatch[1].toLowerCase() !== matchingOp.method.toLowerCase()) diffs.push({
|
|
93
|
+
path: "transport.rest.method",
|
|
94
|
+
type: "modified",
|
|
95
|
+
description: `Method mismatch: spec has "${methodMatch[1]}", OpenAPI has "${matchingOp.method.toUpperCase()}"`
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const valid$1 = diffs.length === 0;
|
|
99
|
+
if (!valid$1) specsWithDiffs++;
|
|
100
|
+
results.push({
|
|
101
|
+
specPath: file,
|
|
102
|
+
operationId: matchingOp.operationId,
|
|
103
|
+
valid: valid$1,
|
|
104
|
+
diffs
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
logger.error(`Error validating ${file}: ${error}`);
|
|
108
|
+
results.push({
|
|
109
|
+
specPath: file,
|
|
110
|
+
valid: false,
|
|
111
|
+
diffs: [{
|
|
112
|
+
path: "",
|
|
113
|
+
type: "modified",
|
|
114
|
+
description: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
115
|
+
}]
|
|
116
|
+
});
|
|
117
|
+
specsWithDiffs++;
|
|
118
|
+
}
|
|
119
|
+
const valid = specsWithDiffs === 0;
|
|
120
|
+
logger.info(`Validation ${valid ? "passed" : "failed"}: ${specsValidated} specs checked, ${specsWithDiffs} with differences`);
|
|
121
|
+
return {
|
|
122
|
+
valid,
|
|
123
|
+
specsValidated,
|
|
124
|
+
specsWithDiffs,
|
|
125
|
+
results
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
export { validateAgainstOpenApiService };
|
|
@@ -1 +1,23 @@
|
|
|
1
|
-
import{RegeneratorService
|
|
1
|
+
import { RegeneratorService } from "../libs/contracts/dist/regenerator/service.js";
|
|
2
|
+
import "../libs/contracts/dist/regenerator/index.js";
|
|
3
|
+
|
|
4
|
+
//#region src/services/regenerator.ts
|
|
5
|
+
/**
|
|
6
|
+
* Regenerator service.
|
|
7
|
+
*
|
|
8
|
+
* Thin wrapper around `@lssm/lib.contracts/regenerator` for reuse across CLI/VSCode/web.
|
|
9
|
+
* This service does not perform module loading; callers provide resolved contexts/rules/sink.
|
|
10
|
+
*/
|
|
11
|
+
function createRegeneratorService(options) {
|
|
12
|
+
return new RegeneratorService({
|
|
13
|
+
contexts: options.contexts,
|
|
14
|
+
adapters: options.adapters ?? {},
|
|
15
|
+
rules: options.rules,
|
|
16
|
+
sink: options.sink,
|
|
17
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
18
|
+
batchDurationMs: options.batchDurationMs
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { createRegeneratorService };
|
|
@@ -1 +1,73 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/services/registry.ts
|
|
2
|
+
/**
|
|
3
|
+
* Registry client for interacting with ContractSpec registry.
|
|
4
|
+
*/
|
|
5
|
+
var RegistryClient = class {
|
|
6
|
+
registryUrl;
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
this.registryUrl = opts.registryUrl.replace(/\/+$/, "");
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Make GET request to registry.
|
|
12
|
+
*/
|
|
13
|
+
async getJson(path) {
|
|
14
|
+
const url = `${this.registryUrl}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
15
|
+
let res;
|
|
16
|
+
try {
|
|
17
|
+
res = await fetch(url, {
|
|
18
|
+
method: "GET",
|
|
19
|
+
headers: { Accept: "application/json" }
|
|
20
|
+
});
|
|
21
|
+
} catch (error) {
|
|
22
|
+
throw new Error(`Registry request failed: ${url} (${error instanceof Error ? error.message : String(error)})`);
|
|
23
|
+
}
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
const text = await res.text().catch(() => "");
|
|
26
|
+
throw new Error(`Registry request failed: ${res.status} ${res.statusText} ${text}`);
|
|
27
|
+
}
|
|
28
|
+
return await res.json();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Resolve registry URL from options or environment.
|
|
33
|
+
*/
|
|
34
|
+
function resolveRegistryUrl(cliRegistryUrl) {
|
|
35
|
+
return cliRegistryUrl || process.env.CONTRACTSPEC_REGISTRY_URL || "http://localhost:8090";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Add spec to registry.
|
|
39
|
+
*/
|
|
40
|
+
async function addToRegistry(specPath, options, adapters) {
|
|
41
|
+
const { logger } = adapters;
|
|
42
|
+
const registryUrl = resolveRegistryUrl(options.registryUrl);
|
|
43
|
+
logger.info(`Adding spec to registry: ${specPath}`, { registryUrl });
|
|
44
|
+
await new RegistryClient({ registryUrl }).getJson(`/specs/add?path=${encodeURIComponent(specPath)}`);
|
|
45
|
+
logger.info("Spec added to registry successfully");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* List specs from registry.
|
|
49
|
+
*/
|
|
50
|
+
async function listFromRegistry(options, adapters) {
|
|
51
|
+
const { logger } = adapters;
|
|
52
|
+
const registryUrl = resolveRegistryUrl(options.registryUrl);
|
|
53
|
+
logger.info("Listing specs from registry", { registryUrl });
|
|
54
|
+
const client = new RegistryClient({ registryUrl });
|
|
55
|
+
const filter = options.filter ? `?filter=${encodeURIComponent(options.filter)}` : "";
|
|
56
|
+
const specs = await client.getJson(`/specs${filter}`);
|
|
57
|
+
logger.info(`Found ${specs.length} specs`);
|
|
58
|
+
return specs;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Search registry for specs.
|
|
62
|
+
*/
|
|
63
|
+
async function searchRegistry(query, options, adapters) {
|
|
64
|
+
const { logger } = adapters;
|
|
65
|
+
const registryUrl = resolveRegistryUrl(options.registryUrl);
|
|
66
|
+
logger.info(`Searching registry: ${query}`, { registryUrl });
|
|
67
|
+
const results = await new RegistryClient({ registryUrl }).getJson(`/specs/search?q=${encodeURIComponent(query)}`);
|
|
68
|
+
logger.info(`Found ${results.length} results`);
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { RegistryClient, addToRegistry, listFromRegistry, resolveRegistryUrl, searchRegistry };
|
|
@@ -1,4 +1,72 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/services/setup/config-generators.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generate .contractsrc.json content.
|
|
4
|
+
*
|
|
5
|
+
* Adapts defaults based on monorepo scope.
|
|
6
|
+
*/
|
|
7
|
+
function generateContractsrcConfig(options) {
|
|
8
|
+
const isPackageLevel = options.isMonorepo && options.scope === "package";
|
|
9
|
+
return {
|
|
10
|
+
$schema: "https://contractspec.dev/schemas/contractsrc.json",
|
|
11
|
+
aiProvider: "claude",
|
|
12
|
+
aiModel: "claude-sonnet-4-20250514",
|
|
13
|
+
agentMode: "claude-code",
|
|
14
|
+
outputDir: "./src",
|
|
15
|
+
conventions: {
|
|
16
|
+
operations: "contracts/operations",
|
|
17
|
+
events: "contracts/events",
|
|
18
|
+
presentations: "contracts/presentations",
|
|
19
|
+
forms: "contracts/forms",
|
|
20
|
+
features: "contracts/features"
|
|
21
|
+
},
|
|
22
|
+
defaultOwners: options.defaultOwners ?? ["@team"],
|
|
23
|
+
defaultTags: [],
|
|
24
|
+
...isPackageLevel && options.packageName ? { package: options.packageName } : {}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generate .vscode/settings.json ContractSpec settings.
|
|
29
|
+
*/
|
|
30
|
+
function generateVscodeSettings() {
|
|
31
|
+
return {
|
|
32
|
+
"contractspec.validation.enabled": true,
|
|
33
|
+
"contractspec.validation.validateOnSave": true,
|
|
34
|
+
"contractspec.validation.validateOnOpen": true,
|
|
35
|
+
"contractspec.codeLens.enabled": true,
|
|
36
|
+
"contractspec.diagnostics.showWarnings": true,
|
|
37
|
+
"contractspec.diagnostics.showHints": true,
|
|
38
|
+
"contractspec.integrity.enabled": true,
|
|
39
|
+
"contractspec.integrity.checkOnSave": true
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Generate .cursor/mcp.json content.
|
|
44
|
+
*/
|
|
45
|
+
function generateCursorMcpConfig() {
|
|
46
|
+
return { mcpServers: { "contractspec-local": {
|
|
47
|
+
command: "bunx",
|
|
48
|
+
args: ["contractspec-mcp"]
|
|
49
|
+
} } };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Generate Claude Desktop MCP config.
|
|
53
|
+
* Returns the mcpServers section to merge into claude_desktop_config.json.
|
|
54
|
+
*/
|
|
55
|
+
function generateClaudeMcpConfig() {
|
|
56
|
+
return { mcpServers: { "contractspec-local": {
|
|
57
|
+
command: "bunx",
|
|
58
|
+
args: ["contractspec-mcp"]
|
|
59
|
+
} } };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Generate .cursor/rules/contractspec.mdc content.
|
|
63
|
+
*
|
|
64
|
+
* Adapts paths based on monorepo scope.
|
|
65
|
+
*/
|
|
66
|
+
function generateCursorRules(options) {
|
|
67
|
+
const projectName = options.projectName ?? "this project";
|
|
68
|
+
const basePath = options.isMonorepo && options.scope === "package" && options.packageRoot ? `${options.packageRoot.split("/").slice(-2).join("/")}/src/contracts` : "src/contracts";
|
|
69
|
+
return `# ContractSpec Development Rules
|
|
2
70
|
|
|
3
71
|
This project uses ContractSpec for spec-first development. Follow these guidelines when working with AI agents.
|
|
4
72
|
|
|
@@ -7,22 +75,14 @@ This project uses ContractSpec for spec-first development. Follow these guidelin
|
|
|
7
75
|
- **Always update contracts first** before changing implementation code.
|
|
8
76
|
- Contracts are the source of truth for operations, events, and presentations.
|
|
9
77
|
- Implementation code should be generated or derived from contracts.
|
|
10
|
-
${
|
|
11
|
-
## Monorepo Structure
|
|
12
|
-
|
|
13
|
-
This is a monorepo. Contracts may exist at:
|
|
14
|
-
- Package level: \`packages/*/src/contracts/\`
|
|
15
|
-
- Workspace level: \`src/contracts/\`
|
|
16
|
-
|
|
17
|
-
Check the appropriate level based on the feature scope.
|
|
18
|
-
`:``}
|
|
78
|
+
${options.isMonorepo ? `\n## Monorepo Structure\n\nThis is a monorepo. Contracts may exist at:\n- Package level: \`packages/*/src/contracts/\`\n- Workspace level: \`src/contracts/\`\n\nCheck the appropriate level based on the feature scope.\n` : ""}
|
|
19
79
|
## Contract Locations
|
|
20
80
|
|
|
21
81
|
Contracts are located in:
|
|
22
|
-
- \`${
|
|
23
|
-
- \`${
|
|
24
|
-
- \`${
|
|
25
|
-
- \`${
|
|
82
|
+
- \`${basePath}/operations/\` - Command and query specs
|
|
83
|
+
- \`${basePath}/events/\` - Event specs
|
|
84
|
+
- \`${basePath}/presentations/\` - UI presentation specs
|
|
85
|
+
- \`${basePath}/features/\` - Feature module specs
|
|
26
86
|
|
|
27
87
|
## When Making Changes
|
|
28
88
|
|
|
@@ -50,17 +110,28 @@ defineCommand({
|
|
|
50
110
|
});
|
|
51
111
|
\`\`\`
|
|
52
112
|
|
|
53
|
-
## Rules for ${
|
|
113
|
+
## Rules for ${projectName}
|
|
54
114
|
|
|
55
115
|
- All API endpoints must have a corresponding operation contract.
|
|
56
116
|
- Events must be declared in contracts before being emitted.
|
|
57
117
|
- UI components should reference presentation contracts.
|
|
58
118
|
- Feature flags should be defined in feature modules.
|
|
59
|
-
|
|
119
|
+
`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Generate AGENTS.md content.
|
|
123
|
+
*
|
|
124
|
+
* Adapts paths and instructions based on monorepo scope.
|
|
125
|
+
*/
|
|
126
|
+
function generateAgentsMd(options) {
|
|
127
|
+
const projectName = options.projectName ?? "This Project";
|
|
128
|
+
const isPackageLevel = options.isMonorepo && options.scope === "package";
|
|
129
|
+
const contractPath = "src/contracts/";
|
|
130
|
+
return `# AI Agent Guide
|
|
60
131
|
|
|
61
132
|
This repository uses **ContractSpec** for spec-first development. AI agents should follow these guidelines.
|
|
62
133
|
|
|
63
|
-
## Project: ${
|
|
134
|
+
## Project: ${projectName}
|
|
64
135
|
|
|
65
136
|
## ContractSpec Overview
|
|
66
137
|
|
|
@@ -71,7 +142,7 @@ ContractSpec is a deterministic, spec-first compiler that keeps AI-written softw
|
|
|
71
142
|
1. **Contracts are the source of truth** - Always check/update contracts before modifying implementation.
|
|
72
143
|
2. **Safe regeneration** - Code can be regenerated from specs without breaking invariants.
|
|
73
144
|
3. **Multi-surface consistency** - API, events, and UI stay in sync via shared contracts.
|
|
74
|
-
${
|
|
145
|
+
${options.isMonorepo ? `
|
|
75
146
|
## Monorepo Structure
|
|
76
147
|
|
|
77
148
|
This is a monorepo. Contracts can exist at multiple levels:
|
|
@@ -87,13 +158,13 @@ When adding a contract, consider:
|
|
|
87
158
|
|
|
88
159
|
### Current Scope
|
|
89
160
|
|
|
90
|
-
${
|
|
91
|
-
|
|
161
|
+
${isPackageLevel ? `You are working at the **package level**: \`${options.packageName ?? options.packageRoot}\`` : "You are working at the **workspace level**."}
|
|
162
|
+
` : ""}
|
|
92
163
|
## Working in This Repository
|
|
93
164
|
|
|
94
165
|
### Before Making Changes
|
|
95
166
|
|
|
96
|
-
1. Check for existing contracts in \`${
|
|
167
|
+
1. Check for existing contracts in \`${contractPath}\`
|
|
97
168
|
2. If a contract exists, update it first
|
|
98
169
|
3. Regenerate implementation with \`contractspec build\`
|
|
99
170
|
4. Validate with \`contractspec validate\`
|
|
@@ -109,10 +180,10 @@ ${n?`You are working at the **package level**: \`${e.packageName??e.packageRoot}
|
|
|
109
180
|
|
|
110
181
|
| Type | Location |
|
|
111
182
|
|------|----------|
|
|
112
|
-
| Operations | \`${
|
|
113
|
-
| Events | \`${
|
|
114
|
-
| Presentations | \`${
|
|
115
|
-
| Features | \`${
|
|
183
|
+
| Operations | \`${contractPath}operations/\` |
|
|
184
|
+
| Events | \`${contractPath}events/\` |
|
|
185
|
+
| Presentations | \`${contractPath}presentations/\` |
|
|
186
|
+
| Features | \`${contractPath}features/\` |
|
|
116
187
|
|
|
117
188
|
## MCP Tools Available
|
|
118
189
|
|
|
@@ -147,4 +218,20 @@ contractspec integrity
|
|
|
147
218
|
## Nested AGENTS.md
|
|
148
219
|
|
|
149
220
|
More specific instructions may exist in subdirectories. Check for \`AGENTS.md\` files in the relevant package or module.
|
|
150
|
-
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get the file path for Claude Desktop config based on platform.
|
|
225
|
+
*/
|
|
226
|
+
function getClaudeDesktopConfigPath() {
|
|
227
|
+
const platform = process.platform;
|
|
228
|
+
const homeDir = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "";
|
|
229
|
+
switch (platform) {
|
|
230
|
+
case "darwin": return `${homeDir}/Library/Application Support/Claude/claude_desktop_config.json`;
|
|
231
|
+
case "win32": return `${process.env["APPDATA"] ?? homeDir}/Claude/claude_desktop_config.json`;
|
|
232
|
+
default: return `${homeDir}/.config/claude/claude_desktop_config.json`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
//#endregion
|
|
237
|
+
export { generateAgentsMd, generateClaudeMcpConfig, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateVscodeSettings, getClaudeDesktopConfigPath };
|