zero-workspace 0.0.2
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/CHANGELOG.md +18 -0
- package/README.md +187 -0
- package/config/component-versions.json +16 -0
- package/config/scenarioCapabilities.json +29 -0
- package/config/version-notes.yaml +244 -0
- package/dist/adapters/OutputAdapter.d.ts +79 -0
- package/dist/adapters/OutputAdapter.d.ts.map +1 -0
- package/dist/adapters/OutputAdapter.js +124 -0
- package/dist/adapters/OutputAdapter.js.map +1 -0
- package/dist/cli/check-node-version.d.ts +3 -0
- package/dist/cli/check-node-version.d.ts.map +1 -0
- package/dist/cli/check-node-version.js +153 -0
- package/dist/cli/check-node-version.js.map +1 -0
- package/dist/cli/plugins.d.ts +41 -0
- package/dist/cli/plugins.d.ts.map +1 -0
- package/dist/cli/plugins.js +742 -0
- package/dist/cli/plugins.js.map +1 -0
- package/dist/cli/rebuild.d.ts +63 -0
- package/dist/cli/rebuild.d.ts.map +1 -0
- package/dist/cli/rebuild.js +989 -0
- package/dist/cli/rebuild.js.map +1 -0
- package/dist/cli/repair.d.ts +7 -0
- package/dist/cli/repair.d.ts.map +1 -0
- package/dist/cli/repair.js +925 -0
- package/dist/cli/repair.js.map +1 -0
- package/dist/cli/setup.d.ts +7 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +452 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/update.d.ts +10 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +426 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/cli/webui.d.ts +6 -0
- package/dist/cli/webui.d.ts.map +1 -0
- package/dist/cli/webui.js +210 -0
- package/dist/cli/webui.js.map +1 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +15 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/middleware/errorHandler.d.ts +16 -0
- package/dist/http/middleware/errorHandler.d.ts.map +1 -0
- package/dist/http/middleware/errorHandler.js +79 -0
- package/dist/http/middleware/errorHandler.js.map +1 -0
- package/dist/http/routes/admin.d.ts +3 -0
- package/dist/http/routes/admin.d.ts.map +1 -0
- package/dist/http/routes/admin.js +730 -0
- package/dist/http/routes/admin.js.map +1 -0
- package/dist/http/routes/backup.d.ts +3 -0
- package/dist/http/routes/backup.d.ts.map +1 -0
- package/dist/http/routes/backup.js +172 -0
- package/dist/http/routes/backup.js.map +1 -0
- package/dist/http/routes/config.d.ts +3 -0
- package/dist/http/routes/config.d.ts.map +1 -0
- package/dist/http/routes/config.js +157 -0
- package/dist/http/routes/config.js.map +1 -0
- package/dist/http/routes/context.d.ts +3 -0
- package/dist/http/routes/context.d.ts.map +1 -0
- package/dist/http/routes/context.js +82 -0
- package/dist/http/routes/context.js.map +1 -0
- package/dist/http/routes/log.d.ts +3 -0
- package/dist/http/routes/log.d.ts.map +1 -0
- package/dist/http/routes/log.js +105 -0
- package/dist/http/routes/log.js.map +1 -0
- package/dist/http/routes/memo.d.ts +6 -0
- package/dist/http/routes/memo.d.ts.map +1 -0
- package/dist/http/routes/memo.js +29 -0
- package/dist/http/routes/memo.js.map +1 -0
- package/dist/http/routes/node.d.ts +3 -0
- package/dist/http/routes/node.d.ts.map +1 -0
- package/dist/http/routes/node.js +251 -0
- package/dist/http/routes/node.js.map +1 -0
- package/dist/http/routes/state.d.ts +3 -0
- package/dist/http/routes/state.d.ts.map +1 -0
- package/dist/http/routes/state.js +48 -0
- package/dist/http/routes/state.js.map +1 -0
- package/dist/http/routes/workspace.d.ts +3 -0
- package/dist/http/routes/workspace.d.ts.map +1 -0
- package/dist/http/routes/workspace.js +249 -0
- package/dist/http/routes/workspace.js.map +1 -0
- package/dist/http/server.d.ts +10 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +284 -0
- package/dist/http/server.js.map +1 -0
- package/dist/http/services.d.ts +93 -0
- package/dist/http/services.d.ts.map +1 -0
- package/dist/http/services.js +297 -0
- package/dist/http/services.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1073 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/guidanceContent.d.ts +18 -0
- package/dist/prompts/guidanceContent.d.ts.map +1 -0
- package/dist/prompts/guidanceContent.js +814 -0
- package/dist/prompts/guidanceContent.js.map +1 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +4 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/instructions.d.ts +56 -0
- package/dist/prompts/instructions.d.ts.map +1 -0
- package/dist/prompts/instructions.js +1343 -0
- package/dist/prompts/instructions.js.map +1 -0
- package/dist/services/BackupService.d.ts +104 -0
- package/dist/services/BackupService.d.ts.map +1 -0
- package/dist/services/BackupService.js +549 -0
- package/dist/services/BackupService.js.map +1 -0
- package/dist/services/CapabilityService.d.ts +38 -0
- package/dist/services/CapabilityService.d.ts.map +1 -0
- package/dist/services/CapabilityService.js +256 -0
- package/dist/services/CapabilityService.js.map +1 -0
- package/dist/services/ConfigService.d.ts +35 -0
- package/dist/services/ConfigService.d.ts.map +1 -0
- package/dist/services/ConfigService.js +105 -0
- package/dist/services/ConfigService.js.map +1 -0
- package/dist/services/ContextService.d.ts +65 -0
- package/dist/services/ContextService.d.ts.map +1 -0
- package/dist/services/ContextService.js +503 -0
- package/dist/services/ContextService.js.map +1 -0
- package/dist/services/DetectionService.d.ts +76 -0
- package/dist/services/DetectionService.d.ts.map +1 -0
- package/dist/services/DetectionService.js +262 -0
- package/dist/services/DetectionService.js.map +1 -0
- package/dist/services/DispatchService.d.ts +267 -0
- package/dist/services/DispatchService.d.ts.map +1 -0
- package/dist/services/DispatchService.js +1357 -0
- package/dist/services/DispatchService.js.map +1 -0
- package/dist/services/EventService.d.ts +81 -0
- package/dist/services/EventService.d.ts.map +1 -0
- package/dist/services/EventService.js +187 -0
- package/dist/services/EventService.js.map +1 -0
- package/dist/services/GuidanceService.d.ts +64 -0
- package/dist/services/GuidanceService.d.ts.map +1 -0
- package/dist/services/GuidanceService.js +259 -0
- package/dist/services/GuidanceService.js.map +1 -0
- package/dist/services/HealthService.d.ts +43 -0
- package/dist/services/HealthService.d.ts.map +1 -0
- package/dist/services/HealthService.js +276 -0
- package/dist/services/HealthService.js.map +1 -0
- package/dist/services/InstallationService.d.ts +62 -0
- package/dist/services/InstallationService.d.ts.map +1 -0
- package/dist/services/InstallationService.js +204 -0
- package/dist/services/InstallationService.js.map +1 -0
- package/dist/services/LogService.d.ts +35 -0
- package/dist/services/LogService.d.ts.map +1 -0
- package/dist/services/LogService.js +189 -0
- package/dist/services/LogService.js.map +1 -0
- package/dist/services/MemoService.d.ts +39 -0
- package/dist/services/MemoService.d.ts.map +1 -0
- package/dist/services/MemoService.js +288 -0
- package/dist/services/MemoService.js.map +1 -0
- package/dist/services/NodeService.d.ts +90 -0
- package/dist/services/NodeService.d.ts.map +1 -0
- package/dist/services/NodeService.js +958 -0
- package/dist/services/NodeService.js.map +1 -0
- package/dist/services/OpenSpecParser.d.ts +43 -0
- package/dist/services/OpenSpecParser.d.ts.map +1 -0
- package/dist/services/OpenSpecParser.js +191 -0
- package/dist/services/OpenSpecParser.js.map +1 -0
- package/dist/services/ReferenceService.d.ts +35 -0
- package/dist/services/ReferenceService.d.ts.map +1 -0
- package/dist/services/ReferenceService.js +195 -0
- package/dist/services/ReferenceService.js.map +1 -0
- package/dist/services/RepairService.d.ts +36 -0
- package/dist/services/RepairService.d.ts.map +1 -0
- package/dist/services/RepairService.js +429 -0
- package/dist/services/RepairService.js.map +1 -0
- package/dist/services/SearchService.d.ts +34 -0
- package/dist/services/SearchService.d.ts.map +1 -0
- package/dist/services/SearchService.js +293 -0
- package/dist/services/SearchService.js.map +1 -0
- package/dist/services/SessionService.d.ts +136 -0
- package/dist/services/SessionService.d.ts.map +1 -0
- package/dist/services/SessionService.js +297 -0
- package/dist/services/SessionService.js.map +1 -0
- package/dist/services/StateService.d.ts +97 -0
- package/dist/services/StateService.d.ts.map +1 -0
- package/dist/services/StateService.js +846 -0
- package/dist/services/StateService.js.map +1 -0
- package/dist/services/TutorialService.d.ts +114 -0
- package/dist/services/TutorialService.d.ts.map +1 -0
- package/dist/services/TutorialService.js +1262 -0
- package/dist/services/TutorialService.js.map +1 -0
- package/dist/services/WorkspaceService.d.ts +273 -0
- package/dist/services/WorkspaceService.d.ts.map +1 -0
- package/dist/services/WorkspaceService.js +1764 -0
- package/dist/services/WorkspaceService.js.map +1 -0
- package/dist/services/index.d.ts +15 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +14 -0
- package/dist/services/index.js.map +1 -0
- package/dist/storage/FileSystemAdapter.d.ts +223 -0
- package/dist/storage/FileSystemAdapter.d.ts.map +1 -0
- package/dist/storage/FileSystemAdapter.js +384 -0
- package/dist/storage/FileSystemAdapter.js.map +1 -0
- package/dist/storage/JsonStorage.d.ts +158 -0
- package/dist/storage/JsonStorage.d.ts.map +1 -0
- package/dist/storage/JsonStorage.js +613 -0
- package/dist/storage/JsonStorage.js.map +1 -0
- package/dist/storage/MarkdownStorage.d.ts +178 -0
- package/dist/storage/MarkdownStorage.d.ts.map +1 -0
- package/dist/storage/MarkdownStorage.js +918 -0
- package/dist/storage/MarkdownStorage.js.map +1 -0
- package/dist/storage/SessionBindingStorage.d.ts +69 -0
- package/dist/storage/SessionBindingStorage.d.ts.map +1 -0
- package/dist/storage/SessionBindingStorage.js +131 -0
- package/dist/storage/SessionBindingStorage.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/tools/capability.d.ts +18 -0
- package/dist/tools/capability.d.ts.map +1 -0
- package/dist/tools/capability.js +73 -0
- package/dist/tools/capability.js.map +1 -0
- package/dist/tools/config.d.ts +14 -0
- package/dist/tools/config.d.ts.map +1 -0
- package/dist/tools/config.js +61 -0
- package/dist/tools/config.js.map +1 -0
- package/dist/tools/context.d.ts +22 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +139 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/dispatch.d.ts +41 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/dispatch.js +380 -0
- package/dist/tools/dispatch.js.map +1 -0
- package/dist/tools/help.d.ts +44 -0
- package/dist/tools/help.d.ts.map +1 -0
- package/dist/tools/help.js +227 -0
- package/dist/tools/help.js.map +1 -0
- package/dist/tools/import.d.ts +17 -0
- package/dist/tools/import.d.ts.map +1 -0
- package/dist/tools/import.js +96 -0
- package/dist/tools/import.js.map +1 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/log.d.ts +21 -0
- package/dist/tools/log.d.ts.map +1 -0
- package/dist/tools/log.js +93 -0
- package/dist/tools/log.js.map +1 -0
- package/dist/tools/memo.d.ts +26 -0
- package/dist/tools/memo.d.ts.map +1 -0
- package/dist/tools/memo.js +188 -0
- package/dist/tools/memo.js.map +1 -0
- package/dist/tools/node.d.ts +34 -0
- package/dist/tools/node.d.ts.map +1 -0
- package/dist/tools/node.js +328 -0
- package/dist/tools/node.js.map +1 -0
- package/dist/tools/search.d.ts +14 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +95 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/session.d.ts +22 -0
- package/dist/tools/session.d.ts.map +1 -0
- package/dist/tools/session.js +127 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/tools/state.d.ts +10 -0
- package/dist/tools/state.d.ts.map +1 -0
- package/dist/tools/state.js +79 -0
- package/dist/tools/state.js.map +1 -0
- package/dist/tools/workspace.d.ts +38 -0
- package/dist/tools/workspace.d.ts.map +1 -0
- package/dist/tools/workspace.js +240 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/types/capability.d.ts +36 -0
- package/dist/types/capability.d.ts.map +1 -0
- package/dist/types/capability.js +3 -0
- package/dist/types/capability.js.map +1 -0
- package/dist/types/confirmation.d.ts +35 -0
- package/dist/types/confirmation.d.ts.map +1 -0
- package/dist/types/confirmation.js +3 -0
- package/dist/types/confirmation.js.map +1 -0
- package/dist/types/context.d.ts +174 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +3 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/errors.d.ts +81 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +154 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/guidance.d.ts +162 -0
- package/dist/types/guidance.d.ts.map +1 -0
- package/dist/types/guidance.js +4 -0
- package/dist/types/guidance.js.map +1 -0
- package/dist/types/health.d.ts +61 -0
- package/dist/types/health.d.ts.map +1 -0
- package/dist/types/health.js +3 -0
- package/dist/types/health.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/memo.d.ts +132 -0
- package/dist/types/memo.d.ts.map +1 -0
- package/dist/types/memo.js +3 -0
- package/dist/types/memo.js.map +1 -0
- package/dist/types/node.d.ts +316 -0
- package/dist/types/node.d.ts.map +1 -0
- package/dist/types/node.js +3 -0
- package/dist/types/node.js.map +1 -0
- package/dist/types/repair.d.ts +62 -0
- package/dist/types/repair.d.ts.map +1 -0
- package/dist/types/repair.js +4 -0
- package/dist/types/repair.js.map +1 -0
- package/dist/types/search.d.ts +58 -0
- package/dist/types/search.d.ts.map +1 -0
- package/dist/types/search.js +3 -0
- package/dist/types/search.js.map +1 -0
- package/dist/types/settings.d.ts +109 -0
- package/dist/types/settings.d.ts.map +1 -0
- package/dist/types/settings.js +30 -0
- package/dist/types/settings.js.map +1 -0
- package/dist/types/workspace.d.ts +357 -0
- package/dist/types/workspace.d.ts.map +1 -0
- package/dist/types/workspace.js +3 -0
- package/dist/types/workspace.js.map +1 -0
- package/dist/utils/contentValidation.d.ts +47 -0
- package/dist/utils/contentValidation.d.ts.map +1 -0
- package/dist/utils/contentValidation.js +93 -0
- package/dist/utils/contentValidation.js.map +1 -0
- package/dist/utils/devLog.d.ts +43 -0
- package/dist/utils/devLog.d.ts.map +1 -0
- package/dist/utils/devLog.js +94 -0
- package/dist/utils/devLog.js.map +1 -0
- package/dist/utils/errorLogger.d.ts +27 -0
- package/dist/utils/errorLogger.d.ts.map +1 -0
- package/dist/utils/errorLogger.js +105 -0
- package/dist/utils/errorLogger.js.map +1 -0
- package/dist/utils/git.d.ts +123 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +400 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/hash.d.ts +32 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +37 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/id.d.ts +54 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +96 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +42 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +228 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/manualChangeFormatter.d.ts +8 -0
- package/dist/utils/manualChangeFormatter.d.ts.map +1 -0
- package/dist/utils/manualChangeFormatter.js +21 -0
- package/dist/utils/manualChangeFormatter.js.map +1 -0
- package/dist/utils/paramValidator.d.ts +35 -0
- package/dist/utils/paramValidator.d.ts.map +1 -0
- package/dist/utils/paramValidator.js +214 -0
- package/dist/utils/paramValidator.js.map +1 -0
- package/dist/utils/port.d.ts +7 -0
- package/dist/utils/port.d.ts.map +1 -0
- package/dist/utils/port.js +28 -0
- package/dist/utils/port.js.map +1 -0
- package/dist/utils/processManager.d.ts +53 -0
- package/dist/utils/processManager.d.ts.map +1 -0
- package/dist/utils/processManager.js +267 -0
- package/dist/utils/processManager.js.map +1 -0
- package/dist/utils/sessionLogger.d.ts +28 -0
- package/dist/utils/sessionLogger.d.ts.map +1 -0
- package/dist/utils/sessionLogger.js +142 -0
- package/dist/utils/sessionLogger.js.map +1 -0
- package/dist/utils/time.d.ts +15 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +32 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/validation.d.ts +23 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +88 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs//346/227/245/345/277/227/347/263/273/347/273/237.md +389 -0
- package/docs//347/224/250/346/210/267/346/211/213/345/206/214.md +1446 -0
- package/docs//347/224/250/346/210/267/346/211/213/345/206/214/344/270/216/346/212/200/346/234/257/346/214/207/345/215/227.md +873 -0
- package/package.json +94 -0
- package/plugin/README.md +141 -0
- package/plugin/agents/zero-executor.md +114 -0
- package/plugin/agents/zero-reviewer.md +133 -0
- package/plugin/docs/diagnostic-guide.md +128 -0
- package/plugin/hooks/hooks.json.deprecated +70 -0
- package/plugin/scripts/cursor-hook-entry.cjs +217 -0
- package/plugin/scripts/hook-entry.cjs +663 -0
- package/plugin/scripts/openspec-import.cjs +714 -0
- package/plugin/scripts/shared/binding.cjs +98 -0
- package/plugin/scripts/shared/config.cjs +65 -0
- package/plugin/scripts/shared/context.cjs +120 -0
- package/plugin/scripts/shared/index.cjs +34 -0
- package/plugin/scripts/shared/logger.cjs +196 -0
- package/plugin/scripts/shared/reminder.cjs +261 -0
- package/plugin/scripts/shared/utils.cjs +62 -0
- package/plugin/scripts/shared/workspace.cjs +322 -0
- package/plugin/skills/aligning-intent/SKILL.md +275 -0
- package/plugin/skills/analyzing-measurements/SKILL.md +223 -0
- package/plugin/skills/bootstrapping-workspace/SKILL.md +260 -0
- package/plugin/skills/designing-solutions/SKILL.md +363 -0
- package/plugin/skills/diagnosing-issues/SKILL.md +219 -0
- package/plugin/skills/discovering-context/SKILL.md +283 -0
- package/plugin/skills/dispatching-parent/SKILL.md +399 -0
- package/plugin/skills/executing-task/SKILL.md +340 -0
- package/plugin/skills/memo-create/SKILL.md +222 -0
- package/plugin/skills/planning-verification/SKILL.md +245 -0
- package/plugin/skills/preparing-dispatch/SKILL.md +299 -0
- package/plugin/skills/researching-tech/SKILL.md +223 -0
- package/plugin/skills/reviewing-quality/SKILL.md +354 -0
- package/plugin/skills/reviewing-spec/SKILL.md +333 -0
- package/plugin/skills/starting-info-flow/SKILL.md +196 -0
- package/web/README.md +5 -0
- package/web/dist/assets/DocsView-Bls_Vjsr.css +1 -0
- package/web/dist/assets/DocsView-Cxc0B63r.js +1447 -0
- package/web/dist/assets/HomeView-C7df9thb.js +9 -0
- package/web/dist/assets/HomeView-ufUdnfHk.css +1 -0
- package/web/dist/assets/MarkdownContent-DXp6CtSP.js +308 -0
- package/web/dist/assets/MarkdownContent-NFqiOBLH.css +1 -0
- package/web/dist/assets/NotFoundView-BYX1oZAn.css +1 -0
- package/web/dist/assets/NotFoundView-zrc0lT9q.js +1 -0
- package/web/dist/assets/WorkspaceView-BckqgNcX.js +27 -0
- package/web/dist/assets/WorkspaceView-J1dgpYMx.css +1 -0
- package/web/dist/assets/WsConfirmDialog-C1CvL4my.css +1 -0
- package/web/dist/assets/WsConfirmDialog-gLEP7uBD.js +4 -0
- package/web/dist/assets/arc-DPkKTkUT.js +1 -0
- package/web/dist/assets/architectureDiagram-VXUJARFQ-CEGpqUlZ.js +36 -0
- package/web/dist/assets/blockDiagram-VD42YOAC-Bv-mqdQH.js +122 -0
- package/web/dist/assets/c4Diagram-YG6GDRKO-DRyPatZ_.js +10 -0
- package/web/dist/assets/channel-B84mKLDZ.js +1 -0
- package/web/dist/assets/chunk-4BX2VUAB-c7DivX0u.js +1 -0
- package/web/dist/assets/chunk-55IACEB6-CGKTaLlo.js +1 -0
- package/web/dist/assets/chunk-B4BG7PRW-Czhx5Q_P.js +165 -0
- package/web/dist/assets/chunk-DI55MBZ5-CQVA7hcZ.js +220 -0
- package/web/dist/assets/chunk-FMBD7UC4-hEiPmi7V.js +15 -0
- package/web/dist/assets/chunk-QN33PNHL-rL6yYI-E.js +1 -0
- package/web/dist/assets/chunk-QZHKN3VN-BRyHBBzq.js +1 -0
- package/web/dist/assets/chunk-TZMSLE5B-D4PXmTz9.js +1 -0
- package/web/dist/assets/classDiagram-2ON5EDUG-CNn53ohi.js +1 -0
- package/web/dist/assets/classDiagram-v2-WZHVMYZB-CNn53ohi.js +1 -0
- package/web/dist/assets/cose-bilkent-S5V4N54A-BAREnRga.js +1 -0
- package/web/dist/assets/cytoscape.esm-BnkdMOzK.js +321 -0
- package/web/dist/assets/dagre-6UL2VRFP-DaYzb3MT.js +4 -0
- package/web/dist/assets/defaultLocale-C4B-KCzX.js +1 -0
- package/web/dist/assets/diagram-PSM6KHXK-BFltDqvd.js +24 -0
- package/web/dist/assets/diagram-QEK2KX5R-CR4VU2La.js +43 -0
- package/web/dist/assets/diagram-S2PKOQOG-0UfIeT-1.js +24 -0
- package/web/dist/assets/erDiagram-Q2GNP2WA-Bo17Xmng.js +60 -0
- package/web/dist/assets/flowDiagram-NV44I4VS-CzqhQp8s.js +162 -0
- package/web/dist/assets/ganttDiagram-JELNMOA3-TXwXtUcq.js +267 -0
- package/web/dist/assets/gitGraphDiagram-NY62KEGX-CoFQTy9O.js +65 -0
- package/web/dist/assets/graph-CIQcRIVd.js +1 -0
- package/web/dist/assets/index-BgLd_o_M.css +1 -0
- package/web/dist/assets/index-Cd_J3fZn.js +30 -0
- package/web/dist/assets/infoDiagram-WHAUD3N6-Dq0xXfVu.js +2 -0
- package/web/dist/assets/init-Gi6I4Gst.js +1 -0
- package/web/dist/assets/journeyDiagram-XKPGCS4Q-jIg5BOfC.js +139 -0
- package/web/dist/assets/kanban-definition-3W4ZIXB7-D2giu6aZ.js +89 -0
- package/web/dist/assets/katex-XbL3y5x-.js +261 -0
- package/web/dist/assets/layout-Bm-XCM-8.js +1 -0
- package/web/dist/assets/linear-FbekP9OZ.js +1 -0
- package/web/dist/assets/min-BrRCpYmF.js +1 -0
- package/web/dist/assets/mindmap-definition-VGOIOE7T-o-4ubbY9.js +68 -0
- package/web/dist/assets/noto-emoji-0-400-normal-BTQbhB77.woff +0 -0
- package/web/dist/assets/noto-emoji-0-400-normal-DHdy6Uhy.woff2 +0 -0
- package/web/dist/assets/noto-emoji-1-400-normal-0IvkdXBB.woff +0 -0
- package/web/dist/assets/noto-emoji-1-400-normal-BY9OovbM.woff2 +0 -0
- package/web/dist/assets/noto-emoji-10-400-normal-D9w4QCof.woff2 +0 -0
- package/web/dist/assets/noto-emoji-10-400-normal-DtCumcZR.woff +0 -0
- package/web/dist/assets/noto-emoji-11-400-normal-BboTlyvx.woff +0 -0
- package/web/dist/assets/noto-emoji-12-400-normal-BB5pgBKj.woff2 +0 -0
- package/web/dist/assets/noto-emoji-12-400-normal-g186qhiA.woff +0 -0
- package/web/dist/assets/noto-emoji-2-400-normal-BKCR1azW.woff2 +0 -0
- package/web/dist/assets/noto-emoji-2-400-normal-BYH0KhDr.woff +0 -0
- package/web/dist/assets/noto-emoji-3-400-normal-CnPTUeEK.woff +0 -0
- package/web/dist/assets/noto-emoji-3-400-normal-TrTb2VQM.woff2 +0 -0
- package/web/dist/assets/noto-emoji-4-400-normal-BxD0KVdj.woff +0 -0
- package/web/dist/assets/noto-emoji-4-400-normal-s_n9EyG1.woff2 +0 -0
- package/web/dist/assets/noto-emoji-5-400-normal-C190AIxR.woff +0 -0
- package/web/dist/assets/noto-emoji-5-400-normal-Ctfx4xc6.woff2 +0 -0
- package/web/dist/assets/noto-emoji-6-400-normal-DlXlXWt7.woff +0 -0
- package/web/dist/assets/noto-emoji-6-400-normal-NzsjD754.woff2 +0 -0
- package/web/dist/assets/noto-emoji-7-400-normal-BHP8KeA6.woff2 +0 -0
- package/web/dist/assets/noto-emoji-7-400-normal-CtuKhtAZ.woff +0 -0
- package/web/dist/assets/noto-emoji-8-400-normal-DR49ZFe7.woff +0 -0
- package/web/dist/assets/noto-emoji-8-400-normal-Dvmkf6b2.woff2 +0 -0
- package/web/dist/assets/noto-emoji-9-400-normal-BeHJQ2iK.woff2 +0 -0
- package/web/dist/assets/noto-emoji-9-400-normal-BlXmCgeQ.woff +0 -0
- package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/web/dist/assets/pieDiagram-ADFJNKIX-C45wSpld.js +30 -0
- package/web/dist/assets/quadrantDiagram-AYHSOK5B-tv-_fe-W.js +7 -0
- package/web/dist/assets/reduce-CoLNNlNb.js +1 -0
- package/web/dist/assets/requirementDiagram-UZGBJVZJ-Dn6PDfkL.js +64 -0
- package/web/dist/assets/sankeyDiagram-TZEHDZUN-CbXTZAsG.js +10 -0
- package/web/dist/assets/sequenceDiagram-WL72ISMW-B-o1CUJ5.js +145 -0
- package/web/dist/assets/stateDiagram-FKZM4ZOC-hzrupXQi.js +1 -0
- package/web/dist/assets/stateDiagram-v2-4FDKWEC3-DN-c2M96.js +1 -0
- package/web/dist/assets/timeline-definition-IT6M3QCI-R5SP9GDo.js +61 -0
- package/web/dist/assets/treemap-KMMF4GRG-Pg9KlUOt.js +128 -0
- package/web/dist/assets/xychartDiagram-PRI3JC2R-C3vbJhd1.js +7 -0
- package/web/dist/favicon.svg +13 -0
- package/web/dist/index.html +17 -0
- package//351/205/215/347/275/256/346/226/271/345/274/217.md +330 -0
|
@@ -0,0 +1,1262 @@
|
|
|
1
|
+
// src/services/TutorialService.ts
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import YAML from "yaml";
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
import { INTERNAL_RULES_HASH } from "./NodeService.js";
|
|
9
|
+
import { computeConclusionsHash } from "../utils/hash.js";
|
|
10
|
+
import pkg from "../../package.json" with { type: "json" };
|
|
11
|
+
/**
|
|
12
|
+
* 教程版本 - 与系统版本同步,版本变更时会自动重建教程工作区
|
|
13
|
+
*/
|
|
14
|
+
const TUTORIAL_VERSION = pkg.version;
|
|
15
|
+
/**
|
|
16
|
+
* 教程工作区内容
|
|
17
|
+
*/
|
|
18
|
+
const TUTORIAL_CONTENT = {
|
|
19
|
+
name: "ZeroWorkspace 功能简介",
|
|
20
|
+
goal: "了解 ZeroWorkspace 的核心功能和使用方式",
|
|
21
|
+
rules: [
|
|
22
|
+
"这是一个演示用的工作区,可以随意操作",
|
|
23
|
+
"规则用于约束 AI 行为,如代码风格、提交规范等",
|
|
24
|
+
],
|
|
25
|
+
docs: [
|
|
26
|
+
{ path: "README.md", description: "项目说明文档(演示用)" },
|
|
27
|
+
],
|
|
28
|
+
nodes: [
|
|
29
|
+
// 界面导航
|
|
30
|
+
{
|
|
31
|
+
type: "planning",
|
|
32
|
+
title: "界面导航",
|
|
33
|
+
requirement: "熟悉 WebUI 的基本操作",
|
|
34
|
+
// 有子节点的规划节点自动进入 monitoring,不设置 targetStatus
|
|
35
|
+
children: [
|
|
36
|
+
{
|
|
37
|
+
type: "execution",
|
|
38
|
+
title: "视图切换",
|
|
39
|
+
requirement: `WebUI 提供两种视图查看工作区:
|
|
40
|
+
- **列表视图**:树形结构,适合查看层级关系
|
|
41
|
+
- **图形视图**:可视化节点图,适合把握全局
|
|
42
|
+
|
|
43
|
+
可在左侧面板顶部切换视图模式。`,
|
|
44
|
+
targetStatus: "completed",
|
|
45
|
+
conclusion: "已了解两种视图的切换方式和适用场景",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: "execution",
|
|
49
|
+
title: "焦点功能",
|
|
50
|
+
requirement: `本节点已被设为焦点,注意观察:
|
|
51
|
+
- 左侧树中焦点节点有特殊标记(红色准星)
|
|
52
|
+
- AI 通过 context_get 获取焦点节点的完整上下文
|
|
53
|
+
- AI 可通过 context_focus 设置焦点节点`,
|
|
54
|
+
setFocus: true,
|
|
55
|
+
targetStatus: "completed",
|
|
56
|
+
conclusion: "焦点功能帮助 AI 聚焦当前工作节点",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: "execution",
|
|
60
|
+
title: "工作区详情",
|
|
61
|
+
requirement: `工作区包含以下全局信息:
|
|
62
|
+
- **Goal**:工作区目标,描述整体任务方向
|
|
63
|
+
- **Rules**:所有节点可见的工作规则,AI 执行时需遵守的约束
|
|
64
|
+
- **Docs**:全局文档,将在规划子节点时选择性传递
|
|
65
|
+
|
|
66
|
+
可在页面顶部「Detail」按钮查看详情。`,
|
|
67
|
+
targetStatus: "completed",
|
|
68
|
+
conclusion: "工作区详情包含全局配置信息",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "execution",
|
|
72
|
+
title: "数据刷新",
|
|
73
|
+
requirement: `WebUI 提供两种刷新方式:
|
|
74
|
+
- **自动刷新**:页面每 5 秒自动刷新一次
|
|
75
|
+
- **手动刷新**:点击「刷新」按钮立即更新
|
|
76
|
+
|
|
77
|
+
刷新可获取 AI 的最新操作结果。`,
|
|
78
|
+
targetStatus: "completed",
|
|
79
|
+
conclusion: "刷新机制确保 WebUI 与后端数据同步",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: "execution",
|
|
83
|
+
title: "数据管理",
|
|
84
|
+
requirement: `管理工作区索引和全局备份。
|
|
85
|
+
|
|
86
|
+
**工作区索引**
|
|
87
|
+
设置 → 数据管理 → 工作区索引 → 管理
|
|
88
|
+
- 拖拽 .twsp 文件直接导入
|
|
89
|
+
- 拖拽项目目录自动扫描
|
|
90
|
+
- 手动输入路径
|
|
91
|
+
- 同步清理无效条目
|
|
92
|
+
|
|
93
|
+
**导出工作区**
|
|
94
|
+
工作区详情页 →「EXPORT」按钮
|
|
95
|
+
- 导出为 .twsp 文件,包含完整工作区数据
|
|
96
|
+
|
|
97
|
+
**全局备份**
|
|
98
|
+
设置 → 数据管理 → 全局备份 → 管理
|
|
99
|
+
- 创建/恢复/删除备份
|
|
100
|
+
- 导入/导出 .twbak 备份文件
|
|
101
|
+
- 备份仅包含全局索引配置,不含工作区内容`,
|
|
102
|
+
targetStatus: "completed",
|
|
103
|
+
conclusion: "通过数据管理可以导入导出工作区和管理全局备份",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
type: "execution",
|
|
107
|
+
title: "置顶功能",
|
|
108
|
+
requirement: `工作区支持置顶功能,将重要工作区固定在列表顶部:
|
|
109
|
+
|
|
110
|
+
- **悬浮显示**:鼠标悬浮卡片时,标题右侧显示 \`>PIN\` 徽派
|
|
111
|
+
- **点击置顶**:点击徽派后变为红色 \`PIN\` 常驻显示
|
|
112
|
+
- **再次点击**:点击红色 \`PIN\` 取消置顶
|
|
113
|
+
- **排序优先**:置顶工作区始终排在最前,不受排序方式影响
|
|
114
|
+
|
|
115
|
+
功能简介和版本更新工作区默认置顶,方便快速访问。`,
|
|
116
|
+
targetStatus: "completed",
|
|
117
|
+
conclusion: "置顶功能帮助快速访问重要工作区",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
// 节点体系 - 规划节点
|
|
122
|
+
{
|
|
123
|
+
type: "planning",
|
|
124
|
+
title: "规划节点演示",
|
|
125
|
+
requirement: `规划节点用于分解复杂任务,可以创建子节点。
|
|
126
|
+
|
|
127
|
+
**状态流转:** pending → planning → monitoring → completed/cancelled
|
|
128
|
+
|
|
129
|
+
本节点处于 **monitoring** 状态,正在等待子节点完成。
|
|
130
|
+
当所有子节点完成后,可以点击「完成」汇总结论。`,
|
|
131
|
+
children: [
|
|
132
|
+
{
|
|
133
|
+
type: "planning",
|
|
134
|
+
title: "待规划节点",
|
|
135
|
+
requirement: `这是一个 **pending** 状态的规划节点。
|
|
136
|
+
|
|
137
|
+
任务尚未开始规划,AI 获取此节点后将分析任务并创建子节点。`,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: "planning",
|
|
141
|
+
title: "规划中节点",
|
|
142
|
+
requirement: `这是一个 **planning** 状态的规划节点。
|
|
143
|
+
|
|
144
|
+
AI 正在分析任务、设计方案,完成后将创建子节点进入 monitoring 状态。`,
|
|
145
|
+
targetStatus: "planning",
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "planning",
|
|
149
|
+
title: "已完成的规划",
|
|
150
|
+
requirement: `这是一个已完成的规划节点。
|
|
151
|
+
|
|
152
|
+
完成规划节点时需要填写结论(Conclusion),总结子任务的执行结果。
|
|
153
|
+
结论会显示在父节点的「Child Conclusions」区域。`,
|
|
154
|
+
targetStatus: "completed",
|
|
155
|
+
conclusion: "演示规划节点的完成状态,结论会向上汇报给父节点",
|
|
156
|
+
children: [
|
|
157
|
+
{
|
|
158
|
+
type: "execution",
|
|
159
|
+
title: "已完成子任务",
|
|
160
|
+
requirement: "这是已完成规划下的子任务",
|
|
161
|
+
targetStatus: "completed",
|
|
162
|
+
conclusion: "子任务执行完毕",
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: "planning",
|
|
168
|
+
title: "已取消的规划",
|
|
169
|
+
requirement: `这是一个已取消的规划节点。
|
|
170
|
+
|
|
171
|
+
当 AI 判断任务不再需要执行时,会取消规划并填写结论说明原因。`,
|
|
172
|
+
targetStatus: "cancelled",
|
|
173
|
+
conclusion: "演示规划节点的取消状态",
|
|
174
|
+
children: [
|
|
175
|
+
{
|
|
176
|
+
type: "execution",
|
|
177
|
+
title: "被跳过的任务",
|
|
178
|
+
requirement: "父节点取消后,子任务也不再执行",
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
// 节点体系 - 执行节点
|
|
185
|
+
{
|
|
186
|
+
type: "planning",
|
|
187
|
+
title: "执行节点演示",
|
|
188
|
+
requirement: `执行节点用于具体任务执行,不能有子节点。
|
|
189
|
+
|
|
190
|
+
**状态流转:** pending → implementing → validating → completed/failed
|
|
191
|
+
|
|
192
|
+
同一父节点下同时只能有一个节点在执行状态。
|
|
193
|
+
|
|
194
|
+
**文档引用**
|
|
195
|
+
规划子节点时可以从全局文档中选择性分发给子节点。
|
|
196
|
+
本规划节点引用了演示文档,查看「Docs」区域可以看到引用列表。`,
|
|
197
|
+
docs: [
|
|
198
|
+
{ path: "README.md", description: "项目说明文档(演示用)" },
|
|
199
|
+
],
|
|
200
|
+
children: [
|
|
201
|
+
{
|
|
202
|
+
type: "execution",
|
|
203
|
+
title: "待执行",
|
|
204
|
+
requirement: `这是一个 **pending** 状态的执行节点。
|
|
205
|
+
|
|
206
|
+
任务尚未开始,AI 获取此节点后将开始执行。`,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
type: "planning",
|
|
210
|
+
title: "执行中状态",
|
|
211
|
+
requirement: `这是一个包含执行中任务的规划节点。
|
|
212
|
+
|
|
213
|
+
子节点正在 **implementing** 状态(蓝白斜纹图标)。`,
|
|
214
|
+
children: [
|
|
215
|
+
{
|
|
216
|
+
type: "execution",
|
|
217
|
+
title: "正在执行",
|
|
218
|
+
requirement: `这是一个 **implementing** 状态的执行节点。
|
|
219
|
+
|
|
220
|
+
任务正在执行中,完成后 AI 将提交验证或直接完成任务。`,
|
|
221
|
+
targetStatus: "implementing",
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
type: "planning",
|
|
227
|
+
title: "验证中状态",
|
|
228
|
+
requirement: `这是一个包含验证中任务的规划节点。
|
|
229
|
+
|
|
230
|
+
子节点正在 **validating** 状态(橙色图标)。`,
|
|
231
|
+
children: [
|
|
232
|
+
{
|
|
233
|
+
type: "execution",
|
|
234
|
+
title: "等待验证",
|
|
235
|
+
requirement: `这是一个 **validating** 状态的执行节点。
|
|
236
|
+
|
|
237
|
+
任务已提交验证,AI 将根据验证结果决定完成或标记失败。`,
|
|
238
|
+
targetStatus: "validating",
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
type: "execution",
|
|
244
|
+
title: "已完成",
|
|
245
|
+
requirement: `这是一个 **completed** 状态的执行节点。
|
|
246
|
+
|
|
247
|
+
任务已完成,结论会显示在父节点的「Child Conclusions」区域。
|
|
248
|
+
|
|
249
|
+
**备注(Note)**
|
|
250
|
+
节点可以记录备注信息,用于临时笔记、补充说明等。
|
|
251
|
+
本节点的备注区域有演示内容。`,
|
|
252
|
+
targetStatus: "completed",
|
|
253
|
+
conclusion: "执行节点完成后的结论示例",
|
|
254
|
+
note: "这是一个演示用的备注内容。备注可以记录任务执行过程中的临时笔记、补充信息等。",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
type: "execution",
|
|
258
|
+
title: "已失败",
|
|
259
|
+
requirement: `这是一个 **failed** 状态的执行节点。
|
|
260
|
+
|
|
261
|
+
任务执行失败,AI 可以根据失败原因决定是否重试。
|
|
262
|
+
|
|
263
|
+
**问题(Problem)**
|
|
264
|
+
节点可以记录当前遇到的障碍或待解决事项。
|
|
265
|
+
AI 会在执行时关注问题内容,本节点的问题区域有演示内容。`,
|
|
266
|
+
targetStatus: "failed",
|
|
267
|
+
conclusion: "失败原因:演示失败状态",
|
|
268
|
+
problem: "这是一个演示用的问题内容,实际使用时会记录具体的障碍或待解决事项。",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
type: "execution",
|
|
272
|
+
title: "信息收集节点",
|
|
273
|
+
requirement: `这是一个特殊角色的执行节点:**信息收集 (info_collection)**
|
|
274
|
+
|
|
275
|
+
信息收集节点用于需求澄清、调研分析、方案评审等场景。
|
|
276
|
+
在树视图中节点标签后显示 INFO 标牌,便于快速识别。
|
|
277
|
+
|
|
278
|
+
**MEMO 功能**
|
|
279
|
+
本节点创建了一个 MEMO,用于记录长篇内容。点击「References」区域查看引用。`,
|
|
280
|
+
role: "info_collection",
|
|
281
|
+
targetStatus: "completed",
|
|
282
|
+
conclusion: "信息收集节点适合需求澄清和调研分析",
|
|
283
|
+
note: "短内容用 Note,长内容用 MEMO",
|
|
284
|
+
memo: {
|
|
285
|
+
title: "MEMO 功能说明",
|
|
286
|
+
summary: "演示 MEMO 的使用方式和适用场景",
|
|
287
|
+
tags: ["功能演示", "MEMO"],
|
|
288
|
+
content: `# MEMO 功能说明
|
|
289
|
+
|
|
290
|
+
## 什么是 MEMO
|
|
291
|
+
|
|
292
|
+
MEMO 是节点级的长篇内容记录功能,适合存储:
|
|
293
|
+
- 技术调研笔记
|
|
294
|
+
- 方案设计文档
|
|
295
|
+
- 会议记录
|
|
296
|
+
- 知识沉淀
|
|
297
|
+
|
|
298
|
+
## MEMO的特点
|
|
299
|
+
- 独立存储且可被节点引用
|
|
300
|
+
- 方便临时记录再后续分析
|
|
301
|
+
|
|
302
|
+
## 与 Note 的区别
|
|
303
|
+
|
|
304
|
+
| 特性 | Note(备注) | MEMO |
|
|
305
|
+
|------|-------------|------|
|
|
306
|
+
| 长度 | 短文本 | 长篇内容 |
|
|
307
|
+
| 显示 | 直接展示 | 独立标签页 |
|
|
308
|
+
| 关系 | 绑定节点 | 独立存储且可被节点引用 |
|
|
309
|
+
|
|
310
|
+
## 使用方法
|
|
311
|
+
|
|
312
|
+
在对话中告知AI使用memo创建草稿/总结上文/跟进讨论
|
|
313
|
+
|
|
314
|
+
## 导出功能
|
|
315
|
+
|
|
316
|
+
MEMO 支持导出为独立 Markdown 文件,点击详情页「下载」按钮即可导出。
|
|
317
|
+
`,
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
},
|
|
322
|
+
// 日志系统
|
|
323
|
+
{
|
|
324
|
+
type: "execution",
|
|
325
|
+
title: "日志系统",
|
|
326
|
+
requirement: `每个节点都有操作日志,记录任务执行过程。
|
|
327
|
+
|
|
328
|
+
查看下方「Log」区域,可以看到:
|
|
329
|
+
- 状态变更记录
|
|
330
|
+
- 操作者标识(AI / Human)
|
|
331
|
+
- 时间戳
|
|
332
|
+
|
|
333
|
+
日志用于追踪任务执行过程、问题排查和复盘。`,
|
|
334
|
+
logs: [
|
|
335
|
+
{ operator: "AI", event: "开始执行任务" },
|
|
336
|
+
{ operator: "AI", event: "分析需求完成" },
|
|
337
|
+
{ operator: "Human", event: "补充了额外的需求说明" },
|
|
338
|
+
{ operator: "AI", event: "根据补充需求调整方案" },
|
|
339
|
+
{ operator: "AI", event: "任务执行完成" },
|
|
340
|
+
],
|
|
341
|
+
targetStatus: "completed",
|
|
342
|
+
conclusion: "日志记录了完整的任务执行过程",
|
|
343
|
+
},
|
|
344
|
+
// 手动变更
|
|
345
|
+
{
|
|
346
|
+
type: "execution",
|
|
347
|
+
title: "手动变更",
|
|
348
|
+
requirement: `这是一个演示 **validating** 状态的节点。
|
|
349
|
+
|
|
350
|
+
任务正在等待验证,AI 将根据验证结果决定后续操作。
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
**关于手动操作**
|
|
355
|
+
|
|
356
|
+
在特殊情况下(如 AI 不在线、需要紧急干预),可以通过 WebUI 进行手动操作:
|
|
357
|
+
|
|
358
|
+
- **手动变更标记**:WebUI 编辑后会显示标记,AI 读取时自动清除
|
|
359
|
+
- **协作建议**:避免与 AI 同时操作同一节点,如有冲突以最新保存为准`,
|
|
360
|
+
targetStatus: "validating",
|
|
361
|
+
},
|
|
362
|
+
// 派发模式
|
|
363
|
+
{
|
|
364
|
+
type: "planning",
|
|
365
|
+
title: "派发模式",
|
|
366
|
+
requirement: `派发模式用于自动化任务执行流程。
|
|
367
|
+
|
|
368
|
+
**工作流程**
|
|
369
|
+
1. AI 规划完成一阶段任务
|
|
370
|
+
2. 按照逻辑循序,逐步准备待派发的细分任务需求和验收标准
|
|
371
|
+
3. 将任务使用 SubAgent 进行派发,其具有明确的任务需求与完成单个任务的信息
|
|
372
|
+
4. 完成后,SubAgent 将信息结论写入派发节点,并将控制权转回主 AI
|
|
373
|
+
5. 在执行中,SubAgent 自行判断提供的信息与任务规模,在超出能力范围时将主动设置失败以让主 AI 重新规划
|
|
374
|
+
|
|
375
|
+
**注意**:派发模式默认关闭,需要用户主动提出启用或在 WebUI 手动开启。`,
|
|
376
|
+
children: [
|
|
377
|
+
{
|
|
378
|
+
type: "execution",
|
|
379
|
+
title: "派发控制",
|
|
380
|
+
requirement: `派发模式需要主动启用才能生效。
|
|
381
|
+
|
|
382
|
+
**如何启用**
|
|
383
|
+
- 用户主动提出为项目开启派发模式
|
|
384
|
+
- 或在 WebUI 工作区详情中手动启用
|
|
385
|
+
|
|
386
|
+
**默认行为**
|
|
387
|
+
- 项目默认关闭派发模式
|
|
388
|
+
- 可在全局设置中修改默认派发模式
|
|
389
|
+
|
|
390
|
+
**WebUI 显示**
|
|
391
|
+
- 「Dispatch: none」表示未启用
|
|
392
|
+
- 「Dispatch: no-git」或「git」表示已启用`,
|
|
393
|
+
},
|
|
394
|
+
// 无派发模式必须在最后(implementing 状态会阻止后续节点状态转换)
|
|
395
|
+
{
|
|
396
|
+
type: "planning",
|
|
397
|
+
title: "启用派发",
|
|
398
|
+
requirement: `派发分为两种模式:**默认派发** 和 **Git 派发**。
|
|
399
|
+
|
|
400
|
+
两种模式各有适用场景,建议根据任务性质选择。
|
|
401
|
+
|
|
402
|
+
**重要提示**:不建议在任务进行中切换派发模式,可能导致状态不一致。`,
|
|
403
|
+
children: [
|
|
404
|
+
{
|
|
405
|
+
type: "execution",
|
|
406
|
+
title: "默认派发",
|
|
407
|
+
requirement: `**推荐模式** - 自动化任务流转
|
|
408
|
+
|
|
409
|
+
使用场景:
|
|
410
|
+
- 日常开发任务
|
|
411
|
+
- 文档编写
|
|
412
|
+
- 已细化的大型任务
|
|
413
|
+
|
|
414
|
+
特点:
|
|
415
|
+
- 自动分配下一个待执行节点
|
|
416
|
+
- 任务完成后自动流转到下一个
|
|
417
|
+
- 不涉及 Git 操作,简单快速`,
|
|
418
|
+
targetStatus: "completed",
|
|
419
|
+
conclusion: "默认派发适合大多数日常任务",
|
|
420
|
+
dispatchInfo: {
|
|
421
|
+
status: "passed",
|
|
422
|
+
startMarker: "2025-12-21T19:30:00.000Z",
|
|
423
|
+
endMarker: "2025-12-21T19:45:00.000Z",
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
type: "execution",
|
|
428
|
+
title: "Git 派发",
|
|
429
|
+
requirement: `**代码隔离模式** - 实验性功能
|
|
430
|
+
|
|
431
|
+
使用场景:
|
|
432
|
+
- 复杂代码修改任务
|
|
433
|
+
- 可能失败需要回滚的操作
|
|
434
|
+
- 需要版本控制的变更
|
|
435
|
+
|
|
436
|
+
工作原理:
|
|
437
|
+
1. 创建独立 Git 分支
|
|
438
|
+
2. 在分支上执行任务
|
|
439
|
+
3. 所有任务完成后根据用户需要进行分支操作
|
|
440
|
+
4. 失败时可丢弃分支回滚
|
|
441
|
+
|
|
442
|
+
要求:项目必须是 Git 仓库`,
|
|
443
|
+
targetStatus: "validating",
|
|
444
|
+
problem: "此功能为实验性功能,请注意 AI 行为,避免信息丢失。建议在使用前确保代码已提交。",
|
|
445
|
+
logs: [
|
|
446
|
+
{ operator: "AI", event: "创建分支 zero/task-xxx" },
|
|
447
|
+
{ operator: "AI", event: "执行任务" },
|
|
448
|
+
{ operator: "AI", event: "任务完成,等待验证" },
|
|
449
|
+
],
|
|
450
|
+
dispatchInfo: {
|
|
451
|
+
status: "testing",
|
|
452
|
+
startMarker: "abc1234",
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
],
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
type: "execution",
|
|
459
|
+
title: "无派发模式",
|
|
460
|
+
requirement: `**手动管理模式** - 项目默认状态
|
|
461
|
+
|
|
462
|
+
使用场景:
|
|
463
|
+
- 探索性任务,不确定下一步做什么
|
|
464
|
+
- 需要逐个审核每个节点的执行结果
|
|
465
|
+
|
|
466
|
+
AI 需要自行管理状态切换,并选择下一个要执行的节点。
|
|
467
|
+
|
|
468
|
+
本节点正在模拟手动执行中的状态。`,
|
|
469
|
+
targetStatus: "implementing",
|
|
470
|
+
logs: [
|
|
471
|
+
{ operator: "AI", event: "手动选择任务开始执行" },
|
|
472
|
+
{ operator: "AI", event: "正在执行任务..." },
|
|
473
|
+
],
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
],
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* 教程服务
|
|
481
|
+
* 负责创建新手教程工作区
|
|
482
|
+
*/
|
|
483
|
+
export class TutorialService {
|
|
484
|
+
workspace;
|
|
485
|
+
node;
|
|
486
|
+
state;
|
|
487
|
+
log;
|
|
488
|
+
context;
|
|
489
|
+
reference;
|
|
490
|
+
dispatch;
|
|
491
|
+
config;
|
|
492
|
+
memo;
|
|
493
|
+
constructor(workspace, node, state, log, context, reference, dispatch, config, memo) {
|
|
494
|
+
this.workspace = workspace;
|
|
495
|
+
this.node = node;
|
|
496
|
+
this.state = state;
|
|
497
|
+
this.log = log;
|
|
498
|
+
this.context = context;
|
|
499
|
+
this.reference = reference;
|
|
500
|
+
this.dispatch = dispatch;
|
|
501
|
+
this.config = config;
|
|
502
|
+
this.memo = memo;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* 获取教程目录路径
|
|
506
|
+
*/
|
|
507
|
+
getTutorialDir() {
|
|
508
|
+
const isDev = process.env.NODE_ENV === "development" || process.env.ZERO_DEV === "true";
|
|
509
|
+
const baseDir = isDev ? ".zero-workspace-dev" : ".zero-workspace";
|
|
510
|
+
return path.join(os.homedir(), baseDir, "tutorial");
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* 检查并创建教程工作区和版本更新工作区
|
|
514
|
+
* - 教程工作区:只创建一次(通过 tutorialCreated 标记)
|
|
515
|
+
* - 版本更新工作区:版本变更时创建(如果不存在)
|
|
516
|
+
*/
|
|
517
|
+
async ensureTutorial() {
|
|
518
|
+
const currentConfig = await this.config.readConfig();
|
|
519
|
+
let needsConfigUpdate = false;
|
|
520
|
+
const configUpdates = {};
|
|
521
|
+
// 1. 检查是否需要创建教程工作区(只创建一次)
|
|
522
|
+
if (!currentConfig.tutorialCreated) {
|
|
523
|
+
try {
|
|
524
|
+
await this.createTutorialWorkspace();
|
|
525
|
+
configUpdates.tutorialCreated = true;
|
|
526
|
+
configUpdates.tutorialVersion = TUTORIAL_VERSION;
|
|
527
|
+
needsConfigUpdate = true;
|
|
528
|
+
}
|
|
529
|
+
catch (err) {
|
|
530
|
+
console.error("[Tutorial] Failed to create tutorial workspace:", err);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
// 2. 检查是否需要创建版本更新工作区
|
|
534
|
+
const oldVersion = currentConfig.tutorialVersion;
|
|
535
|
+
if (oldVersion !== TUTORIAL_VERSION) {
|
|
536
|
+
try {
|
|
537
|
+
// 对于老用户升级,显示所有版本差异
|
|
538
|
+
await this.ensureVersionUpdateWorkspace(oldVersion, false);
|
|
539
|
+
configUpdates.tutorialVersion = TUTORIAL_VERSION;
|
|
540
|
+
needsConfigUpdate = true;
|
|
541
|
+
}
|
|
542
|
+
catch (err) {
|
|
543
|
+
console.error("[Tutorial] Failed to create version update workspace:", err);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
// 3. 更新配置
|
|
547
|
+
if (needsConfigUpdate) {
|
|
548
|
+
await this.config.writeConfig({
|
|
549
|
+
...currentConfig,
|
|
550
|
+
...configUpdates,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
return needsConfigUpdate;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* 手动触发创建教程工作区(覆盖模式)
|
|
557
|
+
* 删除现有工作区后重新创建
|
|
558
|
+
*/
|
|
559
|
+
async manualTriggerTutorial() {
|
|
560
|
+
const tutorialDir = this.getTutorialDir();
|
|
561
|
+
const existingWorkspaces = await this.workspace.list({});
|
|
562
|
+
// 查找并删除现有工作区
|
|
563
|
+
const introWs = existingWorkspaces.workspaces.find(ws => ws.name === "ZeroWorkspace 功能简介" && ws.projectRoot === tutorialDir);
|
|
564
|
+
const versionWs = existingWorkspaces.workspaces.find(ws => ws.name === "ZeroWorkspace 版本更新" && ws.projectRoot === tutorialDir);
|
|
565
|
+
// 删除现有工作区
|
|
566
|
+
if (introWs) {
|
|
567
|
+
await this.workspace.delete({ workspaceId: introWs.id, force: true });
|
|
568
|
+
}
|
|
569
|
+
if (versionWs) {
|
|
570
|
+
await this.workspace.delete({ workspaceId: versionWs.id, force: true });
|
|
571
|
+
}
|
|
572
|
+
// 重新创建工作区
|
|
573
|
+
await this.createTutorialWorkspace();
|
|
574
|
+
await this.createVersionUpdateWorkspace(undefined, true);
|
|
575
|
+
// 更新配置
|
|
576
|
+
const currentConfig = await this.config.readConfig();
|
|
577
|
+
await this.config.writeConfig({
|
|
578
|
+
...currentConfig,
|
|
579
|
+
tutorialCreated: true,
|
|
580
|
+
tutorialVersion: TUTORIAL_VERSION,
|
|
581
|
+
});
|
|
582
|
+
return { created: true, message: "已重新生成功能简介与版本更新记录" };
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* 确保版本更新工作区存在
|
|
586
|
+
* 如果不存在则创建,存在则添加新版本节点
|
|
587
|
+
* @param oldVersion 旧版本号(用于筛选需要显示的版本)
|
|
588
|
+
* @param fullHistory 是否显示完整历史(手动触发时为 true)
|
|
589
|
+
*/
|
|
590
|
+
async ensureVersionUpdateWorkspace(oldVersion, fullHistory = false) {
|
|
591
|
+
const tutorialDir = this.getTutorialDir();
|
|
592
|
+
await fs.mkdir(tutorialDir, { recursive: true });
|
|
593
|
+
// 检查是否已存在版本更新工作区
|
|
594
|
+
const existingWorkspaces = await this.workspace.list({});
|
|
595
|
+
const versionWs = existingWorkspaces.workspaces.find(ws => ws.name === "ZeroWorkspace 版本更新" && ws.projectRoot === tutorialDir);
|
|
596
|
+
if (versionWs) {
|
|
597
|
+
// 已存在,添加新版本节点
|
|
598
|
+
await this.addVersionNodes(versionWs.id, oldVersion, fullHistory);
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
// 创建新的版本更新工作区
|
|
602
|
+
await this.createVersionUpdateWorkspace(oldVersion, fullHistory);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* 读取版本说明文件
|
|
607
|
+
* 向后兼容:优先尝试 assets/,回退到 docs/
|
|
608
|
+
*/
|
|
609
|
+
async readVersionNotes() {
|
|
610
|
+
// 使用模块相对路径,避免 process.cwd() 在不同启动目录下的问题
|
|
611
|
+
const paths = [
|
|
612
|
+
path.join(__dirname, "../../config/version-notes.yaml"),
|
|
613
|
+
path.join(__dirname, "../../assets/version-notes.yaml"), // 向后兼容旧目录
|
|
614
|
+
];
|
|
615
|
+
for (const notesPath of paths) {
|
|
616
|
+
try {
|
|
617
|
+
const content = await fs.readFile(notesPath, "utf-8");
|
|
618
|
+
const data = YAML.parse(content);
|
|
619
|
+
return data.versions || [];
|
|
620
|
+
}
|
|
621
|
+
catch {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return [];
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* 比较版本号,返回 1 如果 a > b,-1 如果 a < b,0 如果相等
|
|
629
|
+
*/
|
|
630
|
+
compareVersions(a, b) {
|
|
631
|
+
const pa = a.split(".").map(Number);
|
|
632
|
+
const pb = b.split(".").map(Number);
|
|
633
|
+
for (let i = 0; i < 3; i++) {
|
|
634
|
+
if (pa[i] > pb[i])
|
|
635
|
+
return 1;
|
|
636
|
+
if (pa[i] < pb[i])
|
|
637
|
+
return -1;
|
|
638
|
+
}
|
|
639
|
+
return 0;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* 获取版本的 major.minor
|
|
643
|
+
*/
|
|
644
|
+
getMajorMinor(version) {
|
|
645
|
+
const [major, minor] = version.split(".");
|
|
646
|
+
return `${major}.${minor}`;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* 判断是否是 major/minor 版本 (x.y.0)
|
|
650
|
+
*/
|
|
651
|
+
isMajorMinorVersion(version) {
|
|
652
|
+
return version.endsWith(".0");
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* 筛选并分组版本
|
|
656
|
+
* @param versions 所有版本数据
|
|
657
|
+
* @param oldVersion 旧版本号(用于筛选升级用户需要看到的版本)
|
|
658
|
+
* @param fullHistory 是否显示完整历史(true: 手动触发,false: 自动创建时限制为3个大版本)
|
|
659
|
+
*/
|
|
660
|
+
groupVersions(versions, oldVersion, fullHistory = false) {
|
|
661
|
+
// 筛选 oldVersion < v <= currentVersion 的版本
|
|
662
|
+
let filtered = versions.filter(v => {
|
|
663
|
+
const gtOld = !oldVersion || this.compareVersions(v.version, oldVersion) > 0;
|
|
664
|
+
const leqCurrent = this.compareVersions(v.version, TUTORIAL_VERSION) <= 0;
|
|
665
|
+
return gtOld && leqCurrent;
|
|
666
|
+
});
|
|
667
|
+
// 如果不是完整历史模式,且 oldVersion 为 undefined(新用户),则只显示最近 3 个大版本
|
|
668
|
+
if (!fullHistory && oldVersion === undefined) {
|
|
669
|
+
// 获取所有不同的 major.minor 版本
|
|
670
|
+
const majorMinors = new Set();
|
|
671
|
+
for (const v of filtered) {
|
|
672
|
+
majorMinors.add(this.getMajorMinor(v.version));
|
|
673
|
+
}
|
|
674
|
+
// 按版本号排序(降序)
|
|
675
|
+
const sortedMM = Array.from(majorMinors).sort((a, b) => {
|
|
676
|
+
const [aMajor, aMinor] = a.split(".").map(Number);
|
|
677
|
+
const [bMajor, bMinor] = b.split(".").map(Number);
|
|
678
|
+
if (aMajor !== bMajor)
|
|
679
|
+
return bMajor - aMajor;
|
|
680
|
+
return bMinor - aMinor;
|
|
681
|
+
});
|
|
682
|
+
// 只保留最近 3 个大版本
|
|
683
|
+
const recentMM = new Set(sortedMM.slice(0, 3));
|
|
684
|
+
filtered = filtered.filter(v => recentMM.has(this.getMajorMinor(v.version)));
|
|
685
|
+
}
|
|
686
|
+
// 按 major.minor 分组
|
|
687
|
+
const groups = new Map();
|
|
688
|
+
for (const v of filtered) {
|
|
689
|
+
const mm = this.getMajorMinor(v.version);
|
|
690
|
+
if (!groups.has(mm)) {
|
|
691
|
+
groups.set(mm, { major: null, patches: [], hasMinorStart: false });
|
|
692
|
+
}
|
|
693
|
+
const group = groups.get(mm);
|
|
694
|
+
if (this.isMajorMinorVersion(v.version)) {
|
|
695
|
+
group.major = v;
|
|
696
|
+
group.hasMinorStart = true;
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
group.patches.push(v);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
// 按 patch 版本号排序(降序,新版本在前)
|
|
703
|
+
for (const group of groups.values()) {
|
|
704
|
+
group.patches.sort((a, b) => this.compareVersions(b.version, a.version));
|
|
705
|
+
}
|
|
706
|
+
return groups;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* 创建版本更新工作区
|
|
710
|
+
* @param oldVersion 旧版本号
|
|
711
|
+
* @param fullHistory 是否显示完整历史
|
|
712
|
+
*/
|
|
713
|
+
async createVersionUpdateWorkspace(oldVersion, fullHistory = false) {
|
|
714
|
+
const tutorialDir = this.getTutorialDir();
|
|
715
|
+
const result = await this.workspace.init({
|
|
716
|
+
name: "ZeroWorkspace 版本更新",
|
|
717
|
+
goal: `查看 ZeroWorkspace 版本更新内容`,
|
|
718
|
+
projectRoot: tutorialDir,
|
|
719
|
+
rules: ["这是版本更新说明工作区,记录各版本的功能变更"],
|
|
720
|
+
});
|
|
721
|
+
await this.addVersionNodes(result.workspaceId, oldVersion, fullHistory);
|
|
722
|
+
// 置顶版本更新工作区,方便用户快速访问(失败不阻断主流程)
|
|
723
|
+
try {
|
|
724
|
+
await this.workspace.togglePin(result.workspaceId);
|
|
725
|
+
}
|
|
726
|
+
catch {
|
|
727
|
+
// 置顶是辅助功能,失败时静默忽略
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* 查找已存在的 major.minor 规划节点
|
|
732
|
+
* @returns Map<majorMinor, nodeId>
|
|
733
|
+
*/
|
|
734
|
+
async findExistingMajorNodes(workspaceId) {
|
|
735
|
+
const result = new Map();
|
|
736
|
+
try {
|
|
737
|
+
const rootNode = await this.node.get({ workspaceId, nodeId: "root" });
|
|
738
|
+
for (const childId of rootNode.meta.children) {
|
|
739
|
+
const child = await this.node.get({ workspaceId, nodeId: childId });
|
|
740
|
+
// 从 dirName 中提取版本号,格式如 "V1.9 版本更新_mjmqarcp"
|
|
741
|
+
const match = child.meta.dirName?.match(/V(\d+\.\d+)/);
|
|
742
|
+
if (match) {
|
|
743
|
+
result.set(match[1], childId);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
catch {
|
|
748
|
+
// 如果获取失败,返回空映射
|
|
749
|
+
}
|
|
750
|
+
return result;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* 添加版本节点到工作区
|
|
754
|
+
* @param workspaceId 工作区ID
|
|
755
|
+
* @param oldVersion 旧版本号
|
|
756
|
+
* @param fullHistory 是否显示完整历史
|
|
757
|
+
*/
|
|
758
|
+
async addVersionNodes(workspaceId, oldVersion, fullHistory = false) {
|
|
759
|
+
const versions = await this.readVersionNotes();
|
|
760
|
+
const groups = this.groupVersions(versions, oldVersion, fullHistory);
|
|
761
|
+
if (groups.size === 0) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
// 按 major.minor 版本号排序(降序,新版本在前)
|
|
765
|
+
const sortedMajorMinors = Array.from(groups.keys()).sort((a, b) => {
|
|
766
|
+
const [aMajor, aMinor] = a.split(".").map(Number);
|
|
767
|
+
const [bMajor, bMinor] = b.split(".").map(Number);
|
|
768
|
+
if (aMajor !== bMajor)
|
|
769
|
+
return bMajor - aMajor;
|
|
770
|
+
return bMinor - aMinor;
|
|
771
|
+
});
|
|
772
|
+
let latestNodeId = null; // 记录最新版本节点 ID
|
|
773
|
+
let rootReopened = false; // 标记是否已 reopen 根节点
|
|
774
|
+
// 预先获取已存在的 major.minor 节点映射
|
|
775
|
+
const existingMajorNodes = await this.findExistingMajorNodes(workspaceId);
|
|
776
|
+
for (const mm of sortedMajorMinors) {
|
|
777
|
+
// 如果根节点已完成,需要先 reopen 才能添加新子节点
|
|
778
|
+
if (!rootReopened) {
|
|
779
|
+
const rootNode = await this.node.get({ workspaceId, nodeId: "root" });
|
|
780
|
+
if (rootNode.meta.status === "completed") {
|
|
781
|
+
await this.state.transition({
|
|
782
|
+
workspaceId,
|
|
783
|
+
nodeId: "root",
|
|
784
|
+
action: "reopen",
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
rootReopened = true;
|
|
788
|
+
}
|
|
789
|
+
const group = groups.get(mm);
|
|
790
|
+
// 检查是否已存在对应的 major.minor 节点
|
|
791
|
+
let majorNodeId;
|
|
792
|
+
let isExistingNode = false;
|
|
793
|
+
if (existingMajorNodes.has(mm)) {
|
|
794
|
+
// 使用已存在的节点
|
|
795
|
+
majorNodeId = existingMajorNodes.get(mm);
|
|
796
|
+
isExistingNode = true;
|
|
797
|
+
// 如果节点已完成,需要先 reopen 才能添加子节点
|
|
798
|
+
const existingNode = await this.node.get({ workspaceId, nodeId: majorNodeId });
|
|
799
|
+
if (existingNode.meta.status === "completed") {
|
|
800
|
+
await this.state.transition({
|
|
801
|
+
workspaceId,
|
|
802
|
+
nodeId: majorNodeId,
|
|
803
|
+
action: "reopen",
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
// 创建新的 major.minor 规划节点
|
|
809
|
+
// 从完整版本列表中获取该 minor 的所有版本(包括 x.y.0)
|
|
810
|
+
const allMinorVersions = versions.filter(v => this.getMajorMinor(v.version) === mm);
|
|
811
|
+
const minorStartVersion = allMinorVersions.find(v => this.isMajorMinorVersion(v.version));
|
|
812
|
+
let majorRequirement;
|
|
813
|
+
let majorNote;
|
|
814
|
+
if (minorStartVersion) {
|
|
815
|
+
// 使用 x.y.0 版本的信息作为父节点内容
|
|
816
|
+
majorRequirement = minorStartVersion.requirement || `v${mm} 版本更新`;
|
|
817
|
+
majorNote = minorStartVersion.note;
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
// 兜底:没有 x.y.0 版本时使用默认文案
|
|
821
|
+
majorRequirement = `v${mm} 版本更新`;
|
|
822
|
+
}
|
|
823
|
+
// 更新 group,包含该 minor 的所有版本
|
|
824
|
+
group.patches = allMinorVersions
|
|
825
|
+
.filter(v => !this.isMajorMinorVersion(v.version))
|
|
826
|
+
.sort((a, b) => this.compareVersions(b.version, a.version));
|
|
827
|
+
group.major = minorStartVersion || null;
|
|
828
|
+
group.hasMinorStart = !!minorStartVersion;
|
|
829
|
+
const majorNodeResult = await this.node.create({
|
|
830
|
+
workspaceId,
|
|
831
|
+
parentId: "root",
|
|
832
|
+
type: "planning",
|
|
833
|
+
title: `V${mm} 版本更新`,
|
|
834
|
+
requirement: majorRequirement,
|
|
835
|
+
rulesHash: INTERNAL_RULES_HASH,
|
|
836
|
+
});
|
|
837
|
+
majorNodeId = majorNodeResult.nodeId;
|
|
838
|
+
// 如果有 note,设置到节点
|
|
839
|
+
if (majorNote) {
|
|
840
|
+
await this.node.update({
|
|
841
|
+
workspaceId,
|
|
842
|
+
nodeId: majorNodeId,
|
|
843
|
+
note: majorNote,
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
// 创建 patch 版本子节点
|
|
848
|
+
for (const patch of group.patches) {
|
|
849
|
+
// 需求:版本更新详情 + requirement
|
|
850
|
+
const patchRequirement = patch.requirement
|
|
851
|
+
? `V${patch.version} 版本更新详情:\n${patch.requirement}`
|
|
852
|
+
: `V${patch.version} 版本更新`;
|
|
853
|
+
const patchNodeResult = await this.node.create({
|
|
854
|
+
workspaceId,
|
|
855
|
+
parentId: majorNodeId,
|
|
856
|
+
type: "execution",
|
|
857
|
+
title: `V${patch.version} 版本更新`,
|
|
858
|
+
requirement: patchRequirement,
|
|
859
|
+
rulesHash: INTERNAL_RULES_HASH,
|
|
860
|
+
});
|
|
861
|
+
// 记录第一个(最新)节点 ID 用于设置 focus
|
|
862
|
+
if (!latestNodeId) {
|
|
863
|
+
latestNodeId = patchNodeResult.nodeId;
|
|
864
|
+
}
|
|
865
|
+
// 开始并完成节点
|
|
866
|
+
// 结论:使用 requirement(简洁描述,展示到父节点)
|
|
867
|
+
await this.state.transition({
|
|
868
|
+
workspaceId,
|
|
869
|
+
nodeId: patchNodeResult.nodeId,
|
|
870
|
+
action: "start",
|
|
871
|
+
});
|
|
872
|
+
await this.state.transition({
|
|
873
|
+
workspaceId,
|
|
874
|
+
nodeId: patchNodeResult.nodeId,
|
|
875
|
+
action: "complete",
|
|
876
|
+
conclusion: patch.requirement || "版本更新",
|
|
877
|
+
});
|
|
878
|
+
// 备注:changelog 内容
|
|
879
|
+
if (patch.conclusion) {
|
|
880
|
+
await this.node.update({
|
|
881
|
+
workspaceId,
|
|
882
|
+
nodeId: patchNodeResult.nodeId,
|
|
883
|
+
note: patch.conclusion,
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
// 如果有 major 版本自身(x.y.0),也作为子节点添加(仅新创建的节点需要)
|
|
888
|
+
if (!isExistingNode && group.major && group.hasMinorStart) {
|
|
889
|
+
// 需求:版本更新详情 + requirement
|
|
890
|
+
const majorVersionRequirement = group.major.requirement
|
|
891
|
+
? `V${group.major.version} 版本更新详情:\n${group.major.requirement}`
|
|
892
|
+
: `V${group.major.version} 版本发布`;
|
|
893
|
+
const majorVersionResult = await this.node.create({
|
|
894
|
+
workspaceId,
|
|
895
|
+
parentId: majorNodeId,
|
|
896
|
+
type: "execution",
|
|
897
|
+
title: `V${group.major.version} 版本更新`,
|
|
898
|
+
requirement: majorVersionRequirement,
|
|
899
|
+
rulesHash: INTERNAL_RULES_HASH,
|
|
900
|
+
});
|
|
901
|
+
// 结论:使用 requirement(简洁描述)
|
|
902
|
+
await this.state.transition({
|
|
903
|
+
workspaceId,
|
|
904
|
+
nodeId: majorVersionResult.nodeId,
|
|
905
|
+
action: "start",
|
|
906
|
+
});
|
|
907
|
+
await this.state.transition({
|
|
908
|
+
workspaceId,
|
|
909
|
+
nodeId: majorVersionResult.nodeId,
|
|
910
|
+
action: "complete",
|
|
911
|
+
conclusion: group.major.requirement || "版本发布",
|
|
912
|
+
});
|
|
913
|
+
// 备注:changelog 内容
|
|
914
|
+
if (group.major.conclusion) {
|
|
915
|
+
await this.node.update({
|
|
916
|
+
workspaceId,
|
|
917
|
+
nodeId: majorVersionResult.nodeId,
|
|
918
|
+
note: group.major.conclusion,
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
// 对 major.minor 节点的子节点按版本号降序排序(新版本在前)
|
|
923
|
+
const majorNode = await this.node.get({ workspaceId, nodeId: majorNodeId });
|
|
924
|
+
const patchChildIds = majorNode.meta.children;
|
|
925
|
+
if (patchChildIds.length > 1) {
|
|
926
|
+
const patchVersions = [];
|
|
927
|
+
for (const patchId of patchChildIds) {
|
|
928
|
+
const patchNode = await this.node.get({ workspaceId, nodeId: patchId });
|
|
929
|
+
// 从 dirName 中提取版本号,格式如 "V1.9.1 版本更新_mjoeaxds"
|
|
930
|
+
const match = patchNode.meta.dirName?.match(/V(\d+\.\d+\.\d+)/);
|
|
931
|
+
if (match) {
|
|
932
|
+
patchVersions.push({ id: patchId, version: match[1] });
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
// 按版本号降序排序
|
|
936
|
+
patchVersions.sort((a, b) => this.compareVersions(b.version, a.version));
|
|
937
|
+
const sortedPatchIds = patchVersions.map(p => p.id);
|
|
938
|
+
// 如果顺序有变化,重新排序
|
|
939
|
+
if (sortedPatchIds.length === patchChildIds.length &&
|
|
940
|
+
sortedPatchIds.some((id, i) => id !== patchChildIds[i])) {
|
|
941
|
+
await this.node.reorderChildren({
|
|
942
|
+
workspaceId,
|
|
943
|
+
nodeId: majorNodeId,
|
|
944
|
+
orderedChildIds: sortedPatchIds,
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
// 将 major 规划节点标记为已完成
|
|
949
|
+
// 由于添加子节点后,规划节点已自动进入 monitoring 状态
|
|
950
|
+
// 所有子节点已完成,可直接标记 complete
|
|
951
|
+
// 需要计算 conclusionsHash 以通过校验
|
|
952
|
+
const majorNodeForComplete = await this.node.get({ workspaceId, nodeId: majorNodeId });
|
|
953
|
+
const majorChildConclusions = [];
|
|
954
|
+
for (const childId of majorNodeForComplete.meta.children) {
|
|
955
|
+
const child = await this.node.get({ workspaceId, nodeId: childId });
|
|
956
|
+
majorChildConclusions.push({ nodeId: childId, conclusion: child.meta.conclusion || "" });
|
|
957
|
+
}
|
|
958
|
+
const majorConclusionsHash = computeConclusionsHash(majorChildConclusions);
|
|
959
|
+
await this.state.transition({
|
|
960
|
+
workspaceId,
|
|
961
|
+
nodeId: majorNodeId,
|
|
962
|
+
action: "complete",
|
|
963
|
+
conclusion: `v${mm} 版本更新完成`,
|
|
964
|
+
conclusionsHash: majorConclusionsHash,
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
// 按版本号降序排序根节点的子节点(新版本在前)
|
|
968
|
+
const rootNodeForSort = await this.node.get({ workspaceId, nodeId: "root" });
|
|
969
|
+
const childIds = rootNodeForSort.meta.children;
|
|
970
|
+
if (childIds.length > 1) {
|
|
971
|
+
// 获取每个子节点的版本号
|
|
972
|
+
const childVersions = [];
|
|
973
|
+
for (const childId of childIds) {
|
|
974
|
+
const child = await this.node.get({ workspaceId, nodeId: childId });
|
|
975
|
+
// 从 dirName 中提取版本号,格式如 "V1.6 版本更新_mjgrvwam"
|
|
976
|
+
const match = child.meta.dirName?.match(/V(\d+\.\d+)/);
|
|
977
|
+
if (match) {
|
|
978
|
+
childVersions.push({ id: childId, version: match[1] });
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
// 按版本号降序排序
|
|
982
|
+
childVersions.sort((a, b) => this.compareVersions(b.version + ".0", a.version + ".0"));
|
|
983
|
+
const sortedChildIds = childVersions.map(c => c.id);
|
|
984
|
+
// 如果顺序有变化,重新排序
|
|
985
|
+
if (sortedChildIds.length === childIds.length &&
|
|
986
|
+
sortedChildIds.some((id, i) => id !== childIds[i])) {
|
|
987
|
+
await this.node.reorderChildren({
|
|
988
|
+
workspaceId,
|
|
989
|
+
nodeId: "root",
|
|
990
|
+
orderedChildIds: sortedChildIds,
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
// 完成根节点(如果还未完成)
|
|
995
|
+
const rootNode = await this.node.get({ workspaceId, nodeId: "root" });
|
|
996
|
+
if (rootNode.meta.status === "monitoring") {
|
|
997
|
+
// 计算根节点子节点的 conclusionsHash
|
|
998
|
+
const rootChildConclusions = [];
|
|
999
|
+
for (const childId of rootNode.meta.children) {
|
|
1000
|
+
const child = await this.node.get({ workspaceId, nodeId: childId });
|
|
1001
|
+
rootChildConclusions.push({ nodeId: childId, conclusion: child.meta.conclusion || "" });
|
|
1002
|
+
}
|
|
1003
|
+
const rootConclusionsHash = computeConclusionsHash(rootChildConclusions);
|
|
1004
|
+
await this.state.transition({
|
|
1005
|
+
workspaceId,
|
|
1006
|
+
nodeId: "root",
|
|
1007
|
+
action: "complete",
|
|
1008
|
+
conclusion: "版本更新说明",
|
|
1009
|
+
conclusionsHash: rootConclusionsHash,
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
// 设置 focus 到最新版本节点
|
|
1013
|
+
if (latestNodeId) {
|
|
1014
|
+
await this.context.focus({
|
|
1015
|
+
workspaceId,
|
|
1016
|
+
nodeId: latestNodeId,
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* 创建教程工作区
|
|
1022
|
+
*/
|
|
1023
|
+
async createTutorialWorkspace() {
|
|
1024
|
+
const tutorialDir = this.getTutorialDir();
|
|
1025
|
+
// 确保目录存在
|
|
1026
|
+
await fs.mkdir(tutorialDir, { recursive: true });
|
|
1027
|
+
// 创建工作区
|
|
1028
|
+
const result = await this.workspace.init({
|
|
1029
|
+
name: TUTORIAL_CONTENT.name,
|
|
1030
|
+
goal: TUTORIAL_CONTENT.goal,
|
|
1031
|
+
projectRoot: tutorialDir,
|
|
1032
|
+
rules: TUTORIAL_CONTENT.rules,
|
|
1033
|
+
docs: TUTORIAL_CONTENT.docs,
|
|
1034
|
+
});
|
|
1035
|
+
// 创建独立 MEMO:版本更新与帮助系统(在 MEMO 功能说明之前创建)
|
|
1036
|
+
await this.memo.create({
|
|
1037
|
+
workspaceId: result.workspaceId,
|
|
1038
|
+
title: "版本更新与帮助系统",
|
|
1039
|
+
summary: "版本更新、插件更新方式和 WebUI 帮助入口",
|
|
1040
|
+
tags: ["新手教程", "帮助"],
|
|
1041
|
+
content: `# 版本更新与帮助系统
|
|
1042
|
+
|
|
1043
|
+
## 版本更新
|
|
1044
|
+
|
|
1045
|
+
### npm 全局包更新
|
|
1046
|
+
ZeroWorkspace 作为 npm 全局包发布,更新命令:
|
|
1047
|
+
\`\`\`bash
|
|
1048
|
+
npm i -g zero-workspace
|
|
1049
|
+
\`\`\`
|
|
1050
|
+
|
|
1051
|
+
### 版本检查机制
|
|
1052
|
+
- 启动时自动检查版本
|
|
1053
|
+
- 有新版本时创建「版本更新」工作区
|
|
1054
|
+
- 可在工作区中查看各版本的更新内容
|
|
1055
|
+
|
|
1056
|
+
## 插件更新
|
|
1057
|
+
|
|
1058
|
+
插件(Hooks、Agents、Skills)随 npm 包一起更新。
|
|
1059
|
+
|
|
1060
|
+
### 更新流程
|
|
1061
|
+
1. 更新 npm 包:\`npm i -g zero-workspace\`
|
|
1062
|
+
2. 重新安装插件:\`zero-workspace plugins install --claude\`
|
|
1063
|
+
或通过\`zero-workspace setup\`重新安装所有插件
|
|
1064
|
+
|
|
1065
|
+
### 查看插件状态
|
|
1066
|
+
\`\`\`bash
|
|
1067
|
+
zero-workspace plugins
|
|
1068
|
+
\`\`\`
|
|
1069
|
+
|
|
1070
|
+
### 插件管理命令
|
|
1071
|
+
- 安装 Claude 插件:\`zero-workspace plugins install --claude\`
|
|
1072
|
+
- 安装 Cursor 插件:\`zero-workspace plugins install --cursor\`
|
|
1073
|
+
- 卸载:\`zero-workspace plugins uninstall --claude\`
|
|
1074
|
+
|
|
1075
|
+
## WebUI 帮助入口
|
|
1076
|
+
|
|
1077
|
+
### 设置面板
|
|
1078
|
+
点击主页面顶部「设置」按钮:
|
|
1079
|
+
- 查看用户帮助(快速入门、触发词速查)
|
|
1080
|
+
- 查看插件详情和版本信息
|
|
1081
|
+
- 配置派发模式默认设置
|
|
1082
|
+
|
|
1083
|
+
### 用户帮助区域
|
|
1084
|
+
- **快速入门**:工作流程和核心概念
|
|
1085
|
+
- **触发词速查**:常用对话触发词参考
|
|
1086
|
+
- **查看完整手册**:详细用户文档
|
|
1087
|
+
`,
|
|
1088
|
+
});
|
|
1089
|
+
// 创建子节点(使用 INTERNAL_RULES_HASH 绕过规则确认检查)
|
|
1090
|
+
const focusNodeId = await this.createNodes(result.workspaceId, "root", TUTORIAL_CONTENT.nodes);
|
|
1091
|
+
// 最后设置焦点(避免被后续操作覆盖)
|
|
1092
|
+
if (focusNodeId) {
|
|
1093
|
+
await this.context.focus({ workspaceId: result.workspaceId, nodeId: focusNodeId });
|
|
1094
|
+
}
|
|
1095
|
+
// 启用 no-git 派发模式
|
|
1096
|
+
await this.dispatch.enable({ workspaceId: result.workspaceId, useGit: false });
|
|
1097
|
+
// 置顶教程工作区,方便用户快速访问(失败不阻断主流程)
|
|
1098
|
+
try {
|
|
1099
|
+
await this.workspace.togglePin(result.workspaceId);
|
|
1100
|
+
}
|
|
1101
|
+
catch {
|
|
1102
|
+
// 置顶是辅助功能,失败时静默忽略
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* 递归创建节点,返回需要设为焦点的节点ID
|
|
1107
|
+
*/
|
|
1108
|
+
async createNodes(workspaceId, parentId, nodes) {
|
|
1109
|
+
let focusNodeId = null;
|
|
1110
|
+
for (const nodeDef of nodes) {
|
|
1111
|
+
// 1. 创建节点
|
|
1112
|
+
const result = await this.node.create({
|
|
1113
|
+
workspaceId,
|
|
1114
|
+
parentId,
|
|
1115
|
+
type: nodeDef.type,
|
|
1116
|
+
title: nodeDef.title,
|
|
1117
|
+
requirement: nodeDef.requirement,
|
|
1118
|
+
role: nodeDef.role,
|
|
1119
|
+
docs: nodeDef.docs,
|
|
1120
|
+
rulesHash: INTERNAL_RULES_HASH,
|
|
1121
|
+
});
|
|
1122
|
+
const nodeId = result.nodeId;
|
|
1123
|
+
// 2. 递归创建子节点
|
|
1124
|
+
if (nodeDef.children && nodeDef.children.length > 0) {
|
|
1125
|
+
const childFocusId = await this.createNodes(workspaceId, nodeId, nodeDef.children);
|
|
1126
|
+
if (childFocusId)
|
|
1127
|
+
focusNodeId = childFocusId;
|
|
1128
|
+
}
|
|
1129
|
+
// 3. 设置目标状态
|
|
1130
|
+
if (nodeDef.targetStatus) {
|
|
1131
|
+
const hasChildren = nodeDef.children && nodeDef.children.length > 0;
|
|
1132
|
+
await this.transitionToStatus(workspaceId, nodeId, nodeDef.type, nodeDef.targetStatus, nodeDef.conclusion, hasChildren);
|
|
1133
|
+
}
|
|
1134
|
+
// 4. 设置备注(状态转换后设置,避免被覆盖)
|
|
1135
|
+
if (nodeDef.note) {
|
|
1136
|
+
await this.node.update({
|
|
1137
|
+
workspaceId,
|
|
1138
|
+
nodeId,
|
|
1139
|
+
note: nodeDef.note,
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
// 5. 设置问题(状态转换后设置,避免被覆盖)
|
|
1143
|
+
if (nodeDef.problem) {
|
|
1144
|
+
await this.log.updateProblem({
|
|
1145
|
+
workspaceId,
|
|
1146
|
+
nodeId,
|
|
1147
|
+
problem: nodeDef.problem,
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
// 6. 添加日志
|
|
1151
|
+
if (nodeDef.logs) {
|
|
1152
|
+
for (const logEntry of nodeDef.logs) {
|
|
1153
|
+
await this.log.append({
|
|
1154
|
+
workspaceId,
|
|
1155
|
+
nodeId,
|
|
1156
|
+
operator: logEntry.operator,
|
|
1157
|
+
event: logEntry.event,
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
// 7. 记录焦点节点(不立即设置)
|
|
1162
|
+
if (nodeDef.setFocus) {
|
|
1163
|
+
focusNodeId = nodeId;
|
|
1164
|
+
}
|
|
1165
|
+
// 8. Hack: 直接写入派发信息
|
|
1166
|
+
if (nodeDef.dispatchInfo) {
|
|
1167
|
+
await this.hackSetDispatchInfo(workspaceId, nodeId, nodeDef.dispatchInfo);
|
|
1168
|
+
}
|
|
1169
|
+
// 9. 创建 MEMO 并添加引用
|
|
1170
|
+
if (nodeDef.memo) {
|
|
1171
|
+
const memoResult = await this.memo.create({
|
|
1172
|
+
workspaceId,
|
|
1173
|
+
title: nodeDef.memo.title,
|
|
1174
|
+
summary: nodeDef.memo.summary,
|
|
1175
|
+
tags: nodeDef.memo.tags,
|
|
1176
|
+
content: nodeDef.memo.content,
|
|
1177
|
+
});
|
|
1178
|
+
// 使用 reference 服务添加引用(会同时更新 graph.json 和 Info.md)
|
|
1179
|
+
await this.reference.reference({
|
|
1180
|
+
workspaceId,
|
|
1181
|
+
nodeId,
|
|
1182
|
+
targetIdOrPath: `memo://${memoResult.memoId}`,
|
|
1183
|
+
action: "add",
|
|
1184
|
+
description: nodeDef.memo.title,
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return focusNodeId;
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Hack: 直接写入节点的派发信息(绕过正常派发流程)
|
|
1192
|
+
*/
|
|
1193
|
+
async hackSetDispatchInfo(workspaceId, nodeId, dispatchInfo) {
|
|
1194
|
+
// 获取工作区配置以拿到 dirName
|
|
1195
|
+
const wsResult = await this.workspace.get({ workspaceId });
|
|
1196
|
+
const wsConfig = wsResult.config;
|
|
1197
|
+
// 读取 graph.json
|
|
1198
|
+
const tutorialDir = this.getTutorialDir();
|
|
1199
|
+
const isDev = process.env.NODE_ENV === "development" || process.env.ZERO_DEV === "true";
|
|
1200
|
+
const baseDir = isDev ? ".zero-workspace-dev" : ".zero-workspace";
|
|
1201
|
+
const graphPath = path.join(tutorialDir, baseDir, wsConfig.dirName, "graph.json");
|
|
1202
|
+
const graphContent = await fs.readFile(graphPath, "utf-8");
|
|
1203
|
+
const graph = JSON.parse(graphContent);
|
|
1204
|
+
// 设置节点的 dispatch 字段
|
|
1205
|
+
if (graph.nodes && graph.nodes[nodeId]) {
|
|
1206
|
+
graph.nodes[nodeId].dispatch = {
|
|
1207
|
+
startMarker: dispatchInfo.startMarker,
|
|
1208
|
+
endMarker: dispatchInfo.endMarker,
|
|
1209
|
+
status: dispatchInfo.status,
|
|
1210
|
+
};
|
|
1211
|
+
await fs.writeFile(graphPath, JSON.stringify(graph, null, 2), "utf-8");
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* 将节点转换到目标状态
|
|
1216
|
+
*/
|
|
1217
|
+
async transitionToStatus(workspaceId, nodeId, type, targetStatus, conclusion, hasChildren) {
|
|
1218
|
+
const transitions = this.getTransitionPath(type, targetStatus, hasChildren);
|
|
1219
|
+
for (const action of transitions) {
|
|
1220
|
+
await this.state.transition({
|
|
1221
|
+
workspaceId,
|
|
1222
|
+
nodeId,
|
|
1223
|
+
action: action,
|
|
1224
|
+
conclusion: action === transitions[transitions.length - 1] ? conclusion : undefined,
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* 获取到达目标状态需要的转换路径
|
|
1230
|
+
* @param hasChildren 规划节点是否有子节点(有子节点的会自动进入 monitoring)
|
|
1231
|
+
*/
|
|
1232
|
+
getTransitionPath(type, targetStatus, hasChildren) {
|
|
1233
|
+
if (type === "execution") {
|
|
1234
|
+
switch (targetStatus) {
|
|
1235
|
+
case "implementing": return ["start"];
|
|
1236
|
+
case "validating": return ["start", "submit"];
|
|
1237
|
+
case "completed": return ["start", "complete"];
|
|
1238
|
+
case "failed": return ["start", "fail"];
|
|
1239
|
+
default: return [];
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
// 规划节点:有子节点的会自动进入 monitoring,只需要 complete/cancel
|
|
1244
|
+
if (hasChildren) {
|
|
1245
|
+
switch (targetStatus) {
|
|
1246
|
+
case "completed": return ["complete"];
|
|
1247
|
+
case "cancelled": return ["cancel"];
|
|
1248
|
+
default: return [];
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
// 无子节点的规划节点需要先 start
|
|
1252
|
+
switch (targetStatus) {
|
|
1253
|
+
case "planning": return ["start"];
|
|
1254
|
+
case "monitoring": return ["start"];
|
|
1255
|
+
case "completed": return ["start", "complete"];
|
|
1256
|
+
case "cancelled": return ["start", "cancel"];
|
|
1257
|
+
default: return [];
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
//# sourceMappingURL=TutorialService.js.map
|