@intentius/chant-lexicon-fountain 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/codegen/docs-cli.d.ts +3 -0
- package/dist/codegen/docs-cli.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts +16 -0
- package/dist/codegen/docs.d.ts.map +1 -0
- package/dist/codegen/generate-cli.d.ts +3 -0
- package/dist/codegen/generate-cli.d.ts.map +1 -0
- package/dist/codegen/generate-lexicon.d.ts +24 -0
- package/dist/codegen/generate-lexicon.d.ts.map +1 -0
- package/dist/codegen/generate-typescript.d.ts +11 -0
- package/dist/codegen/generate-typescript.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +15 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/naming.d.ts +14 -0
- package/dist/codegen/naming.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +17 -0
- package/dist/codegen/package.d.ts.map +1 -0
- package/dist/composites/concierge-stack.d.ts +44 -0
- package/dist/composites/concierge-stack.d.ts.map +1 -0
- package/dist/coverage.d.ts +56 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +45 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/detect.d.ts +10 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/entity-props.d.ts +11 -0
- package/dist/entity-props.d.ts.map +1 -0
- package/dist/export-resources.d.ts +29 -0
- package/dist/export-resources.d.ts.map +1 -0
- package/dist/generated/index.d.ts +5 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/runtime.d.ts +5 -0
- package/dist/generated/runtime.d.ts.map +1 -0
- package/dist/import/generator.d.ts +15 -0
- package/dist/import/generator.d.ts.map +1 -0
- package/dist/import/parser.d.ts +19 -0
- package/dist/import/parser.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/init-templates.d.ts +13 -0
- package/dist/init-templates.d.ts.map +1 -0
- package/dist/integrity.json +21 -0
- package/dist/lint/audit-catalog.d.ts +15 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn010-networking-explicit.d.ts +11 -0
- package/dist/lint/post-synth/ftn010-networking-explicit.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn011-no-unrestricted-networking.d.ts +11 -0
- package/dist/lint/post-synth/ftn011-no-unrestricted-networking.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn012-no-cloud-credential-env.d.ts +3 -0
- package/dist/lint/post-synth/ftn012-no-cloud-credential-env.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn013-substitution-resolvable.d.ts +3 -0
- package/dist/lint/post-synth/ftn013-substitution-resolvable.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn014-vault-shadowing.d.ts +3 -0
- package/dist/lint/post-synth/ftn014-vault-shadowing.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn015-mcp-secret-env-substitution.d.ts +3 -0
- package/dist/lint/post-synth/ftn015-mcp-secret-env-substitution.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn016-runtime-model-valid.d.ts +3 -0
- package/dist/lint/post-synth/ftn016-runtime-model-valid.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn017-unique-resource-names.d.ts +11 -0
- package/dist/lint/post-synth/ftn017-unique-resource-names.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts +3 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -0
- package/dist/lint/rules/ftn001-no-secret-literals.d.ts +3 -0
- package/dist/lint/rules/ftn001-no-secret-literals.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +5 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts +7 -0
- package/dist/lsp/completions.d.ts.map +1 -0
- package/dist/lsp/hover.d.ts +4 -0
- package/dist/lsp/hover.d.ts.map +1 -0
- package/dist/manifest.json +6 -0
- package/dist/meta.json +69 -0
- package/dist/op/activities/fountain-apply.d.ts +76 -0
- package/dist/op/activities/fountain-apply.d.ts.map +1 -0
- package/dist/op/activities/fountain-run.d.ts +36 -0
- package/dist/op/activities/fountain-run.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +11 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/package-cli.d.ts +3 -0
- package/dist/package-cli.d.ts.map +1 -0
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/reference-catalog.d.ts +16 -0
- package/dist/reference-catalog.d.ts.map +1 -0
- package/dist/rules/ftn001-no-secret-literals.ts +71 -0
- package/dist/rules/ftn010-networking-explicit.ts +37 -0
- package/dist/rules/ftn011-no-unrestricted-networking.ts +36 -0
- package/dist/rules/ftn012-no-cloud-credential-env.ts +58 -0
- package/dist/rules/ftn013-substitution-resolvable.ts +93 -0
- package/dist/rules/ftn014-vault-shadowing.ts +61 -0
- package/dist/rules/ftn015-mcp-secret-env-substitution.ts +49 -0
- package/dist/rules/ftn016-runtime-model-valid.ts +50 -0
- package/dist/rules/ftn017-unique-resource-names.ts +43 -0
- package/dist/serializer.d.ts +3 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/skills/chant-fountain-locked-sandboxes.md +34 -0
- package/dist/skills/chant-fountain-secrets.md +29 -0
- package/dist/skills/chant-fountain.md +45 -0
- package/dist/spec/fetch.d.ts +28 -0
- package/dist/spec/fetch.d.ts.map +1 -0
- package/dist/spec/parse.d.ts +58 -0
- package/dist/spec/parse.d.ts.map +1 -0
- package/dist/types/index.d.ts +60 -0
- package/dist/validate-cli.d.ts +3 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate.d.ts +15 -0
- package/dist/validate.d.ts.map +1 -0
- package/package.json +61 -0
- package/src/codegen/docs-cli.ts +7 -0
- package/src/codegen/docs.ts +278 -0
- package/src/codegen/generate-cli.ts +8 -0
- package/src/codegen/generate-lexicon.ts +58 -0
- package/src/codegen/generate-typescript.ts +69 -0
- package/src/codegen/generate.ts +109 -0
- package/src/codegen/naming.ts +45 -0
- package/src/codegen/package.ts +32 -0
- package/src/composites/composites.test.ts +35 -0
- package/src/composites/concierge-stack.ts +71 -0
- package/src/coverage.test.ts +63 -0
- package/src/coverage.ts +178 -0
- package/src/describe-resources.test.ts +203 -0
- package/src/describe-resources.ts +192 -0
- package/src/detect.ts +37 -0
- package/src/entity-props.ts +22 -0
- package/src/export-resources.ts +103 -0
- package/src/generated/.gitkeep +0 -0
- package/src/generated/index.d.ts +60 -0
- package/src/generated/index.ts +10 -0
- package/src/generated/lexicon-fountain.json +69 -0
- package/src/generated/runtime.ts +4 -0
- package/src/import/generator.ts +112 -0
- package/src/import/parser.ts +83 -0
- package/src/import/roundtrip.test.ts +113 -0
- package/src/index.ts +17 -0
- package/src/init-templates.ts +60 -0
- package/src/lint/audit-catalog.ts +107 -0
- package/src/lint/post-synth/ftn010-networking-explicit.ts +37 -0
- package/src/lint/post-synth/ftn011-no-unrestricted-networking.ts +36 -0
- package/src/lint/post-synth/ftn012-no-cloud-credential-env.ts +58 -0
- package/src/lint/post-synth/ftn013-substitution-resolvable.ts +93 -0
- package/src/lint/post-synth/ftn014-vault-shadowing.ts +61 -0
- package/src/lint/post-synth/ftn015-mcp-secret-env-substitution.ts +49 -0
- package/src/lint/post-synth/ftn016-runtime-model-valid.ts +50 -0
- package/src/lint/post-synth/ftn017-unique-resource-names.ts +43 -0
- package/src/lint/post-synth/index.ts +21 -0
- package/src/lint/post-synth/post-synth.test.ts +133 -0
- package/src/lint/rules/ftn001-no-secret-literals.ts +71 -0
- package/src/lint/rules/index.ts +7 -0
- package/src/lint/rules/rules.test.ts +126 -0
- package/src/lsp/completions.test.ts +51 -0
- package/src/lsp/completions.ts +21 -0
- package/src/lsp/hover.test.ts +47 -0
- package/src/lsp/hover.ts +70 -0
- package/src/op/activities/fountain-apply.test.ts +208 -0
- package/src/op/activities/fountain-apply.ts +249 -0
- package/src/op/activities/fountain-run.ts +95 -0
- package/src/op/activities/index.ts +28 -0
- package/src/package-cli.ts +26 -0
- package/src/plugin.test.ts +73 -0
- package/src/plugin.ts +170 -0
- package/src/reference-catalog.ts +27 -0
- package/src/serializer.test.ts +109 -0
- package/src/serializer.ts +143 -0
- package/src/skills/chant-fountain-locked-sandboxes.md +34 -0
- package/src/skills/chant-fountain-secrets.md +29 -0
- package/src/skills/chant-fountain.md +45 -0
- package/src/spec/fetch.ts +53 -0
- package/src/spec/fountain-openapi.snapshot.json +1 -0
- package/src/spec/parse.ts +309 -0
- package/src/validate-cli.ts +13 -0
- package/src/validate.ts +34 -0
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intentius/chant-lexicon-fountain",
|
|
3
|
+
"version": "0.33.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Fountain lexicon for chant — sandboxed agent environments, vaults, and agents as typed estate",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/INTENTIUS/chant.git",
|
|
10
|
+
"directory": "lexicons/fountain"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src/",
|
|
17
|
+
"dist/"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"development": "./src/index.ts",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./src/index.ts"
|
|
24
|
+
},
|
|
25
|
+
"./*": {
|
|
26
|
+
"development": "./src/*.ts",
|
|
27
|
+
"types": "./dist/*.d.ts",
|
|
28
|
+
"default": "./src/*.ts"
|
|
29
|
+
},
|
|
30
|
+
"./lint/post-synth": {
|
|
31
|
+
"development": "./src/lint/post-synth/index.ts",
|
|
32
|
+
"types": "./dist/lint/post-synth/index.d.ts",
|
|
33
|
+
"default": "./src/lint/post-synth/index.ts"
|
|
34
|
+
},
|
|
35
|
+
"./manifest": "./dist/manifest.json",
|
|
36
|
+
"./meta": "./dist/meta.json",
|
|
37
|
+
"./types": "./dist/types/index.d.ts",
|
|
38
|
+
"./op/activities": {
|
|
39
|
+
"development": "./src/op/activities/index.ts",
|
|
40
|
+
"types": "./dist/op/activities/index.d.ts",
|
|
41
|
+
"default": "./src/op/activities/index.ts"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"generate": "npx tsx src/codegen/generate-cli.ts",
|
|
46
|
+
"validate": "npx tsx src/validate-cli.ts",
|
|
47
|
+
"docs": "npx tsx src/codegen/docs-cli.ts",
|
|
48
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete",
|
|
49
|
+
"prepack": "npm run generate && npm run bundle && npm run validate && npm run build",
|
|
50
|
+
"bundle": "tsx src/package-cli.ts"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@intentius/chant": "^0.33.0",
|
|
54
|
+
"typescript": "^5.9.3"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@intentius/chant": "*",
|
|
58
|
+
"tsc-alias": "^1.8.17",
|
|
59
|
+
"typescript": "^5.9.3"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fountain documentation generator.
|
|
3
|
+
*
|
|
4
|
+
* Calls the core docsPipeline with fountain-specific config. The reference
|
|
5
|
+
* pages (resources, composites, ops, adoption, skills) are declared as
|
|
6
|
+
* `extraPages` rather than left as hand-written files in docs/: the sidebar is
|
|
7
|
+
* rebuilt from generated pages on every run, so a page the config does not
|
|
8
|
+
* know about exists but cannot be navigated to.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { dirname, join } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/codegen/docs";
|
|
14
|
+
|
|
15
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
16
|
+
|
|
17
|
+
const overview = `The **fountain** lexicon declares [fountain](https://github.com/BinaryBourbon/fountain)'s workload layer as typed chant resources. fountain runs coding agents in sandboxed VMs; its three declarable kinds are \`Environment\` (sandbox baseline), \`Vault\` (env-var overrides), and \`Agent\` (a runnable agent config).
|
|
18
|
+
|
|
19
|
+
Types are generated from fountain's served OpenAPI spec, so they track the real API.
|
|
20
|
+
|
|
21
|
+
Install it with:
|
|
22
|
+
|
|
23
|
+
\`\`\`bash
|
|
24
|
+
npm install --save-dev @intentius/chant-lexicon-fountain
|
|
25
|
+
\`\`\`
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
\`\`\`typescript
|
|
30
|
+
import { Environment, Agent } from "@intentius/chant-lexicon-fountain";
|
|
31
|
+
|
|
32
|
+
export const env = new Environment({
|
|
33
|
+
name: "team-env",
|
|
34
|
+
networking_type: "limited", // FTN010 requires explicit intent
|
|
35
|
+
networking_config: { allowed_hosts: ["github.com"] },
|
|
36
|
+
metadata: { "managed-by": "chant" }, // enables owned-only reconcile/prune
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const helper = new Agent({
|
|
40
|
+
name: "helper",
|
|
41
|
+
model: "anthropic/claude-sonnet-4-6",
|
|
42
|
+
runtime: "claude",
|
|
43
|
+
environment: env, // typed ref — dangling name = build error
|
|
44
|
+
});
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
## The loop
|
|
48
|
+
|
|
49
|
+
1. \`chant build\` — synthesize and lint. The FTN rules catch open networking, credential literals, and unresolvable \`\${VAR}\` references before review.
|
|
50
|
+
2. \`chant run <apply op>\` or call \`fountainApply\` — reconcile against the API. Idempotent by name.
|
|
51
|
+
3. \`chant lifecycle diff --live\` — drift. A UI edit to an owned Environment shows up here.
|
|
52
|
+
4. \`chant import --from\` — adopt UI-built resources into typed files.
|
|
53
|
+
|
|
54
|
+
## Endpoint and auth
|
|
55
|
+
|
|
56
|
+
\`FOUNTAIN_ENDPOINT\` (defaults to the hosted instance) and \`FOUNTAIN_TOKEN\`. Mint a token via \`POST /api/auth/token\` with email and password, or from the account UI. The same code applies to a local \`mix phx.server\` fountain by pointing \`FOUNTAIN_ENDPOINT\` at it — registration and token mint work headless, so CI needs no browser.`;
|
|
57
|
+
|
|
58
|
+
const outputFormat = `The fountain lexicon serializes to fountain's own manifest YAML plus a \`fountain-plan.json\` sidecar.
|
|
59
|
+
|
|
60
|
+
## Manifests
|
|
61
|
+
|
|
62
|
+
Each declared resource becomes a manifest document with \`apiVersion: fountain.dev/v1\`:
|
|
63
|
+
|
|
64
|
+
\`\`\`yaml
|
|
65
|
+
apiVersion: fountain.dev/v1
|
|
66
|
+
kind: Environment
|
|
67
|
+
metadata:
|
|
68
|
+
name: team-env
|
|
69
|
+
spec:
|
|
70
|
+
networking_type: limited
|
|
71
|
+
networking_config:
|
|
72
|
+
allowed_hosts:
|
|
73
|
+
- github.com
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
The output is ejectable — \`fountain apply -f\` accepts it verbatim, so adopting chant here does not trap the manifests behind chant.
|
|
77
|
+
|
|
78
|
+
## The plan sidecar
|
|
79
|
+
|
|
80
|
+
\`fountain-plan.json\` is entity name → \`{ kind, spec }\`. The \`fountainApply\` activity reconciles from it directly against the REST API, so nothing on the apply side parses YAML. Apply order is Environment → Vault → Agent; an agent's \`environment\` reference carries the entity name and is resolved to the live id at apply.
|
|
81
|
+
|
|
82
|
+
## Ownership
|
|
83
|
+
|
|
84
|
+
Resources carrying \`metadata."managed-by": chant\` are chant-owned. That marker gates the opt-in prune (\`fountainApply\` deletes only owned resources absent from the plan) and the \`--owned\` filter on drift and live export. Set it on every declaration you want reconciled.
|
|
85
|
+
|
|
86
|
+
## Secrets
|
|
87
|
+
|
|
88
|
+
\`spec.secrets\` entries are split out of the resource body and upserted through the secrets sub-resource. Values are write-only upstream, so this is upsert-always — a changed value cannot be detected, only overwritten.`;
|
|
89
|
+
|
|
90
|
+
const resourcesPage = `The lexicon types the three kinds \`fountain apply\` reconciles — the workload
|
|
91
|
+
layer of [fountain](https://github.com/BinaryBourbon/fountain). Types are
|
|
92
|
+
generated from fountain's served OpenAPI spec, so they track the real API.
|
|
93
|
+
Conversations are deliberately **not** a resource: they are runs with a
|
|
94
|
+
status lifecycle, modeled as ops.
|
|
95
|
+
|
|
96
|
+
## Environment
|
|
97
|
+
|
|
98
|
+
A reusable sandbox baseline: packages, repos, setup script, env vars,
|
|
99
|
+
encrypted secrets, and the networking policy. \`networking_type\` is
|
|
100
|
+
\`"unrestricted" | "limited"\`; under \`limited\`, egress is restricted to
|
|
101
|
+
\`networking_config.allowed_hosts\`, and with no hosts (or an empty list) the
|
|
102
|
+
sandbox denies all egress — a deny-all, not an allow-all. FTN010 requires the
|
|
103
|
+
networking intent to be explicit.
|
|
104
|
+
|
|
105
|
+
## Vault
|
|
106
|
+
|
|
107
|
+
A bag of env-var overrides selected at conversation create. Vault values
|
|
108
|
+
win on key collision with the environment — which is why agents can carry
|
|
109
|
+
a vault allowlist upstream (fountain#136). \`allowed_vault_ids\` on an Agent is
|
|
110
|
+
three-state: \`null\` allows any tenant vault, \`[]\` forbids all, a list is an
|
|
111
|
+
allowlist.
|
|
112
|
+
|
|
113
|
+
## Agent
|
|
114
|
+
|
|
115
|
+
A named, re-runnable agent configuration: model, runtime, skills (inline
|
|
116
|
+
SKILL.md or GitHub-sourced with a \`ref\` pin), MCP servers, and an optional
|
|
117
|
+
\`environment\` reference — typed, so a dangling reference is a build error,
|
|
118
|
+
not a 422 at apply time.
|
|
119
|
+
|
|
120
|
+
## Example
|
|
121
|
+
|
|
122
|
+
\`\`\`ts
|
|
123
|
+
import { Environment, Agent } from "@intentius/chant-lexicon-fountain";
|
|
124
|
+
|
|
125
|
+
export const conciergeEnv = new Environment({
|
|
126
|
+
name: "concierge-env",
|
|
127
|
+
networking_type: "limited",
|
|
128
|
+
networking_config: { allowed_hosts: ["registry.npmjs.org", "github.com"] },
|
|
129
|
+
metadata: { "managed-by": "chant" },
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export const researcher = new Agent({
|
|
133
|
+
name: "researcher",
|
|
134
|
+
model: "anthropic/claude-sonnet-4-6",
|
|
135
|
+
runtime: "claude",
|
|
136
|
+
environment: conciergeEnv,
|
|
137
|
+
skills: [{ source: "vercel-labs/agent-skills", ref: "main" }],
|
|
138
|
+
});
|
|
139
|
+
\`\`\``;
|
|
140
|
+
|
|
141
|
+
const compositesPage = `## ConciergeStack
|
|
142
|
+
|
|
143
|
+
An Environment + Agent pair with the secure-by-construction defaults for agents that touch anything sensitive:
|
|
144
|
+
|
|
145
|
+
\`\`\`typescript
|
|
146
|
+
import { ConciergeStack } from "@intentius/chant-lexicon-fountain";
|
|
147
|
+
|
|
148
|
+
export const { environment, agent } = ConciergeStack({
|
|
149
|
+
name: "concierge",
|
|
150
|
+
model: "anthropic/claude-sonnet-4-6",
|
|
151
|
+
allowedHosts: ["registry.npmjs.org", "github.com"],
|
|
152
|
+
});
|
|
153
|
+
\`\`\`
|
|
154
|
+
|
|
155
|
+
| Default | Effect |
|
|
156
|
+
|---|---|
|
|
157
|
+
| \`networking_type: limited\` with an empty allowlist | deny-all egress — fountain's isolation mode |
|
|
158
|
+
| \`allowed_vault_ids: []\` | no conversation may override the reviewed environment at spawn |
|
|
159
|
+
| \`managed-by: chant\` on both | owned-only reconcile, prune, and drift filtering see them |
|
|
160
|
+
|
|
161
|
+
Every default is the closed one, so loosening any of it is a visible, reviewable act: pass an allowlist, pass vault ids, or drop to the raw classes.
|
|
162
|
+
|
|
163
|
+
Give such a sandbox **no cloud credentials of any kind** — anything readable inside it is exfiltratable by prompt injection. Services the agent needs live outside the sandbox behind their own auth; the sandbox gets at most a conversation-scoped token.`;
|
|
164
|
+
|
|
165
|
+
const opsPage = `Two op activities ship with the lexicon, resolvable by name via \`loadActivities(["fountain"])\`.
|
|
166
|
+
|
|
167
|
+
## fountainApply
|
|
168
|
+
|
|
169
|
+
The native applier: a direct-REST reconciler over the serializer's \`fountain-plan.json\`.
|
|
170
|
+
|
|
171
|
+
| Behavior | Detail |
|
|
172
|
+
|---|---|
|
|
173
|
+
| Create / update | By name. A resource in the plan that exists live is updated; one that does not is created. |
|
|
174
|
+
| Order | Environment → Vault → Agent, so an agent's environment reference resolves to a live id. |
|
|
175
|
+
| Prune | Off by default. With \`prune: true\`, chant-owned resources absent from the plan are deleted, in reverse order. |
|
|
176
|
+
| Secrets | Split from the body and upserted through the secrets sub-resource. Upsert-always — values are write-only upstream. |
|
|
177
|
+
|
|
178
|
+
\`\`\`typescript
|
|
179
|
+
await fountainApply({ planPath: "build/fountain-plan.json", prune: true });
|
|
180
|
+
\`\`\`
|
|
181
|
+
|
|
182
|
+
Endpoint and token resolution: explicit args win, then \`FOUNTAIN_ENDPOINT\` / \`FOUNTAIN_TOKEN\`, then the hosted default.
|
|
183
|
+
|
|
184
|
+
## fountainRun
|
|
185
|
+
|
|
186
|
+
Conversations are runs, not resources, so they are started rather than declared. \`fountainRun\` resolves the agent by name, starts a conversation (optionally with a prompt and an allowlisted vault), polls to \`completed | failed | timed_out\`, and terminates at its deadline so a hung sandbox never outlives the op.
|
|
187
|
+
|
|
188
|
+
Multi-turn interaction — follow-up prompts, interrupt — is fountain's own conversations API. The lexicon stays at the lifecycle edges.`;
|
|
189
|
+
|
|
190
|
+
const adoptionPage = `The lexicon reads live fountain state on three paths.
|
|
191
|
+
|
|
192
|
+
## Drift
|
|
193
|
+
|
|
194
|
+
\`chant lifecycle diff --live\` reports each declared entity as observed present, observed absent, or **not observed** with a reason — a read failure is never reported as an absence, which would propose a spurious create. Ownership comes from the \`managed-by: chant\` marker, so \`--owned\` filters to what chant declared.
|
|
195
|
+
|
|
196
|
+
An out-of-band change to a locked environment — a UI edit that adds a secret, opens networking, or drops the marker — is what this catches. Wire it into a scheduled watch and treat a hit as an incident, not housekeeping.
|
|
197
|
+
|
|
198
|
+
## Import
|
|
199
|
+
|
|
200
|
+
\`chant import --from\` adopts UI-built resources into typed files. Server-written fields are stripped to the authored shape, and an agent's \`environment_id\` is resolved back to the exported environment's logical name so the generated code carries a reviewable reference.
|
|
201
|
+
|
|
202
|
+
Secrets do not round-trip: values are write-only upstream and secret keys are not on the typed request surface, so environments export without them and the caller is warned per environment that carried any. Re-declare them through your secret provider.
|
|
203
|
+
|
|
204
|
+
## Graph
|
|
205
|
+
|
|
206
|
+
\`chant graph --live\` reconstructs the topology from one edge: an Agent runs in an Environment. Vaults are deliberately edge-free — vault-to-agent binding is a conversation-time choice scoped by \`allowed_vault_ids\`, not standing topology.`;
|
|
207
|
+
|
|
208
|
+
const skillsPage = `Three agent skills ship with the lexicon and load automatically in a project that uses it.
|
|
209
|
+
|
|
210
|
+
| Skill | Covers |
|
|
211
|
+
|---|---|
|
|
212
|
+
| \`chant-fountain\` | The core authoring loop — declaring the three kinds, the build/apply/drift/import cycle, endpoint and auth |
|
|
213
|
+
| \`chant-fountain-secrets\` | Secrets, \`env_vars\`, and \`\${VAR}\` substitution: the order of preference, vault precedence, and what does not round-trip |
|
|
214
|
+
| \`chant-fountain-locked-sandboxes\` | The locked-down posture for untrusted or security-sensitive agents, and running conversations against them |
|
|
215
|
+
|
|
216
|
+
Invoke one directly by name, or let it trigger on context (\`fountain\`, \`vault\`, \`sandbox\`, \`networking_type\`).`;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Generate documentation site for the fountain lexicon.
|
|
220
|
+
*/
|
|
221
|
+
export async function generateDocs(options?: { verbose?: boolean }): Promise<void> {
|
|
222
|
+
const config: DocsConfig = {
|
|
223
|
+
name: "fountain",
|
|
224
|
+
displayName: "Fountain",
|
|
225
|
+
description: "Fountain workload primitives (Environment, Vault, Agent) as typed estate.",
|
|
226
|
+
distDir: join(pkgDir, "dist"),
|
|
227
|
+
outDir: join(pkgDir, "docs"),
|
|
228
|
+
srcDir: join(pkgDir, "src"),
|
|
229
|
+
basePath: process.env.DOCS_BASE_PATH ?? "/chant/lexicons/fountain/",
|
|
230
|
+
overview,
|
|
231
|
+
outputFormat,
|
|
232
|
+
serviceFromType: (type: string) => type.split("::")[1] ?? type,
|
|
233
|
+
// No `resourceTypeUrl` key: DocsConfig has none, so passing it was a
|
|
234
|
+
// silent no-op. The upstream reference link lives in the resources page
|
|
235
|
+
// content, where it actually renders.
|
|
236
|
+
extraPages: [
|
|
237
|
+
{
|
|
238
|
+
slug: "resources",
|
|
239
|
+
title: "Resources",
|
|
240
|
+
description: "The three fountain workload kinds the lexicon declares.",
|
|
241
|
+
content: resourcesPage,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
slug: "composites",
|
|
245
|
+
title: "Composites",
|
|
246
|
+
description: "ConciergeStack — a locked-down Environment and Agent pair.",
|
|
247
|
+
content: compositesPage,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
slug: "ops",
|
|
251
|
+
title: "Ops",
|
|
252
|
+
description: "fountainApply and fountainRun — the applier and the conversation runner.",
|
|
253
|
+
content: opsPage,
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
slug: "adoption",
|
|
257
|
+
title: "Drift and Adoption",
|
|
258
|
+
description: "Live observation, import, and the graph edge fountain reconstructs.",
|
|
259
|
+
content: adoptionPage,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
slug: "skills",
|
|
263
|
+
title: "Skills",
|
|
264
|
+
description: "The agent skills the lexicon ships.",
|
|
265
|
+
content: skillsPage,
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const result = docsPipeline(config);
|
|
271
|
+
writeDocsSite(config, result);
|
|
272
|
+
|
|
273
|
+
if (options?.verbose) {
|
|
274
|
+
console.error(
|
|
275
|
+
`Generated docs: ${result.stats.resources} resources, ${result.stats.properties} properties, ${result.stats.services} services, ${result.stats.rules} rules`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { generate, writeGeneratedFiles } from "./generate";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
7
|
+
const result = await generate({ verbose: true });
|
|
8
|
+
writeGeneratedFiles(result, pkgDir);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lexicon JSON generator — produces lexicon-fountain.json with metadata for the
|
|
3
|
+
* fly resource and property types.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { PropertyConstraints } from "@intentius/chant/codegen/json-schema";
|
|
7
|
+
import type { FountainParseResult } from "../spec/parse";
|
|
8
|
+
import { fountainShortName } from "../spec/parse";
|
|
9
|
+
import type { NamingStrategy } from "./naming";
|
|
10
|
+
import { buildRegistry, serializeRegistry, type RegistryResource } from "@intentius/chant/codegen/generate-registry";
|
|
11
|
+
|
|
12
|
+
export interface FountainLexiconEntry {
|
|
13
|
+
resourceType: string;
|
|
14
|
+
kind: "resource" | "property";
|
|
15
|
+
lexicon: "fountain";
|
|
16
|
+
/**
|
|
17
|
+
* Per-property constraints. Named to match core's `LexiconEntry`
|
|
18
|
+
* contract (and the aws/azure peers) — core reserves bare `constraints`
|
|
19
|
+
* for the extension-constraint array, and the LSP providers read
|
|
20
|
+
* property names off this key.
|
|
21
|
+
*/
|
|
22
|
+
propertyConstraints?: Record<string, PropertyConstraints>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate the lexicon-fountain.json content.
|
|
27
|
+
*/
|
|
28
|
+
export function generateLexiconJSON(results: FountainParseResult[], naming: NamingStrategy): string {
|
|
29
|
+
const registryResources: RegistryResource[] = results.map((r) => ({
|
|
30
|
+
typeName: r.resource.typeName,
|
|
31
|
+
attributes: r.resource.attributes,
|
|
32
|
+
properties: r.resource.properties,
|
|
33
|
+
propertyTypes: [],
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const entries = buildRegistry<FountainLexiconEntry>(registryResources, naming, {
|
|
37
|
+
shortName: fountainShortName,
|
|
38
|
+
buildEntry: (resource, _tsName, _attrs, propConstraints) => {
|
|
39
|
+
const r = results.find((res) => res.resource.typeName === resource.typeName);
|
|
40
|
+
const entry: FountainLexiconEntry = {
|
|
41
|
+
resourceType: resource.typeName,
|
|
42
|
+
kind: r?.isProperty ? "property" : "resource",
|
|
43
|
+
lexicon: "fountain",
|
|
44
|
+
};
|
|
45
|
+
if (propConstraints && Object.keys(propConstraints).length > 0) {
|
|
46
|
+
entry.propertyConstraints = propConstraints;
|
|
47
|
+
}
|
|
48
|
+
return entry;
|
|
49
|
+
},
|
|
50
|
+
buildPropertyEntry: (resourceType, propertyType) => ({
|
|
51
|
+
resourceType: `${resourceType}.${propertyType}`,
|
|
52
|
+
kind: "property",
|
|
53
|
+
lexicon: "fountain",
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return serializeRegistry(entries);
|
|
58
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript declaration file generator — produces index.d.ts with the fly
|
|
3
|
+
* resource classes (App, Machine, Volume) and their property-type classes.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { FountainParseResult } from "../spec/parse";
|
|
7
|
+
import type { NamingStrategy } from "./naming";
|
|
8
|
+
import {
|
|
9
|
+
writeResourceClass,
|
|
10
|
+
writePropertyClass,
|
|
11
|
+
type DtsProperty,
|
|
12
|
+
type DtsAttribute,
|
|
13
|
+
} from "@intentius/chant/codegen/generate-typescript";
|
|
14
|
+
|
|
15
|
+
interface Entry {
|
|
16
|
+
tsName: string;
|
|
17
|
+
isProperty: boolean;
|
|
18
|
+
properties: DtsProperty[];
|
|
19
|
+
attributes: DtsAttribute[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate the complete .d.ts file content.
|
|
24
|
+
*/
|
|
25
|
+
export function generateTypeScriptDeclarations(results: FountainParseResult[], naming: NamingStrategy): string {
|
|
26
|
+
const lines: string[] = [];
|
|
27
|
+
lines.push("// Code generated by chant fly generate. DO NOT EDIT.");
|
|
28
|
+
|
|
29
|
+
const entries: Entry[] = [];
|
|
30
|
+
|
|
31
|
+
for (const r of results) {
|
|
32
|
+
const tsName = naming.resolve(r.resource.typeName);
|
|
33
|
+
if (!tsName) continue;
|
|
34
|
+
|
|
35
|
+
const properties: DtsProperty[] = r.resource.properties.map((p) => ({
|
|
36
|
+
name: p.name,
|
|
37
|
+
type: p.tsType,
|
|
38
|
+
required: p.required,
|
|
39
|
+
description: p.description,
|
|
40
|
+
}));
|
|
41
|
+
const attributes: DtsAttribute[] = r.resource.attributes.map((a) => ({ name: a.name, type: a.tsType }));
|
|
42
|
+
|
|
43
|
+
entries.push({ tsName, isProperty: !!r.isProperty, properties, attributes });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
entries.sort((a, b) => a.tsName.localeCompare(b.tsName));
|
|
47
|
+
|
|
48
|
+
const resources = entries.filter((e) => !e.isProperty);
|
|
49
|
+
const propertyTypes = entries.filter((e) => e.isProperty);
|
|
50
|
+
|
|
51
|
+
if (resources.length > 0) {
|
|
52
|
+
lines.push("");
|
|
53
|
+
lines.push("// --- Fly Resource classes ---");
|
|
54
|
+
for (const re of resources) {
|
|
55
|
+
writeResourceClass(lines, re.tsName, re.properties, re.attributes);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (propertyTypes.length > 0) {
|
|
60
|
+
lines.push("");
|
|
61
|
+
lines.push("// --- Property type classes ---");
|
|
62
|
+
for (const pe of propertyTypes) {
|
|
63
|
+
writePropertyClass(lines, pe.tsName, pe.properties);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
lines.push("");
|
|
68
|
+
return lines.join("\n");
|
|
69
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fountain generation pipeline — uses core generatePipeline with
|
|
3
|
+
* fountain-specific fetch, parse, naming, and generation callbacks.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
generatePipeline,
|
|
8
|
+
writeGeneratedArtifacts,
|
|
9
|
+
type GenerateOptions,
|
|
10
|
+
type GenerateResult,
|
|
11
|
+
type GeneratePipelineConfig,
|
|
12
|
+
} from "@intentius/chant/codegen/generate";
|
|
13
|
+
import { fetchSchemas } from "../spec/fetch";
|
|
14
|
+
import { parseFountainOpenAPI, type FountainParseResult } from "../spec/parse";
|
|
15
|
+
import { NamingStrategy } from "./naming";
|
|
16
|
+
import { generateLexiconJSON } from "./generate-lexicon";
|
|
17
|
+
import { generateTypeScriptDeclarations } from "./generate-typescript";
|
|
18
|
+
import {
|
|
19
|
+
generateRuntimeIndex as coreGenerateRuntimeIndex,
|
|
20
|
+
type RuntimeIndexEntry,
|
|
21
|
+
type RuntimeIndexPropertyEntry,
|
|
22
|
+
} from "@intentius/chant/codegen/generate-runtime-index";
|
|
23
|
+
import { dirname } from "path";
|
|
24
|
+
import { fileURLToPath } from "url";
|
|
25
|
+
|
|
26
|
+
export type { GenerateResult };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Run the full fountain generation pipeline.
|
|
30
|
+
*/
|
|
31
|
+
export async function generate(opts: GenerateOptions = {}): Promise<GenerateResult> {
|
|
32
|
+
// The fountain spec is a single document — parseFountainOpenAPI returns
|
|
33
|
+
// multiple results. The pipeline calls parseSchema once, so we return the
|
|
34
|
+
// first result and inject the rest via augmentResults.
|
|
35
|
+
let pendingResults: FountainParseResult[] = [];
|
|
36
|
+
|
|
37
|
+
const config: GeneratePipelineConfig<FountainParseResult> = {
|
|
38
|
+
fetchSchemas: (fetchOpts) => fetchSchemas({ force: fetchOpts.force }),
|
|
39
|
+
|
|
40
|
+
parseSchema: (_typeName, data) => {
|
|
41
|
+
const results = parseFountainOpenAPI(data);
|
|
42
|
+
if (results.length === 0) return null;
|
|
43
|
+
pendingResults = results.slice(1);
|
|
44
|
+
return results[0];
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
createNaming: (results) => new NamingStrategy(results),
|
|
48
|
+
|
|
49
|
+
augmentResults: (results, _opts, log) => {
|
|
50
|
+
if (pendingResults.length > 0) {
|
|
51
|
+
results.push(...pendingResults);
|
|
52
|
+
log(`Added ${pendingResults.length} additional fountain schemas from OpenAPI spec`);
|
|
53
|
+
pendingResults = [];
|
|
54
|
+
}
|
|
55
|
+
log(`Total: ${results.length} fountain resource/property schemas`);
|
|
56
|
+
return { results };
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
generateRegistry: (results, naming) => generateLexiconJSON(results, naming as NamingStrategy),
|
|
60
|
+
|
|
61
|
+
generateTypes: (results, naming) => generateTypeScriptDeclarations(results, naming as NamingStrategy),
|
|
62
|
+
|
|
63
|
+
generateRuntimeIndex: (results, naming) => generateRuntimeIndex(results, naming as NamingStrategy),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return generatePipeline(config, opts);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Write generated artifacts to disk.
|
|
71
|
+
*/
|
|
72
|
+
export function writeGeneratedFiles(result: GenerateResult, pkgDir?: string): void {
|
|
73
|
+
const baseDir = pkgDir ?? dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
74
|
+
writeGeneratedArtifacts({
|
|
75
|
+
baseDir,
|
|
76
|
+
files: {
|
|
77
|
+
"lexicon-fountain.json": result.lexiconJSON,
|
|
78
|
+
"index.d.ts": result.typesDTS,
|
|
79
|
+
"index.ts": result.indexTS,
|
|
80
|
+
"runtime.ts": `/**\n * Runtime factory constructors — re-exported from core.\n */\nexport { createResource, createProperty } from "@intentius/chant/runtime";\n`,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Generate the runtime index.ts with factory constructor exports.
|
|
87
|
+
*/
|
|
88
|
+
function generateRuntimeIndex(results: FountainParseResult[], naming: NamingStrategy): string {
|
|
89
|
+
const resourceEntries: RuntimeIndexEntry[] = [];
|
|
90
|
+
const propertyEntries: RuntimeIndexPropertyEntry[] = [];
|
|
91
|
+
|
|
92
|
+
for (const r of results) {
|
|
93
|
+
const typeName = r.resource.typeName;
|
|
94
|
+
const tsName = naming.resolve(typeName);
|
|
95
|
+
if (!tsName) continue;
|
|
96
|
+
|
|
97
|
+
if (r.isProperty) {
|
|
98
|
+
propertyEntries.push({ tsName, resourceType: typeName });
|
|
99
|
+
} else {
|
|
100
|
+
const attrs: Record<string, string> = {};
|
|
101
|
+
for (const attr of r.resource.attributes) {
|
|
102
|
+
attrs[attr.name] = attr.name;
|
|
103
|
+
}
|
|
104
|
+
resourceEntries.push({ tsName, resourceType: typeName, attrs });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return coreGenerateRuntimeIndex(resourceEntries, propertyEntries, { lexiconName: "fountain" });
|
|
109
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fountain naming strategy — maps Fountain::V1::{Kind} type names to
|
|
3
|
+
* user-friendly TypeScript class names.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
NamingStrategy as CoreNamingStrategy,
|
|
8
|
+
type NamingConfig,
|
|
9
|
+
type NamingInput,
|
|
10
|
+
} from "@intentius/chant/codegen/naming";
|
|
11
|
+
import { fountainShortName, fountainServiceName, type FountainParseResult } from "../spec/parse";
|
|
12
|
+
|
|
13
|
+
export { propertyTypeName, extractDefName } from "@intentius/chant/codegen/naming";
|
|
14
|
+
|
|
15
|
+
const flyNamingConfig: NamingConfig = {
|
|
16
|
+
priorityNames: {
|
|
17
|
+
"Fountain::V1::Environment": "Environment",
|
|
18
|
+
"Fountain::V1::Agent": "Agent",
|
|
19
|
+
"Fountain::V1::Vault": "Vault",
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
priorityAliases: {},
|
|
23
|
+
|
|
24
|
+
priorityPropertyAliases: {},
|
|
25
|
+
|
|
26
|
+
serviceAbbreviations: {
|
|
27
|
+
V1: "V1",
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
shortName: fountainShortName,
|
|
31
|
+
serviceName: fountainServiceName,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Fountain-specific naming strategy. Extends the core strategy with the fountain config.
|
|
36
|
+
*/
|
|
37
|
+
export class NamingStrategy extends CoreNamingStrategy {
|
|
38
|
+
constructor(results: FountainParseResult[]) {
|
|
39
|
+
const inputs: NamingInput[] = results.map((r) => ({
|
|
40
|
+
typeName: r.resource.typeName,
|
|
41
|
+
propertyTypes: r.propertyTypes,
|
|
42
|
+
}));
|
|
43
|
+
super(inputs, flyNamingConfig);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { packagePipeline, collectSkills } from "@intentius/chant/codegen/package";
|
|
2
|
+
import { generate } from "./generate";
|
|
3
|
+
import { fountainPlugin } from "../plugin";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Package the fountain lexicon for distribution.
|
|
10
|
+
*/
|
|
11
|
+
export async function packageLexicon(options?: { verbose?: boolean; force?: boolean }) {
|
|
12
|
+
// This file is src/codegen/package.ts — rules and skills are collected
|
|
13
|
+
// relative to src/, so srcDir must be the parent of this directory.
|
|
14
|
+
const srcDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
15
|
+
const pkgJson = JSON.parse(readFileSync(join(srcDir, "..", "package.json"), "utf-8"));
|
|
16
|
+
|
|
17
|
+
const { spec, stats } = await packagePipeline({
|
|
18
|
+
generate: (opts) => generate({ verbose: opts?.verbose, force: opts?.force }),
|
|
19
|
+
buildManifest: (_genResult) => ({
|
|
20
|
+
name: "fountain",
|
|
21
|
+
version: pkgJson.version ?? "0.0.0",
|
|
22
|
+
chantVersion: ">=0.1.0",
|
|
23
|
+
namespace: "Fountain",
|
|
24
|
+
}),
|
|
25
|
+
srcDir,
|
|
26
|
+
collectSkills: () => collectSkills(fountainPlugin.skills?.() ?? []),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Both callers (the plugin's package() and package-cli) print their own
|
|
30
|
+
// summary — don't double-report here.
|
|
31
|
+
return { spec, stats };
|
|
32
|
+
}
|