@synap-core/workspace-templates 0.11.0 → 0.23.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 +483 -0
- package/automations/bookmark-enrichment.automation.json +321 -0
- package/automations/github-pr-events.automation.json +505 -0
- package/automations/mail-feed.automation.json +86 -0
- package/automations/ship-a-change-checks-green.automation.json +106 -0
- package/automations/ship-a-change-checks-red.automation.json +106 -0
- package/automations/ship-a-change-deployed.automation.json +56 -0
- package/automations/ship-a-change-pr-merged.automation.json +110 -0
- package/automations/ship-a-change-pr-opened.automation.json +104 -0
- package/automations/url-bookmark-capture.automation.json +132 -0
- package/capabilities/agency-skills.capability.json +157 -0
- package/capabilities/apify.capability.json +265 -0
- package/capabilities/apollo.capability.json +120 -0
- package/capabilities/arch-backend.capability.json +97 -0
- package/capabilities/arch-client-intelligence.capability.json +401 -0
- package/capabilities/backblaze-b2.capability.json +205 -0
- package/capabilities/cal-com.capability.json +266 -0
- package/capabilities/canva.capability.json +274 -0
- package/capabilities/claude-code-routines.capability.json +172 -0
- package/capabilities/claude-managed-agents.capability.json +215 -0
- package/capabilities/client-comms-report.capability.json +246 -0
- package/capabilities/content-idea-to-production.capability.json +29 -0
- package/capabilities/datagouv.capability.json +315 -0
- package/capabilities/discord-bot.capability.json +157 -0
- package/capabilities/dropbox.capability.json +281 -0
- package/capabilities/exa.capability.json +109 -0
- package/capabilities/fal-ai.capability.json +83 -0
- package/capabilities/fal-media-lab.capability.json +158 -0
- package/capabilities/fireflies.capability.json +191 -0
- package/capabilities/freellmapi.capability.json +114 -0
- package/capabilities/generic-apikey.capability.json +92 -0
- package/capabilities/github-merge.capability.json +99 -0
- package/capabilities/github-read.capability.json +325 -0
- package/capabilities/governance-tighten-recommender.capability.json +81 -0
- package/capabilities/jev.capability.json +226 -0
- package/capabilities/lead-conversion-enrollment.capability.json +246 -0
- package/capabilities/mail-feed.capability.json +277 -0
- package/capabilities/mailgun.capability.json +52 -0
- package/capabilities/nango-google.capability.json +639 -0
- package/capabilities/notion.capability.json +417 -0
- package/capabilities/omniroute.capability.json +137 -0
- package/capabilities/posthog-analytics.capability.json +258 -0
- package/capabilities/postiz.capability.json +467 -0
- package/capabilities/proactive-digest.capability.json +190 -0
- package/capabilities/proton.capability.json +288 -0
- package/capabilities/replicate-rvm.capability.json +97 -0
- package/capabilities/research-methods.capability.json +57 -0
- package/capabilities/shopify.capability.json +395 -0
- package/capabilities/slack.capability.json +369 -0
- package/capabilities/stripe.capability.json +420 -0
- package/capabilities/telegram-bridge.capability.json +56 -0
- package/capabilities/treg.capability.json +102 -0
- package/capabilities/unipile-linkedin.capability.json +471 -0
- package/capabilities/vercel.capability.json +424 -0
- package/dist/define-CPS0n8BV.d.ts +1331 -0
- package/dist/index.d.ts +189 -900
- package/dist/index.js +24654 -21639
- package/dist/index.js.map +1 -1
- package/dist/wire.d.ts +222 -0
- package/dist/wire.js +77 -0
- package/dist/wire.js.map +1 -0
- package/package.json +41 -27
- package/packs/bookmark-views-pack.json +33 -0
- package/packs/crm-pack.json +76 -0
- package/packs/customer-profile.json +28 -0
- package/packs/deep-research.playbook.json +30 -0
- package/packs/event-views-pack.json +33 -0
- package/packs/habit-profile.json +27 -0
- package/packs/hr-pack.json +54 -0
- package/packs/invoice-profile.json +28 -0
- package/packs/knowledge-base-pack.json +56 -0
- package/packs/meeting-profile.json +29 -0
- package/packs/product-profile.json +30 -0
- package/packs/project-management-pack.json +49 -0
- package/packs/recipe-profile.json +29 -0
- package/packs/task-views-pack.json +39 -0
- package/retired.yaml +136 -0
- package/skills/app-factory-build-slice/SKILL.md +70 -0
- package/skills/app-factory-build-slice.catalog.json +17 -0
- package/skills/app-factory-design-canvas/SKILL.md +96 -0
- package/skills/app-factory-design-canvas.catalog.json +17 -0
- package/skills/app-factory-design-review/SKILL.md +99 -0
- package/skills/app-factory-design-review.catalog.json +18 -0
- package/skills/app-factory-research/SKILL.md +123 -0
- package/skills/app-factory-research.catalog.json +17 -0
- package/skills/bookmark-enrichment/SKILL.md +40 -0
- package/skills/carousel-format/carousel-format.skill.json +18 -0
- package/skills/collage-broll/collage-broll.skill.json +20 -0
- package/skills/content-taste/content-taste.skill.json +18 -0
- package/skills/creative-director/creative-director.skill.json +18 -0
- package/skills/design-critique/SKILL.md +135 -0
- package/skills/design-critique.catalog.json +12 -0
- package/skills/designing-with-real-components/SKILL.md +140 -0
- package/skills/designing-with-real-components.catalog.json +12 -0
- package/skills/edit-loop/edit-loop.skill.json +25 -0
- package/skills/facecam-edit/facecam-edit.skill.json +24 -0
- package/skills/mapping-the-server/SKILL.md +54 -0
- package/skills/math-explainer-manimgx/math-explainer-manimgx.skill.json +20 -0
- package/skills/motion-quality-gates/motion-quality-gates.skill.json +20 -0
- package/skills/open-design-edit/open-design-edit.skill.json +24 -0
- package/skills/reading-client-progress/SKILL.md +65 -0
- package/skills/routing-to-channels/SKILL.md +54 -0
- package/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
- package/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
- package/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
- package/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
- package/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
- package/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
- package/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
- package/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
- package/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
- package/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
- package/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
- package/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
- package/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
- package/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
- package/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
- package/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
- package/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
- package/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
- package/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
- package/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
- package/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
- package/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
- package/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
- package/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
- package/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
- package/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
- package/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
- package/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
- package/skills/video-direction/video-direction.skill.json +20 -0
- package/skills/video-style-vocabulary/video-style-vocabulary.skill.json +20 -0
- package/skills/video-toolbox/video-toolbox.skill.json +20 -0
- package/src/__fixtures__/lifecycle-presets.flat-before.json +205 -0
- package/src/agency-os.yaml +122 -0
- package/src/agent-os-skill-slugs.test.ts +65 -0
- package/src/apify-social-reader.test.ts +317 -0
- package/src/base.template.test.ts +25 -19
- package/src/base.yaml +95 -39
- package/src/blockchain-ecosystem.yaml +1 -0
- package/src/brand-library.yaml +525 -14
- package/src/builder-dev-fold.template.test.ts +113 -0
- package/src/builder.yaml +798 -92
- package/src/business-model-catalog-description.test.ts +47 -0
- package/src/business-model-grp.template.test.ts +214 -0
- package/src/business-model.yaml +598 -0
- package/src/catalog-safety.test.ts +198 -0
- package/src/catalog.template-items.test.ts +75 -0
- package/src/catalog.ts +85 -2
- package/src/civic-france.yaml +102 -0
- package/src/concept-guard.test.ts +28 -8
- package/src/concept-guard.ts +2 -2
- package/src/content-creation.template.test.ts +52 -0
- package/src/content-creation.yaml +192 -0
- package/src/content-os.edit-loop.template.test.ts +210 -0
- package/src/content-os.publish-due-posts.template.test.ts +261 -0
- package/src/content-os.template.test.ts +322 -0
- package/src/content-os.video-takes.template.test.ts +338 -0
- package/src/content-os.work-a-take.template.test.ts +125 -0
- package/src/content-os.yaml +1830 -39
- package/src/content-studio-retired.template.test.ts +82 -0
- package/src/corpus-flow-validity.test.ts +4 -5
- package/src/crm-absorbs-outreach.template.test.ts +117 -0
- package/src/crm-build-plan.template.test.ts +128 -0
- package/src/crm-lists.template.test.ts +96 -0
- package/src/crm-messages-cadence.template.test.ts +164 -0
- package/src/crm-one-send-door.template.test.ts +65 -0
- package/src/crm.yaml +1456 -181
- package/src/decisions-wave.template.test.ts +186 -0
- package/src/define.ts +130 -17
- package/src/design-to-implementation.template.test.ts +94 -0
- package/src/dist-freshness.test.ts +97 -0
- package/src/domain-template-type.test.ts +75 -0
- package/src/ecosystem.yaml +27 -66
- package/src/enterprise-os.yaml +10 -134
- package/src/facecam-edit.audio-studio.test.ts +188 -0
- package/src/fal-generate-image.test.ts +200 -0
- package/src/fal-media-lab-pod-files.test.ts +180 -0
- package/src/finance.yaml +254 -1
- package/src/foundation.yaml +130 -28
- package/src/frame-host-modules.d.mts +6 -0
- package/src/frame-host-modules.mjs +58 -0
- package/src/generate.mjs +9 -3
- package/src/github-merge.test.ts +210 -0
- package/src/grants.yaml +57 -17
- package/src/hr.yaml +39 -6
- package/src/index.ts +36 -1
- package/src/intent.test.ts +161 -0
- package/src/internal-runbook.yaml +19 -1
- package/src/jev.test.ts +356 -0
- package/src/legal.yaml +33 -1
- package/src/life-os.yaml +65 -240
- package/src/lifecycle-coverage.test.ts +124 -0
- package/src/lifecycle-declarations.test.ts +252 -0
- package/src/lifecycle-presets.test.ts +468 -0
- package/src/lifecycle-presets.ts +494 -0
- package/src/lifecycle-stuck.test.ts +46 -0
- package/src/lifecycle-waits.parity.test.ts +319 -0
- package/src/marketing.yaml +108 -4
- package/src/meetings-knowledge.yaml +18 -0
- package/src/networking.yaml +23 -2
- package/src/operations.yaml +304 -4
- package/src/pipeline-views.template.test.ts +88 -0
- package/src/playbook-goal-placeholders.test.ts +57 -0
- package/src/postiz-contract.test.ts +134 -0
- package/src/presentation-declarations.test.ts +174 -0
- package/src/process-contract.validate.test.ts +352 -0
- package/src/project-management.yaml +39 -740
- package/src/publish-body.d.mts +29 -0
- package/src/publish-body.mjs +74 -0
- package/src/publish-body.test.ts +74 -0
- package/src/publish-official-lib.test.ts +176 -0
- package/src/replicate-rvm.test.ts +504 -0
- package/src/research-base.yaml +119 -20
- package/src/research-decision.yaml +60 -3
- package/src/reserved-profile-slugs.test.ts +83 -0
- package/src/retired-goal-kinds.test.ts +58 -0
- package/src/role-reference-and-step-domain.test.ts +192 -0
- package/src/seed-obligation.test.ts +176 -0
- package/src/send-message-maps.test.ts +227 -0
- package/src/shared-role-ssot.test.ts +42 -1
- package/src/ship-a-change.template.test.ts +177 -0
- package/src/skills.test.ts +170 -0
- package/src/social.yaml +85 -27
- package/src/space-packages.freshness.test.ts +97 -0
- package/src/space-packages.generated.ts +40 -0
- package/src/space-packages.test.ts +125 -0
- package/src/space-packages.ts +73 -0
- package/src/start.test.ts +188 -0
- package/src/task-intents.test.ts +293 -0
- package/src/templates.ts +21639 -21522
- package/src/types.ts +443 -60
- package/src/unipile-publish-post.test.ts +162 -0
- package/src/validate-flow.drift.test.ts +2 -3
- package/src/validate-flow.ts +32 -2
- package/src/validate-onboarding.test.ts +59 -0
- package/src/validate.test.ts +156 -3
- package/src/validate.ts +1384 -7
- package/src/wire-core.ts +231 -0
- package/src/wire.test.ts +159 -0
- package/src/wire.ts +107 -0
- package/src/__fixtures__/report-automation-flow.json +0 -393
- package/src/agent-fleet.yaml +0 -1645
- package/src/business-developer.template.test.ts +0 -351
- package/src/business-developer.yaml +0 -860
- package/src/content-studio.yaml +0 -361
- package/src/dev-dashboard.yaml +0 -990
- package/src/outreach-comms.yaml +0 -486
- package/src/the-arch.yaml +0 -201
package/src/wire-core.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-kind wire envelopes and the ONE unwrap — import-free on purpose.
|
|
3
|
+
*
|
|
4
|
+
* Re-exported (with the workspace types) by `./wire`, the public subpath
|
|
5
|
+
* `@synap-core/workspace-templates/wire`. It has no imports so a consumer that
|
|
6
|
+
* still resolves an older npm copy of this package (the CLI, the CP, the pod)
|
|
7
|
+
* can carry it as a BYTE-IDENTICAL mirror pinned by a tripwire until it can
|
|
8
|
+
* import the subpath. Edit it here; the mirror copies it.
|
|
9
|
+
*
|
|
10
|
+
* What `GET {CP}/api/packages/:slug` serves as `package.definition`, per kind:
|
|
11
|
+
* the outputs of this package's producers (`scripts/catalog-lib.mjs`
|
|
12
|
+
* `toPublishBody`; `toOfficialPublishBody` for workspaces) plus what the CP
|
|
13
|
+
* adds on store/serve (`_meta.slug` via `withTemplateSlug`,
|
|
14
|
+
* `capability.contentHash`).
|
|
15
|
+
*
|
|
16
|
+
* WHY: a skill package is served as `{ _meta, skill: {…} }`. Read flat, every
|
|
17
|
+
* field is `undefined`: install refused a "bodiless" skill and the update door
|
|
18
|
+
* reported "no drift" forever (founder pod 2026-10-13, creative-director). Each
|
|
19
|
+
* consumer had its own cast; this is the one place the envelope is known.
|
|
20
|
+
*
|
|
21
|
+
* Element fields are pinned to the catalog schema (`SKILL_FIELDS`,
|
|
22
|
+
* `CapabilitySpec`) and `AutomationElement` to `PackageAutomationWire` by
|
|
23
|
+
* `schema/wire.parity.test.ts` (compile time).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// ─── Kinds ──────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
/** The kinds whose served definition this module describes. */
|
|
29
|
+
export const WIRE_KINDS = ["workspace", "capability", "skill", "automation", "view"] as const;
|
|
30
|
+
export type WireKind = (typeof WIRE_KINDS)[number];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Other names the same kinds go by: the pod's `market.install` says
|
|
34
|
+
* `template`, the CP category for an automation is `workflow`, and a pack is
|
|
35
|
+
* a workspace-shaped definition.
|
|
36
|
+
*/
|
|
37
|
+
export const WIRE_KIND_ALIASES = {
|
|
38
|
+
template: "workspace",
|
|
39
|
+
pack: "workspace",
|
|
40
|
+
workflow: "automation",
|
|
41
|
+
} as const satisfies Record<string, WireKind>;
|
|
42
|
+
export type WireKindName = WireKind | keyof typeof WIRE_KIND_ALIASES;
|
|
43
|
+
|
|
44
|
+
/** `template` → `workspace`, `workflow` → `automation`; `null` for a kind with no wire contract here (e.g. `cell`). */
|
|
45
|
+
export function toWireKind(kind: string): WireKind | null {
|
|
46
|
+
if ((WIRE_KINDS as readonly string[]).includes(kind)) return kind as WireKind;
|
|
47
|
+
return (WIRE_KIND_ALIASES as Record<string, WireKind>)[kind] ?? null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ─── Envelope pieces every kind shares ──────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* `definition._meta` as served: the CP stamps `slug` on every row (the pod
|
|
54
|
+
* keys "which space is this template's?" on it); the CLI adds the `version`
|
|
55
|
+
* label it installs.
|
|
56
|
+
*/
|
|
57
|
+
export interface WireMeta {
|
|
58
|
+
slug?: string;
|
|
59
|
+
version?: string;
|
|
60
|
+
[key: string]: unknown;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** `meta.icon` / `color` / `domain`, mirrored onto the definition by every publish builder. */
|
|
64
|
+
export interface WireIdentity {
|
|
65
|
+
icon?: string;
|
|
66
|
+
color?: string;
|
|
67
|
+
domain?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** A composition dependency. */
|
|
71
|
+
export interface WireDependency {
|
|
72
|
+
slug: string;
|
|
73
|
+
kind?: "workspace" | "capability" | "skill" | "workflow" | "view" | "cell" | "automation";
|
|
74
|
+
relation?: "compose" | "require";
|
|
75
|
+
reason?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface WireEnvelope extends WireIdentity {
|
|
79
|
+
_meta?: WireMeta;
|
|
80
|
+
dependencies?: WireDependency[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ─── Elements and envelopes, per kind ───────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
/** The capability itself (`CapabilityDefinition`). */
|
|
86
|
+
export interface CapabilityElement {
|
|
87
|
+
key: string;
|
|
88
|
+
name: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
params?: Array<Record<string, unknown>>;
|
|
91
|
+
vault?: Array<Record<string, unknown>>;
|
|
92
|
+
tools?: Array<Record<string, unknown>>;
|
|
93
|
+
skills?: Array<Record<string, unknown>>;
|
|
94
|
+
provides?: string[];
|
|
95
|
+
playbooks?: Array<Record<string, unknown>>;
|
|
96
|
+
/** Stamped by the CP on publish; the pod's drift marker. */
|
|
97
|
+
contentHash?: string;
|
|
98
|
+
automations?: Array<Record<string, unknown>>;
|
|
99
|
+
mcpServers?: unknown;
|
|
100
|
+
metadata?: Record<string, unknown>;
|
|
101
|
+
_generated?: unknown;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** capability: `{ profiles: [], description, capability }`. */
|
|
105
|
+
export interface CapabilityWire extends WireEnvelope {
|
|
106
|
+
profiles: unknown[];
|
|
107
|
+
description?: string;
|
|
108
|
+
capability: CapabilityElement;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** ONE standalone skill. Not a workspace's `skills[]` link list. */
|
|
112
|
+
export interface SkillElement {
|
|
113
|
+
/** The pod-side `load_skill` ref — its own identity, not the package slug. */
|
|
114
|
+
slug?: string;
|
|
115
|
+
name?: string;
|
|
116
|
+
displayName?: string;
|
|
117
|
+
description?: string;
|
|
118
|
+
kind?: "instruction" | "code" | "declarative" | "builtin";
|
|
119
|
+
scope?: "pod" | "user" | "workspace";
|
|
120
|
+
agentTypes?: string[];
|
|
121
|
+
body?: string;
|
|
122
|
+
code?: string;
|
|
123
|
+
providerSpec?: Record<string, unknown>;
|
|
124
|
+
parameters?: Record<string, unknown>;
|
|
125
|
+
category?: string;
|
|
126
|
+
executionMode?: "sync" | "async";
|
|
127
|
+
timeoutSeconds?: number;
|
|
128
|
+
intent?: string;
|
|
129
|
+
[key: string]: unknown;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** skill: `{ skill, icon?, color?, domain?, dependencies? }`. */
|
|
133
|
+
export interface SkillWire extends WireEnvelope {
|
|
134
|
+
skill: SkillElement;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** One graph automation (= `PackageAutomationWire`): `flowDefinition`, not the authored `flow`. */
|
|
138
|
+
export interface AutomationElement {
|
|
139
|
+
key?: string;
|
|
140
|
+
name: string;
|
|
141
|
+
description?: string;
|
|
142
|
+
triggerType: "event" | "cron" | "webhook" | "manual";
|
|
143
|
+
triggerConfig?: Record<string, unknown>;
|
|
144
|
+
flowDefinition?: { nodes: unknown[]; edges: unknown[]; precondition?: string };
|
|
145
|
+
status?: "draft" | "active" | "paused";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** automation (CP category `workflow`): `{ profiles: [], automations: [one] }`. */
|
|
149
|
+
export interface AutomationWire extends WireEnvelope {
|
|
150
|
+
profiles: unknown[];
|
|
151
|
+
automations: AutomationElement[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** One view, as the pod's view install and update doors read it. */
|
|
155
|
+
export interface ViewElement {
|
|
156
|
+
slug?: string;
|
|
157
|
+
name?: string;
|
|
158
|
+
displayName?: string;
|
|
159
|
+
description?: string;
|
|
160
|
+
type?: string;
|
|
161
|
+
config?: Record<string, unknown>;
|
|
162
|
+
query?: Record<string, unknown>;
|
|
163
|
+
metadata?: Record<string, unknown>;
|
|
164
|
+
scopeProfileSlugs?: string[];
|
|
165
|
+
scopeProfileIds?: string[];
|
|
166
|
+
[key: string]: unknown;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** view: `{ views: [...] }`, or a legacy single view with its fields on top (has its own `type`). No catalog producer today. */
|
|
170
|
+
export type ViewWire = (WireEnvelope & { views: ViewElement[] }) | ViewElement;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* What {@link unwrapPackage} returns per kind. `workspace` is the definition
|
|
174
|
+
* itself; `./wire` narrows it to `WorkspaceWire`.
|
|
175
|
+
*/
|
|
176
|
+
export interface PackageElementByKind<W = Record<string, unknown>> {
|
|
177
|
+
workspace: W;
|
|
178
|
+
capability: CapabilityElement;
|
|
179
|
+
skill: SkillElement;
|
|
180
|
+
automation: AutomationElement[];
|
|
181
|
+
view: ViewElement[];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type ElementOf<K extends WireKindName, W = Record<string, unknown>> = PackageElementByKind<W>[K extends WireKind
|
|
185
|
+
? K
|
|
186
|
+
: K extends keyof typeof WIRE_KIND_ALIASES
|
|
187
|
+
? (typeof WIRE_KIND_ALIASES)[K]
|
|
188
|
+
: never];
|
|
189
|
+
|
|
190
|
+
// ─── The ONE unwrap ─────────────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
const isRecord = (v: unknown): v is Record<string, unknown> =>
|
|
193
|
+
typeof v === "object" && v !== null && !Array.isArray(v);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The installable element(s) inside a served definition:
|
|
197
|
+
*
|
|
198
|
+
* skill → the `skill` object (a legacy flat definition is the skill itself)
|
|
199
|
+
* capability → the `capability` object (a flat `CapabilityDefinition` — the
|
|
200
|
+
* pod cache / CP by-key shape — passes through)
|
|
201
|
+
* automation → `automations[]` (`[]` when the definition declares none)
|
|
202
|
+
* view → `views[]`, or a legacy flat view (top-level `type`) as `[def]`, else `[]`
|
|
203
|
+
* workspace → the definition itself
|
|
204
|
+
*
|
|
205
|
+
* An empty array means the definition declares none; the install doors refuse
|
|
206
|
+
* that themselves. A definition that is not an object is a failed read, never
|
|
207
|
+
* an empty one: it throws.
|
|
208
|
+
*/
|
|
209
|
+
export function unwrapPackage<K extends WireKindName>(kind: K, definition: unknown): ElementOf<K>;
|
|
210
|
+
export function unwrapPackage(kind: string, definition: unknown): unknown {
|
|
211
|
+
const wireKind = toWireKind(kind);
|
|
212
|
+
if (!wireKind) throw new Error(`unwrapPackage: "${kind}" has no wire contract`);
|
|
213
|
+
if (!isRecord(definition)) {
|
|
214
|
+
throw new TypeError(
|
|
215
|
+
`unwrapPackage(${kind}): the definition is not an object (${definition === null ? "null" : Array.isArray(definition) ? "array" : typeof definition})`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
switch (wireKind) {
|
|
219
|
+
case "skill":
|
|
220
|
+
return isRecord(definition.skill) ? definition.skill : definition;
|
|
221
|
+
case "capability":
|
|
222
|
+
return isRecord(definition.capability) ? definition.capability : definition;
|
|
223
|
+
case "automation":
|
|
224
|
+
return Array.isArray(definition.automations) ? definition.automations : [];
|
|
225
|
+
case "view":
|
|
226
|
+
if (Array.isArray(definition.views) && definition.views.length > 0) return definition.views;
|
|
227
|
+
return definition.type ? [definition] : [];
|
|
228
|
+
case "workspace":
|
|
229
|
+
return definition;
|
|
230
|
+
}
|
|
231
|
+
}
|
package/src/wire.test.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract, driven from the REAL producers: every capability, skill,
|
|
3
|
+
* automation and workspace in this catalog is compiled by `loadCatalog` (the
|
|
4
|
+
* same `toPublishBody` the official publish sends), given the `_meta.slug` the
|
|
5
|
+
* CP stamps on serve, and unwrapped. Nothing between the catalog file and the
|
|
6
|
+
* unwrap is hand-built, so a producer that moves an element out of its slot
|
|
7
|
+
* fails here.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
import { loadCatalog } from "../scripts/catalog-lib.mjs";
|
|
13
|
+
import { toAutomationWire, toPackageDefinition, toWorkspaceDefinition } from "./define";
|
|
14
|
+
import { WORKSPACE_TEMPLATES } from "./templates";
|
|
15
|
+
import { toWireKind, toWorkspaceInput, unwrapPackage, type WorkspaceWire } from "./wire";
|
|
16
|
+
|
|
17
|
+
const loaded = await loadCatalog();
|
|
18
|
+
// The shipped automations are STAGED (raw bridge files, no catalog header), so
|
|
19
|
+
// no live automation compiles today; the fixture catalog's `demo-auto` goes
|
|
20
|
+
// through the same `toPublishBody`.
|
|
21
|
+
const fixture = await loadCatalog({
|
|
22
|
+
root: fileURLToPath(new URL("../scripts/__fixtures__/catalog", import.meta.url)),
|
|
23
|
+
dirs: { workspace: ["workspaces"] },
|
|
24
|
+
});
|
|
25
|
+
const ofKind = (kind: string) =>
|
|
26
|
+
[...loaded.corpus, ...(kind === "automation" ? fixture.corpus : [])].filter((e) => e.kind === kind && e.publishBody);
|
|
27
|
+
/** What the CP serves: the stored definition with `_meta.slug` stamped (`withTemplateSlug`). */
|
|
28
|
+
const served = (e: { slug: string; publishBody: { definition: Record<string, unknown> } }) => ({
|
|
29
|
+
...e.publishBody.definition,
|
|
30
|
+
_meta: { ...((e.publishBody.definition._meta as object | undefined) ?? {}), slug: e.slug },
|
|
31
|
+
});
|
|
32
|
+
const one = (kind: string, slug: string) => {
|
|
33
|
+
const e = ofKind(kind).find((x) => x.slug === slug);
|
|
34
|
+
if (!e) throw new Error(`catalog has no ${kind} "${slug}"`);
|
|
35
|
+
return e;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
describe("unwrapPackage — real producer output", () => {
|
|
39
|
+
it("non-vacuity: the catalog compiled entries of every kind", () => {
|
|
40
|
+
expect(ofKind("skill").length).toBeGreaterThanOrEqual(5);
|
|
41
|
+
expect(ofKind("capability").length).toBeGreaterThanOrEqual(20);
|
|
42
|
+
expect(ofKind("automation").length).toBeGreaterThanOrEqual(1);
|
|
43
|
+
expect(ofKind("workspace").length).toBeGreaterThanOrEqual(10);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("skill: creative-director's body arrives (read flat it is undefined — the 10-13 bug)", () => {
|
|
47
|
+
const e = one("skill", "creative-director");
|
|
48
|
+
const def = served(e);
|
|
49
|
+
const skill = unwrapPackage("skill", def);
|
|
50
|
+
expect(typeof skill.body).toBe("string");
|
|
51
|
+
expect((skill.body as string).length).toBeGreaterThan(200);
|
|
52
|
+
expect(skill.name).toBeTruthy();
|
|
53
|
+
expect(skill).toEqual(e.manifest.spec);
|
|
54
|
+
expect((def as { body?: unknown }).body).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("skill: every catalog skill unwraps to something the pod installs (body, code or providerSpec)", () => {
|
|
58
|
+
for (const e of ofKind("skill")) {
|
|
59
|
+
const s = unwrapPackage("skill", served(e));
|
|
60
|
+
expect(Boolean(s.body?.trim() || s.code?.trim() || s.providerSpec), e.slug).toBe(true);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("capability: every catalog capability unwraps to the capability, its key and skills intact", () => {
|
|
65
|
+
for (const e of ofKind("capability")) {
|
|
66
|
+
const cap = unwrapPackage("capability", served(e));
|
|
67
|
+
expect(cap.key, e.slug).toBe(e.slug);
|
|
68
|
+
expect(cap).toEqual(e.manifest.spec);
|
|
69
|
+
expect(Array.isArray(cap.skills) || Array.isArray(cap.playbooks) || Array.isArray(cap.tools), e.slug).toBe(true);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("automation: every catalog automation unwraps to its one flow, under either kind name", () => {
|
|
74
|
+
for (const e of ofKind("automation")) {
|
|
75
|
+
const autos = unwrapPackage("workflow", served(e));
|
|
76
|
+
expect(autos, e.slug).toHaveLength(1);
|
|
77
|
+
expect(autos).toEqual(toAutomationWire([e.manifest.spec as never]));
|
|
78
|
+
expect(autos[0]!.flowDefinition?.nodes.length, e.slug).toBeGreaterThan(0);
|
|
79
|
+
expect(unwrapPackage("automation", served(e))).toBe(autos);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("workspace: the served definition is the element, under workspace / template / pack", () => {
|
|
84
|
+
const e = one("workspace", "content-os");
|
|
85
|
+
const def = served(e);
|
|
86
|
+
expect(unwrapPackage("template", def)).toBe(def);
|
|
87
|
+
expect(unwrapPackage("workspace", def).workspaceName).toBeTruthy();
|
|
88
|
+
expect(unwrapPackage("pack", def).profiles.length).toBeGreaterThan(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("legacy flat definitions pass through", () => {
|
|
92
|
+
const skill = { name: "Flat", body: "# flat" };
|
|
93
|
+
expect(unwrapPackage("skill", skill)).toBe(skill);
|
|
94
|
+
const cap = one("capability", ofKind("capability")[0]!.slug).manifest.spec;
|
|
95
|
+
expect(unwrapPackage("capability", cap)).toBe(cap);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("view: views[], a legacy single view as [def], none as []", () => {
|
|
99
|
+
const a = { name: "A", type: "table" };
|
|
100
|
+
const b = { name: "B", type: "kanban" };
|
|
101
|
+
expect(unwrapPackage("view", { views: [a, b] })).toEqual([a, b]);
|
|
102
|
+
const flat = { name: "Flat", type: "list", config: {} };
|
|
103
|
+
expect(unwrapPackage("view", flat)).toEqual([flat]);
|
|
104
|
+
expect(unwrapPackage("view", { views: [] })).toEqual([]);
|
|
105
|
+
expect(unwrapPackage("automation", { profiles: [] })).toEqual([]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("a definition that is not an object is a failed read, not an empty one; an unknown kind is refused", () => {
|
|
109
|
+
expect(() => unwrapPackage("skill", null)).toThrow(/not an object/);
|
|
110
|
+
expect(() => unwrapPackage("automation", [] as unknown)).toThrow(/not an object/);
|
|
111
|
+
expect(() => unwrapPackage("cell" as never, {})).toThrow(/no wire contract/);
|
|
112
|
+
expect(toWireKind("template")).toBe("workspace");
|
|
113
|
+
expect(toWireKind("workflow")).toBe("automation");
|
|
114
|
+
expect(toWireKind("cell")).toBeNull();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("toWorkspaceInput — the served workspace → create input", () => {
|
|
119
|
+
/**
|
|
120
|
+
* Keys where it differs from `toWorkspaceDefinition` (the bundle path), with
|
|
121
|
+
* why. Pinned as EXACT equality: a new difference — or one closing — fails.
|
|
122
|
+
* - proposalId: the bundle uses `workspace.proposalId ?? <slug>-v1`; the
|
|
123
|
+
* served definition only has the slug.
|
|
124
|
+
* - taskIntents: NOT carried by the pod's cache path today (a real gap,
|
|
125
|
+
* reported by lane W5a; mirrored 1:1 here so the pod can swap).
|
|
126
|
+
* - capabilities / playbooks / actionPlacements: read off the PACKAGE
|
|
127
|
+
* definition by the post-workspace layer, not the create input.
|
|
128
|
+
*/
|
|
129
|
+
const EXPECTED_DIFFERENT = ["actionPlacements", "capabilities", "playbooks", "proposalId", "taskIntents"];
|
|
130
|
+
|
|
131
|
+
const slugs = Object.keys(WORKSPACE_TEMPLATES);
|
|
132
|
+
it("non-vacuity: the bundle has templates", () => expect(slugs.length).toBeGreaterThanOrEqual(10));
|
|
133
|
+
|
|
134
|
+
it("carries every other field exactly as the bundle path does, for every bundled template", () => {
|
|
135
|
+
const differing = new Set<string>();
|
|
136
|
+
const norm = (v: unknown) => JSON.parse(JSON.stringify(v ?? null));
|
|
137
|
+
for (const slug of slugs) {
|
|
138
|
+
const fromWire = toWorkspaceInput({ ...toPackageDefinition(slug), _meta: { slug } } as WorkspaceWire) as unknown as Record<string, unknown>;
|
|
139
|
+
const fromBundle = toWorkspaceDefinition(slug).definition as unknown as Record<string, unknown>;
|
|
140
|
+
for (const k of new Set([...Object.keys(fromWire), ...Object.keys(fromBundle)])) {
|
|
141
|
+
const a = norm(fromWire[k]);
|
|
142
|
+
const b = norm(fromBundle[k]);
|
|
143
|
+
const emptyEq = (x: unknown) => x === null || (Array.isArray(x) && x.length === 0);
|
|
144
|
+
if (JSON.stringify(a) !== JSON.stringify(b) && !(emptyEq(a) && emptyEq(b))) differing.add(k);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
expect([...differing].sort()).toEqual(EXPECTED_DIFFERENT);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("the two renames land: suggestedEntities → seedEntities, automations → flowAutomations", () => {
|
|
151
|
+
const slug = slugs.find((s) => (toPackageDefinition(s).automations?.length ?? 0) > 0)!;
|
|
152
|
+
const pd = toPackageDefinition(slug);
|
|
153
|
+
const input = toWorkspaceInput(pd);
|
|
154
|
+
expect(input.flowAutomations).toEqual(pd.automations);
|
|
155
|
+
expect(input.flowAutomations!.length).toBeGreaterThan(0);
|
|
156
|
+
expect(input.seedEntities).toBe(pd.suggestedEntities);
|
|
157
|
+
expect(input.proposalId).toBe(slug);
|
|
158
|
+
});
|
|
159
|
+
});
|
package/src/wire.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synap-core/workspace-templates/wire — ONE wire contract per package kind.
|
|
3
|
+
*
|
|
4
|
+
* The per-kind envelopes and `unwrapPackage` live in `./wire-core` (import-free,
|
|
5
|
+
* so it can be mirrored byte-for-byte by consumers still pinned to an older npm
|
|
6
|
+
* copy). This adds what needs the rest of the package: the workspace envelope,
|
|
7
|
+
* derived from `PackageDefinitionOutput` instead of re-declared, and the one
|
|
8
|
+
* workspace wire → create-input translation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PackageDefinitionOutput, WorkspaceDefinitionInput } from "./define";
|
|
12
|
+
import { unwrapPackage as unwrapCore, type ElementOf, type WireIdentity, type WireKindName, type WireMeta } from "./wire-core";
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
WIRE_KINDS,
|
|
16
|
+
WIRE_KIND_ALIASES,
|
|
17
|
+
toWireKind,
|
|
18
|
+
type WireKind,
|
|
19
|
+
type WireKindName,
|
|
20
|
+
type WireMeta,
|
|
21
|
+
type WireIdentity,
|
|
22
|
+
type WireDependency,
|
|
23
|
+
type WireEnvelope,
|
|
24
|
+
type CapabilityElement,
|
|
25
|
+
type CapabilityWire,
|
|
26
|
+
type SkillElement,
|
|
27
|
+
type SkillWire,
|
|
28
|
+
type AutomationElement,
|
|
29
|
+
type AutomationWire,
|
|
30
|
+
type ViewElement,
|
|
31
|
+
type ViewWire,
|
|
32
|
+
type PackageElementByKind,
|
|
33
|
+
} from "./wire-core";
|
|
34
|
+
import type { AutomationWire, CapabilityWire, SkillWire, ViewWire, WireKind } from "./wire-core";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* workspace / pack: `toPackageDefinition()` output — re-used, not re-declared.
|
|
38
|
+
* As served it is `toOfficialPublishBody().definition` (identity mirrored on
|
|
39
|
+
* top, `sourcePackage`) with `_meta` cut down to what the CP stamps; a bundled
|
|
40
|
+
* `PackageDefinitionOutput` is assignable to it as is.
|
|
41
|
+
*/
|
|
42
|
+
export type WorkspaceWire = Omit<PackageDefinitionOutput, "_meta"> &
|
|
43
|
+
WireIdentity & {
|
|
44
|
+
_meta?: Partial<PackageDefinitionOutput["_meta"]> & WireMeta;
|
|
45
|
+
/** Which build of this package generated the row (official rows only). */
|
|
46
|
+
sourcePackage?: { name: string; version: string };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** The served definition, keyed by kind. */
|
|
50
|
+
export interface PackageWireByKind {
|
|
51
|
+
workspace: WorkspaceWire;
|
|
52
|
+
capability: CapabilityWire;
|
|
53
|
+
skill: SkillWire;
|
|
54
|
+
automation: AutomationWire;
|
|
55
|
+
view: ViewWire;
|
|
56
|
+
}
|
|
57
|
+
export type PackageWire = PackageWireByKind[WireKind];
|
|
58
|
+
|
|
59
|
+
/** `./wire-core`'s `unwrapPackage`, with the workspace element typed as {@link WorkspaceWire}. */
|
|
60
|
+
export function unwrapPackage<K extends WireKindName>(kind: K, definition: unknown): ElementOf<K, WorkspaceWire> {
|
|
61
|
+
return unwrapCore(kind, definition) as ElementOf<K, WorkspaceWire>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The served workspace definition → the input the pod's create/reconcile door
|
|
66
|
+
* takes (`WorkspaceDefinitionInput`). The two renames live here and only here:
|
|
67
|
+
* `suggestedEntities` → `seedEntities` and `automations` (graph flows) →
|
|
68
|
+
* `flowAutomations`.
|
|
69
|
+
*
|
|
70
|
+
* A 1:1 copy of the pod's `toWorkspaceDefinitionInput`
|
|
71
|
+
* (synap-backend `services/capabilities/resolve-workspace-template.ts`), so the
|
|
72
|
+
* pod can import this instead. Like it, it does NOT carry `taskIntents`,
|
|
73
|
+
* `capabilities`, `playbooks`, `actionPlacements`, `rules` or `skills`: the
|
|
74
|
+
* post-workspace layer reads the last five off the package definition itself;
|
|
75
|
+
* `taskIntents` is a gap on that path today. `wire.test.ts` pins every
|
|
76
|
+
* difference from `toWorkspaceDefinition`.
|
|
77
|
+
*/
|
|
78
|
+
export function toWorkspaceInput(pkg: WorkspaceWire): WorkspaceDefinitionInput {
|
|
79
|
+
return {
|
|
80
|
+
workspaceName: pkg.workspaceName,
|
|
81
|
+
description: pkg.description,
|
|
82
|
+
proposalId: pkg._meta?.slug,
|
|
83
|
+
profiles: pkg.profiles,
|
|
84
|
+
views: pkg.views ?? [],
|
|
85
|
+
entityLinks: pkg.entityLinks ?? [],
|
|
86
|
+
seedEntities: pkg.suggestedEntities ?? [],
|
|
87
|
+
suggestedRelations: pkg.suggestedRelations,
|
|
88
|
+
displayTemplates: pkg.displayTemplates,
|
|
89
|
+
layoutConfig: pkg.layoutConfig,
|
|
90
|
+
bentoViewName: pkg.bentoViewName,
|
|
91
|
+
bentoLayout: pkg.bentoLayout,
|
|
92
|
+
bentoViewBlocks: pkg.bentoViewBlocks,
|
|
93
|
+
profileEntityBentoTemplates: pkg.profileEntityBentoTemplates,
|
|
94
|
+
workspaceSubtype: pkg.workspaceSubtype,
|
|
95
|
+
workspaceType: pkg.workspaceType,
|
|
96
|
+
workspaceVisibility: pkg.workspaceVisibility,
|
|
97
|
+
workspaceCapabilities: pkg.workspaceCapabilities,
|
|
98
|
+
intent: pkg.intent,
|
|
99
|
+
sourceRoles: pkg.sourceRoles,
|
|
100
|
+
defaultSources: pkg.defaultSources,
|
|
101
|
+
onboarding: pkg.onboarding,
|
|
102
|
+
dependencies: pkg.dependencies,
|
|
103
|
+
flowAutomations: pkg.automations ?? [],
|
|
104
|
+
commands: pkg.commands ?? [],
|
|
105
|
+
relationDefs: pkg.relationDefs ?? [],
|
|
106
|
+
};
|
|
107
|
+
}
|