@thinkingai/ae-cli 6.1.25 → 6.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -9
- package/README.zh.md +25 -9
- package/bin/ae-cli.js +6 -1
- package/cli-installation-guide.md +91 -0
- package/dist/{auth-LHM7NQPR.js → auth-WA7YGGRT.js} +6 -8
- package/dist/automation-VAAQBM7Y.js +459 -0
- package/dist/{capability-SJI5KOCK.js → capability-GAAYJ3IQ.js} +6 -6
- package/dist/{chunk-KJDOTPYU.js → chunk-3YVEAZUN.js} +59 -26
- package/dist/{chunk-KS4DE3MX.js → chunk-5XJYLEVC.js} +4 -4
- package/dist/{chunk-BW7JUDEI.js → chunk-6VNIR4AP.js} +514 -213
- package/dist/{chunk-5XRQ3CZR.js → chunk-7KU2WNQE.js} +43 -8
- package/dist/{chunk-7WZACOAI.js → chunk-AP7YP2NX.js} +2 -2
- package/dist/{chunk-XKIW3QMF.js → chunk-AQJPNWZF.js} +3 -3
- package/dist/chunk-CI24BDR2.js +43 -0
- package/dist/{chunk-SO5LKIWP.js → chunk-CT7QDJS6.js} +2 -2
- package/dist/{chunk-DU72X2IO.js → chunk-GHXZK54S.js} +22 -10
- package/dist/{chunk-2FJM4HRV.js → chunk-MWIA43UJ.js} +3 -3
- package/dist/{chunk-N4BLPJC7.js → chunk-OP44TT4H.js} +1 -1
- package/dist/chunk-Q5US7JC5.js +133 -0
- package/dist/chunk-RK6GLDGI.js +27 -0
- package/dist/chunk-RPBOAQQQ.js +56 -0
- package/dist/{chunk-GK7WDY7E.js → chunk-S6M42KND.js} +1 -1
- package/dist/{chunk-QYXDJOLA.js → chunk-VZZNLV3I.js} +19 -11
- package/dist/{chunk-YVGXGTD6.js → chunk-WNGFSIOB.js} +7 -1
- package/dist/{chunk-IG3DYEIR.js → chunk-ZL7SGNIA.js} +5 -3
- package/dist/{community-report-client-6VJDDMJJ.js → community-report-client-PEERQCX2.js} +1 -1
- package/dist/{config-XQWOPDHN.js → config-JOD5DOPE.js} +4 -4
- package/dist/context-NGVFPCBK.js +136 -0
- package/dist/{data-integration-XBTCGXQT.js → data-integration-BCLQFTGU.js} +6 -6
- package/dist/index.js +123 -46
- package/dist/{local-data-upload-client-3P7NIVQ4.js → local-data-upload-client-TWMHFLUA.js} +1 -1
- package/dist/memory-CQKH2JAV.js +580 -0
- package/dist/{metadata-JRYKNUS5.js → metadata-NR3PHR23.js} +7 -7
- package/dist/{model-ZS7HVGKN.js → model-VX5M2CJ6.js} +9 -5
- package/dist/{personal-semantic-preference-IDE2GE5T.js → personal-semantic-preference-2RAI36P3.js} +117 -11
- package/dist/{project-semantic-36KOCYN7.js → project-semantic-3BUGP3ZM.js} +6 -6
- package/dist/{sync-EQLSTUS7.js → sync-RZIAV37C.js} +12 -8
- package/dist/{te-agent-Z3HCTKR7.js → te-agent-AORRE2FM.js} +90 -454
- package/dist/{te-analysis-5ZZ6YHVH.js → te-analysis-GP7DSQ7Q.js} +297 -20
- package/dist/{te-community-Z7JACGF3.js → te-community-42M7ICDO.js} +3 -3
- package/dist/{te-dataops-F7GQOIS6.js → te-dataops-BNKNZ4F2.js} +5 -5
- package/dist/{te-engage-RNRMYDO3.js → te-engage-2CO6LRCX.js} +6 -6
- package/dist/{te-experiment-BTAC2UNK.js → te-experiment-652CLXMU.js} +6 -6
- package/dist/{te-kb-QJLJEX5K.js → te-kb-ULATOTQ3.js} +494 -214
- package/dist/{te-system-IXC43QHZ.js → te-system-UGHVKBVV.js} +10 -9
- package/dist/{te-team-BIZIKIHZ.js → te-team-YA6SNOJ3.js} +6 -6
- package/dist/things-DTCOQIQB.js +1091 -0
- package/dist/{update-W2SGQNKT.js → update-ESNYKUVR.js} +59 -51
- package/dist/workspace-JEOHKFPX.js +554 -0
- package/package.json +21 -9
- package/skills/ae-agent/SKILL.md +91 -139
- package/skills/ae-agent/references/add-model.md +1 -1
- package/skills/ae-agent/references/create-agent.md +1 -1
- package/skills/ae-agent/references/find-archived-conversations.md +12 -5
- package/skills/ae-agent/references/get-agent.md +1 -1
- package/skills/ae-agent/references/list-agents.md +2 -2
- package/skills/ae-agent/references/list-models.md +2 -2
- package/skills/ae-agent/references/restore-conversation.md +3 -1
- package/skills/ae-analysis/SKILL.md +15 -6
- package/skills/ae-analysis/references/ai_models/funnel.md +5 -3
- package/skills/ae-analysis/references/ai_models.md +27 -0
- package/skills/ae-analysis/references/command_index.md +12 -4
- package/skills/ae-analysis/references/dashboard_move.md +21 -0
- package/skills/ae-analysis/references/dashboard_report_add.md +2 -0
- package/skills/ae-analysis/references/dashboard_report_get.md +19 -0
- package/skills/ae-analysis/references/dashboard_report_update.md +27 -0
- package/skills/ae-analysis/references/dashboard_update.md +1 -1
- package/skills/ae-analysis/references/event_report_presentation.md +76 -0
- package/skills/ae-analysis/references/feedback_submit.md +37 -0
- package/skills/ae-analysis/references/metadata_resolution.md +15 -0
- package/skills/ae-analysis/references/personal_semantic_preference_review.md +9 -0
- package/skills/ae-analysis/references/personal_semantic_preference_review_list.md +7 -0
- package/skills/ae-analysis/references/personal_semantic_preference_submit.md +7 -0
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +68 -27
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +40 -1
- package/skills/ae-analysis/references/report_create.md +13 -3
- package/skills/ae-analysis/references/report_get.md +5 -1
- package/skills/ae-analysis/references/report_update.md +15 -4
- package/skills/ae-analysis/references/system_query_monitor_overview.md +2 -0
- package/skills/ae-analysis/references/system_query_task_cancel.md +2 -0
- package/skills/ae-analysis/references/system_query_task_export.md +6 -2
- package/skills/ae-analysis/references/system_query_task_get.md +2 -0
- package/skills/ae-analysis/references/system_query_task_list.md +7 -3
- package/skills/ae-analysis/references/system_query_task_options.md +2 -2
- package/skills/ae-analysis/references/system_query_task_realtime_list.md +15 -0
- package/skills/ae-analysis/references/user_tag_models.md +2 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-empty-skeleton.mjs +105 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +337 -22
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +21 -8
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +24 -11
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +66 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +1 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +109 -40
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/plan-kb-source-sync.mjs +1 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/prepare-compile-schema.mjs +64 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/refresh-state-parts.mjs +91 -0
- package/skills/ae-automation/SKILL.md +16 -0
- package/skills/ae-automation/references/cli.md +53 -0
- package/skills/ae-automation/references/command_index.md +17 -0
- package/skills/ae-capability/SKILL.md +15 -6
- package/skills/ae-current-context/SKILL.md +3 -2
- package/skills/ae-kb/SKILL.md +62 -12
- package/skills/ae-kb/references/analysis-workflow.md +73 -36
- package/skills/ae-kb/references/query-workflow.md +67 -33
- package/skills/ae-kb/references/schema-import.md +5 -3
- package/skills/ae-kb/references/source-mutations.md +6 -4
- package/skills/ae-kb/references/text-sources.md +53 -0
- package/skills/ae-kb-discovery/SKILL.md +1 -1
- package/skills/ae-team/SKILL.md +23 -17
- package/skills/ae-things/SKILL.md +85 -0
- package/skills/ae-things/references/cli.md +103 -0
- package/skills/ae-things-progress/SKILL.md +43 -0
- package/skills/ae-things-review/SKILL.md +42 -0
- package/skills/ae-workspace/SKILL.md +43 -0
- package/skills/ae-workspace/references/commands.md +51 -0
- package/dist/chunk-E2JKXMVO.js +0 -29
- package/dist/context-M3HDGEIR.js +0 -46
- package/dist/memory-6APEB2JB.js +0 -892
- package/skills/ae-agent/references/create-automation.md +0 -125
- package/skills/ae-agent/references/list-automations.md +0 -56
- package/skills/ae-agent/references/update-automation.md +0 -107
package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs
CHANGED
|
@@ -71,9 +71,12 @@ const dashboards = readIndex('dashboard-catalog');
|
|
|
71
71
|
const reports = readIndex('report-catalog');
|
|
72
72
|
const metrics = readIndex('metric-catalog');
|
|
73
73
|
const containers = readIndex('asset-containers');
|
|
74
|
+
const adoptedPersonalSemantics = readPackageJsonl('sources/adopted-personal-semantics.jsonl');
|
|
75
|
+
const eventGroups = readOptionalIndex('event-groups');
|
|
74
76
|
const dashboardById = indexBy(dashboards, 'resource_key');
|
|
75
77
|
const reportById = indexBy(reports, 'resource_key');
|
|
76
78
|
const metricById = indexBy(metrics, 'resource_key');
|
|
79
|
+
const adoptedPersonalBySourceId = indexBy(adoptedPersonalSemantics, 'source_id');
|
|
77
80
|
const dashboardFileNames = titleFirstAssetFileMap(dashboards, 'dashboard');
|
|
78
81
|
const reportFileNames = titleFirstAssetFileMap(reports, 'report');
|
|
79
82
|
const metricFileNames = titleFirstAssetFileMap(metrics, 'metric');
|
|
@@ -81,6 +84,7 @@ const titleFirstAssetPathMap = titleFirstAssetPathRewrites();
|
|
|
81
84
|
const containerById = indexBy(containers, 'container_key');
|
|
82
85
|
const domains = asArray(semanticPlan.domains);
|
|
83
86
|
const appendices = asArray(semanticPlan.appendices);
|
|
87
|
+
const personalSemanticIntegrations = asArray(semanticPlan.personal_semantic_integrations);
|
|
84
88
|
const domainByDashboardId = new Map();
|
|
85
89
|
const appendixByDashboardId = new Map();
|
|
86
90
|
for (const domain of domains) for (const id of asArray(domain.dashboard_ids).map(clean)) domainByDashboardId.set(id, domain);
|
|
@@ -110,8 +114,11 @@ try {
|
|
|
110
114
|
const wikiRoot = path.join(staging, 'wiki');
|
|
111
115
|
for (const directory of [
|
|
112
116
|
'domains', 'technical-appendices', 'source-containers', 'dashboards', 'reports', 'metrics',
|
|
113
|
-
'metadata', 'recall-cards', 'governance',
|
|
117
|
+
'metadata', 'recall-cards', 'personal-semantics', 'governance', 'common', 'event-map', 'asset-index',
|
|
114
118
|
]) fs.mkdirSync(path.join(wikiRoot, directory), { recursive: true });
|
|
119
|
+
for (const type of ['background', 'preference', 'experience', 'asset-context']) {
|
|
120
|
+
fs.mkdirSync(path.join(wikiRoot, 'personal-semantics', type), { recursive: true });
|
|
121
|
+
}
|
|
115
122
|
|
|
116
123
|
for (const metadataType of fs.readdirSync(path.join(buildIr, 'metadata'), { withFileTypes: true })
|
|
117
124
|
.filter((entry) => entry.isDirectory()).map((entry) => entry.name)) {
|
|
@@ -125,7 +132,8 @@ try {
|
|
|
125
132
|
const cardLinks = cards.map((card) => `- [${escapeLink(card.intent || card.card_id)}](../recall-cards/${fileName('recall-card', card.card_id)})`).join('\n');
|
|
126
133
|
writeText(path.join(wikiRoot, 'domains', fileName('domain', id)),
|
|
127
134
|
replaceFrontmatter(source, domainFrontmatter(domain))
|
|
128
|
-
+ `\n## 场景召回卡\n\n${cardLinks || '- 无'}\n`
|
|
135
|
+
+ `\n## 场景召回卡\n\n${cardLinks || '- 无'}\n`
|
|
136
|
+
+ renderTargetedKnowledge('domain', id, '../personal-semantics/'));
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
for (const appendix of appendices) {
|
|
@@ -185,7 +193,7 @@ try {
|
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
copyIndex(path.join(buildIr, 'dashboards', 'index.md'), path.join(wikiRoot, 'dashboards', 'index.md'));
|
|
188
|
-
|
|
196
|
+
writeText(path.join(wikiRoot, 'reports', 'index.md'), renderReportIndex());
|
|
189
197
|
copyIndex(path.join(buildIr, 'metrics', 'index.md'), path.join(wikiRoot, 'metrics', 'index.md'));
|
|
190
198
|
copyIndex(path.join(buildIr, 'metadata', 'index.md'), path.join(wikiRoot, 'metadata', 'index.md'));
|
|
191
199
|
|
|
@@ -194,12 +202,29 @@ try {
|
|
|
194
202
|
}
|
|
195
203
|
writeText(path.join(wikiRoot, 'recall-cards', 'index.md'), renderRecallCardIndex(planModel.cards));
|
|
196
204
|
|
|
205
|
+
writeText(path.join(wikiRoot, 'common', 'index.md'), renderCommonIndex());
|
|
206
|
+
writeText(path.join(wikiRoot, 'asset-index', 'index.md'), renderAssetIndex());
|
|
207
|
+
writeEventMap(wikiRoot, buildIr);
|
|
208
|
+
|
|
209
|
+
for (const integration of planModel.personalSemanticIntegrations) {
|
|
210
|
+
const contextPath = personalSemanticContextPath(integration.context_type);
|
|
211
|
+
writeText(path.join(wikiRoot, 'personal-semantics', contextPath,
|
|
212
|
+
fileName('personal-semantic', integration.integration_id)), renderPersonalSemanticIntegration(integration));
|
|
213
|
+
}
|
|
214
|
+
writeText(path.join(wikiRoot, 'personal-semantics', 'index.md'),
|
|
215
|
+
renderPersonalSemanticIndex(planModel.personalSemanticIntegrations));
|
|
216
|
+
for (const type of ['background', 'preference', 'experience', 'asset_context']) {
|
|
217
|
+
writeText(path.join(wikiRoot, 'personal-semantics', personalSemanticContextPath(type), 'index.md'),
|
|
218
|
+
renderPersonalSemanticTypeIndex(type, planModel.personalSemanticIntegrations));
|
|
219
|
+
}
|
|
220
|
+
|
|
197
221
|
const coverage = readText(path.join(buildIr, 'indexes', 'coverage.md'))
|
|
198
222
|
.replaceAll('../appendices/', '../technical-appendices/')
|
|
199
223
|
.replaceAll('../briefs/reports/', '../reports/')
|
|
200
224
|
.replaceAll('../briefs/metadata/', '../metadata/');
|
|
201
225
|
writeText(path.join(wikiRoot, 'governance', 'coverage.md'), coverage);
|
|
202
226
|
writeText(path.join(wikiRoot, 'governance', 'authority-index.md'), renderAuthorityIndex(authorityRows));
|
|
227
|
+
writeText(path.join(wikiRoot, 'governance', 'knowledge-adoption.md'), renderKnowledgeAdoptionIndex());
|
|
203
228
|
writeText(path.join(wikiRoot, 'governance', 'index.md'), renderGovernanceIndex(conflictReportIds.size));
|
|
204
229
|
writeText(path.join(wikiRoot, 'governance', 'source-project-boundary.md'), renderSourceProjectBoundary(sourceProjectReferencesFromPackage()));
|
|
205
230
|
writeText(path.join(wikiRoot, 'project-overview.md'), renderProjectOverview(corpus));
|
|
@@ -226,9 +251,13 @@ try {
|
|
|
226
251
|
semantic_plan_fragment_count: semanticPlanState.fragments.length,
|
|
227
252
|
asset_package_schema_version: '3.0',
|
|
228
253
|
asset_scope: packageAssetScope,
|
|
229
|
-
wiki_schema_version: '
|
|
254
|
+
wiki_schema_version: '2.0',
|
|
255
|
+
navigation_taxonomy_version: '2.1',
|
|
230
256
|
generated_at: descriptor.generated_at ?? packageManifest.generated_at ?? null,
|
|
231
|
-
counts: { ...corpus.counts, recall_cards: planModel.cards.length,
|
|
257
|
+
counts: { ...corpus.counts, recall_cards: planModel.cards.length,
|
|
258
|
+
adopted_personal_semantics: adoptedPersonalSemantics.length,
|
|
259
|
+
personal_semantic_integrations: planModel.personalSemanticIntegrations.length,
|
|
260
|
+
blocked_assets: blockedCount, unknown_sql_reports: unknownSqlCount },
|
|
232
261
|
quality_warnings: [...asArray(corpus.warnings),
|
|
233
262
|
...(sourceProjectRefs.filter((row) => Number(row.source_project_id) !== semanticProjectId).length
|
|
234
263
|
? [`${sourceProjectRefs.filter((row) => Number(row.source_project_id) !== semanticProjectId).length} packaged asset reference(s) mention another project: ${sourceProjectRefs.filter((row) => Number(row.source_project_id) !== semanticProjectId).slice(0, 5).map((row) => `${row.resource_type}:${row.resource_key}->${row.source_project_id}`).join(', ')}`] : []),
|
|
@@ -304,6 +333,25 @@ function validateSemanticPlan() {
|
|
|
304
333
|
if (!inDomain) fail(`Recall card ${cardId} references ${type}:${key} outside domain ${domainId}.`);
|
|
305
334
|
if (preferred.includes(ref)) addMulti(preferredByAsset, `${type}:${key}`, cardId);
|
|
306
335
|
}
|
|
336
|
+
const routing = asObject(card.routing);
|
|
337
|
+
if (card.routing != null) {
|
|
338
|
+
for (const field of ['applicable_when', 'answer_grain', 'stop_when', 'fallback_when_unavailable', 'evidence_boundary']) {
|
|
339
|
+
if (!clean(routing[field])) fail(`Recall card ${cardId} routing requires ${field}.`);
|
|
340
|
+
}
|
|
341
|
+
if (!asArray(routing.branches).length) fail(`Recall card ${cardId} routing requires branches.`);
|
|
342
|
+
for (const branch of asArray(routing.branches)) {
|
|
343
|
+
if (!clean(branch.when) || !asArray(branch.asset_refs).length) {
|
|
344
|
+
fail(`Recall card ${cardId} routing branch requires when and asset_refs.`);
|
|
345
|
+
}
|
|
346
|
+
for (const ref of asArray(branch.asset_refs)) {
|
|
347
|
+
validateAssetRef(ref, cardId);
|
|
348
|
+
if (![...preferred, ...asArray(card.fallback_asset_refs)].some((allowed) =>
|
|
349
|
+
clean(allowed.resource_type) === clean(ref.resource_type) && clean(allowed.resource_key) === clean(ref.resource_key))) {
|
|
350
|
+
fail(`Recall card ${cardId} routing branch references an asset outside preferred/fallback refs.`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
307
355
|
for (const ref of asArray(card.excluded_asset_refs)) {
|
|
308
356
|
validateAssetRef(ref, cardId);
|
|
309
357
|
if (!clean(ref.reason)) fail(`Recall card ${cardId} excluded asset ${clean(ref.resource_key)} is missing a reason.`);
|
|
@@ -344,9 +392,11 @@ function validateSemanticPlan() {
|
|
|
344
392
|
if (missingSql.length && !allowAllVisible) {
|
|
345
393
|
fail(`Semantic plan is missing SQL semantics for ${missingSql.length} report(s): ${missingSql.join(', ')}`);
|
|
346
394
|
}
|
|
395
|
+
const personalIntegrations = validatePersonalSemanticIntegrations(domainIds, cardIds);
|
|
347
396
|
|
|
348
397
|
return {
|
|
349
398
|
cards,
|
|
399
|
+
personalSemanticIntegrations: personalIntegrations,
|
|
350
400
|
excludedByAsset,
|
|
351
401
|
preferredByAsset,
|
|
352
402
|
sqlByReportId,
|
|
@@ -355,6 +405,73 @@ function validateSemanticPlan() {
|
|
|
355
405
|
};
|
|
356
406
|
}
|
|
357
407
|
|
|
408
|
+
function validatePersonalSemanticIntegrations(domainIds, cardIds) {
|
|
409
|
+
const integrationIds = new Set();
|
|
410
|
+
const referencedSourceIds = new Set();
|
|
411
|
+
const integrations = [];
|
|
412
|
+
for (const [index, value] of personalSemanticIntegrations.entries()) {
|
|
413
|
+
const row = asObject(value);
|
|
414
|
+
const integrationId = clean(row.integration_id);
|
|
415
|
+
if (!/^[a-z0-9][a-z0-9_-]{1,79}$/.test(integrationId) || integrationIds.has(integrationId)) {
|
|
416
|
+
fail(`Invalid or duplicate personal semantic integration ID: ${integrationId || `<index ${index}>`}.`);
|
|
417
|
+
}
|
|
418
|
+
integrationIds.add(integrationId);
|
|
419
|
+
const contextType = normalizePersonalSemanticContextType(row.context_type);
|
|
420
|
+
const sourceIds = asArray(row.source_ids).map(clean).filter(Boolean);
|
|
421
|
+
if (!sourceIds.length) fail(`Personal semantic integration ${integrationId} requires source_ids.`);
|
|
422
|
+
for (const sourceId of sourceIds) {
|
|
423
|
+
const source = adoptedPersonalBySourceId.get(sourceId);
|
|
424
|
+
if (!source) fail(`Personal semantic integration ${integrationId} references unknown source ${sourceId}.`);
|
|
425
|
+
if (normalizePersonalSemanticContextType(source.context_type) !== contextType) {
|
|
426
|
+
fail(`Personal semantic integration ${integrationId} mixes context_type ${contextType} with source ${sourceId}:${source.context_type}.`);
|
|
427
|
+
}
|
|
428
|
+
referencedSourceIds.add(sourceId);
|
|
429
|
+
}
|
|
430
|
+
const title = clean(row.title);
|
|
431
|
+
const projectUsage = clean(row.project_usage);
|
|
432
|
+
const boundaries = asArray(row.boundaries).map(clean).filter(Boolean);
|
|
433
|
+
const conflictPolicy = clean(row.conflict_policy);
|
|
434
|
+
if (!title || !projectUsage) fail(`Personal semantic integration ${integrationId} requires title and project_usage.`);
|
|
435
|
+
if (!['compatible', 'scoped', 'blocked'].includes(conflictPolicy)) {
|
|
436
|
+
fail(`Personal semantic integration ${integrationId} has invalid conflict_policy.`);
|
|
437
|
+
}
|
|
438
|
+
if (!boundaries.length) fail(`Personal semantic integration ${integrationId} requires boundaries.`);
|
|
439
|
+
const target = validatePersonalSemanticIntegrationTarget(row.integration_target, integrationId, domainIds, cardIds);
|
|
440
|
+
integrations.push({ ...row, integration_id: integrationId, context_type: contextType,
|
|
441
|
+
source_ids: sourceIds, title, project_usage: projectUsage, boundaries, conflict_policy: conflictPolicy,
|
|
442
|
+
integration_target: target });
|
|
443
|
+
}
|
|
444
|
+
const missing = adoptedPersonalSemantics
|
|
445
|
+
.map((source) => clean(source.source_id))
|
|
446
|
+
.filter((sourceId) => sourceId && !referencedSourceIds.has(sourceId));
|
|
447
|
+
if (missing.length) {
|
|
448
|
+
fail(`Semantic plan is missing adopted personal semantic source(s): ${missing.join(', ')}`);
|
|
449
|
+
}
|
|
450
|
+
return integrations;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function validatePersonalSemanticIntegrationTarget(value, integrationId, domainIds, cardIds) {
|
|
454
|
+
const target = asObject(value);
|
|
455
|
+
const type = clean(target.target_type);
|
|
456
|
+
const id = clean(target.target_id);
|
|
457
|
+
if (!['project', 'domain', 'asset', 'recall_card'].includes(type)) {
|
|
458
|
+
fail(`Personal semantic integration ${integrationId} has invalid integration_target.target_type.`);
|
|
459
|
+
}
|
|
460
|
+
if (type === 'project') return { target_type: type, target_id: id || 'project' };
|
|
461
|
+
if (!id) fail(`Personal semantic integration ${integrationId} target ${type} requires target_id.`);
|
|
462
|
+
if (type === 'domain' && !domainIds.has(id)) fail(`Personal semantic integration ${integrationId} references unknown domain ${id}.`);
|
|
463
|
+
if (type === 'recall_card' && !cardIds.has(id)) fail(`Personal semantic integration ${integrationId} references unknown recall card ${id}.`);
|
|
464
|
+
if (type === 'asset') {
|
|
465
|
+
const [assetType, assetKey] = id.includes(':') ? id.split(/:(.*)/s).filter(Boolean) : ['', id];
|
|
466
|
+
const exists = assetType === 'dashboard' ? dashboardById.has(assetKey)
|
|
467
|
+
: assetType === 'report' ? reportById.has(assetKey)
|
|
468
|
+
: assetType === 'metric' ? metricById.has(assetKey)
|
|
469
|
+
: dashboardById.has(assetKey) || reportById.has(assetKey) || metricById.has(assetKey);
|
|
470
|
+
if (!exists) fail(`Personal semantic integration ${integrationId} references unknown asset target ${id}.`);
|
|
471
|
+
}
|
|
472
|
+
return { target_type: type, target_id: id };
|
|
473
|
+
}
|
|
474
|
+
|
|
358
475
|
function validateProjectBusinessModel(value, domainIds) {
|
|
359
476
|
const model = asObject(value);
|
|
360
477
|
const businessPositioning = clean(model.business_positioning);
|
|
@@ -579,7 +696,7 @@ function writeMergedAsset(wikiRoot, directory, asset, authority, extra = '') {
|
|
|
579
696
|
const type = directory === 'dashboards' ? 'project-dashboard' : directory === 'reports' ? 'project-report' : 'project-reusable-metric';
|
|
580
697
|
const title = assetReadableTitle(asset, directory.slice(0, -1));
|
|
581
698
|
const authorityNotice = renderAssetAuthorityNotice(authority);
|
|
582
|
-
const mergedExtra = [authorityNotice, extra.trim()].filter(Boolean).join('\n\n');
|
|
699
|
+
const mergedExtra = [authorityNotice, extra.trim(), renderTargetedKnowledge('asset', `${directory.slice(0, -1)}:${id}`, '../personal-semantics/')].filter(Boolean).join('\n\n');
|
|
583
700
|
writeText(path.join(wikiRoot, directory, assetOutputFileName(directory, id)),
|
|
584
701
|
ensureReadableHeading(mergePage(source, brief, authorityFrontmatter(type, id, title, authority), mergedExtra), title));
|
|
585
702
|
}
|
|
@@ -635,6 +752,12 @@ ${asArray(values).map((ref) => {
|
|
|
635
752
|
const linkPath = assetPath(clean(ref.resource_type), clean(ref.resource_key));
|
|
636
753
|
return `- [${escapeLink(recallAssetLabel(ref))}](${linkPath}):${clean(ref.reason)}`;
|
|
637
754
|
}).join('\n') || '- 无'}`;
|
|
755
|
+
const routing = asObject(card.routing);
|
|
756
|
+
const branches = asArray(routing.branches).map((branch) => {
|
|
757
|
+
const item = asObject(branch);
|
|
758
|
+
const targets = asArray(item.asset_refs).map(recallAssetLabel).join('、') || '回到业务域核对资产';
|
|
759
|
+
return `- 当${clean(item.when)}:使用 ${targets}。${clean(item.reason)}`;
|
|
760
|
+
});
|
|
638
761
|
return `---
|
|
639
762
|
type: project-semantic-recall-card
|
|
640
763
|
card_id: ${yaml(card.card_id)}
|
|
@@ -662,12 +785,15 @@ ${alternateQuestions.map((value) => `- ${value}`).join('\n') || '- 同页面标
|
|
|
662
785
|
|
|
663
786
|
${clean(card.intent)}
|
|
664
787
|
|
|
665
|
-
##
|
|
788
|
+
## 条件路由与停止
|
|
666
789
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
790
|
+
- 适用条件:${clean(routing.applicable_when) || clean(card.intent)}
|
|
791
|
+
- 答案对象与粒度:${clean(routing.answer_grain) || '先按用户问法确认对象、统计粒度与时间范围。'}
|
|
792
|
+
- 必要参数:${asArray(routing.required_parameters).map(clean).filter(Boolean).join('、') || '按首选资产的输入定义核对。'}
|
|
793
|
+
${branches.join('\n') || `- 问法和资产定义匹配时使用首选资产;不匹配时先回到业务域确认对象与口径,再考虑备选资产。`}
|
|
794
|
+
- 停止条件:${clean(routing.stop_when) || '取得对象、粒度、范围、时间和权威状态均匹配的最小证据后停止扩搜。'}
|
|
795
|
+
- 无匹配或不可用时:${clean(routing.fallback_when_unavailable) || '回到业务域按对象、粒度、过滤和时间筛选域内资产;仍不匹配则说明缺口。'}
|
|
796
|
+
- 执行边界:${clean(routing.evidence_boundary) || '排除资产不能作为当前答案;当前数值、客户名单、趋势或明细必须实时执行。'}
|
|
671
797
|
|
|
672
798
|
${refs(card.preferred_asset_refs, '首选资产')}
|
|
673
799
|
|
|
@@ -679,6 +805,7 @@ ${refs(card.excluded_asset_refs, '排除资产')}
|
|
|
679
805
|
|
|
680
806
|
- 是否需要执行实时数据:${Boolean(card.requires_live_execution)}
|
|
681
807
|
- 原因:${clean(card.live_execution_reason) || '未说明'}
|
|
808
|
+
${renderTargetedKnowledge('recall_card', clean(card.card_id), '../personal-semantics/')}
|
|
682
809
|
`;
|
|
683
810
|
}
|
|
684
811
|
|
|
@@ -695,11 +822,140 @@ function recallAssetLabel(ref) {
|
|
|
695
822
|
}
|
|
696
823
|
|
|
697
824
|
function renderRecallCardIndex(cards) {
|
|
698
|
-
return `# 场景召回卡\n\n
|
|
825
|
+
return `# 场景召回卡\n\n先按问法、对象、粒度和参数选择匹配的卡;卡内按条件分支找到最小证据并在满足停止条件后停止。无匹配卡时,回到[业务领域](../domains/index.md),按对象、粒度、过滤和时间筛选域内资产;仍无可用资产时说明具体缺口。\n\n${cards.map((card) => `- [${escapeLink(card.intent || card.card_id)}](${fileName('recall-card', card.card_id)})(${clean(card.domain_title)})`).join('\n')}\n`;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function renderReportIndex() {
|
|
829
|
+
const assigned = new Set();
|
|
830
|
+
const sections = domains.map((domain) => {
|
|
831
|
+
const dashboardIds = new Set(asArray(domain.dashboard_ids).map(clean));
|
|
832
|
+
const matching = reports.filter((report) => asArray(report.dashboard_refs)
|
|
833
|
+
.some((ref) => dashboardIds.has(clean(ref.dashboard_id))))
|
|
834
|
+
.sort((a, b) => clean(a.resource_key).localeCompare(clean(b.resource_key), 'en'));
|
|
835
|
+
for (const report of matching) assigned.add(clean(report.resource_key));
|
|
836
|
+
const questions = asArray(domain.primary_questions).map(clean).filter(Boolean);
|
|
837
|
+
const cards = asArray(domain.recall_cards)
|
|
838
|
+
.map((card) => `- 问题入口:[${escapeLink(clean(card.questions?.[0]) || clean(card.intent))}](../recall-cards/${fileName('recall-card', card.card_id)})`);
|
|
839
|
+
return `## ${clean(domain.title)}\n\n- 业务问题:${questions.join(';') || clean(domain.summary)}\n- [领域判断](../domains/${fileName('domain', domain.domain_id)})\n${cards.join('\n')}\n${matching.map((report) => `- [${escapeLink(assetReadableTitle(report, 'report'))}](${reportFileNames.get(clean(report.resource_key))})(report:${clean(report.resource_key)})`).join('\n') || '- 本快照无该域报表,按领域页核对其他资产。'}\n`;
|
|
840
|
+
});
|
|
841
|
+
const unassigned = reports.filter((report) => !assigned.has(clean(report.resource_key)))
|
|
842
|
+
.sort((a, b) => clean(a.resource_key).localeCompare(clean(b.resource_key), 'en'));
|
|
843
|
+
return `# 报表\n\n先按业务问题选择领域或场景,再核对报表的对象、粒度、过滤和时间。点名报表时可直接进入报表页;未归属报表不自动视为业务入口。\n\n${sections.join('\n')}\n## 其他与未归属报表\n\n${unassigned.map((report) => `- [${escapeLink(assetReadableTitle(report, 'report'))}](${reportFileNames.get(clean(report.resource_key))})(report:${clean(report.resource_key)})`).join('\n') || '- 无'}\n`;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function renderPersonalSemanticIntegration(integration) {
|
|
847
|
+
const sourceRows = integration.source_ids.map((sourceId) => adoptedPersonalBySourceId.get(sourceId)).filter(Boolean);
|
|
848
|
+
const provenanceRows = sourceRows.map((source) => {
|
|
849
|
+
const payload = asObject(source.payload);
|
|
850
|
+
return `| \`${clean(source.source_id)}\` | ${escapeTable(personalSemanticOwnerName(payload))} | ${escapeTable(formatPersonalSemanticTime(payload.updated_at ?? source.updated_at))} | ${escapeTable(payload.heat_count)} |`;
|
|
851
|
+
}).join('\n');
|
|
852
|
+
const sourceSummaries = sourceRows.map((source) => {
|
|
853
|
+
const payload = asObject(source.payload);
|
|
854
|
+
return `### ${clean(payload.title) || clean(source.source_id)}\n\n- Source ID: \`${clean(source.source_id)}\`\n- 来源人:${personalSemanticOwnerName(payload)}\n- 更新时间:${formatPersonalSemanticTime(payload.updated_at ?? source.updated_at)}\n- 热度:${clean(payload.heat_count) || '0'}\n- 摘要:${clean(payload.summary) || 'unknown'}\n- 内容:${clean(payload.content) || 'unknown'}\n- 关键词:${asArray(payload.keywords).map(clean).filter(Boolean).join('、') || '无'}\n- 资源引用:${renderPersonalSemanticResourceRefs(payload.resource_refs)}\n`;
|
|
855
|
+
}).join('\n');
|
|
856
|
+
return `---\ntype: project-semantic-personal-integration\nsemantic_project_id: ${semanticProjectId}\nintegration_id: ${yaml(integration.integration_id)}\ncontext_type: ${yaml(integration.context_type)}\nsource_snapshot_hash: ${yaml(snapshotHash)}\ntarget_type: ${yaml(integration.integration_target.target_type)}\ntarget_id: ${yaml(integration.integration_target.target_id)}\nconflict_policy: ${yaml(integration.conflict_policy)}\n---\n\n# ${clean(integration.title)}\n\n## Agent 使用摘要\n\n- 类型:${personalSemanticContextLabel(integration.context_type)}\n- 项目用法:${clean(integration.project_usage)}\n- 作用目标:${renderPersonalSemanticTarget(integration.integration_target)}\n- 冲突策略:${clean(integration.conflict_policy)}\n- 边界:${joinChineseClauses(integration.boundaries)}\n\n## 来源\n\n| Source ID | 来源人 | 更新时间 | 热度 |\n| --- | --- | --- | ---: |\n${provenanceRows || '| - | - | - | - |'}\n\n## 原始个人语义摘要\n\n${sourceSummaries || '无'}\n`;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function personalSemanticOwnerName(payload) {
|
|
860
|
+
return clean(payload.owner_name) || clean(payload.owner_display_name) || '未知用户';
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function renderPersonalSemanticIndex(integrations) {
|
|
864
|
+
const rows = integrations
|
|
865
|
+
.slice()
|
|
866
|
+
.sort((left, right) => `${left.context_type}:${left.integration_id}`.localeCompare(`${right.context_type}:${right.integration_id}`, 'en'));
|
|
867
|
+
return `# 知识采纳记录\n\n已采纳的补充知识按目标写入项目、业务领域、场景或资产页;这里保留来源和适用边界以便追溯。\n\n- [背景](background/index.md)\n- [偏好](preference/index.md)\n- [经验](experience/index.md)\n- [资产上下文](asset-context/index.md)\n\n## 采纳项\n\n${rows.map((row) => `- [${escapeLink(row.title)}](${personalSemanticContextPath(row.context_type)}/${fileName('personal-semantic', row.integration_id)}):${personalSemanticContextLabel(row.context_type)},${clean(row.project_usage)}`).join('\n') || '- 无已采纳补充知识。'}\n`;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
function renderTargetedKnowledge(type, id, relativeRoot) {
|
|
871
|
+
const rows = planModel.personalSemanticIntegrations.filter((integration) => {
|
|
872
|
+
const target = integration.integration_target;
|
|
873
|
+
if (target.target_type !== type) return false;
|
|
874
|
+
if (type !== 'asset') return target.target_id === id;
|
|
875
|
+
return target.target_id === id || target.target_id === id.split(':')[1];
|
|
876
|
+
});
|
|
877
|
+
if (!rows.length) return '';
|
|
878
|
+
return `\n## 项目补充知识\n\n${rows.map((row) => `- [${escapeLink(row.title)}](${relativeRoot}${personalSemanticContextPath(row.context_type)}/${fileName('personal-semantic', row.integration_id)}):${clean(row.project_usage)};适用边界:${joinChineseClauses(row.boundaries)}`).join('\n')}\n`;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function renderKnowledgeAdoptionIndex() {
|
|
882
|
+
return `# 知识采纳记录\n\n[查看已采纳补充知识及来源](../personal-semantics/index.md)。内容按适用目标进入项目、领域、场景和资产页;个人偏好只在声明的范围内生效。\n`;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
function renderCommonIndex() {
|
|
886
|
+
const model = planModel.projectBusinessModel;
|
|
887
|
+
const objects = asArray(model.business_objects).map((row) => `- **${clean(row.name)}**:${clean(row.meaning)}`).join('\n');
|
|
888
|
+
const relationships = asArray(model.object_relationships).map((row) => `- ${clean(row.from_object)} → ${clean(row.to_object)}:${clean(row.relationship)}`).join('\n');
|
|
889
|
+
const supplements = planModel.personalSemanticIntegrations.filter((row) => row.integration_target.target_type === 'project')
|
|
890
|
+
.map((row) => `- [${escapeLink(row.title)}](../personal-semantics/${personalSemanticContextPath(row.context_type)}/${fileName('personal-semantic', row.integration_id)}):${clean(row.project_usage)};适用边界:${joinChineseClauses(row.boundaries)}`).join('\n');
|
|
891
|
+
return `# 项目共识\n\n这里收录跨业务领域适用的项目对象、关系与已采纳补充知识。领域特有的判断方法保留在对应领域页。\n\n## 共同业务对象\n\n${objects || '- 无。'}\n\n## 对象关系\n\n${relationships || '- 无。'}\n\n## 跨领域补充知识\n\n${supplements || '- 暂无。'}\n\n[查看完整项目判断链路](../project-overview.md#业务判断链路)。\n`;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
function renderAssetIndex() {
|
|
895
|
+
return `# 事件与资产目录\n\n事件公共分组帮助按产品模块找到事件;分组名称本身不定义业务领域或认证状态。业务含义以领域判断和事件定义为准。\n\n- [事件地图](../event-map/index.md)\n- [看板](../dashboards/index.md)\n- [报表](../reports/index.md)\n- [可复用指标](../metrics/index.md)\n- [分析元数据](../metadata/index.md)\n`;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
function writeEventMap(wikiRoot, buildIrRoot) {
|
|
899
|
+
const eventPages = new Map();
|
|
900
|
+
const eventsDir = path.join(buildIrRoot, 'metadata', 'events');
|
|
901
|
+
if (fs.existsSync(eventsDir)) for (const name of fs.readdirSync(eventsDir).filter((item) => item.endsWith('.md'))) {
|
|
902
|
+
const content = readText(path.join(eventsDir, name));
|
|
903
|
+
const key = frontmatterValue(content, 'resource_key');
|
|
904
|
+
if (key) eventPages.set(key, name);
|
|
905
|
+
}
|
|
906
|
+
const groups = eventGroups.filter((group) => clean(group.catalog_scope) === 'project_public');
|
|
907
|
+
const seen = new Set();
|
|
908
|
+
const links = [];
|
|
909
|
+
for (const group of groups) {
|
|
910
|
+
const name = clean(group.group_name);
|
|
911
|
+
if (!name || seen.has(name)) fail(`Duplicate or empty public event group: ${name || '<empty>'}.`);
|
|
912
|
+
seen.add(name);
|
|
913
|
+
const members = asArray(group.events).filter((event) => eventPages.has(clean(event.event_name)));
|
|
914
|
+
if (!members.length) continue;
|
|
915
|
+
const file = fileName('event-group', `group-${name}-${sha256(name).slice(0, 8)}`);
|
|
916
|
+
links.push(`- [${escapeLink(name)}](${file})(${members.length} 个已导出事件)`);
|
|
917
|
+
writeText(path.join(wikiRoot, 'event-map', file), `# ${name}\n\n来源:项目公共事件目录。此分组仅用于查找事件,不自动定义业务领域或事件认证状态。\n\n${members.map((event) => `- [${escapeLink(clean(event.event_title) || clean(event.event_name))}(\`${clean(event.event_name)}\`)](../metadata/events/${eventPages.get(clean(event.event_name))})`).join('\n')}\n`);
|
|
918
|
+
}
|
|
919
|
+
writeText(path.join(wikiRoot, 'event-map', 'index.md'), `# 事件地图\n\n按项目公共事件分组查找已纳入资产包的事件。未纳入当前资产范围的事件不会在这里出现;事件分组不等于业务领域。\n\n${links.join('\n') || '- 当前资产范围内没有可展示的公共事件分组。'}\n\n[按元数据类型查找事件](../metadata/index.md)。\n`);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function renderPersonalSemanticTypeIndex(type, integrations) {
|
|
923
|
+
const normalized = normalizePersonalSemanticContextType(type);
|
|
924
|
+
const rows = integrations.filter((row) => normalizePersonalSemanticContextType(row.context_type) === normalized)
|
|
925
|
+
.sort((left, right) => left.integration_id.localeCompare(right.integration_id, 'en'));
|
|
926
|
+
return `# ${personalSemanticContextLabel(normalized)}\n\n${personalSemanticContextUsage(normalized)}\n\n${rows.map((row) => `- [${escapeLink(row.title)}](${fileName('personal-semantic', row.integration_id)}):${clean(row.project_usage)}`).join('\n') || '- 暂无。'}\n`;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function renderPersonalSemanticTarget(target) {
|
|
930
|
+
const type = clean(target.target_type);
|
|
931
|
+
const id = clean(target.target_id);
|
|
932
|
+
if (type === 'domain') return `业务域 \`${id}\``;
|
|
933
|
+
if (type === 'recall_card') return `召回卡 \`${id}\``;
|
|
934
|
+
if (type === 'asset') return `资产 \`${id}\``;
|
|
935
|
+
return '项目整体';
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
function renderPersonalSemanticResourceRefs(value) {
|
|
939
|
+
const refs = asArray(value).map(asObject).map((ref) => {
|
|
940
|
+
const type = clean(ref.resource_type);
|
|
941
|
+
const key = clean(ref.resource_key);
|
|
942
|
+
return type && key ? `${type}:${key}` : clean(ref);
|
|
943
|
+
}).filter(Boolean);
|
|
944
|
+
return refs.join('、') || '无';
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
function formatPersonalSemanticTime(value) {
|
|
948
|
+
const text = clean(value);
|
|
949
|
+
if (!text) return 'unknown';
|
|
950
|
+
if (/^\d{12,}$/.test(text)) {
|
|
951
|
+
const date = new Date(Number(text));
|
|
952
|
+
if (!Number.isNaN(date.getTime())) return date.toISOString().replace('T', ' ').replace('.000Z', ' UTC');
|
|
953
|
+
}
|
|
954
|
+
return text;
|
|
699
955
|
}
|
|
700
956
|
|
|
701
957
|
function renderAuthorityIndex(rows) {
|
|
702
|
-
return `# 资产权威状态\n\n## Agent 判定规则\n\n- \`runtime_policy=allow\`:可以作为主要答案依据,但当前数值仍需实时执行。\n- \`runtime_policy=warn\`:只能作为依赖或辅助线索,回答时需要说明它不是独立召回入口。\n- \`runtime_policy=block\`:不能直接回答,必须回到 canonical 资产、业务域或等待资产作者确认。\n- \`authority_role=dependency_only
|
|
958
|
+
return `# 资产权威状态\n\n## Agent 判定规则\n\n- \`runtime_policy=allow\`:可以作为主要答案依据,但当前数值仍需实时执行。\n- \`runtime_policy=warn\`:只能作为依赖或辅助线索,回答时需要说明它不是独立召回入口。\n- \`runtime_policy=block\`:不能直接回答,必须回到 canonical 资产、业务域或等待资产作者确认。\n- \`authority_role=dependency_only\`:定义、依赖关系或冲突解释可以引用已知元数据;不能单独据此断言业务状态或当前数值。平台禁止直接检索时回到授权引用资产。\n- \`definition_state=conflict\` 或 \`unknown\`:不要断言精确口径,只能描述已知证据和待确认点。\n\n| 类型 | 资产 | Authority role | Certification | Definition | Runtime | Standalone recall | Canonical |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n${rows.sort((a, b) => `${a.resource_type}:${a.resource_key}`.localeCompare(`${b.resource_type}:${b.resource_key}`, 'en')).map((row) => `| ${row.resource_type} | \`${row.resource_key}\` ${escapeTable(row.title)} | ${row.authority_role} | ${row.certification_state} | ${row.definition_state} | ${row.runtime_policy} | ${row.standalone_recall} | ${row.canonical_asset_id ?? '-'} |`).join('\n')}\n`;
|
|
703
959
|
}
|
|
704
960
|
|
|
705
961
|
function renderSourceProjectBoundary(rows) {
|
|
@@ -721,20 +977,20 @@ ${external.map((row) => `| ${row.resource_type}:${row.resource_key} ${escapeTabl
|
|
|
721
977
|
}
|
|
722
978
|
|
|
723
979
|
function renderGovernanceIndex(conflicts) {
|
|
724
|
-
return `#
|
|
980
|
+
return `# 治理与来源\n\n- [知识采纳记录](knowledge-adoption.md)\n- [资产权威状态](authority-index.md)\n- [覆盖、物理来源与未归属资产](coverage.md)\n- [项目来源边界](source-project-boundary.md)\n\n## Agent 使用方式\n\n- 回答前先看资产页 frontmatter 的 \`runtime_policy\`、\`definition_state\` 和 \`authority_role\`。\n- \`runtime_policy=block\` 的资产不能直接回答;如果存在 canonical 资产,优先跳转到 canonical。\n- \`dependency_only\` 元数据可用于有证据的定义、依赖和冲突解释;不能据此单独回答业务状态或当前数值。\n- 语义冲突表示多个资产表达同一业务含义但口径不同,不能只凭名称选择资产;优先使用业务域、召回卡或用户确认。\n- 项目来源边界用于识别资产包里引用了其他项目 ID 的字段;跨项目引用只能作为来源线索,不代表当前项目事实。\n\n当前检测到 ${conflicts} 张语义冲突报表。\n`;
|
|
725
981
|
}
|
|
726
982
|
|
|
727
983
|
function renderWikiIndex(corpus) {
|
|
728
|
-
return `---\ntype: project-semantic-knowledge-wiki-index\nsemantic_project_id: ${semanticProjectId}\nproject_name: ${yaml(projectName)}\nsource_snapshot_hash: ${yaml(snapshotHash)}\n---\n\n# ${projectName} 项目语义知识库 Wiki\n\n##
|
|
984
|
+
return `---\ntype: project-semantic-knowledge-wiki-index\nsemantic_project_id: ${semanticProjectId}\nproject_name: ${yaml(projectName)}\nsource_snapshot_hash: ${yaml(snapshotHash)}\nnavigation_taxonomy_version: "2.1"\n---\n\n# ${projectName} 项目语义知识库 Wiki\n\n## 问题意图路由\n\n- 业务判断或当前数值:先选[业务领域](domains/index.md)及其[场景召回卡](recall-cards/index.md),按对象、粒度、参数选择分支并实时执行。\n- 点名资产、字段定义或依赖关系:从[事件与资产目录](asset-index/index.md)定位资产,再核对[治理与来源](governance/index.md);依赖元数据可解释定义与关系,但不能单独证明业务状态。\n- 产品机制或共同背景:先读[项目共识](common/index.md),再进入相关业务域。\n- 无匹配场景卡:进入相关业务域,按对象、粒度、过滤和时间筛选域内资产;仍无合适资产就说明缺口,不编造答案。\n- 已取得对象、粒度、时间、范围和权威性匹配的最小证据后停止扩搜;需要当前值时按权限执行。\n\n## 知识导航\n\n1. [项目总览](project-overview.md):项目定位、对象关系和判断链路。\n2. [项目共识](common/index.md):跨领域适用的知识。\n3. [业务领域](domains/index.md):按业务问题进入判断路径和证据。\n4. [事件与资产目录](asset-index/index.md):按事件公共分组或资产类型查找。\n5. [治理与来源](governance/index.md):采纳、权威状态和边界。\n\n技术、演示、副本和定向诊断资产只在[技术附录](technical-appendices/index.md)中追溯。物理空间在[source containers](source-containers/index.md)中保留,不作为业务域。\n\n${countSummary(corpus)}\n`;
|
|
729
985
|
}
|
|
730
986
|
|
|
731
987
|
function renderSnapshotIndex(corpus) {
|
|
732
988
|
const title = String(projectName).replace(/\r?\n/g, ' ').replace(/^#+\s*/, '');
|
|
733
|
-
return `# ${title} 项目语义知识库 Wiki\n\n
|
|
989
|
+
return `# ${title} 项目语义知识库 Wiki\n\n## 问题意图路由\n\n- 业务判断或当前数值:先选[业务领域](wiki/domains/index.md)和匹配的[场景召回卡](wiki/recall-cards/index.md),按对象、粒度和参数选择分支。\n- 点名资产、字段定义或依赖关系:从[事件与资产目录](wiki/asset-index/index.md)定位,再核对[治理与来源](wiki/governance/index.md)。\n- 产品机制或共同背景:先读[项目共识](wiki/common/index.md)。\n- 无匹配场景卡:回到相关业务域,按对象、粒度、过滤和时间筛选;仍无合适资产则说明缺口。\n- 证据已经匹配对象、粒度、范围、时间和权威状态时停止扩搜;当前数值需要授权实时执行。\n\n## 知识导航\n\n1. [项目总览](wiki/project-overview.md)\n2. [项目共识](wiki/common/index.md)\n3. [业务领域](wiki/domains/index.md)\n4. [事件与资产目录](wiki/asset-index/index.md)\n5. [治理与来源](wiki/governance/index.md)\n\n${countSummary(corpus)}\n`;
|
|
734
990
|
}
|
|
735
991
|
|
|
736
992
|
function renderProjectOverview(corpus) {
|
|
737
|
-
return `# ${projectName}
|
|
993
|
+
return `# ${projectName} 项目总览\n\n${renderProjectBusinessModel(planModel.projectBusinessModel)}${renderTargetedKnowledge('project', 'project', 'personal-semantics/')}\n\n## 资产与治理范围\n\n- Semantic project ID: ${semanticProjectId}\n- Snapshot hash: \`${snapshotHash}\`\n- Asset scope: ${packageAssetScope}\n- Business domains: ${corpus.counts.business_domains}\n- Dashboards: ${corpus.counts.dashboards}\n- Reports: ${corpus.counts.reports}\n- Reusable metrics: ${corpus.counts.reusable_metrics}\n- Metadata: ${corpus.counts.analysis_metadata}\n\nCommon 资产包是权威来源。本 Wiki 将业务判断模型、用途总结和精确证据合并为单一页面,不再发布第二套 raw/briefs 语料。\n`;
|
|
738
994
|
}
|
|
739
995
|
|
|
740
996
|
function renderProjectBusinessModel(model) {
|
|
@@ -774,7 +1030,7 @@ function renderLog(corpus) {
|
|
|
774
1030
|
}
|
|
775
1031
|
|
|
776
1032
|
function countSummary(corpus) {
|
|
777
|
-
return `## 数量\n\n|
|
|
1033
|
+
return `## 数量\n\n| 内容 | 数量 |\n| --- | ---: |\n| 业务领域 | ${corpus.counts.business_domains} |\n| 公共事件分组 | ${eventGroups.length} |\n| 看板 | ${corpus.counts.dashboards} |\n| 报表 | ${corpus.counts.reports} |\n| 可复用指标 | ${corpus.counts.reusable_metrics} |\n| 分析元数据 | ${corpus.counts.analysis_metadata} |\n| 场景召回卡 | ${planModel.cards.length} |\n| 已采纳补充知识 | ${planModel.personalSemanticIntegrations.length} |`;
|
|
778
1034
|
}
|
|
779
1035
|
|
|
780
1036
|
function authorityFrontmatter(type, resourceKey, title, authority) {
|
|
@@ -801,6 +1057,35 @@ function assetPath(type, key) {
|
|
|
801
1057
|
fail(`Unsupported recall-card asset type ${type}.`);
|
|
802
1058
|
}
|
|
803
1059
|
|
|
1060
|
+
function normalizePersonalSemanticContextType(value) {
|
|
1061
|
+
const type = clean(value).toLowerCase().replace('-', '_');
|
|
1062
|
+
if (!['background', 'preference', 'experience', 'asset_context'].includes(type)) {
|
|
1063
|
+
fail(`Invalid adopted personal semantic context_type: ${clean(value) || '<empty>'}.`);
|
|
1064
|
+
}
|
|
1065
|
+
return type;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
function personalSemanticContextPath(value) {
|
|
1069
|
+
const type = normalizePersonalSemanticContextType(value);
|
|
1070
|
+
return type === 'asset_context' ? 'asset-context' : type;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
function personalSemanticContextLabel(value) {
|
|
1074
|
+
const type = normalizePersonalSemanticContextType(value);
|
|
1075
|
+
if (type === 'background') return '项目背景';
|
|
1076
|
+
if (type === 'preference') return '偏好';
|
|
1077
|
+
if (type === 'experience') return '经验';
|
|
1078
|
+
return '资产上下文';
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
function personalSemanticContextUsage(value) {
|
|
1082
|
+
const type = normalizePersonalSemanticContextType(value);
|
|
1083
|
+
if (type === 'background') return '用于补充项目、业务域和对象关系的背景信息。';
|
|
1084
|
+
if (type === 'preference') return '用于补充项目内的回答偏好、入口选择和路由方式。';
|
|
1085
|
+
if (type === 'experience') return '用于补充已经验证过的分析路径、风险提示和经验规则。';
|
|
1086
|
+
return '用于补充具体资产的使用语境;引用资产不存在时不能作为当前资产事实。';
|
|
1087
|
+
}
|
|
1088
|
+
|
|
804
1089
|
function assetOutputFileName(directory, key) {
|
|
805
1090
|
if (directory === 'dashboards') return dashboardFileNames.get(key) ?? fileName('dashboard', key);
|
|
806
1091
|
if (directory === 'reports') return reportFileNames.get(key) ?? fileName('report', key);
|
|
@@ -947,10 +1232,8 @@ function assertSnapshotEntryPoint(root) {
|
|
|
947
1232
|
const content = readText(path.join(root, 'index.md'));
|
|
948
1233
|
const requiredLinks = [
|
|
949
1234
|
'wiki/project-overview.md',
|
|
950
|
-
'wiki/
|
|
951
|
-
'wiki/
|
|
952
|
-
'wiki/governance/index.md', 'wiki/technical-appendices/index.md',
|
|
953
|
-
'wiki/source-containers/index.md',
|
|
1235
|
+
'wiki/common/index.md', 'wiki/domains/index.md', 'wiki/asset-index/index.md',
|
|
1236
|
+
'wiki/governance/index.md',
|
|
954
1237
|
];
|
|
955
1238
|
const missing = requiredLinks.filter((target) => !content.includes(`(${target})`));
|
|
956
1239
|
if (missing.length) fail(`Snapshot root index is missing required navigation: ${missing.join(', ')}.`);
|
|
@@ -1118,6 +1401,7 @@ function writeFlatUploadSources(sourceRoot, targetRoot, replace) {
|
|
|
1118
1401
|
writeJson(path.join(staging, 'kb-upload-manifest.json'), {
|
|
1119
1402
|
schema_version: '1.0',
|
|
1120
1403
|
manifest_kind: 'ae_project_semantic_kb_upload_sources',
|
|
1404
|
+
navigation_taxonomy_version: '2.1',
|
|
1121
1405
|
namespace: uploadSourceNamespace,
|
|
1122
1406
|
semantic_project_id: semanticProjectId,
|
|
1123
1407
|
project_name: projectName,
|
|
@@ -1162,6 +1446,17 @@ function uploadSourceIdentity(rel, content = '') {
|
|
|
1162
1446
|
if (section === 'metrics') return namedUploadSource('metric', stem, frontmatterValue(content, 'resource_key'));
|
|
1163
1447
|
if (section === 'domains') return namedUploadSource('domain', stem);
|
|
1164
1448
|
if (section === 'recall-cards') return namedUploadSource('recall-card', stem);
|
|
1449
|
+
if (section === 'personal-semantics') {
|
|
1450
|
+
if (rest.endsWith('/index') || rest === 'index') {
|
|
1451
|
+
return {
|
|
1452
|
+
source_kind: 'personal-semantic',
|
|
1453
|
+
asset_type: null,
|
|
1454
|
+
asset_key: null,
|
|
1455
|
+
file_stem: `personal-semantic-${stem}`,
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
return namedUploadSource('personal-semantic', stem, frontmatterValue(content, 'integration_id'));
|
|
1459
|
+
}
|
|
1165
1460
|
if (section === 'technical-appendices') return namedUploadSource('appendix', stem);
|
|
1166
1461
|
if (section === 'source-containers') return namedUploadSource('source-container', stem);
|
|
1167
1462
|
if (section === 'governance') return namedUploadSource('governance', stem);
|
|
@@ -1187,6 +1482,9 @@ function semanticPlanFragmentRefsForSource(identity, rel) {
|
|
|
1187
1482
|
if (sourceKind === 'domain' && assetKey) refs.add(`domain:${assetKey}`);
|
|
1188
1483
|
if (sourceKind === 'appendix' && assetKey) refs.add(`appendix:${assetKey}`);
|
|
1189
1484
|
if (sourceKind === 'recall-card' && assetKey) refs.add(`recall-card:${assetKey}`);
|
|
1485
|
+
if (sourceKind === 'personal-semantic' && assetKey) {
|
|
1486
|
+
refs.add(`personal-semantic-integration:${assetKey}`);
|
|
1487
|
+
}
|
|
1190
1488
|
if (assetType === 'dashboard' && assetKey) {
|
|
1191
1489
|
const domain = domainByDashboardId.get(assetKey);
|
|
1192
1490
|
const appendix = appendixByDashboardId.get(assetKey);
|
|
@@ -1210,6 +1508,9 @@ function semanticPlanFragmentRefsForSource(identity, rel) {
|
|
|
1210
1508
|
if (sourceKind === 'index' && rel === 'wiki/domains/index.md') {
|
|
1211
1509
|
for (const domain of domains) refs.add(`domain:${clean(domain.domain_id)}`);
|
|
1212
1510
|
}
|
|
1511
|
+
if (sourceKind === 'personal-semantic' && /\/index\.md$/.test(rel)) {
|
|
1512
|
+
for (const integration of planModel.personalSemanticIntegrations) refs.add(`personal-semantic-integration:${clean(integration.integration_id)}`);
|
|
1513
|
+
}
|
|
1213
1514
|
return [...refs].filter(Boolean).sort();
|
|
1214
1515
|
}
|
|
1215
1516
|
|
|
@@ -1242,6 +1543,14 @@ function buildSemanticPlanState() {
|
|
|
1242
1543
|
for (const [reportId, summary] of [...planModel.sqlByReportId.entries()].sort(([left], [right]) => left.localeCompare(right, 'en'))) {
|
|
1243
1544
|
add(`report:${reportId}:sql_semantics`, 'sql-report', summary, { report_id: reportId });
|
|
1244
1545
|
}
|
|
1546
|
+
for (const integration of planModel.personalSemanticIntegrations) {
|
|
1547
|
+
const id = clean(integration.integration_id);
|
|
1548
|
+
add(`personal-semantic-integration:${id}`, 'personal-semantic-integration', integration, {
|
|
1549
|
+
integration_id: id,
|
|
1550
|
+
context_type: clean(integration.context_type),
|
|
1551
|
+
source_ids: integration.source_ids,
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1245
1554
|
fragments.sort((left, right) => left.id.localeCompare(right.id, 'en'));
|
|
1246
1555
|
return {
|
|
1247
1556
|
schema_version: '1.0',
|
|
@@ -1355,6 +1664,12 @@ function renderNumberedSteps(value, indent = '') {
|
|
|
1355
1664
|
function writeText(file, value) { fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, value.endsWith('\n') ? value : `${value}\n`, 'utf8'); }
|
|
1356
1665
|
function writeJson(file, value) { writeText(file, JSON.stringify(value, null, 2)); }
|
|
1357
1666
|
function readIndex(name) { return readText(path.join(packageRoot, 'indexes', `${name}.jsonl`)).split(/\r?\n/).filter(Boolean).map(JSON.parse).filter((row) => row.record_type !== 'header'); }
|
|
1667
|
+
function readOptionalIndex(name) { return fs.existsSync(path.join(packageRoot, 'indexes', `${name}.jsonl`)) ? readIndex(name) : []; }
|
|
1668
|
+
function readPackageJsonl(rel) {
|
|
1669
|
+
const file = path.join(packageRoot, rel);
|
|
1670
|
+
if (!fs.existsSync(file)) return [];
|
|
1671
|
+
return readText(file).split(/\r?\n/).filter(Boolean).map(JSON.parse).filter((row) => row.record_type !== 'header');
|
|
1672
|
+
}
|
|
1358
1673
|
function listFiles(root) { return fs.readdirSync(root, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? listFiles(path.join(root, entry.name)) : [path.join(root, entry.name)]); }
|
|
1359
1674
|
function parseArgs(values) { const out = {}; for (let i = 0; i < values.length; i += 1) { const value = values[i]; if (!value.startsWith('--')) fail(`Unexpected argument: ${value}`); const key = value.slice(2); if (['force', 'keep-build-ir', 'allow-all-visible', 'allow-semantic-plan-snapshot-drift'].includes(key)) out[key] = true; else out[key] = values[++i]; } return out; }
|
|
1360
1675
|
function required(values, key) { const value = clean(values[key]); if (!value) fail(`--${key} is required.`); return value; }
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
3
4
|
import { spawnSync } from 'node:child_process';
|
|
4
5
|
import { pathToFileURL } from 'node:url';
|
|
5
6
|
|
|
6
|
-
const scoped = new Set(['+new', '+add', '+list-sources', '+schema', '+compile', '+status', '+import']);
|
|
7
|
+
const scoped = new Set(['+new', '+add', '+list-sources', '+schema', '+compile', '+status', '+import', '+schema-download', '+schema-import', '+schema-import-list']);
|
|
7
8
|
const requestScoped = new Set(['+import-status']);
|
|
8
9
|
const directory = new Set(['+source-ls', '+source-read', '+source-put', '+source-rm']);
|
|
9
10
|
const value = (args, key) => args[args.indexOf(key) + 1];
|
|
10
11
|
|
|
12
|
+
export function invokeCompanyKbCli(flags, { spawn = spawnSync, localCli = path.resolve(import.meta.dirname, '../../../../bin/ae-cli.js') } = {}) {
|
|
13
|
+
// Packaged/project scripts use their matching CLI; standalone installed Skills retain PATH lookup.
|
|
14
|
+
const bundled = fs.existsSync(localCli);
|
|
15
|
+
const child = spawn(bundled ? process.execPath : 'ae-cli', bundled ? [localCli, ...flags] : flags,
|
|
16
|
+
{ encoding: 'utf8', stdio: ['inherit', 'pipe', 'pipe'] });
|
|
17
|
+
if (child.stderr) process.stderr.write(child.stderr);
|
|
18
|
+
if (child.error) throw child.error;
|
|
19
|
+
if (child.status === 0) return JSON.parse(child.stdout);
|
|
20
|
+
// CLI failures are JSON on stderr, possibly surrounded by compatibility/progress messages.
|
|
21
|
+
const start = child.stderr.indexOf('{\n "ok": false,');
|
|
22
|
+
const end = start < 0 ? -1 : child.stderr.indexOf('\n}', start);
|
|
23
|
+
if (end >= 0) return JSON.parse(child.stderr.slice(start, end + 2));
|
|
24
|
+
throw new Error(child.stderr || child.stdout || 'CLI process failed.');
|
|
25
|
+
}
|
|
26
|
+
|
|
11
27
|
// Project semantic KB operations must never fall back to a personal KB.
|
|
12
28
|
export async function runCompanyKb(command, args, invoke) {
|
|
13
29
|
if (args.some((arg) => arg === '--custom-instructions' || arg.startsWith('--custom-instructions='))) {
|
|
@@ -24,7 +40,9 @@ export async function runCompanyKb(command, args, invoke) {
|
|
|
24
40
|
const call = async (cmd, flags) => {
|
|
25
41
|
const result = await invoke(['kb', cmd, ...flags]);
|
|
26
42
|
if (!result || result.ok !== true) {
|
|
27
|
-
|
|
43
|
+
const error = new Error(`Company KB operation failed; stop without personal fallback: ${JSON.stringify(result?.error ?? result)}`);
|
|
44
|
+
error.code = result?.error?.code;
|
|
45
|
+
throw error;
|
|
28
46
|
}
|
|
29
47
|
return result;
|
|
30
48
|
};
|
|
@@ -98,12 +116,7 @@ function expandCustomInstructionsFile(args) {
|
|
|
98
116
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
99
117
|
try {
|
|
100
118
|
const [command, ...args] = process.argv.slice(2);
|
|
101
|
-
const result = await runCompanyKb(command, args,
|
|
102
|
-
const child = spawnSync('ae-cli', flags, { encoding: 'utf8', stdio: ['inherit', 'pipe', 'pipe'] });
|
|
103
|
-
if (child.stderr) process.stderr.write(child.stderr);
|
|
104
|
-
if (child.error || child.status !== 0) throw new Error(child.error?.message || child.stderr || child.stdout || 'CLI failed.');
|
|
105
|
-
return JSON.parse(child.stdout);
|
|
106
|
-
});
|
|
119
|
+
const result = await runCompanyKb(command, args, invokeCompanyKbCli);
|
|
107
120
|
console.log(JSON.stringify(result, null, 2));
|
|
108
121
|
} catch (error) {
|
|
109
122
|
console.error(error.message);
|