@archsight/aios 1.3.2 → 1.5.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.
Files changed (126) hide show
  1. package/.claude-plugin/marketplace.json +6 -1
  2. package/.claude-plugin/plugin.json +5 -1
  3. package/CHANGELOG.md +53 -0
  4. package/README.md +90 -3
  5. package/RELEASE_NOTES.md +51 -0
  6. package/bin/archsight-aios.mjs +932 -15
  7. package/delivery/README.md +1 -0
  8. package/delivery/v1.4.0-release-readiness.md +64 -0
  9. package/delivery/v1.5.0-release-readiness.md +62 -0
  10. package/docs/PUBLIC_DISCOVERY.md +1 -1
  11. package/docs/industry-user-trial-guide.md +343 -0
  12. package/docs/quickstart.md +10 -0
  13. package/docs/v1.4.0-writing-boundary.md +42 -0
  14. package/docs/v1.4.0-writing-workflow-quickstart.md +83 -0
  15. package/docs/v1.5.0-knowledge-pack-runtime.md +100 -0
  16. package/gemini-extension.json +1 -1
  17. package/knowledge/README.md +6 -3
  18. package/package.json +10 -1
  19. package/prompts/README.md +4 -0
  20. package/prompts/evaluation-policy.md +33 -0
  21. package/prompts/evaluations/engineering-document-writing-fixtures.json +129 -0
  22. package/prompts/evaluations/engineering-document-writing-scorecard.json +108 -0
  23. package/prompts/evaluations/engineering-knowledge-pack-scorecard.json +57 -0
  24. package/prompts/evaluations/skill-runtime/README.md +15 -0
  25. package/prompts/evaluations/skill-runtime/raw/codex-scheme-writing-sample.md +111 -0
  26. package/prompts/evaluations/skill-runtime/raw/codex-tender-writing-sample.md +108 -0
  27. package/prompts/evaluations/skill-runtime/raw/workbuddy-scheme-writing-sample.md +228 -0
  28. package/prompts/evaluations/skill-runtime/raw/workbuddy-tender-writing-sample.md +143 -0
  29. package/prompts/evaluations/skill-runtime/v1.4.0-writing-host-scorecard-review.md +29 -0
  30. package/prompts/evaluations/skill-runtime/v1.4.0-writing-host-validation.json +112 -0
  31. package/prompts/evaluations/skill-runtime/v1.4.0-writing-host-validation.md +43 -0
  32. package/prompts/prompt-registry.md +8 -2
  33. package/rag/README.md +4 -0
  34. package/runtime/archsight-aios.manifest.json +227 -8
  35. package/runtime/capability-adapters.json +13 -0
  36. package/runtime/capability-registry.json +23 -2
  37. package/runtime/skill-routing.md +19 -4
  38. package/scripts/build-prompt-run-pack.mjs +27 -9
  39. package/scripts/validate-knowledge-pack.mjs +96 -0
  40. package/scripts/validate-prompt-fixtures.mjs +31 -10
  41. package/scripts/validate-prompt-scorecard.mjs +22 -6
  42. package/scripts/validate-skill-runtime-evidence.mjs +125 -0
  43. package/skills/README.md +29 -3
  44. package/skills/aios/SKILL.md +24 -10
  45. package/skills/aios-commercial-tender/SKILL.md +2 -0
  46. package/skills/aios-construction-scheme/SKILL.md +7 -3
  47. package/skills/aios-contract-audit/SKILL.md +121 -0
  48. package/skills/aios-contract-audit/agents/openai.yaml +4 -0
  49. package/skills/aios-contract-audit/prompts/basic-prompt.md +85 -0
  50. package/skills/aios-contract-draft/SKILL.md +130 -0
  51. package/skills/aios-contract-draft/agents/openai.yaml +4 -0
  52. package/skills/aios-contract-draft/prompts/basic-prompt.md +76 -0
  53. package/skills/aios-daily/SKILL.md +51 -0
  54. package/skills/aios-daily/agents/openai.yaml +4 -0
  55. package/skills/aios-daily-write/SKILL.md +116 -0
  56. package/skills/aios-daily-write/agents/openai.yaml +4 -0
  57. package/skills/aios-daily-write/prompts/basic-prompt.md +72 -0
  58. package/skills/aios-knowledge/SKILL.md +14 -3
  59. package/skills/aios-meeting/SKILL.md +52 -0
  60. package/skills/aios-meeting/agents/openai.yaml +4 -0
  61. package/skills/aios-meeting-write/SKILL.md +117 -0
  62. package/skills/aios-meeting-write/agents/openai.yaml +4 -0
  63. package/skills/aios-meeting-write/prompts/basic-prompt.md +72 -0
  64. package/skills/aios-review/SKILL.md +9 -6
  65. package/skills/aios-runtime/SKILL.md +17 -7
  66. package/skills/aios-scheme/SKILL.md +50 -0
  67. package/skills/aios-scheme/agents/openai.yaml +4 -0
  68. package/skills/aios-scheme-audit/SKILL.md +113 -0
  69. package/skills/aios-scheme-audit/agents/openai.yaml +4 -0
  70. package/skills/aios-scheme-audit/prompts/basic-prompt.md +90 -0
  71. package/skills/aios-scheme-write/SKILL.md +132 -0
  72. package/skills/aios-scheme-write/agents/openai.yaml +4 -0
  73. package/skills/aios-scheme-write/prompts/basic-prompt.md +83 -0
  74. package/skills/aios-tender/SKILL.md +50 -0
  75. package/skills/aios-tender/agents/openai.yaml +4 -0
  76. package/skills/aios-tender-audit/SKILL.md +119 -0
  77. package/skills/aios-tender-audit/agents/openai.yaml +4 -0
  78. package/skills/aios-tender-audit/prompts/basic-prompt.md +94 -0
  79. package/skills/aios-tender-write/SKILL.md +130 -0
  80. package/skills/aios-tender-write/agents/openai.yaml +4 -0
  81. package/skills/aios-tender-write/prompts/basic-prompt.md +82 -0
  82. package/skills/archsight-aios/SKILL.md +17 -5
  83. package/skills/engineering-business-starter-kit.md +21 -7
  84. package/templates/README.md +29 -4
  85. package/templates/document-writing/draft.md +15 -0
  86. package/templates/document-writing/final.md +16 -0
  87. package/templates/document-writing/material-index.md +18 -0
  88. package/templates/document-writing/review-notes.md +18 -0
  89. package/templates/document-writing/source-normalized.md +20 -0
  90. package/templates/document-writing/writing-brief.md +23 -0
  91. package/templates/document-writing-samples/scheme/README.md +16 -0
  92. package/templates/document-writing-samples/scheme/draft.md +25 -0
  93. package/templates/document-writing-samples/scheme/final.md +20 -0
  94. package/templates/document-writing-samples/scheme/material-index.md +23 -0
  95. package/templates/document-writing-samples/scheme/review-notes.md +23 -0
  96. package/templates/document-writing-samples/scheme/source-normalized.md +35 -0
  97. package/templates/document-writing-samples/scheme/writing-brief.md +26 -0
  98. package/templates/document-writing-samples/tender/README.md +16 -0
  99. package/templates/document-writing-samples/tender/draft.md +27 -0
  100. package/templates/document-writing-samples/tender/final.md +20 -0
  101. package/templates/document-writing-samples/tender/material-index.md +23 -0
  102. package/templates/document-writing-samples/tender/review-notes.md +23 -0
  103. package/templates/document-writing-samples/tender/source-normalized.md +34 -0
  104. package/templates/document-writing-samples/tender/writing-brief.md +26 -0
  105. package/templates/knowledge-pack/README.md +30 -0
  106. package/templates/knowledge-pack/clause-map.md +11 -0
  107. package/templates/knowledge-pack/entity-relation-map.md +18 -0
  108. package/templates/knowledge-pack/eval-questions.md +13 -0
  109. package/templates/knowledge-pack/knowledge-pack.source.json +107 -0
  110. package/templates/knowledge-pack/review-notes.md +14 -0
  111. package/templates/knowledge-pack/source-register.md +13 -0
  112. package/templates/knowledge-pack/standard-register.md +10 -0
  113. package/templates/knowledge-pack-samples/scheme-review/README.md +18 -0
  114. package/templates/knowledge-pack-samples/scheme-review/clause-map.md +8 -0
  115. package/templates/knowledge-pack-samples/scheme-review/entity-relation-map.md +17 -0
  116. package/templates/knowledge-pack-samples/scheme-review/eval-questions.md +9 -0
  117. package/templates/knowledge-pack-samples/scheme-review/knowledge-pack.source.json +251 -0
  118. package/templates/knowledge-pack-samples/scheme-review/review-notes.md +8 -0
  119. package/templates/knowledge-pack-samples/scheme-review/source-register.md +9 -0
  120. package/templates/knowledge-pack-samples/scheme-review/standard-register.md +9 -0
  121. package/templates/project-ai/.ai/agent-routing.md +6 -2
  122. package/templates/project-ai/.ai/skills.md +29 -3
  123. package/vision/README.md +1 -0
  124. package/vision/roadmap.md +22 -3
  125. package/vision/v1.4.0-engineering-document-workflow.md +205 -0
  126. package/workflows/rag-pipeline.md +14 -9
@@ -3,6 +3,8 @@
3
3
  import fs from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import os from "node:os";
6
+ import crypto from "node:crypto";
7
+ import readline from "node:readline";
6
8
  import { spawn } from "node:child_process";
7
9
  import { fileURLToPath } from "node:url";
8
10
 
@@ -14,6 +16,7 @@ const home = os.homedir();
14
16
  const managedStart = "<!-- ARCHSIGHT-AIOS:START -->";
15
17
  const managedEnd = "<!-- ARCHSIGHT-AIOS:END -->";
16
18
  const antigravityPluginName = "archsight-aios";
19
+ const aiosVersion = "1.5.0";
17
20
 
18
21
  const assetDirs = [
19
22
  "skills",
@@ -55,12 +58,24 @@ const skillAliases = {
55
58
  "archsight-ai-runtime-design"
56
59
  ],
57
60
  "aios-exec": ["aios-controlled-execution", "archsight-controlled-execution"],
58
- "aios-commercial-tender": ["aios-tender", "archsight-tender"],
59
- "aios-commercial-contract": ["aios-contract", "archsight-contract"],
61
+ "aios-tender": ["archsight-tender"],
62
+ "aios-tender-audit": ["aios-tender-review", "aios-bid-audit", "archsight-tender-audit"],
63
+ "aios-commercial-tender": ["aios-commercial-bid", "archsight-commercial-tender"],
64
+ "aios-tender-write": ["aios-bid-write", "archsight-bid-write", "aios-technical-bid-write"],
65
+ "aios-contract-audit": ["aios-contract", "aios-contract-review", "archsight-contract-audit"],
66
+ "aios-contract-draft": ["aios-contract-write", "aios-contract-letter", "archsight-contract-draft"],
67
+ "aios-commercial-contract": ["archsight-commercial-contract"],
60
68
  "aios-commercial-variation": ["aios-variation", "archsight-variation"],
61
- "aios-construction-daily": ["aios-daily", "archsight-daily"],
62
- "aios-construction-meeting": ["aios-meeting", "archsight-meeting"],
63
- "aios-construction-scheme": ["aios-scheme", "archsight-scheme"]
69
+ "aios-daily": ["aios-site-daily", "archsight-daily"],
70
+ "aios-daily-write": ["aios-daily-report-write", "archsight-daily-write"],
71
+ "aios-construction-daily": ["archsight-construction-daily"],
72
+ "aios-meeting": ["aios-site-meeting", "archsight-meeting"],
73
+ "aios-meeting-write": ["aios-minutes-write", "archsight-meeting-write"],
74
+ "aios-construction-meeting": ["archsight-construction-meeting"],
75
+ "aios-scheme": ["archsight-scheme"],
76
+ "aios-scheme-audit": ["aios-scheme-review", "aios-construction-scheme-audit", "archsight-scheme-audit"],
77
+ "aios-construction-scheme": ["archsight-construction-scheme"],
78
+ "aios-scheme-write": ["aios-construction-scheme-write", "archsight-scheme-write"]
64
79
  };
65
80
 
66
81
  const profileDetectionRules = {
@@ -113,6 +128,8 @@ const profileDetectionRules = {
113
128
  "条文",
114
129
  "审图",
115
130
  "标准",
131
+ "knowledge pack",
132
+ "知识包",
116
133
  "检索",
117
134
  "向量",
118
135
  "embedding",
@@ -126,17 +143,29 @@ const skillDetectionRules = {
126
143
  "aios-design": ["界面", "ui", "ux", "工作台", "交互", "原型"],
127
144
  "aios-plan": ["计划", "排期", "里程碑", "任务拆解", "交付"],
128
145
  "aios-review": ["code review", "代码审查", "安全审查", "技术债"],
129
- "aios-knowledge": ["bim", "ifc", "规范", "审图", "条文", "知识结构化"],
146
+ "aios-knowledge": ["bim", "ifc", "规范", "审图", "条文", "知识结构化", "knowledge pack", "知识包"],
130
147
  "aios-structural": ["结构", "荷载", "挠度", "fem", "有限元", "计算书"],
131
- "aios-runtime": ["rag", "graphrag", "mcp", "tool calling", "memory", "agent runtime"],
148
+ "aios-runtime": ["rag", "graphrag", "mcp", "tool calling", "memory", "agent runtime", "reference runtime"],
132
149
  "aios-compare": ["aios-compare"],
133
150
  "aios-prompt-compare": ["aios-prompt-compare"],
151
+ "aios-tender": ["招标", "投标", "技术标", "商务标", "招采"],
152
+ "aios-tender-audit": ["读标", "评标办法", "评分", "废标", "资格", "响应性", "资料缺口", "技术标复核", "投标复核"],
134
153
  "aios-commercial-tender": ["招标", "投标", "技术标", "商务标", "评分", "废标", "招采", "资格"],
154
+ "aios-tender-write": ["标书编写", "技术标编写", "技术标生成", "技术标改写", "投标文件生成", "投标响应生成", "标书优化", "标书改写", "历史标书", "评分点响应"],
155
+ "aios-contract-audit": ["合同审核", "合同复核", "合同履约", "付款条件", "责任边界", "违约风险", "合同资料缺口", "补充协议复核"],
156
+ "aios-contract-draft": ["合同草拟", "补充协议草稿", "条款改写", "履约通知", "催款函", "回函", "合同交底", "合同函件"],
135
157
  "aios-commercial-contract": ["合同", "协议", "付款", "履约", "违约", "分包", "采购", "结算条款"],
158
+ "aios-daily": ["施工日报", "项目日报", "现场日报", "周报素材", "现场记录", "施工日志"],
159
+ "aios-daily-write": ["日报生成", "日报编写", "施工日报生成", "项目日报生成", "周报生成", "现场记录整理", "口述日报"],
136
160
  "aios-construction-daily": ["日报", "周报", "现场记录", "施工日志", "进度", "材料进场", "机械", "劳务"],
161
+ "aios-meeting": ["会议纪要", "工程会议", "例会", "协调会", "专题会", "交底会", "待办闭环"],
162
+ "aios-meeting-write": ["会议纪要生成", "会议纪要编写", "会议记录整理", "录音转写", "会议待办生成", "纪要草稿"],
137
163
  "aios-construction-meeting": ["会议纪要", "例会", "协调会", "专题会", "待办", "责任人"],
138
164
  "aios-commercial-variation": ["变更", "签证", "联系单", "索赔", "洽商", "工程量"],
139
- "aios-construction-scheme": ["施工方案", "专项方案", "危大", "交底", "危险源", "专家论证"]
165
+ "aios-scheme": ["施工方案", "专项方案", "危大", "交底"],
166
+ "aios-scheme-audit": ["方案复核", "危险源", "计算书缺口", "专家意见回查", "专家论证", "交底要点", "规范核验"],
167
+ "aios-construction-scheme": ["施工方案", "专项方案", "危大", "交底", "危险源", "专家论证"],
168
+ "aios-scheme-write": ["方案编写", "方案生成", "施工方案生成", "专项施工方案生成", "方案改写", "施工方案改写", "方案优化", "历史方案", "专家意见回写", "施工方案初稿"]
140
169
  };
141
170
 
142
171
  const ignoredDetectionDirs = new Set([
@@ -164,6 +193,14 @@ function usage() {
164
193
  " archsight-aios install --target <codex|agents|gemini|antigravity|workbuddy|opencode|claude-code|all> --scope user",
165
194
  " archsight-aios doctor",
166
195
  " archsight-aios init [--cwd <path>] [--mode <auto|full|linked|ai-only>] [--profile <auto|none|all|name>]",
196
+ " archsight-aios writing:init [--cwd <path>] [--type <tender|scheme|general>] [--name <folder>] [--sample]",
197
+ " archsight-aios writing:validate [--cwd <path>] [--name <folder>]",
198
+ " archsight-aios knowledge:init [--cwd <path>] [--name <folder>] [--sample]",
199
+ " archsight-aios knowledge:validate [--cwd <path>] [--name <folder>]",
200
+ " archsight-aios knowledge:compile [--cwd <path>] [--name <folder>] [--out <json-file>]",
201
+ " archsight-aios knowledge:inspect [--cwd <path>] [--name <folder>] [--pack <json-file>]",
202
+ " archsight-aios knowledge:lookup --pack <json-file> --query <text> [--region <id>] [--discipline <id>] [--source-version <version>] [--project-condition <text>]",
203
+ " archsight-aios knowledge:eval [--cwd <path>] [--name <folder>] [--pack <json-file>]",
167
204
  " archsight-aios validate [--cwd <path>] [--profile <auto|none|all|name>] [--temp]",
168
205
  " archsight-aios capability:call --capability <id> --agent <id> --skill <id> --input <json-file>",
169
206
  " archsight-aios hermes:validate",
@@ -175,6 +212,9 @@ function usage() {
175
212
  " install Install AIOS assets into user-level assistant locations.",
176
213
  " doctor Check repository assets and user-level installation.",
177
214
  " init Add AI rules and .ai governance files to a project.",
215
+ " writing:init Create a Markdown document-writing workbench.",
216
+ " writing:validate Check a Markdown document-writing workbench.",
217
+ " knowledge:* Create, compile, query, and evaluate AIOS Knowledge Packs.",
178
218
  " validate Validate the project AI template output.",
179
219
  " capability:call Authorize and call a registered local Capability adapter.",
180
220
  " hermes:* Validate or dry-run Hermes runtime prompt sync.",
@@ -186,6 +226,12 @@ function usage() {
186
226
  " npx @archsight/aios install --target opencode --scope user",
187
227
  " npx @archsight/aios install --target claude-code --scope user",
188
228
  " npx @archsight/aios init",
229
+ " npx @archsight/aios writing:init --type tender",
230
+ " npx @archsight/aios writing:init --type scheme --sample --name scheme-sample",
231
+ " npx @archsight/aios writing:validate --name document-writing",
232
+ " npx @archsight/aios knowledge:init --sample --name scheme-review",
233
+ " npx @archsight/aios knowledge:compile --name scheme-review",
234
+ " npx @archsight/aios knowledge:lookup --pack scheme-review/compiled/knowledge-pack.json --query \"高支模方案是否应检查计算书\"",
189
235
  " npx @archsight/aios validate --temp",
190
236
  " npx @archsight/aios doctor"
191
237
  ].join("\n");
@@ -206,6 +252,16 @@ function parseArgs(argv) {
206
252
  capability: undefined,
207
253
  agent: undefined,
208
254
  skill: undefined,
255
+ documentType: "general",
256
+ workspaceName: "document-writing",
257
+ sample: false,
258
+ pack: undefined,
259
+ out: undefined,
260
+ query: undefined,
261
+ region: undefined,
262
+ discipline: undefined,
263
+ sourceVersion: undefined,
264
+ projectCondition: undefined,
209
265
  input: undefined,
210
266
  mcpCwd: undefined,
211
267
  mcpCommand: undefined,
@@ -233,6 +289,26 @@ function parseArgs(argv) {
233
289
  options.agent = rest[++i];
234
290
  } else if (arg === "--skill") {
235
291
  options.skill = rest[++i];
292
+ } else if (arg === "--type") {
293
+ options.documentType = rest[++i];
294
+ } else if (arg === "--name") {
295
+ options.workspaceName = rest[++i];
296
+ } else if (arg === "--sample") {
297
+ options.sample = true;
298
+ } else if (arg === "--pack") {
299
+ options.pack = path.resolve(rest[++i]);
300
+ } else if (arg === "--out") {
301
+ options.out = path.resolve(rest[++i]);
302
+ } else if (arg === "--query") {
303
+ options.query = rest[++i];
304
+ } else if (arg === "--region") {
305
+ options.region = rest[++i];
306
+ } else if (arg === "--discipline") {
307
+ options.discipline = rest[++i];
308
+ } else if (arg === "--source-version") {
309
+ options.sourceVersion = rest[++i];
310
+ } else if (arg === "--project-condition") {
311
+ options.projectCondition = rest[++i];
236
312
  } else if (arg === "--input") {
237
313
  options.input = path.resolve(rest[++i]);
238
314
  } else if (arg === "--mcp-cwd") {
@@ -353,7 +429,7 @@ async function readManifest() {
353
429
 
354
430
  async function readJson(filePath) {
355
431
  const raw = await fs.readFile(filePath, "utf8");
356
- return JSON.parse(raw);
432
+ return JSON.parse(raw.replace(/^\uFEFF/, ""));
357
433
  }
358
434
 
359
435
  async function readCapabilityRegistry() {
@@ -625,7 +701,7 @@ function callMcpStdio({ command, args, cwd, toolName, input, timeoutMs }) {
625
701
  params: {
626
702
  protocolVersion: "2025-06-18",
627
703
  capabilities: {},
628
- clientInfo: { name: "archsight-aios", version: "1.3.2" }
704
+ clientInfo: { name: "archsight-aios", version: aiosVersion }
629
705
  }
630
706
  };
631
707
  const callTool = {
@@ -971,15 +1047,32 @@ function confidenceFromScore(score) {
971
1047
  return "low";
972
1048
  }
973
1049
 
974
- function scoreDetectionRules(ruleMap, signalText) {
1050
+ function detectionKeywordWeight(keyword, weighted) {
1051
+ if (!weighted) {
1052
+ return 1;
1053
+ }
1054
+
1055
+ const length = normalizeSignal(keyword).trim().length;
1056
+ if (length >= 8) {
1057
+ return 4;
1058
+ }
1059
+ if (length >= 5) {
1060
+ return 3;
1061
+ }
1062
+ return 1;
1063
+ }
1064
+
1065
+ function scoreDetectionRules(ruleMap, signalText, options = {}) {
975
1066
  const normalized = normalizeSignal(signalText);
976
1067
  return Object.entries(ruleMap)
977
1068
  .map(([id, keywords]) => {
978
1069
  const matches = keywords.filter((keyword) => normalized.includes(normalizeSignal(keyword)));
1070
+ const score = matches.reduce((sum, keyword) => sum + detectionKeywordWeight(keyword, options.weighted), 0);
979
1071
  return {
980
1072
  id,
981
- score: matches.length,
982
- confidence: matches.length > 0 ? confidenceFromScore(matches.length) : "none",
1073
+ score,
1074
+ matchCount: matches.length,
1075
+ confidence: score > 0 ? confidenceFromScore(score) : "none",
983
1076
  matches
984
1077
  };
985
1078
  })
@@ -1077,7 +1170,7 @@ async function collectProjectDiscovery(targetRoot) {
1077
1170
 
1078
1171
  function detectProjectContext(manifest, discovery) {
1079
1172
  const profileScores = scoreDetectionRules(profileDetectionRules, discovery.signalText);
1080
- const skillScores = scoreDetectionRules(skillDetectionRules, discovery.signalText);
1173
+ const skillScores = scoreDetectionRules(skillDetectionRules, discovery.signalText, { weighted: true });
1081
1174
  const profileDescriptions = new Map((manifest.projectProfiles ?? []).map((profile) => [profile.id, profile.description]));
1082
1175
  const skillMetadata = new Map((manifest.skills ?? []).map((skill) => [skill.id, skill]));
1083
1176
 
@@ -1129,7 +1222,10 @@ function renderMatchList(scores, emptyText) {
1129
1222
 
1130
1223
  return scores.map((item) => {
1131
1224
  const matches = item.matches.slice(0, 8).join("、");
1132
- return `- \`${item.id}\`:${item.confidence},命中 ${item.score} 项(${matches})`;
1225
+ const scoreText = item.matchCount && item.matchCount !== item.score
1226
+ ? `命中 ${item.matchCount} 项,权重 ${item.score}`
1227
+ : `命中 ${item.score} 项`;
1228
+ return `- \`${item.id}\`:${item.confidence},${scoreText}(${matches})`;
1133
1229
  });
1134
1230
  }
1135
1231
 
@@ -1755,6 +1851,809 @@ async function initProject(options) {
1755
1851
  }
1756
1852
  }
1757
1853
 
1854
+ function resolveDocumentWritingType(value) {
1855
+ const normalized = normalizeSignal(value ?? "general").replaceAll("_", "-");
1856
+ const aliases = new Map([
1857
+ ["general", "general"],
1858
+ ["all", "general"],
1859
+ ["通用", "general"],
1860
+ ["tender", "tender"],
1861
+ ["bid", "tender"],
1862
+ ["technical-bid", "tender"],
1863
+ ["标书", "tender"],
1864
+ ["技术标", "tender"],
1865
+ ["投标", "tender"],
1866
+ ["scheme", "scheme"],
1867
+ ["construction-scheme", "scheme"],
1868
+ ["方案", "scheme"],
1869
+ ["施工方案", "scheme"],
1870
+ ["专项施工方案", "scheme"]
1871
+ ]);
1872
+
1873
+ const type = aliases.get(normalized);
1874
+ if (!type) {
1875
+ throw new Error(`Unsupported writing workspace type: ${value}`);
1876
+ }
1877
+ return type;
1878
+ }
1879
+
1880
+ function documentWritingTypeConfig(type) {
1881
+ const configs = {
1882
+ general: {
1883
+ label: "工程文档写作",
1884
+ skill: "aios-tender-write / aios-scheme-write",
1885
+ gate: "aios-tender-audit / aios-scheme-audit",
1886
+ firstStep: "先在 writing-brief.md 明确是标书、技术标、专项施工方案还是交底材料。"
1887
+ },
1888
+ tender: {
1889
+ label: "标书 / 技术标写作",
1890
+ skill: "aios-tender-write",
1891
+ gate: "aios-tender-audit",
1892
+ firstStep: "先把招标文件、评分办法、技术要求、用户初稿和历史标书索引写入工作母版。"
1893
+ },
1894
+ scheme: {
1895
+ label: "专项施工方案写作",
1896
+ skill: "aios-scheme-write",
1897
+ gate: "aios-scheme-audit",
1898
+ firstStep: "先把工程概况、方案初稿、历史方案、专家意见和计算书目录写入工作母版。"
1899
+ }
1900
+ };
1901
+ return configs[type];
1902
+ }
1903
+
1904
+ function renderDocumentWritingReadme(type) {
1905
+ const config = documentWritingTypeConfig(type);
1906
+ return [
1907
+ "# AIOS Document Writing Workbench",
1908
+ "",
1909
+ `> 类型:${config.label}`,
1910
+ "",
1911
+ "## 使用顺序",
1912
+ "",
1913
+ "1. 在 `source-normalized.md` 中归一化输入资料,只写来源明确的事实。",
1914
+ "2. 在 `material-index.md` 中登记历史素材、复用级别和不可复用原因。",
1915
+ "3. 在 `writing-brief.md` 中明确写作任务、目标章节、人工复核岗位和禁止结论。",
1916
+ "4. 使用对应写作 Skill 生成或改写 `draft.md`。",
1917
+ "5. 把草稿交给审核门禁 Skill,审核结论写入 `review-notes.md`。",
1918
+ "6. 人工确认后再整理 `final.md`,Word / PDF / PPT 只作为交付格式。",
1919
+ "",
1920
+ "## 推荐 Skill",
1921
+ "",
1922
+ `- 写作入口:\`${config.skill}\``,
1923
+ `- 审核门禁:\`${config.gate}\``,
1924
+ "",
1925
+ "## 首步动作",
1926
+ "",
1927
+ config.firstStep,
1928
+ "",
1929
+ "## 边界",
1930
+ "",
1931
+ "- 不编造资质、业绩、人员、设备、工期、金额、奖项或项目事实。",
1932
+ "- 缺少依据时写 `待补`、`需核验` 或 `转人工复核`。",
1933
+ "- AI 输出是 Markdown 工作母版,不是正式交付定稿。",
1934
+ ""
1935
+ ].join("\n");
1936
+ }
1937
+
1938
+ async function initDocumentWritingWorkspace(options) {
1939
+ const targetRoot = path.resolve(options.cwd);
1940
+ const workspaceName = options.workspaceName ?? "document-writing";
1941
+ if (!workspaceName || path.isAbsolute(workspaceName)) {
1942
+ throw new Error("--name must be a relative folder name");
1943
+ }
1944
+
1945
+ const requestedType = resolveDocumentWritingType(options.documentType);
1946
+ const type = options.sample && requestedType === "general" ? "tender" : requestedType;
1947
+ const templateRoot = options.sample
1948
+ ? path.join(repoRoot, "templates", "document-writing-samples", type)
1949
+ : path.join(repoRoot, "templates", "document-writing");
1950
+ const workspaceRoot = path.resolve(targetRoot, workspaceName);
1951
+ assertInside(workspaceRoot, targetRoot);
1952
+
1953
+ await ensureDir(targetRoot);
1954
+ await copyTreeMissing(templateRoot, workspaceRoot);
1955
+
1956
+ const readmePath = path.join(workspaceRoot, "README.md");
1957
+ assertInside(readmePath, workspaceRoot);
1958
+ if (await exists(readmePath)) {
1959
+ console.log(`SKIP existing ${readmePath}`);
1960
+ } else {
1961
+ await fs.writeFile(readmePath, renderDocumentWritingReadme(type), "utf8");
1962
+ console.log(`CREATE ${readmePath}`);
1963
+ }
1964
+
1965
+ console.log(`WRITING ${type}: ${workspaceRoot}`);
1966
+ }
1967
+
1968
+ const documentWritingFiles = [
1969
+ "source-normalized.md",
1970
+ "material-index.md",
1971
+ "writing-brief.md",
1972
+ "draft.md",
1973
+ "review-notes.md",
1974
+ "final.md"
1975
+ ];
1976
+
1977
+ async function resolveDocumentWritingWorkspaceRoot(options) {
1978
+ const targetRoot = path.resolve(options.cwd);
1979
+ const workspaceName = options.workspaceName ?? "document-writing";
1980
+ if (!workspaceName || path.isAbsolute(workspaceName)) {
1981
+ throw new Error("--name must be a relative folder name");
1982
+ }
1983
+
1984
+ const namedRoot = path.resolve(targetRoot, workspaceName);
1985
+ assertInside(namedRoot, targetRoot);
1986
+ if (await exists(namedRoot)) {
1987
+ return namedRoot;
1988
+ }
1989
+
1990
+ let targetRootHasWorkbench = true;
1991
+ for (const fileName of documentWritingFiles) {
1992
+ if (!(await exists(path.join(targetRoot, fileName)))) {
1993
+ targetRootHasWorkbench = false;
1994
+ break;
1995
+ }
1996
+ }
1997
+ if (targetRootHasWorkbench) {
1998
+ return targetRoot;
1999
+ }
2000
+
2001
+ return namedRoot;
2002
+ }
2003
+
2004
+ async function validateDocumentWritingWorkspace(options) {
2005
+ const workspaceRoot = await resolveDocumentWritingWorkspaceRoot(options);
2006
+ const checks = [];
2007
+
2008
+ async function check(label, ok, detail = "") {
2009
+ checks.push({ label, ok, detail });
2010
+ }
2011
+
2012
+ await check("workspace directory", await exists(workspaceRoot), workspaceRoot);
2013
+ for (const fileName of documentWritingFiles) {
2014
+ const filePath = path.join(workspaceRoot, fileName);
2015
+ const ok = await exists(filePath);
2016
+ await check(`${fileName} exists`, ok, filePath);
2017
+ if (!ok) {
2018
+ continue;
2019
+ }
2020
+ const content = await fs.readFile(filePath, "utf8");
2021
+ await check(`${fileName} is non-empty`, content.trim().length > 0, filePath);
2022
+ }
2023
+
2024
+ const source = await readTextIfExists(path.join(workspaceRoot, "source-normalized.md"));
2025
+ const materials = await readTextIfExists(path.join(workspaceRoot, "material-index.md"));
2026
+ const brief = await readTextIfExists(path.join(workspaceRoot, "writing-brief.md"));
2027
+ const draft = await readTextIfExists(path.join(workspaceRoot, "draft.md"));
2028
+ const review = await readTextIfExists(path.join(workspaceRoot, "review-notes.md"));
2029
+ const final = await readTextIfExists(path.join(workspaceRoot, "final.md"));
2030
+
2031
+ await check("source-normalized keeps source list", source.includes("资料来源清单"));
2032
+ await check("material-index keeps reuse levels", materials.includes("复用级别"));
2033
+ await check("writing-brief keeps banned claims", brief.includes("禁止承诺") || brief.includes("禁止结论"));
2034
+ await check("draft keeps provenance placeholders", draft.includes("来源") && draft.includes("待补"));
2035
+ await check(
2036
+ "review-notes keeps audit gate",
2037
+ review.includes("aios-tender-audit") ||
2038
+ review.includes("aios-scheme-audit") ||
2039
+ review.includes("aios-commercial-tender") ||
2040
+ review.includes("aios-construction-scheme")
2041
+ );
2042
+ await check("final keeps manual confirmation", final.includes("人工") && final.includes("定稿"));
2043
+
2044
+ const failed = checks.filter((item) => !item.ok);
2045
+ for (const item of checks) {
2046
+ console.log(`${item.ok ? "OK " : "MISS"} ${item.label}${item.detail ? `: ${item.detail}` : ""}`);
2047
+ }
2048
+
2049
+ if (failed.length > 0) {
2050
+ process.exitCode = 1;
2051
+ console.error(`Writing workbench validation failed: ${failed.length} issue(s).`);
2052
+ return;
2053
+ }
2054
+
2055
+ console.log(`Writing workbench validation passed: ${workspaceRoot}`);
2056
+ }
2057
+
2058
+ const knowledgePackFiles = [
2059
+ "knowledge-pack.source.json",
2060
+ "source-register.md",
2061
+ "standard-register.md",
2062
+ "clause-map.md",
2063
+ "entity-relation-map.md",
2064
+ "eval-questions.md",
2065
+ "review-notes.md"
2066
+ ];
2067
+
2068
+ function knowledgePackSourcePath(workspaceRoot) {
2069
+ return path.join(workspaceRoot, "knowledge-pack.source.json");
2070
+ }
2071
+
2072
+ function compiledKnowledgePackPath(workspaceRoot) {
2073
+ return path.join(workspaceRoot, "compiled", "knowledge-pack.json");
2074
+ }
2075
+
2076
+ function isObject(value) {
2077
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2078
+ }
2079
+
2080
+ function sha256(text) {
2081
+ return crypto.createHash("sha256").update(text).digest("hex");
2082
+ }
2083
+
2084
+ function collection(source, key) {
2085
+ return Array.isArray(source?.[key]) ? source[key] : [];
2086
+ }
2087
+
2088
+ function validateKnowledgePackSource(source) {
2089
+ const checks = [];
2090
+
2091
+ function check(label, ok, detail = "") {
2092
+ checks.push({ label, ok: Boolean(ok), detail });
2093
+ }
2094
+
2095
+ check("source is object", isObject(source));
2096
+ if (!isObject(source)) {
2097
+ return checks;
2098
+ }
2099
+
2100
+ check("schema is 1", source.schema === 1, "schema === 1");
2101
+ check("pack metadata exists", isObject(source.pack));
2102
+ check("pack.id exists", typeof source.pack?.id === "string" && source.pack.id.length > 0);
2103
+ check("pack.title exists", typeof source.pack?.title === "string" && source.pack.title.length > 0);
2104
+ check("pack.version exists", typeof source.pack?.version === "string" && source.pack.version.length > 0);
2105
+ check("pack.status valid", ["draft", "reviewed", "blocked", "published"].includes(source.pack?.status));
2106
+ check("pack.dataBoundary exists", typeof source.pack?.dataBoundary === "string" && source.pack.dataBoundary.length > 0);
2107
+
2108
+ for (const key of ["sources", "standards", "clauses", "entities", "relations", "lookupRules", "evalQuestions"]) {
2109
+ check(`${key} is non-empty array`, Array.isArray(source[key]) && source[key].length > 0);
2110
+ }
2111
+
2112
+ const idSets = new Map();
2113
+ for (const key of ["sources", "standards", "clauses", "entities", "relations", "lookupRules", "evalQuestions"]) {
2114
+ const ids = new Set();
2115
+ for (const item of collection(source, key)) {
2116
+ check(`${key} item has id`, typeof item.id === "string" && item.id.length > 0);
2117
+ if (typeof item.id === "string") {
2118
+ check(`${key} id unique ${item.id}`, !ids.has(item.id), item.id);
2119
+ ids.add(item.id);
2120
+ }
2121
+ }
2122
+ idSets.set(key, ids);
2123
+ }
2124
+
2125
+ const sourceIds = idSets.get("sources") ?? new Set();
2126
+ const standardIds = idSets.get("standards") ?? new Set();
2127
+ const clauseIds = idSets.get("clauses") ?? new Set();
2128
+ const entityIds = idSets.get("entities") ?? new Set();
2129
+ const graphNodeIds = new Set([...entityIds, ...clauseIds]);
2130
+
2131
+ for (const sourceItem of collection(source, "sources")) {
2132
+ check(`source ${sourceItem.id} authorization`, typeof sourceItem.authorization === "string" && sourceItem.authorization.length > 0);
2133
+ check(`source ${sourceItem.id} version`, typeof sourceItem.version === "string" && sourceItem.version.length > 0);
2134
+ check(`source ${sourceItem.id} reviewStatus`, typeof sourceItem.reviewStatus === "string" && sourceItem.reviewStatus.length > 0);
2135
+ }
2136
+
2137
+ for (const standard of collection(source, "standards")) {
2138
+ check(`standard ${standard.id} source exists`, sourceIds.has(standard.sourceId), standard.sourceId);
2139
+ check(`standard ${standard.id} version`, typeof standard.version === "string" && standard.version.length > 0);
2140
+ check(`standard ${standard.id} sourceVersion`, typeof standard.sourceVersion === "string" && standard.sourceVersion.length > 0);
2141
+ }
2142
+
2143
+ for (const clause of collection(source, "clauses")) {
2144
+ check(`clause ${clause.id} standard exists`, standardIds.has(clause.standardId), clause.standardId);
2145
+ check(`clause ${clause.id} source exists`, sourceIds.has(clause.sourceId), clause.sourceId);
2146
+ check(`clause ${clause.id} clauseNo`, typeof clause.clauseNo === "string" && clause.clauseNo.length > 0);
2147
+ check(`clause ${clause.id} applicability`, ["applicable", "not_applicable", "need_context"].includes(clause.applicability));
2148
+ check(`clause ${clause.id} pageRange`, typeof clause.pageRange === "string" && clause.pageRange.length > 0);
2149
+ check(`clause ${clause.id} reviewStatus`, typeof clause.reviewStatus === "string" && clause.reviewStatus.length > 0);
2150
+ }
2151
+
2152
+ for (const entity of collection(source, "entities")) {
2153
+ check(`entity ${entity.id} type`, typeof entity.type === "string" && entity.type.length > 0);
2154
+ check(`entity ${entity.id} confidence`, typeof entity.confidence === "number" && entity.confidence >= 0 && entity.confidence <= 1);
2155
+ for (const ref of entity.sourceRefs ?? []) {
2156
+ check(`entity ${entity.id} sourceRef exists ${ref}`, clauseIds.has(ref) || sourceIds.has(ref), ref);
2157
+ }
2158
+ }
2159
+
2160
+ for (const relation of collection(source, "relations")) {
2161
+ check(`relation ${relation.id} from exists`, graphNodeIds.has(relation.from), relation.from);
2162
+ check(`relation ${relation.id} to exists`, graphNodeIds.has(relation.to), relation.to);
2163
+ check(`relation ${relation.id} type`, typeof relation.type === "string" && relation.type.length > 0);
2164
+ check(`relation ${relation.id} confidence`, typeof relation.confidence === "number" && relation.confidence >= 0 && relation.confidence <= 1);
2165
+ }
2166
+
2167
+ for (const rule of collection(source, "lookupRules")) {
2168
+ check(`lookup ${rule.id} queryTerms`, Array.isArray(rule.queryTerms) && rule.queryTerms.length > 0);
2169
+ check(`lookup ${rule.id} clauseIds`, Array.isArray(rule.clauseIds) && rule.clauseIds.length > 0);
2170
+ for (const clauseId of rule.clauseIds ?? []) {
2171
+ check(`lookup ${rule.id} clause exists ${clauseId}`, clauseIds.has(clauseId), clauseId);
2172
+ }
2173
+ check(`lookup ${rule.id} applicability`, ["applicable", "not_applicable", "need_context"].includes(rule.applicability));
2174
+ }
2175
+
2176
+ for (const evalItem of collection(source, "evalQuestions")) {
2177
+ check(`eval ${evalItem.id} question`, typeof evalItem.question === "string" && evalItem.question.length > 0);
2178
+ check(`eval ${evalItem.id} expectedStatus`, ["found", "not_found", "conflict", "inapplicable", "error"].includes(evalItem.expectedStatus));
2179
+ check(`eval ${evalItem.id} expectedApplicability`, ["applicable", "not_applicable", "need_context"].includes(evalItem.expectedApplicability));
2180
+ check(`eval ${evalItem.id} expectedClauseIds`, Array.isArray(evalItem.expectedClauseIds));
2181
+ for (const clauseId of evalItem.expectedClauseIds ?? []) {
2182
+ check(`eval ${evalItem.id} clause exists ${clauseId}`, clauseIds.has(clauseId), clauseId);
2183
+ }
2184
+ }
2185
+
2186
+ check("review metadata exists", isObject(source.review));
2187
+ check("review status valid", ["draft", "reviewed", "blocked", "published"].includes(source.review?.status));
2188
+ return checks;
2189
+ }
2190
+
2191
+ async function readKnowledgePackSource(workspaceRoot) {
2192
+ const sourcePath = knowledgePackSourcePath(workspaceRoot);
2193
+ const raw = await fs.readFile(sourcePath, "utf8");
2194
+ return { source: JSON.parse(raw), raw, sourcePath };
2195
+ }
2196
+
2197
+ async function initKnowledgePackWorkspace(options) {
2198
+ const targetRoot = path.resolve(options.cwd);
2199
+ const workspaceName = options.workspaceName ?? "knowledge-pack";
2200
+ if (!workspaceName || path.isAbsolute(workspaceName)) {
2201
+ throw new Error("--name must be a relative folder name");
2202
+ }
2203
+
2204
+ const templateRoot = options.sample
2205
+ ? path.join(repoRoot, "templates", "knowledge-pack-samples", "scheme-review")
2206
+ : path.join(repoRoot, "templates", "knowledge-pack");
2207
+ const workspaceRoot = path.resolve(targetRoot, workspaceName);
2208
+ assertInside(workspaceRoot, targetRoot);
2209
+
2210
+ await ensureDir(targetRoot);
2211
+ await copyTreeMissing(templateRoot, workspaceRoot);
2212
+ console.log(`KNOWLEDGE ${options.sample ? "scheme-review" : "blank"}: ${workspaceRoot}`);
2213
+ }
2214
+
2215
+ async function resolveKnowledgePackWorkspaceRoot(options) {
2216
+ const targetRoot = path.resolve(options.cwd);
2217
+ const workspaceName = options.workspaceName ?? "knowledge-pack";
2218
+ if (!workspaceName || path.isAbsolute(workspaceName)) {
2219
+ throw new Error("--name must be a relative folder name");
2220
+ }
2221
+
2222
+ const namedRoot = path.resolve(targetRoot, workspaceName);
2223
+ assertInside(namedRoot, targetRoot);
2224
+ if (await exists(namedRoot)) {
2225
+ return namedRoot;
2226
+ }
2227
+
2228
+ let targetRootHasWorkbench = true;
2229
+ for (const fileName of knowledgePackFiles) {
2230
+ if (!(await exists(path.join(targetRoot, fileName)))) {
2231
+ targetRootHasWorkbench = false;
2232
+ break;
2233
+ }
2234
+ }
2235
+ if (targetRootHasWorkbench) {
2236
+ return targetRoot;
2237
+ }
2238
+
2239
+ return namedRoot;
2240
+ }
2241
+
2242
+ async function validateKnowledgePackWorkspace(options) {
2243
+ const workspaceRoot = await resolveKnowledgePackWorkspaceRoot(options);
2244
+ const checks = [];
2245
+
2246
+ function check(label, ok, detail = "") {
2247
+ checks.push({ label, ok: Boolean(ok), detail });
2248
+ }
2249
+
2250
+ check("workspace directory", await exists(workspaceRoot), workspaceRoot);
2251
+ for (const fileName of knowledgePackFiles) {
2252
+ const filePath = path.join(workspaceRoot, fileName);
2253
+ const ok = await exists(filePath);
2254
+ check(`${fileName} exists`, ok, filePath);
2255
+ if (ok) {
2256
+ const content = await fs.readFile(filePath, "utf8");
2257
+ check(`${fileName} is non-empty`, content.trim().length > 0, filePath);
2258
+ }
2259
+ }
2260
+
2261
+ try {
2262
+ const { source } = await readKnowledgePackSource(workspaceRoot);
2263
+ checks.push(...validateKnowledgePackSource(source));
2264
+ } catch (error) {
2265
+ check("knowledge-pack.source.json parses", false, error.message);
2266
+ }
2267
+
2268
+ const failed = checks.filter((item) => !item.ok);
2269
+ for (const item of checks) {
2270
+ console.log(`${item.ok ? "OK " : "MISS"} ${item.label}${item.detail ? `: ${item.detail}` : ""}`);
2271
+ }
2272
+
2273
+ if (failed.length > 0) {
2274
+ process.exitCode = 1;
2275
+ console.error(`Knowledge Pack validation failed: ${failed.length} issue(s).`);
2276
+ return;
2277
+ }
2278
+
2279
+ console.log(`Knowledge Pack validation passed: ${workspaceRoot}`);
2280
+ }
2281
+
2282
+ function compileKnowledgePackData(source, raw) {
2283
+ const standardsById = new Map(collection(source, "standards").map((item) => [item.id, item]));
2284
+ const sourcesById = new Map(collection(source, "sources").map((item) => [item.id, item]));
2285
+ const compiledClauses = collection(source, "clauses").map((clause) => {
2286
+ const standard = standardsById.get(clause.standardId) ?? {};
2287
+ const sourceItem = sourcesById.get(clause.sourceId) ?? {};
2288
+ return {
2289
+ ...clause,
2290
+ standard: {
2291
+ id: standard.id,
2292
+ name: standard.name,
2293
+ code: standard.code,
2294
+ version: standard.version,
2295
+ region: standard.region,
2296
+ discipline: standard.discipline,
2297
+ sourceVersion: standard.sourceVersion
2298
+ },
2299
+ source: {
2300
+ id: sourceItem.id,
2301
+ name: sourceItem.name,
2302
+ version: sourceItem.version,
2303
+ authorization: sourceItem.authorization,
2304
+ hash: sourceItem.hash
2305
+ }
2306
+ };
2307
+ });
2308
+
2309
+ return {
2310
+ schema: 1,
2311
+ type: "archsight-aios.knowledge-pack",
2312
+ compiledAt: new Date().toISOString(),
2313
+ compiler: {
2314
+ name: "archsight-aios",
2315
+ version: aiosVersion
2316
+ },
2317
+ sourceDigest: `sha256:${sha256(raw)}`,
2318
+ pack: source.pack,
2319
+ sources: collection(source, "sources"),
2320
+ standards: collection(source, "standards"),
2321
+ clauses: compiledClauses,
2322
+ graph: {
2323
+ entities: collection(source, "entities"),
2324
+ relations: collection(source, "relations")
2325
+ },
2326
+ runtime: {
2327
+ capabilityId: "knowledge.norm_lookup",
2328
+ lookupIndex: collection(source, "lookupRules")
2329
+ },
2330
+ evalQuestions: collection(source, "evalQuestions"),
2331
+ review: source.review,
2332
+ boundary: {
2333
+ notOfficialStandardDatabase: true,
2334
+ noAutomatedComplianceConclusion: true,
2335
+ requiresHumanReviewForFormalUse: true
2336
+ }
2337
+ };
2338
+ }
2339
+
2340
+ async function compileKnowledgePack(options, silent = false) {
2341
+ const workspaceRoot = await resolveKnowledgePackWorkspaceRoot(options);
2342
+ const { source, raw } = await readKnowledgePackSource(workspaceRoot);
2343
+ const checks = validateKnowledgePackSource(source);
2344
+ const failed = checks.filter((item) => !item.ok);
2345
+ if (failed.length > 0) {
2346
+ const details = failed.map((item) => item.label).join("; ");
2347
+ throw new Error(`Knowledge Pack source is invalid: ${details}`);
2348
+ }
2349
+
2350
+ const artifact = compileKnowledgePackData(source, raw);
2351
+ const outPath = options.out ?? compiledKnowledgePackPath(workspaceRoot);
2352
+ await ensureDir(path.dirname(outPath));
2353
+ await fs.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
2354
+
2355
+ if (!silent) {
2356
+ console.log(`KNOWLEDGE_PACK ${artifact.pack.id}: ${outPath}`);
2357
+ console.log(`CLAUSES ${artifact.clauses.length}`);
2358
+ console.log(`EVAL_QUESTIONS ${artifact.evalQuestions.length}`);
2359
+ }
2360
+
2361
+ return { artifact, outPath, workspaceRoot };
2362
+ }
2363
+
2364
+ async function resolveKnowledgePackArtifactPath(options) {
2365
+ if (options.pack) {
2366
+ return options.pack;
2367
+ }
2368
+ const workspaceRoot = await resolveKnowledgePackWorkspaceRoot(options);
2369
+ return compiledKnowledgePackPath(workspaceRoot);
2370
+ }
2371
+
2372
+ async function readCompiledKnowledgePack(optionsOrPath) {
2373
+ const packPath = typeof optionsOrPath === "string"
2374
+ ? path.resolve(optionsOrPath)
2375
+ : await resolveKnowledgePackArtifactPath(optionsOrPath);
2376
+ const pack = await readJson(packPath);
2377
+ if (pack.schema !== 1 || pack.type !== "archsight-aios.knowledge-pack") {
2378
+ throw new Error(`Invalid Knowledge Pack artifact: ${packPath}`);
2379
+ }
2380
+ return { pack, packPath };
2381
+ }
2382
+
2383
+ async function inspectKnowledgePack(options) {
2384
+ const { pack, packPath } = await readCompiledKnowledgePack(options);
2385
+ const summary = {
2386
+ schema: 1,
2387
+ path: packPath,
2388
+ packId: pack.pack?.id,
2389
+ title: pack.pack?.title,
2390
+ version: pack.pack?.version,
2391
+ status: pack.pack?.status,
2392
+ sourceDigest: pack.sourceDigest,
2393
+ counts: {
2394
+ sources: pack.sources?.length ?? 0,
2395
+ standards: pack.standards?.length ?? 0,
2396
+ clauses: pack.clauses?.length ?? 0,
2397
+ entities: pack.graph?.entities?.length ?? 0,
2398
+ relations: pack.graph?.relations?.length ?? 0,
2399
+ lookupRules: pack.runtime?.lookupIndex?.length ?? 0,
2400
+ evalQuestions: pack.evalQuestions?.length ?? 0
2401
+ },
2402
+ boundary: pack.boundary
2403
+ };
2404
+ console.log(JSON.stringify(summary, null, 2));
2405
+ }
2406
+
2407
+ function citationForClause(clause) {
2408
+ return {
2409
+ sourceId: clause.source?.id ?? clause.sourceId,
2410
+ sourceName: clause.source?.name,
2411
+ standardId: clause.standard?.id ?? clause.standardId,
2412
+ standardName: clause.standard?.name,
2413
+ standardCode: clause.standard?.code,
2414
+ sourceVersion: clause.standard?.sourceVersion ?? clause.source?.version,
2415
+ clauseId: clause.id,
2416
+ clauseNo: clause.clauseNo,
2417
+ title: clause.title,
2418
+ pageRange: clause.pageRange,
2419
+ reviewStatus: clause.reviewStatus,
2420
+ applicability: clause.applicability
2421
+ };
2422
+ }
2423
+
2424
+ function lookupRuleScore(rule, query) {
2425
+ const normalizedQuery = normalizeSignal(query);
2426
+ return (rule.queryTerms ?? []).reduce((score, term) => {
2427
+ const normalizedTerm = normalizeSignal(term);
2428
+ return normalizedTerm && normalizedQuery.includes(normalizedTerm)
2429
+ ? score + Math.max(1, normalizedTerm.length)
2430
+ : score;
2431
+ }, 0);
2432
+ }
2433
+
2434
+ function lookupKnowledgePack(pack, request) {
2435
+ const query = request?.query ?? "";
2436
+ const rules = pack.runtime?.lookupIndex ?? [];
2437
+ const clausesById = new Map((pack.clauses ?? []).map((clause) => [clause.id, clause]));
2438
+ const matchedRules = rules
2439
+ .map((rule) => ({ rule, score: lookupRuleScore(rule, query) }))
2440
+ .filter((item) => item.score > 0)
2441
+ .sort((left, right) => right.score - left.score || left.rule.id.localeCompare(right.rule.id));
2442
+
2443
+ if (matchedRules.length === 0) {
2444
+ return {
2445
+ status: "not_found",
2446
+ citations: [],
2447
+ applicability: "need_context",
2448
+ sourceVersion: request?.sourceVersion ?? pack.pack?.sourceVersion ?? "",
2449
+ notes: "未命中当前 Knowledge Pack;不得把模型常识写成规范结论。"
2450
+ };
2451
+ }
2452
+
2453
+ const candidateClauses = [];
2454
+ const seenClauseIds = new Set();
2455
+ for (const { rule } of matchedRules) {
2456
+ for (const clauseId of rule.clauseIds ?? []) {
2457
+ if (seenClauseIds.has(clauseId)) {
2458
+ continue;
2459
+ }
2460
+ const clause = clausesById.get(clauseId);
2461
+ if (clause) {
2462
+ candidateClauses.push(clause);
2463
+ seenClauseIds.add(clauseId);
2464
+ }
2465
+ }
2466
+ }
2467
+
2468
+ if (request?.sourceVersion) {
2469
+ const versionMatches = candidateClauses.filter((clause) => {
2470
+ const sourceVersion = clause.standard?.sourceVersion ?? clause.source?.version;
2471
+ return sourceVersion === request.sourceVersion;
2472
+ });
2473
+ if (versionMatches.length === 0) {
2474
+ return {
2475
+ status: "inapplicable",
2476
+ citations: [],
2477
+ applicability: "not_applicable",
2478
+ sourceVersion: request.sourceVersion,
2479
+ notes: `请求版本 ${request.sourceVersion} 未命中当前 Knowledge Pack 的来源版本。`
2480
+ };
2481
+ }
2482
+ }
2483
+
2484
+ const conflict = matchedRules.some((item) => item.rule.status === "conflict");
2485
+ const citations = candidateClauses.map(citationForClause);
2486
+ const firstRule = matchedRules[0].rule;
2487
+ const applicability = conflict
2488
+ ? "need_context"
2489
+ : firstRule.applicability ?? candidateClauses[0]?.applicability ?? "need_context";
2490
+ const sourceVersion = citations[0]?.sourceVersion ?? pack.pack?.sourceVersion ?? "";
2491
+ const notes = matchedRules
2492
+ .map((item) => item.rule.notes)
2493
+ .filter(Boolean)
2494
+ .join(" ");
2495
+
2496
+ return {
2497
+ status: conflict ? "conflict" : "found",
2498
+ citations,
2499
+ applicability,
2500
+ sourceVersion,
2501
+ notes: notes || "已命中 Knowledge Pack;正式结论仍需结合项目条件和人工复核。"
2502
+ };
2503
+ }
2504
+
2505
+ async function lookupKnowledgePackCommand(options) {
2506
+ if (!options.pack) {
2507
+ throw new Error("--pack is required for knowledge:lookup");
2508
+ }
2509
+ if (!options.query) {
2510
+ throw new Error("--query is required for knowledge:lookup");
2511
+ }
2512
+
2513
+ const { pack } = await readCompiledKnowledgePack(options.pack);
2514
+ const result = lookupKnowledgePack(pack, {
2515
+ query: options.query,
2516
+ region: options.region,
2517
+ discipline: options.discipline,
2518
+ sourceVersion: options.sourceVersion,
2519
+ projectCondition: options.projectCondition
2520
+ });
2521
+ console.log(JSON.stringify(result, null, 2));
2522
+ }
2523
+
2524
+ async function evalKnowledgePack(options) {
2525
+ let pack;
2526
+ let packPath;
2527
+ if (options.pack) {
2528
+ ({ pack, packPath } = await readCompiledKnowledgePack(options.pack));
2529
+ } else {
2530
+ const compiled = await compileKnowledgePack(options, true);
2531
+ pack = compiled.artifact;
2532
+ packPath = compiled.outPath;
2533
+ }
2534
+
2535
+ const cases = [];
2536
+ for (const evalItem of pack.evalQuestions ?? []) {
2537
+ const result = lookupKnowledgePack(pack, {
2538
+ query: evalItem.question,
2539
+ sourceVersion: evalItem.inputSourceVersion
2540
+ });
2541
+ const expectedClauseIds = new Set(evalItem.expectedClauseIds ?? []);
2542
+ const actualClauseIds = new Set((result.citations ?? []).map((item) => item.clauseId));
2543
+ const checks = [
2544
+ {
2545
+ label: "status",
2546
+ ok: result.status === evalItem.expectedStatus,
2547
+ expected: evalItem.expectedStatus,
2548
+ actual: result.status
2549
+ },
2550
+ {
2551
+ label: "applicability",
2552
+ ok: result.applicability === evalItem.expectedApplicability,
2553
+ expected: evalItem.expectedApplicability,
2554
+ actual: result.applicability
2555
+ },
2556
+ {
2557
+ label: "citations",
2558
+ ok: [...expectedClauseIds].every((clauseId) => actualClauseIds.has(clauseId))
2559
+ && (expectedClauseIds.size > 0 || actualClauseIds.size === 0),
2560
+ expected: [...expectedClauseIds],
2561
+ actual: [...actualClauseIds]
2562
+ },
2563
+ {
2564
+ label: "sourceVersion",
2565
+ ok: !evalItem.mustCiteSourceVersion || (result.sourceVersion && (result.citations ?? []).every((item) => item.sourceVersion)),
2566
+ expected: "sourceVersion present when required",
2567
+ actual: result.sourceVersion
2568
+ },
2569
+ {
2570
+ label: "notes",
2571
+ ok: (evalItem.expectedNotesContains ?? []).every((term) => result.notes.includes(term)),
2572
+ expected: evalItem.expectedNotesContains ?? [],
2573
+ actual: result.notes
2574
+ }
2575
+ ];
2576
+ cases.push({
2577
+ id: evalItem.id,
2578
+ question: evalItem.question,
2579
+ passed: checks.every((item) => item.ok),
2580
+ checks,
2581
+ result
2582
+ });
2583
+ }
2584
+
2585
+ const report = {
2586
+ schema: 1,
2587
+ packPath,
2588
+ packId: pack.pack?.id,
2589
+ total: cases.length,
2590
+ passed: cases.filter((item) => item.passed).length,
2591
+ failed: cases.filter((item) => !item.passed).length,
2592
+ cases
2593
+ };
2594
+
2595
+ console.log(JSON.stringify(report, null, 2));
2596
+ if (report.failed > 0) {
2597
+ process.exitCode = 1;
2598
+ }
2599
+ }
2600
+
2601
+ function knowledgePackPathFromMcpArgs(args) {
2602
+ const value = args.knowledgePackPath ?? args.packPath;
2603
+ if (typeof value === "string" && value.length > 0) {
2604
+ return path.resolve(value);
2605
+ }
2606
+ return path.resolve(process.cwd(), "knowledge-pack", "compiled", "knowledge-pack.json");
2607
+ }
2608
+
2609
+ async function runKnowledgeMcpServer() {
2610
+ const rl = readline.createInterface({ input: process.stdin });
2611
+ for await (const line of rl) {
2612
+ if (!line.trim()) {
2613
+ continue;
2614
+ }
2615
+ const request = JSON.parse(line);
2616
+ if (request.method === "initialize") {
2617
+ console.log(JSON.stringify({
2618
+ jsonrpc: "2.0",
2619
+ id: request.id,
2620
+ result: {
2621
+ protocolVersion: "2025-06-18",
2622
+ serverInfo: { name: "archsight-aios-knowledge-reference", version: aiosVersion },
2623
+ capabilities: { tools: {} }
2624
+ }
2625
+ }));
2626
+ continue;
2627
+ }
2628
+ if (request.method === "tools/call") {
2629
+ try {
2630
+ const args = request.params?.arguments ?? {};
2631
+ const toolName = request.params?.name;
2632
+ if (!["norm_lookup", "knowledge.norm_lookup"].includes(toolName)) {
2633
+ throw new Error(`Unknown knowledge tool: ${toolName}`);
2634
+ }
2635
+ const { pack } = await readCompiledKnowledgePack(knowledgePackPathFromMcpArgs(args));
2636
+ const result = lookupKnowledgePack(pack, args);
2637
+ console.log(JSON.stringify({
2638
+ jsonrpc: "2.0",
2639
+ id: request.id,
2640
+ result: {
2641
+ content: [{ type: "text", text: JSON.stringify(result) }],
2642
+ isError: false,
2643
+ structuredContent: result
2644
+ }
2645
+ }));
2646
+ } catch (error) {
2647
+ console.log(JSON.stringify({
2648
+ jsonrpc: "2.0",
2649
+ id: request.id,
2650
+ error: { code: -32000, message: error.message }
2651
+ }));
2652
+ }
2653
+ }
2654
+ }
2655
+ }
2656
+
1758
2657
  async function validateProjectTemplate(options) {
1759
2658
  const manifest = await readManifest();
1760
2659
  const createdTemp = options.temp;
@@ -1949,6 +2848,24 @@ async function main() {
1949
2848
  await doctor();
1950
2849
  } else if (options.command === "init") {
1951
2850
  await initProject(options);
2851
+ } else if (options.command === "writing:init") {
2852
+ await initDocumentWritingWorkspace(options);
2853
+ } else if (options.command === "writing:validate") {
2854
+ await validateDocumentWritingWorkspace(options);
2855
+ } else if (options.command === "knowledge:init") {
2856
+ await initKnowledgePackWorkspace(options);
2857
+ } else if (options.command === "knowledge:validate") {
2858
+ await validateKnowledgePackWorkspace(options);
2859
+ } else if (options.command === "knowledge:compile") {
2860
+ await compileKnowledgePack(options);
2861
+ } else if (options.command === "knowledge:inspect") {
2862
+ await inspectKnowledgePack(options);
2863
+ } else if (options.command === "knowledge:lookup") {
2864
+ await lookupKnowledgePackCommand(options);
2865
+ } else if (options.command === "knowledge:eval") {
2866
+ await evalKnowledgePack(options);
2867
+ } else if (options.command === "knowledge:mcp") {
2868
+ await runKnowledgeMcpServer();
1952
2869
  } else if (options.command === "validate") {
1953
2870
  await validateProjectTemplate(options);
1954
2871
  } else if (options.command === "capability:call") {