@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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
import { PROJECTED_BANNER_FLAG } from "../../../hooks/session-banner";
|
|
5
4
|
import { getClaudePluginRoot } from "../../../lib/package-paths";
|
|
5
|
+
import { PROJECTED_FLAG } from "../../../runtime/projected-flag";
|
|
6
6
|
import { runtimeClaudePluginRoot } from "../../../runtime/runtime-directory";
|
|
7
7
|
import { hookGroupKey, type ClaudeHookGroup } from "./claude-format";
|
|
8
8
|
|
|
@@ -12,12 +12,11 @@ import { hookGroupKey, type ClaudeHookGroup } from "./claude-format";
|
|
|
12
12
|
* all, so the working-target settings document has to carry it instead.
|
|
13
13
|
*
|
|
14
14
|
* A managed session loads the Working Repository's settings as its `local`
|
|
15
|
-
* source *alongside* the plugin, so every group carried over runs twice there
|
|
16
|
-
*
|
|
17
|
-
* input
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* launch's.
|
|
15
|
+
* source *alongside* the plugin, so every group carried over runs twice there;
|
|
16
|
+
* a plain session may load both too, through `--plugin-dir`. The guard is
|
|
17
|
+
* input-pure, the guidance hook yields under a launch environment, and the
|
|
18
|
+
* banner, prepare and SubagentStart instruction copies carried here hold
|
|
19
|
+
* `PROJECTED_FLAG`, so one copy of each acts.
|
|
21
20
|
*
|
|
22
21
|
* The wiring is read from the installed plugin, but every command names
|
|
23
22
|
* `<mate home>/runtime/claude-plugin`, so a reinstall or Node switch does not
|
|
@@ -28,6 +27,7 @@ const GUARD_HOOK_SHIM = "validate-artifact-path.mjs";
|
|
|
28
27
|
const GUIDANCE_HOOK_SHIM = "session-guidance.mjs";
|
|
29
28
|
const BANNER_HOOK_SHIM = "session-banner.mjs";
|
|
30
29
|
const PREPARE_HOOK_SHIM = "session-prepare.mjs";
|
|
30
|
+
const INSTRUCTIONS_HOOK_SHIM = "companion-instructions.mjs";
|
|
31
31
|
const PLUGIN_ROOT_TOKEN = "${CLAUDE_PLUGIN_ROOT}";
|
|
32
32
|
|
|
33
33
|
interface PluginHookWiring {
|
|
@@ -46,16 +46,23 @@ function readPluginHookWiring(pluginRoot: string): PluginHookWiring {
|
|
|
46
46
|
return {};
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function
|
|
49
|
+
function mapCommands(
|
|
50
|
+
group: ClaudeHookGroup,
|
|
51
|
+
rewrite: (command: string) => string,
|
|
52
|
+
): ClaudeHookGroup {
|
|
50
53
|
return {
|
|
51
54
|
...group,
|
|
52
55
|
hooks: (group.hooks ?? []).map((hook) => ({
|
|
53
56
|
...hook,
|
|
54
|
-
...(hook.command ? { command: hook.command
|
|
57
|
+
...(hook.command ? { command: rewrite(hook.command) } : {}),
|
|
55
58
|
})),
|
|
56
59
|
};
|
|
57
60
|
}
|
|
58
61
|
|
|
62
|
+
function resolveCommands(group: ClaudeHookGroup, pluginRoot: string): ClaudeHookGroup {
|
|
63
|
+
return mapCommands(group, (command) => command.split(PLUGIN_ROOT_TOKEN).join(pluginRoot));
|
|
64
|
+
}
|
|
65
|
+
|
|
59
66
|
function runsShim(group: ClaudeHookGroup, shim: string): boolean {
|
|
60
67
|
return (group.hooks ?? []).some((hook) => (hook.command ?? "").includes(shim));
|
|
61
68
|
}
|
|
@@ -90,31 +97,43 @@ export function mateGuidanceHookGroups(
|
|
|
90
97
|
|
|
91
98
|
/**
|
|
92
99
|
* The banner's `SessionStart` group, resolved the same way and carrying
|
|
93
|
-
* `
|
|
100
|
+
* `PROJECTED_FLAG`. Without the marker the carried command would be
|
|
94
101
|
* byte-identical to the plugin's, and a managed session — which loads both —
|
|
95
102
|
* would print the banner twice.
|
|
96
103
|
*/
|
|
97
104
|
export function mateBannerHookGroups(
|
|
98
105
|
commandRoot: string = runtimeClaudePluginRoot(),
|
|
99
106
|
): ClaudeHookGroup[] {
|
|
100
|
-
return groupsFor("SessionStart", BANNER_HOOK_SHIM, commandRoot)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
return withProjectedFlag(groupsFor("SessionStart", BANNER_HOOK_SHIM, commandRoot));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function withProjectedFlag(groups: ClaudeHookGroup[]): ClaudeHookGroup[] {
|
|
111
|
+
return groups.map((group) => mapCommands(group, (command) => `${command} ${PROJECTED_FLAG}`));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The `SubagentStart` instruction group, resolved the same way and carrying
|
|
116
|
+
* `PROJECTED_FLAG`: a session that loads both this copy and the plugin's,
|
|
117
|
+
* through a launch or `--plugin-dir`, would otherwise deliver the instructions
|
|
118
|
+
* twice.
|
|
119
|
+
*/
|
|
120
|
+
export function mateInstructionHookGroups(
|
|
121
|
+
commandRoot: string = runtimeClaudePluginRoot(),
|
|
122
|
+
): ClaudeHookGroup[] {
|
|
123
|
+
return withProjectedFlag(groupsFor("SubagentStart", INSTRUCTIONS_HOOK_SHIM, commandRoot));
|
|
107
124
|
}
|
|
108
125
|
|
|
109
126
|
/**
|
|
110
127
|
* The session-prepare `SessionStart` group, resolved the same way. Its declared
|
|
111
128
|
* `timeout` sits above the shim's own bound, so Claude Code never kills a
|
|
112
|
-
* prepare the shim has not given up on.
|
|
129
|
+
* prepare the shim has not given up on. It carries `PROJECTED_FLAG`: this copy
|
|
130
|
+
* alone prepares, which it skips under a launch environment, and then delivers
|
|
131
|
+
* the main thread's instructions; the plugin's copy stays inert.
|
|
113
132
|
*/
|
|
114
133
|
export function mateSessionPrepareHookGroups(
|
|
115
134
|
commandRoot: string = runtimeClaudePluginRoot(),
|
|
116
135
|
): ClaudeHookGroup[] {
|
|
117
|
-
return groupsFor("SessionStart", PREPARE_HOOK_SHIM, commandRoot);
|
|
136
|
+
return withProjectedFlag(groupsFor("SessionStart", PREPARE_HOOK_SHIM, commandRoot));
|
|
118
137
|
}
|
|
119
138
|
|
|
120
139
|
function mateOwnHookGroups(commandRoot: string): ClaudeHookGroup[] {
|
|
@@ -123,6 +142,7 @@ function mateOwnHookGroups(commandRoot: string): ClaudeHookGroup[] {
|
|
|
123
142
|
...mateGuidanceHookGroups(commandRoot),
|
|
124
143
|
...mateBannerHookGroups(commandRoot),
|
|
125
144
|
...mateSessionPrepareHookGroups(commandRoot),
|
|
145
|
+
...mateInstructionHookGroups(commandRoot),
|
|
126
146
|
];
|
|
127
147
|
}
|
|
128
148
|
|
|
@@ -4,6 +4,17 @@ import path from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { FRAMEWORK_NAME } from "../../../framework";
|
|
6
6
|
import type { FrameworkConfig } from "../../../lib/orchestrator/types";
|
|
7
|
+
import { getClaudePluginRoot } from "../../../lib/package-paths";
|
|
8
|
+
import { writeAtomicThroughLink } from "../../../runtime/write-atomic";
|
|
9
|
+
import { resolveSecretPolicy } from "../../../runtime/policy";
|
|
10
|
+
import {
|
|
11
|
+
CLAUDE_LOCAL_CONFIG_DOCUMENT,
|
|
12
|
+
CLAUDE_SETTINGS_DOCUMENT,
|
|
13
|
+
renderedDocument,
|
|
14
|
+
type ManagedRegion,
|
|
15
|
+
type RenderedRuntimeDocuments,
|
|
16
|
+
} from "../../../runtime/runtime-document-manifest";
|
|
17
|
+
import { projectableSecretDenyPatterns } from "../../../runtime/secret-patterns";
|
|
7
18
|
import { refreshFromTemplate, stripGuidanceBlock } from "../plugins/guidance";
|
|
8
19
|
import {
|
|
9
20
|
instructionBlockKey,
|
|
@@ -11,9 +22,19 @@ import {
|
|
|
11
22
|
upsertManagedBlock,
|
|
12
23
|
} from "../context-services";
|
|
13
24
|
import type { CapabilityContributionInput, ProviderPlugin, SetupContext } from "../plugin";
|
|
14
|
-
import {
|
|
25
|
+
import { projectionRepoRoot, surfaceRoot } from "../surface-target";
|
|
15
26
|
import { mergeDir, pruneEmptyAncestors } from "../utils";
|
|
16
27
|
import { stripSectionFromFile, type RemoveHeadingSectionOptions } from "./agent-file-sections";
|
|
28
|
+
import {
|
|
29
|
+
claudeUserConfigDir,
|
|
30
|
+
definesUserClaudeAttribution,
|
|
31
|
+
isManagedClaudeAttribution,
|
|
32
|
+
MANAGED_CLAUDE_ATTRIBUTION,
|
|
33
|
+
} from "./claude-attribution";
|
|
34
|
+
import {
|
|
35
|
+
inspectClaudePluginFolders,
|
|
36
|
+
type PublishedClaudePluginFolder,
|
|
37
|
+
} from "./claude-plugin-folders";
|
|
17
38
|
import { patchSkillTreeMarkdownFiles } from "./skill-tree";
|
|
18
39
|
import {
|
|
19
40
|
filterClaudeHookGroups,
|
|
@@ -28,6 +49,13 @@ import {
|
|
|
28
49
|
type ClaudeHookGroup,
|
|
29
50
|
type ClaudeSettings,
|
|
30
51
|
} from "./claude-format";
|
|
52
|
+
import {
|
|
53
|
+
mateBannerHookGroups,
|
|
54
|
+
mateGuardHookGroups,
|
|
55
|
+
mateGuidanceHookGroups,
|
|
56
|
+
mateInstructionHookGroups,
|
|
57
|
+
mateSessionPrepareHookGroups,
|
|
58
|
+
} from "./claude-plugin-hooks";
|
|
31
59
|
import { getSetupRootTemplates } from "./utils";
|
|
32
60
|
|
|
33
61
|
async function configureClaudeGuidance(companionPath: string): Promise<void> {
|
|
@@ -106,6 +134,54 @@ function getAllManagedPermissionEntries(companionPath: string): Set<string> {
|
|
|
106
134
|
]);
|
|
107
135
|
}
|
|
108
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Claude Code features Mate turns off because they compete with its own
|
|
139
|
+
* workflow: plan mode writes plans outside the Companion Repository, the
|
|
140
|
+
* Artifact tool competes with `mate report`, and DesignSync has no role in a
|
|
141
|
+
* Mate session. `ExitPlanMode` stays allowed so a user who enters plan mode
|
|
142
|
+
* by hand can still leave it. Fixed, not configurable.
|
|
143
|
+
*/
|
|
144
|
+
export const MANAGED_CLAUDE_DENY_ENTRIES: readonly string[] = ["EnterPlanMode", "DesignSync"];
|
|
145
|
+
|
|
146
|
+
const SECRET_DENY_TOOLS = ["Read", "Edit"] as const;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Claude deny rules for the default secret files, at any depth. Claude checks
|
|
150
|
+
* deny before allow, so only patterns that can't match an allow-listed file are
|
|
151
|
+
* rendered; the hook enforces the rest of the pattern set. Claude applies
|
|
152
|
+
* `Edit(...)` rules to every built-in file-editing tool, `Write` included, so
|
|
153
|
+
* no `Write(...)` rule is rendered: Claude never matches one and warns about it.
|
|
154
|
+
*/
|
|
155
|
+
export function renderSecretDenyEntries(): string[] {
|
|
156
|
+
return projectableSecretDenyPatterns().flatMap((pattern) =>
|
|
157
|
+
SECRET_DENY_TOOLS.map((tool) => `${tool}(**/${pattern})`),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** The managed `permissions.deny` list: fixed tool denies, plus secret files while guardrails are on. */
|
|
162
|
+
function renderManagedClaudeDenyEntries(companionPath: string): string[] {
|
|
163
|
+
return [
|
|
164
|
+
...MANAGED_CLAUDE_DENY_ENTRIES,
|
|
165
|
+
...(resolveSecretPolicy(companionPath).guardrails ? renderSecretDenyEntries() : []),
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Every deny entry Mate may have written, whatever the current config says, so
|
|
171
|
+
* an opt-out strips the secret entries instead of keeping them as user entries.
|
|
172
|
+
*/
|
|
173
|
+
function getAllManagedDenyEntries(): Set<string> {
|
|
174
|
+
return new Set([
|
|
175
|
+
...MANAGED_CLAUDE_DENY_ENTRIES,
|
|
176
|
+
...renderSecretDenyEntries(),
|
|
177
|
+
// Legacy secret entries: Claude Code never matched Write() rules for file
|
|
178
|
+
// permission checks and warns about them, so setup no longer emits them.
|
|
179
|
+
// Keep them managed so re-running setup strips them from existing installs.
|
|
180
|
+
...projectableSecretDenyPatterns().map((pattern) => `Write(**/${pattern})`),
|
|
181
|
+
]);
|
|
182
|
+
}
|
|
183
|
+
const MANAGED_CLAUDE_FORCED_SETTINGS = { enableArtifact: false } as const;
|
|
184
|
+
|
|
109
185
|
/** Companion-owned Claude settings: sole source of Mate-managed hooks, permissions and MCP servers. */
|
|
110
186
|
export function getCompanionClaudeSettingsPath(companionPath: string): string {
|
|
111
187
|
return path.join(companionPath, ".claude", "settings.local.json");
|
|
@@ -121,7 +197,7 @@ export function getCompanionClaudeMcpConfigPath(companionPath: string): string {
|
|
|
121
197
|
* Rendered separately from the settings document so a working-target pass can
|
|
122
198
|
* obtain them without a write.
|
|
123
199
|
*/
|
|
124
|
-
|
|
200
|
+
function renderManagedClaudePermissionEntries(
|
|
125
201
|
companionPath: string,
|
|
126
202
|
contributions: CapabilityContributionInput[] = [],
|
|
127
203
|
): string[] {
|
|
@@ -134,7 +210,7 @@ export function renderManagedClaudePermissionEntries(
|
|
|
134
210
|
}
|
|
135
211
|
|
|
136
212
|
/** The Mate-managed `.mcp.json` server map of one pass, as a value. */
|
|
137
|
-
|
|
213
|
+
function renderManagedClaudeMcpServers(
|
|
138
214
|
contributions: CapabilityContributionInput[] = [],
|
|
139
215
|
): Record<string, unknown> {
|
|
140
216
|
const servers: Record<string, unknown> = {};
|
|
@@ -151,7 +227,7 @@ export function renderManagedClaudeMcpServers(
|
|
|
151
227
|
* Enabled Capabilities' Claude hook groups per event, in declared order, as a
|
|
152
228
|
* value: what a Claude wrap carries into the Working Repository.
|
|
153
229
|
*/
|
|
154
|
-
|
|
230
|
+
function renderManagedClaudeHookGroups(
|
|
155
231
|
contributions: CapabilityContributionInput[] = [],
|
|
156
232
|
): Record<string, ClaudeHookGroup[]> {
|
|
157
233
|
const hooks: Record<string, ClaudeHookGroup[]> = {};
|
|
@@ -164,23 +240,6 @@ export function renderManagedClaudeHookGroups(
|
|
|
164
240
|
return hooks;
|
|
165
241
|
}
|
|
166
242
|
|
|
167
|
-
/**
|
|
168
|
-
* A layer's Claude settings: the enabled inputs' hook groups and permission
|
|
169
|
-
* entries, nothing of Mate's own. The launch merges them over its base settings.
|
|
170
|
-
*/
|
|
171
|
-
export function renderLayerClaudeSettings(
|
|
172
|
-
contributions: CapabilityContributionInput[] = [],
|
|
173
|
-
): ClaudeSettings {
|
|
174
|
-
const hooks = renderManagedClaudeHookGroups(contributions);
|
|
175
|
-
const allow = contributions
|
|
176
|
-
.filter((input) => input.enabled)
|
|
177
|
-
.flatMap((input) => input.contributions.permissionEntries ?? []);
|
|
178
|
-
return {
|
|
179
|
-
...(Object.keys(hooks).length > 0 ? { hooks } : {}),
|
|
180
|
-
...(allow.length > 0 ? { permissions: { allow } } : {}),
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
243
|
// Reconcile the Mate-managed Claude settings shape (hooks, permissions, MCP
|
|
185
244
|
// servers) on top of whatever already exists in the settings document. Managed
|
|
186
245
|
// groups/entries always lead their arrays so the emitted shape stays stable
|
|
@@ -190,6 +249,7 @@ function renderManagedClaudeSettings(
|
|
|
190
249
|
companionPath: string,
|
|
191
250
|
config: FrameworkConfig,
|
|
192
251
|
contributions: CapabilityContributionInput[] = [],
|
|
252
|
+
userDefinesAttribution: boolean,
|
|
193
253
|
): ClaudeSettings {
|
|
194
254
|
// Declared markers and permission entries widen the managed strip set for
|
|
195
255
|
// every registered Capability, enabled or not, so deselection tears down.
|
|
@@ -238,6 +298,13 @@ function renderManagedClaudeSettings(
|
|
|
238
298
|
} else {
|
|
239
299
|
delete permissions.allow;
|
|
240
300
|
}
|
|
301
|
+
// permissions.deny: same reconciliation as allow, against the fixed set.
|
|
302
|
+
const managedDeny = getAllManagedDenyEntries();
|
|
303
|
+
const existingDeny = Array.isArray(existingPermissions.deny) ? existingPermissions.deny : [];
|
|
304
|
+
permissions.deny = [
|
|
305
|
+
...existingDeny.filter((entry) => !managedDeny.has(entry)),
|
|
306
|
+
...renderManagedClaudeDenyEntries(companionPath),
|
|
307
|
+
];
|
|
241
308
|
|
|
242
309
|
const mcpServers = { ...existing.mcpServers };
|
|
243
310
|
// tokensave (and any future Mate-managed MCP server) now lives in the
|
|
@@ -245,7 +312,12 @@ function renderManagedClaudeSettings(
|
|
|
245
312
|
// entry is removed so it cannot shadow the `.mcp.json` definition.
|
|
246
313
|
delete mcpServers.tokensave;
|
|
247
314
|
|
|
248
|
-
const settings: ClaudeSettings = {
|
|
315
|
+
const settings: ClaudeSettings = {
|
|
316
|
+
...existing,
|
|
317
|
+
hooks,
|
|
318
|
+
autoMemoryEnabled: false,
|
|
319
|
+
...MANAGED_CLAUDE_FORCED_SETTINGS,
|
|
320
|
+
};
|
|
249
321
|
if (Object.keys(hooks).length === 0) {
|
|
250
322
|
delete settings.hooks;
|
|
251
323
|
}
|
|
@@ -259,10 +331,190 @@ function renderManagedClaudeSettings(
|
|
|
259
331
|
} else {
|
|
260
332
|
delete settings.mcpServers;
|
|
261
333
|
}
|
|
334
|
+
/** The document's own value is kept; Mate's yields to one the user scope sets. */
|
|
335
|
+
if (!("attribution" in existing) || isManagedClaudeAttribution(existing.attribution)) {
|
|
336
|
+
if (userDefinesAttribution) delete settings.attribution;
|
|
337
|
+
else settings.attribution = { ...MANAGED_CLAUDE_ATTRIBUTION };
|
|
338
|
+
}
|
|
262
339
|
|
|
263
340
|
return settings;
|
|
264
341
|
}
|
|
265
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Loaded by a managed session beside the launch's plugin, so each Mate hook
|
|
345
|
+
* here runs twice there: the guard is input-pure, guidance yields under a
|
|
346
|
+
* launch env, and the banner, prepare and instruction copies carry
|
|
347
|
+
* `--projected`, so one copy of each acts. Capability groups run once: the
|
|
348
|
+
* launch omits them from `--settings`.
|
|
349
|
+
*
|
|
350
|
+
* `permissions.additionalDirectories` grants companion file access only; it
|
|
351
|
+
* loads no `CLAUDE.md`.
|
|
352
|
+
*
|
|
353
|
+
* Unlike {@link renderManagedClaudeSettings}, this carries no
|
|
354
|
+
* `autoMemoryEnabled: false`. Whether a Wrap should leave the user's choice
|
|
355
|
+
* alone there is an open question, not settled policy.
|
|
356
|
+
*/
|
|
357
|
+
function claudeSettingsRegions(
|
|
358
|
+
ctx: SetupContext,
|
|
359
|
+
inputs: CapabilityContributionInput[],
|
|
360
|
+
repoRoot: string,
|
|
361
|
+
pluginFolders: readonly PublishedClaudePluginFolder[],
|
|
362
|
+
): ManagedRegion[] {
|
|
363
|
+
const capabilityHooks = renderManagedClaudeHookGroups(inputs);
|
|
364
|
+
const mateHooks: Record<string, unknown[]> = {
|
|
365
|
+
PreToolUse: mateGuardHookGroups(),
|
|
366
|
+
SessionStart: [
|
|
367
|
+
...mateBannerHookGroups(),
|
|
368
|
+
...mateGuidanceHookGroups(),
|
|
369
|
+
...mateSessionPrepareHookGroups(),
|
|
370
|
+
],
|
|
371
|
+
SubagentStart: mateInstructionHookGroups(),
|
|
372
|
+
};
|
|
373
|
+
const events = [...new Set([...Object.keys(mateHooks), ...Object.keys(capabilityHooks)])];
|
|
374
|
+
return [
|
|
375
|
+
...events.map((event): ManagedRegion => ({
|
|
376
|
+
at: ["hooks", event],
|
|
377
|
+
kind: "list",
|
|
378
|
+
values: [...(mateHooks[event] ?? []), ...(capabilityHooks[event] ?? [])],
|
|
379
|
+
})),
|
|
380
|
+
/**
|
|
381
|
+
* `stripPrefix` heals a repository an older Mate wrapped. That version wrote
|
|
382
|
+
* the whole launch environment here, and Claude Code applies `env` to the
|
|
383
|
+
* session, so every hook in a bare session inherited `MATE_*` and read the
|
|
384
|
+
* repository as a Managed Session — silently, since looking managed is
|
|
385
|
+
* exactly what makes the guidance hook emit nothing. Guidance must be the
|
|
386
|
+
* projection's to give in an Unmanaged Session, so no `MATE_*` key may
|
|
387
|
+
* survive here. It sets no entry of its own: the
|
|
388
|
+
* `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD` an earlier wrap set is
|
|
389
|
+
* reverted from the manifest, so a user's own value stays.
|
|
390
|
+
*/
|
|
391
|
+
{
|
|
392
|
+
at: ["env"],
|
|
393
|
+
kind: "map",
|
|
394
|
+
entries: {},
|
|
395
|
+
stripPrefix: "MATE_",
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
at: ["permissions", "allow"],
|
|
399
|
+
kind: "list",
|
|
400
|
+
values: renderManagedClaudePermissionEntries(ctx.companionPath, inputs),
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
at: ["permissions", "deny"],
|
|
404
|
+
kind: "list",
|
|
405
|
+
values: renderManagedClaudeDenyEntries(ctx.companionPath),
|
|
406
|
+
},
|
|
407
|
+
...claudePluginRegions(pluginFolders),
|
|
408
|
+
/**
|
|
409
|
+
* Yields: the document is the user's, so their own `enableArtifact` wins,
|
|
410
|
+
* and unwrapping restores it instead of deleting a key Mate overwrote.
|
|
411
|
+
*/
|
|
412
|
+
...Object.entries(MANAGED_CLAUDE_FORCED_SETTINGS).map(([key, value]): ManagedRegion => ({
|
|
413
|
+
at: [key],
|
|
414
|
+
kind: "value",
|
|
415
|
+
value,
|
|
416
|
+
yields: true,
|
|
417
|
+
})),
|
|
418
|
+
/**
|
|
419
|
+
* Placed only while no scope sets attribution: a project-scope value would
|
|
420
|
+
* lose to this local one, yielding or not. Mate's own earlier value does
|
|
421
|
+
* not count as the user's.
|
|
422
|
+
*/
|
|
423
|
+
...(definesUserClaudeAttribution({ repoRoot })
|
|
424
|
+
? []
|
|
425
|
+
: [
|
|
426
|
+
{
|
|
427
|
+
at: ["attribution"],
|
|
428
|
+
kind: "value",
|
|
429
|
+
value: { ...MANAGED_CLAUDE_ATTRIBUTION },
|
|
430
|
+
yields: true,
|
|
431
|
+
} satisfies ManagedRegion,
|
|
432
|
+
]),
|
|
433
|
+
];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Each published plugin folder as a local `directory` marketplace and its one
|
|
438
|
+
* enabled plugin, so a plain session in a trusted folder loads it in place. The
|
|
439
|
+
* path is the folder as the launch passes it, so the wrap state can name what
|
|
440
|
+
* the launch must leave to the wrap.
|
|
441
|
+
*/
|
|
442
|
+
function claudePluginRegions(published: readonly PublishedClaudePluginFolder[]): ManagedRegion[] {
|
|
443
|
+
return [
|
|
444
|
+
{
|
|
445
|
+
at: ["extraKnownMarketplaces"],
|
|
446
|
+
kind: "map",
|
|
447
|
+
entries: Object.fromEntries(
|
|
448
|
+
published.map(({ path: folder, marketplace }) => [
|
|
449
|
+
marketplace,
|
|
450
|
+
{ source: { source: "directory", path: folder } },
|
|
451
|
+
]),
|
|
452
|
+
),
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
at: ["enabledPlugins"],
|
|
456
|
+
kind: "map",
|
|
457
|
+
entries: Object.fromEntries(
|
|
458
|
+
published.map(({ plugin, marketplace }) => [`${plugin}@${marketplace}`, true]),
|
|
459
|
+
),
|
|
460
|
+
},
|
|
461
|
+
];
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* The working target's Claude documents, rendered as values. Each is a document
|
|
466
|
+
* the runtime finds by walking up from the current directory, and every path
|
|
467
|
+
* inside one still names the Companion Repository — only where the document is
|
|
468
|
+
* placed differs from the companion target.
|
|
469
|
+
*/
|
|
470
|
+
export async function renderClaudeWorkingDocuments(
|
|
471
|
+
ctx: SetupContext,
|
|
472
|
+
inputs: CapabilityContributionInput[],
|
|
473
|
+
): Promise<RenderedRuntimeDocuments> {
|
|
474
|
+
const repoRoot = projectionRepoRoot(ctx);
|
|
475
|
+
/** Reads the folders only; the pass published them before this render. */
|
|
476
|
+
const pluginFolders = (
|
|
477
|
+
await inspectClaudePluginFolders(inputs, { bundledPluginRoot: getClaudePluginRoot() })
|
|
478
|
+
).published;
|
|
479
|
+
return {
|
|
480
|
+
documents: [
|
|
481
|
+
...renderedDocument(
|
|
482
|
+
CLAUDE_SETTINGS_DOCUMENT,
|
|
483
|
+
claudeSettingsRegions(ctx, inputs, repoRoot, pluginFolders),
|
|
484
|
+
),
|
|
485
|
+
/**
|
|
486
|
+
* Local scope, not `.mcp.json`: a project-scoped server is inert until a
|
|
487
|
+
* human approves it in a session, which an Unmanaged Session is exactly the
|
|
488
|
+
* case that cannot rely on. The repo path is the key Claude Code files a
|
|
489
|
+
* project under, resolved so a symlinked working directory still matches.
|
|
490
|
+
*
|
|
491
|
+
* Confirmed against a real `~/.claude.json`: the keys there are the
|
|
492
|
+
* directories sessions started in, not repository roots — sibling
|
|
493
|
+
* directories of one checkout each hold their own entry, as do temporary
|
|
494
|
+
* directories. So this reaches exactly one session: the one started at the
|
|
495
|
+
* repository root. A session started in a subdirectory of a wrapped
|
|
496
|
+
* repository has its own key, finds no `mcpServers` under it, and sees none
|
|
497
|
+
* of these servers — the Unmanaged Session case this document exists for,
|
|
498
|
+
* missed. That limit is deliberate. The directories a session might start
|
|
499
|
+
* in are unbounded, and every one of them would be a fresh entry in the
|
|
500
|
+
* user's global configuration that nothing later reclaims; keying the
|
|
501
|
+
* repository root only keeps the projection's footprint there to a single
|
|
502
|
+
* key. A subdirectory session still gets the rest of the projection — the
|
|
503
|
+
* documents inside the repository are found by the runtime's own upward
|
|
504
|
+
* walk — it loses only the MCP servers.
|
|
505
|
+
*/
|
|
506
|
+
...renderedDocument(CLAUDE_LOCAL_CONFIG_DOCUMENT, [
|
|
507
|
+
{
|
|
508
|
+
at: ["projects", repoRoot, "mcpServers"],
|
|
509
|
+
kind: "map",
|
|
510
|
+
entries: renderManagedClaudeMcpServers(inputs),
|
|
511
|
+
},
|
|
512
|
+
]),
|
|
513
|
+
],
|
|
514
|
+
warnings: [],
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
|
|
266
518
|
// Write the Mate-managed Claude settings into the companion repo. This is the
|
|
267
519
|
// config surface Mate owns and loads at launch via `--settings`, so hooks,
|
|
268
520
|
// permissions, and MCP servers no longer need to live in the working repo.
|
|
@@ -270,10 +522,17 @@ export async function syncCompanionClaudeSettings(
|
|
|
270
522
|
companionPath: string,
|
|
271
523
|
config: FrameworkConfig,
|
|
272
524
|
contributions: CapabilityContributionInput[] = [],
|
|
525
|
+
env: Record<string, string | undefined> = process.env,
|
|
273
526
|
): Promise<void> {
|
|
274
527
|
const settingsPath = getCompanionClaudeSettingsPath(companionPath);
|
|
275
528
|
const existing = await readClaudeSettings(settingsPath);
|
|
276
|
-
const settings = renderManagedClaudeSettings(
|
|
529
|
+
const settings = renderManagedClaudeSettings(
|
|
530
|
+
existing,
|
|
531
|
+
companionPath,
|
|
532
|
+
config,
|
|
533
|
+
contributions,
|
|
534
|
+
definesUserClaudeAttribution({ userConfigDir: claudeUserConfigDir(env) }),
|
|
535
|
+
);
|
|
277
536
|
|
|
278
537
|
await writeClaudeSettings(settingsPath, settings);
|
|
279
538
|
|
|
@@ -304,15 +563,7 @@ export async function reconcileClaudeContributions(
|
|
|
304
563
|
// The settings sync (re)creates the managed settings document, so it only
|
|
305
564
|
// runs while the Claude runtime is active; a deactivated runtime's pass is
|
|
306
565
|
// teardown-only and must not resurrect files the provider teardown removed.
|
|
307
|
-
|
|
308
|
-
// launch to merge into its one `--settings` file.
|
|
309
|
-
if (projectionTarget(ctx) === "audience-layer") {
|
|
310
|
-
await writeClaudeSettings(
|
|
311
|
-
getCompanionClaudeSettingsPath(root),
|
|
312
|
-
renderLayerClaudeSettings(inputs),
|
|
313
|
-
);
|
|
314
|
-
await syncCompanionClaudeMcpConfig(root);
|
|
315
|
-
} else if (ctx.activeProviders.includes("claude")) {
|
|
566
|
+
if (ctx.activeProviders.includes("claude")) {
|
|
316
567
|
await syncCompanionClaudeSettings(root, config, inputs);
|
|
317
568
|
}
|
|
318
569
|
|
|
@@ -420,7 +671,7 @@ async function configureClaude(companionPath: string): Promise<void> {
|
|
|
420
671
|
try {
|
|
421
672
|
await fs.access(agentsMdDest);
|
|
422
673
|
} catch {
|
|
423
|
-
await fs.
|
|
674
|
+
await writeAtomicThroughLink(agentsMdDest, await fs.readFile(agentsMdSrc));
|
|
424
675
|
}
|
|
425
676
|
|
|
426
677
|
const claudeMdSrc = path.join(getSetupRootTemplates(), "TEMPLATE_CLAUDE.md");
|
|
@@ -428,7 +679,7 @@ async function configureClaude(companionPath: string): Promise<void> {
|
|
|
428
679
|
try {
|
|
429
680
|
await fs.access(claudeMdDest);
|
|
430
681
|
} catch {
|
|
431
|
-
await fs.
|
|
682
|
+
await writeAtomicThroughLink(claudeMdDest, await fs.readFile(claudeMdSrc));
|
|
432
683
|
}
|
|
433
684
|
}
|
|
434
685
|
|