@deepstorm/cli 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/README.md +72 -0
- package/dist/agents/reef-inspect-figma.md +77 -0
- package/dist/agents/reef-review-backend.md.tmpl +112 -0
- package/dist/agents/reef-review-frontend.md.tmpl +78 -0
- package/dist/agents/reef-review-infra.md +47 -0
- package/dist/agents/reef-review-security.md.tmpl +80 -0
- package/dist/agents/reef-scope-analysis.md +64 -0
- package/dist/build-registry.js +375 -0
- package/dist/cli.js +8581 -0
- package/dist/config-schema.json +133 -0
- package/dist/env-examples/context7.env-example +19 -0
- package/dist/env-examples/feishu-wiki.env-example +16 -0
- package/dist/env-examples/figma.env-example +16 -0
- package/dist/env-examples/github.env-example +20 -0
- package/dist/env-examples/jira.env-example +20 -0
- package/dist/hooks/mcp-hook.sh +77 -0
- package/dist/hooks/reef-auto-format.sh.tmpl +72 -0
- package/dist/hooks/reef-block-dangerous.sh +70 -0
- package/dist/hooks/reef-hooks.json +72 -0
- package/dist/hooks/reef-intent-detect.sh +129 -0
- package/dist/hooks/reef-protect-files.sh +55 -0
- package/dist/hooks/reef-run-tests.sh +84 -0
- package/dist/hooks/reef-scope-check.sh +386 -0
- package/dist/hooks/reef-scope-ci.sh +28 -0
- package/dist/hooks/reef-scope-gate.sh +115 -0
- package/dist/hooks/reef-scope-pre-commit.sh.tmpl +28 -0
- package/dist/hooks/reef-scope-setup.sh +204 -0
- package/dist/hooks/reef-scope-split.sh +203 -0
- package/dist/hooks/sweep-hooks.json +14 -0
- package/dist/hooks/sweep-mcp-hook.sh +77 -0
- package/dist/hooks/tide-hooks.json +14 -0
- package/dist/hooks/tide-session-preload.sh +17 -0
- package/dist/mcp/code-hosting/github.json +20 -0
- package/dist/mcp/design-tools/figma.json +19 -0
- package/dist/mcp/docs-reference/context7.json +28 -0
- package/dist/mcp/e2e-testing/playwright.json +13 -0
- package/dist/mcp/knowledge-base/feishu-wiki.json +19 -0
- package/dist/mcp/project-management/jira.json +27 -0
- package/dist/mcp-skills/deepflow-mcp-feishu-wiki-read/SKILL.md +65 -0
- package/dist/mcp-skills/deepflow-mcp-feishu-wiki-write/SKILL.md +63 -0
- package/dist/mcp-skills/deepflow-mcp-figma-read/SKILL.md +98 -0
- package/dist/mcp-skills/deepflow-mcp-github-read/SKILL.md +62 -0
- package/dist/mcp-skills/deepflow-mcp-github-write/SKILL.md +63 -0
- package/dist/mcp-skills/deepflow-mcp-jira-read/SKILL.md +80 -0
- package/dist/mcp-skills/deepflow-mcp-jira-write/SKILL.md +74 -0
- package/dist/mcp-skills/deepflow-mcp-playwright-read/SKILL.md +79 -0
- package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +65 -0
- package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +63 -0
- package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +98 -0
- package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +62 -0
- package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +63 -0
- package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +80 -0
- package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +74 -0
- package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +79 -0
- package/dist/registry.json +818 -0
- package/dist/skills/atoll-ops/SKILL.md +46 -0
- package/dist/skills/reef-commit/SKILL.md +127 -0
- package/dist/skills/reef-gen-backend/SKILL.md.tmpl +87 -0
- package/dist/skills/reef-gen-backend/variants/java/steps.md +28 -0
- package/dist/skills/reef-gen-backend/variants/python/steps.md +70 -0
- package/dist/skills/reef-gen-frontend/SKILL.md.tmpl +83 -0
- package/dist/skills/reef-gen-frontend/variants/angular/steps.md +30 -0
- package/dist/skills/reef-harden/EXAMPLES.md +89 -0
- package/dist/skills/reef-harden/SKILL.md +136 -0
- package/dist/skills/reef-pr/SKILL.md +97 -0
- package/dist/skills/reef-review/SKILL.md.tmpl +107 -0
- package/dist/skills/reef-scope/SKILL.md +134 -0
- package/dist/skills/reef-start/SKILL.md.tmpl +562 -0
- package/dist/skills/reef-start/references/jira-start-subagent.md +60 -0
- package/dist/skills/reef-style-backend/SKILL.md.tmpl +134 -0
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/chat-client.md +96 -0
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/rag.md +94 -0
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +62 -0
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/tool-calling.md +68 -0
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +220 -0
- package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +148 -0
- package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +131 -0
- package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/quick-reference.md +103 -0
- package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +119 -0
- package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +101 -0
- package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +181 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/controller.md +95 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +121 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/infrastructure.md +179 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +202 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +107 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +83 -0
- package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +150 -0
- package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +197 -0
- package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/examples/user-repository-test.md +69 -0
- package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +101 -0
- package/dist/skills/reef-style-backend/fragments/java/test/junit5/examples/user-service-test.md +61 -0
- package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +100 -0
- package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/examples/user-controller-test.md +61 -0
- package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +85 -0
- package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/examples/user-service-integration-test.md +56 -0
- package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +83 -0
- package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +77 -0
- package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +164 -0
- package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +139 -0
- package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +177 -0
- package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +101 -0
- package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +135 -0
- package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +111 -0
- package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +83 -0
- package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +207 -0
- package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +91 -0
- package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +227 -0
- package/dist/skills/reef-style-backend/variants/java/examples/contributor-pattern.md +97 -0
- package/dist/skills/reef-style-backend/variants/java/quick-reference.md +117 -0
- package/dist/skills/reef-style-backend/variants/python/examples/crud-router.md +71 -0
- package/dist/skills/reef-style-backend/variants/python/examples/pydantic-schema.md +45 -0
- package/dist/skills/reef-style-backend/variants/python/examples/pytest-fixture.md +60 -0
- package/dist/skills/reef-style-backend/variants/python/examples/sqlalchemy-model.md +31 -0
- package/dist/skills/reef-style-backend/variants/python/quick-reference.md +111 -0
- package/dist/skills/reef-style-frontend/SKILL.md.tmpl +70 -0
- package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +79 -0
- package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +150 -0
- package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +141 -0
- package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +112 -0
- package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +134 -0
- package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/quick-reference.md +66 -0
- package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +252 -0
- package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +56 -0
- package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +100 -0
- package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +119 -0
- package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +95 -0
- package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +100 -0
- package/dist/skills/reef-testcase/SKILL.md +138 -0
- package/dist/skills/reef-testcase/references/coverage-dimensions.md +99 -0
- package/dist/skills/reef-testcase/references/test-case-template.md +63 -0
- package/dist/skills/sweep-init/SKILL.md +286 -0
- package/dist/skills/sweep-init/scripts/flow-selector.mjs +305 -0
- package/dist/skills/sweep-plan/SKILL.md.tmpl +312 -0
- package/dist/skills/sweep-plan/references/test-flow-template.md +46 -0
- package/dist/skills/sweep-run/SKILL.md +437 -0
- package/dist/skills/sweep-run/scripts/env-manager.mjs +208 -0
- package/dist/skills/sweep-run/scripts/flow-parser.mjs +329 -0
- package/dist/skills/sweep-run/scripts/flow-selector.mjs +483 -0
- package/dist/skills/sweep-run/scripts/mcp-manager.mjs +208 -0
- package/dist/skills/sweep-run/scripts/spec-compiler.mjs +303 -0
- package/dist/skills/tide-discuss/SKILL.md.tmpl +449 -0
- package/dist/skills/tide-discuss/references/checklists.md +88 -0
- package/dist/skills/tide-discuss/references/data-format.md +237 -0
- package/dist/skills/tide-discuss/references/prd-template.md +134 -0
- package/dist/skills/tide-discuss/references/publish-flow.md +167 -0
- package/dist/skills/tide-discuss/references/role-prompts.md +105 -0
- package/package.json +38 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# ๆต่ฏ็จไพๆจกๆฟ
|
|
2
|
+
|
|
3
|
+
## ๅญๆฎตๅฎไน
|
|
4
|
+
|
|
5
|
+
ๆฏไธชๆต่ฏ็จไพๅ
ๅซไปฅไธๅญๆฎต๏ผ
|
|
6
|
+
|
|
7
|
+
| ๅญๆฎต | ๅฟ
ๅกซ | ่ฏดๆ |
|
|
8
|
+
|------|------|------|
|
|
9
|
+
| `ID` | ๆฏ | ๅฏไธๆ ่ฏ๏ผๆ ผๅผ `TC-{feature}-{seq}` |
|
|
10
|
+
| `็ฑปๅ` | ๆฏ | ๆญฃๅธธๆต็จ / ่พน็ๆกไปถ / ๅผๅธธๅบๆฏ / ้ชๆถๆ ๅ |
|
|
11
|
+
| `ๅ็ฝฎๆกไปถ` | ๆฏ | ๆต่ฏๆ้็ๅ็ฝฎ็ถๆๆๆฐๆฎ |
|
|
12
|
+
| `ๆต่ฏๆญฅ้ชค` | ๆฏ | ๆธ
ๆฐ็ๆไฝๆญฅ้ชคๆ่ฟฐ |
|
|
13
|
+
| `้ขๆ็ปๆ` | ๆฏ | ๆๆ็่กไธบๆ่พๅบ |
|
|
14
|
+
| `ๅ
ณ่้ชๆถๆ ๅ` | ๅฆ | ๅฏนๅบ PRD ๆ Jira ไธญ็้ชๆถๆ ๅ็ผๅท |
|
|
15
|
+
|
|
16
|
+
## ๆจกๆฟ็คบไพ
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
### TC-{feature}-001
|
|
20
|
+
|
|
21
|
+
| ๅญๆฎต | ๅ
ๅฎน |
|
|
22
|
+
|------|------|
|
|
23
|
+
| **ID** | TC-{feature}-001 |
|
|
24
|
+
| **็ฑปๅ** | ๆญฃๅธธๆต็จ |
|
|
25
|
+
| **ๅ็ฝฎๆกไปถ** | {ๆต่ฏๆ้็ๅ็ฝฎ็ถๆๆๆฐๆฎ} |
|
|
26
|
+
| **ๆต่ฏๆญฅ้ชค** | 1. {ๆญฅ้ชคไธ}<br>2. {ๆญฅ้ชคไบ}<br>3. {ๆญฅ้ชคไธ} |
|
|
27
|
+
| **้ขๆ็ปๆ** | {ๆๆ็่กไธบๆ่พๅบ} |
|
|
28
|
+
| **ๅ
ณ่้ชๆถๆ ๅ** | AC-{id}๏ผๅฏ้๏ผ |
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## ่พๅบ็ปๆ
|
|
32
|
+
|
|
33
|
+
็ๆ็ๆต่ฏ็จไพๆธ
ๅๆดไฝ็ปๆ๏ผ
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
## ๆต่ฏ็จไพๆธ
ๅ
|
|
37
|
+
|
|
38
|
+
**ๅ่ฝ๏ผ** {feature name}
|
|
39
|
+
**ๆฅๆบ๏ผ** {Jira Issue ID}
|
|
40
|
+
**PRD ไธไธๆ๏ผ** {PRD link / "ๆ "}
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### ๆญฃๅธธๆต็จ
|
|
45
|
+
|
|
46
|
+
{ๆญฃๅธธๆต็จๆต่ฏ็จไพๅ่กจ}
|
|
47
|
+
|
|
48
|
+
### ่พน็ๆกไปถ
|
|
49
|
+
|
|
50
|
+
{่พน็ๆกไปถๆต่ฏ็จไพๅ่กจ}
|
|
51
|
+
|
|
52
|
+
### ๅผๅธธๅบๆฏ
|
|
53
|
+
|
|
54
|
+
{ๅผๅธธๅบๆฏๆต่ฏ็จไพๅ่กจ}
|
|
55
|
+
|
|
56
|
+
### ้ชๆถๆ ๅ้ช่ฏ
|
|
57
|
+
|
|
58
|
+
{้ชๆถๆ ๅๆต่ฏ็จไพๅ่กจ}
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
> ่ฏฅๆต่ฏ็จไพๆธ
ๅๅฏ่พๅ
ฅ superpowers ่พ
ๅฉ็ๆๆดๅฎๅค็ๅๅ
ๆต่ฏใ
|
|
63
|
+
```
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sweep-init
|
|
3
|
+
description: ๅๅงๅ E2E ๆต่ฏ้กน็ฎ้ชจๆถใๅๅปบ็ฎๅฝ็ปๆใๆ นๆฎ setup ้
็ฝฎ็ๆๅฏนๅบๆต่ฏๆกๆถ้
็ฝฎใ่ฏปๅ MCP ้
็ฝฎใ่ฎพ็ฝฎๅค็ฏๅขๅ้๏ผๆ ๅฟ้กน็ฎๅฏ่ขซ flow-create ๅ flow-run ไฝฟ็จใ
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash
|
|
5
|
+
deepstorm:
|
|
6
|
+
tool: sweep
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Sweep Setup โ E2E ๆต่ฏ้กน็ฎๅๅงๅ
|
|
10
|
+
|
|
11
|
+
ๅๅงๅๅฝๅ็ฎๅฝไธบ Sweep E2E ๆต่ฏ้กน็ฎใๆ นๆฎ DeepStorm setup ้ถๆฎต้ๆฉ็ E2E ๆกๆถ๏ผๅฆ Playwright๏ผ๏ผๅๅปบๅฏนๅบ็้กน็ฎ้ชจๆถใ
|
|
12
|
+
|
|
13
|
+
> **ๆณจๆ๏ผ** setup ๆฏ flow-create ๅ flow-run ็็กฌๆงๅ็ฝฎๆกไปถใๅฆๆๅฝๅ็ฎๅฝๆชๅๅงๅ๏ผๅ
ถไป skill ไผๆฅ้ๅผๅฏผๆง่ก `/sweep-init`ใ
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ไฝฟ็จๆนๅผ
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
/sweep-init
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
ๅจ้่ฆไฝไธบ E2E ๆต่ฏ้กน็ฎ็็ฎๅฝไธญๆง่กใ้ๅธธๅจไธไธช็ฉบ็ๆๅทฒๆ git ไปๅบ็็ฎๅฝไธญ่ฟ่กใ
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ๅทฅไฝๆต
|
|
28
|
+
|
|
29
|
+
### ๆญฅ้ชค 0๏ผ่ฏปๅๆกๆถ้
็ฝฎ
|
|
30
|
+
|
|
31
|
+
ๅจๆง่กๅๅงๅๅ๏ผๅ
่ฏปๅ `.claude/settings.json` ไธญ็ `deepstorm.sweep.e2eFramework` ้
็ฝฎ๏ผ็กฎๅฎๅฝๅ้กน็ฎไฝฟ็จ็ E2E ๆกๆถใ
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cat .claude/settings.json 2>/dev/null | grep -o '"e2eFramework"[^,]*' | head -1 | cut -d'"' -f4
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
ๅฆๆ้
็ฝฎไธๅญๅจๆไธบ็ฉบ๏ผไฝฟ็จ้ป่ฎคๅผ `playwright` ๅนถ่พๅบๆ็คบใ
|
|
38
|
+
|
|
39
|
+
ๅฝๅๆฏๆ็ๆกๆถ๏ผ
|
|
40
|
+
- **playwright** โ Microsoft Playwright๏ผ้ป่ฎค๏ผ
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### ๆญฅ้ชค 1๏ผๆฃๆฅๅๅงๅ็ถๆ
|
|
45
|
+
|
|
46
|
+
ๆฃๆฅๅฝๅ็ฎๅฝๆฏๅฆๅญๅจ `.sweep-init` ๆ ่ฎฐๆไปถใ
|
|
47
|
+
|
|
48
|
+
#### 1.1 ๅทฒๅๅงๅ โ ้ๅบ
|
|
49
|
+
|
|
50
|
+
- **WHEN** `.sweep-init` ๆไปถๅทฒๅญๅจ
|
|
51
|
+
- **THEN** ๆ็คบ"ๅฝๅ็ฎๅฝๅทฒๅๅงๅไธบ Sweep ๆต่ฏ้กน็ฎใๅฆ้้ๆฐๅๅงๅ๏ผ่ฏทๅ ้ค .sweep-init ๆไปถๅ้่ฏใ"ๅนถ้ๅบ
|
|
52
|
+
|
|
53
|
+
#### 1.2 ๆชๅๅงๅ โ ็ปง็ปญ
|
|
54
|
+
|
|
55
|
+
- **WHEN** `.sweep-init` ๆไปถไธๅญๅจ
|
|
56
|
+
- **THEN** ็ปง็ปญๆง่กๅๅงๅๆต็จ
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### ๆญฅ้ชค 2๏ผๅๅปบ้กน็ฎ็ฎๅฝ็ปๆ
|
|
61
|
+
|
|
62
|
+
ๅๅปบ E2E ๆต่ฏ้กน็ฎ็็ฎๅฝ้ชจๆถใ
|
|
63
|
+
|
|
64
|
+
#### ็ฎๅฝ็ปๆ
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
.
|
|
68
|
+
โโโ flows/ # ๆต่ฏๆๅพๆๆกฃ็ฎๅฝ
|
|
69
|
+
โ โโโ topology.yaml # ๅ่ฝๆจกๅๆๆๅฎไน๏ผๅพ
็จๆท็ผ่พ๏ผ
|
|
70
|
+
โ โโโ reports/ # ๆง่กๆฅๅๆไน
ๅ็ฎๅฝ
|
|
71
|
+
โโโ scripts/
|
|
72
|
+
โ โโโ flow-selector.mjs # ๅฑ็บง้ๆฉๅทฅๅ
ท๏ผ้ข็ฝฎ๏ผ
|
|
73
|
+
โโโ .env # ็ฏๅขๅ้๏ผgitignored๏ผๅณๆจกๆฟ๏ผ
|
|
74
|
+
โโโ package.json # ไพ่ตๅฃฐๆ
|
|
75
|
+
โโโ tsconfig.json # TypeScript ้
็ฝฎ
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> ๅฆๆๆกๆถไธบ `playwright`๏ผ่ฟไผ้ขๅค็ๆ `playwright.config.ts`ใ
|
|
79
|
+
|
|
80
|
+
#### ๆง่ก
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
mkdir -p flows flows/reports scripts
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### ๆญฅ้ชค 3๏ผ็ๆ้กน็ฎ้
็ฝฎๆไปถ๏ผๆกๆถๆ็ฅ๏ผ
|
|
89
|
+
|
|
90
|
+
ๆ นๆฎๆญฅ้ชค 0 ่ฏปๅ็ๆกๆถ้
็ฝฎ๏ผ็ๆๅฏนๅบ็้
็ฝฎๆไปถใ
|
|
91
|
+
|
|
92
|
+
#### 3.1 package.json
|
|
93
|
+
|
|
94
|
+
ๅๅ
ฅๅบ็ก `package.json`ใๅฆๆๆกๆถไธบ `playwright`๏ผๅ
ๅซ Playwright ไพ่ต๏ผ
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"name": "sweep-e2e",
|
|
99
|
+
"version": "1.0.0",
|
|
100
|
+
"private": true,
|
|
101
|
+
"type": "module",
|
|
102
|
+
"scripts": {
|
|
103
|
+
"test": "playwright test",
|
|
104
|
+
"report": "playwright show-report"
|
|
105
|
+
},
|
|
106
|
+
"devDependencies": {
|
|
107
|
+
"@playwright/test": "^1.50.0",
|
|
108
|
+
"@inquirer/checkbox": "^4.0.0",
|
|
109
|
+
"@types/node": "^22.0.0"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
> ๅฝ E2E ๆกๆถๆช็ฅๆๆช้
็ฝฎๆถ๏ผ`package.json` ไธญไป
ๅ
ๅซ `@inquirer/checkbox` ๅ `@types/node` ไพ่ต๏ผ**ไธๅ
ๅซ** `@playwright/test`ใ
|
|
115
|
+
|
|
116
|
+
#### 3.2 ๆกๆถ้
็ฝฎๆไปถ
|
|
117
|
+
|
|
118
|
+
**ๅฝๆกๆถไธบ `playwright` ๆถ**๏ผๅๅ
ฅ `playwright.config.ts`๏ผๅ
ๅซๅค็ฏๅข baseURL ่ฎพ็ฝฎ๏ผ
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { defineConfig } from '@playwright/test';
|
|
122
|
+
|
|
123
|
+
export default defineConfig({
|
|
124
|
+
use: {
|
|
125
|
+
baseURL: process.env.BASE_URL || 'http://localhost:3000',
|
|
126
|
+
},
|
|
127
|
+
timeout: 30000,
|
|
128
|
+
retries: 0,
|
|
129
|
+
reporter: [['line'], ['html', { outputFolder: 'flows/reports' }]],
|
|
130
|
+
projects: [
|
|
131
|
+
{ name: 'chromium', use: { browserName: 'chromium' } },
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**ๅฝๆกๆถๆช็ฅๆๆช้
็ฝฎๆถ**๏ผ่ทณ่ฟๆกๆถ้
็ฝฎๆไปถ็็ๆ๏ผ่พๅบๆ็คบ๏ผ"ๆกๆถๆช้
็ฝฎ๏ผ่ฏท่ฟ่ก deepstorm setup ๅนถ้ๆฉ E2E ๆกๆถใ"
|
|
137
|
+
|
|
138
|
+
#### 3.3 tsconfig.json
|
|
139
|
+
|
|
140
|
+
ๅๅ
ฅ TypeScript ้
็ฝฎ๏ผๆกๆถๆ ๅ
ณ๏ผ๏ผ
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"compilerOptions": {
|
|
145
|
+
"target": "ES2022",
|
|
146
|
+
"module": "ESNext",
|
|
147
|
+
"moduleResolution": "bundler",
|
|
148
|
+
"strict": true,
|
|
149
|
+
"esModuleInterop": true
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### ๆญฅ้ชค 4๏ผๆถ้ๅค็ฏๅข้
็ฝฎไฟกๆฏ
|
|
157
|
+
|
|
158
|
+
#### 4.1 ไบคไบๅผ่ฏข้ฎ็ฏๅขๅฐๅ
|
|
159
|
+
|
|
160
|
+
้้กน่ฏข้ฎ็จๆท่พๅ
ฅ่ขซๆต็ณป็ป็็ฏๅขๅฐๅ๏ผ
|
|
161
|
+
|
|
162
|
+
1. ๆต่ฏ็ฏๅข๏ผtest๏ผbaseURL
|
|
163
|
+
2. ้ขๅๅธ็ฏๅข๏ผstaging๏ผbaseURL
|
|
164
|
+
3. ็ไบง็ฏๅข๏ผprod๏ผbaseURL
|
|
165
|
+
4. ้ป่ฎค็ฎๆ ็ฏๅข๏ผtest / staging / prod๏ผ
|
|
166
|
+
|
|
167
|
+
#### 4.2 ๅๅ
ฅ .env
|
|
168
|
+
|
|
169
|
+
ๅชๅๅ
ฅ็ฏๅขๅฐๅ้
็ฝฎ๏ผไธๅ
ๅซ MCP ่ฟๆฅ่ฏดๆ๏ผMCP ้
็ฝฎๅจ `.mcp.json` ไธญ็ปไธ็ฎก็๏ผ๏ผ
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# .env๏ผgitignored๏ผไธๆไบค๏ผ
|
|
173
|
+
BASE_URL_TEST=http://localhost:3000
|
|
174
|
+
BASE_URL_STAGING=https://staging.example.com
|
|
175
|
+
BASE_URL_PROD=https://prod.example.com
|
|
176
|
+
DEFAULT_ENV=test
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### ๆญฅ้ชค 5๏ผๅๅปบ topology.yaml ๅๅงๆจกๆฟ
|
|
182
|
+
|
|
183
|
+
ๅๅ
ฅๅ่ฝๆจกๅๆๆๆไปถๅบ็ก็ปๆ๏ผ
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
# flows/topology.yaml
|
|
187
|
+
name: E2E ๆต่ฏๆๆ
|
|
188
|
+
version: 1
|
|
189
|
+
|
|
190
|
+
modules:
|
|
191
|
+
- name: example
|
|
192
|
+
description: ็คบไพๆจกๅ
|
|
193
|
+
children:
|
|
194
|
+
- name: feature1
|
|
195
|
+
description: ๅ่ฝ 1
|
|
196
|
+
features: []
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**ๆ็คบ็จๆท๏ผ** ่ฏทๆ นๆฎๅฎ้
ไบงๅ็ปๆ็ผ่พ `flows/topology.yaml`๏ผๆทปๅ ๅฏนๅบ็ๅ่ฝๆจกๅใ
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### ๆญฅ้ชค 6๏ผๅๅปบ flow-selector.mjs
|
|
204
|
+
|
|
205
|
+
ไฝฟ็จ Read ่ฏปๅๆฌ skill ็ฎๅฝไธ็ `scripts/flow-selector.mjs` ๆไปถ๏ผ็จ Write ๅๅ
ฅ็ฎๆ ้กน็ฎ็ `scripts/flow-selector.mjs`ใ
|
|
206
|
+
|
|
207
|
+
> **่ฏดๆ๏ผ** `flow-selector.mjs` ๆฏๅบไบ `@inquirer/checkbox` ็ๅฑ็บง้ๆฉๅทฅๅ
ท่ๆฌ๏ผไพ flow-run skill ่ฐ็จ๏ผใ
|
|
208
|
+
> ๅฎไธๆฌ SKILL.md ๅๅฑไธไธช skill๏ผไฝไธบ skill ็ๅญๆไปถๅๅผ็ปดๆค๏ผ้ฟๅ
ๅ
่ไปฃ็ ๅๅฏผ่ด็้ๅคใ
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### ๆญฅ้ชค 7๏ผ็กฎ่ฎค E2E ๆกๆถ MCP ้
็ฝฎ๏ผไป `.mcp.json` ่ฏปๅ๏ผ
|
|
213
|
+
|
|
214
|
+
ๆฃๆฅ `.mcp.json` ไธญๆฏๅฆๅญๅจๅฏนๅบๆกๆถ็ MCP ๆๅก้
็ฝฎใๅฝๆกๆถไธบ `playwright` ๆถ๏ผๆฃๆฅ `deepstorm-playwright` ๆๅกใ
|
|
215
|
+
|
|
216
|
+
#### ๆฃๆฅ MCP ้
็ฝฎ
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
cat .mcp.json 2>/dev/null | grep -c "deepstorm-playwright"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### 7.1 MCP ๅทฒ้
็ฝฎ
|
|
223
|
+
|
|
224
|
+
- **WHEN** `.mcp.json` ไธญๅญๅจ `deepstorm-playwright`
|
|
225
|
+
- **THEN** ่พๅบ "โ
Playwright MCP ๅทฒๅฐฑ็ปช๏ผ็ฑ deepstorm setup ็ฎก็๏ผ"
|
|
226
|
+
|
|
227
|
+
#### 7.2 MCP ๆช้
็ฝฎ
|
|
228
|
+
|
|
229
|
+
- **WHEN** `.mcp.json` ไธญไธๅญๅจ `deepstorm-playwright`
|
|
230
|
+
- **THEN** ่พๅบๆ็คบ๏ผ"โ ๏ธ Playwright MCP ๆช้
็ฝฎใๅปบ่ฎฎ่ฟ่ก `deepstorm setup` ๅนถ้ๆฉ Playwright MCP ๆๅกไปฅๅฏ็จๆต่งๅจ่ชๅจๅใ"
|
|
231
|
+
- **THEN** ไธ้ปๅกๅๅงๅๆต็จ๏ผ็ปง็ปญๆง่ก
|
|
232
|
+
|
|
233
|
+
> **ๆณจๆ๏ผ** Playwright MCP ้
็ฝฎ็ฑ CLI setup wizard ็ปไธ็ฎก็๏ผไธๅ็ฑๆฌ skill ๅจ `.claude/settings.json` ไธญ็ฌ็ซ้
็ฝฎใ
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### ๆญฅ้ชค 8๏ผๅฎๆๅๅงๅ
|
|
238
|
+
|
|
239
|
+
#### 8.1 ๅๅปบๅๅงๅๆ ่ฎฐ
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
echo "sweep-e2e-project" > .sweep-init
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### 8.2 ๅฎ่ฃ
ไพ่ต
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
npm install
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### 8.3 ่พๅบๅฎๆไฟกๆฏ
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
โ
Sweep E2E ๆต่ฏ้กน็ฎๅๅงๅๅฎๆ๏ผ
|
|
255
|
+
|
|
256
|
+
ๆกๆถ๏ผ{ๆ้ๆกๆถ}
|
|
257
|
+
|
|
258
|
+
้กน็ฎ็ปๆ๏ผ
|
|
259
|
+
flows/ โ ๆต่ฏๆๅพๆๆกฃ็ฎๅฝ
|
|
260
|
+
flows/reports/ โ ๆง่กๆฅๅ็ฎๅฝ
|
|
261
|
+
scripts/ โ ่พ
ๅฉ่ๆฌ
|
|
262
|
+
(ๆกๆถ้
็ฝฎๆไปถ) โ {ๆกๆถๅ} ้
็ฝฎๆไปถ
|
|
263
|
+
|
|
264
|
+
ไธไธๆญฅ๏ผ
|
|
265
|
+
1. ็ผ่พ flows/topology.yaml ๆทปๅ ไฝ ็ๅ่ฝๆจกๅ
|
|
266
|
+
2. ่ฟ่ก /sweep-plan ๅๅปบๆต่ฏๆๅพๆๆกฃ
|
|
267
|
+
3. ่ฟ่ก /sweep-run ๆง่กๆต่ฏๆต็จ
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## ๆฃๆฅๆธ
ๅ
|
|
273
|
+
|
|
274
|
+
- [ ] ๅทฒ่ฏปๅๆกๆถ้
็ฝฎ๏ผ`deepstorm.sweep.e2eFramework`๏ผ
|
|
275
|
+
- [ ] `.sweep-init` ไธๅญๅจ โ ็ปง็ปญ
|
|
276
|
+
- [ ] ้กน็ฎ็ฎๅฝ็ปๆๅทฒๅๅปบ๏ผflows/ใflows/reports/ใscripts/๏ผ
|
|
277
|
+
- [ ] package.json ๅทฒๅๅ
ฅ๏ผๅซๅฏนๅบๆกๆถ็ไพ่ต๏ผ
|
|
278
|
+
- [ ] ๆกๆถ้
็ฝฎๆไปถๅทฒ็ๆ๏ผๅฆ playwright.config.ts๏ผ
|
|
279
|
+
- [ ] tsconfig.json ๅทฒๅๅ
ฅ
|
|
280
|
+
- [ ] ็จๆทๅทฒ่พๅ
ฅไธไธช็ฏๅข็ baseURL
|
|
281
|
+
- [ ] .env ๅทฒๅๅ
ฅ๏ผgitignored๏ผ
|
|
282
|
+
- [ ] topology.yaml ๅๅงๆจกๆฟๅทฒๅๅปบ
|
|
283
|
+
- [ ] flow-selector.mjs ๅทฒๅๅ
ฅ
|
|
284
|
+
- [ ] ๅทฒ็กฎ่ฎค MCP ้
็ฝฎ็ถๆ๏ผไป `.mcp.json` ่ฏปๅ๏ผ
|
|
285
|
+
- [ ] .sweep-init ๆ ่ฎฐๆไปถๅทฒๅๅปบ
|
|
286
|
+
- [ ] npm install ๅทฒๆง่ก
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sweep Flow Selector โ ๅบไบ @inquirer/checkbox ็ๅฑ็บง้ๆฉๅทฅๅ
ท
|
|
5
|
+
*
|
|
6
|
+
* ๆฏๆ้ๆฉ็ฒๅบฆ๏ผ
|
|
7
|
+
* 1. ๆจกๅ็บงๅซ๏ผeg. user-system๏ผ
|
|
8
|
+
* 2. ๆไปถ็บงๅซ๏ผeg. user-system/login.flow.md๏ผ
|
|
9
|
+
* 3. ็จไพ็บงๅซ๏ผeg. L01 - ๆญฃๅธธ็ปๅฝ๏ผ
|
|
10
|
+
*
|
|
11
|
+
* ่ฏปๅ config๏ผtopology.yaml ๆๆไปถ็ณป็ปๆซๆ๏ผ๏ผๅฑ็คบ้็จไพๅพ้็้ขใ
|
|
12
|
+
* ๅฐ้ไธญ็ปๆๅๅ
ฅ .sweep-selection.json ๅนถ่พๅบๅฐ stdoutใ
|
|
13
|
+
*
|
|
14
|
+
* ไฝฟ็จๆนๅผ๏ผnode scripts/flow-selector.mjs
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readFileSync, readdirSync, existsSync, writeFileSync } from 'node:fs';
|
|
18
|
+
import { join, relative } from 'node:path';
|
|
19
|
+
|
|
20
|
+
const BASE_FLOWS_DIR = join(process.cwd(), 'flows');
|
|
21
|
+
const TOPOLOGY_PATH = join(BASE_FLOWS_DIR, 'topology.yaml');
|
|
22
|
+
const SELECTION_PATH = join(process.cwd(), '.sweep-selection.json');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Override BASE_FLOWS_DIR for testing.
|
|
26
|
+
* Only affects function calls that receive this parameter.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_FLOWS_DIR = BASE_FLOWS_DIR;
|
|
29
|
+
|
|
30
|
+
// โโ YAML ่งฃๆ๏ผ่ฝป้๏ผไธไพ่ต yaml ๅ
๏ผ โโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
31
|
+
|
|
32
|
+
export function parseTopology(yaml) {
|
|
33
|
+
const modules = [];
|
|
34
|
+
const lines = yaml.split('\n');
|
|
35
|
+
let stack = [];
|
|
36
|
+
|
|
37
|
+
for (const raw of lines) {
|
|
38
|
+
const trimmed = raw.trimEnd();
|
|
39
|
+
if (!trimmed.trim() || trimmed.trimStart().startsWith('#')) continue;
|
|
40
|
+
|
|
41
|
+
const indent = trimmed.length - trimmed.trimStart().length;
|
|
42
|
+
while (stack.length > 0 && stack[stack.length - 1].indent >= indent) {
|
|
43
|
+
stack.pop();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const lineTrimmed = trimmed.trimStart();
|
|
47
|
+
const listMatch = lineTrimmed.match(/^-\s*name:\s*(.+)$/);
|
|
48
|
+
if (!listMatch) continue;
|
|
49
|
+
|
|
50
|
+
const name = listMatch[1];
|
|
51
|
+
const parentList = stack.length > 0 ? stack[stack.length - 1].list : modules;
|
|
52
|
+
const existing = parentList.find((m) => m.name === name);
|
|
53
|
+
if (!existing) {
|
|
54
|
+
parentList.push({ name, children: [] });
|
|
55
|
+
}
|
|
56
|
+
stack.push({ indent, list: parentList[parentList.length - 1].children });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return modules;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// โโ Flow ๆไปถ่งฃๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* ่งฃๆ .flow.md ๅ
ๅฎน๏ผๆๅๆๆ Flow ๅฎไน
|
|
66
|
+
* @returns {Array<{id: string, title: string}>}
|
|
67
|
+
*/
|
|
68
|
+
export function parseFlows(content) {
|
|
69
|
+
const flows = [];
|
|
70
|
+
const regex = /^## Flow:\s*(\S+)\s*-\s*(.+)$/gm;
|
|
71
|
+
let match;
|
|
72
|
+
while ((match = regex.exec(content)) !== null) {
|
|
73
|
+
flows.push({ id: match[1], title: match[2].trim() });
|
|
74
|
+
}
|
|
75
|
+
return flows;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ๆ นๆฎๆจกๅๅๆฅๆพๅฏนๅบ็ .flow.md ๆไปถ
|
|
80
|
+
* ๆ็ดข็ญ็ฅ๏ผ
|
|
81
|
+
* 1. ็ดๆฅๅน้
๏ผflows/{module.path}.flow.md
|
|
82
|
+
* 2. ็ถ็ฎๅฝๆซๆ๏ผๅจ็ถ็ฎๅฝไธญๆพๅ็งฐๅ
ๅซๆจกๅๅ็ .flow.md
|
|
83
|
+
* 3. ๅญ็ฎๅฝๆจกๅผ๏ผflows/{module.path}/ ไธ็ .flow.md
|
|
84
|
+
*/
|
|
85
|
+
export function resolveFlowFile(modulePath, flowsDir = BASE_FLOWS_DIR) {
|
|
86
|
+
const directPath = join(flowsDir, `${modulePath}.flow.md`);
|
|
87
|
+
if (existsSync(directPath)) return directPath;
|
|
88
|
+
|
|
89
|
+
const parts = modulePath.split('/');
|
|
90
|
+
const leafName = parts[parts.length - 1];
|
|
91
|
+
const parentDir = parts.length > 1
|
|
92
|
+
? join(flowsDir, parts.slice(0, -1).join('/'))
|
|
93
|
+
: flowsDir;
|
|
94
|
+
if (existsSync(parentDir)) {
|
|
95
|
+
const files = readdirSync(parentDir);
|
|
96
|
+
const found = files.find(
|
|
97
|
+
(f) => f.endsWith('.flow.md') && f.toLowerCase().includes(leafName.toLowerCase())
|
|
98
|
+
);
|
|
99
|
+
if (found) return join(parentDir, found);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const dirPath = join(flowsDir, modulePath);
|
|
103
|
+
if (existsSync(dirPath)) {
|
|
104
|
+
const files = readdirSync(dirPath);
|
|
105
|
+
const found = files.find((f) => f.endsWith('.flow.md'));
|
|
106
|
+
if (found) return join(dirPath, found);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// โโ ๆไปถ็ณป็ปๆซๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
113
|
+
|
|
114
|
+
export function scanFlowFiles(dir) {
|
|
115
|
+
const result = [];
|
|
116
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
const fullPath = join(dir, entry.name);
|
|
119
|
+
if (entry.isDirectory()) {
|
|
120
|
+
if (entry.name.startsWith('.')) continue;
|
|
121
|
+
result.push(...scanFlowFiles(fullPath));
|
|
122
|
+
} else if (entry.name.endsWith('.flow.md')) {
|
|
123
|
+
result.push(fullPath);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// โโ ๆๅปบ Choice ๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
130
|
+
|
|
131
|
+
export function buildChoicesWithFlows(modules, prefix = '', flowsDir = BASE_FLOWS_DIR) {
|
|
132
|
+
const choices = [];
|
|
133
|
+
|
|
134
|
+
for (const mod of modules) {
|
|
135
|
+
const path = prefix ? `${prefix}/${mod.name}` : mod.name;
|
|
136
|
+
|
|
137
|
+
if (mod.children && mod.children.length > 0) {
|
|
138
|
+
choices.push(...buildChoicesWithFlows(mod.children, path, flowsDir));
|
|
139
|
+
} else {
|
|
140
|
+
const flowFile = resolveFlowFile(path, flowsDir);
|
|
141
|
+
if (flowFile) {
|
|
142
|
+
const content = readFileSync(flowFile, 'utf-8');
|
|
143
|
+
const flows = parseFlows(content);
|
|
144
|
+
|
|
145
|
+
choices.push({
|
|
146
|
+
name: `๐ ${path}`,
|
|
147
|
+
value: `__file:${flowFile}`,
|
|
148
|
+
description: `${flows.length} ไธช็จไพ`,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
for (const f of flows) {
|
|
152
|
+
choices.push({
|
|
153
|
+
name: ` ${f.id} - ${f.title}`,
|
|
154
|
+
value: JSON.stringify({ file: flowFile, flowId: f.id }),
|
|
155
|
+
description: flowFile,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
choices.push({
|
|
160
|
+
name: `๐ ${path}`,
|
|
161
|
+
value: `__module:${path}`,
|
|
162
|
+
description: 'ๆชๆพๅฐๅฏนๅบ .flow.md ๆไปถ',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return choices;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// โโ ๅค็้ไธญ็ปๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
172
|
+
|
|
173
|
+
export function normalizeSelection(answer) {
|
|
174
|
+
if (answer.includes('__all__')) {
|
|
175
|
+
return { type: 'all' };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const fileMap = new Map();
|
|
179
|
+
|
|
180
|
+
for (const item of answer) {
|
|
181
|
+
if (item.startsWith('__file:')) {
|
|
182
|
+
const filePath = item.slice('__file:'.length);
|
|
183
|
+
if (!fileMap.has(filePath)) fileMap.set(filePath, []);
|
|
184
|
+
} else if (!item.startsWith('__module:')) {
|
|
185
|
+
try {
|
|
186
|
+
const { file, flowId } = JSON.parse(item);
|
|
187
|
+
if (!fileMap.has(file)) fileMap.set(file, []);
|
|
188
|
+
const flows = fileMap.get(file);
|
|
189
|
+
if (!flows.includes(flowId)) flows.push(flowId);
|
|
190
|
+
} catch { /* ignore */ }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const files = [];
|
|
195
|
+
for (const [filePath, selectedFlows] of fileMap) {
|
|
196
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
197
|
+
const allFlows = parseFlows(content);
|
|
198
|
+
const allIds = allFlows.map((f) => f.id);
|
|
199
|
+
|
|
200
|
+
if (selectedFlows.length === 0 || selectedFlows.length >= allIds.length) {
|
|
201
|
+
files.push({ file: filePath, flows: [], all: true });
|
|
202
|
+
} else {
|
|
203
|
+
files.push({ file: filePath, flows: selectedFlows, all: false });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (const item of answer) {
|
|
208
|
+
if (item.startsWith('__file:')) {
|
|
209
|
+
const filePath = item.slice('__file:'.length);
|
|
210
|
+
const entry = files.find((f) => f.file === filePath);
|
|
211
|
+
if (entry) entry.all = true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return { type: 'selection', files };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function writeSelection(data, selectionPath = SELECTION_PATH) {
|
|
219
|
+
const json = JSON.stringify(data, null, 2);
|
|
220
|
+
writeFileSync(selectionPath, json, 'utf-8');
|
|
221
|
+
console.log(json);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// โโ CLI entry point โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
225
|
+
|
|
226
|
+
if (process.argv[1] === import.meta.filename) {
|
|
227
|
+
main().catch((e) => {
|
|
228
|
+
if (e.name === 'ExitPromptError') process.exit(0);
|
|
229
|
+
const fallback = { type: 'all' };
|
|
230
|
+
writeSelection(fallback);
|
|
231
|
+
process.exit(0);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function main() {
|
|
236
|
+
try {
|
|
237
|
+
let modules = [];
|
|
238
|
+
let isFileScan = false;
|
|
239
|
+
|
|
240
|
+
if (existsSync(TOPOLOGY_PATH)) {
|
|
241
|
+
const yaml = readFileSync(TOPOLOGY_PATH, 'utf-8');
|
|
242
|
+
modules = parseTopology(yaml);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!modules.length && !existsSync(BASE_FLOWS_DIR)) {
|
|
246
|
+
console.error('โ flows/ ็ฎๅฝไธๅญๅจ');
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let choices;
|
|
251
|
+
|
|
252
|
+
if (modules.length > 0) {
|
|
253
|
+
choices = buildChoicesWithFlows(modules);
|
|
254
|
+
} else {
|
|
255
|
+
const files = scanFlowFiles(BASE_FLOWS_DIR);
|
|
256
|
+
if (files.length === 0) {
|
|
257
|
+
console.error('โ flows/ ็ฎๅฝไธๆฒกๆๆพๅฐไปปไฝ .flow.md ๆไปถ');
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
choices = [{ name: '๐ ๅ
จ้จๆง่ก', value: '__all__' }];
|
|
262
|
+
for (const file of files) {
|
|
263
|
+
const rel = relative(BASE_FLOWS_DIR, file);
|
|
264
|
+
const content = readFileSync(file, 'utf-8');
|
|
265
|
+
const flows = parseFlows(content);
|
|
266
|
+
choices.push({
|
|
267
|
+
name: `๐ ${rel}`,
|
|
268
|
+
value: `__file:${file}`,
|
|
269
|
+
description: `${flows.length} ไธช็จไพ`,
|
|
270
|
+
});
|
|
271
|
+
for (const f of flows) {
|
|
272
|
+
choices.push({
|
|
273
|
+
name: ` ${f.id} - ${f.title}`,
|
|
274
|
+
value: JSON.stringify({ file, flowId: f.id }),
|
|
275
|
+
description: rel,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
choices = [
|
|
282
|
+
{ name: '๐ ๅ
จ้จๆง่ก', value: '__all__' },
|
|
283
|
+
...choices,
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
const { default: checkbox } = await import('@inquirer/checkbox');
|
|
287
|
+
const answer = await checkbox({
|
|
288
|
+
message: '้ๆฉ่ฆๆง่ก็ๆต่ฏ็จไพ๏ผ็ฉบๆ ผๅพ้๏ผๅ่ฝฆ็กฎ่ฎค๏ผa=ๅ
จ้๏ผ๏ผ',
|
|
289
|
+
pageSize: 24,
|
|
290
|
+
loop: false,
|
|
291
|
+
choices,
|
|
292
|
+
shortcuts: { all: 'a', invert: 'i' },
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const selection = normalizeSelection(answer);
|
|
296
|
+
writeSelection(selection);
|
|
297
|
+
} catch (e) {
|
|
298
|
+
if (e.name === 'ExitPromptError') {
|
|
299
|
+
process.exit(0);
|
|
300
|
+
}
|
|
301
|
+
const fallback = { type: 'all' };
|
|
302
|
+
writeSelection(fallback);
|
|
303
|
+
process.exit(0);
|
|
304
|
+
}
|
|
305
|
+
}
|