speccrew 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.speccrew/agents/speccrew-feature-designer.md +142 -0
- package/.speccrew/agents/speccrew-product-manager.md +61 -0
- package/.speccrew/agents/speccrew-system-designer.md +200 -0
- package/.speccrew/agents/speccrew-system-developer.md +238 -0
- package/.speccrew/agents/speccrew-task-worker.md +80 -0
- package/.speccrew/agents/speccrew-team-leader.md +92 -0
- package/.speccrew/agents/speccrew-test-manager.md +313 -0
- package/.speccrew/skills/speccrew-create-agents/SKILL.md +98 -0
- package/.speccrew/skills/speccrew-create-agents/templates/agents/designer-agent.md +54 -0
- package/.speccrew/skills/speccrew-create-agents/templates/agents/dev-agent.md +79 -0
- package/.speccrew/skills/speccrew-create-agents/templates/agents/test-agent.md +80 -0
- package/.speccrew/skills/speccrew-dev-backend/SKILL.md +205 -0
- package/.speccrew/skills/speccrew-dev-backend/templates/TASK-RECORD-TEMPLATE.md +118 -0
- package/.speccrew/skills/speccrew-dev-desktop/SKILL.md +258 -0
- package/.speccrew/skills/speccrew-dev-desktop/templates/TASK-RECORD-TEMPLATE.md +161 -0
- package/.speccrew/skills/speccrew-dev-frontend/SKILL.md +202 -0
- package/.speccrew/skills/speccrew-dev-frontend/templates/TASK-RECORD-TEMPLATE.md +115 -0
- package/.speccrew/skills/speccrew-dev-mobile/SKILL.md +200 -0
- package/.speccrew/skills/speccrew-dev-mobile/templates/TASK-RECORD-TEMPLATE.md +125 -0
- package/.speccrew/skills/speccrew-fd-api-contract/SKILL.md +73 -0
- package/.speccrew/skills/speccrew-fd-api-contract/templates/API-CONTRACT-TEMPLATE.md +96 -0
- package/.speccrew/skills/speccrew-fd-feature-design/SKILL.md +395 -0
- package/.speccrew/skills/speccrew-fd-feature-design/templates/FEATURE-SPEC-TEMPLATE.md +387 -0
- package/.speccrew/skills/speccrew-get-timestamp/SKILL.md +80 -0
- package/.speccrew/skills/speccrew-get-timestamp/scripts/get-timestamp.js +35 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/SKILL.md +1116 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE-FASTAPI.md +462 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE-JAVA.md +480 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE-NET.md +464 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE.md +480 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/MODULE-OVERVIEW-TEMPLATE.md +367 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/SKILL.md +667 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/STATUS-FORMATS.md +74 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js +176 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/get-next-batch.js +150 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/get-pending-features.js +106 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/mark-stale.js +249 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/process-batch-results.js +848 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/update-feature-status.js +226 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/SKILL.md +264 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/examples/features.json +34 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js +867 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/test-inventory.js +26 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/SKILL.md +165 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/scripts/apply-module-mapping.js +208 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/scripts/extract-module-summary.js +180 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/scripts/reindex-modules.js +358 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/SKILL.md +1055 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-DESKTOP.md +303 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-ELECTRON.md +327 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-MINIAPP.md +292 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-MOBILE.md +281 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI.md +324 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/SKILL.md +270 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/templates/COMPONENT-PATTERN-TEMPLATE.md +33 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/templates/LAYOUT-PATTERN-TEMPLATE.md +33 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/templates/PAGE-TYPE-TEMPLATE.md +33 -0
- package/.speccrew/skills/speccrew-knowledge-graph-query/SKILL.md +229 -0
- package/.speccrew/skills/speccrew-knowledge-graph-query/scripts/graph-query.js +549 -0
- package/.speccrew/skills/speccrew-knowledge-graph-write/SKILL.md +181 -0
- package/.speccrew/skills/speccrew-knowledge-graph-write/scripts/graph-write.js +651 -0
- package/.speccrew/skills/speccrew-knowledge-module-summarize/SKILL.md +305 -0
- package/.speccrew/skills/speccrew-knowledge-module-summarize/templates/MODULE-OVERVIEW-TEMPLATE.md +400 -0
- package/.speccrew/skills/speccrew-knowledge-system-summarize/SKILL.md +351 -0
- package/.speccrew/skills/speccrew-knowledge-system-summarize/templates/SYSTEM-OVERVIEW-TEMPLATE.md +294 -0
- package/.speccrew/skills/speccrew-knowledge-techs-dispatch/SKILL.md +683 -0
- package/.speccrew/skills/speccrew-knowledge-techs-dispatch/STATUS-FORMATS.md +550 -0
- package/.speccrew/skills/speccrew-knowledge-techs-dispatch/templates/techs-manifest-EXAMPLE.json +35 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/SKILL.md +1087 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/ARCHITECTURE-TEMPLATE.md +240 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/COLOR-SYSTEM-TEMPLATE.md +68 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/COMPONENT-LIBRARY-TEMPLATE.md +86 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-BUILD-TEMPLATE.md +466 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-DATA-TEMPLATE.md +432 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-DESIGN-TEMPLATE.md +1209 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-DEV-TEMPLATE.md +1433 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-SYSTEM-TEST-TEMPLATE.md +1052 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-UNIT-TEST-TEMPLATE.md +946 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/INDEX-TEMPLATE.md +29 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/PAGE-LAYOUTS-TEMPLATE.md +69 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/PAGE-TYPE-SUMMARY-TEMPLATE.md +74 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/TECH-STACK-TEMPLATE.md +232 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate-conventions/SKILL.md +628 -0
- package/.speccrew/skills/speccrew-knowledge-techs-generate-ui-style/SKILL.md +392 -0
- package/.speccrew/skills/speccrew-knowledge-techs-index/SKILL.md +489 -0
- package/.speccrew/skills/speccrew-knowledge-techs-index/templates/INDEX-TEMPLATE.md +243 -0
- package/.speccrew/skills/speccrew-knowledge-techs-init/SKILL.md +269 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/SKILL.md +562 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/BUSINESS-COMPONENTS-TEMPLATE.md +171 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/COMMON-COMPONENTS-TEMPLATE.md +177 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/COMPONENT-INDIVIDUAL-TEMPLATE.md +80 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/COMPONENT-LIBRARY-TEMPLATE.md +118 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/LAYOUT-INDIVIDUAL-TEMPLATE.md +97 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/LAYOUT-PATTERNS-TEMPLATE.md +208 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/NAVIGATION-PATTERNS-TEMPLATE.md +157 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/PAGE-TYPE-INDIVIDUAL-TEMPLATE.md +123 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/PAGE-TYPE-SUMMARY-TEMPLATE.md +58 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/SPACING-TEMPLATE.md +119 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/STYLE-SYSTEM-TEMPLATE.md +117 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/TYPOGRAPHY-TEMPLATE.md +107 -0
- package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/UI-STYLE-GUIDE-TEMPLATE.md +171 -0
- package/.speccrew/skills/speccrew-pm-requirement-analysis/SKILL.md +434 -0
- package/.speccrew/skills/speccrew-pm-requirement-analysis/templates/BIZS-MODELING-TEMPLATE.md +332 -0
- package/.speccrew/skills/speccrew-pm-requirement-analysis/templates/PRD-TEMPLATE.md +200 -0
- package/.speccrew/skills/speccrew-pm-requirement-assess/SKILL.md +195 -0
- package/.speccrew/skills/speccrew-project-diagnosis/SKILL.md +208 -0
- package/.speccrew/skills/speccrew-project-diagnosis/templates/DIAGNOSIS-REPORT-TEMPLATE.md +202 -0
- package/.speccrew/skills/speccrew-sd-backend/SKILL.md +188 -0
- package/.speccrew/skills/speccrew-sd-backend/templates/INDEX-TEMPLATE.md +85 -0
- package/.speccrew/skills/speccrew-sd-backend/templates/SD-BACKEND-TEMPLATE.md +269 -0
- package/.speccrew/skills/speccrew-sd-desktop/SKILL.md +192 -0
- package/.speccrew/skills/speccrew-sd-desktop/templates/INDEX-TEMPLATE.md +271 -0
- package/.speccrew/skills/speccrew-sd-desktop/templates/SD-DESKTOP-TEMPLATE.md +673 -0
- package/.speccrew/skills/speccrew-sd-frontend/SKILL.md +176 -0
- package/.speccrew/skills/speccrew-sd-frontend/templates/INDEX-TEMPLATE.md +184 -0
- package/.speccrew/skills/speccrew-sd-frontend/templates/SD-FRONTEND-TEMPLATE.md +382 -0
- package/.speccrew/skills/speccrew-sd-mobile/SKILL.md +189 -0
- package/.speccrew/skills/speccrew-sd-mobile/templates/INDEX-TEMPLATE.md +219 -0
- package/.speccrew/skills/speccrew-sd-mobile/templates/SD-MOBILE-TEMPLATE.md +534 -0
- package/.speccrew/skills/speccrew-test-case-design/SKILL.md +284 -0
- package/.speccrew/skills/speccrew-test-case-design/templates/TEST-CASE-DESIGN-TEMPLATE.md +263 -0
- package/.speccrew/skills/speccrew-test-code-gen/SKILL.md +313 -0
- package/.speccrew/skills/speccrew-test-code-gen/templates/TEST-CODE-PLAN-TEMPLATE.md +180 -0
- package/.speccrew/skills/speccrew-test-execute/SKILL.md +283 -0
- package/.speccrew/skills/speccrew-test-execute/templates/BUG-REPORT-TEMPLATE.md +50 -0
- package/.speccrew/skills/speccrew-test-execute/templates/TEST-REPORT-TEMPLATE.md +57 -0
- package/.speccrew/skills/speccrew-workflow-diagnose/SKILL.md +155 -0
- package/LICENSE +21 -0
- package/README.ar.md +318 -0
- package/README.en.md +318 -0
- package/README.es.md +318 -0
- package/README.md +340 -0
- package/bin/cli.js +62 -0
- package/lib/commands/doctor.js +138 -0
- package/lib/commands/init.js +231 -0
- package/lib/commands/list.js +114 -0
- package/lib/commands/uninstall.js +117 -0
- package/lib/commands/update.js +351 -0
- package/lib/ide-adapters.js +73 -0
- package/lib/utils.js +104 -0
- package/package.json +28 -0
- package/workspace-template/docs/configs/document-templates.json +667 -0
- package/workspace-template/docs/configs/platform-mapping.json +194 -0
- package/workspace-template/docs/configs/tech-stack-mappings.json +313 -0
- package/workspace-template/docs/configs/validation-rules.json +87 -0
- package/workspace-template/docs/rules/mermaid-rule.md +114 -0
- package/workspace-template/docs/solutions/Agent/346/212/200/350/203/275/345/256/232/344/271/211+/351/234/200/346/261/202/346/226/207/346/241/243+UML/344/275/277/347/224/250/346/250/241/346/235/277/357/274/210ISA-95/345/205/255/346/256/265/345/274/217/350/236/215/345/220/210/347/211/210/357/274/211.md +586 -0
- package/workspace-template/docs/solutions/agent-knowledge-map.md +238 -0
- package/workspace-template/docs/solutions/bizs-knowledge-pipeline.md +678 -0
- package/workspace-template/docs/solutions/harness.md +410 -0
- package/workspace-template/docs/solutions/knowledge-incremental-sync-spec.md +943 -0
- package/workspace-template/docs/solutions/techs-knowledge-pipeline.md +803 -0
- package/workspace-template/docs/solutions/workspace-structure.md +318 -0
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Knowledge Graph Write Operations
|
|
4
|
+
* Write, update, and initialize knowledge graph data (nodes, edges, index, metadata).
|
|
5
|
+
* All data stored under {graphRoot}/ directory.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// ── Parse Arguments ─────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
function parseArgs() {
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
const parsed = {};
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const arg = args[i];
|
|
19
|
+
if (arg.startsWith('--')) {
|
|
20
|
+
const key = arg.slice(2);
|
|
21
|
+
const value = args[i + 1] && !args[i + 1].startsWith('--') ? args[i + 1] : true;
|
|
22
|
+
parsed[key] = value;
|
|
23
|
+
if (value !== true) i++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const args = parseArgs();
|
|
31
|
+
|
|
32
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
function ensureDir(dirPath) {
|
|
35
|
+
if (!fs.existsSync(dirPath)) {
|
|
36
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readJsonFile(filePath) {
|
|
41
|
+
if (fs.existsSync(filePath)) {
|
|
42
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
43
|
+
return JSON.parse(content);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function writeJsonFile(filePath, obj) {
|
|
49
|
+
const json = JSON.stringify(obj, null, 2);
|
|
50
|
+
fs.writeFileSync(filePath, json, 'utf-8');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getModuleFromId(nodeId) {
|
|
54
|
+
if (!nodeId || typeof nodeId !== 'string') return null;
|
|
55
|
+
// ID format: {type}-{module}-{name}, extract module (second segment)
|
|
56
|
+
const parts = nodeId.split('-');
|
|
57
|
+
if (parts.length >= 2) return parts[1];
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getIndexPath(graphRoot) {
|
|
62
|
+
return path.join(graphRoot, 'indices', 'index.json');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getMetaPath(graphRoot) {
|
|
66
|
+
return path.join(graphRoot, 'graph-meta.json');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getNodesPath(graphRoot, platformId, module) {
|
|
70
|
+
return path.join(graphRoot, 'nodes', platformId, `${module}.json`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getEdgesPath(graphRoot, platformId, module) {
|
|
74
|
+
return path.join(graphRoot, 'edges', platformId, `${module}.json`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getCrossEdgesPath(graphRoot, platformId) {
|
|
78
|
+
return path.join(graphRoot, 'edges', platformId, 'cross-module.json');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getCurrentTimestamp() {
|
|
82
|
+
return new Date().toISOString();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── Actions ─────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
function invokeInitModule(graphRoot, platformId, module) {
|
|
88
|
+
ensureDir(path.join(graphRoot, 'nodes', platformId));
|
|
89
|
+
ensureDir(path.join(graphRoot, 'edges', platformId));
|
|
90
|
+
ensureDir(path.join(graphRoot, 'indices'));
|
|
91
|
+
|
|
92
|
+
// nodes/{platformId}/{module}.json
|
|
93
|
+
const nodesPath = getNodesPath(graphRoot, platformId, module);
|
|
94
|
+
if (!fs.existsSync(nodesPath)) {
|
|
95
|
+
const nodesObj = { module, nodes: [] };
|
|
96
|
+
writeJsonFile(nodesPath, nodesObj);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// edges/{platformId}/{module}.json
|
|
100
|
+
const edgesPath = getEdgesPath(graphRoot, platformId, module);
|
|
101
|
+
if (!fs.existsSync(edgesPath)) {
|
|
102
|
+
const edgesObj = { module, edges: [] };
|
|
103
|
+
writeJsonFile(edgesPath, edgesObj);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// edges/{platformId}/cross-module.json
|
|
107
|
+
const crossPath = getCrossEdgesPath(graphRoot, platformId);
|
|
108
|
+
if (!fs.existsSync(crossPath)) {
|
|
109
|
+
const crossObj = { edges: [] };
|
|
110
|
+
writeJsonFile(crossPath, crossObj);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// indices/index.json
|
|
114
|
+
const indexPath = getIndexPath(graphRoot);
|
|
115
|
+
if (!fs.existsSync(indexPath)) {
|
|
116
|
+
writeJsonFile(indexPath, {});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// graph-meta.json
|
|
120
|
+
const metaPath = getMetaPath(graphRoot);
|
|
121
|
+
if (fs.existsSync(metaPath)) {
|
|
122
|
+
const meta = readJsonFile(metaPath);
|
|
123
|
+
const modules = meta.modules || [];
|
|
124
|
+
const moduleKey = `${platformId}/${module}`;
|
|
125
|
+
if (!modules.includes(moduleKey)) {
|
|
126
|
+
modules.push(moduleKey);
|
|
127
|
+
meta.modules = modules;
|
|
128
|
+
meta.updatedAt = getCurrentTimestamp();
|
|
129
|
+
writeJsonFile(metaPath, meta);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
const meta = {
|
|
133
|
+
version: '1.0.0',
|
|
134
|
+
updatedAt: getCurrentTimestamp(),
|
|
135
|
+
modules: [`${platformId}/${module}`],
|
|
136
|
+
stats: {
|
|
137
|
+
totalNodes: 0,
|
|
138
|
+
totalEdges: 0,
|
|
139
|
+
nodesByType: {
|
|
140
|
+
page: 0, api: 0, table: 0, service: 0, component: 0, dto: 0, module: 0
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
writeJsonFile(metaPath, meta);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
status: 'success',
|
|
149
|
+
action: 'init-module',
|
|
150
|
+
platformId,
|
|
151
|
+
module,
|
|
152
|
+
message: `Module '${module}' initialized for platform '${platformId}'`
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function invokeAddNodes(graphRoot, platformId, module, filePath) {
|
|
157
|
+
const batchData = readJsonFile(filePath);
|
|
158
|
+
const newNodes = batchData.nodes || [];
|
|
159
|
+
|
|
160
|
+
if (newNodes.length === 0) {
|
|
161
|
+
return {
|
|
162
|
+
status: 'success',
|
|
163
|
+
action: 'add-nodes',
|
|
164
|
+
platformId,
|
|
165
|
+
module,
|
|
166
|
+
nodesWritten: 0,
|
|
167
|
+
message: 'No nodes to add'
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const nodesPath = getNodesPath(graphRoot, platformId, module);
|
|
172
|
+
let existing = readJsonFile(nodesPath);
|
|
173
|
+
if (!existing) {
|
|
174
|
+
invokeInitModule(graphRoot, platformId, module);
|
|
175
|
+
existing = readJsonFile(nodesPath);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Build lookup of existing nodes by id
|
|
179
|
+
const nodeMap = {};
|
|
180
|
+
for (const n of existing.nodes) {
|
|
181
|
+
nodeMap[n.id] = n;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Add/replace nodes
|
|
185
|
+
for (const n of newNodes) {
|
|
186
|
+
nodeMap[n.id] = n;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
existing.nodes = Object.values(nodeMap);
|
|
190
|
+
writeJsonFile(nodesPath, existing);
|
|
191
|
+
|
|
192
|
+
// Update index
|
|
193
|
+
const indexPath = getIndexPath(graphRoot);
|
|
194
|
+
let index = readJsonFile(indexPath);
|
|
195
|
+
if (!index) index = {};
|
|
196
|
+
|
|
197
|
+
for (const n of newNodes) {
|
|
198
|
+
index[n.id] = { platformId, module, type: n.type };
|
|
199
|
+
}
|
|
200
|
+
writeJsonFile(indexPath, index);
|
|
201
|
+
|
|
202
|
+
// Update graph-meta.json stats
|
|
203
|
+
invokeUpdateMeta(graphRoot);
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
status: 'success',
|
|
207
|
+
action: 'add-nodes',
|
|
208
|
+
platformId,
|
|
209
|
+
module,
|
|
210
|
+
nodesWritten: newNodes.length,
|
|
211
|
+
message: `Added ${newNodes.length} nodes to ${platformId}/${module}`
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function invokeAddEdges(graphRoot, platformId, module, filePath) {
|
|
216
|
+
const batchData = readJsonFile(filePath);
|
|
217
|
+
const newEdges = batchData.edges || [];
|
|
218
|
+
|
|
219
|
+
if (newEdges.length === 0) {
|
|
220
|
+
return {
|
|
221
|
+
status: 'success',
|
|
222
|
+
action: 'add-edges',
|
|
223
|
+
platformId,
|
|
224
|
+
module,
|
|
225
|
+
edgesWritten: 0,
|
|
226
|
+
message: 'No edges to add'
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Separate module-internal and cross-module edges
|
|
231
|
+
const internalEdges = [];
|
|
232
|
+
const crossEdges = [];
|
|
233
|
+
|
|
234
|
+
for (const e of newEdges) {
|
|
235
|
+
if (!e.source || !e.target) {
|
|
236
|
+
console.warn(`Skipping invalid edge (missing source/target): ${JSON.stringify(e)}`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const srcMod = getModuleFromId(e.source);
|
|
240
|
+
const tgtMod = getModuleFromId(e.target);
|
|
241
|
+
if (!srcMod || !tgtMod) {
|
|
242
|
+
console.warn(`Skipping edge with unparseable node ID: source=${e.source}, target=${e.target}`);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (srcMod !== tgtMod) {
|
|
246
|
+
crossEdges.push(e);
|
|
247
|
+
} else {
|
|
248
|
+
internalEdges.push(e);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Write internal edges
|
|
253
|
+
if (internalEdges.length > 0) {
|
|
254
|
+
const edgesPath = getEdgesPath(graphRoot, platformId, module);
|
|
255
|
+
let existing = readJsonFile(edgesPath);
|
|
256
|
+
if (!existing) {
|
|
257
|
+
invokeInitModule(graphRoot, platformId, module);
|
|
258
|
+
existing = readJsonFile(edgesPath);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Build dedup key: source+target+type
|
|
262
|
+
const edgeMap = {};
|
|
263
|
+
for (const e of existing.edges) {
|
|
264
|
+
const key = `${e.source}|${e.target}|${e.type}`;
|
|
265
|
+
edgeMap[key] = e;
|
|
266
|
+
}
|
|
267
|
+
for (const e of internalEdges) {
|
|
268
|
+
const key = `${e.source}|${e.target}|${e.type}`;
|
|
269
|
+
edgeMap[key] = e;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
existing.edges = Object.values(edgeMap);
|
|
273
|
+
writeJsonFile(edgesPath, existing);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Write cross-module edges
|
|
277
|
+
if (crossEdges.length > 0) {
|
|
278
|
+
const crossPath = getCrossEdgesPath(graphRoot, platformId);
|
|
279
|
+
let crossFile = readJsonFile(crossPath);
|
|
280
|
+
if (!crossFile) {
|
|
281
|
+
// Ensure directory exists before creating cross-module.json
|
|
282
|
+
ensureDir(path.dirname(crossPath));
|
|
283
|
+
crossFile = { edges: [] };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const edgeMap = {};
|
|
287
|
+
for (const e of crossFile.edges) {
|
|
288
|
+
const key = `${e.source}|${e.target}|${e.type}`;
|
|
289
|
+
edgeMap[key] = e;
|
|
290
|
+
}
|
|
291
|
+
for (const e of crossEdges) {
|
|
292
|
+
const key = `${e.source}|${e.target}|${e.type}`;
|
|
293
|
+
edgeMap[key] = e;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
crossFile.edges = Object.values(edgeMap);
|
|
297
|
+
writeJsonFile(crossPath, crossFile);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const total = internalEdges.length + crossEdges.length;
|
|
301
|
+
|
|
302
|
+
// Update graph-meta.json stats
|
|
303
|
+
invokeUpdateMeta(graphRoot);
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
status: 'success',
|
|
307
|
+
action: 'add-edges',
|
|
308
|
+
platformId,
|
|
309
|
+
module,
|
|
310
|
+
edgesWritten: total,
|
|
311
|
+
internalEdges: internalEdges.length,
|
|
312
|
+
crossModuleEdges: crossEdges.length,
|
|
313
|
+
message: `Added ${total} edges (${internalEdges.length} internal, ${crossEdges.length} cross-module)`
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function invokeUpdateNode(graphRoot, platformId, nodeId, dataJson) {
|
|
318
|
+
const module = getModuleFromId(nodeId);
|
|
319
|
+
const nodesPath = getNodesPath(graphRoot, platformId, module);
|
|
320
|
+
const existing = readJsonFile(nodesPath);
|
|
321
|
+
|
|
322
|
+
if (!existing) {
|
|
323
|
+
return {
|
|
324
|
+
status: 'failed',
|
|
325
|
+
message: `Module '${module}' not found for platform '${platformId}'`
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const updateData = JSON.parse(dataJson);
|
|
330
|
+
let found = false;
|
|
331
|
+
|
|
332
|
+
for (let i = 0; i < existing.nodes.length; i++) {
|
|
333
|
+
if (existing.nodes[i].id === nodeId) {
|
|
334
|
+
// Merge update fields into existing node
|
|
335
|
+
Object.assign(existing.nodes[i], updateData);
|
|
336
|
+
found = true;
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!found) {
|
|
342
|
+
return {
|
|
343
|
+
status: 'failed',
|
|
344
|
+
message: `Node '${nodeId}' not found in module '${module}' (platform: ${platformId})`
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
writeJsonFile(nodesPath, existing);
|
|
349
|
+
return {
|
|
350
|
+
status: 'success',
|
|
351
|
+
action: 'update-node',
|
|
352
|
+
platformId,
|
|
353
|
+
nodeId,
|
|
354
|
+
message: `Node '${nodeId}' updated`
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function invokeRemoveNode(graphRoot, platformId, nodeId) {
|
|
359
|
+
const module = getModuleFromId(nodeId);
|
|
360
|
+
const nodesPath = getNodesPath(graphRoot, platformId, module);
|
|
361
|
+
const existing = readJsonFile(nodesPath);
|
|
362
|
+
|
|
363
|
+
if (!existing) {
|
|
364
|
+
return {
|
|
365
|
+
status: 'failed',
|
|
366
|
+
message: `Module '${module}' not found for platform '${platformId}'`
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Remove node
|
|
371
|
+
existing.nodes = existing.nodes.filter(n => n.id !== nodeId);
|
|
372
|
+
writeJsonFile(nodesPath, existing);
|
|
373
|
+
|
|
374
|
+
// Remove edges referencing this node (internal)
|
|
375
|
+
const edgesPath = getEdgesPath(graphRoot, platformId, module);
|
|
376
|
+
const edgesFile = readJsonFile(edgesPath);
|
|
377
|
+
if (edgesFile) {
|
|
378
|
+
edgesFile.edges = edgesFile.edges.filter(e => e.source !== nodeId && e.target !== nodeId);
|
|
379
|
+
writeJsonFile(edgesPath, edgesFile);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Remove edges referencing this node (cross-module)
|
|
383
|
+
const crossPath = getCrossEdgesPath(graphRoot, platformId);
|
|
384
|
+
const crossFile = readJsonFile(crossPath);
|
|
385
|
+
if (crossFile) {
|
|
386
|
+
crossFile.edges = crossFile.edges.filter(e => e.source !== nodeId && e.target !== nodeId);
|
|
387
|
+
writeJsonFile(crossPath, crossFile);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Remove from index
|
|
391
|
+
const indexPath = getIndexPath(graphRoot);
|
|
392
|
+
const index = readJsonFile(indexPath);
|
|
393
|
+
if (index && index[nodeId]) {
|
|
394
|
+
delete index[nodeId];
|
|
395
|
+
writeJsonFile(indexPath, index);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
status: 'success',
|
|
400
|
+
action: 'remove-node',
|
|
401
|
+
platformId,
|
|
402
|
+
nodeId,
|
|
403
|
+
message: `Node '${nodeId}' and related edges removed`
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function invokeRebuildIndex(graphRoot) {
|
|
408
|
+
const indexPath = getIndexPath(graphRoot);
|
|
409
|
+
const nodesDir = path.join(graphRoot, 'nodes');
|
|
410
|
+
const index = {};
|
|
411
|
+
|
|
412
|
+
if (fs.existsSync(nodesDir)) {
|
|
413
|
+
// Scan platform subdirectories
|
|
414
|
+
const platformDirs = fs.readdirSync(nodesDir, { withFileTypes: true })
|
|
415
|
+
.filter(d => d.isDirectory())
|
|
416
|
+
.map(d => d.name);
|
|
417
|
+
|
|
418
|
+
for (const platformId of platformDirs) {
|
|
419
|
+
const platformDir = path.join(nodesDir, platformId);
|
|
420
|
+
const files = fs.readdirSync(platformDir).filter(f => f.endsWith('.json'));
|
|
421
|
+
for (const file of files) {
|
|
422
|
+
const filePath = path.join(platformDir, file);
|
|
423
|
+
const data = readJsonFile(filePath);
|
|
424
|
+
if (data && data.nodes) {
|
|
425
|
+
for (const n of data.nodes) {
|
|
426
|
+
index[n.id] = { platformId, module: data.module, type: n.type };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
writeJsonFile(indexPath, index);
|
|
434
|
+
const count = Object.keys(index).length;
|
|
435
|
+
return {
|
|
436
|
+
status: 'success',
|
|
437
|
+
action: 'rebuild-index',
|
|
438
|
+
indexEntries: count,
|
|
439
|
+
message: `Index rebuilt with ${count} entries`
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function invokeUpdateMeta(graphRoot) {
|
|
444
|
+
const metaPath = getMetaPath(graphRoot);
|
|
445
|
+
const nodesDir = path.join(graphRoot, 'nodes');
|
|
446
|
+
const edgesDir = path.join(graphRoot, 'edges');
|
|
447
|
+
|
|
448
|
+
let totalNodes = 0;
|
|
449
|
+
let totalEdges = 0;
|
|
450
|
+
const nodesByType = { page: 0, api: 0, table: 0, service: 0, component: 0, dto: 0, module: 0 };
|
|
451
|
+
const modules = [];
|
|
452
|
+
|
|
453
|
+
if (fs.existsSync(nodesDir)) {
|
|
454
|
+
// Scan platform subdirectories
|
|
455
|
+
const platformDirs = fs.readdirSync(nodesDir, { withFileTypes: true })
|
|
456
|
+
.filter(d => d.isDirectory())
|
|
457
|
+
.map(d => d.name);
|
|
458
|
+
|
|
459
|
+
for (const platformId of platformDirs) {
|
|
460
|
+
const platformDir = path.join(nodesDir, platformId);
|
|
461
|
+
const files = fs.readdirSync(platformDir).filter(f => f.endsWith('.json'));
|
|
462
|
+
for (const file of files) {
|
|
463
|
+
const filePath = path.join(platformDir, file);
|
|
464
|
+
const data = readJsonFile(filePath);
|
|
465
|
+
if (data && data.nodes) {
|
|
466
|
+
modules.push(`${platformId}/${data.module}`);
|
|
467
|
+
for (const n of data.nodes) {
|
|
468
|
+
totalNodes++;
|
|
469
|
+
if (nodesByType.hasOwnProperty(n.type)) {
|
|
470
|
+
nodesByType[n.type]++;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (fs.existsSync(edgesDir)) {
|
|
479
|
+
// Scan platform subdirectories
|
|
480
|
+
const platformDirs = fs.readdirSync(edgesDir, { withFileTypes: true })
|
|
481
|
+
.filter(d => d.isDirectory())
|
|
482
|
+
.map(d => d.name);
|
|
483
|
+
|
|
484
|
+
for (const platformId of platformDirs) {
|
|
485
|
+
const platformDir = path.join(edgesDir, platformId);
|
|
486
|
+
const files = fs.readdirSync(platformDir).filter(f => f.endsWith('.json'));
|
|
487
|
+
for (const file of files) {
|
|
488
|
+
const filePath = path.join(platformDir, file);
|
|
489
|
+
const data = readJsonFile(filePath);
|
|
490
|
+
if (data && data.edges) {
|
|
491
|
+
totalEdges += data.edges.length;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const meta = {
|
|
498
|
+
version: '1.0.0',
|
|
499
|
+
updatedAt: getCurrentTimestamp(),
|
|
500
|
+
modules: [...new Set(modules)].sort(),
|
|
501
|
+
stats: {
|
|
502
|
+
totalNodes,
|
|
503
|
+
totalEdges,
|
|
504
|
+
nodesByType
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
writeJsonFile(metaPath, meta);
|
|
509
|
+
return {
|
|
510
|
+
status: 'success',
|
|
511
|
+
action: 'update-meta',
|
|
512
|
+
totalNodes,
|
|
513
|
+
totalEdges,
|
|
514
|
+
message: `Metadata updated: ${totalNodes} nodes, ${totalEdges} edges`
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function invokeBatchWrite(graphRoot, platformId, module, filePath) {
|
|
519
|
+
// Batch write combines add-nodes and add-edges
|
|
520
|
+
const batchData = readJsonFile(filePath);
|
|
521
|
+
|
|
522
|
+
let nodesWritten = 0;
|
|
523
|
+
let edgesWritten = 0;
|
|
524
|
+
let internalEdges = 0;
|
|
525
|
+
let crossModuleEdges = 0;
|
|
526
|
+
|
|
527
|
+
// Add nodes if present
|
|
528
|
+
if (batchData.nodes && batchData.nodes.length > 0) {
|
|
529
|
+
const nodesResult = invokeAddNodes(graphRoot, platformId, module, filePath);
|
|
530
|
+
nodesWritten = nodesResult.nodesWritten || 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Add edges if present
|
|
534
|
+
if (batchData.edges && batchData.edges.length > 0) {
|
|
535
|
+
const edgesResult = invokeAddEdges(graphRoot, platformId, module, filePath);
|
|
536
|
+
edgesWritten = edgesResult.edgesWritten || 0;
|
|
537
|
+
internalEdges = edgesResult.internalEdges || 0;
|
|
538
|
+
crossModuleEdges = edgesResult.crossModuleEdges || 0;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Update index and meta
|
|
542
|
+
invokeRebuildIndex(graphRoot);
|
|
543
|
+
invokeUpdateMeta(graphRoot);
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
status: 'success',
|
|
547
|
+
action: 'batch-write',
|
|
548
|
+
platformId,
|
|
549
|
+
module,
|
|
550
|
+
nodesWritten,
|
|
551
|
+
edgesWritten,
|
|
552
|
+
internalEdges,
|
|
553
|
+
crossModuleEdges,
|
|
554
|
+
message: `Successfully wrote ${nodesWritten} nodes and ${edgesWritten} edges to ${platformId}/${module} module`
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// ── Main ────────────────────────────────────────────────────────────────────
|
|
559
|
+
|
|
560
|
+
function main() {
|
|
561
|
+
const action = args.action;
|
|
562
|
+
const graphRoot = args.graphRoot;
|
|
563
|
+
const platformId = args.platformId;
|
|
564
|
+
|
|
565
|
+
if (!action) {
|
|
566
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameter: --action' }));
|
|
567
|
+
process.exit(1);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (!graphRoot) {
|
|
571
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameter: --graphRoot' }));
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const validActions = ['batch-write', 'init-module', 'add-nodes', 'add-edges', 'update-node', 'remove-node', 'rebuild-index', 'update-meta'];
|
|
576
|
+
if (!validActions.includes(action)) {
|
|
577
|
+
console.error(JSON.stringify({ status: 'failed', message: `Invalid action: ${action}. Valid actions: ${validActions.join(', ')}` }));
|
|
578
|
+
process.exit(1);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Actions that require platformId
|
|
582
|
+
const platformRequiredActions = ['batch-write', 'init-module', 'add-nodes', 'add-edges', 'update-node', 'remove-node'];
|
|
583
|
+
if (platformRequiredActions.includes(action) && !platformId) {
|
|
584
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameter: --platformId' }));
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
let result;
|
|
589
|
+
|
|
590
|
+
switch (action) {
|
|
591
|
+
case 'init-module':
|
|
592
|
+
if (!args.module) {
|
|
593
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameter: --module' }));
|
|
594
|
+
process.exit(1);
|
|
595
|
+
}
|
|
596
|
+
result = invokeInitModule(graphRoot, platformId, args.module);
|
|
597
|
+
break;
|
|
598
|
+
|
|
599
|
+
case 'add-nodes':
|
|
600
|
+
if (!args.module || !args.file) {
|
|
601
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameters: --module and --file' }));
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
result = invokeAddNodes(graphRoot, platformId, args.module, args.file);
|
|
605
|
+
break;
|
|
606
|
+
|
|
607
|
+
case 'add-edges':
|
|
608
|
+
if (!args.module || !args.file) {
|
|
609
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameters: --module and --file' }));
|
|
610
|
+
process.exit(1);
|
|
611
|
+
}
|
|
612
|
+
result = invokeAddEdges(graphRoot, platformId, args.module, args.file);
|
|
613
|
+
break;
|
|
614
|
+
|
|
615
|
+
case 'update-node':
|
|
616
|
+
if (!args.id || !args.data) {
|
|
617
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameters: --id and --data' }));
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
result = invokeUpdateNode(graphRoot, platformId, args.id, args.data);
|
|
621
|
+
break;
|
|
622
|
+
|
|
623
|
+
case 'remove-node':
|
|
624
|
+
if (!args.id) {
|
|
625
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameter: --id' }));
|
|
626
|
+
process.exit(1);
|
|
627
|
+
}
|
|
628
|
+
result = invokeRemoveNode(graphRoot, platformId, args.id);
|
|
629
|
+
break;
|
|
630
|
+
|
|
631
|
+
case 'rebuild-index':
|
|
632
|
+
result = invokeRebuildIndex(graphRoot);
|
|
633
|
+
break;
|
|
634
|
+
|
|
635
|
+
case 'update-meta':
|
|
636
|
+
result = invokeUpdateMeta(graphRoot);
|
|
637
|
+
break;
|
|
638
|
+
|
|
639
|
+
case 'batch-write':
|
|
640
|
+
if (!args.module || !args.file) {
|
|
641
|
+
console.error(JSON.stringify({ status: 'failed', message: 'Missing required parameters: --module and --file' }));
|
|
642
|
+
process.exit(1);
|
|
643
|
+
}
|
|
644
|
+
result = invokeBatchWrite(graphRoot, platformId, args.module, args.file);
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
console.log(JSON.stringify(result));
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
main();
|