@fitlab-ai/agent-infra 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -4
- package/README.zh-CN.md +16 -4
- package/bin/cli.ts +12 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/internal-cli.js +15 -0
- package/dist/lib/agent-client.js +163 -0
- package/dist/lib/agent-clients/adapter.js +294 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +62 -0
- package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
- package/dist/lib/agent-clients/adapters/codex.js +54 -0
- package/dist/lib/agent-clients/adapters/gemini-cli.js +64 -0
- package/dist/lib/agent-clients/adapters/index.js +20 -0
- package/dist/lib/agent-clients/adapters/opencode.js +64 -0
- package/dist/lib/agent-clients/config.js +177 -0
- package/dist/lib/agent-clients/custom-tuis.js +99 -0
- package/dist/lib/agent-clients/invocation.js +9 -0
- package/dist/lib/agent-clients/next-steps.js +38 -0
- package/dist/lib/agent-clients/project-assets.js +45 -0
- package/dist/lib/agent-clients/reconcile.js +235 -0
- package/dist/lib/agent-clients/registry.js +72 -0
- package/dist/lib/agent-clients/schema.js +57 -0
- package/dist/lib/agent-clients/types.js +29 -0
- package/dist/lib/builtin-tuis.js +9 -14
- package/dist/lib/defaults.json +85 -73
- package/dist/lib/git/review-snapshot.js +25 -10
- package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
- package/dist/lib/init.js +47 -91
- package/dist/lib/internal/agent-client.js +117 -0
- package/dist/lib/internal/git-workflow.js +1 -1
- package/dist/lib/internal/release-workflow.js +71 -16
- package/dist/lib/internal/task-orchestration.js +151 -0
- package/dist/lib/internal/task-review.js +65 -0
- package/dist/lib/merge.js +2 -1
- package/dist/lib/platform/adapters.js +38 -1
- package/dist/lib/platform/change-request-git-evidence.js +113 -0
- package/dist/lib/platform/merged-pr-equivalence.js +41 -11
- package/dist/lib/platform/pr-checks.js +38 -10
- package/dist/lib/platform/pull-requests.js +110 -6
- package/dist/lib/platform/releases.js +1 -1
- package/dist/lib/platform/verification-required.js +8 -10
- package/dist/lib/prompt.js +15 -3
- package/dist/lib/release/channels.js +4 -1
- package/dist/lib/release/workflow.js +4 -2
- package/dist/lib/remove-dir.js +25 -0
- package/dist/lib/run/tui.js +8 -2
- package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
- package/dist/lib/sandbox/clipboard/linux.js +2 -1
- package/dist/lib/sandbox/commands/create.js +76 -180
- package/dist/lib/sandbox/commands/enter.js +17 -1
- package/dist/lib/sandbox/commands/prune.js +2 -2
- package/dist/lib/sandbox/commands/rm.js +3 -2
- package/dist/lib/sandbox/config.js +21 -4
- package/dist/lib/sandbox/constants.js +3 -0
- package/dist/lib/sandbox/dockerfile.js +2 -1
- package/dist/lib/sandbox/managed-fs.js +10 -5
- package/dist/lib/sandbox/recovery.js +52 -36
- package/dist/lib/sandbox/shell.js +1 -1
- package/dist/lib/sandbox/tool-types.js +8 -0
- package/dist/lib/sandbox/tools.js +2 -126
- package/dist/lib/task/artifact-lifecycle.js +1 -49
- package/dist/lib/task/commands/decisions.js +50 -20
- package/dist/lib/task/delegation-receipts.js +107 -0
- package/dist/lib/task/events.js +100 -1
- package/dist/lib/task/orchestration.js +420 -0
- package/dist/lib/task/review-artifacts.js +143 -59
- package/dist/lib/task/review-finalization.js +166 -0
- package/dist/lib/task/review-fingerprint.js +4 -0
- package/dist/lib/task/verification-checks.js +2 -1
- package/dist/lib/task/verification-engine.js +156 -28
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/verification.js +3 -1
- package/dist/lib/task/workspace-snapshot.js +34 -0
- package/dist/lib/update.js +42 -161
- package/lib/agent-client.ts +214 -0
- package/lib/agent-clients/adapter.ts +461 -0
- package/lib/agent-clients/adapters/claude-code.ts +70 -0
- package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
- package/lib/agent-clients/adapters/codex.ts +58 -0
- package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
- package/lib/agent-clients/adapters/index.ts +27 -0
- package/lib/agent-clients/adapters/opencode.ts +66 -0
- package/lib/agent-clients/config.ts +278 -0
- package/lib/agent-clients/custom-tuis.ts +149 -0
- package/lib/agent-clients/invocation.ts +19 -0
- package/lib/agent-clients/next-steps.ts +72 -0
- package/lib/agent-clients/project-assets.ts +96 -0
- package/lib/agent-clients/reconcile.ts +324 -0
- package/lib/agent-clients/registry.ts +144 -0
- package/lib/agent-clients/schema.ts +62 -0
- package/lib/agent-clients/types.ts +78 -0
- package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
- package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
- package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
- package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
- package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
- package/lib/builtin-tuis.ts +16 -15
- package/lib/defaults.json +24 -12
- package/lib/git/review-snapshot.ts +39 -9
- package/lib/git/reviewed-commit-equivalence.ts +135 -0
- package/lib/init.ts +53 -121
- package/lib/internal/agent-client.ts +131 -0
- package/lib/internal/git-workflow.ts +1 -1
- package/lib/internal/release-workflow.ts +68 -16
- package/lib/internal/task-orchestration.ts +132 -0
- package/lib/internal/task-review.ts +65 -0
- package/lib/merge.ts +2 -1
- package/lib/platform/adapters.ts +142 -3
- package/lib/platform/change-request-git-evidence.ts +159 -0
- package/lib/platform/merged-pr-equivalence.ts +51 -14
- package/lib/platform/pr-checks.ts +50 -22
- package/lib/platform/pull-requests.ts +134 -25
- package/lib/platform/releases.ts +1 -1
- package/lib/platform/verification-required.ts +12 -10
- package/lib/prompt.ts +16 -3
- package/lib/release/channels.ts +4 -1
- package/lib/release/workflow.ts +4 -3
- package/lib/remove-dir.ts +28 -0
- package/lib/run/tui.ts +9 -1
- package/lib/sandbox/agent-client-reconciler.ts +378 -0
- package/lib/sandbox/clipboard/linux.ts +2 -1
- package/lib/sandbox/commands/create.ts +111 -192
- package/lib/sandbox/commands/enter.ts +23 -1
- package/lib/sandbox/commands/prune.ts +2 -2
- package/lib/sandbox/commands/rm.ts +3 -2
- package/lib/sandbox/config.ts +31 -4
- package/lib/sandbox/constants.ts +6 -0
- package/lib/sandbox/dockerfile.ts +2 -1
- package/lib/sandbox/managed-fs.ts +18 -5
- package/lib/sandbox/recovery.ts +98 -67
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/tool-types.ts +143 -0
- package/lib/sandbox/tools.ts +5 -157
- package/lib/task/artifact-lifecycle.ts +1 -38
- package/lib/task/commands/decisions.ts +53 -20
- package/lib/task/delegation-receipts.ts +170 -0
- package/lib/task/events.ts +110 -2
- package/lib/task/orchestration.ts +543 -0
- package/lib/task/review-artifacts.ts +201 -69
- package/lib/task/review-finalization.ts +275 -0
- package/lib/task/review-fingerprint.ts +5 -0
- package/lib/task/verification-checks.ts +2 -1
- package/lib/task/verification-engine.ts +177 -28
- package/lib/task/verification-review.ts +1 -0
- package/lib/task/verification.ts +5 -2
- package/lib/task/workspace-snapshot.ts +36 -0
- package/lib/update.ts +48 -184
- package/package.json +2 -2
- package/templates/.agents/README.en.md +21 -20
- package/templates/.agents/README.zh-CN.md +21 -20
- package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/commit-and-pr.en.md +1 -0
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
- package/templates/.agents/rules/human-decision-context.en.md +14 -12
- package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
- package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
- package/templates/.agents/rules/next-step-output.en.md +16 -0
- package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
- package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
- package/templates/.agents/rules/release-commands.github.en.md +11 -5
- package/templates/.agents/rules/release-commands.github.zh-CN.md +11 -5
- package/templates/.agents/rules/review-handshake.en.md +4 -4
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
- package/templates/.agents/rules/review-method.en.md +113 -0
- package/templates/.agents/rules/review-method.zh-CN.md +98 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
- package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
- package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/SKILL.en.md +11 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
- package/templates/.agents/skills/create-task/SKILL.en.md +11 -11
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +11 -11
- package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
- package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
- package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
- package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
- package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
- package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
- package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
- package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
- package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
- package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
- package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
- package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
- package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
- package/templates/.agents/skills/test/SKILL.en.md +4 -4
- package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
- package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
- package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
- package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
- package/templates/.claude/commands/run-task.en.md +8 -0
- package/templates/.claude/commands/run-task.zh-CN.md +8 -0
- package/templates/.claude/settings.json +24 -0
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
- package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
- package/templates/.opencode/commands/run-task.en.md +11 -0
- package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
|
@@ -28,17 +28,35 @@ const DEFAULTS = {
|
|
|
28
28
|
"platform": {
|
|
29
29
|
"type": "github"
|
|
30
30
|
},
|
|
31
|
+
"agentClients": [
|
|
32
|
+
{
|
|
33
|
+
"id": "claude-code",
|
|
34
|
+
"enabled": true,
|
|
35
|
+
"installInSandbox": true
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "codex",
|
|
39
|
+
"enabled": true,
|
|
40
|
+
"installInSandbox": true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "gemini-cli",
|
|
44
|
+
"enabled": true,
|
|
45
|
+
"installInSandbox": true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "opencode",
|
|
49
|
+
"enabled": true,
|
|
50
|
+
"installInSandbox": true
|
|
51
|
+
}
|
|
52
|
+
],
|
|
31
53
|
"sandbox": {
|
|
32
54
|
"engine": null,
|
|
33
55
|
"runtimes": [
|
|
34
56
|
"node22"
|
|
35
57
|
],
|
|
36
58
|
"tools": [
|
|
37
|
-
"agent-infra"
|
|
38
|
-
"claude-code",
|
|
39
|
-
"codex",
|
|
40
|
-
"gemini-cli",
|
|
41
|
-
"opencode"
|
|
59
|
+
"agent-infra"
|
|
42
60
|
],
|
|
43
61
|
"refreshIntervalDays": 7,
|
|
44
62
|
"dockerfile": null,
|
|
@@ -65,16 +83,12 @@ const DEFAULTS = {
|
|
|
65
83
|
".agents/templates/",
|
|
66
84
|
".agents/workflows/",
|
|
67
85
|
".agents/workspace/README.md",
|
|
68
|
-
".claude/commands/",
|
|
69
|
-
".codex/hooks.json",
|
|
70
|
-
".gemini/commands/",
|
|
71
86
|
".git-hooks/check-large-files.cjs",
|
|
72
87
|
".git-hooks/check-version-format.sh",
|
|
73
88
|
".github/scripts/",
|
|
74
89
|
".github/workflows/metadata-sync.yml",
|
|
75
90
|
".github/workflows/pr-label.yml",
|
|
76
|
-
".github/workflows/status-label.yml"
|
|
77
|
-
".opencode/commands/"
|
|
91
|
+
".github/workflows/status-label.yml"
|
|
78
92
|
],
|
|
79
93
|
"guardedManaged": [
|
|
80
94
|
".github/workflows/metadata-sync.yml",
|
|
@@ -93,8 +107,6 @@ const DEFAULTS = {
|
|
|
93
107
|
".agents/skills/test-integration/SKILL.*",
|
|
94
108
|
".agents/skills/test/SKILL.*",
|
|
95
109
|
".agents/skills/upgrade-dependency/SKILL.*",
|
|
96
|
-
".claude/settings.json",
|
|
97
|
-
".gemini/settings.json",
|
|
98
110
|
".git-hooks/pre-commit",
|
|
99
111
|
".gitignore"
|
|
100
112
|
],
|
|
@@ -102,64 +114,283 @@ const DEFAULTS = {
|
|
|
102
114
|
}
|
|
103
115
|
};
|
|
104
116
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
const AGENT_CLIENT_MANIFEST = [
|
|
118
|
+
{
|
|
119
|
+
"id": "claude-code",
|
|
120
|
+
"displayName": "Claude Code",
|
|
121
|
+
"invocation": "/${skillName}",
|
|
122
|
+
"ownedPathPrefixes": [
|
|
123
|
+
".claude/"
|
|
124
|
+
],
|
|
125
|
+
"managed": [
|
|
126
|
+
".claude/commands/",
|
|
127
|
+
".claude/agents/"
|
|
128
|
+
],
|
|
129
|
+
"merged": [
|
|
130
|
+
".claude/settings.json"
|
|
131
|
+
],
|
|
132
|
+
"ejected": []
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "codex",
|
|
136
|
+
"displayName": "Codex",
|
|
137
|
+
"invocation": "$${skillName}",
|
|
138
|
+
"ownedPathPrefixes": [
|
|
139
|
+
".codex/"
|
|
140
|
+
],
|
|
141
|
+
"managed": [
|
|
142
|
+
".codex/hooks.json",
|
|
143
|
+
".codex/agents/"
|
|
144
|
+
],
|
|
145
|
+
"merged": [],
|
|
146
|
+
"ejected": []
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "gemini-cli",
|
|
150
|
+
"displayName": "Gemini CLI",
|
|
151
|
+
"invocation": "/${projectName}:${skillName}",
|
|
152
|
+
"ownedPathPrefixes": [
|
|
153
|
+
".gemini/"
|
|
154
|
+
],
|
|
155
|
+
"managed": [
|
|
156
|
+
".gemini/commands/"
|
|
157
|
+
],
|
|
158
|
+
"merged": [
|
|
159
|
+
".gemini/settings.json"
|
|
160
|
+
],
|
|
161
|
+
"ejected": []
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"id": "opencode",
|
|
165
|
+
"displayName": "OpenCode",
|
|
166
|
+
"invocation": "/${skillName}",
|
|
167
|
+
"ownedPathPrefixes": [
|
|
168
|
+
".opencode/"
|
|
169
|
+
],
|
|
170
|
+
"managed": [
|
|
171
|
+
".opencode/commands/"
|
|
172
|
+
],
|
|
173
|
+
"merged": [],
|
|
174
|
+
"ejected": []
|
|
175
|
+
}
|
|
176
|
+
];
|
|
177
|
+
const CUSTOM_TUI_CONTRACT = {
|
|
178
|
+
"requiredFields": [
|
|
179
|
+
"name",
|
|
180
|
+
"dir",
|
|
181
|
+
"invoke"
|
|
182
|
+
],
|
|
183
|
+
"allowedPlaceholders": [
|
|
184
|
+
"skillName",
|
|
185
|
+
"projectName"
|
|
186
|
+
]
|
|
187
|
+
};
|
|
108
188
|
// Add a new identifier here only after shipping matching .{platform}. template variants.
|
|
109
189
|
const KNOWN_PLATFORMS = new Set(['github', 'none']);
|
|
110
190
|
const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
|
|
111
191
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
192
|
+
const BUILTIN_TUI_IDS = AGENT_CLIENT_MANIFEST.map((entry) => entry.id);
|
|
193
|
+
|
|
194
|
+
function normalizeAgentClientConfig(cfg) {
|
|
195
|
+
const own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
196
|
+
const diagnostics = [];
|
|
197
|
+
const failure = (code, path) => ({
|
|
198
|
+
source: null,
|
|
199
|
+
state: null,
|
|
200
|
+
canonical: null,
|
|
201
|
+
remainingSandboxTools: undefined,
|
|
202
|
+
removeLegacyTuis: false,
|
|
203
|
+
changed: false,
|
|
204
|
+
diagnostics,
|
|
205
|
+
error: `${code} at ${path}`,
|
|
206
|
+
errorCode: code,
|
|
207
|
+
errorPath: path
|
|
208
|
+
});
|
|
209
|
+
const projectTuis = (value) => {
|
|
210
|
+
if (!Array.isArray(value)) {
|
|
211
|
+
return Object.fromEntries(BUILTIN_TUI_IDS.map((id) => [id, true]));
|
|
212
|
+
}
|
|
213
|
+
const enabled = new Set();
|
|
214
|
+
for (const [index, candidate] of value.entries()) {
|
|
215
|
+
if (BUILTIN_TUI_IDS.includes(candidate)) enabled.add(candidate);
|
|
216
|
+
else diagnostics.push({ code: 'LEGACY_VALUE_IGNORED', path: `tuis[${index}]` });
|
|
217
|
+
}
|
|
218
|
+
return Object.fromEntries(BUILTIN_TUI_IDS.map((id) => [id, enabled.has(id)]));
|
|
219
|
+
};
|
|
220
|
+
const projectSandbox = (value) => {
|
|
221
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
222
|
+
return {
|
|
223
|
+
installed: Object.fromEntries(BUILTIN_TUI_IDS.map((id) => [id, true])),
|
|
224
|
+
clientSignals: new Set(),
|
|
225
|
+
remainingTools: Array.isArray(value) ? [] : undefined
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const installed = new Set();
|
|
229
|
+
const remainingTools = [];
|
|
230
|
+
for (const [index, candidate] of value.entries()) {
|
|
231
|
+
if (BUILTIN_TUI_IDS.includes(candidate)) installed.add(candidate);
|
|
232
|
+
else if (typeof candidate === 'string') remainingTools.push(candidate);
|
|
233
|
+
else diagnostics.push({ code: 'LEGACY_VALUE_IGNORED', path: `sandbox.tools[${index}]` });
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
installed: Object.fromEntries(BUILTIN_TUI_IDS.map((id) => [id, installed.has(id)])),
|
|
237
|
+
clientSignals: installed,
|
|
238
|
+
remainingTools
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
const serialize = (state) => BUILTIN_TUI_IDS.map((id) => ({ id, ...state[id] }));
|
|
242
|
+
const hasCanonical = own(cfg, 'agentClients');
|
|
243
|
+
const hasLegacyTuis = own(cfg, 'tuis');
|
|
244
|
+
const sandbox = cfg.sandbox && typeof cfg.sandbox === 'object' && !Array.isArray(cfg.sandbox)
|
|
245
|
+
? cfg.sandbox
|
|
246
|
+
: undefined;
|
|
247
|
+
const hasSandboxTools = sandbox !== undefined && own(sandbox, 'tools');
|
|
248
|
+
const tuiProjection = projectTuis(cfg.tuis);
|
|
249
|
+
const sandboxProjection = projectSandbox(sandbox?.tools);
|
|
250
|
+
|
|
251
|
+
if (!hasCanonical) {
|
|
252
|
+
const state = Object.fromEntries(BUILTIN_TUI_IDS.map((id) => [id, {
|
|
253
|
+
enabled: tuiProjection[id],
|
|
254
|
+
installInSandbox: sandboxProjection.installed[id]
|
|
255
|
+
}]));
|
|
256
|
+
return {
|
|
257
|
+
source: 'legacy',
|
|
258
|
+
state,
|
|
259
|
+
canonical: serialize(state),
|
|
260
|
+
remainingSandboxTools: sandboxProjection.remainingTools,
|
|
261
|
+
removeLegacyTuis: hasLegacyTuis,
|
|
262
|
+
changed: true,
|
|
263
|
+
diagnostics,
|
|
264
|
+
error: null,
|
|
265
|
+
errorCode: null,
|
|
266
|
+
errorPath: null
|
|
267
|
+
};
|
|
129
268
|
}
|
|
130
|
-
return set;
|
|
131
|
-
}
|
|
132
269
|
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
for (const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
270
|
+
if (!Array.isArray(cfg.agentClients)) return failure('INVALID_AGENT_CLIENTS', 'agentClients');
|
|
271
|
+
const entries = new Map();
|
|
272
|
+
for (const [index, candidate] of cfg.agentClients.entries()) {
|
|
273
|
+
const entryPath = `agentClients[${index}]`;
|
|
274
|
+
if (typeof candidate !== 'object' || candidate === null || Array.isArray(candidate)) {
|
|
275
|
+
return failure('INVALID_AGENT_CLIENTS', entryPath);
|
|
276
|
+
}
|
|
277
|
+
const keys = Object.keys(candidate);
|
|
278
|
+
if (
|
|
279
|
+
keys.length !== 3
|
|
280
|
+
|| !own(candidate, 'id')
|
|
281
|
+
|| !own(candidate, 'enabled')
|
|
282
|
+
|| !own(candidate, 'installInSandbox')
|
|
283
|
+
) {
|
|
284
|
+
return failure('INVALID_AGENT_CLIENTS', entryPath);
|
|
285
|
+
}
|
|
286
|
+
if (!BUILTIN_TUI_IDS.includes(candidate.id)) {
|
|
287
|
+
return failure('UNKNOWN_AGENT_CLIENT', `${entryPath}.id`);
|
|
140
288
|
}
|
|
289
|
+
if (entries.has(candidate.id)) return failure('DUPLICATE_AGENT_CLIENT', `${entryPath}.id`);
|
|
290
|
+
if (typeof candidate.enabled !== 'boolean' || typeof candidate.installInSandbox !== 'boolean') {
|
|
291
|
+
return failure('INVALID_AGENT_CLIENTS', entryPath);
|
|
292
|
+
}
|
|
293
|
+
entries.set(candidate.id, {
|
|
294
|
+
enabled: candidate.enabled,
|
|
295
|
+
installInSandbox: candidate.installInSandbox
|
|
296
|
+
});
|
|
141
297
|
}
|
|
142
|
-
|
|
298
|
+
if (BUILTIN_TUI_IDS.some((id) => !entries.has(id))) {
|
|
299
|
+
return failure('MISSING_AGENT_CLIENT', 'agentClients');
|
|
300
|
+
}
|
|
301
|
+
const state = Object.fromEntries(BUILTIN_TUI_IDS.map((id) => [id, entries.get(id)]));
|
|
302
|
+
if (hasLegacyTuis && BUILTIN_TUI_IDS.some((id) => state[id].enabled !== tuiProjection[id])) {
|
|
303
|
+
return failure('LEGACY_CONFLICT', 'tuis');
|
|
304
|
+
}
|
|
305
|
+
if ([...sandboxProjection.clientSignals].some((id) => !state[id].installInSandbox)) {
|
|
306
|
+
return failure('LEGACY_CONFLICT', 'sandbox.tools');
|
|
307
|
+
}
|
|
308
|
+
const sameOrder = cfg.agentClients.every((entry, index) => entry.id === BUILTIN_TUI_IDS[index]);
|
|
309
|
+
return {
|
|
310
|
+
source: 'canonical',
|
|
311
|
+
state,
|
|
312
|
+
canonical: serialize(state),
|
|
313
|
+
remainingSandboxTools: hasSandboxTools ? sandboxProjection.remainingTools : undefined,
|
|
314
|
+
removeLegacyTuis: hasLegacyTuis,
|
|
315
|
+
changed: hasLegacyTuis || sandboxProjection.clientSignals.size > 0 || !sameOrder,
|
|
316
|
+
diagnostics,
|
|
317
|
+
error: null,
|
|
318
|
+
errorCode: null,
|
|
319
|
+
errorPath: null
|
|
320
|
+
};
|
|
143
321
|
}
|
|
144
322
|
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
323
|
+
function materializeAgentClientConfig(cfg, normalized) {
|
|
324
|
+
cfg.agentClients = normalized.canonical;
|
|
325
|
+
delete cfg.tuis;
|
|
326
|
+
if (normalized.remainingSandboxTools !== undefined) {
|
|
327
|
+
cfg.sandbox = {
|
|
328
|
+
...(cfg.sandbox || {}),
|
|
329
|
+
tools: [
|
|
330
|
+
'agent-infra',
|
|
331
|
+
...normalized.remainingSandboxTools.filter((tool) => tool !== 'agent-infra')
|
|
332
|
+
]
|
|
333
|
+
};
|
|
148
334
|
}
|
|
149
|
-
const tools = new Set(value);
|
|
150
|
-
return LEGACY_DEFAULT_SANDBOX_TOOLS.every(tool => tools.has(tool));
|
|
151
335
|
}
|
|
152
336
|
|
|
153
|
-
function
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
337
|
+
function assetMatches(entry, target) {
|
|
338
|
+
const normalizedEntry = norm(entry);
|
|
339
|
+
const normalizedTarget = norm(target);
|
|
340
|
+
return normalizedEntry.endsWith('/')
|
|
341
|
+
? normalizedTarget.startsWith(normalizedEntry)
|
|
342
|
+
: normalizedTarget === normalizedEntry;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function adapterAssets(adapters, category) {
|
|
346
|
+
return adapters.flatMap((adapter) => adapter[category]);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function planProjectRegistry(current, sharedDefaults, enabledSet) {
|
|
350
|
+
const enabledAdapters = AGENT_CLIENT_MANIFEST.filter((adapter) => enabledSet.has(adapter.id));
|
|
351
|
+
const disabledAdapters = AGENT_CLIENT_MANIFEST.filter((adapter) => !enabledSet.has(adapter.id));
|
|
352
|
+
const allAdapterAssets = new Set(
|
|
353
|
+
AGENT_CLIENT_MANIFEST.flatMap((adapter) => [
|
|
354
|
+
...adapter.managed,
|
|
355
|
+
...adapter.merged,
|
|
356
|
+
...adapter.ejected
|
|
357
|
+
])
|
|
358
|
+
);
|
|
359
|
+
const enabled = {
|
|
360
|
+
managed: adapterAssets(enabledAdapters, 'managed'),
|
|
361
|
+
merged: adapterAssets(enabledAdapters, 'merged'),
|
|
362
|
+
ejected: adapterAssets(enabledAdapters, 'ejected')
|
|
363
|
+
};
|
|
364
|
+
const unique = (values) => [...new Set(values)];
|
|
365
|
+
const ejected = unique([
|
|
366
|
+
...current.ejected,
|
|
367
|
+
...enabled.ejected,
|
|
368
|
+
...sharedDefaults.ejected
|
|
369
|
+
]);
|
|
370
|
+
const ejectedSet = new Set(ejected);
|
|
371
|
+
const preserve = (values, enabledValues) => values.filter((entry) =>
|
|
372
|
+
!ejectedSet.has(entry)
|
|
373
|
+
&& (!allAdapterAssets.has(entry) || enabledValues.includes(entry))
|
|
374
|
+
);
|
|
375
|
+
const managed = unique([
|
|
376
|
+
...preserve(current.managed, enabled.managed),
|
|
377
|
+
...enabled.managed.filter((entry) => !ejectedSet.has(entry)),
|
|
378
|
+
...sharedDefaults.managed.filter((entry) => !ejectedSet.has(entry))
|
|
379
|
+
]);
|
|
380
|
+
const managedSet = new Set(managed);
|
|
381
|
+
const merged = unique([
|
|
382
|
+
...preserve(current.merged, enabled.merged),
|
|
383
|
+
...enabled.merged.filter((entry) => !ejectedSet.has(entry) && !managedSet.has(entry)),
|
|
384
|
+
...sharedDefaults.merged.filter((entry) => !ejectedSet.has(entry) && !managedSet.has(entry))
|
|
385
|
+
]);
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
registry: { managed, merged, ejected },
|
|
389
|
+
enabledManaged: enabled.managed,
|
|
390
|
+
enabledMerged: enabled.merged,
|
|
391
|
+
enabledEjected: enabled.ejected,
|
|
392
|
+
disabledManaged: adapterAssets(disabledAdapters, 'managed')
|
|
161
393
|
};
|
|
162
|
-
return true;
|
|
163
394
|
}
|
|
164
395
|
|
|
165
396
|
function norm(p) { return p.replace(/\\/g, '/'); }
|
|
@@ -618,9 +849,49 @@ function generateOpenCodeCommand(skill, lang) {
|
|
|
618
849
|
}
|
|
619
850
|
|
|
620
851
|
function validateCustomTUIs(projectRoot, customTUIs, report) {
|
|
621
|
-
|
|
852
|
+
if (customTUIs === undefined) return [];
|
|
853
|
+
if (!Array.isArray(customTUIs)) {
|
|
854
|
+
recordCustomTUISkipped(report, {
|
|
855
|
+
index: -1,
|
|
856
|
+
name: '',
|
|
857
|
+
dir: '',
|
|
858
|
+
reason: 'customTUIs must be an array'
|
|
859
|
+
});
|
|
860
|
+
return [];
|
|
861
|
+
}
|
|
862
|
+
const tools = customTUIs;
|
|
622
863
|
return tools
|
|
623
864
|
.map((tool, index) => {
|
|
865
|
+
if (
|
|
866
|
+
typeof tool !== 'object'
|
|
867
|
+
|| tool === null
|
|
868
|
+
|| Array.isArray(tool)
|
|
869
|
+
) {
|
|
870
|
+
recordCustomTUISkipped(report, {
|
|
871
|
+
index,
|
|
872
|
+
name: '',
|
|
873
|
+
dir: '',
|
|
874
|
+
reason: 'invalid custom TUI'
|
|
875
|
+
});
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
for (const field of CUSTOM_TUI_CONTRACT.requiredFields) {
|
|
880
|
+
if (
|
|
881
|
+
typeof tool[field] !== 'string'
|
|
882
|
+
|| tool[field].trim() === ''
|
|
883
|
+
|| /[\r\n]/.test(tool[field])
|
|
884
|
+
) {
|
|
885
|
+
recordCustomTUISkipped(report, {
|
|
886
|
+
index,
|
|
887
|
+
name: String(tool.name || ''),
|
|
888
|
+
dir: String(tool.dir || ''),
|
|
889
|
+
reason: `invalid ${field}`
|
|
890
|
+
});
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
624
895
|
if (typeof tool?.dir !== 'string' || tool.dir.trim() === '') {
|
|
625
896
|
recordCustomTUISkipped(report, {
|
|
626
897
|
index,
|
|
@@ -631,6 +902,16 @@ function validateCustomTUIs(projectRoot, customTUIs, report) {
|
|
|
631
902
|
return null;
|
|
632
903
|
}
|
|
633
904
|
|
|
905
|
+
if (tool.dir.includes('\\')) {
|
|
906
|
+
recordCustomTUISkipped(report, {
|
|
907
|
+
index,
|
|
908
|
+
name: tool.name,
|
|
909
|
+
dir: tool.dir,
|
|
910
|
+
reason: 'dir must use POSIX separators'
|
|
911
|
+
});
|
|
912
|
+
return null;
|
|
913
|
+
}
|
|
914
|
+
|
|
634
915
|
if (!isInsideProject(projectRoot, tool.dir)) {
|
|
635
916
|
recordCustomTUISkipped(report, {
|
|
636
917
|
index,
|
|
@@ -641,6 +922,27 @@ function validateCustomTUIs(projectRoot, customTUIs, report) {
|
|
|
641
922
|
return null;
|
|
642
923
|
}
|
|
643
924
|
|
|
925
|
+
const placeholders = [...tool.invoke.matchAll(/\$\{([^}]+)\}/g)]
|
|
926
|
+
.map((match) => match[1]);
|
|
927
|
+
if (
|
|
928
|
+
!placeholders.includes('skillName')
|
|
929
|
+
|| placeholders.some((placeholder) =>
|
|
930
|
+
!CUSTOM_TUI_CONTRACT.allowedPlaceholders.includes(placeholder)
|
|
931
|
+
)
|
|
932
|
+
|| tool.invoke
|
|
933
|
+
.replaceAll('${skillName}', '')
|
|
934
|
+
.replaceAll('${projectName}', '')
|
|
935
|
+
.includes('${')
|
|
936
|
+
) {
|
|
937
|
+
recordCustomTUISkipped(report, {
|
|
938
|
+
index,
|
|
939
|
+
name: tool.name,
|
|
940
|
+
dir: tool.dir,
|
|
941
|
+
reason: 'invalid invoke placeholders'
|
|
942
|
+
});
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
|
|
644
946
|
return { ...tool, index, dir: normDir(tool.dir) };
|
|
645
947
|
})
|
|
646
948
|
.filter(Boolean);
|
|
@@ -764,27 +1066,34 @@ function learnAndGenerateCommands(projectRoot, customSkills, tool, templateSkill
|
|
|
764
1066
|
}
|
|
765
1067
|
}
|
|
766
1068
|
|
|
767
|
-
function generateCustomCommands(
|
|
1069
|
+
function generateCustomCommands(
|
|
1070
|
+
projectRoot,
|
|
1071
|
+
customSkills,
|
|
1072
|
+
project,
|
|
1073
|
+
lang,
|
|
1074
|
+
report,
|
|
1075
|
+
customTUIs,
|
|
1076
|
+
templateSkillNames,
|
|
1077
|
+
enabledTUIs,
|
|
1078
|
+
managedWriter
|
|
1079
|
+
) {
|
|
768
1080
|
for (const skill of customSkills) {
|
|
769
1081
|
if (enabledTUIs.has('claude-code')) {
|
|
770
|
-
|
|
771
|
-
projectRoot,
|
|
1082
|
+
managedWriter(
|
|
772
1083
|
`.claude/commands/${skill.dirName}.md`,
|
|
773
1084
|
generateClaudeCommand(skill, lang),
|
|
774
1085
|
report.custom.commands
|
|
775
1086
|
);
|
|
776
1087
|
}
|
|
777
1088
|
if (enabledTUIs.has('gemini-cli')) {
|
|
778
|
-
|
|
779
|
-
projectRoot,
|
|
1089
|
+
managedWriter(
|
|
780
1090
|
'.gemini/commands/' + project + '/' + skill.dirName + '.toml',
|
|
781
1091
|
generateGeminiCommand(skill, lang),
|
|
782
1092
|
report.custom.commands
|
|
783
1093
|
);
|
|
784
1094
|
}
|
|
785
1095
|
if (enabledTUIs.has('opencode')) {
|
|
786
|
-
|
|
787
|
-
projectRoot,
|
|
1096
|
+
managedWriter(
|
|
788
1097
|
`.opencode/commands/${skill.dirName}.md`,
|
|
789
1098
|
generateOpenCodeCommand(skill, lang),
|
|
790
1099
|
report.custom.commands
|
|
@@ -935,7 +1244,8 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
935
1244
|
return { error: 'No .agents/.airc.json in project root.' };
|
|
936
1245
|
}
|
|
937
1246
|
|
|
938
|
-
const
|
|
1247
|
+
const originalConfigText = fs.readFileSync(cfgPath, 'utf8');
|
|
1248
|
+
const cfg = JSON.parse(originalConfigText);
|
|
939
1249
|
const configPathRel = norm(path.relative(projectRoot, cfgPath));
|
|
940
1250
|
let templateRoot = templateRootOverride;
|
|
941
1251
|
if (!templateRoot) {
|
|
@@ -951,20 +1261,43 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
951
1261
|
}
|
|
952
1262
|
}
|
|
953
1263
|
const version = resolveVersionFromTemplateRoot(templateRoot);
|
|
954
|
-
const hadTemplateSource = Object.prototype.hasOwnProperty.call(cfg, 'templateSource');
|
|
955
1264
|
|
|
956
1265
|
const { project, org, language: lang = 'en' } = cfg;
|
|
957
1266
|
const platformType = cfg.platform?.type || DEFAULTS.platform.type;
|
|
958
|
-
const
|
|
1267
|
+
const enabledResolution = normalizeAgentClientConfig(cfg);
|
|
1268
|
+
if (enabledResolution.error) {
|
|
1269
|
+
return { error: enabledResolution.error };
|
|
1270
|
+
}
|
|
1271
|
+
const enabledTUIs = new Set(
|
|
1272
|
+
BUILTIN_TUI_IDS.filter((id) => enabledResolution.state[id].enabled)
|
|
1273
|
+
);
|
|
1274
|
+
materializeAgentClientConfig(cfg, enabledResolution);
|
|
959
1275
|
const customTUIsConfig = Array.isArray(cfg.customTUIs) ? cfg.customTUIs : [];
|
|
960
1276
|
const vars = { project, org };
|
|
961
1277
|
const templateSkillNames = listTemplateSkillNames(templateRoot);
|
|
962
1278
|
const protectedCustomSkills = detectCustomSkills(projectRoot, templateSkillNames);
|
|
963
1279
|
|
|
964
|
-
|
|
965
|
-
const
|
|
966
|
-
|
|
1280
|
+
cfg.files ||= {};
|
|
1281
|
+
const currentRegistry = {
|
|
1282
|
+
managed: [...(cfg.files.managed || [])],
|
|
1283
|
+
merged: [...(cfg.files.merged || [])],
|
|
1284
|
+
ejected: [...(cfg.files.ejected || [])]
|
|
1285
|
+
};
|
|
1286
|
+
const sharedDefaults = {
|
|
1287
|
+
managed: (DEFAULTS.files.managed || []).filter(
|
|
1288
|
+
(entry) => !isPathOwnedByOtherPlatform(entry, platformType)
|
|
1289
|
+
),
|
|
1290
|
+
merged: (DEFAULTS.files.merged || []).filter(
|
|
1291
|
+
(entry) => !isPathOwnedByOtherPlatform(entry, platformType)
|
|
1292
|
+
),
|
|
1293
|
+
ejected: [...(DEFAULTS.files.ejected || [])]
|
|
1294
|
+
};
|
|
1295
|
+
const assetPlan = planProjectRegistry(currentRegistry, sharedDefaults, enabledTUIs);
|
|
1296
|
+
const managed = [...assetPlan.registry.managed];
|
|
1297
|
+
const merged = [...assetPlan.registry.merged];
|
|
1298
|
+
const ejected = [...assetPlan.registry.ejected];
|
|
967
1299
|
const guardedManaged = new Set((DEFAULTS.files.guardedManaged || []).map(norm));
|
|
1300
|
+
const allClientManaged = adapterAssets(AGENT_CLIENT_MANIFEST, 'managed');
|
|
968
1301
|
const managedBaselines = cfg.files.managedBaselines && typeof cfg.files.managedBaselines === 'object'
|
|
969
1302
|
&& !Array.isArray(cfg.files.managedBaselines)
|
|
970
1303
|
? { ...cfg.files.managedBaselines }
|
|
@@ -972,7 +1305,10 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
972
1305
|
let baselinesChanged = false;
|
|
973
1306
|
|
|
974
1307
|
for (const target of Object.keys(managedBaselines)) {
|
|
975
|
-
if (
|
|
1308
|
+
if (
|
|
1309
|
+
!guardedManaged.has(norm(target))
|
|
1310
|
+
&& !allClientManaged.some((entry) => assetMatches(entry, target))
|
|
1311
|
+
) {
|
|
976
1312
|
delete managedBaselines[target];
|
|
977
1313
|
baselinesChanged = true;
|
|
978
1314
|
}
|
|
@@ -982,6 +1318,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
982
1318
|
templateVersion: version,
|
|
983
1319
|
templateRoot: norm(templateRoot),
|
|
984
1320
|
registryAdded: [],
|
|
1321
|
+
registryRemoved: [],
|
|
985
1322
|
templateSources: {
|
|
986
1323
|
configured: 0,
|
|
987
1324
|
loaded: 0,
|
|
@@ -1022,17 +1359,23 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1022
1359
|
templateSkillNames
|
|
1023
1360
|
);
|
|
1024
1361
|
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
if (!known.has(e)) { merged.push(e); known.add(e); report.registryAdded.push({ entry: e, list: 'merged' }); }
|
|
1362
|
+
for (const category of ['managed', 'merged', 'ejected']) {
|
|
1363
|
+
const before = currentRegistry[category];
|
|
1364
|
+
const after = assetPlan.registry[category];
|
|
1365
|
+
for (const entry of after) {
|
|
1366
|
+
if (!before.includes(entry)) report.registryAdded.push({ entry, list: category });
|
|
1367
|
+
}
|
|
1368
|
+
for (const entry of before) {
|
|
1369
|
+
if (!after.includes(entry)) report.registryRemoved.push({ entry, list: category });
|
|
1370
|
+
}
|
|
1035
1371
|
}
|
|
1372
|
+
report.managed.skippedTUI.push(
|
|
1373
|
+
...assetPlan.disabledManaged,
|
|
1374
|
+
...adapterAssets(
|
|
1375
|
+
AGENT_CLIENT_MANIFEST.filter((adapter) => !enabledTUIs.has(adapter.id)),
|
|
1376
|
+
'merged'
|
|
1377
|
+
)
|
|
1378
|
+
);
|
|
1036
1379
|
|
|
1037
1380
|
const templateSources = Array.isArray(cfg.templates?.sources) ? cfg.templates.sources : [];
|
|
1038
1381
|
report.templateSources.configured = templateSources.length;
|
|
@@ -1056,6 +1399,97 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1056
1399
|
: renderContent(fs.readFileSync(srcFull, 'utf8'), vars);
|
|
1057
1400
|
}
|
|
1058
1401
|
|
|
1402
|
+
function selectedTargetsForEntry(entry) {
|
|
1403
|
+
let entryRels;
|
|
1404
|
+
if (entry.endsWith('/')) {
|
|
1405
|
+
const builtinDir = path.join(templateRoot, entry);
|
|
1406
|
+
const builtinRels = fs.existsSync(builtinDir)
|
|
1407
|
+
? walkDir(builtinDir).map((filePath) => norm(path.relative(templateRoot, filePath)))
|
|
1408
|
+
: [];
|
|
1409
|
+
const prefix = norm(entry);
|
|
1410
|
+
const externalRels = allRels.filter((rel) =>
|
|
1411
|
+
rel.startsWith(prefix) && !builtinRels.includes(rel)
|
|
1412
|
+
);
|
|
1413
|
+
entryRels = [...builtinRels, ...externalRels];
|
|
1414
|
+
} else {
|
|
1415
|
+
entryRels = entryVariantRels(entry, allSet, platformType);
|
|
1416
|
+
}
|
|
1417
|
+
return platformSelect(
|
|
1418
|
+
langSelect(entryRels, lang, allSet, project),
|
|
1419
|
+
platformType,
|
|
1420
|
+
project
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
function writeProtectedManaged(target, content, bucket) {
|
|
1425
|
+
const dstFull = path.join(projectRoot, target);
|
|
1426
|
+
const exists = fs.existsSync(dstFull);
|
|
1427
|
+
const rawBaseline = managedBaselines[target];
|
|
1428
|
+
const baseline = trustedBaseline(rawBaseline);
|
|
1429
|
+
const templateHash = sha256(content);
|
|
1430
|
+
const localHash = exists ? sha256(fs.readFileSync(dstFull)) : null;
|
|
1431
|
+
|
|
1432
|
+
if (rawBaseline !== undefined && baseline === null) {
|
|
1433
|
+
delete managedBaselines[target];
|
|
1434
|
+
baselinesChanged = true;
|
|
1435
|
+
}
|
|
1436
|
+
if (baseline === null && localHash !== null && localHash !== templateHash) {
|
|
1437
|
+
report.managed.conflicts.push({
|
|
1438
|
+
target,
|
|
1439
|
+
reason: 'unknown-origin',
|
|
1440
|
+
baseline: null,
|
|
1441
|
+
local: localHash,
|
|
1442
|
+
template: templateHash
|
|
1443
|
+
});
|
|
1444
|
+
return false;
|
|
1445
|
+
}
|
|
1446
|
+
if (baseline !== null && templateHash === baseline && localHash !== baseline) {
|
|
1447
|
+
report.managed.protected.push({
|
|
1448
|
+
target,
|
|
1449
|
+
reason: localHash === null ? 'user-deleted' : 'user-modified',
|
|
1450
|
+
baseline,
|
|
1451
|
+
local: localHash,
|
|
1452
|
+
template: templateHash
|
|
1453
|
+
});
|
|
1454
|
+
return false;
|
|
1455
|
+
}
|
|
1456
|
+
if (
|
|
1457
|
+
baseline !== null
|
|
1458
|
+
&& localHash !== baseline
|
|
1459
|
+
&& templateHash !== baseline
|
|
1460
|
+
&& localHash !== templateHash
|
|
1461
|
+
) {
|
|
1462
|
+
report.managed.conflicts.push({
|
|
1463
|
+
target,
|
|
1464
|
+
reason: 'both-modified',
|
|
1465
|
+
baseline,
|
|
1466
|
+
local: localHash,
|
|
1467
|
+
template: templateHash
|
|
1468
|
+
});
|
|
1469
|
+
return false;
|
|
1470
|
+
}
|
|
1471
|
+
if (localHash === templateHash) {
|
|
1472
|
+
bucket.unchanged.push(target);
|
|
1473
|
+
if (managedBaselines[target] !== templateHash) {
|
|
1474
|
+
managedBaselines[target] = templateHash;
|
|
1475
|
+
baselinesChanged = true;
|
|
1476
|
+
}
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
const dir = path.dirname(dstFull);
|
|
1481
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
1482
|
+
fs.writeFileSync(dstFull, content);
|
|
1483
|
+
managedBaselines[target] = templateHash;
|
|
1484
|
+
baselinesChanged = true;
|
|
1485
|
+
if (Object.prototype.hasOwnProperty.call(bucket, 'written')) {
|
|
1486
|
+
(exists ? bucket.written : bucket.created).push(target);
|
|
1487
|
+
} else {
|
|
1488
|
+
(exists ? bucket.updated : bucket.generated).push(target);
|
|
1489
|
+
}
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1059
1493
|
for (const entry of [...managed, ...merged, ...ejected]) {
|
|
1060
1494
|
if (!isPathOwnedByOtherPlatform(entry, platformType)) continue;
|
|
1061
1495
|
|
|
@@ -1109,39 +1543,81 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1109
1543
|
}
|
|
1110
1544
|
}
|
|
1111
1545
|
|
|
1112
|
-
//
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1546
|
+
// Disabled clients are converged conservatively: only exact manifest
|
|
1547
|
+
// managed targets or previously baselined generated targets are candidates.
|
|
1548
|
+
// Merged/ejected and content without trustworthy origin evidence are kept.
|
|
1549
|
+
for (const entry of assetPlan.disabledManaged) {
|
|
1550
|
+
const selectedTargets = selectedTargetsForEntry(entry);
|
|
1551
|
+
const candidates = new Set(
|
|
1552
|
+
Object.keys(managedBaselines).filter((target) => assetMatches(entry, target))
|
|
1553
|
+
);
|
|
1554
|
+
for (const target of selectedTargets.keys()) candidates.add(target);
|
|
1555
|
+
|
|
1556
|
+
for (const target of candidates) {
|
|
1557
|
+
const dstFull = path.join(projectRoot, target);
|
|
1558
|
+
const baseline = trustedBaseline(managedBaselines[target]);
|
|
1559
|
+
const selectedSource = selectedTargets.get(target);
|
|
1560
|
+
const sourceRoot = selectedSource ? (sourceMap.get(selectedSource) || templateRoot) : null;
|
|
1561
|
+
const templateContent = selectedSource && sourceRoot === templateRoot
|
|
1562
|
+
? (
|
|
1563
|
+
isBinary(path.join(sourceRoot, selectedSource))
|
|
1564
|
+
? fs.readFileSync(path.join(sourceRoot, selectedSource))
|
|
1565
|
+
: renderContent(fs.readFileSync(path.join(sourceRoot, selectedSource), 'utf8'), vars)
|
|
1566
|
+
)
|
|
1567
|
+
: null;
|
|
1568
|
+
const localHash = fs.existsSync(dstFull) ? sha256(fs.readFileSync(dstFull)) : null;
|
|
1569
|
+
const templateHash = templateContent === null ? null : sha256(templateContent);
|
|
1570
|
+
const protectedByEjection = ejected.some((pattern) =>
|
|
1571
|
+
assetMatches(pattern, target) || globMatch(pattern, target)
|
|
1572
|
+
);
|
|
1573
|
+
const protectedByCustom = customTUICommandTargets.has(target);
|
|
1574
|
+
|
|
1575
|
+
if (protectedByEjection || protectedByCustom || (sourceRoot && sourceRoot !== templateRoot)) {
|
|
1576
|
+
report.managed.protected.push({
|
|
1577
|
+
target,
|
|
1578
|
+
reason: protectedByEjection
|
|
1579
|
+
? 'ejected'
|
|
1580
|
+
: protectedByCustom
|
|
1581
|
+
? 'custom'
|
|
1582
|
+
: 'external-source',
|
|
1583
|
+
baseline,
|
|
1584
|
+
local: localHash,
|
|
1585
|
+
template: templateHash
|
|
1586
|
+
});
|
|
1587
|
+
continue;
|
|
1134
1588
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1589
|
+
if (localHash === null) {
|
|
1590
|
+
if (Object.prototype.hasOwnProperty.call(managedBaselines, target)) {
|
|
1591
|
+
delete managedBaselines[target];
|
|
1592
|
+
baselinesChanged = true;
|
|
1593
|
+
}
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
const legacyManaged = currentRegistry.managed.includes(entry);
|
|
1597
|
+
if (
|
|
1598
|
+
(baseline !== null && localHash === baseline)
|
|
1599
|
+
|| (baseline === null && legacyManaged && templateHash !== null && localHash === templateHash)
|
|
1600
|
+
) {
|
|
1601
|
+
fs.unlinkSync(dstFull);
|
|
1602
|
+
report.managed.removed.push(target);
|
|
1603
|
+
if (Object.prototype.hasOwnProperty.call(managedBaselines, target)) {
|
|
1604
|
+
delete managedBaselines[target];
|
|
1605
|
+
baselinesChanged = true;
|
|
1606
|
+
}
|
|
1607
|
+
removeEmptyDirs(path.dirname(dstFull));
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
report.managed.protected.push({
|
|
1611
|
+
target,
|
|
1612
|
+
reason: baseline === null ? 'unknown-origin' : 'user-modified',
|
|
1613
|
+
baseline,
|
|
1614
|
+
local: localHash,
|
|
1615
|
+
template: templateHash
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
if (entry.endsWith('/')) {
|
|
1619
|
+
removeEmptyDirs(path.join(projectRoot, entry));
|
|
1137
1620
|
}
|
|
1138
|
-
|
|
1139
|
-
const target = path.join(projectRoot, renderPathname(entry, project));
|
|
1140
|
-
if (!fs.existsSync(target)) continue;
|
|
1141
|
-
const relProj = norm(path.relative(projectRoot, target));
|
|
1142
|
-
if (customTUICommandTargets.has(relProj)) continue;
|
|
1143
|
-
fs.unlinkSync(target);
|
|
1144
|
-
report.managed.removed.push(relProj);
|
|
1145
1621
|
}
|
|
1146
1622
|
|
|
1147
1623
|
for (const entry of managed) {
|
|
@@ -1149,11 +1625,6 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1149
1625
|
report.managed.skippedPlatform.push(entry);
|
|
1150
1626
|
continue;
|
|
1151
1627
|
}
|
|
1152
|
-
if (isPathOwnedByDisabledTUI(entry, enabledTUIs)) {
|
|
1153
|
-
report.managed.skippedTUI.push(entry);
|
|
1154
|
-
continue;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
1628
|
const isDir = entry.endsWith('/');
|
|
1158
1629
|
let entryRels;
|
|
1159
1630
|
const expectedTargets = isDir ? new Set() : null;
|
|
@@ -1191,65 +1662,14 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1191
1662
|
: renderContent(fs.readFileSync(srcFull, 'utf8'), vars);
|
|
1192
1663
|
|
|
1193
1664
|
const exists = fs.existsSync(dstFull);
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
delete managedBaselines[tgt];
|
|
1202
|
-
baselinesChanged = true;
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
if (baseline === null && localHash !== null && localHash !== templateHash) {
|
|
1206
|
-
report.managed.conflicts.push({
|
|
1207
|
-
target: tgt,
|
|
1208
|
-
reason: 'unknown-origin',
|
|
1209
|
-
baseline: null,
|
|
1210
|
-
local: localHash,
|
|
1211
|
-
template: templateHash
|
|
1212
|
-
});
|
|
1213
|
-
continue;
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
if (baseline !== null && templateHash === baseline && localHash !== baseline) {
|
|
1217
|
-
report.managed.protected.push({
|
|
1218
|
-
target: tgt,
|
|
1219
|
-
reason: localHash === null ? 'user-deleted' : 'user-modified',
|
|
1220
|
-
baseline,
|
|
1221
|
-
local: localHash,
|
|
1222
|
-
template: templateHash
|
|
1223
|
-
});
|
|
1224
|
-
continue;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
if (baseline !== null && localHash !== baseline && templateHash !== baseline && localHash !== templateHash) {
|
|
1228
|
-
report.managed.conflicts.push({
|
|
1229
|
-
target: tgt,
|
|
1230
|
-
reason: 'both-modified',
|
|
1231
|
-
baseline,
|
|
1232
|
-
local: localHash,
|
|
1233
|
-
template: templateHash
|
|
1234
|
-
});
|
|
1235
|
-
continue;
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
if (localHash === templateHash) {
|
|
1239
|
-
report.managed.unchanged.push(tgt);
|
|
1240
|
-
if (managedBaselines[tgt] !== templateHash) {
|
|
1241
|
-
managedBaselines[tgt] = templateHash;
|
|
1242
|
-
baselinesChanged = true;
|
|
1243
|
-
}
|
|
1244
|
-
continue;
|
|
1665
|
+
const clientManagedTarget = assetPlan.enabledManaged.some((asset) =>
|
|
1666
|
+
assetMatches(asset, tgt)
|
|
1667
|
+
);
|
|
1668
|
+
if (guardedManaged.has(tgt) || (clientManagedTarget && srcRoot === templateRoot)) {
|
|
1669
|
+
const written = writeProtectedManaged(tgt, content, report.managed);
|
|
1670
|
+
if (written && tgt.endsWith('.sh')) {
|
|
1671
|
+
try { fs.chmodSync(dstFull, 0o755); } catch { /* Windows */ }
|
|
1245
1672
|
}
|
|
1246
|
-
|
|
1247
|
-
const dir = path.dirname(dstFull);
|
|
1248
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
1249
|
-
fs.writeFileSync(dstFull, content);
|
|
1250
|
-
managedBaselines[tgt] = templateHash;
|
|
1251
|
-
baselinesChanged = true;
|
|
1252
|
-
(exists ? report.managed.written : report.managed.created).push(tgt);
|
|
1253
1673
|
continue;
|
|
1254
1674
|
}
|
|
1255
1675
|
|
|
@@ -1281,7 +1701,25 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1281
1701
|
if (projFile === configPathRel) continue;
|
|
1282
1702
|
if (isCustomProtected(projFile, protectedCustomSkills, project, customTUICommandTargets)) continue;
|
|
1283
1703
|
if (matchesAny(projFile, merged) || matchesAny(projFile, ejected)) continue;
|
|
1284
|
-
|
|
1704
|
+
if (assetPlan.enabledManaged.includes(entry)) {
|
|
1705
|
+
const baseline = trustedBaseline(managedBaselines[projFile]);
|
|
1706
|
+
const localHash = sha256(fs.readFileSync(path.join(projectRoot, projFile)));
|
|
1707
|
+
if (baseline !== null && localHash === baseline) {
|
|
1708
|
+
fs.unlinkSync(path.join(projectRoot, projFile));
|
|
1709
|
+
delete managedBaselines[projFile];
|
|
1710
|
+
baselinesChanged = true;
|
|
1711
|
+
report.managed.removed.push(projFile);
|
|
1712
|
+
} else {
|
|
1713
|
+
report.managed.protected.push({
|
|
1714
|
+
target: projFile,
|
|
1715
|
+
reason: baseline === null ? 'unknown-origin' : 'user-modified',
|
|
1716
|
+
baseline,
|
|
1717
|
+
local: localHash,
|
|
1718
|
+
template: null
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
continue;
|
|
1722
|
+
}
|
|
1285
1723
|
fs.unlinkSync(path.join(projectRoot, projFile));
|
|
1286
1724
|
report.managed.removed.push(projFile);
|
|
1287
1725
|
}
|
|
@@ -1300,7 +1738,17 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1300
1738
|
|
|
1301
1739
|
const customSkills = detectCustomSkills(projectRoot, templateSkillNames);
|
|
1302
1740
|
report.custom.detected = customSkills.map((skill) => skill.dirName);
|
|
1303
|
-
generateCustomCommands(
|
|
1741
|
+
generateCustomCommands(
|
|
1742
|
+
projectRoot,
|
|
1743
|
+
customSkills,
|
|
1744
|
+
project,
|
|
1745
|
+
lang,
|
|
1746
|
+
report,
|
|
1747
|
+
customTUIs,
|
|
1748
|
+
templateSkillNames,
|
|
1749
|
+
enabledTUIs,
|
|
1750
|
+
writeProtectedManaged
|
|
1751
|
+
);
|
|
1304
1752
|
|
|
1305
1753
|
for (const entry of ejected) {
|
|
1306
1754
|
const dstFull = path.join(projectRoot, entry);
|
|
@@ -1310,7 +1758,11 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1310
1758
|
}
|
|
1311
1759
|
// Do not (re)create ejected files for disabled TUIs. Existing files are
|
|
1312
1760
|
// never touched by sync (handled above); this guard only blocks creation.
|
|
1313
|
-
|
|
1761
|
+
const disabledEjected = AGENT_CLIENT_MANIFEST.some((adapter) =>
|
|
1762
|
+
!enabledTUIs.has(adapter.id)
|
|
1763
|
+
&& adapter.ejected.some((asset) => assetMatches(asset, entry))
|
|
1764
|
+
);
|
|
1765
|
+
if (disabledEjected) continue;
|
|
1314
1766
|
|
|
1315
1767
|
const selected = platformSelect(langSelect(entryVariantRels(entry, allSet, platformType), lang, allSet, project), platformType, project);
|
|
1316
1768
|
const target = norm(renderPathname(entry, project));
|
|
@@ -1331,11 +1783,6 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1331
1783
|
report.managed.skippedPlatform.push(entry);
|
|
1332
1784
|
continue;
|
|
1333
1785
|
}
|
|
1334
|
-
if (isPathOwnedByDisabledTUI(entry, enabledTUIs)) {
|
|
1335
|
-
report.managed.skippedTUI.push(entry);
|
|
1336
|
-
continue;
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
1786
|
if (entry.includes('*')) {
|
|
1340
1787
|
const hits = allRels.filter(r => {
|
|
1341
1788
|
const t = norm(renderPathname(stripLangVariant(r), project));
|
|
@@ -1356,22 +1803,6 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1356
1803
|
([target, template]) => ({ target, template })
|
|
1357
1804
|
);
|
|
1358
1805
|
|
|
1359
|
-
const hasChanges = (
|
|
1360
|
-
report.managed.written.length +
|
|
1361
|
-
report.managed.created.length +
|
|
1362
|
-
report.managed.removed.length +
|
|
1363
|
-
report.custom.generated.length +
|
|
1364
|
-
report.custom.updated.length +
|
|
1365
|
-
report.custom.removed.length +
|
|
1366
|
-
report.custom.commands.generated.length +
|
|
1367
|
-
report.custom.commands.updated.length +
|
|
1368
|
-
report.ejected.created.length +
|
|
1369
|
-
report.registryAdded.length
|
|
1370
|
-
) > 0;
|
|
1371
|
-
|
|
1372
|
-
const prevVersion = cfg.templateVersion;
|
|
1373
|
-
const sandboxToolsMigrated = migrateSandboxTools(cfg);
|
|
1374
|
-
|
|
1375
1806
|
cfg.files.managed = managed;
|
|
1376
1807
|
cfg.files.merged = merged;
|
|
1377
1808
|
cfg.files.ejected = ejected;
|
|
@@ -1384,9 +1815,22 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1384
1815
|
cfg.templateVersion = version;
|
|
1385
1816
|
delete cfg.templateSource;
|
|
1386
1817
|
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1818
|
+
const nextConfigText = JSON.stringify(cfg, null, 2) + '\n';
|
|
1819
|
+
report.configUpdated = originalConfigText !== nextConfigText;
|
|
1820
|
+
if (report.configUpdated) {
|
|
1821
|
+
const temporary = `${cfgPath}.tmp-${process.pid}-${Date.now()}`;
|
|
1822
|
+
try {
|
|
1823
|
+
fs.writeFileSync(temporary, nextConfigText, 'utf8');
|
|
1824
|
+
fs.renameSync(temporary, cfgPath);
|
|
1825
|
+
} catch (error) {
|
|
1826
|
+
try {
|
|
1827
|
+
if (fs.existsSync(temporary)) fs.unlinkSync(temporary);
|
|
1828
|
+
} catch {
|
|
1829
|
+
// Preserve the original write/rename failure.
|
|
1830
|
+
}
|
|
1831
|
+
throw error;
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1390
1834
|
|
|
1391
1835
|
return report;
|
|
1392
1836
|
}
|
|
@@ -1399,4 +1843,4 @@ if (entryPath === fileURLToPath(import.meta.url)) {
|
|
|
1399
1843
|
if (result.error) process.exitCode = 1;
|
|
1400
1844
|
}
|
|
1401
1845
|
|
|
1402
|
-
export { syncTemplates };
|
|
1846
|
+
export { normalizeAgentClientConfig, syncTemplates };
|