sourcecode 0.29.0__tar.gz → 0.31.0__tar.gz
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.
- sourcecode-0.31.0/.agents/skills/source-command-gsd-join-discord/SKILL.md +24 -0
- sourcecode-0.31.0/.agents/skills/source-command-gsd-review-backlog/SKILL.md +63 -0
- sourcecode-0.31.0/.agents/skills/source-command-gsd-workstreams/SKILL.md +72 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/PKG-INFO +1 -1
- {sourcecode-0.29.0 → sourcecode-0.31.0}/pyproject.toml +1 -1
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/architecture_analyzer.py +9 -5
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/architecture_summary.py +4 -8
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/classifier.py +5 -1
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/cli.py +24 -34
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/confidence_analyzer.py +33 -20
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/nodejs.py +60 -18
- sourcecode-0.31.0/src/sourcecode/entrypoint_classifier.py +106 -0
- sourcecode-0.31.0/src/sourcecode/file_classifier.py +215 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/prepare_context.py +12 -7
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/schema.py +6 -4
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/serializer.py +268 -87
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/summarizer.py +10 -7
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_architecture_analyzer.py +3 -2
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_architecture_summary.py +11 -3
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_classifier.py +17 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_nodejs.py +2 -2
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_pipeline_integrity.py +20 -9
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_real_projects.py +4 -2
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_signal_hierarchy.py +5 -3
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_summarizer.py +4 -4
- {sourcecode-0.29.0 → sourcecode-0.31.0}/.gitignore +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/.ruff.toml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/CONTRIBUTING.md +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/LICENSE +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/README.md +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/SECURITY.md +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/docs/privacy.md +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/docs/schema.md +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/raw +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/__init__.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/conftest.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/lcov.info +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_cli.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_coverage_parser.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_cross_consistency.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_dependency_schema.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_python.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_detectors_base.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_graph_schema.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_detection.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_docs.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_lqn.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_metrics.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_multistack.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_semantics.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_integration_universal.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_packaging.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_redactor.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_scanner.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_schema.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_schema_normalization.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_semantic_schema.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_telemetry.py +0 -0
- {sourcecode-0.29.0 → sourcecode-0.31.0}/tests/test_workspace_analyzer.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "source-command-gsd-join-discord"
|
|
3
|
+
description: "Join the GSD Discord community"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# source-command-gsd-join-discord
|
|
7
|
+
|
|
8
|
+
Use this skill when the user asks to run the migrated source command `gsd-join-discord`.
|
|
9
|
+
|
|
10
|
+
## Command Template
|
|
11
|
+
|
|
12
|
+
<objective>
|
|
13
|
+
Display the Discord invite link for the GSD community server.
|
|
14
|
+
</objective>
|
|
15
|
+
|
|
16
|
+
<output>
|
|
17
|
+
# Join the GSD Discord
|
|
18
|
+
|
|
19
|
+
Connect with other GSD users, get help, share what you're building, and stay updated.
|
|
20
|
+
|
|
21
|
+
**Invite link:** https://discord.gg/mYgfVNfA2r
|
|
22
|
+
|
|
23
|
+
Click the link or paste it into your browser to join.
|
|
24
|
+
</output>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "source-command-gsd-review-backlog"
|
|
3
|
+
description: "Review and promote backlog items to active milestone"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# source-command-gsd-review-backlog
|
|
7
|
+
|
|
8
|
+
Use this skill when the user asks to run the migrated source command `gsd-review-backlog`.
|
|
9
|
+
|
|
10
|
+
## Command Template
|
|
11
|
+
|
|
12
|
+
<objective>
|
|
13
|
+
Review all 999.x backlog items and optionally promote them into the active
|
|
14
|
+
milestone sequence or remove stale entries.
|
|
15
|
+
</objective>
|
|
16
|
+
|
|
17
|
+
<process>
|
|
18
|
+
|
|
19
|
+
1. **List backlog items:**
|
|
20
|
+
```bash
|
|
21
|
+
ls -d .planning/phases/999* 2>/dev/null || echo "No backlog items found"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
2. **Read ROADMAP.md** and extract all 999.x phase entries:
|
|
25
|
+
```bash
|
|
26
|
+
cat .planning/ROADMAP.md
|
|
27
|
+
```
|
|
28
|
+
Show each backlog item with its description, any accumulated context (CONTEXT.md, RESEARCH.md), and creation date.
|
|
29
|
+
|
|
30
|
+
3. **Present the list to the user** via AskUserQuestion:
|
|
31
|
+
- For each backlog item, show: phase number, description, accumulated artifacts
|
|
32
|
+
- Options per item: **Promote** (move to active), **Keep** (leave in backlog), **Remove** (delete)
|
|
33
|
+
|
|
34
|
+
4. **For items to PROMOTE:**
|
|
35
|
+
- Find the next sequential phase number in the active milestone
|
|
36
|
+
- Rename the directory from `999.x-slug` to `{new_num}-slug`:
|
|
37
|
+
```bash
|
|
38
|
+
NEW_NUM=$(node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" phase add "${DESCRIPTION}" --raw)
|
|
39
|
+
```
|
|
40
|
+
- Move accumulated artifacts to the new phase directory
|
|
41
|
+
- Update ROADMAP.md: move the entry from `## Backlog` section to the active phase list
|
|
42
|
+
- Remove `(BACKLOG)` marker
|
|
43
|
+
- Add appropriate `**Depends on:**` field
|
|
44
|
+
|
|
45
|
+
5. **For items to REMOVE:**
|
|
46
|
+
- Delete the phase directory
|
|
47
|
+
- Remove the entry from ROADMAP.md `## Backlog` section
|
|
48
|
+
|
|
49
|
+
6. **Commit changes:**
|
|
50
|
+
```bash
|
|
51
|
+
node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" commit "docs: review backlog — promoted N, removed M" --files .planning/ROADMAP.md
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
7. **Report summary:**
|
|
55
|
+
```
|
|
56
|
+
## 📋 Backlog Review Complete
|
|
57
|
+
|
|
58
|
+
Promoted: {list of promoted items with new phase numbers}
|
|
59
|
+
Kept: {list of items remaining in backlog}
|
|
60
|
+
Removed: {list of deleted items}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
</process>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "source-command-gsd-workstreams"
|
|
3
|
+
description: "Manage parallel workstreams — list, create, switch, status, progress, complete, and resume"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# source-command-gsd-workstreams
|
|
7
|
+
|
|
8
|
+
Use this skill when the user asks to run the migrated source command `gsd-workstreams`.
|
|
9
|
+
|
|
10
|
+
## Command Template
|
|
11
|
+
|
|
12
|
+
# /gsd-workstreams
|
|
13
|
+
|
|
14
|
+
Manage parallel workstreams for concurrent milestone work.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
`/gsd-workstreams [subcommand] [args]`
|
|
19
|
+
|
|
20
|
+
### Subcommands
|
|
21
|
+
|
|
22
|
+
| Command | Description |
|
|
23
|
+
|---------|-------------|
|
|
24
|
+
| `list` | List all workstreams with status |
|
|
25
|
+
| `create <name>` | Create a new workstream |
|
|
26
|
+
| `status <name>` | Detailed status for one workstream |
|
|
27
|
+
| `switch <name>` | Set active workstream |
|
|
28
|
+
| `progress` | Progress summary across all workstreams |
|
|
29
|
+
| `complete <name>` | Archive a completed workstream |
|
|
30
|
+
| `resume <name>` | Resume work in a workstream |
|
|
31
|
+
|
|
32
|
+
## Step 1: Parse Subcommand
|
|
33
|
+
|
|
34
|
+
Parse the user's input to determine which workstream operation to perform.
|
|
35
|
+
If no subcommand given, default to `list`.
|
|
36
|
+
|
|
37
|
+
## Step 2: Execute Operation
|
|
38
|
+
|
|
39
|
+
### list
|
|
40
|
+
Run: `node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" workstream list --raw --cwd "$CWD"`
|
|
41
|
+
Display the workstreams in a table format showing name, status, current phase, and progress.
|
|
42
|
+
|
|
43
|
+
### create
|
|
44
|
+
Run: `node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" workstream create <name> --raw --cwd "$CWD"`
|
|
45
|
+
After creation, display the new workstream path and suggest next steps:
|
|
46
|
+
- `/gsd-new-milestone --ws <name>` to set up the milestone
|
|
47
|
+
|
|
48
|
+
### status
|
|
49
|
+
Run: `node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" workstream status <name> --raw --cwd "$CWD"`
|
|
50
|
+
Display detailed phase breakdown and state information.
|
|
51
|
+
|
|
52
|
+
### switch
|
|
53
|
+
Run: `node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" workstream set <name> --raw --cwd "$CWD"`
|
|
54
|
+
Also set `GSD_WORKSTREAM` for the current session when the runtime supports it.
|
|
55
|
+
If the runtime exposes a session identifier, GSD also stores the active workstream
|
|
56
|
+
session-locally so concurrent sessions do not overwrite each other.
|
|
57
|
+
|
|
58
|
+
### progress
|
|
59
|
+
Run: `node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" workstream progress --raw --cwd "$CWD"`
|
|
60
|
+
Display a progress overview across all workstreams.
|
|
61
|
+
|
|
62
|
+
### complete
|
|
63
|
+
Run: `node "C:/Users/dominique.haroun_m3i/Documents/workspace/test-gsd/.Codex/get-shit-done/bin/gsd-tools.cjs" workstream complete <name> --raw --cwd "$CWD"`
|
|
64
|
+
Archive the workstream to milestones/.
|
|
65
|
+
|
|
66
|
+
### resume
|
|
67
|
+
Set the workstream as active and suggest `/gsd-resume-work --ws <name>`.
|
|
68
|
+
|
|
69
|
+
## Step 3: Display Results
|
|
70
|
+
|
|
71
|
+
Format the JSON output from gsd-tools into a human-readable display.
|
|
72
|
+
Include the `${GSD_WS}` flag in any routing suggestions.
|
|
@@ -215,18 +215,22 @@ class ArchitectureAnalyzer:
|
|
|
215
215
|
if pattern not in (None, "unknown", "flat"):
|
|
216
216
|
if all_layers_weak:
|
|
217
217
|
# Layers came from file-naming heuristic only, not directory structure
|
|
218
|
-
confidence = "
|
|
218
|
+
confidence = "low"
|
|
219
219
|
limitations.append(
|
|
220
|
-
"
|
|
220
|
+
"Low confidence inference: pattern inferred from filenames only, without import graph confirmation"
|
|
221
221
|
)
|
|
222
222
|
else:
|
|
223
|
-
confidence = "
|
|
223
|
+
confidence = "medium" if len(strong_domains) >= 3 else "low"
|
|
224
|
+
if graph is None:
|
|
225
|
+
limitations.append(
|
|
226
|
+
"Pattern not confirmed by module import graph; run with --graph-modules for structural validation"
|
|
227
|
+
)
|
|
224
228
|
elif len(strong_domains) >= 1:
|
|
225
229
|
confidence = "medium"
|
|
226
230
|
else:
|
|
227
231
|
confidence = "low"
|
|
228
232
|
|
|
229
|
-
method = "graph+
|
|
233
|
+
method = "graph+structure" if graph is not None else "filesystem_inference"
|
|
230
234
|
|
|
231
235
|
return ArchitectureAnalysis(
|
|
232
236
|
requested=True,
|
|
@@ -339,7 +343,7 @@ class ArchitectureAnalyzer:
|
|
|
339
343
|
best_matched = matched
|
|
340
344
|
|
|
341
345
|
if best_score >= 2:
|
|
342
|
-
layer_confidence: Literal["high", "medium", "low"] = "
|
|
346
|
+
layer_confidence: Literal["high", "medium", "low"] = "medium" if best_score >= 3 else "low"
|
|
343
347
|
layers: list[ArchitectureLayer] = []
|
|
344
348
|
for layer_key, matched_dirs in best_matched.items():
|
|
345
349
|
matched_files = [
|
|
@@ -5,6 +5,7 @@ import re
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
+
from sourcecode.entrypoint_classifier import is_production_entry_point
|
|
8
9
|
from sourcecode.schema import EntryPoint, SourceMap, StackDetection
|
|
9
10
|
from sourcecode.tree_utils import flatten_file_tree
|
|
10
11
|
|
|
@@ -63,11 +64,8 @@ class ArchitectureSummarizer:
|
|
|
63
64
|
entry for entry in sm.entry_points
|
|
64
65
|
if not self._is_tooling_path(entry.path)
|
|
65
66
|
and not self._is_auxiliary_path(entry.path)
|
|
66
|
-
and entry
|
|
67
|
+
and is_production_entry_point(entry)
|
|
67
68
|
]
|
|
68
|
-
if not entry_points:
|
|
69
|
-
fallback = self._infer_fallback_entry_points(file_paths, sm.stacks)
|
|
70
|
-
entry_points = fallback[:1]
|
|
71
69
|
|
|
72
70
|
lang_lines: list[str] = []
|
|
73
71
|
if entry_points:
|
|
@@ -280,8 +278,7 @@ class ArchitectureSummarizer:
|
|
|
280
278
|
if modules:
|
|
281
279
|
formatted = self._format_module_list([self._module_label(module) for module in modules])
|
|
282
280
|
if formatted:
|
|
283
|
-
lines.append(f"
|
|
284
|
-
lines.append("Produce la salida principal del entry point JavaScript/TypeScript detectado.")
|
|
281
|
+
lines.append(f"Imports internos del entry point: {formatted}.")
|
|
285
282
|
return lines
|
|
286
283
|
|
|
287
284
|
def _summarize_java_entry(self, path: str, content: str, stacks: list[StackDetection]) -> list[str]:
|
|
@@ -344,8 +341,7 @@ class ArchitectureSummarizer:
|
|
|
344
341
|
if internal:
|
|
345
342
|
formatted = self._format_module_list([self._module_label(module) for module in internal])
|
|
346
343
|
if formatted:
|
|
347
|
-
lines.append(f"
|
|
348
|
-
lines.append("Produce la salida principal del binario Go detectado.")
|
|
344
|
+
lines.append(f"Imports internos del binario Go: {formatted}.")
|
|
349
345
|
return lines
|
|
350
346
|
|
|
351
347
|
def _describe_entry_point(self, entry_point: EntryPoint, project_type: str | None) -> str:
|
|
@@ -45,8 +45,12 @@ class TypeClassifier:
|
|
|
45
45
|
primary_stack = self._select_primary_stack(enriched, project_type)
|
|
46
46
|
|
|
47
47
|
final_stacks: list[StackDetection] = []
|
|
48
|
+
primary_assigned = False
|
|
48
49
|
for stack in enriched:
|
|
49
|
-
|
|
50
|
+
is_primary = stack.stack == primary_stack and not primary_assigned
|
|
51
|
+
if is_primary:
|
|
52
|
+
primary_assigned = True
|
|
53
|
+
final_stacks.append(replace(stack, primary=is_primary))
|
|
50
54
|
return final_stacks, project_type
|
|
51
55
|
|
|
52
56
|
def _enrich_stack(
|
|
@@ -6,9 +6,10 @@ import time
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Optional, cast
|
|
8
8
|
|
|
9
|
-
import typer
|
|
10
|
-
|
|
11
|
-
from sourcecode import __version__
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from sourcecode import __version__
|
|
12
|
+
from sourcecode.entrypoint_classifier import is_production_entry_point, normalize_entry_point
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
# ---------------------------------------------------------------------------
|
|
@@ -117,11 +118,11 @@ def _check_pipeline_coherence(sm: "SourceMap") -> list[str]: # type: ignore[nam
|
|
|
117
118
|
)
|
|
118
119
|
|
|
119
120
|
# overall:high requires at least one production entry point
|
|
120
|
-
if cs.overall == "high":
|
|
121
|
-
prod_eps = [
|
|
122
|
-
ep for ep in sm.entry_points
|
|
123
|
-
if ep
|
|
124
|
-
]
|
|
121
|
+
if cs.overall == "high":
|
|
122
|
+
prod_eps = [
|
|
123
|
+
ep for ep in sm.entry_points
|
|
124
|
+
if is_production_entry_point(ep)
|
|
125
|
+
]
|
|
125
126
|
if not prod_eps and sm.entry_points:
|
|
126
127
|
issues.append(
|
|
127
128
|
"[coherence] overall=high but no production entry points exist — "
|
|
@@ -134,21 +135,7 @@ def _check_pipeline_coherence(sm: "SourceMap") -> list[str]: # type: ignore[nam
|
|
|
134
135
|
"[coherence] entry_point_confidence=high but entry_points is empty"
|
|
135
136
|
)
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
# appear in agent_view output (checked post-facto via produced_by + type)
|
|
139
|
-
benchmark_eps = [
|
|
140
|
-
ep for ep in sm.entry_points
|
|
141
|
-
if ep.entrypoint_type in ("benchmark", "example")
|
|
142
|
-
]
|
|
143
|
-
if benchmark_eps and sm.entry_points and all(
|
|
144
|
-
ep.entrypoint_type in ("benchmark", "example") for ep in sm.entry_points
|
|
145
|
-
):
|
|
146
|
-
issues.append(
|
|
147
|
-
f"[coherence] all {len(sm.entry_points)} entry point(s) are benchmark/example — "
|
|
148
|
-
"no production entry detected; analysis_gaps should reflect impact=high"
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
return issues
|
|
138
|
+
return issues
|
|
152
139
|
|
|
153
140
|
_HELP = """\
|
|
154
141
|
Deterministic codebase context for AI coding agents.
|
|
@@ -909,11 +896,13 @@ def main(
|
|
|
909
896
|
if dependency_analyzer is not None:
|
|
910
897
|
from sourcecode.dependency_analyzer import _ROLE_PRIORITY
|
|
911
898
|
|
|
912
|
-
primary_ecosystem = sm.stacks[0].stack if sm.stacks else ""
|
|
913
|
-
direct_deps = [
|
|
914
|
-
d for d in sm.dependencies
|
|
915
|
-
if d.scope != "transitive" and d.source in {"manifest", "lockfile"}
|
|
916
|
-
|
|
899
|
+
primary_ecosystem = sm.stacks[0].stack if sm.stacks else ""
|
|
900
|
+
direct_deps = [
|
|
901
|
+
d for d in sm.dependencies
|
|
902
|
+
if d.scope != "transitive" and d.source in {"manifest", "lockfile"}
|
|
903
|
+
and (d.role or "unknown") in {"runtime", "parsing", "serialization", "observability", "infra"}
|
|
904
|
+
and d.scope not in {"dev"}
|
|
905
|
+
]
|
|
917
906
|
|
|
918
907
|
def _dep_sort_key(d: Any) -> tuple[int, int, str]:
|
|
919
908
|
role_order = _ROLE_PRIORITY.get(d.role or "runtime", 5)
|
|
@@ -993,12 +982,13 @@ def main(
|
|
|
993
982
|
"example", "examples", "docs", "doc", "fixtures", "fixture",
|
|
994
983
|
})
|
|
995
984
|
for _ep in sm.entry_points:
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
985
|
+
_normalized_ep = normalize_entry_point(_ep)
|
|
986
|
+
_ep_type = _normalized_ep.entrypoint_type
|
|
987
|
+
_path_parts = _ep.path.replace("\\", "/").lower().split("/")
|
|
988
|
+
_filtered = (
|
|
989
|
+
_normalized_ep.classification != "production"
|
|
990
|
+
or any(p in _aux_parts for p in _path_parts)
|
|
991
|
+
)
|
|
1002
992
|
if _filtered:
|
|
1003
993
|
_trace.emit("output", "agent_view", "filter_ep",
|
|
1004
994
|
target=_ep.path,
|
|
@@ -12,6 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import TYPE_CHECKING
|
|
14
14
|
|
|
15
|
+
from sourcecode.entrypoint_classifier import is_production_entry_point, normalize_entry_point
|
|
15
16
|
from sourcecode.schema import AnalysisGap, ConfidenceSummary, SourceMap
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
@@ -59,8 +60,15 @@ class ConfidenceAnalyzer:
|
|
|
59
60
|
hard_signals.append(sig)
|
|
60
61
|
|
|
61
62
|
# ── Entry point signals ───────────────────────────────────────────────
|
|
62
|
-
for ep in sm.entry_points
|
|
63
|
-
|
|
63
|
+
normalized_entry_points = [normalize_entry_point(ep) for ep in sm.entry_points]
|
|
64
|
+
|
|
65
|
+
for ep in normalized_entry_points:
|
|
66
|
+
if ep.classification != "production":
|
|
67
|
+
sig = f"entry:{ep.path} ({ep.classification}, {ep.reason or ep.source})"
|
|
68
|
+
if sig not in ignored_signals:
|
|
69
|
+
ignored_signals.append(sig)
|
|
70
|
+
continue
|
|
71
|
+
if ep.source in _HARD_SOURCES or ep.reason == "console_script" or ep.runtime_relevance == "high":
|
|
64
72
|
sig = f"entry:{ep.path} ({ep.reason or ep.source})"
|
|
65
73
|
if sig not in hard_signals:
|
|
66
74
|
hard_signals.append(sig)
|
|
@@ -95,13 +103,13 @@ class ConfidenceAnalyzer:
|
|
|
95
103
|
anomalies.append("All stacks detected via heuristic only — no manifest found")
|
|
96
104
|
|
|
97
105
|
# ── Anomaly: entry points all low-confidence ──────────────────────────
|
|
98
|
-
if
|
|
106
|
+
if normalized_entry_points and all(ep.confidence == "low" for ep in normalized_entry_points):
|
|
99
107
|
anomalies.append("All entry points are low-confidence (heuristic/code_signal only)")
|
|
100
108
|
|
|
101
109
|
# ── Anomaly: all production EPs are convention-only (no manifest evidence) ──
|
|
102
110
|
production_eps_check = [
|
|
103
|
-
ep for ep in
|
|
104
|
-
if ep
|
|
111
|
+
ep for ep in normalized_entry_points
|
|
112
|
+
if is_production_entry_point(ep)
|
|
105
113
|
]
|
|
106
114
|
if production_eps_check and all(
|
|
107
115
|
ep.source in ("convention", "heuristic") or ep.reason in ("convention", "entry_file_pattern")
|
|
@@ -113,40 +121,40 @@ class ConfidenceAnalyzer:
|
|
|
113
121
|
)
|
|
114
122
|
|
|
115
123
|
# ── Anomaly: no production entry points ───────────────────────────────
|
|
116
|
-
if
|
|
124
|
+
if normalized_entry_points:
|
|
117
125
|
production_eps = [
|
|
118
|
-
ep for ep in
|
|
119
|
-
if ep
|
|
126
|
+
ep for ep in normalized_entry_points
|
|
127
|
+
if is_production_entry_point(ep)
|
|
120
128
|
]
|
|
121
129
|
if not production_eps:
|
|
122
130
|
anomalies.append(
|
|
123
|
-
"No production entry points — all detected entries are
|
|
131
|
+
"No production entry points — all detected entries are development/auxiliary"
|
|
124
132
|
)
|
|
125
133
|
|
|
126
134
|
# ── Gaps ──────────────────────────────────────────────────────────────
|
|
127
|
-
if not
|
|
135
|
+
if not normalized_entry_points:
|
|
128
136
|
gaps.append(AnalysisGap(
|
|
129
137
|
area="entry_points",
|
|
130
|
-
reason="
|
|
138
|
+
reason="Critical: no runtime entrypoint detected; system cannot be executed without manual inference",
|
|
131
139
|
impact="high",
|
|
132
140
|
))
|
|
133
141
|
elif all(
|
|
134
|
-
ep.
|
|
135
|
-
for ep in
|
|
142
|
+
ep.classification in ("development", "auxiliary")
|
|
143
|
+
for ep in normalized_entry_points
|
|
136
144
|
):
|
|
137
145
|
gaps.append(AnalysisGap(
|
|
138
146
|
area="entry_points",
|
|
139
147
|
reason=(
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
148
|
+
"Critical: no production runtime entrypoint detected; detected entries are "
|
|
149
|
+
"development or auxiliary only. Add/verify a start/serve script, CLI bin, "
|
|
150
|
+
"or server bootstrap before using this context for automation."
|
|
143
151
|
),
|
|
144
152
|
impact="high",
|
|
145
153
|
))
|
|
146
|
-
elif all(ep.confidence == "low" for ep in
|
|
154
|
+
elif all(ep.confidence == "low" for ep in normalized_entry_points):
|
|
147
155
|
gaps.append(AnalysisGap(
|
|
148
156
|
area="entry_points",
|
|
149
|
-
reason="Entry points inferred from code patterns only
|
|
157
|
+
reason="Entry points inferred from code patterns only; no manifest script, CLI bin, or server bootstrap declaration found",
|
|
150
158
|
impact="medium",
|
|
151
159
|
))
|
|
152
160
|
|
|
@@ -196,12 +204,17 @@ class ConfidenceAnalyzer:
|
|
|
196
204
|
# Entry points: only consider production EPs for confidence scoring.
|
|
197
205
|
# Benchmark/example/dev-only entries are not evidence of production readiness.
|
|
198
206
|
production_eps = [
|
|
199
|
-
ep for ep in
|
|
200
|
-
if ep
|
|
207
|
+
ep for ep in normalized_entry_points
|
|
208
|
+
if is_production_entry_point(ep)
|
|
201
209
|
]
|
|
202
210
|
ep_conf = _max_confidence([ep.confidence for ep in production_eps] or ["low"])
|
|
203
211
|
overall = _min_confidence([stack_conf, ep_conf])
|
|
204
212
|
|
|
213
|
+
if normalized_entry_points and not production_eps:
|
|
214
|
+
overall = "low"
|
|
215
|
+
elif production_eps and all(ep.runtime_relevance == "low" for ep in production_eps):
|
|
216
|
+
overall = _min_confidence([overall, "low"])
|
|
217
|
+
|
|
205
218
|
# Factor in architecture confidence when available
|
|
206
219
|
arch = sm.architecture
|
|
207
220
|
if arch is not None and arch.requested:
|
|
@@ -58,7 +58,7 @@ class NodejsDetector(AbstractDetector):
|
|
|
58
58
|
|
|
59
59
|
from sourcecode.detectors.hybrid import merge_framework_detections, scan_for_frameworks
|
|
60
60
|
|
|
61
|
-
dependency_names = self._collect_dependency_names(package_json)
|
|
61
|
+
dependency_names = self._collect_dependency_names(package_json, runtime_only=True)
|
|
62
62
|
seen_fw: set[str] = set()
|
|
63
63
|
manifest_frameworks = []
|
|
64
64
|
for pkg_name, label in _FRAMEWORK_MAP.items():
|
|
@@ -98,9 +98,17 @@ class NodejsDetector(AbstractDetector):
|
|
|
98
98
|
signals.append("monorepo:npm-workspaces")
|
|
99
99
|
return signals
|
|
100
100
|
|
|
101
|
-
def _collect_dependency_names(
|
|
101
|
+
def _collect_dependency_names(
|
|
102
|
+
self,
|
|
103
|
+
package_json: dict[str, Any],
|
|
104
|
+
*,
|
|
105
|
+
runtime_only: bool = False,
|
|
106
|
+
) -> set[str]:
|
|
102
107
|
names: set[str] = set()
|
|
103
|
-
|
|
108
|
+
fields = ("dependencies", "peerDependencies", "optionalDependencies")
|
|
109
|
+
if not runtime_only:
|
|
110
|
+
fields = fields + ("devDependencies",)
|
|
111
|
+
for field in fields:
|
|
104
112
|
raw = package_json.get(field, {})
|
|
105
113
|
if isinstance(raw, dict):
|
|
106
114
|
names.update(str(name) for name in raw)
|
|
@@ -125,6 +133,9 @@ class NodejsDetector(AbstractDetector):
|
|
|
125
133
|
"playground", "playgrounds",
|
|
126
134
|
"fixture", "fixtures",
|
|
127
135
|
"sandbox", "e2e", "docs",
|
|
136
|
+
"test", "tests", "__tests__", "spec", "specs",
|
|
137
|
+
"scripts", "script", "tools", "tooling", "ci",
|
|
138
|
+
".storybook", "storybook",
|
|
128
139
|
})
|
|
129
140
|
|
|
130
141
|
def _collect_entry_points(
|
|
@@ -144,19 +155,20 @@ class NodejsDetector(AbstractDetector):
|
|
|
144
155
|
continue
|
|
145
156
|
# Extract file path from script command
|
|
146
157
|
path = self._extract_script_path(script_cmd, context)
|
|
158
|
+
if path is None:
|
|
159
|
+
path = self._infer_tool_script_path(script_name, script_cmd, context)
|
|
147
160
|
if path and path not in seen and path_exists_in_tree(context.file_tree, path):
|
|
148
161
|
seen.add(path)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
))
|
|
162
|
+
entry_points.append(EntryPoint(
|
|
163
|
+
path=path,
|
|
164
|
+
stack="nodejs",
|
|
165
|
+
kind=kind,
|
|
166
|
+
source="package.json#scripts",
|
|
167
|
+
confidence="high",
|
|
168
|
+
reason=f"script:{script_name}",
|
|
169
|
+
evidence=f"scripts.{script_name} = {script_cmd!r:.80}",
|
|
170
|
+
entrypoint_type=self._path_entrypoint_type(path, fallback=ep_type),
|
|
171
|
+
))
|
|
160
172
|
|
|
161
173
|
# Priority 2: package.json bin — CLI production entry points
|
|
162
174
|
bin_field = package_json.get("bin")
|
|
@@ -233,7 +245,7 @@ class NodejsDetector(AbstractDetector):
|
|
|
233
245
|
def _classify_script(self, script_name: str) -> tuple[str | None, str]:
|
|
234
246
|
"""Map script name → (entrypoint_type, kind). Returns (None, '') to skip."""
|
|
235
247
|
lower = script_name.lower()
|
|
236
|
-
if lower in ("start", "serve"):
|
|
248
|
+
if lower in ("start", "serve", "server"):
|
|
237
249
|
return "production", "server"
|
|
238
250
|
if lower in ("dev", "develop", "watch"):
|
|
239
251
|
return "development", "server"
|
|
@@ -243,6 +255,12 @@ class NodejsDetector(AbstractDetector):
|
|
|
243
255
|
return "benchmark", "script"
|
|
244
256
|
if lower.startswith("example") or lower.startswith("demo"):
|
|
245
257
|
return "example", "script"
|
|
258
|
+
if lower in {"docs", "doc", "storybook", "playground"} or any(
|
|
259
|
+
marker in lower for marker in ("rspress", "vite", "storybook", "playground")
|
|
260
|
+
):
|
|
261
|
+
return "development", "server"
|
|
262
|
+
if lower in {"test", "e2e", "spec", "lint", "format", "typecheck", "build"}:
|
|
263
|
+
return "development", "script"
|
|
246
264
|
return None, ""
|
|
247
265
|
|
|
248
266
|
def _extract_script_path(self, cmd: str, context: DetectionContext) -> str | None:
|
|
@@ -264,12 +282,36 @@ class NodejsDetector(AbstractDetector):
|
|
|
264
282
|
return p
|
|
265
283
|
return None
|
|
266
284
|
|
|
285
|
+
def _infer_tool_script_path(
|
|
286
|
+
self,
|
|
287
|
+
script_name: str,
|
|
288
|
+
script_cmd: str,
|
|
289
|
+
context: DetectionContext,
|
|
290
|
+
) -> str | None:
|
|
291
|
+
text = f"{script_name} {script_cmd}".lower()
|
|
292
|
+
candidates: list[str] = []
|
|
293
|
+
if "rspress" in text or "docs" in text or "doc" in text:
|
|
294
|
+
candidates.extend(["docs/rspress.mjs", "docs/rspress.config.mjs"])
|
|
295
|
+
if "storybook" in text:
|
|
296
|
+
candidates.extend([".storybook/main.js", ".storybook/main.ts"])
|
|
297
|
+
if "vite" in text or "playground" in text:
|
|
298
|
+
candidates.extend(["playground/vite.config.ts", "vite.config.ts"])
|
|
299
|
+
for candidate in candidates:
|
|
300
|
+
if path_exists_in_tree(context.file_tree, candidate):
|
|
301
|
+
return candidate
|
|
302
|
+
return None
|
|
303
|
+
|
|
267
304
|
def _is_auxiliary_path(self, path: str) -> bool:
|
|
268
305
|
norm = path.replace("\\", "/")
|
|
269
306
|
parts = norm.split("/")
|
|
270
307
|
return any(p.lower() in self._AUXILIARY_DIRS for p in parts)
|
|
271
308
|
|
|
272
|
-
def _path_entrypoint_type(self, path: str) -> str:
|
|
273
|
-
|
|
309
|
+
def _path_entrypoint_type(self, path: str, *, fallback: str = "production") -> str:
|
|
310
|
+
parts = {p.lower() for p in path.replace("\\", "/").split("/")}
|
|
311
|
+
if parts & {"benchmark", "benchmarks", "bench", "benches"}:
|
|
312
|
+
return "benchmark"
|
|
313
|
+
if parts & {"example", "examples", "demo", "demos", "fixture", "fixtures"}:
|
|
274
314
|
return "example"
|
|
275
|
-
|
|
315
|
+
if self._is_auxiliary_path(path):
|
|
316
|
+
return "development"
|
|
317
|
+
return fallback
|