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