@uniqbit/mate-core 0.18.4 → 1.0.0-canary.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/claude-plugin/hooks/companion-instructions.mjs +9 -0
- package/claude-plugin/hooks/hooks.json +12 -2
- package/opencode-plugin/src/add-dir.ts +76 -10
- package/opencode-plugin/src/companion.ts +1 -8
- package/opencode-plugin/src/server.ts +2 -15
- package/package.json +10 -2
- package/src/brand/art.generated.ts +69 -0
- package/src/brand/index.ts +12 -0
- package/src/brand/palette.ts +19 -0
- package/src/brand/svg.generated.ts +8 -0
- package/src/brand/terminal.ts +83 -0
- package/src/brand/types.ts +33 -0
- package/src/cli/commands/artifact/artifact.ts +8 -0
- package/src/cli/commands/artifact/delivery/archive.ts +117 -0
- package/src/cli/commands/artifact/delivery/branch-flags.ts +55 -0
- package/src/cli/commands/artifact/delivery/environment.ts +104 -0
- package/src/cli/commands/artifact/delivery/link.ts +154 -0
- package/src/cli/commands/artifact/delivery/output.ts +58 -0
- package/src/cli/commands/artifact/finish/command.ts +33 -3
- package/src/cli/commands/artifact/finish/engine.ts +47 -3
- package/src/cli/commands/artifact/finish/finisher.ts +10 -0
- package/src/cli/commands/artifact/finish/openspec.ts +200 -129
- package/src/cli/commands/artifact/finish/secret-scan.ts +43 -0
- package/src/cli/commands/artifact/pending/command.ts +31 -3
- package/src/cli/commands/artifact/pending/discovery.ts +21 -57
- package/src/cli/commands/cap/graphify.ts +52 -3
- package/src/cli/commands/cap/index-cmd.ts +8 -1
- package/src/cli/commands/cap/openspec.ts +13 -25
- package/src/cli/commands/companion/open.ts +56 -39
- package/src/cli/commands/companion/update.ts +75 -42
- package/src/cli/commands/doctor.ts +257 -78
- package/src/cli/commands/install.ts +0 -8
- package/src/cli/commands/plugin/install.ts +9 -4
- package/src/cli/commands/plugin/plugin.ts +3 -2
- package/src/cli/commands/report/adapter.ts +11 -2
- package/src/cli/commands/report/contract.ts +21 -0
- package/src/cli/commands/report/highlight.ts +34 -4
- package/src/cli/commands/report/markdown.ts +110 -0
- package/src/cli/commands/report/palette.ts +118 -0
- package/src/cli/commands/report/renderer.ts +456 -153
- package/src/cli/commands/report/types.ts +16 -0
- package/src/cli/commands/setup.ts +7 -15
- package/src/cli/commands/studio/client-asset.ts +16 -0
- package/src/cli/commands/studio/openspec-cli.ts +10 -58
- package/src/cli/commands/studio/routes.ts +2 -0
- package/src/cli/commands/studio/selection.ts +19 -1
- package/src/cli/commands/studio/server.ts +42 -1
- package/src/cli/commands/studio/terminal-launch.ts +7 -16
- package/src/cli/commands/studio/views/client.ts +6 -616
- package/src/cli/commands/studio/views/dashboard/changes.tsx +5 -10
- package/src/cli/commands/studio/views/document.tsx +137 -69
- package/src/cli/commands/studio/views/markdown.tsx +250 -0
- package/src/cli/commands/studio/views/palette.ts +134 -0
- package/src/cli/commands/studio/views/reports/index.tsx +2 -7
- package/src/cli/commands/studio/views/skills/index.tsx +43 -62
- package/src/cli/commands/studio/views/specs/index.tsx +7 -15
- package/src/cli/commands/studio/views/studio-client/actions.ts +51 -0
- package/src/cli/commands/studio/views/studio-client/companion.ts +13 -0
- package/src/cli/commands/studio/views/studio-client/index.ts +32 -0
- package/src/cli/commands/studio/views/studio-client/keys.ts +3 -0
- package/src/cli/commands/studio/views/studio-client/main.ts +3 -0
- package/src/cli/commands/studio/views/studio-client/page.ts +146 -0
- package/src/cli/commands/studio/views/studio-client/panels.ts +57 -0
- package/src/cli/commands/studio/views/studio-client/reports.ts +122 -0
- package/src/cli/commands/studio/views/studio-client/theme.ts +63 -0
- package/src/cli/commands/studio/views/studio-client/vault-editor.ts +166 -0
- package/src/cli/commands/studio/views/studio-client/vault-pane.ts +202 -0
- package/src/cli/commands/studio/views/studio-client/vault-tree.ts +258 -0
- package/src/cli/commands/studio/views/studio-client.generated.ts +2 -0
- package/src/cli/commands/studio/views/styles.ts +217 -206
- package/src/cli/commands/studio/views/vault/state.ts +3 -5
- package/src/cli/commands/studio/views/workflow/delivery-path.tsx +370 -0
- package/src/cli/commands/studio/views/workflow/graph.ts +220 -0
- package/src/cli/commands/studio/views/workflow/index.tsx +2 -3
- package/src/cli/commands/studio/views/workflow/steps.ts +228 -287
- package/src/cli/commands/wrap.ts +9 -42
- package/src/cli/main.ts +4 -1
- package/src/cli/parse-flags.ts +25 -7
- package/src/cli/setup-selector.tsx +38 -162
- package/src/cli/usage.ts +5 -2
- package/src/hooks/companion-instructions.ts +190 -0
- package/src/hooks/hook-io.ts +63 -0
- package/src/hooks/session-banner.ts +21 -29
- package/src/hooks/session-guidance.ts +10 -36
- package/src/hooks/session-prepare.ts +115 -28
- package/src/hooks/validate-artifact-path.ts +82 -24
- package/src/index.ts +4 -0
- package/src/lib/change-layout.ts +154 -0
- package/src/lib/components/wizard-header.tsx +3 -1
- package/src/lib/context-mode-package.ts +24 -11
- package/src/lib/delivery/archive-change.ts +154 -0
- package/src/lib/delivery/branches.ts +108 -0
- package/src/lib/delivery/environment.ts +29 -0
- package/src/lib/delivery/forge.ts +279 -0
- package/src/lib/delivery/overlap.ts +202 -0
- package/src/lib/delivery/record-delivery.ts +196 -0
- package/src/lib/delivery/record.ts +343 -0
- package/src/lib/delivery/refresh.ts +174 -0
- package/src/lib/delivery/repository-access.ts +97 -0
- package/src/lib/delivery/stages.ts +111 -0
- package/src/lib/delivery/token.ts +58 -0
- package/src/lib/frontmatter.ts +18 -0
- package/src/lib/opencode-plugin-package.ts +5 -5
- package/src/lib/openspec-cli.ts +116 -0
- package/src/lib/openspec-scopes.ts +86 -0
- package/src/lib/orchestrator/adapters/claude-args.ts +50 -0
- package/src/lib/orchestrator/adapters/claude.ts +60 -162
- package/src/lib/orchestrator/adapters/opencode.ts +9 -24
- package/src/lib/orchestrator/config-store.ts +2 -70
- package/src/lib/orchestrator/editor.ts +9 -9
- package/src/lib/orchestrator/openspec-store.ts +14 -54
- package/src/lib/orchestrator/projection-claude-commands.ts +36 -0
- package/src/lib/orchestrator/projection-claude-links.ts +159 -0
- package/src/lib/orchestrator/projection-claude-skills.ts +19 -190
- package/src/lib/orchestrator/projection-entries.ts +45 -15
- package/src/lib/orchestrator/projection-runtime-documents.ts +15 -6
- package/src/lib/orchestrator/projection-types.ts +3 -2
- package/src/lib/orchestrator/refresh-working-claude-links.ts +87 -0
- package/src/lib/orchestrator/session-prepare.ts +49 -87
- package/src/lib/orchestrator/setup-compatibilities.ts +18 -75
- package/src/lib/orchestrator/types.ts +2 -2
- package/src/lib/orchestrator/wrap-pass.ts +22 -88
- package/src/lib/package-paths.ts +8 -0
- package/src/opencode/companion-hooks.ts +64 -5
- package/src/opencode/companion-policy.ts +37 -18
- package/src/opencode/projected-guidance.ts +4 -1
- package/src/opencode/session-prepare.ts +2 -1
- package/src/opencode/tui.tsx +4 -2
- package/src/runtime/artifact-refusal.ts +63 -0
- package/src/runtime/claude-delivery-plan.ts +89 -7
- package/src/runtime/commit-attribution-guard.ts +181 -0
- package/src/runtime/companion-guidance.ts +15 -3
- package/src/runtime/companion-instructions.ts +340 -0
- package/src/runtime/error-message.ts +4 -0
- package/src/runtime/guidance.ts +0 -17
- package/src/runtime/index.ts +5 -0
- package/src/runtime/managed-block.ts +117 -0
- package/src/runtime/markdown-scan.ts +266 -0
- package/src/runtime/policy.ts +16 -15
- package/src/runtime/projected-flag.ts +7 -0
- package/src/runtime/projected-guidance.ts +1 -0
- package/src/runtime/runtime-document-manifest.ts +62 -28
- package/src/runtime/secret-guard.ts +148 -0
- package/src/runtime/secret-patterns.ts +164 -0
- package/src/runtime/secret-scan.ts +90 -0
- package/src/runtime/session-kind.ts +13 -0
- package/src/runtime/shell-heredoc.ts +81 -0
- package/src/runtime/wrap-state.ts +36 -6
- package/src/runtime/write-atomic.ts +64 -0
- package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +8 -6
- package/src/templates/capabilities/openspec-cap/mate-minimal/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/mate-v1/schema.yaml +7 -9
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/openspec-conventions.yaml +10 -12
- package/src/templates/mate-skills/THIRD-PARTY-NOTICES.md +40 -0
- package/src/templates/mate-skills/agents/mate-apply-change/SKILL.md +76 -0
- package/src/templates/mate-skills/agents/mate-apply-change/references/openspec-apply-change.md +198 -0
- package/src/templates/mate-skills/agents/mate-archive-change/SKILL.md +59 -0
- package/src/templates/mate-skills/{claude/mate-openspec-backfill → agents/mate-backfill-spec}/SKILL.md +4 -4
- package/src/templates/mate-skills/agents/mate-clarify-intent/SKILL.md +95 -0
- package/src/templates/mate-skills/agents/mate-explore-change/SKILL.md +50 -0
- package/src/templates/mate-skills/agents/mate-explore-change/references/openspec-explore.md +348 -0
- package/src/templates/mate-skills/agents/mate-grill-me/SKILL.md +3 -3
- package/src/templates/mate-skills/agents/mate-interview-me/SKILL.md +5 -5
- package/src/templates/mate-skills/agents/mate-propose-change/SKILL.md +103 -0
- package/src/templates/mate-skills/agents/mate-propose-change/references/openspec-propose.md +167 -0
- package/src/templates/mate-skills/agents/mate-propose-change/references/openspec-update-change.md +101 -0
- package/src/templates/mate-skills/agents/{mate-artifact-publish → mate-publish-artifact}/SKILL.md +91 -23
- package/src/templates/mate-skills/agents/{mate-artifact-publish → mate-publish-artifact}/references/openspec.md +4 -3
- package/src/templates/mate-skills/agents/mate-show-me/SKILL.md +74 -16
- package/src/templates/mate-skills/agents/mate-simplify-code/SKILL.md +74 -68
- package/src/templates/mate-skills/claude/mate-apply-change/SKILL.md +76 -0
- package/src/templates/mate-skills/claude/mate-apply-change/references/openspec-apply-change.md +198 -0
- package/src/templates/mate-skills/claude/mate-archive-change/SKILL.md +59 -0
- package/src/templates/mate-skills/{agents/mate-openspec-backfill → claude/mate-backfill-spec}/SKILL.md +4 -4
- package/src/templates/mate-skills/claude/mate-clarify-intent/SKILL.md +95 -0
- package/src/templates/mate-skills/claude/mate-explore-change/SKILL.md +50 -0
- package/src/templates/mate-skills/claude/mate-explore-change/references/openspec-explore.md +348 -0
- package/src/templates/mate-skills/claude/mate-grill-me/SKILL.md +3 -3
- package/src/templates/mate-skills/claude/mate-interview-me/SKILL.md +5 -5
- package/src/templates/mate-skills/claude/mate-propose-change/SKILL.md +103 -0
- package/src/templates/mate-skills/claude/mate-propose-change/references/openspec-propose.md +167 -0
- package/src/templates/mate-skills/claude/mate-propose-change/references/openspec-update-change.md +101 -0
- package/src/templates/mate-skills/claude/{mate-artifact-publish → mate-publish-artifact}/SKILL.md +91 -23
- package/src/templates/mate-skills/claude/{mate-artifact-publish → mate-publish-artifact}/references/openspec.md +4 -3
- package/src/templates/mate-skills/claude/mate-show-me/SKILL.md +74 -16
- package/src/templates/mate-skills/claude/mate-simplify-code/SKILL.md +74 -68
- package/src/templates/mate-skills/openspec-references.ts +140 -0
- package/src/templates/root/TEMPLATE_AGENTS.md +2 -2
- package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +3727 -320
- package/src/tools/setup/capabilities/context-mode.ts +25 -5
- package/src/tools/setup/capabilities/graphify-gate.ts +31 -0
- package/src/tools/setup/capabilities/graphify-secrets.ts +255 -0
- package/src/tools/setup/capabilities/graphify.ts +12 -0
- package/src/tools/setup/capabilities/openspec.ts +273 -270
- package/src/tools/setup/capabilities/tokensave.ts +36 -3
- package/src/tools/setup/context-services.ts +9 -17
- package/src/tools/setup/dynamic-plugins/audiences.ts +7 -39
- package/src/tools/setup/dynamic-plugins/declarations.ts +1 -1
- package/src/tools/setup/dynamic-plugins/hydrate.ts +4 -7
- package/src/tools/setup/dynamic-plugins/install.ts +24 -28
- package/src/tools/setup/engine.ts +93 -148
- package/src/tools/setup/managed-output.ts +51 -0
- package/src/tools/setup/mate.ts +86 -11
- package/src/tools/setup/plugin.ts +37 -17
- package/src/tools/setup/plugins/gitignore.ts +1 -7
- package/src/tools/setup/plugins/guidance.ts +7 -4
- package/src/tools/setup/providers/agent-file-sections.ts +4 -2
- package/src/tools/setup/providers/claude-attribution.ts +65 -0
- package/src/tools/setup/providers/claude-plugin-folders.ts +625 -0
- package/src/tools/setup/providers/claude-plugin-hooks.ts +39 -19
- package/src/tools/setup/providers/claude.ts +285 -34
- package/src/tools/setup/providers/opencode.ts +180 -11
- package/src/tools/setup/registry.ts +2 -24
- package/src/tools/setup/surface-target.ts +4 -13
- package/src/tools/setup/utils.ts +14 -4
- package/src/tools/setup.ts +131 -18
- package/wrappers/bin/graphify +52 -4
- package/wrappers/bin/openspec +33 -9
- package/wrappers/lib/graphify-gate.mjs +8 -0
- package/opencode-plugin/src/audience-layer.ts +0 -91
- package/src/cli/commands/studio/views/workflow/transcript.tsx +0 -190
- package/src/runtime/audience-layer.ts +0 -84
- package/src/runtime/opencode-audience-layer.ts +0 -176
- package/src/tools/setup/audience-isolation.fixture.ts +0 -325
- package/src/tools/setup/audience-layer.ts +0 -207
- package/src/tools/setup/audience-registrations.ts +0 -52
- package/src/tools/setup/contribution-ledger.ts +0 -207
- package/src/tools/setup/isolation-diagnostics.ts +0 -139
- package/src/tools/setup/runtime-documents.ts +0 -291
- package/src/tools/setup/upgrade-sweep.ts +0 -153
|
@@ -2,28 +2,29 @@
|
|
|
2
2
|
import { getActiveDistribution } from "../../distribution";
|
|
3
3
|
import { FRAMEWORK_NAME } from "../../framework";
|
|
4
4
|
import type { FrameworkConfig } from "../../lib/orchestrator/types";
|
|
5
|
-
import
|
|
5
|
+
import { getClaudePluginRoot } from "../../lib/package-paths";
|
|
6
|
+
import type { RenderedRuntimeDocuments } from "../../runtime/runtime-document-manifest";
|
|
6
7
|
import { collectHostingProviders, ContextServiceMediator } from "./context-services";
|
|
7
|
-
import {
|
|
8
|
-
ledgerFromInputs,
|
|
9
|
-
ledgerTeardownInput,
|
|
10
|
-
readContributionLedger,
|
|
11
|
-
writeContributionLedger,
|
|
12
|
-
type ContributionLedger,
|
|
13
|
-
} from "./contribution-ledger";
|
|
14
8
|
import type {
|
|
15
9
|
CapabilityContributionInput,
|
|
16
10
|
CapabilityPlugin,
|
|
17
11
|
Plugin,
|
|
18
12
|
PluginRegistration,
|
|
13
|
+
RuntimeContributionsByRuntime,
|
|
19
14
|
SetupContext,
|
|
20
15
|
} from "./plugin";
|
|
21
|
-
import { reconcileClaudeContributions } from "./providers/claude";
|
|
22
|
-
import {
|
|
23
|
-
|
|
16
|
+
import { reconcileClaudeContributions, renderClaudeWorkingDocuments } from "./providers/claude";
|
|
17
|
+
import {
|
|
18
|
+
inspectClaudePluginFolders,
|
|
19
|
+
publishClaudePluginFolders,
|
|
20
|
+
type ClaudePluginFolders,
|
|
21
|
+
} from "./providers/claude-plugin-folders";
|
|
22
|
+
import {
|
|
23
|
+
reconcileOpenCodeContributions,
|
|
24
|
+
renderOpenCodeWorkingDocuments,
|
|
25
|
+
} from "./providers/opencode";
|
|
24
26
|
import { normalizeRegistration, type NormalizedRegistration } from "./registry";
|
|
25
|
-
import {
|
|
26
|
-
import { removeForeignGuidanceBlocks, sweepAudienceDeclarations } from "./upgrade-sweep";
|
|
27
|
+
import { projectionRepoRoot } from "./surface-target";
|
|
27
28
|
|
|
28
29
|
export interface SetupInstallationPlanAction {
|
|
29
30
|
phase: Plugin["kind"];
|
|
@@ -42,25 +43,18 @@ export interface SetupInstallationOutcome {
|
|
|
42
43
|
executedActions: SetupInstallationPlanAction[];
|
|
43
44
|
skippedActions: SetupInstallationPlanAction[];
|
|
44
45
|
warnings: string[];
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* its lifecycle hooks nor its declared contributions — whatever audience is
|
|
51
|
-
* active; its contributions reach sessions only through the launch layer.
|
|
52
|
-
*/
|
|
53
|
-
export function persistedRegistrations(
|
|
54
|
-
registrations: PluginRegistration[],
|
|
55
|
-
): NormalizedRegistration[] {
|
|
56
|
-
return registrations.map(normalizeRegistration).filter((entry) => entry.audience === null);
|
|
46
|
+
/**
|
|
47
|
+
* Enabled Capabilities' Claude plugin folders, published outside a hub (a hub
|
|
48
|
+
* has no wrap for plain sessions to load them through); never printed here.
|
|
49
|
+
*/
|
|
50
|
+
claudePluginFolders: ClaudePluginFolders;
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
export function buildSetupInstallationPlan(
|
|
60
54
|
config: FrameworkConfig,
|
|
61
55
|
registrations: PluginRegistration[],
|
|
62
56
|
): SetupInstallationPlan {
|
|
63
|
-
const entries =
|
|
57
|
+
const entries = registrations.map(normalizeRegistration);
|
|
64
58
|
// Required plugins are always treated as enabled: saved selections cannot
|
|
65
59
|
// deselect them and deselection never produces a teardown action.
|
|
66
60
|
const isEntryEnabled = (entry: NormalizedRegistration) =>
|
|
@@ -130,7 +124,7 @@ export async function executeSetupInstallationPlan(
|
|
|
130
124
|
registrations: PluginRegistration[],
|
|
131
125
|
plan: SetupInstallationPlan,
|
|
132
126
|
): Promise<SetupInstallationOutcome> {
|
|
133
|
-
const plugins =
|
|
127
|
+
const plugins = registrations.map((entry) => normalizeRegistration(entry).plugin);
|
|
134
128
|
const pluginById = new Map(plugins.map((plugin) => [plugin.id, plugin]));
|
|
135
129
|
const executedActions: SetupInstallationPlanAction[] = [];
|
|
136
130
|
const skippedActions: SetupInstallationPlanAction[] = [];
|
|
@@ -197,22 +191,19 @@ export async function executeSetupInstallationPlan(
|
|
|
197
191
|
|
|
198
192
|
await mediator.finalize();
|
|
199
193
|
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
warnings.push(warning);
|
|
208
|
-
process.stderr.write(`${warning}\n`);
|
|
209
|
-
}
|
|
194
|
+
const inputsByRuntime = await reconcileCapabilityContributions(ctx, plugins, plan);
|
|
195
|
+
const claudeInputs = inputsByRuntime.get("claude") ?? [];
|
|
196
|
+
const folderOptions = { bundledPluginRoot: getClaudePluginRoot() };
|
|
197
|
+
const claudePluginFolders =
|
|
198
|
+
ctx.scope === "hub"
|
|
199
|
+
? await inspectClaudePluginFolders(claudeInputs, folderOptions)
|
|
200
|
+
: await publishClaudePluginFolders(claudeInputs, folderOptions);
|
|
210
201
|
|
|
211
|
-
return { executedActions, skippedActions, warnings };
|
|
202
|
+
return { executedActions, skippedActions, warnings, claudePluginFolders };
|
|
212
203
|
}
|
|
213
204
|
|
|
214
205
|
// The Runtime Surface of each active Agent Runtime, by runtime id.
|
|
215
|
-
|
|
206
|
+
const RUNTIME_SURFACE_RECONCILERS: Record<
|
|
216
207
|
string,
|
|
217
208
|
(ctx: SetupContext, inputs: CapabilityContributionInput[]) => Promise<void>
|
|
218
209
|
> = {
|
|
@@ -220,6 +211,18 @@ export const RUNTIME_SURFACE_RECONCILERS: Record<
|
|
|
220
211
|
opencode: reconcileOpenCodeContributions,
|
|
221
212
|
};
|
|
222
213
|
|
|
214
|
+
/**
|
|
215
|
+
* The working-target render of each Runtime Surface, by runtime id, in the
|
|
216
|
+
* order its documents are rendered.
|
|
217
|
+
*/
|
|
218
|
+
const RUNTIME_SURFACE_WORKING_RENDERERS: Record<
|
|
219
|
+
string,
|
|
220
|
+
(ctx: SetupContext, inputs: CapabilityContributionInput[]) => Promise<RenderedRuntimeDocuments>
|
|
221
|
+
> = {
|
|
222
|
+
claude: renderClaudeWorkingDocuments,
|
|
223
|
+
opencode: renderOpenCodeWorkingDocuments,
|
|
224
|
+
};
|
|
225
|
+
|
|
223
226
|
/**
|
|
224
227
|
* The declared Capability contributions of one pass, keyed by runtime. Shared
|
|
225
228
|
* by both targets: what a companion pass writes is what a working pass renders.
|
|
@@ -228,6 +231,7 @@ async function collectContributionInputs(
|
|
|
228
231
|
ctx: SetupContext,
|
|
229
232
|
plugins: Plugin[],
|
|
230
233
|
plan: SetupInstallationPlan,
|
|
234
|
+
onContributionError?: ContributionErrorHandler,
|
|
231
235
|
): Promise<Map<string, CapabilityContributionInput[]>> {
|
|
232
236
|
// The plan already resolved enablement (policy, saved selection, package
|
|
233
237
|
// manager requirements); mirror it instead of recomputing.
|
|
@@ -243,7 +247,14 @@ async function collectContributionInputs(
|
|
|
243
247
|
const capability = plugin as CapabilityPlugin;
|
|
244
248
|
if (!capability.getRuntimeContributions) continue;
|
|
245
249
|
const enabled = enabledByPluginId.get(capability.id) ?? false;
|
|
246
|
-
|
|
250
|
+
let byRuntime: RuntimeContributionsByRuntime;
|
|
251
|
+
try {
|
|
252
|
+
byRuntime = await capability.getRuntimeContributions(ctx);
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (!onContributionError) throw error;
|
|
255
|
+
onContributionError(capability.id, error);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
247
258
|
for (const [runtimeId, contributions] of Object.entries(byRuntime)) {
|
|
248
259
|
if (!contributions) continue;
|
|
249
260
|
// Inactive runtimes still reconcile — with everything disabled — so a
|
|
@@ -267,143 +278,77 @@ async function collectContributionInputs(
|
|
|
267
278
|
* Reconcile declared Capability contributions through every active runtime's
|
|
268
279
|
* Runtime Surface (spec: plugin-engine). Runs after all plugin phases, so
|
|
269
280
|
* providers are always done first. Disabled capabilities participate with
|
|
270
|
-
* `enabled: false` and drive teardown of their managed entries.
|
|
281
|
+
* `enabled: false` and drive teardown of their managed entries. Returns the
|
|
282
|
+
* inputs it reconciled, so the pass derives launch-only data from the same ones.
|
|
271
283
|
*/
|
|
272
284
|
async function reconcileCapabilityContributions(
|
|
273
285
|
ctx: SetupContext,
|
|
274
286
|
plugins: Plugin[],
|
|
275
287
|
plan: SetupInstallationPlan,
|
|
276
|
-
|
|
277
|
-
): Promise<string[]> {
|
|
288
|
+
): Promise<Map<string, CapabilityContributionInput[]>> {
|
|
278
289
|
const inputsByRuntime = await collectContributionInputs(ctx, plugins, plan);
|
|
279
|
-
const ledgerRoot = surfaceRoot(ctx);
|
|
280
|
-
const ledger = await readContributionLedger(ledgerRoot);
|
|
281
|
-
const warnings: string[] = [];
|
|
282
|
-
let unswept = ledger?.unswept ?? [];
|
|
283
|
-
if (!ledger || unswept.length > 0) {
|
|
284
|
-
if (!ledger) {
|
|
285
|
-
await removeForeignGuidanceBlocks(ledgerRoot, new Set(plugins.map((plugin) => plugin.id)));
|
|
286
|
-
}
|
|
287
|
-
const sweep = await sweepAudienceDeclarations(ctx, {
|
|
288
|
-
registrations,
|
|
289
|
-
...(ledger ? { packages: new Set(unswept) } : {}),
|
|
290
|
-
});
|
|
291
|
-
prependTeardown(inputsByRuntime, sweep.teardown);
|
|
292
|
-
unswept = sweep.unswept;
|
|
293
|
-
warnings.push(...sweep.warnings);
|
|
294
|
-
}
|
|
295
|
-
prependLedgerTeardown(inputsByRuntime, ledger);
|
|
296
290
|
for (const [runtimeId, inputs] of inputsByRuntime) {
|
|
297
291
|
const reconcile = RUNTIME_SURFACE_RECONCILERS[runtimeId];
|
|
298
292
|
if (!reconcile || inputs.length === 0) continue;
|
|
299
293
|
await reconcile(ctx, inputs);
|
|
300
294
|
}
|
|
301
|
-
|
|
302
|
-
return warnings;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Disabled inputs placed first, skipping any owner that is an enabled input
|
|
307
|
-
* of the pass on that runtime: removal runs before enabled inputs apply.
|
|
308
|
-
*/
|
|
309
|
-
function prependTeardown(
|
|
310
|
-
inputsByRuntime: Map<string, CapabilityContributionInput[]>,
|
|
311
|
-
teardownByRuntime: ReadonlyMap<string, readonly CapabilityContributionInput[]>,
|
|
312
|
-
): void {
|
|
313
|
-
for (const [runtimeId, teardown] of teardownByRuntime) {
|
|
314
|
-
const inputs = inputsByRuntime.get(runtimeId) ?? [];
|
|
315
|
-
const enabled = new Set(inputs.filter((input) => input.enabled).map((input) => input.pluginId));
|
|
316
|
-
const kept = teardown.filter((input) => !enabled.has(input.pluginId));
|
|
317
|
-
if (kept.length > 0) inputsByRuntime.set(runtimeId, [...kept, ...inputs]);
|
|
318
|
-
}
|
|
295
|
+
return inputsByRuntime;
|
|
319
296
|
}
|
|
320
297
|
|
|
321
|
-
/**
|
|
322
|
-
|
|
323
|
-
* disabled input placed first: its entries are removed before enabled inputs
|
|
324
|
-
* apply, so an identity another plugin still declares is re-applied after.
|
|
325
|
-
* Entries the ledger does not record are never named, so they survive.
|
|
326
|
-
*/
|
|
327
|
-
function prependLedgerTeardown(
|
|
328
|
-
inputsByRuntime: Map<string, CapabilityContributionInput[]>,
|
|
329
|
-
ledger: ContributionLedger | null,
|
|
330
|
-
): void {
|
|
331
|
-
prependTeardown(
|
|
332
|
-
inputsByRuntime,
|
|
333
|
-
new Map(
|
|
334
|
-
Object.entries(ledger?.runtimes ?? {}).map(([runtimeId, owners]) => [
|
|
335
|
-
runtimeId,
|
|
336
|
-
Object.entries(owners).map(([owner, identities]) => ledgerTeardownInput(owner, identities)),
|
|
337
|
-
]),
|
|
338
|
-
),
|
|
339
|
-
);
|
|
340
|
-
}
|
|
298
|
+
/** Receives one Capability's rejected contributions; that Capability then contributes nothing. */
|
|
299
|
+
export type ContributionErrorHandler = (capabilityId: string, error: unknown) => void;
|
|
341
300
|
|
|
342
301
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
* dropped — the Mate plugin has no way to load another plugin.
|
|
302
|
+
* One pass's declared Capability contributions by runtime, collected without a
|
|
303
|
+
* reconcile. A rejecting Capability fails the collection unless
|
|
304
|
+
* `onContributionError` takes its error; only diagnostics should pass one.
|
|
347
305
|
*/
|
|
348
|
-
export async function
|
|
306
|
+
export async function collectRuntimeContributionInputs(
|
|
349
307
|
ctx: SetupContext,
|
|
350
308
|
registrations: PluginRegistration[],
|
|
351
|
-
|
|
309
|
+
plan: SetupInstallationPlan,
|
|
310
|
+
onContributionError?: ContributionErrorHandler,
|
|
352
311
|
): Promise<Map<string, CapabilityContributionInput[]>> {
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
if (entry.audience !== audience || entry.plugin.kind !== "capability") continue;
|
|
356
|
-
const capability = entry.plugin as CapabilityPlugin;
|
|
357
|
-
if (!capability.getRuntimeContributions) continue;
|
|
358
|
-
if (entry.policy !== "required" && !capability.isEnabled(ctx.config)) continue;
|
|
359
|
-
const byRuntime = await capability.getRuntimeContributions(ctx);
|
|
360
|
-
for (const [runtimeId, contributions] of Object.entries(byRuntime)) {
|
|
361
|
-
if (!contributions || !ctx.activeProviders.includes(runtimeId)) continue;
|
|
362
|
-
const { pluginReferences: _dropped, ...declarative } = contributions;
|
|
363
|
-
const inputs = inputsByRuntime.get(runtimeId) ?? [];
|
|
364
|
-
inputs.push({
|
|
365
|
-
pluginId: capability.id,
|
|
366
|
-
enabled: true,
|
|
367
|
-
capabilityEnabled: true,
|
|
368
|
-
contributions: declarative,
|
|
369
|
-
});
|
|
370
|
-
inputsByRuntime.set(runtimeId, inputs);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return inputsByRuntime;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/** What a render returns: its warnings are data for the caller, never printed here. */
|
|
377
|
-
export interface RenderedRuntimeDocuments {
|
|
378
|
-
documents: RenderedRuntimeDocument[];
|
|
379
|
-
warnings: string[];
|
|
312
|
+
const plugins = registrations.map((entry) => normalizeRegistration(entry).plugin);
|
|
313
|
+
return collectContributionInputs(ctx, plugins, plan, onContributionError);
|
|
380
314
|
}
|
|
381
315
|
|
|
382
316
|
/**
|
|
383
317
|
* The same declarations, rendered rather than written: a working-target pass
|
|
384
318
|
* produces the documents and the Projection Root places them, so no Runtime
|
|
385
|
-
* Surface reaches inside a Working Repository.
|
|
319
|
+
* Surface reaches inside a Working Repository. Refuses before anything renders
|
|
320
|
+
* when the context has no Working Repository: every document is addressed by it.
|
|
321
|
+
* Its warnings are data for the caller, never printed here.
|
|
386
322
|
*/
|
|
387
323
|
export async function renderRuntimeDocuments(
|
|
388
324
|
ctx: SetupContext,
|
|
389
325
|
registrations: PluginRegistration[],
|
|
390
326
|
plan: SetupInstallationPlan,
|
|
391
|
-
wrapped?: { audience: string; registrations: PluginRegistration[] },
|
|
392
327
|
): Promise<RenderedRuntimeDocuments> {
|
|
393
|
-
|
|
394
|
-
const inputsByRuntime = await
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
);
|
|
402
|
-
for (const [runtimeId, inputs] of audienceInputs) {
|
|
403
|
-
inputsByRuntime.set(runtimeId, [...(inputsByRuntime.get(runtimeId) ?? []), ...inputs]);
|
|
404
|
-
}
|
|
328
|
+
projectionRepoRoot(ctx);
|
|
329
|
+
const inputsByRuntime = await collectRuntimeContributionInputs(ctx, registrations, plan);
|
|
330
|
+
const rendered: RenderedRuntimeDocuments = { documents: [], warnings: [] };
|
|
331
|
+
for (const [runtimeId, render] of Object.entries(RUNTIME_SURFACE_WORKING_RENDERERS)) {
|
|
332
|
+
if (!ctx.activeProviders.includes(runtimeId)) continue;
|
|
333
|
+
const { documents, warnings } = await render(ctx, inputsByRuntime.get(runtimeId) ?? []);
|
|
334
|
+
rendered.documents.push(...documents);
|
|
335
|
+
rendered.warnings.push(...warnings);
|
|
405
336
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
337
|
+
return rendered;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Publishes the enabled Claude plugin folders for a wrap pass, before it
|
|
342
|
+
* renders: writes Mate's marketplace files and removes those of disabled
|
|
343
|
+
* Capabilities. Runs no plugin phase.
|
|
344
|
+
*/
|
|
345
|
+
export async function publishRuntimeClaudePluginMarketplaces(
|
|
346
|
+
ctx: SetupContext,
|
|
347
|
+
registrations: PluginRegistration[],
|
|
348
|
+
plan: SetupInstallationPlan,
|
|
349
|
+
): Promise<ClaudePluginFolders> {
|
|
350
|
+
const inputsByRuntime = await collectRuntimeContributionInputs(ctx, registrations, plan);
|
|
351
|
+
return publishClaudePluginFolders(inputsByRuntime.get("claude") ?? [], {
|
|
352
|
+
bundledPluginRoot: getClaudePluginRoot(),
|
|
353
|
+
});
|
|
409
354
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
ManagedOutputEntry,
|
|
6
|
+
ManagedOutputOwner,
|
|
7
|
+
ManagedOutputRecorder,
|
|
8
|
+
ManagedOutputReport,
|
|
9
|
+
} from "./plugin";
|
|
10
|
+
|
|
11
|
+
export interface ManagedOutputCollector {
|
|
12
|
+
recorder: ManagedOutputRecorder;
|
|
13
|
+
/** Entries inside the companion, deduplicated, as companion-relative POSIX paths. */
|
|
14
|
+
report(): ManagedOutputReport;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createManagedOutputCollector(companionPath: string): ManagedOutputCollector {
|
|
18
|
+
const entries: ManagedOutputEntry[] = [];
|
|
19
|
+
return {
|
|
20
|
+
recorder: { record: (entry) => entries.push(entry) },
|
|
21
|
+
report() {
|
|
22
|
+
const seen = new Set<string>();
|
|
23
|
+
const report: ManagedOutputEntry[] = [];
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
const relative = path.relative(companionPath, entry.path);
|
|
26
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) continue;
|
|
27
|
+
const posix = relative.split(path.sep).join("/");
|
|
28
|
+
const key = `${entry.change}\0${entry.owner}\0${posix}`;
|
|
29
|
+
if (seen.has(key)) continue;
|
|
30
|
+
seen.add(key);
|
|
31
|
+
report.push({ ...entry, path: posix });
|
|
32
|
+
}
|
|
33
|
+
return report;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Removes `target` and records it, only when it existed: a no-op removal claims nothing. */
|
|
39
|
+
export async function removeRecorded(
|
|
40
|
+
target: string,
|
|
41
|
+
owner: ManagedOutputOwner,
|
|
42
|
+
recorder?: ManagedOutputRecorder,
|
|
43
|
+
): Promise<void> {
|
|
44
|
+
const existed = await fs.lstat(target).then(
|
|
45
|
+
() => true,
|
|
46
|
+
() => false,
|
|
47
|
+
);
|
|
48
|
+
if (!existed) return;
|
|
49
|
+
await fs.rm(target, { recursive: true, force: true });
|
|
50
|
+
recorder?.record({ path: target, change: "removed", owner });
|
|
51
|
+
}
|
package/src/tools/setup/mate.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
import { removeRecorded } from "./managed-output";
|
|
5
|
+
import type { ManagedOutputRecorder } from "./plugin";
|
|
4
6
|
import { pruneEmptyAncestors } from "./utils";
|
|
7
|
+
import { readFrontmatter } from "../../lib/frontmatter";
|
|
5
8
|
|
|
6
|
-
export const MATE_ARTIFACT_SKILLS = ["mate-artifact-publish"] as const;
|
|
7
9
|
export const MATE_SKILLS = [
|
|
8
|
-
"mate-
|
|
10
|
+
"mate-clarify-intent",
|
|
11
|
+
"mate-explore-change",
|
|
12
|
+
"mate-propose-change",
|
|
13
|
+
"mate-apply-change",
|
|
14
|
+
"mate-archive-change",
|
|
15
|
+
"mate-publish-artifact",
|
|
16
|
+
"mate-backfill-spec",
|
|
9
17
|
"mate-create-report",
|
|
10
|
-
"mate-openspec-backfill",
|
|
11
18
|
"mate-interview-me",
|
|
12
19
|
"mate-grill-me",
|
|
13
20
|
"mate-grilling",
|
|
@@ -17,8 +24,11 @@ export const MATE_SKILLS = [
|
|
|
17
24
|
"mate-simplify-code",
|
|
18
25
|
] as const;
|
|
19
26
|
const LEGACY_MATE_SKILLS = ["mate-artifact-finish", "mate-openspec-artifact-finish"] as const;
|
|
20
|
-
/**
|
|
21
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Renamed without aliases: removed only when Mate wrote them (`metadata.author: mate`),
|
|
29
|
+
* so a user-authored skill that happens to share a retired name is left alone.
|
|
30
|
+
*/
|
|
31
|
+
const RETIRED_MATE_SKILLS = ["mate-artifact-publish", "mate-openspec-backfill"] as const;
|
|
22
32
|
|
|
23
33
|
const MATE_SKILLS_SOURCE = path.join(import.meta.dirname, "../../templates/mate-skills");
|
|
24
34
|
|
|
@@ -83,13 +93,41 @@ A \`diff\` section carries a unified diff patch as produced by \`git diff\`. The
|
|
|
83
93
|
|
|
84
94
|
A report carrying a mermaid payload loads the pinned, integrity-checked diagram runtime from a CDN; a report without one does not. Offline, each diagram stays readable as its source. Otherwise the page stays a single self-contained file.
|
|
85
95
|
|
|
96
|
+
## Presentation Fields
|
|
97
|
+
|
|
98
|
+
These fields are optional. A document without them stays valid and renders with the defaults.
|
|
99
|
+
|
|
100
|
+
- \`tone\` on a status item: \`ok\`, \`warn\`, \`error\`, \`info\`, or \`neutral\`. It sets the marker's colour and shape. When absent, the tone is inferred from well-known status words such as \`passed\`, \`stale\`, or \`failed\`, and any other text is \`neutral\`.
|
|
101
|
+
|
|
102
|
+
\`\`\`json
|
|
103
|
+
{ "label": "Build", "status": "flaky", "tone": "warn" }
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
106
|
+
- \`format\` on a \`text\` section: \`plain\` (default, shown verbatim with its line breaks) or \`markdown\`.
|
|
107
|
+
|
|
108
|
+
\`\`\`json
|
|
109
|
+
{ "id": "notes", "title": "Notes", "type": "text", "format": "markdown", "content": "- **Renderer** owns layout\\n- See \`highlight.ts\`" }
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
- \`caption\` on a \`diagram\` or \`diff\` section: a non-empty Markdown note shown beneath the visual, in the same section and without a heading of its own.
|
|
113
|
+
|
|
114
|
+
\`\`\`json
|
|
115
|
+
{ "id": "changes", "title": "Changes", "type": "diff", "patch": "...", "caption": "Moves validation into \`contract.ts\`." }
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
Markdown supports paragraphs, \`#\` headings, one-level \`-\`, \`*\`, or \`1.\` lists, \`**strong**\`, \`*emphasis*\`, \`\` \`code\` \`\`, fenced code blocks with syntax highlighting, and \`[text](https://…)\` links. Raw HTML is shown as text, links other than \`http\` or \`https\` are shown as plain text, and any other syntax stays literal.
|
|
119
|
+
|
|
120
|
+
The page follows the reader's colour scheme: Mate brand colours on white in light mode, and on a dark background in dark mode, with highlighted code and mermaid diagrams following the same scheme. It always prints as dark text on white.
|
|
121
|
+
|
|
122
|
+
To mark mermaid nodes, apply the theme classes \`added\`, \`changed\`, and \`removed\` with \`class\` or \`:::\`; they follow the colour scheme. Lines that fix a colour with \`classDef\`, \`style\`, or \`linkStyle\` are dropped from the dark copy, because a fill chosen for a white page hides the labels there.
|
|
123
|
+
|
|
86
124
|
## Invocation
|
|
87
125
|
|
|
88
126
|
1. Serialize the complete document to a temporary file or pipe it to stdin.
|
|
89
127
|
2. Run \`mate report --input <file-or->\`.
|
|
90
128
|
3. Add \`--json\` when the caller needs normalized JSON instead of browser delivery.
|
|
91
129
|
|
|
92
|
-
The CLI chooses the delivery surface; deliver only through \`mate report\`, never a hand-written file, server, or browser launch. Inside a Studio terminal it hosts the report in Studio and prints a full link only when Studio has a public address, otherwise it tells the operator to open Studio → Reports; relay that output. Elsewhere, or when Studio is unreachable, it writes self-contained HTML to a unique OS temporary directory and opens it in the default browser. The report
|
|
130
|
+
The CLI chooses the delivery surface; deliver only through \`mate report\`, never a hand-written file, server, or browser launch. Inside a Studio terminal it hosts the report in Studio and prints a full link only when Studio has a public address, otherwise it tells the operator to open Studio → Reports; relay that output. Elsewhere, or when Studio is unreachable, it writes self-contained HTML to a unique OS temporary directory and opens it in the default browser. The report header carries an icon-only print control, named "Print / Save as PDF", that calls the browser's native print dialog. If HTML delivery fails, the CLI warns on stderr and emits the complete report document as JSON on stdout.
|
|
93
131
|
|
|
94
132
|
The built-in \`mate report\` path collects Mate usage data and adapts it to the same contract and renderer.
|
|
95
133
|
`;
|
|
@@ -133,10 +171,41 @@ async function resolveMateSkillSource(skill: string, tool: string): Promise<stri
|
|
|
133
171
|
throw new Error(`Mate skill source not found: ${skill}`);
|
|
134
172
|
}
|
|
135
173
|
|
|
136
|
-
|
|
174
|
+
/** The `metadata.author` a skill directory's SKILL.md declares, if any. */
|
|
175
|
+
export async function readSkillAuthor(skillDir: string): Promise<unknown> {
|
|
176
|
+
let source: string;
|
|
177
|
+
try {
|
|
178
|
+
source = await fs.readFile(path.join(skillDir, "SKILL.md"), "utf8");
|
|
179
|
+
} catch {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
const metadata = readFrontmatter(source)?.metadata as { author?: unknown } | null | undefined;
|
|
183
|
+
return metadata?.author;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function isMateAuthored(skillDir: string): Promise<boolean> {
|
|
187
|
+
return (await readSkillAuthor(skillDir)) === "mate";
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function removeRetiredMateSkills(
|
|
191
|
+
skillsDir: string,
|
|
192
|
+
recorder?: ManagedOutputRecorder,
|
|
193
|
+
): Promise<void> {
|
|
194
|
+
for (const skill of RETIRED_MATE_SKILLS) {
|
|
195
|
+
const dir = path.join(skillsDir, skill);
|
|
196
|
+
if (await isMateAuthored(dir)) await removeRecorded(dir, "mate", recorder);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export async function applyMateSkills(
|
|
201
|
+
skillsDir: string,
|
|
202
|
+
tool: string,
|
|
203
|
+
recorder?: ManagedOutputRecorder,
|
|
204
|
+
): Promise<void> {
|
|
137
205
|
for (const skill of LEGACY_MATE_SKILLS) {
|
|
138
|
-
await
|
|
206
|
+
await removeRecorded(path.join(skillsDir, skill), "mate", recorder);
|
|
139
207
|
}
|
|
208
|
+
await removeRetiredMateSkills(skillsDir, recorder);
|
|
140
209
|
for (const skill of MATE_SKILLS) {
|
|
141
210
|
const destination = path.join(skillsDir, skill);
|
|
142
211
|
if (skill === "mate-create-report") {
|
|
@@ -145,13 +214,19 @@ export async function applyMateSkills(skillsDir: string, tool: string): Promise<
|
|
|
145
214
|
} else {
|
|
146
215
|
await deployMateSkillDir(await resolveMateSkillSource(skill, tool), destination);
|
|
147
216
|
}
|
|
217
|
+
recorder?.record({ path: destination, change: "written", owner: "mate" });
|
|
148
218
|
}
|
|
149
219
|
}
|
|
150
220
|
|
|
151
|
-
export async function teardownMateSkills(
|
|
152
|
-
|
|
221
|
+
export async function teardownMateSkills(
|
|
222
|
+
skillsDir: string,
|
|
223
|
+
companionPath: string,
|
|
224
|
+
recorder?: ManagedOutputRecorder,
|
|
225
|
+
): Promise<void> {
|
|
226
|
+
await removeRetiredMateSkills(skillsDir, recorder);
|
|
227
|
+
for (const skill of [...MATE_SKILLS, ...LEGACY_MATE_SKILLS]) {
|
|
153
228
|
try {
|
|
154
|
-
await
|
|
229
|
+
await removeRecorded(path.join(skillsDir, skill), "mate", recorder);
|
|
155
230
|
} catch {
|
|
156
231
|
/* not present */
|
|
157
232
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FrameworkConfig, LinkedRepository } from "../../lib/orchestrator/types";
|
|
2
|
+
import type { SessionKind } from "../../runtime/session-kind";
|
|
2
3
|
import type { InstallRequirement, InstallRequirementContext } from "./install-contract";
|
|
3
4
|
import type { ClaudeHookGroup } from "./providers/claude-format";
|
|
4
5
|
|
|
@@ -7,10 +8,9 @@ export type SetupScope = "companion" | "hub";
|
|
|
7
8
|
/**
|
|
8
9
|
* Where a reconcile pass lands its documents. `companion` writes the material's
|
|
9
10
|
* own repository; `working` renders the documents an Agent Runtime discovers by
|
|
10
|
-
* its own upward walk and leaves the placing to the Projection Root
|
|
11
|
-
* `audience-layer` writes one audience's launch layer, outside every repository.
|
|
11
|
+
* its own upward walk and leaves the placing to the Projection Root.
|
|
12
12
|
*/
|
|
13
|
-
export type ProjectionTarget = "companion" | "working"
|
|
13
|
+
export type ProjectionTarget = "companion" | "working";
|
|
14
14
|
|
|
15
15
|
export interface SetupContext {
|
|
16
16
|
companionPath: string;
|
|
@@ -23,14 +23,11 @@ export interface SetupContext {
|
|
|
23
23
|
repoPath?: string;
|
|
24
24
|
/** Defaults to `companion`, so a caller that names no target is unchanged. */
|
|
25
25
|
target?: ProjectionTarget;
|
|
26
|
-
/** The audience an `audience-layer` pass renders; required by that target only. */
|
|
27
|
-
audience?: string;
|
|
28
26
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* when absent.
|
|
27
|
+
* Asks the OpenSpec capability to regenerate its CLI output in `sync` mode.
|
|
28
|
+
* Only `mate companion update` sets it; launches leave committed output alone.
|
|
32
29
|
*/
|
|
33
|
-
|
|
30
|
+
regenerateOpenSpec?: boolean;
|
|
34
31
|
/**
|
|
35
32
|
* Provider-mediated context services. Always populated when the engine
|
|
36
33
|
* executes a plugin; optional so hand-built contexts (tests, direct calls)
|
|
@@ -39,13 +36,34 @@ export interface SetupContext {
|
|
|
39
36
|
mcp?: McpService;
|
|
40
37
|
instructions?: InstructionsService;
|
|
41
38
|
templates?: TemplatesService;
|
|
39
|
+
/** Collects the managed output a sync pass touched; absent outside one. */
|
|
40
|
+
managedOutput?: ManagedOutputRecorder;
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
export type ManagedOutputOwner = "mate" | "openspec";
|
|
44
|
+
|
|
45
|
+
/** One path a pass wrote or removed, with the side that owns it. */
|
|
46
|
+
export interface ManagedOutputEntry {
|
|
47
|
+
/** Absolute when recorded; companion-relative POSIX in a {@link ManagedOutputReport}. */
|
|
48
|
+
path: string;
|
|
49
|
+
change: "written" | "removed";
|
|
50
|
+
owner: ManagedOutputOwner;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ManagedOutputRecorder {
|
|
54
|
+
record(entry: ManagedOutputEntry): void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** What a sync pass reports it touched, as companion-relative POSIX paths. */
|
|
58
|
+
export type ManagedOutputReport = readonly ManagedOutputEntry[];
|
|
59
|
+
|
|
44
60
|
export interface LaunchPreflightContext {
|
|
45
61
|
companionPath: string;
|
|
46
62
|
config: FrameworkConfig;
|
|
47
63
|
repository?: LinkedRepository;
|
|
48
64
|
providerId: string;
|
|
65
|
+
/** The session the prepare answers for, so a check can skip what that session does not load. */
|
|
66
|
+
sessionKind: SessionKind;
|
|
49
67
|
}
|
|
50
68
|
|
|
51
69
|
/** Provider-agnostic description of an MCP server to register. */
|
|
@@ -131,15 +149,9 @@ export type PluginPolicy = "required" | "default" | "optional";
|
|
|
131
149
|
|
|
132
150
|
/**
|
|
133
151
|
* A plugin registration entry. Bare plugins derive their policy from
|
|
134
|
-
* `defaultSelected` (`true` → "default", `false` → "optional").
|
|
135
|
-
* the source of a declared plugin: `null` (or absent) for compiled-in plugins
|
|
136
|
-
* and top-level `plugins` declarations, the audience name for a declaration
|
|
137
|
-
* under `audiences.<name>.plugins`. `packageName` names the declared package a
|
|
138
|
-
* dynamic plugin was loaded from.
|
|
152
|
+
* `defaultSelected` (`true` → "default", `false` → "optional").
|
|
139
153
|
*/
|
|
140
|
-
export type PluginRegistration =
|
|
141
|
-
| Plugin
|
|
142
|
-
| { plugin: Plugin; policy: PluginPolicy; audience?: string | null; packageName?: string };
|
|
154
|
+
export type PluginRegistration = Plugin | { plugin: Plugin; policy: PluginPolicy };
|
|
143
155
|
|
|
144
156
|
/**
|
|
145
157
|
* A hook group a Capability contributes to a runtime's settings. `marker` is
|
|
@@ -203,10 +215,17 @@ export interface AgentDefinitionContribution {
|
|
|
203
215
|
content: string;
|
|
204
216
|
}
|
|
205
217
|
|
|
218
|
+
/** A Claude Code plugin folder, declared under the `claude` key. Launch-only: never written to a file. */
|
|
219
|
+
export interface PluginDirectoryContribution {
|
|
220
|
+
/** Absolute path of the folder holding `.claude-plugin/plugin.json`. */
|
|
221
|
+
path: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
206
224
|
/**
|
|
207
225
|
* Declarative Agent Runtime contributions of one Capability for one runtime.
|
|
208
226
|
* The runtime's Runtime Surface reconciles these symmetrically: applied while
|
|
209
227
|
* the Capability is enabled, removed when it is not, idempotent across runs.
|
|
228
|
+
* `pluginDirectories` is the exception: gathered for the launch, written nowhere.
|
|
210
229
|
*/
|
|
211
230
|
export interface RuntimeContributions {
|
|
212
231
|
mcpServers?: McpServerDescriptor[];
|
|
@@ -216,6 +235,7 @@ export interface RuntimeContributions {
|
|
|
216
235
|
skillTrees?: SkillTreeContribution[];
|
|
217
236
|
pluginReferences?: PluginReferenceContribution[];
|
|
218
237
|
agentDefinitions?: AgentDefinitionContribution[];
|
|
238
|
+
pluginDirectories?: PluginDirectoryContribution[];
|
|
219
239
|
}
|
|
220
240
|
|
|
221
241
|
/**
|