@arcbridge/core 0.1.6 → 0.2.1
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/dist/index.d.ts +23 -15
- package/dist/index.js +693 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
var ServiceSchema = z.object({
|
|
4
4
|
name: z.string().min(1),
|
|
5
5
|
path: z.string().default("."),
|
|
6
|
-
type: z.enum(["nextjs", "react", "fastify", "express", "hono", "dotnet"]),
|
|
6
|
+
type: z.enum(["nextjs", "react", "fastify", "express", "hono", "dotnet", "unity"]),
|
|
7
7
|
tsconfig: z.string().optional(),
|
|
8
8
|
csproj: z.string().optional()
|
|
9
9
|
});
|
|
@@ -14,7 +14,8 @@ var ArcBridgeConfigSchema = z.object({
|
|
|
14
14
|
"nextjs-app-router",
|
|
15
15
|
"react-vite",
|
|
16
16
|
"api-service",
|
|
17
|
-
"dotnet-webapi"
|
|
17
|
+
"dotnet-webapi",
|
|
18
|
+
"unity-game"
|
|
18
19
|
]).default("nextjs-app-router"),
|
|
19
20
|
services: z.array(ServiceSchema).default([]),
|
|
20
21
|
platforms: z.array(z.enum(["claude", "copilot", "gemini", "codex"])).default(["claude"]),
|
|
@@ -743,12 +744,44 @@ function configTemplate4(input) {
|
|
|
743
744
|
};
|
|
744
745
|
}
|
|
745
746
|
|
|
747
|
+
// src/templates/config/unity-game.ts
|
|
748
|
+
function configTemplate5(input) {
|
|
749
|
+
return {
|
|
750
|
+
schema_version: 1,
|
|
751
|
+
project_name: input.name,
|
|
752
|
+
project_type: input.template,
|
|
753
|
+
services: [{ name: "main", path: ".", type: "unity" }],
|
|
754
|
+
platforms: input.platforms,
|
|
755
|
+
quality_priorities: input.quality_priorities,
|
|
756
|
+
indexing: {
|
|
757
|
+
include: ["Assets/**/*.cs"],
|
|
758
|
+
exclude: ["Library", "Temp", "obj", "bin", "Logs", "UserSettings", "Packages"],
|
|
759
|
+
default_mode: "fast",
|
|
760
|
+
csharp_indexer: "auto"
|
|
761
|
+
},
|
|
762
|
+
testing: {
|
|
763
|
+
test_command: "unity -batchmode -projectPath . -runTests -testPlatform EditMode",
|
|
764
|
+
timeout_ms: 12e4
|
|
765
|
+
},
|
|
766
|
+
drift: {
|
|
767
|
+
ignore_paths: []
|
|
768
|
+
},
|
|
769
|
+
metrics: { auto_record: false },
|
|
770
|
+
sync: {
|
|
771
|
+
auto_detect_drift: true,
|
|
772
|
+
drift_severity_threshold: "warning",
|
|
773
|
+
propose_updates_on: "phase-complete"
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
746
778
|
// src/generators/config-generator.ts
|
|
747
779
|
var configTemplates = {
|
|
748
780
|
"nextjs-app-router": configTemplate,
|
|
749
781
|
"react-vite": configTemplate2,
|
|
750
782
|
"api-service": configTemplate3,
|
|
751
|
-
"dotnet-webapi": configTemplate4
|
|
783
|
+
"dotnet-webapi": configTemplate4,
|
|
784
|
+
"unity-game": configTemplate5
|
|
752
785
|
};
|
|
753
786
|
function generateConfig(targetDir, input) {
|
|
754
787
|
const templateFn = configTemplates[input.template] ?? configTemplate;
|
|
@@ -777,7 +810,7 @@ function introductionTemplate(input) {
|
|
|
777
810
|
|
|
778
811
|
## Requirements Overview
|
|
779
812
|
|
|
780
|
-
${input.name} is a ${input.template === "nextjs-app-router" ? "Next.js application using the App Router" : input.template === "dotnet-webapi" ? "ASP.NET Core Web API" : "web application"}.
|
|
813
|
+
${input.name} is a ${input.template === "nextjs-app-router" ? "Next.js application using the App Router" : input.template === "dotnet-webapi" ? "ASP.NET Core Web API" : input.template === "unity-game" ? "Unity game built with a code-heavy C# architecture" : "web application"}.
|
|
781
814
|
|
|
782
815
|
### Key Features
|
|
783
816
|
|
|
@@ -814,6 +847,10 @@ function techStack(template) {
|
|
|
814
847
|
return `- **Framework:** Express / Fastify
|
|
815
848
|
- **Language:** TypeScript
|
|
816
849
|
- **Runtime:** Node.js`;
|
|
850
|
+
case "unity-game":
|
|
851
|
+
return `- **Engine:** Unity
|
|
852
|
+
- **Language:** C#
|
|
853
|
+
- **Runtime:** Mono / IL2CPP`;
|
|
817
854
|
default:
|
|
818
855
|
return `- **Framework:** Next.js (App Router)
|
|
819
856
|
- **Language:** TypeScript
|
|
@@ -882,6 +919,8 @@ function getEntrypoints(template, srcPrefix, appPrefix) {
|
|
|
882
919
|
return [`${srcPrefix}main.tsx`, `${srcPrefix}App.tsx`];
|
|
883
920
|
case "api-service":
|
|
884
921
|
return [`${srcPrefix}index.ts`, `${srcPrefix}app.ts`, `${srcPrefix}server.ts`];
|
|
922
|
+
case "unity-game":
|
|
923
|
+
return ["Assets/Scripts/Core/GameManager.cs"];
|
|
885
924
|
default:
|
|
886
925
|
return [`${srcPrefix}index.ts`];
|
|
887
926
|
}
|
|
@@ -891,7 +930,7 @@ function getEntrypoints(template, srcPrefix, appPrefix) {
|
|
|
891
930
|
function buildingBlocksTemplate(input) {
|
|
892
931
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
893
932
|
const layout = detectProjectLayout(input.projectRoot, input.template);
|
|
894
|
-
const defaultBlocks = input.template === "dotnet-webapi" ? buildDotnetBlocks(input) : buildJsBlocks(input, layout);
|
|
933
|
+
const defaultBlocks = input.template === "dotnet-webapi" ? buildDotnetBlocks(input) : input.template === "unity-game" ? buildUnityBlocks() : buildJsBlocks(input, layout);
|
|
895
934
|
function buildJsBlocks(inp, lt) {
|
|
896
935
|
const src = lt.srcPrefix;
|
|
897
936
|
const entries = lt.entrypoints;
|
|
@@ -1087,6 +1126,98 @@ function buildingBlocksTemplate(input) {
|
|
|
1087
1126
|
});
|
|
1088
1127
|
return blocks;
|
|
1089
1128
|
}
|
|
1129
|
+
function buildUnityBlocks() {
|
|
1130
|
+
return [
|
|
1131
|
+
{
|
|
1132
|
+
id: "game-core",
|
|
1133
|
+
name: "Game Core",
|
|
1134
|
+
level: 1,
|
|
1135
|
+
code_paths: ["Assets/Scripts/Core/"],
|
|
1136
|
+
interfaces: [],
|
|
1137
|
+
quality_scenarios: ["PERF-01", "PERF-02"],
|
|
1138
|
+
adrs: [],
|
|
1139
|
+
responsibility: "Game loop, GameManager, state machine, scene management",
|
|
1140
|
+
service: "main"
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
id: "input-system",
|
|
1144
|
+
name: "Input System",
|
|
1145
|
+
level: 1,
|
|
1146
|
+
code_paths: ["Assets/Scripts/Input/"],
|
|
1147
|
+
interfaces: [],
|
|
1148
|
+
quality_scenarios: ["PERF-06"],
|
|
1149
|
+
adrs: [],
|
|
1150
|
+
responsibility: "Input handling layer, action maps, platform-independent input abstraction",
|
|
1151
|
+
service: "main"
|
|
1152
|
+
},
|
|
1153
|
+
{
|
|
1154
|
+
id: "player-systems",
|
|
1155
|
+
name: "Player Systems",
|
|
1156
|
+
level: 1,
|
|
1157
|
+
code_paths: ["Assets/Scripts/Player/"],
|
|
1158
|
+
interfaces: ["input-system"],
|
|
1159
|
+
quality_scenarios: [],
|
|
1160
|
+
adrs: [],
|
|
1161
|
+
responsibility: "Player controller, camera system, character state and animation",
|
|
1162
|
+
service: "main"
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
id: "gameplay-systems",
|
|
1166
|
+
name: "Gameplay Systems",
|
|
1167
|
+
level: 1,
|
|
1168
|
+
code_paths: ["Assets/Scripts/Gameplay/"],
|
|
1169
|
+
interfaces: ["game-core"],
|
|
1170
|
+
quality_scenarios: ["MAINT-02"],
|
|
1171
|
+
adrs: [],
|
|
1172
|
+
responsibility: "Game mechanics, combat, inventory, AI, physics interactions",
|
|
1173
|
+
service: "main"
|
|
1174
|
+
},
|
|
1175
|
+
{
|
|
1176
|
+
id: "ui-framework",
|
|
1177
|
+
name: "UI Framework",
|
|
1178
|
+
level: 1,
|
|
1179
|
+
code_paths: ["Assets/Scripts/UI/"],
|
|
1180
|
+
interfaces: [],
|
|
1181
|
+
quality_scenarios: ["A11Y-01"],
|
|
1182
|
+
adrs: [],
|
|
1183
|
+
responsibility: "HUD, menus, dialogs, settings screens, and UI event handling",
|
|
1184
|
+
service: "main"
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
id: "audio-system",
|
|
1188
|
+
name: "Audio System",
|
|
1189
|
+
level: 1,
|
|
1190
|
+
code_paths: ["Assets/Scripts/Audio/"],
|
|
1191
|
+
interfaces: [],
|
|
1192
|
+
quality_scenarios: [],
|
|
1193
|
+
adrs: [],
|
|
1194
|
+
responsibility: "Music playback, sound effects, spatial audio, and audio mixing",
|
|
1195
|
+
service: "main"
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
id: "data-layer",
|
|
1199
|
+
name: "Data Layer",
|
|
1200
|
+
level: 1,
|
|
1201
|
+
code_paths: ["Assets/Scripts/Data/"],
|
|
1202
|
+
interfaces: [],
|
|
1203
|
+
quality_scenarios: [],
|
|
1204
|
+
adrs: [],
|
|
1205
|
+
responsibility: "ScriptableObject definitions, save/load system, game configuration, and persistent data",
|
|
1206
|
+
service: "main"
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
id: "editor-tools",
|
|
1210
|
+
name: "Editor Tools",
|
|
1211
|
+
level: 1,
|
|
1212
|
+
code_paths: ["Assets/Editor/"],
|
|
1213
|
+
interfaces: [],
|
|
1214
|
+
quality_scenarios: [],
|
|
1215
|
+
adrs: [],
|
|
1216
|
+
responsibility: "Custom inspectors, editor windows, debug overlays, and development tools",
|
|
1217
|
+
service: "main"
|
|
1218
|
+
}
|
|
1219
|
+
];
|
|
1220
|
+
}
|
|
1090
1221
|
return {
|
|
1091
1222
|
frontmatter: {
|
|
1092
1223
|
section: "building-blocks",
|
|
@@ -1121,6 +1252,15 @@ Client \u2192 Kestrel \u2192 Middleware Pipeline \u2192 Controller / Endpoint
|
|
|
1121
1252
|
Client \u2192 HTTP Server \u2192 Middleware \u2192 Route Handler
|
|
1122
1253
|
\u2192 Services
|
|
1123
1254
|
\u2192 Database / External APIs
|
|
1255
|
+
\`\`\``;
|
|
1256
|
+
case "unity-game":
|
|
1257
|
+
return `\`\`\`
|
|
1258
|
+
Input System \u2192 Player Controller \u2192 Gameplay Systems
|
|
1259
|
+
\u2192 Physics / Collision
|
|
1260
|
+
GameManager \u2192 State Machine \u2192 Active Game Systems
|
|
1261
|
+
\u2192 UI Framework
|
|
1262
|
+
\u2192 Audio System
|
|
1263
|
+
Unity Engine \u2192 Update Loop \u2192 Render Pipeline
|
|
1124
1264
|
\`\`\``;
|
|
1125
1265
|
default:
|
|
1126
1266
|
return `\`\`\`
|
|
@@ -1140,7 +1280,7 @@ function runtimeViewsTemplate(input) {
|
|
|
1140
1280
|
|
|
1141
1281
|
## Key Runtime Scenarios
|
|
1142
1282
|
|
|
1143
|
-
### Request Flow
|
|
1283
|
+
### ${input.template === "unity-game" ? "Game Loop" : "Request Flow"}
|
|
1144
1284
|
|
|
1145
1285
|
${runtimeDiagram(input.template)}
|
|
1146
1286
|
|
|
@@ -1168,7 +1308,13 @@ ${input.template === "dotnet-webapi" ? `| Platform | Description | Notes |
|
|
|
1168
1308
|
|----------|-------------|-------|
|
|
1169
1309
|
| Azure App Service | Managed PaaS for .NET | Recommended for ASP.NET Core |
|
|
1170
1310
|
| Docker / Kubernetes | Container-based | For self-hosted or multi-cloud |
|
|
1171
|
-
| AWS ECS / Fargate | Container orchestration | For AWS environments |` : `| Platform | Description | Notes |
|
|
1311
|
+
| AWS ECS / Fargate | Container orchestration | For AWS environments |` : input.template === "unity-game" ? `| Platform | Description | Notes |
|
|
1312
|
+
|----------|-------------|-------|
|
|
1313
|
+
| Steam | PC distribution | Recommended for indie games |
|
|
1314
|
+
| Apple App Store | iOS distribution | Requires Xcode build |
|
|
1315
|
+
| Google Play | Android distribution | For mobile games |
|
|
1316
|
+
| WebGL | Browser-based | For quick prototypes and web distribution |
|
|
1317
|
+
| Console | PlayStation, Xbox, Switch | Requires platform-specific SDKs |` : `| Platform | Description | Notes |
|
|
1172
1318
|
|----------|-------------|-------|
|
|
1173
1319
|
| Vercel | Recommended for Next.js | Zero-config deployment |
|
|
1174
1320
|
| Docker | Container-based | For self-hosted environments |`}
|
|
@@ -1177,7 +1323,7 @@ ${input.template === "dotnet-webapi" ? `| Platform | Description | Notes |
|
|
|
1177
1323
|
|
|
1178
1324
|
| Variable | Description | Required |
|
|
1179
1325
|
|----------|-------------|----------|
|
|
1180
|
-
| \`${input.template === "dotnet-webapi" ? "ASPNETCORE_ENVIRONMENT" : "NODE_ENV"}\` | Runtime environment | Yes |
|
|
1326
|
+
| \`${input.template === "dotnet-webapi" ? "ASPNETCORE_ENVIRONMENT" : input.template === "unity-game" ? "UNITY_TARGET_PLATFORM" : "NODE_ENV"}\` | ${input.template === "unity-game" ? "Build target platform" : "Runtime environment"} | Yes |
|
|
1181
1327
|
| *Add your environment variables here* | | |
|
|
1182
1328
|
`
|
|
1183
1329
|
};
|
|
@@ -1193,6 +1339,8 @@ function firstAdrTemplate(input) {
|
|
|
1193
1339
|
return reactViteAdr(input, now);
|
|
1194
1340
|
case "api-service":
|
|
1195
1341
|
return apiServiceAdr(input, now);
|
|
1342
|
+
case "unity-game":
|
|
1343
|
+
return unityAdr(input, now);
|
|
1196
1344
|
default:
|
|
1197
1345
|
return nextjsAdr(input, now);
|
|
1198
1346
|
}
|
|
@@ -1297,6 +1445,44 @@ Use a Node.js HTTP framework (Express, Fastify, or Hono) as the API service foun
|
|
|
1297
1445
|
`
|
|
1298
1446
|
};
|
|
1299
1447
|
}
|
|
1448
|
+
function unityAdr(input, date) {
|
|
1449
|
+
return {
|
|
1450
|
+
filename: "001-unity-code-heavy.md",
|
|
1451
|
+
frontmatter: {
|
|
1452
|
+
id: "001-unity-code-heavy",
|
|
1453
|
+
title: "Use Unity with Code-Heavy Architecture",
|
|
1454
|
+
status: "accepted",
|
|
1455
|
+
date,
|
|
1456
|
+
affected_blocks: ["game-core", "player-systems"],
|
|
1457
|
+
affected_files: ["Assets/Scripts/"],
|
|
1458
|
+
quality_scenarios: []
|
|
1459
|
+
},
|
|
1460
|
+
body: `# ADR-001: Use Unity with Code-Heavy Architecture
|
|
1461
|
+
|
|
1462
|
+
## Context
|
|
1463
|
+
|
|
1464
|
+
${input.name} needs a game engine with cross-platform support, strong performance, and a productive development workflow. The team prefers a code-driven approach over hand-crafting scenes in the editor.
|
|
1465
|
+
|
|
1466
|
+
## Decision
|
|
1467
|
+
|
|
1468
|
+
Use Unity as the game engine with a code-heavy C# architecture. Favor programmatic scene composition, ScriptableObject data architecture, and assembly definitions for modular code organization.
|
|
1469
|
+
|
|
1470
|
+
## Consequences
|
|
1471
|
+
|
|
1472
|
+
- **Positive:** Version control friendly \u2014 most logic lives in .cs files, not serialized scenes
|
|
1473
|
+
- **Positive:** Testable \u2014 gameplay logic can be unit tested without the editor
|
|
1474
|
+
- **Positive:** Reusable systems \u2014 assembly definitions enforce module boundaries
|
|
1475
|
+
- **Positive:** AI-agent friendly \u2014 agents work effectively with C# scripts
|
|
1476
|
+
- **Negative:** More boilerplate than visual scripting or drag-and-drop workflows
|
|
1477
|
+
- **Negative:** Scene references require discipline (use ScriptableObjects or addressables)
|
|
1478
|
+
- **Negative:** Some Unity features (Animator, Timeline) still require editor interaction
|
|
1479
|
+
|
|
1480
|
+
## Agent Limitations
|
|
1481
|
+
|
|
1482
|
+
AI agents can review C# scripts, suggest architectural improvements, and check code quality \u2014 but they **cannot** evaluate gameplay feel, frame timing, or visual quality. Use [Unity-MCP](https://github.com/IvanMurzak/Unity-MCP) to give agents basic editor access (scene management, asset operations). For runtime quality (actual FPS, GC spikes, input latency), rely on the Unity Profiler and manual playtesting.
|
|
1483
|
+
`
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1300
1486
|
function dotnetAdr(input, date) {
|
|
1301
1487
|
return {
|
|
1302
1488
|
filename: "001-aspnet-core-webapi.md",
|
|
@@ -1611,11 +1797,139 @@ var API_SCENARIOS = {
|
|
|
1611
1797
|
}
|
|
1612
1798
|
]
|
|
1613
1799
|
};
|
|
1800
|
+
var UNITY_GAME_SCENARIOS = {
|
|
1801
|
+
performance: [
|
|
1802
|
+
{
|
|
1803
|
+
id: "PERF-01",
|
|
1804
|
+
name: "Frame rate stability at 60 FPS",
|
|
1805
|
+
category: "performance",
|
|
1806
|
+
priority: "must",
|
|
1807
|
+
scenario: "Game runs on target hardware during typical gameplay",
|
|
1808
|
+
expected: "Maintains 60 FPS (or platform target) with no frame exceeding 16.7ms",
|
|
1809
|
+
linked_code: [],
|
|
1810
|
+
linked_tests: [],
|
|
1811
|
+
linked_blocks: ["game-core"],
|
|
1812
|
+
verification: "semi-automatic",
|
|
1813
|
+
status: "untested"
|
|
1814
|
+
},
|
|
1815
|
+
{
|
|
1816
|
+
id: "PERF-02",
|
|
1817
|
+
name: "Zero per-frame GC allocations in gameplay",
|
|
1818
|
+
category: "performance",
|
|
1819
|
+
priority: "must",
|
|
1820
|
+
scenario: "Gameplay systems run during a typical session",
|
|
1821
|
+
expected: "No GC allocations per frame in hot-path gameplay code (use object pooling)",
|
|
1822
|
+
linked_code: [],
|
|
1823
|
+
linked_tests: [],
|
|
1824
|
+
linked_blocks: ["gameplay-systems"],
|
|
1825
|
+
verification: "semi-automatic",
|
|
1826
|
+
status: "untested"
|
|
1827
|
+
},
|
|
1828
|
+
{
|
|
1829
|
+
id: "PERF-03",
|
|
1830
|
+
name: "Draw calls under budget",
|
|
1831
|
+
category: "performance",
|
|
1832
|
+
priority: "should",
|
|
1833
|
+
scenario: "Peak visual complexity scene is rendered",
|
|
1834
|
+
expected: "Draw calls stay under 200 on target hardware (use batching, atlasing, instancing)",
|
|
1835
|
+
linked_code: [],
|
|
1836
|
+
linked_tests: [],
|
|
1837
|
+
linked_blocks: [],
|
|
1838
|
+
verification: "semi-automatic",
|
|
1839
|
+
status: "untested"
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
id: "PERF-04",
|
|
1843
|
+
name: "Scene load time under 3s",
|
|
1844
|
+
category: "performance",
|
|
1845
|
+
priority: "should",
|
|
1846
|
+
scenario: "Player transitions between major scenes",
|
|
1847
|
+
expected: "Scene load completes within 3 seconds on minimum-spec hardware",
|
|
1848
|
+
linked_code: [],
|
|
1849
|
+
linked_tests: [],
|
|
1850
|
+
linked_blocks: ["game-core"],
|
|
1851
|
+
verification: "semi-automatic",
|
|
1852
|
+
status: "untested"
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
id: "PERF-05",
|
|
1856
|
+
name: "Memory usage under platform budget",
|
|
1857
|
+
category: "performance",
|
|
1858
|
+
priority: "should",
|
|
1859
|
+
scenario: "Game is loaded and gameplay session is active",
|
|
1860
|
+
expected: "Memory stays under 512MB on mobile, 2GB on desktop",
|
|
1861
|
+
linked_code: [],
|
|
1862
|
+
linked_tests: [],
|
|
1863
|
+
linked_blocks: [],
|
|
1864
|
+
verification: "semi-automatic",
|
|
1865
|
+
status: "untested"
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
id: "PERF-06",
|
|
1869
|
+
name: "Input-to-visual response under 100ms",
|
|
1870
|
+
category: "performance",
|
|
1871
|
+
priority: "should",
|
|
1872
|
+
scenario: "Player presses an input during gameplay",
|
|
1873
|
+
expected: "Visual feedback appears within 100ms of input",
|
|
1874
|
+
linked_code: [],
|
|
1875
|
+
linked_tests: [],
|
|
1876
|
+
linked_blocks: ["input-system", "player-systems"],
|
|
1877
|
+
verification: "semi-automatic",
|
|
1878
|
+
status: "untested"
|
|
1879
|
+
}
|
|
1880
|
+
],
|
|
1881
|
+
security: [
|
|
1882
|
+
{
|
|
1883
|
+
id: "SEC-01",
|
|
1884
|
+
name: "No client-only validation for multiplayer state",
|
|
1885
|
+
category: "security",
|
|
1886
|
+
priority: "should",
|
|
1887
|
+
scenario: "Game state changes are validated (if multiplayer)",
|
|
1888
|
+
expected: "Critical game state changes are server-authoritative; client cannot cheat by modifying local state",
|
|
1889
|
+
linked_code: [],
|
|
1890
|
+
linked_tests: [],
|
|
1891
|
+
linked_blocks: [],
|
|
1892
|
+
verification: "manual",
|
|
1893
|
+
status: "untested"
|
|
1894
|
+
}
|
|
1895
|
+
],
|
|
1896
|
+
reliability: [
|
|
1897
|
+
{
|
|
1898
|
+
id: "REL-01",
|
|
1899
|
+
name: "No unhandled exceptions crash the game",
|
|
1900
|
+
category: "reliability",
|
|
1901
|
+
priority: "should",
|
|
1902
|
+
scenario: "An unexpected error occurs during gameplay",
|
|
1903
|
+
expected: "Error is caught and logged; game recovers gracefully or shows error UI without crashing",
|
|
1904
|
+
linked_code: [],
|
|
1905
|
+
linked_tests: [],
|
|
1906
|
+
linked_blocks: ["game-core"],
|
|
1907
|
+
verification: "automatic",
|
|
1908
|
+
status: "untested"
|
|
1909
|
+
}
|
|
1910
|
+
],
|
|
1911
|
+
accessibility: [
|
|
1912
|
+
{
|
|
1913
|
+
id: "A11Y-01",
|
|
1914
|
+
name: "Color-blind friendly UI",
|
|
1915
|
+
category: "accessibility",
|
|
1916
|
+
priority: "should",
|
|
1917
|
+
scenario: "Player with color vision deficiency plays the game",
|
|
1918
|
+
expected: "Critical UI elements distinguish by shape, pattern, or label \u2014 not color alone",
|
|
1919
|
+
linked_code: [],
|
|
1920
|
+
linked_tests: [],
|
|
1921
|
+
linked_blocks: ["ui-framework"],
|
|
1922
|
+
verification: "manual",
|
|
1923
|
+
status: "untested"
|
|
1924
|
+
}
|
|
1925
|
+
]
|
|
1926
|
+
};
|
|
1614
1927
|
var TEMPLATE_SCENARIOS = {
|
|
1615
1928
|
"nextjs-app-router": FRONTEND_SCENARIOS,
|
|
1616
1929
|
"react-vite": FRONTEND_SCENARIOS,
|
|
1617
1930
|
"api-service": API_SCENARIOS,
|
|
1618
|
-
"dotnet-webapi": DOTNET_SCENARIOS
|
|
1931
|
+
"dotnet-webapi": DOTNET_SCENARIOS,
|
|
1932
|
+
"unity-game": UNITY_GAME_SCENARIOS
|
|
1619
1933
|
};
|
|
1620
1934
|
function mergeScenarios(template, category) {
|
|
1621
1935
|
const shared = SHARED_SCENARIOS[category] ?? [];
|
|
@@ -1835,12 +2149,96 @@ function apiConcepts() {
|
|
|
1835
2149
|
- Schema versioning approach for event contracts
|
|
1836
2150
|
`;
|
|
1837
2151
|
}
|
|
2152
|
+
function unityConcepts() {
|
|
2153
|
+
return `## Scripting Architecture
|
|
2154
|
+
|
|
2155
|
+
*Document the code organization and scripting patterns once established.*
|
|
2156
|
+
|
|
2157
|
+
- MonoBehaviour vs plain C# class usage guidelines
|
|
2158
|
+
- Assembly definition (.asmdef) boundaries and dependencies
|
|
2159
|
+
- Component composition patterns
|
|
2160
|
+
- Singleton vs dependency injection approach
|
|
2161
|
+
|
|
2162
|
+
## Asset Management
|
|
2163
|
+
|
|
2164
|
+
*Document how assets are organized and loaded.*
|
|
2165
|
+
|
|
2166
|
+
- Folder structure and naming conventions
|
|
2167
|
+
- Resource loading strategy (Resources, Addressables, AssetBundles)
|
|
2168
|
+
- Asset versioning and memory lifecycle
|
|
2169
|
+
- Prefab organization and instantiation patterns
|
|
2170
|
+
|
|
2171
|
+
## Scene Management
|
|
2172
|
+
|
|
2173
|
+
*Document the scene structure and loading strategy.*
|
|
2174
|
+
|
|
2175
|
+
- Scene organization (main scenes, additive scenes, test scenes)
|
|
2176
|
+
- Scene loading patterns (async loading, transition effects)
|
|
2177
|
+
- DontDestroyOnLoad usage and persistent objects
|
|
2178
|
+
- Scene-to-scene data passing
|
|
2179
|
+
|
|
2180
|
+
## Physics & Collision
|
|
2181
|
+
|
|
2182
|
+
*Document physics setup and collision detection.*
|
|
2183
|
+
|
|
2184
|
+
- Physics layers and collision matrix configuration
|
|
2185
|
+
- Rigidbody usage guidelines (kinematic vs dynamic)
|
|
2186
|
+
- Collision detection mode choices
|
|
2187
|
+
- Physics performance budget
|
|
2188
|
+
|
|
2189
|
+
## Input Handling
|
|
2190
|
+
|
|
2191
|
+
*Document player input processing.*
|
|
2192
|
+
|
|
2193
|
+
- Input System package configuration and action maps
|
|
2194
|
+
- Input abstraction layer for platform-independent code
|
|
2195
|
+
- Rebinding and accessibility considerations
|
|
2196
|
+
- Mobile/touch input handling
|
|
2197
|
+
|
|
2198
|
+
## Audio
|
|
2199
|
+
|
|
2200
|
+
*Document audio implementation.*
|
|
2201
|
+
|
|
2202
|
+
- AudioMixer group structure
|
|
2203
|
+
- Music vs SFX management and pooling
|
|
2204
|
+
- Spatial audio configuration
|
|
2205
|
+
- Volume control and persistence
|
|
2206
|
+
|
|
2207
|
+
## Visual Effects & Animation
|
|
2208
|
+
|
|
2209
|
+
*Document visual effects and animation approach.*
|
|
2210
|
+
|
|
2211
|
+
- Particle system conventions
|
|
2212
|
+
- Shader usage and material management
|
|
2213
|
+
- Animator controller organization and state naming
|
|
2214
|
+
- Animation event and callback patterns
|
|
2215
|
+
|
|
2216
|
+
## Object Pooling
|
|
2217
|
+
|
|
2218
|
+
*Document object pooling strategy.*
|
|
2219
|
+
|
|
2220
|
+
- Which objects are pooled (projectiles, effects, enemies)
|
|
2221
|
+
- Pool sizing and growth strategy
|
|
2222
|
+
- Return-to-pool lifecycle management
|
|
2223
|
+
|
|
2224
|
+
## Save System
|
|
2225
|
+
|
|
2226
|
+
*Document the save/load approach.*
|
|
2227
|
+
|
|
2228
|
+
- Serialization format (JSON, binary, PlayerPrefs)
|
|
2229
|
+
- Save data structure and versioning
|
|
2230
|
+
- Auto-save and checkpoint strategy
|
|
2231
|
+
`;
|
|
2232
|
+
}
|
|
1838
2233
|
function crosscuttingTemplate(input) {
|
|
1839
2234
|
const isDotnet = input.template === "dotnet-webapi";
|
|
1840
2235
|
const isFrontend = input.template === "nextjs-app-router" || input.template === "react-vite";
|
|
2236
|
+
const isUnity = input.template === "unity-game";
|
|
1841
2237
|
let concepts;
|
|
1842
2238
|
if (isDotnet) {
|
|
1843
2239
|
concepts = dotnetConcepts();
|
|
2240
|
+
} else if (isUnity) {
|
|
2241
|
+
concepts = unityConcepts();
|
|
1844
2242
|
} else if (isFrontend) {
|
|
1845
2243
|
concepts = frontendConcepts();
|
|
1846
2244
|
} else {
|
|
@@ -2843,12 +3241,197 @@ function phaseTasksTemplate4(_input, phaseId) {
|
|
|
2843
3241
|
return tasksByPhase[phaseId] ?? null;
|
|
2844
3242
|
}
|
|
2845
3243
|
|
|
3244
|
+
// src/templates/phases/unity-game.ts
|
|
3245
|
+
function phasePlanTemplate5(_input) {
|
|
3246
|
+
const phases = [
|
|
3247
|
+
{
|
|
3248
|
+
id: "phase-0-setup",
|
|
3249
|
+
name: "Project Setup",
|
|
3250
|
+
phase_number: 0,
|
|
3251
|
+
status: "in-progress",
|
|
3252
|
+
description: "Initialize Unity project structure, configure input system, core game loop, and assembly definitions",
|
|
3253
|
+
gate_requirements: [
|
|
3254
|
+
"Unity project opens and runs without errors",
|
|
3255
|
+
"Assembly definitions (.asmdef) created for each module",
|
|
3256
|
+
"Basic scene loads and game loop runs at target FPS",
|
|
3257
|
+
"Development tooling configured (version control, IDE, logging)"
|
|
3258
|
+
]
|
|
3259
|
+
},
|
|
3260
|
+
{
|
|
3261
|
+
id: "phase-1-core",
|
|
3262
|
+
name: "Core Systems",
|
|
3263
|
+
phase_number: 1,
|
|
3264
|
+
status: "planned",
|
|
3265
|
+
description: "Player controller, camera system, game state machine, data architecture with ScriptableObjects",
|
|
3266
|
+
gate_requirements: [
|
|
3267
|
+
"Player input responds and controls character/object",
|
|
3268
|
+
"Camera system follows player correctly",
|
|
3269
|
+
"Game state machine handles transitions (menu, playing, paused)",
|
|
3270
|
+
"ScriptableObject data architecture established",
|
|
3271
|
+
"Quality scenarios PERF-01, MAINT-01 verified"
|
|
3272
|
+
]
|
|
3273
|
+
},
|
|
3274
|
+
{
|
|
3275
|
+
id: "phase-2-gameplay",
|
|
3276
|
+
name: "Gameplay Features",
|
|
3277
|
+
phase_number: 2,
|
|
3278
|
+
status: "planned",
|
|
3279
|
+
description: "Core game mechanics, level design, UI framework, audio integration, save/load system",
|
|
3280
|
+
gate_requirements: [
|
|
3281
|
+
"Core gameplay loop complete and playable",
|
|
3282
|
+
"UI framework in place (HUD, menus, dialogs)",
|
|
3283
|
+
"Audio system integrated (music, SFX)",
|
|
3284
|
+
"Save/load system working",
|
|
3285
|
+
"Performance targets met on target platforms"
|
|
3286
|
+
]
|
|
3287
|
+
},
|
|
3288
|
+
{
|
|
3289
|
+
id: "phase-3-polish",
|
|
3290
|
+
name: "Polish & Launch",
|
|
3291
|
+
phase_number: 3,
|
|
3292
|
+
status: "planned",
|
|
3293
|
+
description: "Performance profiling, accessibility, platform-specific builds, bug fixes, and release",
|
|
3294
|
+
gate_requirements: [
|
|
3295
|
+
"All quality scenarios passing",
|
|
3296
|
+
"Accessibility audit complete",
|
|
3297
|
+
"Platform-specific builds tested and optimized",
|
|
3298
|
+
"No critical or major bugs outstanding",
|
|
3299
|
+
"Release build successful"
|
|
3300
|
+
]
|
|
3301
|
+
}
|
|
3302
|
+
];
|
|
3303
|
+
return { schema_version: 1, phases };
|
|
3304
|
+
}
|
|
3305
|
+
function phaseTasksTemplate5(_input, phaseId) {
|
|
3306
|
+
const tasksByPhase = {
|
|
3307
|
+
"phase-0-setup": {
|
|
3308
|
+
schema_version: 1,
|
|
3309
|
+
phase_id: "phase-0-setup",
|
|
3310
|
+
tasks: [
|
|
3311
|
+
{
|
|
3312
|
+
id: "task-0.1-project-structure",
|
|
3313
|
+
title: "Set up Unity project folder structure and assembly definitions",
|
|
3314
|
+
status: "todo",
|
|
3315
|
+
building_block: "game-core",
|
|
3316
|
+
quality_scenarios: ["MAINT-01"],
|
|
3317
|
+
acceptance_criteria: [
|
|
3318
|
+
"Folder structure: Assets/Scripts/{Core,Input,Player,Gameplay,UI,Audio,Data}, Assets/Editor/",
|
|
3319
|
+
"Assembly definition (.asmdef) for each script folder",
|
|
3320
|
+
"Version control configured (.gitignore for Library/, Temp/, Logs/)"
|
|
3321
|
+
]
|
|
3322
|
+
},
|
|
3323
|
+
{
|
|
3324
|
+
id: "task-0.2-core-loop",
|
|
3325
|
+
title: "Implement core game loop and GameManager",
|
|
3326
|
+
status: "todo",
|
|
3327
|
+
building_block: "game-core",
|
|
3328
|
+
quality_scenarios: ["PERF-01"],
|
|
3329
|
+
acceptance_criteria: [
|
|
3330
|
+
"GameManager handles game lifecycle (init, run, pause, quit)",
|
|
3331
|
+
"Main scene loads and runs at target frame rate",
|
|
3332
|
+
"Debug logging infrastructure in place"
|
|
3333
|
+
]
|
|
3334
|
+
},
|
|
3335
|
+
{
|
|
3336
|
+
id: "task-0.3-input-system",
|
|
3337
|
+
title: "Configure Unity Input System",
|
|
3338
|
+
status: "todo",
|
|
3339
|
+
building_block: "input-system",
|
|
3340
|
+
quality_scenarios: [],
|
|
3341
|
+
acceptance_criteria: [
|
|
3342
|
+
"New Input System package installed and configured",
|
|
3343
|
+
"Input action asset with default action maps",
|
|
3344
|
+
"Input abstraction layer for platform-independent handling"
|
|
3345
|
+
]
|
|
3346
|
+
},
|
|
3347
|
+
{
|
|
3348
|
+
id: "task-0.4-testing",
|
|
3349
|
+
title: "Set up testing infrastructure",
|
|
3350
|
+
status: "todo",
|
|
3351
|
+
quality_scenarios: ["MAINT-02"],
|
|
3352
|
+
acceptance_criteria: [
|
|
3353
|
+
"EditMode test assembly created (NUnit)",
|
|
3354
|
+
"PlayMode test assembly created",
|
|
3355
|
+
"Basic test for GameManager lifecycle"
|
|
3356
|
+
]
|
|
3357
|
+
}
|
|
3358
|
+
]
|
|
3359
|
+
},
|
|
3360
|
+
"phase-1-core": {
|
|
3361
|
+
schema_version: 1,
|
|
3362
|
+
phase_id: "phase-1-core",
|
|
3363
|
+
tasks: [
|
|
3364
|
+
{
|
|
3365
|
+
id: "task-1.1-player-controller",
|
|
3366
|
+
title: "Implement player controller and movement",
|
|
3367
|
+
status: "todo",
|
|
3368
|
+
building_block: "player-systems",
|
|
3369
|
+
quality_scenarios: ["PERF-06"],
|
|
3370
|
+
acceptance_criteria: [
|
|
3371
|
+
"Player character spawns and responds to input",
|
|
3372
|
+
"Movement feels responsive (< 100ms input-to-visual)",
|
|
3373
|
+
"Physics/collision configured correctly"
|
|
3374
|
+
]
|
|
3375
|
+
},
|
|
3376
|
+
{
|
|
3377
|
+
id: "task-1.2-camera-system",
|
|
3378
|
+
title: "Implement camera system",
|
|
3379
|
+
status: "todo",
|
|
3380
|
+
building_block: "player-systems",
|
|
3381
|
+
quality_scenarios: [],
|
|
3382
|
+
acceptance_criteria: [
|
|
3383
|
+
"Camera follows player smoothly",
|
|
3384
|
+
"Camera handles transitions and edge cases",
|
|
3385
|
+
"Camera settings configurable via ScriptableObject"
|
|
3386
|
+
]
|
|
3387
|
+
},
|
|
3388
|
+
{
|
|
3389
|
+
id: "task-1.3-data-architecture",
|
|
3390
|
+
title: "Set up ScriptableObject data architecture",
|
|
3391
|
+
status: "todo",
|
|
3392
|
+
building_block: "data-layer",
|
|
3393
|
+
quality_scenarios: [],
|
|
3394
|
+
acceptance_criteria: [
|
|
3395
|
+
"ScriptableObject base types for game config, events, and data",
|
|
3396
|
+
"Event channel pattern for decoupled communication",
|
|
3397
|
+
"Game settings accessible from ScriptableObject assets"
|
|
3398
|
+
]
|
|
3399
|
+
},
|
|
3400
|
+
{
|
|
3401
|
+
id: "task-1.4-state-machine",
|
|
3402
|
+
title: "Implement game state machine",
|
|
3403
|
+
status: "todo",
|
|
3404
|
+
building_block: "game-core",
|
|
3405
|
+
quality_scenarios: [],
|
|
3406
|
+
acceptance_criteria: [
|
|
3407
|
+
"State machine handles: MainMenu, Loading, Playing, Paused, GameOver",
|
|
3408
|
+
"Clean transitions between states",
|
|
3409
|
+
"State-specific systems enabled/disabled correctly"
|
|
3410
|
+
]
|
|
3411
|
+
},
|
|
3412
|
+
{
|
|
3413
|
+
id: "task-1.5-document-decisions",
|
|
3414
|
+
title: "Document architectural decisions as ADRs",
|
|
3415
|
+
status: "todo",
|
|
3416
|
+
quality_scenarios: [],
|
|
3417
|
+
acceptance_criteria: [
|
|
3418
|
+
"ADR for each significant architecture/pattern choice",
|
|
3419
|
+
"ADRs linked to affected building blocks and code paths"
|
|
3420
|
+
]
|
|
3421
|
+
}
|
|
3422
|
+
]
|
|
3423
|
+
}
|
|
3424
|
+
};
|
|
3425
|
+
return tasksByPhase[phaseId] ?? null;
|
|
3426
|
+
}
|
|
3427
|
+
|
|
2846
3428
|
// src/generators/plan-generator.ts
|
|
2847
3429
|
var planTemplates = {
|
|
2848
3430
|
"nextjs-app-router": { plan: phasePlanTemplate, tasks: phaseTasksTemplate },
|
|
2849
3431
|
"react-vite": { plan: phasePlanTemplate2, tasks: phaseTasksTemplate2 },
|
|
2850
3432
|
"api-service": { plan: phasePlanTemplate3, tasks: phaseTasksTemplate3 },
|
|
2851
|
-
"dotnet-webapi": { plan: phasePlanTemplate4, tasks: phaseTasksTemplate4 }
|
|
3433
|
+
"dotnet-webapi": { plan: phasePlanTemplate4, tasks: phaseTasksTemplate4 },
|
|
3434
|
+
"unity-game": { plan: phasePlanTemplate5, tasks: phaseTasksTemplate5 }
|
|
2852
3435
|
};
|
|
2853
3436
|
function generatePlan(targetDir, input) {
|
|
2854
3437
|
const planDir = join5(targetDir, ".arcbridge", "plan");
|
|
@@ -2974,14 +3557,41 @@ You are responsible for maintaining these sections in \`.arcbridge/arc42/\`. Upd
|
|
|
2974
3557
|
- All ADRs and their status
|
|
2975
3558
|
- Building block \u2192 code mapping
|
|
2976
3559
|
|
|
3560
|
+
## Post-Init Tailoring (CRITICAL \u2014 Do This Before Writing Code)
|
|
3561
|
+
|
|
3562
|
+
The building blocks, quality scenarios, and phase tasks generated during init are a **generic starting template**, not a project-specific plan. Before writing any code, systematically tailor the generated content to the actual project:
|
|
3563
|
+
|
|
3564
|
+
1. **Building blocks:** Review each generated block against the project description. Delete blocks that don't apply (e.g., "API Client" for a client-only app). Add blocks for the real modules/features you'll build. **Declare interfaces between blocks** to specify dependencies \u2014 drift detection and phase gates rely on this.
|
|
3565
|
+
2. **Quality scenarios:** Review each scenario against the project's quality priorities. Delete irrelevant ones (e.g., "API response time" for a localStorage-only app). Add scenarios that reflect the actual requirements.
|
|
3566
|
+
3. **Phase tasks:** Phase 0-1 tasks are ready to use. **Phase 2+ tasks are examples \u2014 delete them** and create tasks that match the features you're actually building. Keep phases small and focused (3-6 tasks per phase). Add more phases if needed using \`arcbridge_create_phase\` \u2014 6, 8, or 10 phases is fine for larger projects.
|
|
3567
|
+
4. **Reindex** after making changes so drift detection picks up your tailored architecture.
|
|
3568
|
+
|
|
3569
|
+
The goal is that by the time you start Phase 0, the building blocks describe your architecture, the quality scenarios test your requirements, and the tasks reflect your build plan.
|
|
3570
|
+
|
|
3571
|
+
### Building Block interfaces
|
|
3572
|
+
|
|
3573
|
+
Each building block in \`05-building-blocks.md\` should declare its dependencies on other blocks using the \`interfaces\` field. This is required for drift detection to catch undeclared cross-block dependencies at phase gates.
|
|
3574
|
+
|
|
3575
|
+
Format \u2014 within the \`blocks:\` array, list the IDs of other blocks this block depends on:
|
|
3576
|
+
\`\`\`yaml
|
|
3577
|
+
blocks:
|
|
3578
|
+
- id: canvas-engine
|
|
3579
|
+
name: Canvas Engine
|
|
3580
|
+
level: 1
|
|
3581
|
+
responsibility: "Render and manage collaborative canvas state"
|
|
3582
|
+
service: main
|
|
3583
|
+
code_paths:
|
|
3584
|
+
- "src/canvas/"
|
|
3585
|
+
interfaces:
|
|
3586
|
+
- workflow-model
|
|
3587
|
+
- shared-types
|
|
3588
|
+
\`\`\`
|
|
3589
|
+
|
|
3590
|
+
If your code imports across block boundaries without declaring the interface, \`arcbridge_check_drift\` will flag it and \`arcbridge_complete_phase\` will block the gate.
|
|
3591
|
+
|
|
2977
3592
|
## Project Planning
|
|
2978
3593
|
|
|
2979
|
-
|
|
2980
|
-
- **ArcBridge generates 4 phases as a starting template** (Setup, Foundation, Features, Polish). These are a baseline \u2014 adapt them to your project's actual scope and complexity.
|
|
2981
|
-
- **For larger projects, add more phases** using \`arcbridge_create_phase\`. Split "Core Features" into multiple phases if needed (e.g., "Auth & Users", "Core Business Logic", "Integrations", "Polish").
|
|
2982
|
-
- **Phase 0-1 tasks are ready to use** \u2014 they cover setup and foundation for this template
|
|
2983
|
-
- **Phase 2+ tasks are examples** \u2014 replace them with real tasks derived from the project's requirements and specifications
|
|
2984
|
-
- Review the phase plan with \`arcbridge_get_phase_plan\` and replace example tasks with project-specific ones
|
|
3594
|
+
- Review the phase plan with \`arcbridge_get_phase_plan\`
|
|
2985
3595
|
- Create tasks using \`arcbridge_create_task\` with the phase ID shown in the plan
|
|
2986
3596
|
- Keep each phase reasonably scoped \u2014 3-6 tasks per phase is ideal
|
|
2987
3597
|
- Map tasks to building blocks so drift detection tracks coverage
|
|
@@ -3492,7 +4102,7 @@ You cannot see screenshots, but you CAN reason about UI quality through code:
|
|
|
3492
4102
|
}
|
|
3493
4103
|
|
|
3494
4104
|
// src/generators/agent-generator.ts
|
|
3495
|
-
var UI_TEMPLATES = /* @__PURE__ */ new Set(["nextjs-app-router", "react-vite"]);
|
|
4105
|
+
var UI_TEMPLATES = /* @__PURE__ */ new Set(["nextjs-app-router", "react-vite", "unity-game"]);
|
|
3496
4106
|
function writeAgentRole(dir, role) {
|
|
3497
4107
|
const { system_prompt, ...frontmatter } = role;
|
|
3498
4108
|
const content = matter2.stringify(system_prompt, frontmatter);
|
|
@@ -5957,9 +6567,23 @@ async function indexCSharpTreeSitter(db, options) {
|
|
|
5957
6567
|
await ensureCSharpParser();
|
|
5958
6568
|
const service = options.service ?? "main";
|
|
5959
6569
|
const projectRoot = options.projectRoot;
|
|
6570
|
+
const ignorePatterns = [
|
|
6571
|
+
"**/bin/**",
|
|
6572
|
+
"**/obj/**",
|
|
6573
|
+
"**/node_modules/**",
|
|
6574
|
+
"**/.git/**",
|
|
6575
|
+
// Unity root-level directories (anchored to avoid matching nested folders
|
|
6576
|
+
// like src/Library/ or src/Packages/ in non-Unity .NET projects)
|
|
6577
|
+
"Library/**",
|
|
6578
|
+
"Temp/**",
|
|
6579
|
+
"Logs/**",
|
|
6580
|
+
"UserSettings/**",
|
|
6581
|
+
"Packages/**",
|
|
6582
|
+
"ProjectSettings/**"
|
|
6583
|
+
];
|
|
5960
6584
|
const csFiles = globbySync("**/*.cs", {
|
|
5961
6585
|
cwd: projectRoot,
|
|
5962
|
-
ignore:
|
|
6586
|
+
ignore: ignorePatterns,
|
|
5963
6587
|
absolute: false
|
|
5964
6588
|
});
|
|
5965
6589
|
const existingHashes = getExistingHashes(db, service);
|
|
@@ -6154,6 +6778,9 @@ function loadConfig(projectRoot) {
|
|
|
6154
6778
|
|
|
6155
6779
|
// src/indexer/index.ts
|
|
6156
6780
|
function detectProjectLanguage(projectRoot) {
|
|
6781
|
+
if (existsSync7(join14(projectRoot, "ProjectSettings")) && existsSync7(join14(projectRoot, "Assets"))) {
|
|
6782
|
+
return "csharp";
|
|
6783
|
+
}
|
|
6157
6784
|
if (existsSync7(join14(projectRoot, "tsconfig.json"))) return "typescript";
|
|
6158
6785
|
if (existsSync7(join14(projectRoot, "package.json"))) return "typescript";
|
|
6159
6786
|
if (findDotnetProject(projectRoot)) return "csharp";
|
|
@@ -6296,6 +6923,17 @@ var FRAMEWORK_IGNORES = {
|
|
|
6296
6923
|
"Properties/",
|
|
6297
6924
|
"Migrations/",
|
|
6298
6925
|
"wwwroot/"
|
|
6926
|
+
],
|
|
6927
|
+
"unity-game": [
|
|
6928
|
+
"Library/",
|
|
6929
|
+
"Temp/",
|
|
6930
|
+
"Logs/",
|
|
6931
|
+
"UserSettings/",
|
|
6932
|
+
"Packages/",
|
|
6933
|
+
"ProjectSettings/",
|
|
6934
|
+
"Assets/Plugins/",
|
|
6935
|
+
"obj/",
|
|
6936
|
+
"bin/"
|
|
6299
6937
|
]
|
|
6300
6938
|
};
|
|
6301
6939
|
function detectDrift(db, options) {
|
|
@@ -6560,7 +7198,7 @@ function safeParseJson(value, fallback) {
|
|
|
6560
7198
|
|
|
6561
7199
|
// src/sync/yaml-writer.ts
|
|
6562
7200
|
import { join as join15 } from "path";
|
|
6563
|
-
import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
7201
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync } from "fs";
|
|
6564
7202
|
import { parse as parse2, stringify as stringify4 } from "yaml";
|
|
6565
7203
|
function syncTaskToYaml(projectRoot, phaseId, taskId, status, completedAt) {
|
|
6566
7204
|
const taskPath = join15(
|
|
@@ -6744,6 +7382,41 @@ function deleteTaskFromYaml(projectRoot, phaseId, taskId) {
|
|
|
6744
7382
|
};
|
|
6745
7383
|
}
|
|
6746
7384
|
}
|
|
7385
|
+
function deletePhaseFromYaml(projectRoot, phaseId) {
|
|
7386
|
+
try {
|
|
7387
|
+
const phasesPath = join15(projectRoot, ".arcbridge", "plan", "phases.yaml");
|
|
7388
|
+
if (!existsSync8(phasesPath)) {
|
|
7389
|
+
return { success: false, warning: "phases.yaml not found" };
|
|
7390
|
+
}
|
|
7391
|
+
const raw = readFileSync8(phasesPath, "utf-8");
|
|
7392
|
+
const result = PhasesFileSchema.safeParse(parse2(raw));
|
|
7393
|
+
if (!result.success) {
|
|
7394
|
+
return {
|
|
7395
|
+
success: false,
|
|
7396
|
+
warning: "Could not parse phases.yaml \u2014 phase may reappear after reindex"
|
|
7397
|
+
};
|
|
7398
|
+
}
|
|
7399
|
+
const phasesFile = result.data;
|
|
7400
|
+
const before = phasesFile.phases.length;
|
|
7401
|
+
phasesFile.phases = phasesFile.phases.filter((p) => p.id !== phaseId);
|
|
7402
|
+
if (phasesFile.phases.length === before) {
|
|
7403
|
+
return { success: false, warning: `Phase '${phaseId}' not found in phases.yaml` };
|
|
7404
|
+
}
|
|
7405
|
+
writeFileSync5(phasesPath, stringify4(phasesFile), "utf-8");
|
|
7406
|
+
const taskFilePath = join15(projectRoot, ".arcbridge", "plan", "tasks", `${phaseId}.yaml`);
|
|
7407
|
+
try {
|
|
7408
|
+
unlinkSync(taskFilePath);
|
|
7409
|
+
} catch (e) {
|
|
7410
|
+
if (e.code !== "ENOENT") throw e;
|
|
7411
|
+
}
|
|
7412
|
+
return { success: true };
|
|
7413
|
+
} catch (err) {
|
|
7414
|
+
return {
|
|
7415
|
+
success: false,
|
|
7416
|
+
warning: `YAML update failed: ${err instanceof Error ? err.message : String(err)}`
|
|
7417
|
+
};
|
|
7418
|
+
}
|
|
7419
|
+
}
|
|
6747
7420
|
|
|
6748
7421
|
// src/sync/task-inference.ts
|
|
6749
7422
|
function inferTaskStatuses(db, phaseId) {
|
|
@@ -7721,6 +8394,7 @@ export {
|
|
|
7721
8394
|
addPhaseToYaml,
|
|
7722
8395
|
addTaskToYaml,
|
|
7723
8396
|
applyInferences,
|
|
8397
|
+
deletePhaseFromYaml,
|
|
7724
8398
|
deleteTaskFromYaml,
|
|
7725
8399
|
detectDrift,
|
|
7726
8400
|
detectProjectLanguage,
|