@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
|
@@ -28,6 +28,7 @@ export type ProjectionEntryId =
|
|
|
28
28
|
| "openspec-store-exclude"
|
|
29
29
|
| "openspec-store-pointer"
|
|
30
30
|
| "claude-skill-links"
|
|
31
|
+
| "claude-command-links"
|
|
31
32
|
| "workspace-document"
|
|
32
33
|
| "capability-excludes"
|
|
33
34
|
| "claude-working-settings"
|
|
@@ -41,6 +42,8 @@ export type ProjectionEntryId =
|
|
|
41
42
|
export interface ProjectionInput {
|
|
42
43
|
repoPath: string;
|
|
43
44
|
companionPath?: string;
|
|
45
|
+
/** Every companion folder the workspace document lists, in order; `[companionPath]` when absent. */
|
|
46
|
+
workspaceCompanionPaths?: string[];
|
|
44
47
|
repository?: LinkedRepository;
|
|
45
48
|
source?: CompanionSource;
|
|
46
49
|
config?: FrameworkConfig;
|
|
@@ -50,8 +53,6 @@ export interface ProjectionInput {
|
|
|
50
53
|
runtimeDocuments?: readonly RenderedRuntimeDocument[];
|
|
51
54
|
/** Restricts runtime-tagged entries to these runtimes; every runtime when absent. */
|
|
52
55
|
runtimes?: readonly WrapRuntime[];
|
|
53
|
-
/** The layer directory of the audience the checkout is wrapped for; `null` or absent for base only. */
|
|
54
|
-
audienceLayerDir?: string | null;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
export interface ProjectionRemovalInput {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { readWrapState } from "../../runtime/wrap-state";
|
|
2
|
+
import { GlobalConfigStore } from "./global-config-store";
|
|
3
|
+
import { reconcileWorkingRepoClaudeCommandLinks } from "./projection-claude-commands";
|
|
4
|
+
import { reconcileWorkingRepoClaudeSkillLinks } from "./projection-claude-skills";
|
|
5
|
+
import { readCompanionRegistry } from "./repository-link";
|
|
6
|
+
import type { FrameworkConfig, LinkedRepository } from "./types";
|
|
7
|
+
import { errorMessage } from "../../runtime/error-message";
|
|
8
|
+
|
|
9
|
+
export interface LinkRefreshResult {
|
|
10
|
+
/** Null when the companion's list of linked repositories could not be read. */
|
|
11
|
+
repository: LinkedRepository | null;
|
|
12
|
+
outcome: "written" | "current" | "failed";
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LinkRefreshDeps {
|
|
17
|
+
readRegistry: (companionPath: string) => Promise<LinkedRepository[]>;
|
|
18
|
+
isWrappedForClaude: (repoPath: string) => Promise<boolean>;
|
|
19
|
+
registeredCompanionPaths: () => Promise<string[]>;
|
|
20
|
+
reconcileSkillLinks: typeof reconcileWorkingRepoClaudeSkillLinks;
|
|
21
|
+
reconcileCommandLinks: typeof reconcileWorkingRepoClaudeCommandLinks;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const linkRefreshDeps: LinkRefreshDeps = {
|
|
25
|
+
readRegistry: async (companionPath) => {
|
|
26
|
+
try {
|
|
27
|
+
return (await readCompanionRegistry(companionPath)).repos;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// No registry file means no linked repositories.
|
|
30
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return [];
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
isWrappedForClaude: async (repoPath) => (await readWrapState(repoPath)).runtimes.has("claude"),
|
|
35
|
+
registeredCompanionPaths: () => new GlobalConfigStore().list(),
|
|
36
|
+
reconcileSkillLinks: reconcileWorkingRepoClaudeSkillLinks,
|
|
37
|
+
reconcileCommandLinks: reconcileWorkingRepoClaudeCommandLinks,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Re-links the companion's Claude skills and commands into every linked Claude-wrapped
|
|
42
|
+
* Working Repository. Links only; runtime documents wait for the wrap pass. Failures
|
|
43
|
+
* are reported per repository, never thrown.
|
|
44
|
+
*/
|
|
45
|
+
export async function refreshWorkingClaudeLinks(
|
|
46
|
+
companionPath: string,
|
|
47
|
+
config: FrameworkConfig,
|
|
48
|
+
deps: LinkRefreshDeps = linkRefreshDeps,
|
|
49
|
+
): Promise<LinkRefreshResult[]> {
|
|
50
|
+
const enabled = config.allowedAgents?.includes("claude") ?? false;
|
|
51
|
+
const results: LinkRefreshResult[] = [];
|
|
52
|
+
let registered: string[] | undefined;
|
|
53
|
+
let repositories: LinkedRepository[];
|
|
54
|
+
try {
|
|
55
|
+
repositories = await deps.readRegistry(companionPath);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return [{ repository: null, outcome: "failed", error: errorMessage(error) }];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const repository of repositories) {
|
|
61
|
+
try {
|
|
62
|
+
if (!(await deps.isWrappedForClaude(repository.path))) continue;
|
|
63
|
+
registered ??= await deps.registeredCompanionPaths();
|
|
64
|
+
const skills = await deps.reconcileSkillLinks(
|
|
65
|
+
repository.path,
|
|
66
|
+
companionPath,
|
|
67
|
+
enabled,
|
|
68
|
+
registered,
|
|
69
|
+
);
|
|
70
|
+
const commands = await deps.reconcileCommandLinks(
|
|
71
|
+
repository.path,
|
|
72
|
+
companionPath,
|
|
73
|
+
enabled,
|
|
74
|
+
registered,
|
|
75
|
+
);
|
|
76
|
+
const written = skills === "written" || commands === "written";
|
|
77
|
+
results.push({ repository, outcome: written ? "written" : "current" });
|
|
78
|
+
} catch (error) {
|
|
79
|
+
results.push({
|
|
80
|
+
repository,
|
|
81
|
+
outcome: "failed",
|
|
82
|
+
error: errorMessage(error),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getActiveDistribution } from "../../distribution";
|
|
2
2
|
import { FRAMEWORK_NAME } from "../../framework";
|
|
3
|
+
import { launchPassesClaudePluginFolders } from "../../runtime/claude-delivery-plan";
|
|
3
4
|
import { recordCompanionSyncUnfinished } from "../../runtime/companion-git-state";
|
|
4
5
|
import { withCompanionLock, type CompanionLockOptions } from "../../runtime/companion-lock";
|
|
5
6
|
import {
|
|
@@ -7,15 +8,11 @@ import {
|
|
|
7
8
|
syncCompanionUnattended,
|
|
8
9
|
type UnattendedSyncOutcome,
|
|
9
10
|
} from "../../runtime/companion-sync";
|
|
10
|
-
import {
|
|
11
|
+
import { managedSessionKind, type SessionKind } from "../../runtime/session-kind";
|
|
12
|
+
import type { WrapState } from "../../runtime/wrap-state";
|
|
11
13
|
import { syncCompanionFiles } from "../../tools/setup";
|
|
12
|
-
import { renderAudienceLayer, type RenderedAudienceLayer } from "../../tools/setup/audience-layer";
|
|
13
|
-
import {
|
|
14
|
-
readAudienceSelection,
|
|
15
|
-
resolveAudience,
|
|
16
|
-
} from "../../tools/setup/dynamic-plugins/audiences";
|
|
17
|
-
import { buildSetupInstallationPlan } from "../../tools/setup/engine";
|
|
18
14
|
import type { CapabilityPlugin, LaunchPreflightContext } from "../../tools/setup/plugin";
|
|
15
|
+
import type { ClaudePluginFolders } from "../../tools/setup/providers/claude-plugin-folders";
|
|
19
16
|
import { attendedLockOptions, syncCompanionGit } from "./companion-git-sync";
|
|
20
17
|
import { readCompanionConfig } from "./config-store";
|
|
21
18
|
import { entryFailureMessage, firstFailure, type ProjectionChangedPaths } from "./projection-types";
|
|
@@ -40,8 +37,7 @@ export type PrepareStepName =
|
|
|
40
37
|
| "file-sync"
|
|
41
38
|
| "launch-projection"
|
|
42
39
|
| "working-target"
|
|
43
|
-
| "preflight"
|
|
44
|
-
| "audience-layer";
|
|
40
|
+
| "preflight";
|
|
45
41
|
|
|
46
42
|
export interface PrepareStep {
|
|
47
43
|
step: PrepareStepName;
|
|
@@ -68,8 +64,8 @@ export interface PrepareResult {
|
|
|
68
64
|
failure?: unknown;
|
|
69
65
|
/** The wrap state the `working-target` step's pass left; a launch reads no manifest itself. */
|
|
70
66
|
wrapState?: WrapState;
|
|
71
|
-
/** The
|
|
72
|
-
|
|
67
|
+
/** The Claude plugin folders the `file-sync` step gathered; a launch gathers none itself. */
|
|
68
|
+
claudePluginDirectories?: string[];
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
export interface PrepareSessionInput {
|
|
@@ -98,10 +94,9 @@ const SYNC_LOCK_TIMEOUT_MS = 5 * 60_000;
|
|
|
98
94
|
*/
|
|
99
95
|
async function runCapabilityPreflight(context: LaunchPreflightContext): Promise<void> {
|
|
100
96
|
const { config, providerId } = context;
|
|
101
|
-
/** Base only: an audience plugin's `forProvider` hooks never run. */
|
|
102
97
|
const preflights = getActiveDistribution()
|
|
103
|
-
.registry.
|
|
104
|
-
.flatMap((
|
|
98
|
+
.registry.getAll()
|
|
99
|
+
.flatMap((plugin) => {
|
|
105
100
|
if (plugin.kind !== "capability" || !plugin.isEnabled(config)) return [];
|
|
106
101
|
const capability = plugin as CapabilityPlugin;
|
|
107
102
|
const preflight = capability.forProvider?.[providerId]?.preflight;
|
|
@@ -133,7 +128,8 @@ export const sessionPrepareDeps = {
|
|
|
133
128
|
syncCompanionGit,
|
|
134
129
|
syncCompanionUnattended,
|
|
135
130
|
recordCompanionSyncUnfinished,
|
|
136
|
-
syncCompanionFiles
|
|
131
|
+
syncCompanionFiles: async (...args: Parameters<typeof syncCompanionFiles>) =>
|
|
132
|
+
(await syncCompanionFiles(...args)).claudePluginFolders,
|
|
137
133
|
projectLaunch: (input: Parameters<typeof project>[1]) => project("launch", input),
|
|
138
134
|
/**
|
|
139
135
|
* The Projection Root a Claude launch guarantees for itself. Companion
|
|
@@ -147,11 +143,6 @@ export const sessionPrepareDeps = {
|
|
|
147
143
|
withCompanionLock,
|
|
148
144
|
/** As the launch decides it: Git may prompt only with a terminal on both ends. */
|
|
149
145
|
isInteractiveTerminal: () => !!(process.stdin.isTTY && process.stdout.isTTY),
|
|
150
|
-
/** The launch's `MATE_AUDIENCE`; read by an attended prepare only. */
|
|
151
|
-
audienceSelection: () => readAudienceSelection(process.env),
|
|
152
|
-
/** The audience a checkout is wrapped for, from its manifest; `null` for base. */
|
|
153
|
-
wrappedAudience: (repoPath: string) => readWrapStateSync(repoPath).audience,
|
|
154
|
-
renderAudienceLayer,
|
|
155
146
|
};
|
|
156
147
|
|
|
157
148
|
function message(error: unknown): string {
|
|
@@ -164,7 +155,7 @@ class StepLog {
|
|
|
164
155
|
readonly warnings: string[] = [];
|
|
165
156
|
failure: unknown;
|
|
166
157
|
wrapState: WrapState | undefined;
|
|
167
|
-
|
|
158
|
+
claudePluginDirectories: string[] | undefined;
|
|
168
159
|
stopped = false;
|
|
169
160
|
companionChanged = false;
|
|
170
161
|
|
|
@@ -192,10 +183,18 @@ async function runFileSync(
|
|
|
192
183
|
): Promise<void> {
|
|
193
184
|
const deps = sessionPrepareDeps;
|
|
194
185
|
try {
|
|
195
|
-
|
|
196
|
-
await deps.syncCompanionFiles(input.companionPath, config, input.repository.path)
|
|
197
|
-
|
|
198
|
-
|
|
186
|
+
const folders = input.repository
|
|
187
|
+
? await deps.syncCompanionFiles(input.companionPath, config, input.repository.path)
|
|
188
|
+
: await deps.syncCompanionFiles(input.companionPath, config);
|
|
189
|
+
run.claudePluginDirectories = [...folders.launch];
|
|
190
|
+
/**
|
|
191
|
+
* The Claude plan speaks for Claude sessions only; OpenCode loads no plugin
|
|
192
|
+
* folder. With a Working Repository the wrap pass reports publication;
|
|
193
|
+
* without one no wrap pass runs, so this step does.
|
|
194
|
+
*/
|
|
195
|
+
if (reportsClaudePluginFolders(input)) {
|
|
196
|
+
run.warnings.push(...folders.loadWarnings);
|
|
197
|
+
if (!input.repository) run.warnings.push(...publicationWarnings(folders));
|
|
199
198
|
}
|
|
200
199
|
run.push({ step: "file-sync", outcome: "ok" });
|
|
201
200
|
} catch (error) {
|
|
@@ -215,6 +214,24 @@ function wrapDetail(wrapped: {
|
|
|
215
214
|
return parts.length > 0 ? `updated (${parts.join("; ")})` : "updated";
|
|
216
215
|
}
|
|
217
216
|
|
|
217
|
+
/** A managed Claude launch; plain sessions' prepares and OpenCode report no plugin-folder problem. */
|
|
218
|
+
function reportsClaudePluginFolders(input: PrepareSessionInput): boolean {
|
|
219
|
+
return input.runtime === "claude" && launchPassesClaudePluginFolders(sessionKindOf(input));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** What a publication left undone, one sentence per folder. */
|
|
223
|
+
function publicationWarnings(folders: ClaudePluginFolders | undefined): string[] {
|
|
224
|
+
const publication = folders?.publication;
|
|
225
|
+
if (!publication) return [];
|
|
226
|
+
return [...publication.unpublished.map((entry) => entry.warning), ...publication.warnings];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Attended is a managed launch, with or without a Working Repository; the rest serve plain sessions. */
|
|
230
|
+
function sessionKindOf(input: PrepareSessionInput): SessionKind {
|
|
231
|
+
if (input.mode !== "attended") return "unmanaged";
|
|
232
|
+
return managedSessionKind(Boolean(input.repository));
|
|
233
|
+
}
|
|
234
|
+
|
|
218
235
|
function runtimesOf(input: PrepareSessionInput): PrepareRuntime[] {
|
|
219
236
|
return input.mode !== "attended" && input.runtimes?.length
|
|
220
237
|
? [...input.runtimes]
|
|
@@ -241,6 +258,9 @@ async function reconcileWrap(
|
|
|
241
258
|
return;
|
|
242
259
|
}
|
|
243
260
|
run.warnings.push(...wrapped.warnings);
|
|
261
|
+
if (reportsClaudePluginFolders(input)) {
|
|
262
|
+
run.warnings.push(...publicationWarnings(wrapped.claudePluginFolders));
|
|
263
|
+
}
|
|
244
264
|
run.wrapState = wrapped.wrapState;
|
|
245
265
|
run.push({
|
|
246
266
|
step: "working-target",
|
|
@@ -324,6 +344,7 @@ async function runLocal(
|
|
|
324
344
|
config,
|
|
325
345
|
repository: input.repository,
|
|
326
346
|
providerId: runtime,
|
|
347
|
+
sessionKind: sessionKindOf(input),
|
|
327
348
|
}),
|
|
328
349
|
),
|
|
329
350
|
);
|
|
@@ -337,71 +358,12 @@ async function runLocal(
|
|
|
337
358
|
});
|
|
338
359
|
}
|
|
339
360
|
|
|
340
|
-
/**
|
|
341
|
-
* The active audience's launch layer, after the base prepare. Only a managed
|
|
342
|
-
* launch reaches here: a bare session's prepare never renders one, whatever
|
|
343
|
-
* `MATE_AUDIENCE` its environment carries. An audience the companion does not
|
|
344
|
-
* declare renders nothing; hydration already warned about it.
|
|
345
|
-
*/
|
|
346
|
-
async function renderLayer(
|
|
347
|
-
input: PrepareSessionInput,
|
|
348
|
-
config: FrameworkConfig,
|
|
349
|
-
run: StepLog,
|
|
350
|
-
): Promise<void> {
|
|
351
|
-
const deps = sessionPrepareDeps;
|
|
352
|
-
/** Adopted from the wrap: the wrap delivers it, so the launch renders no layer of its own. */
|
|
353
|
-
const wrapped = input.repository ? deps.wrappedAudience(input.repository.path) : null;
|
|
354
|
-
if (wrapped) {
|
|
355
|
-
run.push({ step: "audience-layer", outcome: "ok", detail: `${wrapped}: from the wrap` });
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
const audience = resolveAudience(config, deps.audienceSelection());
|
|
359
|
-
if (!audience.ok || audience.active === null) return;
|
|
360
|
-
try {
|
|
361
|
-
const registry = getActiveDistribution().registry;
|
|
362
|
-
const layer = await deps.renderAudienceLayer({
|
|
363
|
-
companionPath: input.companionPath,
|
|
364
|
-
config,
|
|
365
|
-
audience: audience.active,
|
|
366
|
-
activeProviders: buildSetupInstallationPlan(config, registry.baseRegistrations())
|
|
367
|
-
.activeProviders,
|
|
368
|
-
registrations: registry.audienceRegistrations(audience.active),
|
|
369
|
-
});
|
|
370
|
-
run.audienceLayer = layer;
|
|
371
|
-
run.push({
|
|
372
|
-
step: "audience-layer",
|
|
373
|
-
outcome: "ok",
|
|
374
|
-
detail: `${layer.audience}: ${layer.rendered ? "rendered" : "current"}`,
|
|
375
|
-
});
|
|
376
|
-
} catch (error) {
|
|
377
|
-
run.fail("audience-layer", error);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* A checkout wrapped for one audience refuses a launch for another before
|
|
383
|
-
* anything runs: the wrap's on-disk content would reach that session.
|
|
384
|
-
*/
|
|
385
|
-
function audienceConflict(input: PrepareSessionInput, config: FrameworkConfig): string | null {
|
|
386
|
-
if (!input.repository) return null;
|
|
387
|
-
const wrapped = sessionPrepareDeps.wrappedAudience(input.repository.path);
|
|
388
|
-
if (!wrapped) return null;
|
|
389
|
-
const selected = resolveAudience(config, sessionPrepareDeps.audienceSelection());
|
|
390
|
-
if (!selected.ok || selected.active === null || selected.active === wrapped) return null;
|
|
391
|
-
return `${FRAMEWORK_NAME}: ${input.repository.id} is wrapped for audience "${wrapped}", but MATE_AUDIENCE selects "${selected.active}". Run \`${FRAMEWORK_NAME} wrap --audience ${selected.active}\` in ${input.repository.path}, or launch from another worktree wrapped for "${selected.active}".`;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
361
|
async function runAttended(
|
|
395
362
|
input: PrepareSessionInput,
|
|
396
363
|
config: FrameworkConfig,
|
|
397
364
|
run: StepLog,
|
|
398
365
|
): Promise<void> {
|
|
399
366
|
const deps = sessionPrepareDeps;
|
|
400
|
-
const conflict = audienceConflict(input, config);
|
|
401
|
-
if (conflict) {
|
|
402
|
-
run.fail("audience-layer", new LaunchPreflightError(conflict));
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
367
|
if (input.skipGit) {
|
|
406
368
|
run.push({ step: "git-sync", outcome: "skipped", detail: "--no-git" });
|
|
407
369
|
} else if (config.git !== "auto") {
|
|
@@ -422,8 +384,6 @@ async function runAttended(
|
|
|
422
384
|
}
|
|
423
385
|
}
|
|
424
386
|
await runLocal(input, config, run);
|
|
425
|
-
if (run.stopped) return;
|
|
426
|
-
await renderLayer(input, config, run);
|
|
427
387
|
}
|
|
428
388
|
|
|
429
389
|
/** The sync's own config read: only a fast-forward can have changed it. */
|
|
@@ -478,7 +438,9 @@ export async function prepareSession(input: PrepareSessionInput): Promise<Prepar
|
|
|
478
438
|
...(run.companionChanged ? { companionChanged: true as const } : {}),
|
|
479
439
|
...(run.failure === undefined ? {} : { failure: run.failure }),
|
|
480
440
|
...(run.wrapState ? { wrapState: run.wrapState } : {}),
|
|
481
|
-
...(run.
|
|
441
|
+
...(run.claudePluginDirectories
|
|
442
|
+
? { claudePluginDirectories: run.claudePluginDirectories }
|
|
443
|
+
: {}),
|
|
482
444
|
});
|
|
483
445
|
|
|
484
446
|
const locked = await deps.withCompanionLock(input.companionPath, lockOptions(input), async () => {
|
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CapabilityConfig,
|
|
3
|
-
CliToolConfig,
|
|
4
|
-
FrameworkConfig,
|
|
5
|
-
GitModeProfile,
|
|
6
|
-
OpenSpecSchemaProfile,
|
|
7
|
-
} from "./types";
|
|
1
|
+
import type { CapabilityConfig, CliToolConfig, FrameworkConfig, GitModeProfile } from "./types";
|
|
8
2
|
|
|
9
|
-
export type OpenSpecSchemaSelection = OpenSpecSchemaProfile | "default";
|
|
10
3
|
export type GitModeSelection = GitModeProfile | "default";
|
|
11
|
-
const DEFAULT_OPENSPEC_SCHEMA_SELECTION: OpenSpecSchemaSelection = "default";
|
|
12
4
|
export const DEFAULT_GIT_MODE_SELECTION: GitModeSelection = "default";
|
|
13
5
|
|
|
14
|
-
export interface OpenSpecSchemaCompatibility {
|
|
15
|
-
id: OpenSpecSchemaSelection;
|
|
16
|
-
label: string;
|
|
17
|
-
description: string;
|
|
18
|
-
defaultSelected: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
6
|
export interface GitModeCompatibility {
|
|
22
7
|
id: GitModeSelection;
|
|
23
8
|
label: string;
|
|
@@ -25,21 +10,6 @@ export interface GitModeCompatibility {
|
|
|
25
10
|
defaultSelected: boolean;
|
|
26
11
|
}
|
|
27
12
|
|
|
28
|
-
const BUILTIN_OPENSPEC_SCHEMA_COMPATIBILITIES: OpenSpecSchemaCompatibility[] = [
|
|
29
|
-
{
|
|
30
|
-
id: "default",
|
|
31
|
-
label: "Default (vanilla OpenSpec)",
|
|
32
|
-
description: "Use OpenSpec's built-in spec-driven workflow.",
|
|
33
|
-
defaultSelected: true,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: "mate-v1",
|
|
37
|
-
label: "Mate v1",
|
|
38
|
-
description: "Use Mate's schema with proposal, design, spec, and task artifacts.",
|
|
39
|
-
defaultSelected: false,
|
|
40
|
-
},
|
|
41
|
-
];
|
|
42
|
-
|
|
43
13
|
const BUILTIN_GIT_MODE_COMPATIBILITIES: GitModeCompatibility[] = [
|
|
44
14
|
{
|
|
45
15
|
id: "default",
|
|
@@ -59,33 +29,9 @@ export interface SetupSelections {
|
|
|
59
29
|
allowedAgents: string[];
|
|
60
30
|
packageManagers: string[];
|
|
61
31
|
capabilities: CapabilityConfig[];
|
|
62
|
-
selectedOpenSpecSchema: OpenSpecSchemaSelection;
|
|
63
32
|
selectedGitMode: GitModeSelection;
|
|
64
33
|
}
|
|
65
34
|
|
|
66
|
-
export function getOpenSpecSchemaSelection(
|
|
67
|
-
capabilities: CapabilityConfig[],
|
|
68
|
-
): OpenSpecSchemaSelection {
|
|
69
|
-
const openspec = capabilities.find((capability) => capability.name === "openspec");
|
|
70
|
-
return openspec?.schemaProfile ?? DEFAULT_OPENSPEC_SCHEMA_SELECTION;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function applyOpenSpecSchemaSelection(
|
|
74
|
-
capabilities: CapabilityConfig[],
|
|
75
|
-
schemaSelection: OpenSpecSchemaSelection | undefined,
|
|
76
|
-
): CapabilityConfig[] {
|
|
77
|
-
if (schemaSelection === undefined) return capabilities;
|
|
78
|
-
|
|
79
|
-
return capabilities.map((capability) => {
|
|
80
|
-
if (capability.name !== "openspec") return capability;
|
|
81
|
-
if (schemaSelection === "default") {
|
|
82
|
-
const { schemaProfile: _schemaProfile, ...rest } = capability;
|
|
83
|
-
return rest;
|
|
84
|
-
}
|
|
85
|
-
return { ...capability, schemaProfile: schemaSelection };
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
35
|
interface SetupCompatibilityBase {
|
|
90
36
|
id: string;
|
|
91
37
|
label: string;
|
|
@@ -222,24 +168,6 @@ export function listSetupPackageManagerCompatibilities(): SetupPackageManagerCom
|
|
|
222
168
|
);
|
|
223
169
|
}
|
|
224
170
|
|
|
225
|
-
export function listSetupOpenSpecSchemaCompatibilities(
|
|
226
|
-
activeSchemaProfile?: OpenSpecSchemaSelection,
|
|
227
|
-
): OpenSpecSchemaCompatibility[] {
|
|
228
|
-
const compatibilities = [...BUILTIN_OPENSPEC_SCHEMA_COMPATIBILITIES];
|
|
229
|
-
if (
|
|
230
|
-
activeSchemaProfile !== undefined &&
|
|
231
|
-
!BUILTIN_OPENSPEC_SCHEMA_COMPATIBILITIES.some((entry) => entry.id === activeSchemaProfile)
|
|
232
|
-
) {
|
|
233
|
-
compatibilities.push({
|
|
234
|
-
id: activeSchemaProfile,
|
|
235
|
-
label: "Custom",
|
|
236
|
-
description: `Keep the project's current custom schema profile ("${activeSchemaProfile}"). Selecting Default or Mate v1 replaces it.`,
|
|
237
|
-
defaultSelected: false,
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
return compatibilities;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
171
|
export function listSetupGitModeCompatibilities(): GitModeCompatibility[] {
|
|
244
172
|
return [...BUILTIN_GIT_MODE_COMPATIBILITIES];
|
|
245
173
|
}
|
|
@@ -272,7 +200,6 @@ export function getDefaultSetupSelections(): SetupSelections {
|
|
|
272
200
|
allowedAgents,
|
|
273
201
|
packageManagers,
|
|
274
202
|
capabilities,
|
|
275
|
-
selectedOpenSpecSchema: DEFAULT_OPENSPEC_SCHEMA_SELECTION,
|
|
276
203
|
selectedGitMode: DEFAULT_GIT_MODE_SELECTION,
|
|
277
204
|
};
|
|
278
205
|
}
|
|
@@ -284,11 +211,27 @@ export function getSetupSelectionsFromConfig(config: FrameworkConfig): SetupSele
|
|
|
284
211
|
...new Set([...getLockedPackageManagers(), ...(config.packageManagers ?? [])]),
|
|
285
212
|
],
|
|
286
213
|
capabilities: dedupeCapabilities(config.capabilities ?? []),
|
|
287
|
-
selectedOpenSpecSchema: getOpenSpecSchemaSelection(config.capabilities ?? []),
|
|
288
214
|
selectedGitMode: config.git ?? DEFAULT_GIT_MODE_SELECTION,
|
|
289
215
|
};
|
|
290
216
|
}
|
|
291
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Re-selected capabilities keep their saved settings (such as openspec's
|
|
220
|
+
* `protectedBranches`); pickers and flags only name the capabilities.
|
|
221
|
+
*/
|
|
222
|
+
export function keepCapabilitySettings(
|
|
223
|
+
selected: CapabilityConfig[],
|
|
224
|
+
saved: CapabilityConfig[],
|
|
225
|
+
): CapabilityConfig[] {
|
|
226
|
+
const byName = new Map(saved.map((capability) => [capability.name, capability]));
|
|
227
|
+
return selected.map((capability) => {
|
|
228
|
+
// `schemaProfile` is a removed setting; a re-save drops it.
|
|
229
|
+
const { schemaProfile: _removed, ...settings } = (byName.get(capability.name) ??
|
|
230
|
+
{}) as CapabilityConfig & { schemaProfile?: unknown };
|
|
231
|
+
return { ...capability, ...settings };
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
292
235
|
export function dedupeCapabilities(capabilities: CapabilityConfig[]): CapabilityConfig[] {
|
|
293
236
|
const seen = new Set<string>();
|
|
294
237
|
const result: CapabilityConfig[] = [];
|
|
@@ -58,12 +58,12 @@ export interface CliToolConfig {
|
|
|
58
58
|
redirectCwd: "companionRoot" | false;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export type OpenSpecSchemaProfile = "mate-v1" | (string & {});
|
|
62
61
|
export type GitModeProfile = "auto";
|
|
63
62
|
|
|
64
63
|
export interface CapabilityConfig {
|
|
65
64
|
name: string;
|
|
66
|
-
|
|
65
|
+
/** openspec only: branch glob patterns (`release/*`) treated as protected besides the default branch. */
|
|
66
|
+
protectedBranches?: string[];
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export type FrameworkType = "working" | "companion" | "hub";
|