@synap-core/workspace-templates 0.9.3 → 0.10.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 +137 -44
- package/dist/index.js +1816 -128
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__fixtures__/default-relation-defs.json +208 -0
- package/src/__fixtures__/report-automation-flow.json +393 -0
- package/src/agent-fleet.yaml +6 -1
- package/src/base.template.test.ts +160 -0
- package/src/base.yaml +839 -0
- package/src/business-developer.template.test.ts +79 -10
- package/src/business-developer.yaml +61 -39
- package/src/concept-guard.test.ts +47 -31
- package/src/concept-guard.ts +23 -19
- package/src/content-os.yaml +22 -0
- package/src/corpus-flow-validity.test.ts +130 -0
- package/src/crm.yaml +125 -8
- package/src/define.primary-surface.test.ts +2 -4
- package/src/define.ts +28 -0
- package/src/ecosystem.yaml +14 -0
- package/src/enterprise-os.yaml +1 -1
- package/src/foundation.yaml +8 -0
- package/src/grants.yaml +8 -0
- package/src/life-os.yaml +6 -1
- package/src/operations.yaml +270 -0
- package/src/outreach-comms.yaml +196 -0
- package/src/project-management.yaml +6 -1
- package/src/templates.ts +1717 -371
- package/src/types.ts +113 -37
- package/src/validate-flow.ts +186 -7
- package/src/validate-onboarding.test.ts +88 -0
- package/src/validate.ts +148 -12
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract + fidelity tests for the `base` template (Wave 2+3 of
|
|
3
|
+
* REPORT-AUTOMATION-ONE-DOOR-PLAN).
|
|
4
|
+
*
|
|
5
|
+
* `base` carries the pod-wide operational defaults that three hardcoded seeders
|
|
6
|
+
* used to inject: the report automation, the default relation vocabulary, and
|
|
7
|
+
* the default command pack. These tests are the guardrail that lets those
|
|
8
|
+
* seeders be deleted (Wave 4) without silently changing what every workspace
|
|
9
|
+
* gets.
|
|
10
|
+
*
|
|
11
|
+
* FIDELITY MECHANISM. The report prompts are the product — a single altered
|
|
12
|
+
* character is a regression. Importing `REPORT_AUTOMATION_FLOW` from
|
|
13
|
+
* `@synap/database` into this frontend package would be an upward layering
|
|
14
|
+
* violation, so instead the byte-for-byte guardrail is a COMMITTED, GENERATED
|
|
15
|
+
* fixture (`__fixtures__/report-automation-flow.json`) snapshotted from the
|
|
16
|
+
* backend const at authoring time, never hand-typed. The chain the test proves:
|
|
17
|
+
* compiled base flow === fixture (=== REPORT_AUTOMATION_FLOW at capture).
|
|
18
|
+
* Same for the 23-ish relation defs via `__fixtures__/default-relation-defs.json`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync } from "fs";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
import { dirname, join } from "path";
|
|
24
|
+
import { describe, expect, it } from "vitest";
|
|
25
|
+
import { getWorkspaceTemplate } from "./templates.js";
|
|
26
|
+
import { toWorkspaceDefinition, toPackageDefinition } from "./define.js";
|
|
27
|
+
|
|
28
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const readFixture = (name: string) =>
|
|
30
|
+
JSON.parse(readFileSync(join(HERE, "__fixtures__", name), "utf-8"));
|
|
31
|
+
|
|
32
|
+
const base = (() => {
|
|
33
|
+
const resolved = getWorkspaceTemplate("base");
|
|
34
|
+
if (!resolved) throw new Error("base template is not registered");
|
|
35
|
+
return resolved;
|
|
36
|
+
})();
|
|
37
|
+
|
|
38
|
+
describe("base template — identity", () => {
|
|
39
|
+
it("is a pod-visible core-domain template", () => {
|
|
40
|
+
expect(base.meta.slug).toBe("base");
|
|
41
|
+
expect(base.meta.domain).toBe("core");
|
|
42
|
+
expect(base.meta.isPublic).toBe(true);
|
|
43
|
+
expect(base.workspace.visibility).toBe("pod_visible");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("Task A — report automation, byte-faithful", () => {
|
|
48
|
+
const automation = base.automations?.[0];
|
|
49
|
+
|
|
50
|
+
it("carries exactly one manual, active 'Generate report' automation", () => {
|
|
51
|
+
expect(base.automations).toHaveLength(1);
|
|
52
|
+
expect(automation?.name).toBe("Generate report");
|
|
53
|
+
expect(automation?.triggerType).toBe("manual");
|
|
54
|
+
expect(automation?.status).toBe("active");
|
|
55
|
+
expect(automation?.description).toMatch(/Gather this workspace's state/);
|
|
56
|
+
});
|
|
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
|
+
it("preserves the load-bearing hardened prompt fragments (v13)", () => {
|
|
67
|
+
// A coarse smoke check that the specific product content survived — the
|
|
68
|
+
// deep-equal above is authoritative, but these named fragments make a
|
|
69
|
+
// regression legible if the fixture is ever regenerated wrongly.
|
|
70
|
+
const flowStr = JSON.stringify(automation?.flow);
|
|
71
|
+
for (const marker of [
|
|
72
|
+
"COUNTS — the exact number of records gathered",
|
|
73
|
+
"NEVER NARRATE YOUR OWN INSTRUCTIONS",
|
|
74
|
+
"LINK THE RECORDS YOU NAME",
|
|
75
|
+
"DATA INTEGRITY CHECK",
|
|
76
|
+
]) {
|
|
77
|
+
expect(flowStr).toContain(marker);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("Task B — relation defs, full coverage", () => {
|
|
83
|
+
const fixture: Array<{ slug: string }> = readFixture(
|
|
84
|
+
"default-relation-defs.json"
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
it("covers every DEFAULT_RELATION_DEFS slug, byte-faithfully", () => {
|
|
88
|
+
// deep-equal against the generated snapshot: proves slug + displayName +
|
|
89
|
+
// description + isDirectional + uiHints all survived (the fields the
|
|
90
|
+
// entityLinks path would have dropped).
|
|
91
|
+
expect(base.relationDefs).toEqual(fixture);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("has no duplicate slugs and carries the expected count", () => {
|
|
95
|
+
const slugs = (base.relationDefs ?? []).map((d) => d.slug);
|
|
96
|
+
expect(new Set(slugs).size).toBe(slugs.length);
|
|
97
|
+
expect(slugs.length).toBe(fixture.length);
|
|
98
|
+
// Spot-check a representative spread across categories.
|
|
99
|
+
for (const s of ["assigned_to", "relates_to", "works_at", "knows"]) {
|
|
100
|
+
expect(slugs).toContain(s);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("Task C — default command pack", () => {
|
|
106
|
+
const EXPECTED_TITLES = [
|
|
107
|
+
"Create View from Description",
|
|
108
|
+
"Extract Entities from Text",
|
|
109
|
+
"Summarize Selection",
|
|
110
|
+
"Analyze Entities",
|
|
111
|
+
"Create Task from Text",
|
|
112
|
+
"Create Event from Text",
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
it("carries all 6 default command titles", () => {
|
|
116
|
+
const titles = (base.commands ?? []).map((c) => c.title);
|
|
117
|
+
expect(titles).toEqual(EXPECTED_TITLES);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("every command has a non-empty prompt template", () => {
|
|
121
|
+
for (const c of base.commands ?? []) {
|
|
122
|
+
expect(typeof c.promptTemplate).toBe("string");
|
|
123
|
+
expect(c.promptTemplate.length).toBeGreaterThan(0);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("the view command derives a goal input and can create views", () => {
|
|
128
|
+
const viewCmd = base.commands?.find(
|
|
129
|
+
(c) => c.title === "Create View from Description"
|
|
130
|
+
);
|
|
131
|
+
expect(viewCmd?.canCreateViews).toBe(true);
|
|
132
|
+
expect(viewCmd?.outputMode).toBe("view");
|
|
133
|
+
expect(viewCmd?.derivedInputs).toEqual([
|
|
134
|
+
{ name: "goal", label: "Goal", type: "text" },
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe("door contract — resolved definitions forward the new surfaces", () => {
|
|
140
|
+
it("toWorkspaceDefinition('base') exposes commands, relationDefs, flowAutomations", () => {
|
|
141
|
+
const { definition } = toWorkspaceDefinition("base");
|
|
142
|
+
expect(definition.relationDefs).toEqual(base.relationDefs);
|
|
143
|
+
expect(definition.commands).toEqual(base.commands);
|
|
144
|
+
// flowAutomations is the existing wire field (define.ts maps flow→flowDefinition).
|
|
145
|
+
expect(definition.flowAutomations).toHaveLength(1);
|
|
146
|
+
expect(definition.flowAutomations?.[0]?.name).toBe("Generate report");
|
|
147
|
+
expect(definition.flowAutomations?.[0]?.flowDefinition).toEqual(
|
|
148
|
+
base.automations?.[0]?.flow
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("toPackageDefinition('base') carries the same surfaces (CP seed path)", () => {
|
|
153
|
+
const pkg = toPackageDefinition("base");
|
|
154
|
+
expect(pkg.relationDefs).toEqual(base.relationDefs);
|
|
155
|
+
expect(pkg.commands).toEqual(base.commands);
|
|
156
|
+
expect(pkg.automations?.[0]?.flowDefinition).toEqual(
|
|
157
|
+
base.automations?.[0]?.flow
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
});
|