@archsight/aios 1.2.0 → 1.3.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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +59 -0
- package/OPENCODE.md +23 -0
- package/README.md +64 -31
- package/RELEASE_NOTES.md +37 -0
- package/adapters/workbuddy/README.md +11 -1
- package/agents/README.md +6 -3
- package/agents/atlas/responsibilities.md +1 -1
- package/agents/atlas/system-prompt.md +1 -1
- package/agents/daedalus/system-prompt.md +2 -0
- package/agents/hestia/constraints.md +7 -0
- package/agents/hestia/responsibilities.md +7 -0
- package/agents/hestia/role.md +12 -0
- package/agents/hestia/system-prompt.md +23 -0
- package/agents/hestia/workflow.md +8 -0
- package/agents/plutus/constraints.md +7 -0
- package/agents/plutus/responsibilities.md +7 -0
- package/agents/plutus/role.md +12 -0
- package/agents/plutus/system-prompt.md +24 -0
- package/agents/plutus/workflow.md +8 -0
- package/agents/themis/constraints.md +7 -0
- package/agents/themis/responsibilities.md +7 -0
- package/agents/themis/role.md +12 -0
- package/agents/themis/system-prompt.md +24 -0
- package/agents/themis/workflow.md +8 -0
- package/bin/archsight-aios.mjs +558 -25
- package/docs/PUBLIC_DISCOVERY.md +16 -2
- package/docs/business-expert-guide.md +5 -3
- package/docs/glossary.md +11 -3
- package/docs/quickstart.md +18 -4
- package/gemini-extension.json +1 -1
- package/governance/README.md +41 -11
- package/governance/agent-boundary.md +1 -2
- package/governance/ai-review-policy.md +1 -2
- package/governance/arbitration-protocol.md +33 -33
- package/governance/context-policy.md +2 -3
- package/governance/delivery-policy.md +1 -2
- package/governance/memory-policy.md +1 -2
- package/governance/security-policy.md +1 -2
- package/memory/decision-records.md +8 -9
- package/package.json +17 -6
- package/prompts/README.md +12 -0
- package/prompts/evaluation-policy.md +70 -0
- package/prompts/evaluations/engineering-business-basic-advisory-validation-2026-06-16.md +87 -0
- package/prompts/evaluations/engineering-business-basic-fixtures.json +375 -0
- package/prompts/evaluations/engineering-business-basic-model-output.example.json +179 -0
- package/prompts/evaluations/engineering-business-basic-prompts-2026-06-16.md +205 -0
- package/prompts/evaluations/engineering-business-basic-scorecard.json +238 -0
- package/prompts/evaluations/engineering-business-public-advisory-fixtures.json +422 -0
- package/prompts/evaluations/public-advisory-md/01-technical-bid.md +63 -0
- package/prompts/evaluations/public-advisory-md/02-contract.md +61 -0
- package/prompts/evaluations/public-advisory-md/03-daily.md +69 -0
- package/prompts/evaluations/public-advisory-md/04-meeting.md +48 -0
- package/prompts/evaluations/public-advisory-md/05-variation.md +63 -0
- package/prompts/evaluations/public-advisory-md/06-scheme.md +60 -0
- package/prompts/failure-cases.md +5 -1
- package/prompts/prompt-registry.md +10 -0
- package/runtime/agent-routing.md +39 -9
- package/runtime/archsight-aios.manifest.json +154 -51
- package/runtime/hermes/agent-registry.md +3 -0
- package/runtime/hermes/workspace-binding.md +3 -0
- package/runtime/skill-routing.md +23 -12
- package/scripts/analyze-prompt-run-results.mjs +187 -0
- package/scripts/build-prompt-run-pack.mjs +248 -0
- package/scripts/validate-prompt-fixtures.mjs +225 -0
- package/scripts/validate-prompt-model-outputs.mjs +201 -0
- package/scripts/validate-prompt-run-results.mjs +259 -0
- package/scripts/validate-prompt-scorecard.mjs +133 -0
- package/scripts/validate-skills.mjs +8 -3
- package/skills/README.md +12 -6
- package/skills/aios/SKILL.md +79 -0
- package/skills/aios/agents/openai.yaml +4 -0
- package/skills/aios-arch/SKILL.md +14 -14
- package/skills/aios-ceo/SKILL.md +13 -13
- package/skills/aios-commercial-contract/SKILL.md +32 -14
- package/skills/aios-commercial-contract/prompts/basic-prompt.md +83 -0
- package/skills/aios-commercial-tender/SKILL.md +31 -13
- package/skills/aios-commercial-tender/prompts/basic-prompt.md +94 -0
- package/skills/aios-commercial-variation/SKILL.md +33 -15
- package/skills/aios-commercial-variation/prompts/basic-prompt.md +99 -0
- package/skills/aios-compare/SKILL.md +92 -0
- package/skills/aios-compare/agents/openai.yaml +4 -0
- package/skills/aios-construction-daily/SKILL.md +32 -14
- package/skills/aios-construction-daily/prompts/basic-prompt.md +76 -0
- package/skills/aios-construction-meeting/SKILL.md +32 -14
- package/skills/aios-construction-meeting/prompts/basic-prompt.md +78 -0
- package/skills/aios-construction-scheme/SKILL.md +28 -10
- package/skills/aios-construction-scheme/prompts/basic-prompt.md +90 -0
- package/skills/aios-plan/SKILL.md +7 -7
- package/skills/aios-prompt-compare/SKILL.md +180 -0
- package/skills/aios-prompt-compare/agents/openai.yaml +4 -0
- package/skills/aios-review/SKILL.md +1 -1
- package/skills/aios-structural/SKILL.md +7 -7
- package/skills/archsight-aios/SKILL.md +40 -0
- package/skills/archsight-aios/agents/openai.yaml +4 -0
- package/skills/engineering-business-starter-kit.md +112 -0
- package/templates/README.md +16 -2
- package/templates/project-ai/.ai/ARCHSIGHT_AIOS_RULES.md +5 -4
- package/templates/project-ai/.ai/agent-routing.md +3 -1
- package/templates/project-ai/.ai/profile-detection.md +24 -0
- package/templates/project-ai/.ai/project-context.md +4 -1
- package/templates/project-ai/.ai/skills.md +36 -24
- package/templates/project-ai/AGENTS.md +6 -5
- package/templates/project-ai/AI_CODING_RULES.md +1 -1
- package/templates/project-ai/CLAUDE.md +6 -5
- package/templates/project-ai/GEMINI.md +6 -5
- package/templates/project-ai/OPENCODE.md +26 -0
- package/workflows/README.md +1 -1
- package/workflows/architecture-review.md +10 -10
- package/workflows/site-daily-loop.md +25 -25
package/bin/archsight-aios.mjs
CHANGED
|
@@ -34,7 +34,9 @@ const assetDirs = [
|
|
|
34
34
|
"vision",
|
|
35
35
|
"docs"
|
|
36
36
|
];
|
|
37
|
-
const assetFiles = ["README.md", "AI_CODING_RULES.md", "AGENTS.md", "CLAUDE.md", "GEMINI.md"];
|
|
37
|
+
const assetFiles = ["README.md", "AI_CODING_RULES.md", "AGENTS.md", "CLAUDE.md", "GEMINI.md", "OPENCODE.md"];
|
|
38
|
+
const skillSupportFiles = ["README.md", "engineering-business-starter-kit.md"];
|
|
39
|
+
const topLevelSkillNames = new Set(["aios", "archsight-aios"]);
|
|
38
40
|
const skillAliases = {
|
|
39
41
|
"aios-arch": ["aios-architecture-review", "archsight-architecture-review"],
|
|
40
42
|
"aios-plan": ["aios-delivery-planning", "archsight-delivery-planning"],
|
|
@@ -61,16 +63,108 @@ const skillAliases = {
|
|
|
61
63
|
"aios-construction-scheme": ["aios-scheme", "archsight-scheme"]
|
|
62
64
|
};
|
|
63
65
|
|
|
66
|
+
const profileDetectionRules = {
|
|
67
|
+
"bim-platform": [
|
|
68
|
+
"bim",
|
|
69
|
+
"ifc",
|
|
70
|
+
"revit",
|
|
71
|
+
"cad",
|
|
72
|
+
"dynamo",
|
|
73
|
+
"autocad",
|
|
74
|
+
"rvt",
|
|
75
|
+
"dwg",
|
|
76
|
+
"dxf",
|
|
77
|
+
"模型",
|
|
78
|
+
"构件",
|
|
79
|
+
"族",
|
|
80
|
+
"楼层",
|
|
81
|
+
"建模",
|
|
82
|
+
"模型质检"
|
|
83
|
+
],
|
|
84
|
+
"construction-vision": [
|
|
85
|
+
"yolo",
|
|
86
|
+
"sam",
|
|
87
|
+
"segment anything",
|
|
88
|
+
"segmentation",
|
|
89
|
+
"detect",
|
|
90
|
+
"detection",
|
|
91
|
+
"图像",
|
|
92
|
+
"视频",
|
|
93
|
+
"照片",
|
|
94
|
+
"裂缝",
|
|
95
|
+
"焊缝",
|
|
96
|
+
"点云",
|
|
97
|
+
"深度估计",
|
|
98
|
+
"巡检",
|
|
99
|
+
"缺陷",
|
|
100
|
+
"标注",
|
|
101
|
+
"数据集",
|
|
102
|
+
"jpg",
|
|
103
|
+
"png",
|
|
104
|
+
"mp4"
|
|
105
|
+
],
|
|
106
|
+
"rag-knowledge": [
|
|
107
|
+
"rag",
|
|
108
|
+
"graphrag",
|
|
109
|
+
"knowledge graph",
|
|
110
|
+
"知识库",
|
|
111
|
+
"知识图谱",
|
|
112
|
+
"规范",
|
|
113
|
+
"条文",
|
|
114
|
+
"审图",
|
|
115
|
+
"标准",
|
|
116
|
+
"检索",
|
|
117
|
+
"向量",
|
|
118
|
+
"embedding",
|
|
119
|
+
"问答",
|
|
120
|
+
"评估问题"
|
|
121
|
+
]
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const skillDetectionRules = {
|
|
125
|
+
"aios-arch": ["架构", "服务边界", "技术选型", "系统设计"],
|
|
126
|
+
"aios-design": ["界面", "ui", "ux", "工作台", "交互", "原型"],
|
|
127
|
+
"aios-plan": ["计划", "排期", "里程碑", "任务拆解", "交付"],
|
|
128
|
+
"aios-review": ["code review", "代码审查", "安全审查", "技术债"],
|
|
129
|
+
"aios-knowledge": ["bim", "ifc", "规范", "审图", "条文", "知识结构化"],
|
|
130
|
+
"aios-structural": ["结构", "荷载", "挠度", "fem", "有限元", "计算书"],
|
|
131
|
+
"aios-runtime": ["rag", "graphrag", "mcp", "tool calling", "memory", "agent runtime"],
|
|
132
|
+
"aios-compare": ["aios-compare"],
|
|
133
|
+
"aios-prompt-compare": ["aios-prompt-compare"],
|
|
134
|
+
"aios-commercial-tender": ["招标", "投标", "技术标", "商务标", "评分", "废标", "招采", "资格"],
|
|
135
|
+
"aios-commercial-contract": ["合同", "协议", "付款", "履约", "违约", "分包", "采购", "结算条款"],
|
|
136
|
+
"aios-construction-daily": ["日报", "周报", "现场记录", "施工日志", "进度", "材料进场", "机械", "劳务"],
|
|
137
|
+
"aios-construction-meeting": ["会议纪要", "例会", "协调会", "专题会", "待办", "责任人"],
|
|
138
|
+
"aios-commercial-variation": ["变更", "签证", "联系单", "索赔", "洽商", "工程量"],
|
|
139
|
+
"aios-construction-scheme": ["施工方案", "专项方案", "危大", "交底", "危险源", "专家论证"]
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const ignoredDetectionDirs = new Set([
|
|
143
|
+
".git",
|
|
144
|
+
".hg",
|
|
145
|
+
".svn",
|
|
146
|
+
".ai",
|
|
147
|
+
"node_modules",
|
|
148
|
+
"dist",
|
|
149
|
+
"build",
|
|
150
|
+
"coverage",
|
|
151
|
+
".next",
|
|
152
|
+
".nuxt",
|
|
153
|
+
".venv",
|
|
154
|
+
"venv",
|
|
155
|
+
"__pycache__"
|
|
156
|
+
]);
|
|
157
|
+
|
|
64
158
|
function usage() {
|
|
65
159
|
return [
|
|
66
160
|
"ArchSight AIOS",
|
|
67
161
|
"",
|
|
68
162
|
"Usage:",
|
|
69
163
|
" archsight-aios help",
|
|
70
|
-
" archsight-aios install --target <codex|agents|gemini|antigravity|workbuddy|all> --scope user",
|
|
164
|
+
" archsight-aios install --target <codex|agents|gemini|antigravity|workbuddy|opencode|claude-code|all> --scope user",
|
|
71
165
|
" archsight-aios doctor",
|
|
72
|
-
" archsight-aios init [--cwd <path>] [--mode <auto|full|linked|ai-only>] [--profile <name>]",
|
|
73
|
-
" archsight-aios validate [--cwd <path>] [--profile <name>] [--temp]",
|
|
166
|
+
" archsight-aios init [--cwd <path>] [--mode <auto|full|linked|ai-only>] [--profile <auto|none|all|name>]",
|
|
167
|
+
" archsight-aios validate [--cwd <path>] [--profile <auto|none|all|name>] [--temp]",
|
|
74
168
|
" archsight-aios capability:call --capability <id> --agent <id> --skill <id> --input <json-file>",
|
|
75
169
|
" archsight-aios hermes:validate",
|
|
76
170
|
" archsight-aios hermes:sync-dry-run",
|
|
@@ -89,6 +183,8 @@ function usage() {
|
|
|
89
183
|
" npx @archsight/aios install --target codex --scope user",
|
|
90
184
|
" npx @archsight/aios install --target agents --scope user",
|
|
91
185
|
" npx @archsight/aios install --target workbuddy --scope user",
|
|
186
|
+
" npx @archsight/aios install --target opencode --scope user",
|
|
187
|
+
" npx @archsight/aios install --target claude-code --scope user",
|
|
92
188
|
" npx @archsight/aios init",
|
|
93
189
|
" npx @archsight/aios validate --temp",
|
|
94
190
|
" npx @archsight/aios doctor"
|
|
@@ -236,7 +332,7 @@ async function listAiosWorkflowPaths() {
|
|
|
236
332
|
async function listRepositoryAiosSkills() {
|
|
237
333
|
const entries = await fs.readdir(path.join(repoRoot, "skills"), { withFileTypes: true });
|
|
238
334
|
return entries
|
|
239
|
-
.filter((entry) => entry.isDirectory() && entry.name.startsWith("aios-"))
|
|
335
|
+
.filter((entry) => entry.isDirectory() && (entry.name.startsWith("aios-") || topLevelSkillNames.has(entry.name)))
|
|
240
336
|
.map((entry) => entry.name)
|
|
241
337
|
.sort();
|
|
242
338
|
}
|
|
@@ -529,7 +625,7 @@ function callMcpStdio({ command, args, cwd, toolName, input, timeoutMs }) {
|
|
|
529
625
|
params: {
|
|
530
626
|
protocolVersion: "2025-06-18",
|
|
531
627
|
capabilities: {},
|
|
532
|
-
clientInfo: { name: "archsight-aios", version: "1.
|
|
628
|
+
clientInfo: { name: "archsight-aios", version: "1.3.1" }
|
|
533
629
|
}
|
|
534
630
|
};
|
|
535
631
|
const callTool = {
|
|
@@ -671,6 +767,13 @@ async function syncGeminiContent() {
|
|
|
671
767
|
|
|
672
768
|
async function installSkillsTo(targetRoot, skillNames) {
|
|
673
769
|
await ensureDir(targetRoot);
|
|
770
|
+
for (const fileName of skillSupportFiles) {
|
|
771
|
+
await copyFileIfExists(
|
|
772
|
+
path.join(repoRoot, "skills", fileName),
|
|
773
|
+
path.join(targetRoot, fileName)
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
|
|
674
777
|
for (const skillName of skillNames) {
|
|
675
778
|
await copyDir(
|
|
676
779
|
path.join(repoRoot, "skills", skillName),
|
|
@@ -704,6 +807,14 @@ function workBuddySkillsRoot() {
|
|
|
704
807
|
return path.join(home, ".workbuddy", "skills");
|
|
705
808
|
}
|
|
706
809
|
|
|
810
|
+
function openCodeSkillsRoot() {
|
|
811
|
+
return path.join(home, ".opencode", "skills");
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function claudeCodeSkillsRoot() {
|
|
815
|
+
return path.join(home, ".claude", "skills");
|
|
816
|
+
}
|
|
817
|
+
|
|
707
818
|
async function hasAntigravity2Config() {
|
|
708
819
|
if (!(await exists(path.join(home, ".gemini", "config")))) {
|
|
709
820
|
return false;
|
|
@@ -804,7 +915,7 @@ function userInstructionBlock(contentRoot) {
|
|
|
804
915
|
`- Runtime routing: ${p(path.join(contentRoot, "runtime"))}`,
|
|
805
916
|
`- Project template: ${p(path.join(contentRoot, "templates", "project-ai"))}`,
|
|
806
917
|
"",
|
|
807
|
-
"Use enabled `aios-*` skills for architecture review, design review, delivery planning, code review, runtime design, controlled execution, and building knowledge when
|
|
918
|
+
"Use enabled `aios-*` skills for architecture review, design review, delivery planning, code review, runtime design, controlled execution, and building knowledge when project profile detection or the task requires it.",
|
|
808
919
|
"Keep Agent, Skill, Workflow, and Runtime boundaries separate.",
|
|
809
920
|
"Hermes, Feishu, and other runtime adapters are optional; do not assume they are enabled unless the project says so.",
|
|
810
921
|
"Do not claim code changes, tests, builds, or deployments were completed unless verified in the bound project workspace.",
|
|
@@ -820,14 +931,15 @@ function projectInstructionBlock() {
|
|
|
820
931
|
"",
|
|
821
932
|
"本项目接入 ArchSight AIOS 作为补充治理层,不替代本项目已有通用 AI 编码规则。",
|
|
822
933
|
"",
|
|
823
|
-
"当任务涉及 Agent 路由、Skill 选择、Workflow、交付验证、AI Runtime、Code Review
|
|
934
|
+
"当任务涉及 Agent 路由、Skill 选择、Workflow、交付验证、AI Runtime、Code Review,或 AIOS 自动识别 / 用户明确启用的建筑行业 profile 时,先阅读:",
|
|
824
935
|
"",
|
|
825
936
|
"- `.ai/ARCHSIGHT_AIOS_RULES.md`",
|
|
826
937
|
"- `.ai/project-context.md`",
|
|
827
938
|
"- `.ai/agent-routing.md`",
|
|
828
939
|
"- `.ai/skills.md`",
|
|
829
940
|
"- `.ai/workflows.md`",
|
|
830
|
-
"- `.ai/
|
|
941
|
+
"- `.ai/profile-detection.md`",
|
|
942
|
+
"- `.ai/profiles/*.md`(如当前项目自动识别或显式启用了 profile)",
|
|
831
943
|
"",
|
|
832
944
|
"当前项目事实、根目录工具入口文件和 `AI_CODING_RULES.md` 优先;`.ai/ARCHSIGHT_AIOS_RULES.md` 只补充 AIOS 专属规则。接入 AIOS 不代表项目属于 ArchSightLabs,也不要求使用 Hermes、飞书或其他特定运行平台。",
|
|
833
945
|
managedEnd,
|
|
@@ -845,6 +957,377 @@ function containsAiosReference(content) {
|
|
|
845
957
|
].some((needle) => content.includes(needle));
|
|
846
958
|
}
|
|
847
959
|
|
|
960
|
+
function normalizeSignal(value) {
|
|
961
|
+
return String(value ?? "").toLowerCase();
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function confidenceFromScore(score) {
|
|
965
|
+
if (score >= 4) {
|
|
966
|
+
return "high";
|
|
967
|
+
}
|
|
968
|
+
if (score >= 2) {
|
|
969
|
+
return "medium";
|
|
970
|
+
}
|
|
971
|
+
return "low";
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function scoreDetectionRules(ruleMap, signalText) {
|
|
975
|
+
const normalized = normalizeSignal(signalText);
|
|
976
|
+
return Object.entries(ruleMap)
|
|
977
|
+
.map(([id, keywords]) => {
|
|
978
|
+
const matches = keywords.filter((keyword) => normalized.includes(normalizeSignal(keyword)));
|
|
979
|
+
return {
|
|
980
|
+
id,
|
|
981
|
+
score: matches.length,
|
|
982
|
+
confidence: matches.length > 0 ? confidenceFromScore(matches.length) : "none",
|
|
983
|
+
matches
|
|
984
|
+
};
|
|
985
|
+
})
|
|
986
|
+
.filter((item) => item.score > 0)
|
|
987
|
+
.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
async function listDetectionEntries(root, maxDepth = 2, maxEntries = 500) {
|
|
991
|
+
const entries = [];
|
|
992
|
+
|
|
993
|
+
async function walk(currentRoot, depth) {
|
|
994
|
+
if (entries.length >= maxEntries || depth > maxDepth) {
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
let dirEntries;
|
|
999
|
+
try {
|
|
1000
|
+
dirEntries = await fs.readdir(currentRoot, { withFileTypes: true });
|
|
1001
|
+
} catch {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
dirEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1006
|
+
|
|
1007
|
+
for (const entry of dirEntries) {
|
|
1008
|
+
if (entries.length >= maxEntries) {
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
if (entry.name.startsWith(".") && entry.name !== ".ai") {
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
if (entry.isDirectory() && ignoredDetectionDirs.has(entry.name)) {
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
const absolutePath = path.join(currentRoot, entry.name);
|
|
1019
|
+
const relativePath = path.relative(root, absolutePath).replaceAll("\\", "/");
|
|
1020
|
+
entries.push({ relativePath, isDirectory: entry.isDirectory() });
|
|
1021
|
+
|
|
1022
|
+
if (entry.isDirectory()) {
|
|
1023
|
+
await walk(absolutePath, depth + 1);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
await walk(root, 0);
|
|
1029
|
+
return entries;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
async function collectProjectDiscovery(targetRoot) {
|
|
1033
|
+
const entries = await listDetectionEntries(targetRoot);
|
|
1034
|
+
const candidateTextFiles = [
|
|
1035
|
+
"README.md",
|
|
1036
|
+
"README.zh-CN.md",
|
|
1037
|
+
"readme.md",
|
|
1038
|
+
"package.json",
|
|
1039
|
+
"pyproject.toml",
|
|
1040
|
+
"requirements.txt",
|
|
1041
|
+
"Makefile",
|
|
1042
|
+
"Dockerfile",
|
|
1043
|
+
"docker-compose.yml"
|
|
1044
|
+
];
|
|
1045
|
+
const textParts = [path.basename(targetRoot), targetRoot, ...entries.map((entry) => entry.relativePath)];
|
|
1046
|
+
let packageJson;
|
|
1047
|
+
|
|
1048
|
+
for (const fileName of candidateTextFiles) {
|
|
1049
|
+
const filePath = path.join(targetRoot, fileName);
|
|
1050
|
+
if (!(await exists(filePath))) {
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
const content = await readTextIfExists(filePath);
|
|
1054
|
+
textParts.push(fileName, content.slice(0, 12000));
|
|
1055
|
+
if (fileName === "package.json") {
|
|
1056
|
+
try {
|
|
1057
|
+
packageJson = JSON.parse(content);
|
|
1058
|
+
} catch {
|
|
1059
|
+
packageJson = undefined;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
const directories = entries.filter((entry) => entry.isDirectory).map((entry) => entry.relativePath);
|
|
1065
|
+
const files = entries.filter((entry) => !entry.isDirectory).map((entry) => entry.relativePath);
|
|
1066
|
+
const projectName = packageJson?.name ?? path.basename(targetRoot);
|
|
1067
|
+
|
|
1068
|
+
return {
|
|
1069
|
+
targetRoot,
|
|
1070
|
+
projectName,
|
|
1071
|
+
packageJson,
|
|
1072
|
+
directories,
|
|
1073
|
+
files,
|
|
1074
|
+
signalText: textParts.join("\n")
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
function detectProjectContext(manifest, discovery) {
|
|
1079
|
+
const profileScores = scoreDetectionRules(profileDetectionRules, discovery.signalText);
|
|
1080
|
+
const skillScores = scoreDetectionRules(skillDetectionRules, discovery.signalText);
|
|
1081
|
+
const profileDescriptions = new Map((manifest.projectProfiles ?? []).map((profile) => [profile.id, profile.description]));
|
|
1082
|
+
const skillMetadata = new Map((manifest.skills ?? []).map((skill) => [skill.id, skill]));
|
|
1083
|
+
|
|
1084
|
+
return {
|
|
1085
|
+
profileScores: profileScores.map((item) => ({
|
|
1086
|
+
...item,
|
|
1087
|
+
description: profileDescriptions.get(item.id) ?? item.id
|
|
1088
|
+
})),
|
|
1089
|
+
skillScores: skillScores.map((item) => ({
|
|
1090
|
+
...item,
|
|
1091
|
+
metadata: skillMetadata.get(item.id)
|
|
1092
|
+
}))
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function resolveProfileSelection(profileOption, manifest, detection) {
|
|
1097
|
+
const profiles = manifest.projectProfiles ?? [];
|
|
1098
|
+
const profileIds = new Set(profiles.map((profile) => profile.id));
|
|
1099
|
+
const option = profileOption ?? "auto";
|
|
1100
|
+
|
|
1101
|
+
if (option === "auto") {
|
|
1102
|
+
return {
|
|
1103
|
+
mode: "auto",
|
|
1104
|
+
profileIds: detection.profileScores
|
|
1105
|
+
.filter((item) => item.score >= 2 && profileIds.has(item.id))
|
|
1106
|
+
.map((item) => item.id)
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
if (option === "none") {
|
|
1111
|
+
return { mode: "none", profileIds: [] };
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
if (option === "all") {
|
|
1115
|
+
return { mode: "all", profileIds: profiles.map((profile) => profile.id) };
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
if (!profileIds.has(option)) {
|
|
1119
|
+
throw new Error(`Unsupported project profile: ${option}`);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
return { mode: "manual", profileIds: [option] };
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function renderMatchList(scores, emptyText) {
|
|
1126
|
+
if (scores.length === 0) {
|
|
1127
|
+
return [`- ${emptyText}`];
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
return scores.map((item) => {
|
|
1131
|
+
const matches = item.matches.slice(0, 8).join("、");
|
|
1132
|
+
return `- \`${item.id}\`:${item.confidence},命中 ${item.score} 项(${matches})`;
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function renderProfileDetectionDoc(manifest, discovery, detection, selection) {
|
|
1137
|
+
const profiles = manifest.projectProfiles ?? [];
|
|
1138
|
+
const selected = selection.profileIds.length > 0
|
|
1139
|
+
? selection.profileIds.map((id) => `\`${id}\``).join("、")
|
|
1140
|
+
: "未自动启用 profile";
|
|
1141
|
+
const profileRows = profiles.map((profile) => `| \`${profile.id}\` | ${profile.description} |`);
|
|
1142
|
+
|
|
1143
|
+
return [
|
|
1144
|
+
"# Profile Detection",
|
|
1145
|
+
"",
|
|
1146
|
+
"> 本文件由 `archsight-aios init` 根据本地项目名、README、package / pyproject 和浅层文件名生成。它是 AIOS 自动识别草稿,不是业务事实或工程结论;如与项目实际不符,以 `.ai/project-context.md` 和人工说明为准。",
|
|
1147
|
+
"",
|
|
1148
|
+
"## 识别结论",
|
|
1149
|
+
"",
|
|
1150
|
+
`- 模式:\`${selection.mode}\``,
|
|
1151
|
+
`- 当前启用 profile:${selected}`,
|
|
1152
|
+
"- 规则来源:ArchSight AIOS 内置 profile registry;未复制到本项目的 profile 仍可作为包内模板被工具读取。",
|
|
1153
|
+
"",
|
|
1154
|
+
"## Profile 命中证据",
|
|
1155
|
+
"",
|
|
1156
|
+
...renderMatchList(detection.profileScores, "未命中明确行业 profile;按通用项目接入,遇到具体资料时再由任务上下文触发对应 Skill。"),
|
|
1157
|
+
"",
|
|
1158
|
+
"## Skill 候选",
|
|
1159
|
+
"",
|
|
1160
|
+
...renderMatchList(detection.skillScores, "未命中明确 Skill;按用户任务和项目上下文动态选择。"),
|
|
1161
|
+
"",
|
|
1162
|
+
"## 可用 Profile Registry",
|
|
1163
|
+
"",
|
|
1164
|
+
"| Profile | 适用范围 |",
|
|
1165
|
+
"| --- | --- |",
|
|
1166
|
+
...profileRows,
|
|
1167
|
+
"",
|
|
1168
|
+
"## 边界",
|
|
1169
|
+
"",
|
|
1170
|
+
"- 自动识别只用于降低初始化门槛,不替代人工确认。",
|
|
1171
|
+
"- 不因为安装 AIOS 就默认把项目判定为 BIM、施工视觉或 RAG 项目。",
|
|
1172
|
+
"- 涉及金额、工期、法律责任、结构安全、规范合规或人员信息时,必须保留人工复核。",
|
|
1173
|
+
""
|
|
1174
|
+
].join("\n");
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
function dependencyNames(packageJson) {
|
|
1178
|
+
return [
|
|
1179
|
+
...Object.keys(packageJson?.dependencies ?? {}),
|
|
1180
|
+
...Object.keys(packageJson?.devDependencies ?? {}),
|
|
1181
|
+
...Object.keys(packageJson?.peerDependencies ?? {})
|
|
1182
|
+
];
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
function hasAnySignal(discovery, words) {
|
|
1186
|
+
const signal = normalizeSignal(discovery.signalText);
|
|
1187
|
+
return words.some((word) => signal.includes(normalizeSignal(word)));
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
function inferStack(discovery) {
|
|
1191
|
+
const deps = dependencyNames(discovery.packageJson);
|
|
1192
|
+
const depSet = new Set(deps.map((dep) => dep.toLowerCase()));
|
|
1193
|
+
const hasDep = (...names) => names.some((name) => depSet.has(name));
|
|
1194
|
+
const hasFile = (...names) => names.some((name) => discovery.files.includes(name) || discovery.directories.includes(name));
|
|
1195
|
+
|
|
1196
|
+
const frontend = [];
|
|
1197
|
+
if (hasDep("react", "next", "vite", "vue", "@angular/core", "svelte")) {
|
|
1198
|
+
frontend.push(deps.filter((dep) => ["react", "next", "vite", "vue", "@angular/core", "svelte"].includes(dep)).join(" / "));
|
|
1199
|
+
}
|
|
1200
|
+
if (hasFile("src", "app", "pages")) {
|
|
1201
|
+
frontend.push("存在前端入口目录");
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
const backend = [];
|
|
1205
|
+
if (hasDep("express", "fastify", "@nestjs/core", "koa", "hono")) {
|
|
1206
|
+
backend.push(deps.filter((dep) => ["express", "fastify", "@nestjs/core", "koa", "hono"].includes(dep)).join(" / "));
|
|
1207
|
+
}
|
|
1208
|
+
if (hasAnySignal(discovery, ["fastapi", "django", "flask", "spring boot"])) {
|
|
1209
|
+
backend.push("检测到后端框架关键词");
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const database = [];
|
|
1213
|
+
if (hasDep("prisma", "drizzle-orm", "typeorm", "sequelize", "mongoose", "pg", "mysql2")) {
|
|
1214
|
+
database.push(deps.filter((dep) => ["prisma", "drizzle-orm", "typeorm", "sequelize", "mongoose", "pg", "mysql2"].includes(dep)).join(" / "));
|
|
1215
|
+
}
|
|
1216
|
+
if (hasAnySignal(discovery, ["postgres", "mysql", "sqlite", "redis", "mongodb", "sqlalchemy"])) {
|
|
1217
|
+
database.push("检测到数据库关键词");
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
const ai = [];
|
|
1221
|
+
if (hasDep("openai", "langchain", "@langchain/core", "llamaindex", "ai")) {
|
|
1222
|
+
ai.push(deps.filter((dep) => ["openai", "langchain", "@langchain/core", "llamaindex", "ai"].includes(dep)).join(" / "));
|
|
1223
|
+
}
|
|
1224
|
+
if (hasAnySignal(discovery, ["rag", "graphrag", "embedding", "mcp", "agent", "向量", "知识库"])) {
|
|
1225
|
+
ai.push("检测到 AI / RAG / Agent 关键词");
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const deployment = [];
|
|
1229
|
+
if (hasFile("Dockerfile", "docker-compose.yml", ".github")) {
|
|
1230
|
+
deployment.push("检测到 Docker / CI 文件");
|
|
1231
|
+
}
|
|
1232
|
+
if (hasAnySignal(discovery, ["vercel", "railway", "kubernetes", "k8s", "helm"])) {
|
|
1233
|
+
deployment.push("检测到部署平台关键词");
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
return {
|
|
1237
|
+
frontend: frontend.filter(Boolean).join(";") || "待补充",
|
|
1238
|
+
backend: backend.filter(Boolean).join(";") || "待补充",
|
|
1239
|
+
database: database.filter(Boolean).join(";") || "待补充",
|
|
1240
|
+
ai: ai.filter(Boolean).join(";") || "待补充",
|
|
1241
|
+
deployment: deployment.filter(Boolean).join(";") || "待补充"
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
function scriptCommand(discovery, scriptName, fallback = "待补充") {
|
|
1246
|
+
if (discovery.packageJson?.scripts?.[scriptName]) {
|
|
1247
|
+
return `npm run ${scriptName}`;
|
|
1248
|
+
}
|
|
1249
|
+
return fallback;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
function renderProjectContextDoc(manifest, discovery, detection, selection) {
|
|
1253
|
+
const stack = inferStack(discovery);
|
|
1254
|
+
const description = discovery.packageJson?.description || "由 AIOS 根据项目入口自动生成的项目上下文草稿,请按实际业务补充目标、用户、阶段和边界。";
|
|
1255
|
+
const selectedProfiles = selection.profileIds.length > 0
|
|
1256
|
+
? selection.profileIds.map((id) => `\`${id}\``).join("、")
|
|
1257
|
+
: "未自动启用 profile";
|
|
1258
|
+
const selectedSkills = detection.skillScores.length > 0
|
|
1259
|
+
? detection.skillScores.slice(0, 8).map((item) => `\`${item.id}\``).join("、")
|
|
1260
|
+
: "按任务动态选择";
|
|
1261
|
+
const selectedSkillIds = new Set(detection.skillScores.map((item) => item.id));
|
|
1262
|
+
const agents = [...new Set((manifest.skills ?? [])
|
|
1263
|
+
.filter((skill) => selectedSkillIds.has(skill.id))
|
|
1264
|
+
.map((skill) => routeAgentName(manifest, skill.primaryAgent)))]
|
|
1265
|
+
.join("、") || "按任务动态选择";
|
|
1266
|
+
const workflows = [...new Set((manifest.skills ?? [])
|
|
1267
|
+
.filter((skill) => selectedSkillIds.has(skill.id))
|
|
1268
|
+
.map((skill) => skill.defaultWorkflow))]
|
|
1269
|
+
.map((workflow) => `\`${workflow}\``)
|
|
1270
|
+
.join("、") || "按任务动态选择";
|
|
1271
|
+
const codeStructure = [
|
|
1272
|
+
...discovery.directories.slice(0, 12).map((item) => `- \`${item}/\``),
|
|
1273
|
+
...discovery.files.filter((item) => ["package.json", "pyproject.toml", "README.md", "Makefile", "Dockerfile"].includes(item)).map((item) => `- \`${item}\``)
|
|
1274
|
+
];
|
|
1275
|
+
|
|
1276
|
+
return [
|
|
1277
|
+
"# Project Context",
|
|
1278
|
+
"",
|
|
1279
|
+
"> 本文件由 `archsight-aios init` 首次创建并自动预填。请把它当作可编辑草稿;AIOS 不会在重复初始化时覆盖已有项目上下文。",
|
|
1280
|
+
"",
|
|
1281
|
+
"## 项目名称",
|
|
1282
|
+
"",
|
|
1283
|
+
discovery.projectName,
|
|
1284
|
+
"",
|
|
1285
|
+
"## 项目定位",
|
|
1286
|
+
"",
|
|
1287
|
+
description,
|
|
1288
|
+
"",
|
|
1289
|
+
"## 技术栈",
|
|
1290
|
+
"",
|
|
1291
|
+
`- 前端:${stack.frontend}`,
|
|
1292
|
+
`- 后端:${stack.backend}`,
|
|
1293
|
+
`- 数据库:${stack.database}`,
|
|
1294
|
+
`- AI / RAG / Agent:${stack.ai}`,
|
|
1295
|
+
`- 部署环境:${stack.deployment}`,
|
|
1296
|
+
"",
|
|
1297
|
+
"## 代码结构",
|
|
1298
|
+
"",
|
|
1299
|
+
...(codeStructure.length > 0 ? codeStructure : ["- 待补充"]),
|
|
1300
|
+
"",
|
|
1301
|
+
"## 常用命令",
|
|
1302
|
+
"",
|
|
1303
|
+
"```text",
|
|
1304
|
+
`安装:${discovery.packageJson ? "npm install" : "待补充"}`,
|
|
1305
|
+
`开发:${scriptCommand(discovery, "dev")}`,
|
|
1306
|
+
`测试:${scriptCommand(discovery, "test")}`,
|
|
1307
|
+
`构建:${scriptCommand(discovery, "build")}`,
|
|
1308
|
+
`Lint:${scriptCommand(discovery, "lint")}`,
|
|
1309
|
+
`类型检查:${scriptCommand(discovery, "typecheck", scriptCommand(discovery, "type-check"))}`,
|
|
1310
|
+
"部署前检查:待补充",
|
|
1311
|
+
"```",
|
|
1312
|
+
"",
|
|
1313
|
+
"## 关键约束",
|
|
1314
|
+
"",
|
|
1315
|
+
"- 不得修改:项目已有入口文件中非 AIOS 托管块的内容,除非用户明确要求。",
|
|
1316
|
+
"- 必须保持:当前项目事实、测试、构建和发布流程优先于 AIOS 通用模板。",
|
|
1317
|
+
"- 需要人工确认:业务范围、客户资料、金额、工期、法律责任、规范合规、结构安全和人员信息。",
|
|
1318
|
+
"- 已知风险:自动识别只基于本地文件名和少量文本入口,可能漏判或误判;以人工修订后的项目上下文为准。",
|
|
1319
|
+
"",
|
|
1320
|
+
"## 当前接入的 ArchSight AIOS 能力",
|
|
1321
|
+
"",
|
|
1322
|
+
`- Profile:${selectedProfiles}`,
|
|
1323
|
+
`- Agent:${agents}`,
|
|
1324
|
+
`- Skills:${selectedSkills}`,
|
|
1325
|
+
`- Workflows:${workflows}`,
|
|
1326
|
+
"- Runtime:本地 `.ai/` 规则、AIOS Skill / Workflow、可选 Capability 工具证据。",
|
|
1327
|
+
""
|
|
1328
|
+
].join("\n");
|
|
1329
|
+
}
|
|
1330
|
+
|
|
848
1331
|
async function resolveInitProjectMode(requestedMode, targetRoot, rootInstructionFiles, aiFiles) {
|
|
849
1332
|
if (requestedMode !== "auto") {
|
|
850
1333
|
return requestedMode;
|
|
@@ -899,7 +1382,16 @@ async function install(options) {
|
|
|
899
1382
|
throw new Error("Only --scope user is supported in this release.");
|
|
900
1383
|
}
|
|
901
1384
|
|
|
902
|
-
const
|
|
1385
|
+
const targetAliases = {
|
|
1386
|
+
claudecode: "claude-code",
|
|
1387
|
+
claude_code: "claude-code",
|
|
1388
|
+
claude: "claude-code",
|
|
1389
|
+
"open-code": "opencode",
|
|
1390
|
+
open_code: "opencode"
|
|
1391
|
+
};
|
|
1392
|
+
options.target = targetAliases[options.target] ?? options.target;
|
|
1393
|
+
|
|
1394
|
+
const validTargets = new Set(["codex", "agents", "gemini", "antigravity", "workbuddy", "opencode", "claude-code", "all"]);
|
|
903
1395
|
if (!validTargets.has(options.target)) {
|
|
904
1396
|
throw new Error(`Unsupported target: ${options.target}`);
|
|
905
1397
|
}
|
|
@@ -907,7 +1399,7 @@ async function install(options) {
|
|
|
907
1399
|
const skillNames = await listAiosSkills();
|
|
908
1400
|
const workflowPaths = await listAiosWorkflowPaths();
|
|
909
1401
|
const targets = options.target === "all"
|
|
910
|
-
? ["codex", "gemini", "antigravity", "workbuddy"]
|
|
1402
|
+
? ["codex", "gemini", "antigravity", "workbuddy", "opencode", "claude-code"]
|
|
911
1403
|
: [options.target];
|
|
912
1404
|
|
|
913
1405
|
const installed = [];
|
|
@@ -955,6 +1447,18 @@ async function install(options) {
|
|
|
955
1447
|
installed.push("workbuddy skills");
|
|
956
1448
|
}
|
|
957
1449
|
|
|
1450
|
+
if (targets.includes("opencode")) {
|
|
1451
|
+
await removeLegacySkillDirs(openCodeSkillsRoot(), skillNames);
|
|
1452
|
+
await installSkillsTo(openCodeSkillsRoot(), skillNames);
|
|
1453
|
+
installed.push("opencode skills");
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
if (targets.includes("claude-code")) {
|
|
1457
|
+
await removeLegacySkillDirs(claudeCodeSkillsRoot(), skillNames);
|
|
1458
|
+
await installSkillsTo(claudeCodeSkillsRoot(), skillNames);
|
|
1459
|
+
installed.push("claude-code skills");
|
|
1460
|
+
}
|
|
1461
|
+
|
|
958
1462
|
console.log(`Installed: ${installed.join(", ")}`);
|
|
959
1463
|
console.log(`Skills: ${skillNames.join(", ")}`);
|
|
960
1464
|
console.log(`Workflows: ${workflowPaths.map((workflowPath) => path.basename(workflowPath)).join(", ")}`);
|
|
@@ -1005,6 +1509,8 @@ async function doctor() {
|
|
|
1005
1509
|
);
|
|
1006
1510
|
checkCondition("codex workflows target", manifest.installTargets?.codexWorkflows === "~/.codex/workflows/aios", "codexWorkflows");
|
|
1007
1511
|
checkCondition("workbuddy skills target", manifest.installTargets?.workBuddySkills === "~/.workbuddy/skills", "workBuddySkills");
|
|
1512
|
+
checkCondition("opencode skills target", manifest.installTargets?.openCodeSkills === "~/.opencode/skills", "openCodeSkills");
|
|
1513
|
+
checkCondition("claude-code skills target", manifest.installTargets?.claudeCodeSkills === "~/.claude/skills", "claudeCodeSkills");
|
|
1008
1514
|
checkCondition("antigravity plugin target", manifest.installTargets?.antigravityPlugin === "~/.gemini/config/plugins/archsight-aios", "antigravityPlugin");
|
|
1009
1515
|
checkCondition("antigravity legacy skills target", manifest.installTargets?.antigravityLegacySkills === "~/.gemini/antigravity/skills", "antigravityLegacySkills");
|
|
1010
1516
|
|
|
@@ -1107,6 +1613,8 @@ async function doctor() {
|
|
|
1107
1613
|
await check("gemini support delivery", path.join(geminiRoot, "delivery"));
|
|
1108
1614
|
await check("gemini support memory", path.join(geminiRoot, "memory"));
|
|
1109
1615
|
await check("codex skills root", path.join(home, ".codex", "skills"));
|
|
1616
|
+
await check("opencode skills root", openCodeSkillsRoot());
|
|
1617
|
+
await check("claude-code skills root", claudeCodeSkillsRoot());
|
|
1110
1618
|
await check("codex workflows root", path.join(home, ".codex", "workflows", "aios"));
|
|
1111
1619
|
await check("gemini instructions", path.join(home, ".gemini", "GEMINI.md"));
|
|
1112
1620
|
await checkContains("gemini managed block", path.join(home, ".gemini", "GEMINI.md"), managedStart);
|
|
@@ -1127,6 +1635,8 @@ async function doctor() {
|
|
|
1127
1635
|
await check(`gemini support skill ${skillName}`, path.join(geminiRoot, sourceDir, "SKILL.md"));
|
|
1128
1636
|
await check(`codex skill ${skillName}`, path.join(home, ".codex", "skills", skillName, "SKILL.md"));
|
|
1129
1637
|
await check(`workbuddy skill ${skillName}`, path.join(workBuddySkillsRoot(), skillName, "SKILL.md"));
|
|
1638
|
+
await check(`opencode skill ${skillName}`, path.join(openCodeSkillsRoot(), skillName, "SKILL.md"));
|
|
1639
|
+
await check(`claude-code skill ${skillName}`, path.join(claudeCodeSkillsRoot(), skillName, "SKILL.md"));
|
|
1130
1640
|
if (useAntigravityLegacy) {
|
|
1131
1641
|
await check(`antigravity 1.x legacy skill ${skillName}`, path.join(antigravityLegacySkillsRoot(), skillName, "SKILL.md"));
|
|
1132
1642
|
}
|
|
@@ -1162,19 +1672,22 @@ async function initProject(options) {
|
|
|
1162
1672
|
"AGENTS.md",
|
|
1163
1673
|
"AI_CODING_RULES.md",
|
|
1164
1674
|
"CLAUDE.md",
|
|
1165
|
-
"GEMINI.md"
|
|
1675
|
+
"GEMINI.md",
|
|
1676
|
+
"OPENCODE.md"
|
|
1166
1677
|
];
|
|
1167
1678
|
const linkedInstructionFiles = [
|
|
1168
1679
|
"AGENTS.md",
|
|
1169
1680
|
"CLAUDE.md",
|
|
1170
|
-
"GEMINI.md"
|
|
1681
|
+
"GEMINI.md",
|
|
1682
|
+
"OPENCODE.md"
|
|
1171
1683
|
];
|
|
1172
1684
|
const aiFiles = [
|
|
1173
1685
|
path.join(".ai", "ARCHSIGHT_AIOS_RULES.md"),
|
|
1174
1686
|
path.join(".ai", "project-context.md"),
|
|
1175
1687
|
path.join(".ai", "agent-routing.md"),
|
|
1176
1688
|
path.join(".ai", "skills.md"),
|
|
1177
|
-
path.join(".ai", "workflows.md")
|
|
1689
|
+
path.join(".ai", "workflows.md"),
|
|
1690
|
+
path.join(".ai", "profile-detection.md")
|
|
1178
1691
|
];
|
|
1179
1692
|
const mode = await resolveInitProjectMode(options.mode ?? "auto", targetRoot, rootInstructionFiles, aiFiles);
|
|
1180
1693
|
const files = mode === "ai-only"
|
|
@@ -1190,6 +1703,9 @@ async function initProject(options) {
|
|
|
1190
1703
|
}
|
|
1191
1704
|
|
|
1192
1705
|
await ensureDir(targetRoot);
|
|
1706
|
+
const discovery = await collectProjectDiscovery(targetRoot);
|
|
1707
|
+
const detection = detectProjectContext(manifest, discovery);
|
|
1708
|
+
const profileSelection = resolveProfileSelection(options.profile, manifest, detection);
|
|
1193
1709
|
|
|
1194
1710
|
for (const fileName of files) {
|
|
1195
1711
|
const src = path.join(templateRoot, fileName);
|
|
@@ -1200,7 +1716,13 @@ async function initProject(options) {
|
|
|
1200
1716
|
continue;
|
|
1201
1717
|
}
|
|
1202
1718
|
await ensureDir(path.dirname(dest));
|
|
1203
|
-
|
|
1719
|
+
if (fileName === path.join(".ai", "project-context.md")) {
|
|
1720
|
+
await fs.writeFile(dest, renderProjectContextDoc(manifest, discovery, detection, profileSelection), "utf8");
|
|
1721
|
+
} else if (fileName === path.join(".ai", "profile-detection.md")) {
|
|
1722
|
+
await fs.writeFile(dest, renderProfileDetectionDoc(manifest, discovery, detection, profileSelection), "utf8");
|
|
1723
|
+
} else {
|
|
1724
|
+
await fs.copyFile(src, dest);
|
|
1725
|
+
}
|
|
1204
1726
|
console.log(`CREATE ${dest}`);
|
|
1205
1727
|
}
|
|
1206
1728
|
|
|
@@ -1221,11 +1743,14 @@ async function initProject(options) {
|
|
|
1221
1743
|
}
|
|
1222
1744
|
}
|
|
1223
1745
|
|
|
1224
|
-
if (
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1746
|
+
if (profileSelection.profileIds.length > 0) {
|
|
1747
|
+
console.log(`PROFILE ${profileSelection.mode}: ${profileSelection.profileIds.join(", ")}`);
|
|
1748
|
+
} else {
|
|
1749
|
+
console.log(`PROFILE ${profileSelection.mode}: none`);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
for (const profileId of profileSelection.profileIds) {
|
|
1753
|
+
const profile = manifest.projectProfiles?.find((item) => item.id === profileId);
|
|
1229
1754
|
await copyTreeMissing(path.join(repoRoot, profile.path), targetRoot);
|
|
1230
1755
|
}
|
|
1231
1756
|
}
|
|
@@ -1281,7 +1806,9 @@ async function validateProjectTemplate(options) {
|
|
|
1281
1806
|
["project AIOS rules uses AIOS", path.join(".ai", "ARCHSIGHT_AIOS_RULES.md")],
|
|
1282
1807
|
["project CLAUDE uses AIOS", "CLAUDE.md"],
|
|
1283
1808
|
["project GEMINI uses AIOS", "GEMINI.md"],
|
|
1284
|
-
["project
|
|
1809
|
+
["project OPENCODE uses AIOS", "OPENCODE.md"],
|
|
1810
|
+
["project context uses AIOS", path.join(".ai", "project-context.md")],
|
|
1811
|
+
["project profile detection uses AIOS", path.join(".ai", "profile-detection.md")]
|
|
1285
1812
|
]) {
|
|
1286
1813
|
const content = await fs.readFile(path.join(targetRoot, fileName), "utf8");
|
|
1287
1814
|
const legacyAiOsText = ["AI", "OS"].join(" ");
|
|
@@ -1292,13 +1819,19 @@ async function validateProjectTemplate(options) {
|
|
|
1292
1819
|
});
|
|
1293
1820
|
}
|
|
1294
1821
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1822
|
+
const profileCheckIds = options.profile === "all"
|
|
1823
|
+
? (manifest.projectProfiles ?? []).map((profile) => profile.id)
|
|
1824
|
+
: options.profile && !["auto", "none"].includes(options.profile)
|
|
1825
|
+
? [options.profile]
|
|
1826
|
+
: [];
|
|
1827
|
+
|
|
1828
|
+
for (const profileId of profileCheckIds) {
|
|
1829
|
+
const profile = manifest.projectProfiles?.find((item) => item.id === profileId);
|
|
1297
1830
|
if (!profile) {
|
|
1298
|
-
throw new Error(`Unsupported project profile: ${
|
|
1831
|
+
throw new Error(`Unsupported project profile: ${profileId}`);
|
|
1299
1832
|
}
|
|
1300
1833
|
for (const fileName of profile.requiredFiles ?? []) {
|
|
1301
|
-
await check(`profile output ${
|
|
1834
|
+
await check(`profile output ${profileId}/${fileName}`, path.join(targetRoot, fileName));
|
|
1302
1835
|
}
|
|
1303
1836
|
}
|
|
1304
1837
|
|