wingfoil 0.2.1
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/LICENSE +21 -0
- package/README.md +334 -0
- package/dist/cli/error.d.ts +11 -0
- package/dist/cli/error.d.ts.map +1 -0
- package/dist/cli/error.js +27 -0
- package/dist/cli/error.js.map +1 -0
- package/dist/cli/exit.d.ts +19 -0
- package/dist/cli/exit.d.ts.map +1 -0
- package/dist/cli/exit.js +14 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/index.d.ts +28 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +36 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-command.d.ts +34 -0
- package/dist/cli/init-command.d.ts.map +1 -0
- package/dist/cli/init-command.js +100 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/mcp-command.d.ts +24 -0
- package/dist/cli/mcp-command.d.ts.map +1 -0
- package/dist/cli/mcp-command.js +42 -0
- package/dist/cli/mcp-command.js.map +1 -0
- package/dist/cli/output.d.ts +13 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +28 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/program.d.ts +12 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +279 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/registrar.d.ts +69 -0
- package/dist/cli/registrar.d.ts.map +1 -0
- package/dist/cli/registrar.js +82 -0
- package/dist/cli/registrar.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +45 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/approval-authority.d.ts +83 -0
- package/dist/core/approval-authority.d.ts.map +1 -0
- package/dist/core/approval-authority.js +112 -0
- package/dist/core/approval-authority.js.map +1 -0
- package/dist/core/builtin-asset.d.ts +71 -0
- package/dist/core/builtin-asset.d.ts.map +1 -0
- package/dist/core/builtin-asset.js +137 -0
- package/dist/core/builtin-asset.js.map +1 -0
- package/dist/core/builtin-integrity.d.ts +32 -0
- package/dist/core/builtin-integrity.d.ts.map +1 -0
- package/dist/core/builtin-integrity.js +148 -0
- package/dist/core/builtin-integrity.js.map +1 -0
- package/dist/core/confinement.d.ts +57 -0
- package/dist/core/confinement.d.ts.map +1 -0
- package/dist/core/confinement.js +108 -0
- package/dist/core/confinement.js.map +1 -0
- package/dist/core/context.d.ts +187 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +192 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/directive-assign.d.ts +131 -0
- package/dist/core/directive-assign.d.ts.map +1 -0
- package/dist/core/directive-assign.js +352 -0
- package/dist/core/directive-assign.js.map +1 -0
- package/dist/core/directives-list.d.ts +80 -0
- package/dist/core/directives-list.d.ts.map +1 -0
- package/dist/core/directives-list.js +148 -0
- package/dist/core/directives-list.js.map +1 -0
- package/dist/core/exit-code.d.ts +85 -0
- package/dist/core/exit-code.d.ts.map +1 -0
- package/dist/core/exit-code.js +163 -0
- package/dist/core/exit-code.js.map +1 -0
- package/dist/core/git-identity.d.ts +32 -0
- package/dist/core/git-identity.d.ts.map +1 -0
- package/dist/core/git-identity.js +72 -0
- package/dist/core/git-identity.js.map +1 -0
- package/dist/core/index.d.ts +388 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +1331 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/init.d.ts +78 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +167 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/loaders.d.ts +174 -0
- package/dist/core/loaders.d.ts.map +1 -0
- package/dist/core/loaders.js +364 -0
- package/dist/core/loaders.js.map +1 -0
- package/dist/core/memory-add-type.d.ts +43 -0
- package/dist/core/memory-add-type.d.ts.map +1 -0
- package/dist/core/memory-add-type.js +151 -0
- package/dist/core/memory-add-type.js.map +1 -0
- package/dist/core/memory-transition.d.ts +111 -0
- package/dist/core/memory-transition.d.ts.map +1 -0
- package/dist/core/memory-transition.js +269 -0
- package/dist/core/memory-transition.js.map +1 -0
- package/dist/core/registry.d.ts +189 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +66 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/relevance.d.ts +86 -0
- package/dist/core/relevance.d.ts.map +1 -0
- package/dist/core/relevance.js +258 -0
- package/dist/core/relevance.js.map +1 -0
- package/dist/core/require-reason.d.ts +27 -0
- package/dist/core/require-reason.d.ts.map +1 -0
- package/dist/core/require-reason.js +95 -0
- package/dist/core/require-reason.js.map +1 -0
- package/dist/core/types.d.ts +45 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +22 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/usage-error.d.ts +20 -0
- package/dist/core/usage-error.d.ts.map +1 -0
- package/dist/core/usage-error.js +29 -0
- package/dist/core/usage-error.js.map +1 -0
- package/dist/core/write-guard.d.ts +99 -0
- package/dist/core/write-guard.d.ts.map +1 -0
- package/dist/core/write-guard.js +247 -0
- package/dist/core/write-guard.js.map +1 -0
- package/dist/directives/create.d.ts +47 -0
- package/dist/directives/create.d.ts.map +1 -0
- package/dist/directives/create.js +82 -0
- package/dist/directives/create.js.map +1 -0
- package/dist/directives/index.d.ts +20 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +32 -0
- package/dist/directives/index.js.map +1 -0
- package/dist/directives/roles-edit.d.ts +53 -0
- package/dist/directives/roles-edit.d.ts.map +1 -0
- package/dist/directives/roles-edit.js +286 -0
- package/dist/directives/roles-edit.js.map +1 -0
- package/dist/directives/schema.d.ts +65 -0
- package/dist/directives/schema.d.ts.map +1 -0
- package/dist/directives/schema.js +68 -0
- package/dist/directives/schema.js.map +1 -0
- package/dist/dna/edit.d.ts +61 -0
- package/dist/dna/edit.d.ts.map +1 -0
- package/dist/dna/edit.js +429 -0
- package/dist/dna/edit.js.map +1 -0
- package/dist/dna/index.d.ts +24 -0
- package/dist/dna/index.d.ts.map +1 -0
- package/dist/dna/index.js +59 -0
- package/dist/dna/index.js.map +1 -0
- package/dist/dna/mutate.d.ts +74 -0
- package/dist/dna/mutate.d.ts.map +1 -0
- package/dist/dna/mutate.js +318 -0
- package/dist/dna/mutate.js.map +1 -0
- package/dist/dna/path.d.ts +175 -0
- package/dist/dna/path.d.ts.map +1 -0
- package/dist/dna/path.js +289 -0
- package/dist/dna/path.js.map +1 -0
- package/dist/dna/roles.d.ts +57 -0
- package/dist/dna/roles.d.ts.map +1 -0
- package/dist/dna/roles.js +50 -0
- package/dist/dna/roles.js.map +1 -0
- package/dist/dna/schema.d.ts +172 -0
- package/dist/dna/schema.d.ts.map +1 -0
- package/dist/dna/schema.js +182 -0
- package/dist/dna/schema.js.map +1 -0
- package/dist/dna/set.d.ts +145 -0
- package/dist/dna/set.d.ts.map +1 -0
- package/dist/dna/set.js +428 -0
- package/dist/dna/set.js.map +1 -0
- package/dist/mcp/dna-resource.d.ts +16 -0
- package/dist/mcp/dna-resource.d.ts.map +1 -0
- package/dist/mcp/dna-resource.js +56 -0
- package/dist/mcp/dna-resource.js.map +1 -0
- package/dist/mcp/index.d.ts +49 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +60 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/memory-resource.d.ts +17 -0
- package/dist/mcp/memory-resource.d.ts.map +1 -0
- package/dist/mcp/memory-resource.js +133 -0
- package/dist/mcp/memory-resource.js.map +1 -0
- package/dist/mcp/prompt.d.ts +48 -0
- package/dist/mcp/prompt.d.ts.map +1 -0
- package/dist/mcp/prompt.js +176 -0
- package/dist/mcp/prompt.js.map +1 -0
- package/dist/mcp/read-only.d.ts +42 -0
- package/dist/mcp/read-only.d.ts.map +1 -0
- package/dist/mcp/read-only.js +93 -0
- package/dist/mcp/read-only.js.map +1 -0
- package/dist/mcp/registrar.d.ts +54 -0
- package/dist/mcp/registrar.d.ts.map +1 -0
- package/dist/mcp/registrar.js +72 -0
- package/dist/mcp/registrar.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +64 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/workflow-resource.d.ts +17 -0
- package/dist/mcp/workflow-resource.d.ts.map +1 -0
- package/dist/mcp/workflow-resource.js +63 -0
- package/dist/mcp/workflow-resource.js.map +1 -0
- package/dist/memory/add.d.ts +50 -0
- package/dist/memory/add.d.ts.map +1 -0
- package/dist/memory/add.js +131 -0
- package/dist/memory/add.js.map +1 -0
- package/dist/memory/audit.d.ts +177 -0
- package/dist/memory/audit.d.ts.map +1 -0
- package/dist/memory/audit.js +287 -0
- package/dist/memory/audit.js.map +1 -0
- package/dist/memory/commit-message.d.ts +146 -0
- package/dist/memory/commit-message.d.ts.map +1 -0
- package/dist/memory/commit-message.js +203 -0
- package/dist/memory/commit-message.js.map +1 -0
- package/dist/memory/entry.d.ts +56 -0
- package/dist/memory/entry.d.ts.map +1 -0
- package/dist/memory/entry.js +28 -0
- package/dist/memory/entry.js.map +1 -0
- package/dist/memory/frontmatter-edit.d.ts +68 -0
- package/dist/memory/frontmatter-edit.d.ts.map +1 -0
- package/dist/memory/frontmatter-edit.js +333 -0
- package/dist/memory/frontmatter-edit.js.map +1 -0
- package/dist/memory/git-log.d.ts +32 -0
- package/dist/memory/git-log.d.ts.map +1 -0
- package/dist/memory/git-log.js +100 -0
- package/dist/memory/git-log.js.map +1 -0
- package/dist/memory/history.d.ts +142 -0
- package/dist/memory/history.d.ts.map +1 -0
- package/dist/memory/history.js +250 -0
- package/dist/memory/history.js.map +1 -0
- package/dist/memory/index.d.ts +58 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +107 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/query.d.ts +150 -0
- package/dist/memory/query.d.ts.map +1 -0
- package/dist/memory/query.js +307 -0
- package/dist/memory/query.js.map +1 -0
- package/dist/memory/reject.d.ts +11 -0
- package/dist/memory/reject.d.ts.map +1 -0
- package/dist/memory/reject.js +32 -0
- package/dist/memory/reject.js.map +1 -0
- package/dist/memory/schema.d.ts +104 -0
- package/dist/memory/schema.d.ts.map +1 -0
- package/dist/memory/schema.js +161 -0
- package/dist/memory/schema.js.map +1 -0
- package/dist/memory/state-machine.d.ts +166 -0
- package/dist/memory/state-machine.d.ts.map +1 -0
- package/dist/memory/state-machine.js +431 -0
- package/dist/memory/state-machine.js.map +1 -0
- package/dist/memory/submit.d.ts +11 -0
- package/dist/memory/submit.d.ts.map +1 -0
- package/dist/memory/submit.js +44 -0
- package/dist/memory/submit.js.map +1 -0
- package/dist/storage/builtin-directives.d.ts +54 -0
- package/dist/storage/builtin-directives.d.ts.map +1 -0
- package/dist/storage/builtin-directives.js +152 -0
- package/dist/storage/builtin-directives.js.map +1 -0
- package/dist/storage/commit.d.ts +92 -0
- package/dist/storage/commit.d.ts.map +1 -0
- package/dist/storage/commit.js +201 -0
- package/dist/storage/commit.js.map +1 -0
- package/dist/storage/confinement.d.ts +93 -0
- package/dist/storage/confinement.d.ts.map +1 -0
- package/dist/storage/confinement.js +164 -0
- package/dist/storage/confinement.js.map +1 -0
- package/dist/storage/document.d.ts +27 -0
- package/dist/storage/document.d.ts.map +1 -0
- package/dist/storage/document.js +52 -0
- package/dist/storage/document.js.map +1 -0
- package/dist/storage/errors.d.ts +36 -0
- package/dist/storage/errors.d.ts.map +1 -0
- package/dist/storage/errors.js +46 -0
- package/dist/storage/errors.js.map +1 -0
- package/dist/storage/frontmatter.d.ts +27 -0
- package/dist/storage/frontmatter.d.ts.map +1 -0
- package/dist/storage/frontmatter.js +37 -0
- package/dist/storage/frontmatter.js.map +1 -0
- package/dist/storage/git-root.d.ts +17 -0
- package/dist/storage/git-root.d.ts.map +1 -0
- package/dist/storage/git-root.js +49 -0
- package/dist/storage/git-root.js.map +1 -0
- package/dist/storage/index.d.ts +29 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +66 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/init-state.d.ts +9 -0
- package/dist/storage/init-state.d.ts.map +1 -0
- package/dist/storage/init-state.js +24 -0
- package/dist/storage/init-state.js.map +1 -0
- package/dist/storage/layout.d.ts +51 -0
- package/dist/storage/layout.d.ts.map +1 -0
- package/dist/storage/layout.js +88 -0
- package/dist/storage/layout.js.map +1 -0
- package/dist/storage/memory-path.d.ts +72 -0
- package/dist/storage/memory-path.d.ts.map +1 -0
- package/dist/storage/memory-path.js +127 -0
- package/dist/storage/memory-path.js.map +1 -0
- package/dist/storage/snapshot.d.ts +16 -0
- package/dist/storage/snapshot.d.ts.map +1 -0
- package/dist/storage/snapshot.js +72 -0
- package/dist/storage/snapshot.js.map +1 -0
- package/dist/storage/templates.d.ts +88 -0
- package/dist/storage/templates.d.ts.map +1 -0
- package/dist/storage/templates.js +422 -0
- package/dist/storage/templates.js.map +1 -0
- package/dist/validation/error-mapper.d.ts +16 -0
- package/dist/validation/error-mapper.d.ts.map +1 -0
- package/dist/validation/error-mapper.js +18 -0
- package/dist/validation/error-mapper.js.map +1 -0
- package/dist/validation/errors.d.ts +69 -0
- package/dist/validation/errors.d.ts.map +1 -0
- package/dist/validation/errors.js +69 -0
- package/dist/validation/errors.js.map +1 -0
- package/dist/validation/id.d.ts +16 -0
- package/dist/validation/id.d.ts.map +1 -0
- package/dist/validation/id.js +177 -0
- package/dist/validation/id.js.map +1 -0
- package/dist/validation/index.d.ts +18 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +37 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/secret-scan.d.ts +129 -0
- package/dist/validation/secret-scan.d.ts.map +1 -0
- package/dist/validation/secret-scan.js +367 -0
- package/dist/validation/secret-scan.js.map +1 -0
- package/dist/validation/two-pass.d.ts +24 -0
- package/dist/validation/two-pass.d.ts.map +1 -0
- package/dist/validation/two-pass.js +24 -0
- package/dist/validation/two-pass.js.map +1 -0
- package/dist/validation/warning.d.ts +31 -0
- package/dist/validation/warning.d.ts.map +1 -0
- package/dist/validation/warning.js +81 -0
- package/dist/validation/warning.js.map +1 -0
- package/dist/validation/yaml.d.ts +9 -0
- package/dist/validation/yaml.d.ts.map +1 -0
- package/dist/validation/yaml.js +30 -0
- package/dist/validation/yaml.js.map +1 -0
- package/dist/workflow/index.d.ts +10 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +16 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/schema.d.ts +89 -0
- package/dist/workflow/schema.d.ts.map +1 -0
- package/dist/workflow/schema.js +73 -0
- package/dist/workflow/schema.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MCP adapter's Tool/Resource registrar (spec-006-core-domain-api §2/§4,
|
|
3
|
+
* spec-004-mcp-surface-contract — task-006). `registerCoreModules` is the "Tool/Resource
|
|
4
|
+
* registrar" spec-006 §4.1 refers to: it iterates the exact same `enumerateOperations` order as
|
|
5
|
+
* `src/cli`'s registrar, and for each operation registers it as **either** an MCP Tool (`mutates:
|
|
6
|
+
* true`) **or** an MCP Resource (`mutates: false`) — never both, and never a hardcoded allow/deny
|
|
7
|
+
* list of operation names (§4.2). This is the structural half of REQ-SEC-05 ("MCP Resources are
|
|
8
|
+
* read-only — mutations only via validated MCP Tools"): a `mutates: true` operation is
|
|
9
|
+
* *structurally incapable* of being registered as a Resource by this function, and vice versa.
|
|
10
|
+
*
|
|
11
|
+
* Naming: Tool names use the dot form `{module}.{verb}` and Resource URIs use the `wingfoil://`
|
|
12
|
+
* scheme, both per spec-004 (§4.1, §2.1) — spec-004 is the spec explicitly scoped to `src/mcp`
|
|
13
|
+
* (`scope: "src/mcp"`), so it is authoritative for the actual wire-visible names here, ahead of
|
|
14
|
+
* spec-006 §5's own (looser, `src/core`-scoped) naming note, which uses a snake_case Tool-name
|
|
15
|
+
* form (`memory_approve`) that this task deliberately does not follow — see task-006's Execution
|
|
16
|
+
* Notes for the full reasoning on that spec-004/spec-006 naming discrepancy.
|
|
17
|
+
*
|
|
18
|
+
* Resource URIs today are the mechanical, zero-argument `wingfoil://{module}/{verb}` form — spec-004
|
|
19
|
+
* §2.1's fuller scheme (`wingfoil://memory/{type}/{id}`, `wingfoil://dna/{section}`, ...) adds
|
|
20
|
+
* sub-resource addressing that today's `CoreOperation` shape (spec-006 §2: just `{name, mutates,
|
|
21
|
+
* fn}`, no parameter metadata) cannot mechanically derive; that richer addressing is deferred to
|
|
22
|
+
* whichever feature task (018-030) first registers an operation that needs it.
|
|
23
|
+
*/
|
|
24
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
25
|
+
import type { CoreModule, ParamsBuilder } from '../core/registry';
|
|
26
|
+
/** Ambient dependencies {@link registerCoreModules} needs: how to resolve the project root and how to shape each operation's params. */
|
|
27
|
+
export interface RegisterCoreModulesOptions {
|
|
28
|
+
/** Resolves the project root a core call is served from (an ambient concern, not a Tool/Resource argument). */
|
|
29
|
+
readonly resolveRoot: () => string;
|
|
30
|
+
/** Turns a `ParamsContext` into one operation's typed params (`../core/registry.ts`'s {@link ParamsBuilder}). */
|
|
31
|
+
readonly buildParams: ParamsBuilder;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `{module}.{verb}` — spec-004 §4.1's Tool naming convention (mechanical transform of the CLI verb).
|
|
35
|
+
* An empty `verb` (`deriveVerb`'s flat/no-verb form, task-028-implement-paths-category) collapses to
|
|
36
|
+
* the bare module name — there is no verb segment to append a `.` before.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deriveMcpToolName(moduleName: string, verb: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* `wingfoil://{module}/{verb}` — spec-004 §2.1's URI scheme, applied mechanically (see module doc).
|
|
41
|
+
* Same empty-verb collapse as {@link deriveMcpToolName}: `wingfoil://{module}`, not a trailing-slash
|
|
42
|
+
* `wingfoil://{module}/`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function deriveMcpResourceUri(moduleName: string, verb: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Register every operation in `modules` onto `server`: `mutates: true` as a Tool, `mutates: false`
|
|
47
|
+
* as a Resource. Each handler wraps exactly one core call (spec-006 §2) and serializes its
|
|
48
|
+
* `CoreResult` — a successful value as JSON text; a `CoreResult.error` as a Tool `isError: true`
|
|
49
|
+
* response (spec-004 §4.3's "rejected identically to the CLI path") or, for a Resource read (which
|
|
50
|
+
* has no `isError` flag in the MCP protocol), a thrown error surfaced as a protocol-level read
|
|
51
|
+
* failure (spec-004 §2.2's "resource not found"-style refusal, generalized to any read failure).
|
|
52
|
+
*/
|
|
53
|
+
export declare function registerCoreModules(server: McpServer, modules: readonly CoreModule[], options: RegisterCoreModulesOptions): void;
|
|
54
|
+
//# sourceMappingURL=registrar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registrar.d.ts","sourceRoot":"","sources":["../../src/mcp/registrar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGlE,wIAAwI;AACxI,MAAM,WAAW,0BAA0B;IACzC,+GAA+G;IAC/G,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,iHAAiH;IACjH,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,OAAO,EAAE,0BAA0B,GAClC,IAAI,CA+CN"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveMcpToolName = deriveMcpToolName;
|
|
4
|
+
exports.deriveMcpResourceUri = deriveMcpResourceUri;
|
|
5
|
+
exports.registerCoreModules = registerCoreModules;
|
|
6
|
+
const registry_1 = require("../core/registry");
|
|
7
|
+
/**
|
|
8
|
+
* `{module}.{verb}` — spec-004 §4.1's Tool naming convention (mechanical transform of the CLI verb).
|
|
9
|
+
* An empty `verb` (`deriveVerb`'s flat/no-verb form, task-028-implement-paths-category) collapses to
|
|
10
|
+
* the bare module name — there is no verb segment to append a `.` before.
|
|
11
|
+
*/
|
|
12
|
+
function deriveMcpToolName(moduleName, verb) {
|
|
13
|
+
return verb ? `${moduleName}.${verb}` : moduleName;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `wingfoil://{module}/{verb}` — spec-004 §2.1's URI scheme, applied mechanically (see module doc).
|
|
17
|
+
* Same empty-verb collapse as {@link deriveMcpToolName}: `wingfoil://{module}`, not a trailing-slash
|
|
18
|
+
* `wingfoil://{module}/`.
|
|
19
|
+
*/
|
|
20
|
+
function deriveMcpResourceUri(moduleName, verb) {
|
|
21
|
+
return verb ? `wingfoil://${moduleName}/${verb}` : `wingfoil://${moduleName}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Register every operation in `modules` onto `server`: `mutates: true` as a Tool, `mutates: false`
|
|
25
|
+
* as a Resource. Each handler wraps exactly one core call (spec-006 §2) and serializes its
|
|
26
|
+
* `CoreResult` — a successful value as JSON text; a `CoreResult.error` as a Tool `isError: true`
|
|
27
|
+
* response (spec-004 §4.3's "rejected identically to the CLI path") or, for a Resource read (which
|
|
28
|
+
* has no `isError` flag in the MCP protocol), a thrown error surfaced as a protocol-level read
|
|
29
|
+
* failure (spec-004 §2.2's "resource not found"-style refusal, generalized to any read failure).
|
|
30
|
+
*/
|
|
31
|
+
function registerCoreModules(server, modules, options) {
|
|
32
|
+
// Always advertise both channels (spec-004 §1: Resources and Tools are fixed channel types of
|
|
33
|
+
// the MCP surface), even when `modules` currently has zero operations of one kind — as is the
|
|
34
|
+
// case for the real production registry today (0 mutating ops; see task-006 Execution Notes).
|
|
35
|
+
// Without this, a client's `tools/list` call on a server with zero registered Tools fails at the
|
|
36
|
+
// protocol level ("Method not found") because the SDK only auto-declares a capability the first
|
|
37
|
+
// time something is registered under it.
|
|
38
|
+
server.server.registerCapabilities({ tools: {}, resources: {} });
|
|
39
|
+
for (const { module, operation } of (0, registry_1.enumerateOperations)(modules)) {
|
|
40
|
+
const verb = (0, registry_1.deriveVerb)(module.name, operation.name);
|
|
41
|
+
const callCore = async () => {
|
|
42
|
+
const params = options.buildParams({
|
|
43
|
+
moduleName: module.name,
|
|
44
|
+
operationName: operation.name,
|
|
45
|
+
root: options.resolveRoot(),
|
|
46
|
+
});
|
|
47
|
+
const result = await operation.fn(params);
|
|
48
|
+
return result.ok ? { ok: true, text: JSON.stringify(result.value) } : { ok: false, message: result.error.message };
|
|
49
|
+
};
|
|
50
|
+
if (operation.mutates) {
|
|
51
|
+
const toolName = deriveMcpToolName(module.name, verb);
|
|
52
|
+
server.registerTool(toolName, { description: `${module.name} ${verb} (mutating)` }, async () => {
|
|
53
|
+
const outcome = await callCore();
|
|
54
|
+
return outcome.ok
|
|
55
|
+
? { content: [{ type: 'text', text: outcome.text }] }
|
|
56
|
+
: { content: [{ type: 'text', text: outcome.message }], isError: true };
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const uri = deriveMcpResourceUri(module.name, verb);
|
|
61
|
+
const resourceName = deriveMcpToolName(module.name, verb);
|
|
62
|
+
server.registerResource(resourceName, uri, { description: `${module.name} ${verb} (read-only)` }, async (readUri) => {
|
|
63
|
+
const outcome = await callCore();
|
|
64
|
+
if (outcome.ok) {
|
|
65
|
+
return { contents: [{ uri: readUri.toString(), mimeType: 'application/json', text: outcome.text }] };
|
|
66
|
+
}
|
|
67
|
+
throw new Error(outcome.message);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=registrar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registrar.js","sourceRoot":"","sources":["../../src/mcp/registrar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PRODUCTION MCP server entry point (task-030-implement-mcp-resources, P5.2.1,
|
|
3
|
+
* spec-014-mcp-server-entry-point §2/§3, spec-004-mcp-surface-contract §1). This is the first place in
|
|
4
|
+
* the codebase that constructs a real `McpServer` for a shippable process — everything before it
|
|
5
|
+
* (task-006's `registerCoreModules`, task-011's `registerReadOnlyResources`) only ever ran against the
|
|
6
|
+
* SDK's in-memory transport inside tests.
|
|
7
|
+
*
|
|
8
|
+
* The module is split into a testable constructor and a thin, un-testable transport seam — the same
|
|
9
|
+
* pattern `src/cli/program.ts`'s `commander` wiring and `src/cli/init-command.ts`'s `createReadlinePrompt`
|
|
10
|
+
* already use, and for the same reason:
|
|
11
|
+
*
|
|
12
|
+
* - {@link createMcpServer} does all the wiring (construct the `McpServer`, register the v0.1 channel
|
|
13
|
+
* set) and performs NO transport / stdio / process I/O, so it is exercised end-to-end over the SDK's
|
|
14
|
+
* in-memory transport + a real `Client` in `test/mcp/server.test.ts` (the three P5.2.1 acceptance
|
|
15
|
+
* criteria + the read-only-only scope assertion).
|
|
16
|
+
* - {@link startMcpServer} adds the single line that cannot be unit-tested without opening a real
|
|
17
|
+
* stdio channel: `server.connect(new StdioServerTransport())`. It is verified by hand / at runtime,
|
|
18
|
+
* never by an automated test (a test must never open a real stdio server against a repo).
|
|
19
|
+
*
|
|
20
|
+
* Channel scope (spec-014 §3): `createMcpServer` registers the read-only Resources channel
|
|
21
|
+
* (`registerReadOnlyResources` — spec-004 §2, P5.2.1) and, since task-058-mcp-prompts-role-based
|
|
22
|
+
* (P5.2.2, v0.2), the read-only role Prompts channel (`registerRolePrompts` — spec-004 §3). It
|
|
23
|
+
* deliberately does NOT call `registerCoreModules`, which would advertise a mutating Tool for every
|
|
24
|
+
* `mutates: true` CoreOperation (as of task-025, `dnaSet` -> the `dna.set` Tool) — Tools are P5.2.3
|
|
25
|
+
* (v0.4) scope and will extend the channel set here later; the entry point (`wingfoil mcp` + this
|
|
26
|
+
* transport wiring) is unchanged by those additions.
|
|
27
|
+
*/
|
|
28
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
29
|
+
/** Construction/connection options for the production MCP server. */
|
|
30
|
+
export interface McpServerOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the project root the Resource handlers read from — invoked lazily, per request, by
|
|
33
|
+
* task-011's already-registered handlers (never at construction time). The `wingfoil mcp` command
|
|
34
|
+
* resolves the root once up front and passes a closure returning that value (spec-014 §1).
|
|
35
|
+
*/
|
|
36
|
+
readonly resolveRoot: () => string;
|
|
37
|
+
/** Server identity `name`; defaults to `wingfoil`. */
|
|
38
|
+
readonly name?: string;
|
|
39
|
+
/** Server identity `version`; defaults to `0.0.0` (the `wingfoil mcp` command passes the real package version). */
|
|
40
|
+
readonly version?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Construct the production `McpServer` and register the read-only Resources and role Prompts channels
|
|
44
|
+
* on it (spec-014 §3). Pure and synchronous — no transport, no stdio, no filesystem read, no process
|
|
45
|
+
* side effects (spec-014 §2: "no I/O at construction time beyond wiring handlers"); every handler
|
|
46
|
+
* resolves the root and reads the project per request. So a test can connect it over the SDK's
|
|
47
|
+
* in-memory transport and drive it with a real `Client`, and `wingfoil mcp` never fails to start
|
|
48
|
+
* because of the project's content.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createMcpServer(options: McpServerOptions): McpServer;
|
|
51
|
+
/**
|
|
52
|
+
* Construct the server via {@link createMcpServer} and connect it over a real `StdioServerTransport`.
|
|
53
|
+
* Resolves once the transport is connected; the process then stays alive serving requests until the
|
|
54
|
+
* transport closes (client disconnect / stdin EOF). The `server.connect(...)` line is the only part of
|
|
55
|
+
* this module not covered by an automated test (the thin stdio seam — see the module doc).
|
|
56
|
+
*/
|
|
57
|
+
export declare function startMcpServer(options: McpServerOptions): Promise<McpServer>;
|
|
58
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,sDAAsD;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mHAAmH;IACnH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAQpE;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAKlF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMcpServer = createMcpServer;
|
|
4
|
+
exports.startMcpServer = startMcpServer;
|
|
5
|
+
/**
|
|
6
|
+
* The PRODUCTION MCP server entry point (task-030-implement-mcp-resources, P5.2.1,
|
|
7
|
+
* spec-014-mcp-server-entry-point §2/§3, spec-004-mcp-surface-contract §1). This is the first place in
|
|
8
|
+
* the codebase that constructs a real `McpServer` for a shippable process — everything before it
|
|
9
|
+
* (task-006's `registerCoreModules`, task-011's `registerReadOnlyResources`) only ever ran against the
|
|
10
|
+
* SDK's in-memory transport inside tests.
|
|
11
|
+
*
|
|
12
|
+
* The module is split into a testable constructor and a thin, un-testable transport seam — the same
|
|
13
|
+
* pattern `src/cli/program.ts`'s `commander` wiring and `src/cli/init-command.ts`'s `createReadlinePrompt`
|
|
14
|
+
* already use, and for the same reason:
|
|
15
|
+
*
|
|
16
|
+
* - {@link createMcpServer} does all the wiring (construct the `McpServer`, register the v0.1 channel
|
|
17
|
+
* set) and performs NO transport / stdio / process I/O, so it is exercised end-to-end over the SDK's
|
|
18
|
+
* in-memory transport + a real `Client` in `test/mcp/server.test.ts` (the three P5.2.1 acceptance
|
|
19
|
+
* criteria + the read-only-only scope assertion).
|
|
20
|
+
* - {@link startMcpServer} adds the single line that cannot be unit-tested without opening a real
|
|
21
|
+
* stdio channel: `server.connect(new StdioServerTransport())`. It is verified by hand / at runtime,
|
|
22
|
+
* never by an automated test (a test must never open a real stdio server against a repo).
|
|
23
|
+
*
|
|
24
|
+
* Channel scope (spec-014 §3): `createMcpServer` registers the read-only Resources channel
|
|
25
|
+
* (`registerReadOnlyResources` — spec-004 §2, P5.2.1) and, since task-058-mcp-prompts-role-based
|
|
26
|
+
* (P5.2.2, v0.2), the read-only role Prompts channel (`registerRolePrompts` — spec-004 §3). It
|
|
27
|
+
* deliberately does NOT call `registerCoreModules`, which would advertise a mutating Tool for every
|
|
28
|
+
* `mutates: true` CoreOperation (as of task-025, `dnaSet` -> the `dna.set` Tool) — Tools are P5.2.3
|
|
29
|
+
* (v0.4) scope and will extend the channel set here later; the entry point (`wingfoil mcp` + this
|
|
30
|
+
* transport wiring) is unchanged by those additions.
|
|
31
|
+
*/
|
|
32
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
33
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
34
|
+
const index_1 = require("./index");
|
|
35
|
+
/**
|
|
36
|
+
* Construct the production `McpServer` and register the read-only Resources and role Prompts channels
|
|
37
|
+
* on it (spec-014 §3). Pure and synchronous — no transport, no stdio, no filesystem read, no process
|
|
38
|
+
* side effects (spec-014 §2: "no I/O at construction time beyond wiring handlers"); every handler
|
|
39
|
+
* resolves the root and reads the project per request. So a test can connect it over the SDK's
|
|
40
|
+
* in-memory transport and drive it with a real `Client`, and `wingfoil mcp` never fails to start
|
|
41
|
+
* because of the project's content.
|
|
42
|
+
*/
|
|
43
|
+
function createMcpServer(options) {
|
|
44
|
+
const server = new mcp_js_1.McpServer({
|
|
45
|
+
name: options.name ?? 'wingfoil',
|
|
46
|
+
version: options.version ?? '0.0.0',
|
|
47
|
+
});
|
|
48
|
+
(0, index_1.registerReadOnlyResources)(server, { resolveRoot: options.resolveRoot });
|
|
49
|
+
(0, index_1.registerRolePrompts)(server, { resolveRoot: options.resolveRoot });
|
|
50
|
+
return server;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Construct the server via {@link createMcpServer} and connect it over a real `StdioServerTransport`.
|
|
54
|
+
* Resolves once the transport is connected; the process then stays alive serving requests until the
|
|
55
|
+
* transport closes (client disconnect / stdin EOF). The `server.connect(...)` line is the only part of
|
|
56
|
+
* this module not covered by an automated test (the thin stdio seam — see the module doc).
|
|
57
|
+
*/
|
|
58
|
+
async function startMcpServer(options) {
|
|
59
|
+
const server = createMcpServer(options);
|
|
60
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
61
|
+
await server.connect(transport);
|
|
62
|
+
return server;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";;AAsDA,0CAQC;AAQD,wCAKC;AA3ED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,oEAAoE;AACpE,wEAAiF;AAEjF,mCAAyE;AAgBzE;;;;;;;GAOG;AACH,SAAgB,eAAe,CAAC,OAAyB;IACvD,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC;QAC3B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,UAAU;QAChC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO;KACpC,CAAC,CAAC;IACH,IAAA,iCAAyB,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACxE,IAAA,2BAAmB,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,cAAc,CAAC,OAAyB;IAC5D,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/** Options for {@link registerWorkflowResources}. */
|
|
3
|
+
export interface RegisterWorkflowResourcesOptions {
|
|
4
|
+
/** Resolves the project root each Workflow Resource read is served from (an ambient concern, not a request parameter). */
|
|
5
|
+
readonly resolveRoot: () => string;
|
|
6
|
+
}
|
|
7
|
+
/** spec-004 §2.1 — every loaded workflow (main + sub), summary only. */
|
|
8
|
+
export declare const WORKFLOWS_COLLECTION_URI = "wingfoil://workflows";
|
|
9
|
+
/** spec-004 §2.1 — one workflow definition, by `name` (Layer 2 `Workflow.name`). */
|
|
10
|
+
export declare const WORKFLOW_DOCUMENT_URI_TEMPLATE = "wingfoil://workflows/{name}";
|
|
11
|
+
/**
|
|
12
|
+
* Register both Workflow Resources on `server`. Reads `.wingfoil/workflows.yaml` + every included
|
|
13
|
+
* Layer-2 file fresh on every request (no server-lifetime cache), matching every other Resource this
|
|
14
|
+
* task registers.
|
|
15
|
+
*/
|
|
16
|
+
export declare function registerWorkflowResources(server: McpServer, options: RegisterWorkflowResourcesOptions): void;
|
|
17
|
+
//# sourceMappingURL=workflow-resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-resource.d.ts","sourceRoot":"","sources":["../../src/mcp/workflow-resource.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,qDAAqD;AACrD,MAAM,WAAW,gCAAgC;IAC/C,0HAA0H;IAC1H,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;CACpC;AAED,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAC/D,oFAAoF;AACpF,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,gCAAgC,GAAG,IAAI,CAqC5G"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WORKFLOW_DOCUMENT_URI_TEMPLATE = exports.WORKFLOWS_COLLECTION_URI = void 0;
|
|
4
|
+
exports.registerWorkflowResources = registerWorkflowResources;
|
|
5
|
+
/**
|
|
6
|
+
* `wingfoil://workflows` (collection) and `wingfoil://workflows/{name}` (a single workflow
|
|
7
|
+
* definition) Resources — task-011-mcp-resources-read-only, REQ-INT-01,
|
|
8
|
+
* spec-004-mcp-surface-contract §2.1. Distinct from `registerCoreModules`'s existing
|
|
9
|
+
* `wingfoil://workflow/list` Resource (task-006-dual-interface-shared-core, the generic
|
|
10
|
+
* `wingfoil://{module}/{verb}` transform of the `workflowList` `CoreOperation`) — both coexist; this
|
|
11
|
+
* module adds the spec-004 §2.1-conformant plural `wingfoil://workflows` addressing plus
|
|
12
|
+
* per-workflow single-document addressing, neither of which `registerCoreModules`'s mechanical,
|
|
13
|
+
* zero-argument URI derivation can produce (spec-006 §2's `CoreOperation` shape has no
|
|
14
|
+
* sub-resource/parameter metadata — see `src/mcp/registrar.ts`'s own doc comment).
|
|
15
|
+
*
|
|
16
|
+
* A workflow's `name` (Layer 2 `Workflow.name`, spec-003-workflows-yaml-schema) is the addressing key
|
|
17
|
+
* — both `kind: main` and `kind: sub` workflows are addressable through the same URI form; nothing
|
|
18
|
+
* here distinguishes them beyond what each workflow's own `kind` field already reports.
|
|
19
|
+
*
|
|
20
|
+
* Registered directly via `McpServer.registerResource`, not through `registerCoreModules`'s
|
|
21
|
+
* `CoreModule[]` registry — no `workflowShow` `CoreOperation` exists yet; same
|
|
22
|
+
* spec-006-core-domain-api §4 parity deviation `memory-resource.ts`/`dna-resource.ts` document for
|
|
23
|
+
* their own Resources, for the same reason (task-030-implement-mcp-resources' scope).
|
|
24
|
+
*/
|
|
25
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
26
|
+
const core_1 = require("../core");
|
|
27
|
+
const read_only_1 = require("./read-only");
|
|
28
|
+
/** spec-004 §2.1 — every loaded workflow (main + sub), summary only. */
|
|
29
|
+
exports.WORKFLOWS_COLLECTION_URI = 'wingfoil://workflows';
|
|
30
|
+
/** spec-004 §2.1 — one workflow definition, by `name` (Layer 2 `Workflow.name`). */
|
|
31
|
+
exports.WORKFLOW_DOCUMENT_URI_TEMPLATE = 'wingfoil://workflows/{name}';
|
|
32
|
+
/**
|
|
33
|
+
* Register both Workflow Resources on `server`. Reads `.wingfoil/workflows.yaml` + every included
|
|
34
|
+
* Layer-2 file fresh on every request (no server-lifetime cache), matching every other Resource this
|
|
35
|
+
* task registers.
|
|
36
|
+
*/
|
|
37
|
+
function registerWorkflowResources(server, options) {
|
|
38
|
+
server.registerResource('workflows.list', exports.WORKFLOWS_COLLECTION_URI, { description: 'every loaded workflow definition, summary only (read-only)' }, async (uri, extra) => {
|
|
39
|
+
(0, read_only_1.refuseIfWriteIntent)(extra._meta);
|
|
40
|
+
const root = options.resolveRoot();
|
|
41
|
+
const { workflows } = (0, core_1.loadWorkflowsYaml)(root);
|
|
42
|
+
// Deterministic order (REQ-SYS-07): sorted by `name`, independent of `include` list order.
|
|
43
|
+
const summaries = [...workflows]
|
|
44
|
+
.map(({ name, kind, description }) => ({ name, kind, description }))
|
|
45
|
+
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
46
|
+
return (0, read_only_1.jsonResourceResult)(uri, summaries);
|
|
47
|
+
});
|
|
48
|
+
const documentTemplate = new mcp_js_1.ResourceTemplate(exports.WORKFLOW_DOCUMENT_URI_TEMPLATE, { list: undefined });
|
|
49
|
+
server.registerResource('workflows.show', documentTemplate, { description: 'one workflow definition, full content (read-only)' }, async (uri, variables, extra) => {
|
|
50
|
+
(0, read_only_1.refuseIfWriteIntent)(extra._meta);
|
|
51
|
+
const root = options.resolveRoot();
|
|
52
|
+
const { workflows } = (0, core_1.loadWorkflowsYaml)(root);
|
|
53
|
+
// `variables.name` is typed `string | string[]` (see `memory-resource.ts`'s identical note on
|
|
54
|
+
// `{type}`/`{id}`) — this template's `{name}` has no explode modifier, so it is always a single
|
|
55
|
+
// string in practice.
|
|
56
|
+
const name = variables.name;
|
|
57
|
+
const workflow = workflows.find((candidate) => candidate.name === name);
|
|
58
|
+
if (!workflow)
|
|
59
|
+
throw (0, read_only_1.resourceNotFoundError)(`workflows/${name}`);
|
|
60
|
+
return (0, read_only_1.jsonResourceResult)(uri, workflow);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=workflow-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-resource.js","sourceRoot":"","sources":["../../src/mcp/workflow-resource.ts"],"names":[],"mappings":";;;AA2CA,8DAqCC;AAhFD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,oEAA2E;AAG3E,kCAA4C;AAE5C,2CAA6F;AAQ7F,wEAAwE;AAC3D,QAAA,wBAAwB,GAAG,sBAAsB,CAAC;AAC/D,oFAAoF;AACvE,QAAA,8BAA8B,GAAG,6BAA6B,CAAC;AAE5E;;;;GAIG;AACH,SAAgB,yBAAyB,CAAC,MAAiB,EAAE,OAAyC;IACpG,MAAM,CAAC,gBAAgB,CACrB,gBAAgB,EAChB,gCAAwB,EACxB,EAAE,WAAW,EAAE,4DAA4D,EAAE,EAC7E,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,IAAA,+BAAmB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAA,wBAAiB,EAAC,IAAI,CAAC,CAAC;QAC9C,2FAA2F;QAC3F,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC;aAC7B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;aACnE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpE,OAAO,IAAA,8BAAkB,EAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC5C,CAAC,CACF,CAAC;IAEF,MAAM,gBAAgB,GAAG,IAAI,yBAAgB,CAAC,sCAA8B,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACnG,MAAM,CAAC,gBAAgB,CACrB,gBAAgB,EAChB,gBAAgB,EAChB,EAAE,WAAW,EAAE,mDAAmD,EAAE,EACpE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;QAC9B,IAAA,+BAAmB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAA,wBAAiB,EAAC,IAAI,CAAC,CAAC;QAC9C,8FAA8F;QAC9F,gGAAgG;QAChG,sBAAsB;QACtB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAc,CAAC;QACtC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,iCAAqB,EAAC,aAAa,IAAI,EAAE,CAAC,CAAC;QAEhE,OAAO,IAAA,8BAAkB,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn a human `--title` into a single, valid `[a-z0-9-.]` ID slug piece (spec-009-validation-strategy
|
|
3
|
+
* §1's ID character class, the same one `generateId` enforces): lowercase, every run of characters
|
|
4
|
+
* outside `[a-z0-9]` collapsed to one `-`, and no leading/trailing/doubled `-`. Deterministic and
|
|
5
|
+
* idempotent-shaped so `generateId`'s Pass-B slug check (`[a-z0-9.]+(?:-[a-z0-9.]+)*`) accepts it.
|
|
6
|
+
*/
|
|
7
|
+
export declare function slugifyTitle(title: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Parse the CLI `--tags "a,b,c"` value into a trimmed, non-empty string array, or `undefined` when the
|
|
10
|
+
* option is absent or contributes no tags (so `renderAddDocument` leaves the scaffold's `tags` at its
|
|
11
|
+
* default rather than writing an empty list).
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseTags(raw: string | undefined): string[] | undefined;
|
|
14
|
+
/** Whether an `id_pattern` contains a `{n}`-family numeric token (e.g. `task-{n}-{slug}`) — i.e. it
|
|
15
|
+
* needs a sequence counter resolved before {@link generateId} can render it. */
|
|
16
|
+
export declare function hasNumericToken(idPattern: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The directory that holds every document of a type: the type's `path` pattern
|
|
19
|
+
* (spec-001-memory-yaml-schema `MemoryTypeEntry.path`, e.g. `docs/memory/decision/{id}.md`) rendered
|
|
20
|
+
* with a dummy `{id}` and reduced to its containing directory. The directory portion never depends on
|
|
21
|
+
* the concrete id value, so this is well-defined before the id is generated (used by
|
|
22
|
+
* {@link nextSequenceNumber} to count existing siblings).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveTypeDirectory(root: string, pathPattern: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* The next sequence number for a `{n}`-token id: `1 +` the count of existing files in `dir` whose
|
|
27
|
+
* basename (sans `.md`) matches `idPattern` (`patternToRegExp`, task-002). Deterministic — a count is
|
|
28
|
+
* independent of directory-entry order (REQ-SYS-07) — and confined to this type's own directory, so
|
|
29
|
+
* unrelated files never perturb it. Returns `1` when the directory does not yet exist.
|
|
30
|
+
*/
|
|
31
|
+
export declare function nextSequenceNumber(dir: string, idPattern: string): number;
|
|
32
|
+
/** The fields `memory.add` pins on the freshly-created draft document (P1.3 memory.add / spec-010). */
|
|
33
|
+
export interface AddDocumentFields {
|
|
34
|
+
readonly id: string;
|
|
35
|
+
readonly title: string;
|
|
36
|
+
readonly tags?: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Copy a type's `template.file` scaffold verbatim and fill only the frontmatter skeleton `memory.add`
|
|
40
|
+
* pins (P1.3; spec-010-memory-frontmatter-schema): the generated `id`, the `--title`, the
|
|
41
|
+
* initial `status: draft`, and — when `--tags` was supplied — the `tags` flow sequence. Every other
|
|
42
|
+
* field (notably `type` and `tmpl_version`, spec-010: not touched by add) and the whole body are left
|
|
43
|
+
* exactly as the scaffold had them. `title`/`tags` are JSON-quoted (valid YAML double-quoted scalars /
|
|
44
|
+
* flow sequences), so an arbitrary title with spaces or colons is written safely.
|
|
45
|
+
*
|
|
46
|
+
* @throws when the scaffold has no frontmatter block (a malformed template — a config error surfaced
|
|
47
|
+
* as a thrown `Error` the core op maps to a `CoreError`).
|
|
48
|
+
*/
|
|
49
|
+
export declare function renderAddDocument(scaffold: string, fields: AddDocumentFields): string;
|
|
50
|
+
//# sourceMappingURL=add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/memory/add.ts"],"names":[],"mappings":"AAmBA;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAOvE;AAED;gFACgF;AAChF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAK1D;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQzE;AAED,uGAAuG;AACvG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAsBD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAcrF"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.slugifyTitle = slugifyTitle;
|
|
4
|
+
exports.parseTags = parseTags;
|
|
5
|
+
exports.hasNumericToken = hasNumericToken;
|
|
6
|
+
exports.resolveTypeDirectory = resolveTypeDirectory;
|
|
7
|
+
exports.nextSequenceNumber = nextSequenceNumber;
|
|
8
|
+
exports.renderAddDocument = renderAddDocument;
|
|
9
|
+
/**
|
|
10
|
+
* Pure/domain helpers behind `wingfoil memory add` (P1.3, task-020-implement-memory-add). Factored
|
|
11
|
+
* out of the `CoreResult`-wrapped orchestration in `src/core` so that (mirroring `dna set`'s split —
|
|
12
|
+
* pure `setDnaValue` in `src/dna`, the `CoreFn` in `src/core`) the surface-facing operation stays a
|
|
13
|
+
* thin composition and the id/slug/document-render logic is independently unit-testable.
|
|
14
|
+
*
|
|
15
|
+
* Every function here is deterministic (REQ-SYS-07): a slug is a pure function of the title, the
|
|
16
|
+
* rendered document a pure function of `(scaffold, id, title, tags)`, and the sequence counter a pure
|
|
17
|
+
* function of the committed on-disk state (a stable count, order-independent) — no wall-clock, no
|
|
18
|
+
* randomness, no unordered iteration in a value that reaches the produced id or document.
|
|
19
|
+
*/
|
|
20
|
+
const fs_1 = require("fs");
|
|
21
|
+
const path_1 = require("path");
|
|
22
|
+
const storage_1 = require("../storage");
|
|
23
|
+
const validation_1 = require("../validation");
|
|
24
|
+
const TOKEN_RE = /\{([^{}]+)\}/g;
|
|
25
|
+
/**
|
|
26
|
+
* Turn a human `--title` into a single, valid `[a-z0-9-.]` ID slug piece (spec-009-validation-strategy
|
|
27
|
+
* §1's ID character class, the same one `generateId` enforces): lowercase, every run of characters
|
|
28
|
+
* outside `[a-z0-9]` collapsed to one `-`, and no leading/trailing/doubled `-`. Deterministic and
|
|
29
|
+
* idempotent-shaped so `generateId`'s Pass-B slug check (`[a-z0-9.]+(?:-[a-z0-9.]+)*`) accepts it.
|
|
30
|
+
*/
|
|
31
|
+
function slugifyTitle(title) {
|
|
32
|
+
return title
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
35
|
+
.replace(/^-+|-+$/g, '');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse the CLI `--tags "a,b,c"` value into a trimmed, non-empty string array, or `undefined` when the
|
|
39
|
+
* option is absent or contributes no tags (so `renderAddDocument` leaves the scaffold's `tags` at its
|
|
40
|
+
* default rather than writing an empty list).
|
|
41
|
+
*/
|
|
42
|
+
function parseTags(raw) {
|
|
43
|
+
if (raw === undefined)
|
|
44
|
+
return undefined;
|
|
45
|
+
const tags = raw
|
|
46
|
+
.split(',')
|
|
47
|
+
.map((tag) => tag.trim())
|
|
48
|
+
.filter((tag) => tag.length > 0);
|
|
49
|
+
return tags.length > 0 ? tags : undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Whether an `id_pattern` contains a `{n}`-family numeric token (e.g. `task-{n}-{slug}`) — i.e. it
|
|
52
|
+
* needs a sequence counter resolved before {@link generateId} can render it. */
|
|
53
|
+
function hasNumericToken(idPattern) {
|
|
54
|
+
for (const match of idPattern.matchAll(TOKEN_RE)) {
|
|
55
|
+
if (/^n+$/.test(match[1] ?? ''))
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The directory that holds every document of a type: the type's `path` pattern
|
|
62
|
+
* (spec-001-memory-yaml-schema `MemoryTypeEntry.path`, e.g. `docs/memory/decision/{id}.md`) rendered
|
|
63
|
+
* with a dummy `{id}` and reduced to its containing directory. The directory portion never depends on
|
|
64
|
+
* the concrete id value, so this is well-defined before the id is generated (used by
|
|
65
|
+
* {@link nextSequenceNumber} to count existing siblings).
|
|
66
|
+
*/
|
|
67
|
+
function resolveTypeDirectory(root, pathPattern) {
|
|
68
|
+
return (0, path_1.dirname)((0, path_1.join)(root, (0, storage_1.renderMemoryPath)(pathPattern, { id: '__id__' })));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The next sequence number for a `{n}`-token id: `1 +` the count of existing files in `dir` whose
|
|
72
|
+
* basename (sans `.md`) matches `idPattern` (`patternToRegExp`, task-002). Deterministic — a count is
|
|
73
|
+
* independent of directory-entry order (REQ-SYS-07) — and confined to this type's own directory, so
|
|
74
|
+
* unrelated files never perturb it. Returns `1` when the directory does not yet exist.
|
|
75
|
+
*/
|
|
76
|
+
function nextSequenceNumber(dir, idPattern) {
|
|
77
|
+
if (!(0, fs_1.existsSync)(dir) || !(0, fs_1.statSync)(dir).isDirectory())
|
|
78
|
+
return 1;
|
|
79
|
+
const re = (0, validation_1.patternToRegExp)(idPattern);
|
|
80
|
+
let count = 0;
|
|
81
|
+
for (const entry of (0, fs_1.readdirSync)(dir).sort()) {
|
|
82
|
+
if (entry.endsWith('.md') && re.test(entry.slice(0, -'.md'.length)))
|
|
83
|
+
count += 1;
|
|
84
|
+
}
|
|
85
|
+
return count + 1;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Escape a literal string for safe insertion into a `RegExp` source (a frontmatter key here). */
|
|
89
|
+
function escapeRegExp(value) {
|
|
90
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Set one frontmatter field on the raw frontmatter text, line-based: replace the value on the existing
|
|
94
|
+
* `^<indent>key:` line if present (preserving the scaffold's ordering, comments and other fields
|
|
95
|
+
* verbatim — the P1.3 memory.add contract copies the scaffold verbatim), otherwise append the field. `valueYaml`
|
|
96
|
+
* is the already-serialized YAML scalar/flow value (e.g. a JSON-quoted string, a flow sequence).
|
|
97
|
+
*/
|
|
98
|
+
function setFrontmatterField(frontmatter, key, valueYaml) {
|
|
99
|
+
const re = new RegExp(`^([ \\t]*)${escapeRegExp(key)}:.*$`, 'm');
|
|
100
|
+
if (re.test(frontmatter)) {
|
|
101
|
+
return frontmatter.replace(re, (_match, indent) => `${indent}${key}: ${valueYaml}`);
|
|
102
|
+
}
|
|
103
|
+
return `${frontmatter}\n${key}: ${valueYaml}`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Copy a type's `template.file` scaffold verbatim and fill only the frontmatter skeleton `memory.add`
|
|
107
|
+
* pins (P1.3; spec-010-memory-frontmatter-schema): the generated `id`, the `--title`, the
|
|
108
|
+
* initial `status: draft`, and — when `--tags` was supplied — the `tags` flow sequence. Every other
|
|
109
|
+
* field (notably `type` and `tmpl_version`, spec-010: not touched by add) and the whole body are left
|
|
110
|
+
* exactly as the scaffold had them. `title`/`tags` are JSON-quoted (valid YAML double-quoted scalars /
|
|
111
|
+
* flow sequences), so an arbitrary title with spaces or colons is written safely.
|
|
112
|
+
*
|
|
113
|
+
* @throws when the scaffold has no frontmatter block (a malformed template — a config error surfaced
|
|
114
|
+
* as a thrown `Error` the core op maps to a `CoreError`).
|
|
115
|
+
*/
|
|
116
|
+
function renderAddDocument(scaffold, fields) {
|
|
117
|
+
const { frontmatter, body } = (0, storage_1.splitFrontmatter)(scaffold);
|
|
118
|
+
if (frontmatter === null) {
|
|
119
|
+
throw new Error('memory template scaffold has no frontmatter block');
|
|
120
|
+
}
|
|
121
|
+
let fm = frontmatter;
|
|
122
|
+
fm = setFrontmatterField(fm, 'id', fields.id);
|
|
123
|
+
fm = setFrontmatterField(fm, 'title', JSON.stringify(fields.title));
|
|
124
|
+
fm = setFrontmatterField(fm, 'status', 'draft');
|
|
125
|
+
if (fields.tags !== undefined) {
|
|
126
|
+
const flow = `[${fields.tags.map((tag) => JSON.stringify(tag)).join(',')}]`;
|
|
127
|
+
fm = setFrontmatterField(fm, 'tags', flow);
|
|
128
|
+
}
|
|
129
|
+
return `---\n${fm}\n---\n${body}`;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/memory/add.ts"],"names":[],"mappings":"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"}
|