@synap-core/workspace-templates 0.10.0 → 0.12.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/dist/index.d.ts +74 -34
- package/dist/index.js +1177 -11
- package/dist/index.js.map +1 -1
- package/package.json +16 -25
- package/src/base.template.test.ts +25 -19
- package/src/base.yaml +12 -2
- package/src/blockchain-ecosystem.yaml +106 -0
- package/src/builder.yaml +19 -1
- package/src/business-model.yaml +351 -0
- package/src/catalog.ts +55 -0
- package/src/civic-france.yaml +102 -0
- package/src/dist-freshness.test.ts +97 -0
- package/src/foundation.yaml +62 -0
- package/src/grants.yaml +259 -1
- package/src/life-os.yaml +14 -0
- package/src/networking.yaml +14 -3
- package/src/seed-obligation.test.ts +181 -0
- package/src/shared-role-ssot.test.ts +4 -1
- package/src/templates.ts +1132 -15
- package/src/the-arch.yaml +4 -0
- package/src/types.ts +32 -34
- package/src/validate-flow.ts +11 -1
- package/src/validate.test.ts +86 -0
- package/src/validate.ts +49 -0
- package/src/__fixtures__/report-automation-flow.json +0 -393
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synap-core/workspace-templates",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"packageManager": "pnpm@9.15.4",
|
|
6
5
|
"description": "Canonical workspace definitions — YAML source + typed exports for browser, backend, CLI, and marketplace",
|
|
7
6
|
"exports": {
|
|
8
7
|
".": {
|
|
9
8
|
"types": "./dist/index.d.ts",
|
|
10
|
-
"node": "./dist/index.js",
|
|
11
9
|
"default": "./dist/index.js"
|
|
12
10
|
}
|
|
13
11
|
},
|
|
@@ -15,16 +13,6 @@
|
|
|
15
13
|
"dist",
|
|
16
14
|
"src"
|
|
17
15
|
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"type-check": "tsc --noEmit",
|
|
20
|
-
"build:yaml": "node --experimental-strip-types build.mjs",
|
|
21
|
-
"check:converters": "node scripts/check-converters.mjs",
|
|
22
|
-
"check:concepts": "node scripts/check-concepts.mjs",
|
|
23
|
-
"build": "node --experimental-strip-types build.mjs && tsup && node scripts/check-converters.mjs && node scripts/check-concepts.mjs",
|
|
24
|
-
"provision": "node scripts/provision.mjs",
|
|
25
|
-
"eval": "node scripts/eval-standard.mjs",
|
|
26
|
-
"prepublishOnly": "node --experimental-strip-types build.mjs && tsup && node scripts/check-converters.mjs && node scripts/check-concepts.mjs"
|
|
27
|
-
},
|
|
28
16
|
"dependencies": {
|
|
29
17
|
"zod": "^3.0.0",
|
|
30
18
|
"js-yaml": "^4.1.0"
|
|
@@ -37,15 +25,18 @@
|
|
|
37
25
|
},
|
|
38
26
|
"publishConfig": {
|
|
39
27
|
"registry": "https://registry.npmjs.org",
|
|
40
|
-
"access": "public"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"type-check": "tsc --noEmit",
|
|
32
|
+
"build:yaml": "node --experimental-strip-types build.mjs",
|
|
33
|
+
"check:converters": "node scripts/check-converters.mjs",
|
|
34
|
+
"check:concepts": "node scripts/check-concepts.mjs",
|
|
35
|
+
"build": "node --experimental-strip-types build.mjs && tsup && node scripts/check-converters.mjs && node scripts/check-concepts.mjs",
|
|
36
|
+
"provision": "node scripts/provision.mjs",
|
|
37
|
+
"eval": "node scripts/eval-standard.mjs"
|
|
38
|
+
},
|
|
39
|
+
"main": "./dist/index.js",
|
|
40
|
+
"module": "./dist/index.js",
|
|
41
|
+
"types": "./dist/index.d.ts"
|
|
42
|
+
}
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
* seeders be deleted (Wave 4) without silently changing what every workspace
|
|
9
9
|
* gets.
|
|
10
10
|
*
|
|
11
|
-
* FIDELITY MECHANISM.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
11
|
+
* FIDELITY MECHANISM. base.yaml is now the SINGLE source of the report flow —
|
|
12
|
+
* the backend `REPORT_AUTOMATION_FLOW` const it was once snapshotted against was
|
|
13
|
+
* retired, and with it the `__fixtures__/report-automation-flow.json` copy-pin
|
|
14
|
+
* (a copy pinned to a copy caught no upstream drift). The report flow is guarded
|
|
15
|
+
* here directly instead: the prompt-fragment smoke check below proves the product
|
|
16
|
+
* content survived, and `templates-freshness.test.ts` pins templates.ts == the
|
|
17
|
+
* YAML source. The 23-ish relation defs KEEP their byte-for-byte fixture
|
|
18
|
+
* guardrail (`__fixtures__/default-relation-defs.json`).
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { readFileSync } from "fs";
|
|
@@ -55,18 +55,13 @@ describe("Task A — report automation, byte-faithful", () => {
|
|
|
55
55
|
expect(automation?.description).toMatch(/Gather this workspace's state/);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
it("flow BYTE-MATCHES the REPORT_AUTOMATION_FLOW snapshot", () => {
|
|
59
|
-
const fixture = readFixture("report-automation-flow.json");
|
|
60
|
-
// deep-equal: the compiled template's flow is JSON.stringify(parsed YAML), so
|
|
61
|
-
// a deep-equal against the JSON snapshot of the source const proves the
|
|
62
|
-
// transcription is lossless (nodes, edges, and every prompt string).
|
|
63
|
-
expect(automation?.flow).toEqual(fixture);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
58
|
it("preserves the load-bearing hardened prompt fragments (v13)", () => {
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
59
|
+
// The primary guardrail that the report flow's product content survived in
|
|
60
|
+
// base.yaml. (A byte-for-byte fixture pin used to sit above this, snapshotting
|
|
61
|
+
// the retired backend `REPORT_AUTOMATION_FLOW` const; with that const gone
|
|
62
|
+
// base.yaml is the single source, so a copy-pinned-to-a-copy proved nothing
|
|
63
|
+
// and was dropped. `templates-freshness.test.ts` pins templates.ts == the
|
|
64
|
+
// YAML source.)
|
|
70
65
|
const flowStr = JSON.stringify(automation?.flow);
|
|
71
66
|
for (const marker of [
|
|
72
67
|
"COUNTS — the exact number of records gathered",
|
|
@@ -77,6 +72,17 @@ describe("Task A — report automation, byte-faithful", () => {
|
|
|
77
72
|
expect(flowStr).toContain(marker);
|
|
78
73
|
}
|
|
79
74
|
});
|
|
75
|
+
|
|
76
|
+
it("carries the v15 retry policy on all four AI rounds (regression guard)", () => {
|
|
77
|
+
// v15's fix for the 2026-08-03 finishReason=length incident: each of the four
|
|
78
|
+
// ai.generate rounds (analyze/relate/assemble/summarize) gets ONE retry with a
|
|
79
|
+
// 5s delay. This field dropped SILENTLY once — the 700→2000 fix ported maxTokens
|
|
80
|
+
// into base.yaml but not the retry policy, so it went missing on the reconcile-
|
|
81
|
+
// winning path. Assert it here (base.yaml is the SSOT now) so it can't drift again.
|
|
82
|
+
const flowStr = JSON.stringify(automation?.flow);
|
|
83
|
+
expect((flowStr.match(/"retryDelay":5000/g) ?? []).length).toBe(4);
|
|
84
|
+
expect((flowStr.match(/"maxRetries":1(?=[,}])/g) ?? []).length).toBe(4);
|
|
85
|
+
});
|
|
80
86
|
});
|
|
81
87
|
|
|
82
88
|
describe("Task B — relation defs, full coverage", () => {
|
package/src/base.yaml
CHANGED
|
@@ -455,9 +455,11 @@ automations:
|
|
|
455
455
|
Notes — {{steps.gather-notes.output.count}} found: {{steps.project-notes.output.result}}
|
|
456
456
|
People — {{steps.gather-people.output.count}} found: {{steps.project-people.output.result}}
|
|
457
457
|
Companies — {{steps.gather-companies.output.count}} found: {{steps.project-companies.output.result}}
|
|
458
|
-
maxTokens: "
|
|
458
|
+
maxTokens: "2000"
|
|
459
459
|
errorHandling:
|
|
460
460
|
continueOnError: true
|
|
461
|
+
maxRetries: 1
|
|
462
|
+
retryDelay: 5000
|
|
461
463
|
- id: relate
|
|
462
464
|
type: capability
|
|
463
465
|
position:
|
|
@@ -537,9 +539,11 @@ automations:
|
|
|
537
539
|
is busy, a company with people but no tasks. Write only observations
|
|
538
540
|
that span TWO OR MORE records or kinds. If there are none, say what you
|
|
539
541
|
checked and did not find — never answer with nothing.
|
|
540
|
-
maxTokens: "
|
|
542
|
+
maxTokens: "2000"
|
|
541
543
|
errorHandling:
|
|
542
544
|
continueOnError: true
|
|
545
|
+
maxRetries: 1
|
|
546
|
+
retryDelay: 5000
|
|
543
547
|
- id: assemble
|
|
544
548
|
type: capability
|
|
545
549
|
position:
|
|
@@ -724,6 +728,9 @@ automations:
|
|
|
724
728
|
RELATE ROUND MATERIAL:
|
|
725
729
|
{{steps.relate.output}}
|
|
726
730
|
maxTokens: "2000"
|
|
731
|
+
errorHandling:
|
|
732
|
+
maxRetries: 1
|
|
733
|
+
retryDelay: 5000
|
|
727
734
|
- id: summarize
|
|
728
735
|
type: capability
|
|
729
736
|
position:
|
|
@@ -742,6 +749,9 @@ automations:
|
|
|
742
749
|
Material to summarize (may be an error object if the round failed):
|
|
743
750
|
{{steps.analyze.output}}
|
|
744
751
|
maxTokens: "500"
|
|
752
|
+
errorHandling:
|
|
753
|
+
maxRetries: 1
|
|
754
|
+
retryDelay: 5000
|
|
745
755
|
- id: guard-assembled
|
|
746
756
|
type: guard
|
|
747
757
|
position:
|
|
@@ -47,6 +47,10 @@ profiles:
|
|
|
47
47
|
description: A liquidity provider — makes markets and provides depth for a token.
|
|
48
48
|
scope: shared
|
|
49
49
|
profileKind: role
|
|
50
|
+
# Shared supply-role category → the intro-matcher's roster spans ALL roles
|
|
51
|
+
# tagged "provider" via entity.query { roleCategory: "provider" } (no per-role
|
|
52
|
+
# hardcoding). Keep this string in sync with networking.yaml's solution-provider.
|
|
53
|
+
roleCategory: provider
|
|
50
54
|
applicableKinds:
|
|
51
55
|
- company
|
|
52
56
|
- person
|
|
@@ -81,6 +85,10 @@ profiles:
|
|
|
81
85
|
description: A security firm or individual that audits smart contracts and protocols.
|
|
82
86
|
scope: shared
|
|
83
87
|
profileKind: role
|
|
88
|
+
# Shared supply-role category → the intro-matcher's roster spans ALL roles
|
|
89
|
+
# tagged "provider" via entity.query { roleCategory: "provider" } (no per-role
|
|
90
|
+
# hardcoding). Keep this string in sync with networking.yaml's solution-provider.
|
|
91
|
+
roleCategory: provider
|
|
84
92
|
applicableKinds:
|
|
85
93
|
- company
|
|
86
94
|
- person
|
|
@@ -115,6 +123,10 @@ profiles:
|
|
|
115
123
|
description: An outsourced engineering studio or build partner.
|
|
116
124
|
scope: shared
|
|
117
125
|
profileKind: role
|
|
126
|
+
# Shared supply-role category → the intro-matcher's roster spans ALL roles
|
|
127
|
+
# tagged "provider" via entity.query { roleCategory: "provider" } (no per-role
|
|
128
|
+
# hardcoding). Keep this string in sync with networking.yaml's solution-provider.
|
|
129
|
+
roleCategory: provider
|
|
118
130
|
applicableKinds:
|
|
119
131
|
- company
|
|
120
132
|
- person
|
|
@@ -149,6 +161,10 @@ profiles:
|
|
|
149
161
|
description: A brand, growth, or content marketing agency.
|
|
150
162
|
scope: shared
|
|
151
163
|
profileKind: role
|
|
164
|
+
# Shared supply-role category → the intro-matcher's roster spans ALL roles
|
|
165
|
+
# tagged "provider" via entity.query { roleCategory: "provider" } (no per-role
|
|
166
|
+
# hardcoding). Keep this string in sync with networking.yaml's solution-provider.
|
|
167
|
+
roleCategory: provider
|
|
152
168
|
applicableKinds:
|
|
153
169
|
- company
|
|
154
170
|
- person
|
|
@@ -183,6 +199,10 @@ profiles:
|
|
|
183
199
|
description: A performance / paid-media buying agency.
|
|
184
200
|
scope: shared
|
|
185
201
|
profileKind: role
|
|
202
|
+
# Shared supply-role category → the intro-matcher's roster spans ALL roles
|
|
203
|
+
# tagged "provider" via entity.query { roleCategory: "provider" } (no per-role
|
|
204
|
+
# hardcoding). Keep this string in sync with networking.yaml's solution-provider.
|
|
205
|
+
roleCategory: provider
|
|
186
206
|
applicableKinds:
|
|
187
207
|
- company
|
|
188
208
|
- person
|
|
@@ -217,6 +237,10 @@ profiles:
|
|
|
217
237
|
description: A key opinion leader or influencer who amplifies reach.
|
|
218
238
|
scope: shared
|
|
219
239
|
profileKind: role
|
|
240
|
+
# Shared supply-role category → the intro-matcher's roster spans ALL roles
|
|
241
|
+
# tagged "provider" via entity.query { roleCategory: "provider" } (no per-role
|
|
242
|
+
# hardcoding). Keep this string in sync with networking.yaml's solution-provider.
|
|
243
|
+
roleCategory: provider
|
|
220
244
|
applicableKinds:
|
|
221
245
|
- company
|
|
222
246
|
- person
|
|
@@ -243,6 +267,88 @@ profiles:
|
|
|
243
267
|
valueType: string
|
|
244
268
|
inputType: textarea
|
|
245
269
|
|
|
270
|
+
# ── Grant Program (the per-chain funding PROGRAM — parent of a round) ───────
|
|
271
|
+
# The 3-layer grants spine is PROGRAM ≠ ROUND ≠ APPLICATION. `round` (in
|
|
272
|
+
# grants.yaml) is the funding-cycle/deadline carrier; a program is the
|
|
273
|
+
# long-lived, chain-scoped funder above it (e.g. Stellar SCF, Optimism RetroPGF).
|
|
274
|
+
# It lives HERE, with the web3 vocabulary, because a program IS a blockchain-
|
|
275
|
+
# ecosystem thing (it carries a `blockchain` and program mechanics), and it is
|
|
276
|
+
# a real-world entity referenced from every workspace — hence pod-wide, mirroring
|
|
277
|
+
# company/person in ecosystem.yaml (`entityScope: pod`). `scope: shared` makes
|
|
278
|
+
# the profile DEF pod-wide too, so a REUSING template (grants.yaml `require`s this
|
|
279
|
+
# overlay) resolves `grant-program` for its `round → belongs_to → grant-program`
|
|
280
|
+
# edge and deadline view. `defaultPlaybook` is a text ref for now — Wave 2 will
|
|
281
|
+
# create the actual per-chain playbook and bind it.
|
|
282
|
+
- slug: grant-program
|
|
283
|
+
displayName: Grant Program
|
|
284
|
+
icon: landmark
|
|
285
|
+
color: emerald
|
|
286
|
+
description: A per-chain funding program (e.g. Stellar SCF, Optimism RetroPGF) — the long-lived funder above a round.
|
|
287
|
+
profileKind: kind
|
|
288
|
+
entityScope: pod
|
|
289
|
+
scope: shared
|
|
290
|
+
properties:
|
|
291
|
+
- slug: blockchain
|
|
292
|
+
label: Blockchain / Chain
|
|
293
|
+
valueType: string
|
|
294
|
+
inputType: text
|
|
295
|
+
- slug: programName
|
|
296
|
+
label: Program Name
|
|
297
|
+
valueType: string
|
|
298
|
+
inputType: text
|
|
299
|
+
- slug: programType
|
|
300
|
+
label: Program Type
|
|
301
|
+
valueType: string
|
|
302
|
+
inputType: select
|
|
303
|
+
enumValues:
|
|
304
|
+
- direct
|
|
305
|
+
- retroactive
|
|
306
|
+
- quadratic
|
|
307
|
+
- rfp
|
|
308
|
+
- slug: status
|
|
309
|
+
label: Status
|
|
310
|
+
valueType: string
|
|
311
|
+
inputType: select
|
|
312
|
+
enumValues:
|
|
313
|
+
- active
|
|
314
|
+
- paused
|
|
315
|
+
- retired
|
|
316
|
+
- slug: url
|
|
317
|
+
label: Program URL
|
|
318
|
+
valueType: string
|
|
319
|
+
inputType: url
|
|
320
|
+
- slug: cadence
|
|
321
|
+
label: Cadence
|
|
322
|
+
valueType: string
|
|
323
|
+
inputType: text
|
|
324
|
+
placeholder: every 6 weeks
|
|
325
|
+
- slug: nextDeadline
|
|
326
|
+
label: Next Deadline
|
|
327
|
+
valueType: date
|
|
328
|
+
inputType: date
|
|
329
|
+
- slug: submissionTracks
|
|
330
|
+
label: Submission Tracks
|
|
331
|
+
valueType: array
|
|
332
|
+
inputType: text
|
|
333
|
+
- slug: trancheModel
|
|
334
|
+
label: Tranche Model
|
|
335
|
+
valueType: string
|
|
336
|
+
inputType: text
|
|
337
|
+
placeholder: 4 tranches / 90 days
|
|
338
|
+
- slug: defaultPlaybook
|
|
339
|
+
label: Default Playbook
|
|
340
|
+
valueType: string
|
|
341
|
+
inputType: text
|
|
342
|
+
# Defaults to the BASE grant playbook (grants.yaml `Grant Process`), the
|
|
343
|
+
# data-driven process that reads THIS program's cadence/tracks/tranche
|
|
344
|
+
# model at runtime. Override per-program only for a differently-shaped chain.
|
|
345
|
+
constraints:
|
|
346
|
+
defaultValue: Grant Process
|
|
347
|
+
- slug: description
|
|
348
|
+
label: Description
|
|
349
|
+
valueType: string
|
|
350
|
+
inputType: textarea
|
|
351
|
+
|
|
246
352
|
# Web3 actor↔actor relations (company→company). `company` resolves from the
|
|
247
353
|
# Ecosystem base — not redeclared here.
|
|
248
354
|
entityLinks:
|
package/src/builder.yaml
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# Builder workspace template
|
|
2
2
|
# Developer + agent intelligence layer.
|
|
3
|
-
#
|
|
3
|
+
#
|
|
4
|
+
# ✅ SINGLE SOURCE OF TRUTH for the Builder workspace, on every door.
|
|
5
|
+
# Both doors now derive from this file:
|
|
6
|
+
# • apps/devplane/lib/builderWorkspaceDefinition.ts → the devplane onboarding
|
|
7
|
+
# path (trpc.workspaces.createFromDefinition) — since 2026-09-05 that module
|
|
8
|
+
# is a five-line `toWorkspaceDefinition("builder-workspace")` derivation
|
|
9
|
+
# • the registry / marketplace install path — same seam
|
|
10
|
+
# Until 2026-09-05 the TS file held a ~1,150-line hand-typed PEER copy of this
|
|
11
|
+
# workspace and nothing compared the two, which produced five real divergences
|
|
12
|
+
# (four capabilities, a dead-Coolify seed pair, defaultApp/primarySurface, an
|
|
13
|
+
# unprefixed calendar dateField, and this file's playbooks/onboarding). Edit the
|
|
14
|
+
# schema HERE; there is no second copy to keep in sync.
|
|
4
15
|
|
|
5
16
|
meta:
|
|
6
17
|
slug: builder-workspace
|
|
@@ -23,6 +34,13 @@ workspace:
|
|
|
23
34
|
- builder.deployments
|
|
24
35
|
- builder.agents
|
|
25
36
|
- builder.packages
|
|
37
|
+
# Tier-1 signal for `resolveWorkspaceForScope` — must match the DevPlane app
|
|
38
|
+
# manifest's `defaultScope.capability` (browser/…/apps/manifest.ts) and the
|
|
39
|
+
# `workspaceCapabilities` list the devplane door derives from this block.
|
|
40
|
+
# Without it a workspace created through THIS door fails all four resolver tiers
|
|
41
|
+
# (no capability · subtype "builder" ≠ kind "devplane" · name "Builder" ≠ "DevPlane")
|
|
42
|
+
# and the workspace press falls silently to a setup card.
|
|
43
|
+
- devplane.workspace
|
|
26
44
|
|
|
27
45
|
profiles:
|
|
28
46
|
- slug: devplane_app
|