@mriekki/project-forge 2.2.0 → 3.0.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/assets/components.json +3 -3
- package/assets/deployment/distribution.json +1 -1
- package/assets/generated/ASSEMBLY.json +25 -25
- package/assets/generated/core/core/process/DEPLOYMENT_ENABLEMENT.md +1 -1
- package/assets/generated/core/core/process/PROJECT_DOCUMENTATION_FRAMEWORK.md +3 -3
- package/assets/generated/core/core/process/PROJECT_FORGE_ENGINEERING_GUIDE.md +14 -14
- package/assets/generated/core/core/skills/deploy/SKILL.md +1 -1
- package/assets/generated/core/core/skills/deployment-readiness/SKILL.md +1 -1
- package/assets/generated/core/core/skills/progress/SKILL.md +1 -1
- package/assets/generated/core/core/skills/setup/SKILL.md +5 -5
- package/assets/generated/core/core/skills/tear-down/SKILL.md +4 -4
- package/assets/generated/deployment/docs/DEVELOPER_ENVIRONMENTS.md +11 -11
- package/assets/generated/deployment/docs/ENVIRONMENT_PROOF.md +2 -2
- package/assets/generated/deployment/docs/WORKSPACE_INSTANCES.md +1 -1
- package/assets/generated/deployment/docs/images/developer-environment-journey.svg +2 -2
- package/assets/generated/deployment/docs/images/{poc-environment-model.svg → project-environment-model.svg} +4 -4
- package/assets/generated/deployment/src/project_forge_deployment/cli.py +1 -1
- package/assets/generated/deployment/src/project_forge_deployment/entrypoint.py +1 -1
- package/assets/generated/deployment/src/project_forge_deployment/environment_probe.py +2 -2
- package/assets/generated/deployment/src/project_forge_deployment/route_registry.py +2 -2
- package/assets/generated/deployment/src/project_forge_deployment/teardown.py +7 -7
- package/assets/generated/deployment/src/project_forge_deployment/teardown_cli.py +6 -6
- package/assets/generated/deployment/src/project_forge_deployment/teardown_remote.py +6 -6
- package/package.json +1 -1
package/assets/components.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "@mriekki/project-forge",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"defaultProfile": "greenfield-project",
|
|
6
6
|
"profiles": {
|
|
7
7
|
"greenfield-project": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"components": {
|
|
15
15
|
"core": {
|
|
16
16
|
"repository": "mriekki/project-forge-core",
|
|
17
|
-
"commit": "
|
|
17
|
+
"commit": "17a09fc913a12902c4a9172e53bc70d421f5b0d5",
|
|
18
18
|
"version": "3.3.0",
|
|
19
19
|
"distribution": "greenfield-workspace",
|
|
20
20
|
"descriptor": "assets/core/distribution.json",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"deployment": {
|
|
25
25
|
"repository": "mriekki/project-forge-deployment-kit",
|
|
26
|
-
"commit": "
|
|
26
|
+
"commit": "0974f36bcb5062c4becb7c5c4e0fbc3e629ad4a9",
|
|
27
27
|
"distribution": "greenfield-project",
|
|
28
28
|
"descriptor": "assets/deployment/distribution.json",
|
|
29
29
|
"sourceRoot": "assets/generated/deployment",
|
|
@@ -49,6 +49,6 @@
|
|
|
49
49
|
{"source": "docs/ENVIRONMENT_PROOF.md", "destination": "docs/project-forge/ENVIRONMENT_PROOF.md"},
|
|
50
50
|
{"source": "docs/images/developer-environment-journey.svg", "destination": "docs/project-forge/images/developer-environment-journey.svg"},
|
|
51
51
|
{"source": "docs/images/personal-environment-architecture.svg", "destination": "docs/project-forge/images/personal-environment-architecture.svg"},
|
|
52
|
-
{"source": "docs/images/
|
|
52
|
+
{"source": "docs/images/project-environment-model.svg", "destination": "docs/project-forge/images/project-environment-model.svg"}
|
|
53
53
|
]
|
|
54
54
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "@mriekki/project-forge",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"components": {
|
|
6
6
|
"core": {
|
|
7
7
|
"repository": "mriekki/project-forge-core",
|
|
8
|
-
"commit": "
|
|
8
|
+
"commit": "17a09fc913a12902c4a9172e53bc70d421f5b0d5",
|
|
9
9
|
"version": "3.3.0",
|
|
10
10
|
"distribution": "greenfield-workspace",
|
|
11
11
|
"files": [
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
{
|
|
63
63
|
"source": "core/skills/setup/SKILL.md",
|
|
64
64
|
"destination": ".github/skills/setup/SKILL.md",
|
|
65
|
-
"sha256": "
|
|
65
|
+
"sha256": "60dcb93e98f6f00177e9e2d406c55f15bd59ebf8607c3f79ae464fe7c00616b6"
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
"source": "core/skills/build/SKILL.md",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
{
|
|
88
88
|
"source": "core/skills/progress/SKILL.md",
|
|
89
89
|
"destination": ".github/skills/progress/SKILL.md",
|
|
90
|
-
"sha256": "
|
|
90
|
+
"sha256": "9b0ba914529e6bd91ad5fd7a30f666884c1687b35b847bfe77ed745c50f0fd12"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"source": "core/skills/next-step/SKILL.md",
|
|
@@ -137,17 +137,17 @@
|
|
|
137
137
|
{
|
|
138
138
|
"source": "core/skills/deployment-readiness/SKILL.md",
|
|
139
139
|
"destination": ".github/skills/deployment-readiness/SKILL.md",
|
|
140
|
-
"sha256": "
|
|
140
|
+
"sha256": "82eaf37f8acc4e3d69871a02ad38ab9bf94caccaa0b3a40784dbb622621e112c"
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"source": "core/skills/deploy/SKILL.md",
|
|
144
144
|
"destination": ".github/skills/deploy/SKILL.md",
|
|
145
|
-
"sha256": "
|
|
145
|
+
"sha256": "8296d5cdd166dc5e0125df5d8ebc83d901a04f71caad8563ec67e9d02761955a"
|
|
146
146
|
},
|
|
147
147
|
{
|
|
148
148
|
"source": "core/skills/tear-down/SKILL.md",
|
|
149
149
|
"destination": ".github/skills/tear-down/SKILL.md",
|
|
150
|
-
"sha256": "
|
|
150
|
+
"sha256": "7565b5600af2883abfc47bac29abfd056cfa81536c52408b07da82f696b335b8"
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
153
|
"source": "core/skills/coach/SKILL.md",
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
{
|
|
193
193
|
"source": "core/process/DEPLOYMENT_ENABLEMENT.md",
|
|
194
194
|
"destination": "docs/process/DEPLOYMENT_ENABLEMENT.md",
|
|
195
|
-
"sha256": "
|
|
195
|
+
"sha256": "fa4f0bf3929d7d07b0061191232d39a7d03ae5e1e334e2aeafd27bad83b845fc"
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
"source": "core/process/HUMAN_GATES.md",
|
|
@@ -227,12 +227,12 @@
|
|
|
227
227
|
{
|
|
228
228
|
"source": "core/process/PROJECT_DOCUMENTATION_FRAMEWORK.md",
|
|
229
229
|
"destination": "docs/process/PROJECT_DOCUMENTATION_FRAMEWORK.md",
|
|
230
|
-
"sha256": "
|
|
230
|
+
"sha256": "bcb9f73dad1490ac5b45fe1bac931d488112727bad537534d8b9ffd5b115d84b"
|
|
231
231
|
},
|
|
232
232
|
{
|
|
233
233
|
"source": "core/process/PROJECT_FORGE_ENGINEERING_GUIDE.md",
|
|
234
234
|
"destination": "docs/project-forge/PROJECT_FORGE_ENGINEERING_GUIDE.md",
|
|
235
|
-
"sha256": "
|
|
235
|
+
"sha256": "c09e0f088682302751d2f98629959cc4dab5e8a441ba19fb3417468e3895cc20"
|
|
236
236
|
},
|
|
237
237
|
{
|
|
238
238
|
"source": "core/process/SETUP_ACCEPTANCE_CHECKLIST.md",
|
|
@@ -348,7 +348,7 @@
|
|
|
348
348
|
},
|
|
349
349
|
"deployment": {
|
|
350
350
|
"repository": "mriekki/project-forge-deployment-kit",
|
|
351
|
-
"commit": "
|
|
351
|
+
"commit": "0974f36bcb5062c4becb7c5c4e0fbc3e629ad4a9",
|
|
352
352
|
"distribution": "greenfield-project",
|
|
353
353
|
"files": [
|
|
354
354
|
{
|
|
@@ -404,7 +404,7 @@
|
|
|
404
404
|
{
|
|
405
405
|
"source": "src/project_forge_deployment/cli.py",
|
|
406
406
|
"destination": "tools/project-forge-deployment/project_forge_deployment/cli.py",
|
|
407
|
-
"sha256": "
|
|
407
|
+
"sha256": "3c3e7d4fadeccc1b8a7691c1a213250790fb728400914894c0d4e70a1ec91cc7"
|
|
408
408
|
},
|
|
409
409
|
{
|
|
410
410
|
"source": "src/project_forge_deployment/doctor.py",
|
|
@@ -414,7 +414,7 @@
|
|
|
414
414
|
{
|
|
415
415
|
"source": "src/project_forge_deployment/entrypoint.py",
|
|
416
416
|
"destination": "tools/project-forge-deployment/project_forge_deployment/entrypoint.py",
|
|
417
|
-
"sha256": "
|
|
417
|
+
"sha256": "94c5eeff4ef684a4665909f7710d95fb4f65c118a71f60782b048697d6a495dd"
|
|
418
418
|
},
|
|
419
419
|
{
|
|
420
420
|
"source": "src/project_forge_deployment/environment_cli.py",
|
|
@@ -424,7 +424,7 @@
|
|
|
424
424
|
{
|
|
425
425
|
"source": "src/project_forge_deployment/environment_probe.py",
|
|
426
426
|
"destination": "tools/project-forge-deployment/project_forge_deployment/environment_probe.py",
|
|
427
|
-
"sha256": "
|
|
427
|
+
"sha256": "3971264b425c9eb49845a48a54aea849ef35b36b86b13017c0946d3b90e9d707"
|
|
428
428
|
},
|
|
429
429
|
{
|
|
430
430
|
"source": "src/project_forge_deployment/errors.py",
|
|
@@ -499,7 +499,7 @@
|
|
|
499
499
|
{
|
|
500
500
|
"source": "src/project_forge_deployment/route_registry.py",
|
|
501
501
|
"destination": "tools/project-forge-deployment/project_forge_deployment/route_registry.py",
|
|
502
|
-
"sha256": "
|
|
502
|
+
"sha256": "ea08753878e9e6b59a8986aac7e40e40f66651cc704fff50842badf956705744"
|
|
503
503
|
},
|
|
504
504
|
{
|
|
505
505
|
"source": "src/project_forge_deployment/route_registry_remote.py",
|
|
@@ -539,17 +539,17 @@
|
|
|
539
539
|
{
|
|
540
540
|
"source": "src/project_forge_deployment/teardown.py",
|
|
541
541
|
"destination": "tools/project-forge-deployment/project_forge_deployment/teardown.py",
|
|
542
|
-
"sha256": "
|
|
542
|
+
"sha256": "08215b8b5fa87ca8abf96f10f38aca0207840bd1b1faf4c2c53cb691caf20a72"
|
|
543
543
|
},
|
|
544
544
|
{
|
|
545
545
|
"source": "src/project_forge_deployment/teardown_cli.py",
|
|
546
546
|
"destination": "tools/project-forge-deployment/project_forge_deployment/teardown_cli.py",
|
|
547
|
-
"sha256": "
|
|
547
|
+
"sha256": "214987895cde77648b5274042f1c21557046c3bf76224bfdd415ea34fec3d873"
|
|
548
548
|
},
|
|
549
549
|
{
|
|
550
550
|
"source": "src/project_forge_deployment/teardown_remote.py",
|
|
551
551
|
"destination": "tools/project-forge-deployment/project_forge_deployment/teardown_remote.py",
|
|
552
|
-
"sha256": "
|
|
552
|
+
"sha256": "ad764f5a67c43f81b4973dd5639b2c28b23ae883a85e5ae29efc14dad506e88e"
|
|
553
553
|
},
|
|
554
554
|
{
|
|
555
555
|
"source": "src/project_forge_deployment/trust.py",
|
|
@@ -559,22 +559,22 @@
|
|
|
559
559
|
{
|
|
560
560
|
"source": "docs/DEVELOPER_ENVIRONMENTS.md",
|
|
561
561
|
"destination": "docs/project-forge/DEVELOPER_ENVIRONMENTS.md",
|
|
562
|
-
"sha256": "
|
|
562
|
+
"sha256": "e818931055044f6158ffe321303a5cbcd2f58724430d51e87c1688e1f71a8fbc"
|
|
563
563
|
},
|
|
564
564
|
{
|
|
565
565
|
"source": "docs/WORKSPACE_INSTANCES.md",
|
|
566
566
|
"destination": "docs/project-forge/WORKSPACE_INSTANCES.md",
|
|
567
|
-
"sha256": "
|
|
567
|
+
"sha256": "43da263213d3822308d4a9bc57b53119e8b0abdc92e14afb354e88dedd2b0706"
|
|
568
568
|
},
|
|
569
569
|
{
|
|
570
570
|
"source": "docs/ENVIRONMENT_PROOF.md",
|
|
571
571
|
"destination": "docs/project-forge/ENVIRONMENT_PROOF.md",
|
|
572
|
-
"sha256": "
|
|
572
|
+
"sha256": "d139ec1691d073e845a679edf45cb01c971a40b3ccc31404efb8c1e81e481ea5"
|
|
573
573
|
},
|
|
574
574
|
{
|
|
575
575
|
"source": "docs/images/developer-environment-journey.svg",
|
|
576
576
|
"destination": "docs/project-forge/images/developer-environment-journey.svg",
|
|
577
|
-
"sha256": "
|
|
577
|
+
"sha256": "f799027ee52105f482231998ecda9bf6f6e05590f131ec0c7d04cd8d27b3ca51"
|
|
578
578
|
},
|
|
579
579
|
{
|
|
580
580
|
"source": "docs/images/personal-environment-architecture.svg",
|
|
@@ -582,9 +582,9 @@
|
|
|
582
582
|
"sha256": "a2d5a4a6b52eaa451bb3b28eb9a856a30750b00e9f1c5932c645bdc8e96f935f"
|
|
583
583
|
},
|
|
584
584
|
{
|
|
585
|
-
"source": "docs/images/
|
|
586
|
-
"destination": "docs/project-forge/images/
|
|
587
|
-
"sha256": "
|
|
585
|
+
"source": "docs/images/project-environment-model.svg",
|
|
586
|
+
"destination": "docs/project-forge/images/project-environment-model.svg",
|
|
587
|
+
"sha256": "357896c40ff2c7a93bf77811af61d2559103d2e386a5fd887c7041d016114b10"
|
|
588
588
|
}
|
|
589
589
|
]
|
|
590
590
|
}
|
|
@@ -104,7 +104,7 @@ Keep their targetable scope, runtime/container, route, data, readiness evidence,
|
|
|
104
104
|
TOPOLOGY NOTE
|
|
105
105
|
|
|
106
106
|
Staging and Production are logically isolated but share one physical
|
|
107
|
-
failure domain. This may fit
|
|
107
|
+
failure domain. This may fit Project cost/learning goals, but it does not
|
|
108
108
|
demonstrate host-level Production isolation.
|
|
109
109
|
```
|
|
110
110
|
|
|
@@ -15,7 +15,7 @@ Project Forge project documentation is a small, evidence-aware engineering syste
|
|
|
15
15
|
|
|
16
16
|
## Canonical shape
|
|
17
17
|
|
|
18
|
-
Greenfield
|
|
18
|
+
Greenfield Projects should normally converge on:
|
|
19
19
|
|
|
20
20
|
```text
|
|
21
21
|
README.md
|
|
@@ -82,7 +82,7 @@ Keep it short. It should answer:
|
|
|
82
82
|
|
|
83
83
|
`PROJECT_BRIEF.md` is the integrated project briefing and navigation surface. It may summarize approved product scope, stack, environments, initial work items, learning goals, and important documentation links.
|
|
84
84
|
|
|
85
|
-
It is **not** a second requirements authority. In a normal Project Forge greenfield
|
|
85
|
+
It is **not** a second requirements authority. In a normal Project Forge greenfield Project:
|
|
86
86
|
|
|
87
87
|
- `docs/product/PRODUCT_BRIEF.md` remains product authority;
|
|
88
88
|
- approved work-item briefs/requirements remain work-item authority;
|
|
@@ -143,7 +143,7 @@ Recommended schema:
|
|
|
143
143
|
{
|
|
144
144
|
"schemaVersion": 1,
|
|
145
145
|
"site": {
|
|
146
|
-
"title": "Example
|
|
146
|
+
"title": "Example Project",
|
|
147
147
|
"entry": "PROJECT_BRIEF.md"
|
|
148
148
|
},
|
|
149
149
|
"documents": [
|
|
@@ -31,7 +31,7 @@ The platform lowers the friction of starting a personal project while preserving
|
|
|
31
31
|
| Choice | Select a technology direction based on project needs or learning goals, with explicit support-state signals rather than hidden assumptions. |
|
|
32
32
|
| Discipline | Use a Project Forge workflow with bounded implementation, review, CI evidence, and meaningful human acceptance points. |
|
|
33
33
|
| Learning | Build understanding alongside code through work-item guides, code walkthroughs, learning review, and targeted coaching. |
|
|
34
|
-
| Realism | Exercise containerization, source control, CI, releases, environment isolation, and deployment tradeoffs without pretending every
|
|
34
|
+
| Realism | Exercise containerization, source control, CI, releases, environment isolation, and deployment tradeoffs without pretending every Project needs dedicated Staging/Production computers. |
|
|
35
35
|
| Repeatability | Create self-contained generated repositories with explicit provenance and controlled platform updates. |
|
|
36
36
|
|
|
37
37
|
### Why this is different from “generate me an app”
|
|
@@ -65,23 +65,23 @@ Clear ownership boundaries keep process, package transport, orchestration, deplo
|
|
|
65
65
|
|
|
66
66
|
```mermaid
|
|
67
67
|
flowchart TB
|
|
68
|
-
BOOT[
|
|
69
|
-
CORE[Agentic Core<br/>Workflow, agents, skills,<br/>HITL gates, learning] -->
|
|
70
|
-
PLATFORM[Project Forge Platform / @mriekki/project-forge<br/>Exact accepted reusable components] -->
|
|
71
|
-
CONTROL[Control Plane<br/>GitHub App orchestration<br/>and safe publication] -->
|
|
72
|
-
DEPLOY[Deployment Kit<br/>Workstation + remote-target mechanics] -->
|
|
68
|
+
BOOT[Project Bootstrap<br/>Discovery, catalog, manifests,<br/>deterministic generation] --> PROJECT[Generated Project<br/>self-contained consumer]
|
|
69
|
+
CORE[Agentic Core<br/>Workflow, agents, skills,<br/>HITL gates, learning] --> PROJECT
|
|
70
|
+
PLATFORM[Project Forge Platform / @mriekki/project-forge<br/>Exact accepted reusable components] --> PROJECT
|
|
71
|
+
CONTROL[Control Plane<br/>GitHub App orchestration<br/>and safe publication] --> PROJECT
|
|
72
|
+
DEPLOY[Deployment Kit<br/>Workstation + remote-target mechanics] --> PROJECT
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
| Layer | Responsibility |
|
|
76
76
|
| --- | --- |
|
|
77
|
-
|
|
|
77
|
+
| Project Bootstrap | Discovery protocol, catalog/support states, approved `PROJECT_BOOTSTRAP.json`, deployment topology intent, deterministic generation, setup/readiness helpers, work-item materialization. |
|
|
78
78
|
| Agentic Core | Reusable workflow behavior, agents/skills, Human-in-the-Loop gates, review/delivery semantics, learning flows, topology-aware deployment orchestration. |
|
|
79
79
|
| Project Forge Platform | Consumer-facing `@mriekki/project-forge` package that assembles exact accepted reusable components and records provenance. |
|
|
80
80
|
| Control Plane | GitHub App orchestration for target validation, short-lived scoped credentials, deterministic generation, and safe publication. |
|
|
81
81
|
| Deployment Kit | Reusable one-workstation loopback-container runtime plus strict remote target/access, Ubuntu/Docker/Caddy routing, persistence, and scoped tear-down mechanics. Managed hosting remains adapter-specific rather than generic implied support. |
|
|
82
|
-
| Generated
|
|
82
|
+
| Generated Project | Owns product scope, architecture, code/tests, work items, CI evidence, logical environment/topology facts, concrete deployment bindings, accepted baselines, and implementation history. |
|
|
83
83
|
|
|
84
|
-
**Architectural outcome:** a generated
|
|
84
|
+
**Architectural outcome:** a generated Project remains usable on its own. Normal development and deployment do not depend on sibling clones of the platform repositories.
|
|
85
85
|
|
|
86
86
|
---
|
|
87
87
|
|
|
@@ -191,7 +191,7 @@ flowchart LR
|
|
|
191
191
|
|
|
192
192
|
### Use AI to increase capability, not only throughput
|
|
193
193
|
|
|
194
|
-
The system treats a personal
|
|
194
|
+
The system treats a personal Project as both a software deliverable and a deliberate learning vehicle — without turning learning into a release gate.
|
|
195
195
|
|
|
196
196
|
- **Embedded context** — work-item Implementation & Learning Guides connect engineering outcomes to concepts, reasoning prompts, things to notice, hands-on opportunities, and learning evidence.
|
|
197
197
|
- **Code walkthrough** — `/code-walkthrough` explains the actual implementation, architecture boundaries, control flow, and important tradeoffs after the work exists.
|
|
@@ -271,7 +271,7 @@ The original briefing used Family Meal Planner v3 to demonstrate re-baselining a
|
|
|
271
271
|
- **Selected stack:** `dotnet-react-sqlite` recipe with partial support; generic scaffold intentionally deferred rather than allowed to overwrite mature architecture decisions.
|
|
272
272
|
- **First work item:** EN-001 — Application Foundation / Walking Skeleton: prove React, ASP.NET, browser-to-API, SQLite through approved layers, dependency injection, health/system info, Compose, and CI.
|
|
273
273
|
- **App-specific deployment model in that reference consumer:** Production and Staging are distinct Ubuntu environments over trusted-LAN SSH with separate target/access contracts and no cross-environment fallback.
|
|
274
|
-
- **Learning goal:** use the project as a hands-on software-engineering
|
|
274
|
+
- **Learning goal:** use the project as a hands-on software-engineering Project and build enough understanding to review and explain the system rather than only accept generated implementation.
|
|
275
275
|
- **Lifecycle point in the original briefing:** the v3 repository had an approved seed manifest and was at the GitHub-first generation handoff when the original briefings were prepared.
|
|
276
276
|
|
|
277
277
|
The FMP topology is an **example consumer choice**, not a reusable requirement for other Project Forge users.
|
|
@@ -287,13 +287,13 @@ The FMP topology is an **example consumer choice**, not a reusable requirement f
|
|
|
287
287
|
The strongest claim is not that AI can do everything. It is that a reusable operating model can make disciplined engineering the lowest-friction way to explore an idea.
|
|
288
288
|
|
|
289
289
|
- **Not “any stack, fully automated.”** Technology choice is broad; Bootstrap automation is claimed only where the live catalog supports it.
|
|
290
|
-
- **Not “every
|
|
290
|
+
- **Not “every Project needs servers.”** One-machine local/demo and explicitly deferred deployment are valid outcomes.
|
|
291
291
|
- **Not generic cloud support.** A plausible provider is not supported until a provider adapter is cataloged, implemented, and proven.
|
|
292
292
|
- **Not autonomous Production.** Merge, CI, or release publication never implies Production deployment. Production and destructive operations remain separately gated regardless of placement.
|
|
293
293
|
- **Not model-dependent.** Repository-local workflow assets define behavior; Core does not rely on one fixed AI model to preserve the engineering process.
|
|
294
|
-
- **Not hidden regeneration.** Generated
|
|
294
|
+
- **Not hidden regeneration.** Generated Projects are self-contained consumers. Reusable updates go through controlled package/baseline paths rather than silent wholesale regeneration.
|
|
295
295
|
- **AI drift is bounded.** Repository protocol, catalog, baselines, and project-owned artifacts outrank conversational inference about project state.
|
|
296
|
-
- **Still a
|
|
296
|
+
- **Still a Project platform.** This is a disciplined engineering Project platform with strong foundations and explicit remaining proof/maturity work — not a finished enterprise developer platform.
|
|
297
297
|
|
|
298
298
|
### Strategic takeaway
|
|
299
299
|
|
|
@@ -48,7 +48,7 @@ Read only what is needed, including when present:
|
|
|
48
48
|
- fresh setup-time environment-proof evidence for this workstation;
|
|
49
49
|
- established application deployment facts.
|
|
50
50
|
|
|
51
|
-
For package-managed generated
|
|
51
|
+
For package-managed generated Projects, prefer the repository-distributed launcher:
|
|
52
52
|
|
|
53
53
|
```text
|
|
54
54
|
tools/project-forge-deployment/project-forge-deploy.py
|
|
@@ -171,7 +171,7 @@ select exact project-defined environment
|
|
|
171
171
|
→ /deploy <environment>
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
For remote placement, reuse valid existing target access rather than creating duplicate credentials simply because another
|
|
174
|
+
For remote placement, reuse valid existing target access rather than creating duplicate credentials simply because another Project/environment uses the same machine.
|
|
175
175
|
|
|
176
176
|
## 6. Read-only status
|
|
177
177
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: progress
|
|
3
|
-
description: "Read-only developer-facing progress view across
|
|
3
|
+
description: "Read-only developer-facing progress view across Project creation, this workspace instance, work-item/delivery state, and exact project-defined environment capabilities."
|
|
4
4
|
argument-hint: "[optional work-item ID or environment]"
|
|
5
5
|
user-invocable: true
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -8,7 +8,7 @@ disable-model-invocation: true
|
|
|
8
8
|
|
|
9
9
|
# Setup
|
|
10
10
|
|
|
11
|
-
Purpose: give the developer one obvious entry point after cloning/opening a Project Forge workspace, whether this is the first workstation for the project or an additional independent workstation for an existing
|
|
11
|
+
Purpose: give the developer one obvious entry point after cloning/opening a Project Forge workspace, whether this is the first workstation for the project or an additional independent workstation for an existing Project.
|
|
12
12
|
|
|
13
13
|
Normal first use is simply:
|
|
14
14
|
|
|
@@ -107,7 +107,7 @@ Each workstation normally owns independent local development data. Reproduce sch
|
|
|
107
107
|
|
|
108
108
|
## 4. Establish/sync the developer's personal Project Forge profile
|
|
109
109
|
|
|
110
|
-
When the installed Deployment Kit exposes personal-profile operations, `/setup` should establish the authenticated developer's portable non-secret profile as routine setup state. This repo is per developer, not per
|
|
110
|
+
When the installed Deployment Kit exposes personal-profile operations, `/setup` should establish the authenticated developer's portable non-secret profile as routine setup state. This repo is per developer, not per Project or workstation.
|
|
111
111
|
|
|
112
112
|
First inspect profile status and authenticated GitHub login. If the expected private repository is missing, tell the developer what will happen before writing:
|
|
113
113
|
|
|
@@ -170,7 +170,7 @@ Use `PROJECT_BOOTSTRAP.json` deployment topology only as the initial topology fa
|
|
|
170
170
|
|
|
171
171
|
`PROJECT_BOOTSTRAP.json` is generation/provenance evidence and should not be casually rewritten merely because a developer adds an environment later.
|
|
172
172
|
|
|
173
|
-
If an older
|
|
173
|
+
If an older Project has no `DEPLOYMENT_TOPOLOGY.json` and the developer chooses to add/change a logical environment, first materialize the currently approved deployment topology into the project-owned file, then make the scoped project configuration change there. Preserve the original Bootstrap provenance file.
|
|
174
174
|
|
|
175
175
|
A topology entry should keep logical identity distinct from purpose and placement. A name such as `demo`, `qa`, or `prod-east` is the command-facing environment identity. Its purpose remains one of the project-supported semantic roles such as development/demo/staging/production.
|
|
176
176
|
|
|
@@ -220,7 +220,7 @@ If host prerequisites cannot yet be prepared automatically, report the exact pre
|
|
|
220
220
|
|
|
221
221
|
When the installed Deployment Kit exposes environment proof operations, a selected remote environment should normally be taken through an end-to-end **environment proof deployment** during setup.
|
|
222
222
|
|
|
223
|
-
The proof is not the
|
|
223
|
+
The proof is not the Project application. It is a tiny disposable Project Forge-owned probe that should:
|
|
224
224
|
|
|
225
225
|
```text
|
|
226
226
|
acquire a small stable probe image on this workstation
|
|
@@ -349,7 +349,7 @@ When the installed Deployment Kit exposes profile migration and this workstation
|
|
|
349
349
|
|
|
350
350
|
Never ask the developer to paste passwords, PATs, private SSH keys, or other credentials into chat.
|
|
351
351
|
|
|
352
|
-
When a repository/tool needs a credential, direct the deterministic local tool to prompt in the local terminal using a hidden/secure prompt. Secrets remain workstation-local and must not be committed to the
|
|
352
|
+
When a repository/tool needs a credential, direct the deterministic local tool to prompt in the local terminal using a hidden/secure prompt. Secrets remain workstation-local and must not be committed to the Project repository or portable profile.
|
|
353
353
|
|
|
354
354
|
## 13. Relationship to other Project Forge commands
|
|
355
355
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tear-down
|
|
3
|
-
description: "Guided destructive cleanup for local state, one exact repository-defined named environment, or all explicitly configured
|
|
3
|
+
description: "Guided destructive cleanup for local state, one exact repository-defined named environment, or all explicitly configured Project environments. Preserves ownership boundaries and resolved Production-data authorization."
|
|
4
4
|
argument-hint: "[local|<environment>|all]"
|
|
5
5
|
user-invocable: true
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -8,7 +8,7 @@ disable-model-invocation: true
|
|
|
8
8
|
|
|
9
9
|
# Tear Down
|
|
10
10
|
|
|
11
|
-
`/tear-down` is the human-facing destructive cleanup workflow for repository-owned
|
|
11
|
+
`/tear-down` is the human-facing destructive cleanup workflow for repository-owned Project state.
|
|
12
12
|
|
|
13
13
|
Logical environment names are data-driven and are not limited to Staging/Production:
|
|
14
14
|
|
|
@@ -47,7 +47,7 @@ all
|
|
|
47
47
|
|
|
48
48
|
If no scope is named, present only scopes the repository actually supports; never silently default to a Production environment or `all`.
|
|
49
49
|
|
|
50
|
-
`all` means only all explicitly configured scopes for this
|
|
50
|
+
`all` means only all explicitly configured scopes for this Project; it never means machine-wide cleanup.
|
|
51
51
|
|
|
52
52
|
Selecting scope does not authorize deletion. Physical colocation never merges ownership: deleting `demo` must not remove `staging` or `prod-east` merely because they share hardware.
|
|
53
53
|
|
|
@@ -99,7 +99,7 @@ Do not promise deletion of named/shared Docker volumes unless the installed dete
|
|
|
99
99
|
Every modifying tear-down requires the installed normal authorization, conceptually:
|
|
100
100
|
|
|
101
101
|
```text
|
|
102
|
-
[
|
|
102
|
+
[PROJECT TEAR DOWN]
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
whenever **any selected environment is Production-class**, require the stronger Production-data deletion authorization, conceptually:
|
|
@@ -13,7 +13,7 @@ The happy path intentionally hides Bootstrap/package/control-plane plumbing. Dev
|
|
|
13
13
|
The normal progression is:
|
|
14
14
|
|
|
15
15
|
```text
|
|
16
|
-
generated
|
|
16
|
+
generated Project repository
|
|
17
17
|
→ clone/open workspace
|
|
18
18
|
→ /setup
|
|
19
19
|
→ LOCAL READY
|
|
@@ -42,7 +42,7 @@ The normal conversational entry point is:
|
|
|
42
42
|
|
|
43
43
|
`/setup` explains the current state/options and invokes the correct repository-local setup launcher. Direct script invocation remains the non-AI/automation fallback.
|
|
44
44
|
|
|
45
|
-
The first local success target is `LOCAL WORKSPACE READY`. Remote access must not block it unless the
|
|
45
|
+
The first local success target is `LOCAL WORKSPACE READY`. Remote access must not block it unless the Project explicitly requires a remote dependency for local development.
|
|
46
46
|
|
|
47
47
|
## Progress and next action
|
|
48
48
|
|
|
@@ -156,11 +156,11 @@ A changed previously pinned host key remains a blocker and requires explicit tru
|
|
|
156
156
|
|
|
157
157
|
## Docker and host preparation
|
|
158
158
|
|
|
159
|
-
Docker is a workstation/target capability, not something every
|
|
159
|
+
Docker is a workstation/target capability, not something every Project should reinstall.
|
|
160
160
|
|
|
161
161
|
### Developer workstation
|
|
162
162
|
|
|
163
|
-
The first
|
|
163
|
+
The first Project on a computer may install/verify required local tools and Docker through the generated setup contract. Later Projects reuse the ready workstation.
|
|
164
164
|
|
|
165
165
|
### Remote Ubuntu target
|
|
166
166
|
|
|
@@ -209,17 +209,17 @@ A credential needed to acquire a private image is entered only through the local
|
|
|
209
209
|
|
|
210
210
|
If the exact immutable image is already cached locally, registry authentication is not required merely to transfer it to the remote target.
|
|
211
211
|
|
|
212
|
-
##
|
|
212
|
+
## Project environment model
|
|
213
213
|
|
|
214
|
-

|
|
215
215
|
|
|
216
|
-
The
|
|
216
|
+
The Project owns project-specific facts such as environment identities/roles, placement, target binding, application image, runtime/health contract, persistence, routes/exposure, and Production classification/authorization.
|
|
217
217
|
|
|
218
|
-
The reusable workstation/target layer owns machine mechanics. A
|
|
218
|
+
The reusable workstation/target layer owns machine mechanics. A Project references targets; it does not own or duplicate a developer's private credentials.
|
|
219
219
|
|
|
220
220
|
## New workstation
|
|
221
221
|
|
|
222
|
-
A developer normally starts from any generated
|
|
222
|
+
A developer normally starts from any generated Project:
|
|
223
223
|
|
|
224
224
|
```text
|
|
225
225
|
clone repository
|
|
@@ -233,7 +233,7 @@ When GitHub is reachable, personal profile sync supplies portable target definit
|
|
|
233
233
|
|
|
234
234
|
## New remote box
|
|
235
235
|
|
|
236
|
-
Adding a new remote target is a workstation-driven onboarding operation, not a
|
|
236
|
+
Adding a new remote target is a workstation-driven onboarding operation, not a Project implementation step:
|
|
237
237
|
|
|
238
238
|
```text
|
|
239
239
|
add/import portable target definition
|
|
@@ -243,7 +243,7 @@ add/import portable target definition
|
|
|
243
243
|
→ TARGET READY
|
|
244
244
|
```
|
|
245
245
|
|
|
246
|
-
Once ready, multiple
|
|
246
|
+
Once ready, multiple Projects can bind logical environments to that target without repeating host bootstrap.
|
|
247
247
|
|
|
248
248
|
## Portable export/import fallback
|
|
249
249
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Environment Proof Deployment
|
|
2
2
|
|
|
3
|
-
A Project Forge environment proof verifies that one developer workstation can exercise the real remote deployment path for one exact named logical environment before the
|
|
3
|
+
A Project Forge environment proof verifies that one developer workstation can exercise the real remote deployment path for one exact named logical environment before the Project application exists or before its first real deployment.
|
|
4
4
|
|
|
5
5
|
It is intentionally **not** the project application.
|
|
6
6
|
|
|
@@ -84,7 +84,7 @@ The proof attempts cleanup even when deployment raises after mutation begins.
|
|
|
84
84
|
|
|
85
85
|
Successful completion requires terminal cleanup evidence (`removed` or already `absent`) for the reserved probe runtime. If deployment succeeds but cleanup cannot be verified, the command fails rather than reporting a clean proof.
|
|
86
86
|
|
|
87
|
-
The probe must not delete another
|
|
87
|
+
The probe must not delete another Project, another application, another logical environment, or shared host platform state.
|
|
88
88
|
|
|
89
89
|
## Relationship to `/setup` and `/deploy`
|
|
90
90
|
|
|
@@ -63,7 +63,7 @@ Local mutable application data is not synchronized between workstations by Proje
|
|
|
63
63
|
|
|
64
64
|
## Setup on another workstation
|
|
65
65
|
|
|
66
|
-
The normal flow for an existing generated
|
|
66
|
+
The normal flow for an existing generated Project is:
|
|
67
67
|
|
|
68
68
|
```text
|
|
69
69
|
clone repository
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="520" viewBox="0 0 1200 520" role="img" aria-labelledby="title desc">
|
|
2
2
|
<title id="title">Project Forge developer environment journey</title>
|
|
3
|
-
<desc id="desc">Generated
|
|
3
|
+
<desc id="desc">Generated Project repository progresses through clone and setup to local ready, then optionally to staging ready and production ready.</desc>
|
|
4
4
|
<defs>
|
|
5
5
|
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
6
6
|
<stop offset="0" stop-color="#0b1220"/>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<g filter="url(#shadow)" font-family="Inter,Segoe UI,Arial,sans-serif">
|
|
21
21
|
<rect x="70" y="180" width="205" height="128" rx="18" fill="#1e2a40" stroke="#405274" stroke-width="2"/>
|
|
22
22
|
<text x="172" y="222" text-anchor="middle" font-size="15" font-weight="700" fill="#91a4c4">PROJECT</text>
|
|
23
|
-
<text x="172" y="254" text-anchor="middle" font-size="22" font-weight="700" fill="#ffffff">Generated
|
|
23
|
+
<text x="172" y="254" text-anchor="middle" font-size="22" font-weight="700" fill="#ffffff">Generated Project</text>
|
|
24
24
|
<text x="172" y="282" text-anchor="middle" font-size="15" fill="#b8c5d8">clone + open workspace</text>
|
|
25
25
|
|
|
26
26
|
<rect x="360" y="180" width="205" height="128" rx="18" fill="#1f3440" stroke="#3b7584" stroke-width="2"/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720" role="img" aria-labelledby="title desc">
|
|
2
2
|
<title id="title">Project Forge environment model</title>
|
|
3
|
-
<desc id="desc">A
|
|
3
|
+
<desc id="desc">A Project uses local workstation runtime and optional remote logical staging and production environments bound to reusable remote targets and shared host platform infrastructure.</desc>
|
|
4
4
|
<defs>
|
|
5
5
|
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
6
6
|
<stop offset="0" stop-color="#0b1220"/>
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
</marker>
|
|
15
15
|
</defs>
|
|
16
16
|
<rect width="1200" height="720" rx="24" fill="url(#bg)"/>
|
|
17
|
-
<text x="70" y="70" font-family="Inter,Segoe UI,Arial,sans-serif" font-size="30" font-weight="700" fill="#f7f9fc">
|
|
18
|
-
<text x="70" y="102" font-family="Inter,Segoe UI,Arial,sans-serif" font-size="17" fill="#aebbd0">The
|
|
17
|
+
<text x="70" y="70" font-family="Inter,Segoe UI,Arial,sans-serif" font-size="30" font-weight="700" fill="#f7f9fc">Project Environment Model</text>
|
|
18
|
+
<text x="70" y="102" font-family="Inter,Segoe UI,Arial,sans-serif" font-size="17" fill="#aebbd0">The Project owns application/environment facts; reusable workstation and target layers own machine mechanics.</text>
|
|
19
19
|
|
|
20
20
|
<g filter="url(#shadow)" font-family="Inter,Segoe UI,Arial,sans-serif">
|
|
21
21
|
<rect x="390" y="135" width="420" height="106" rx="20" fill="#25294a" stroke="#7277c9" stroke-width="2"/>
|
|
22
|
-
<text x="600" y="176" text-anchor="middle" font-size="15" font-weight="700" fill="#aaaef1">GENERATED
|
|
22
|
+
<text x="600" y="176" text-anchor="middle" font-size="15" font-weight="700" fill="#aaaef1">GENERATED Project</text>
|
|
23
23
|
<text x="600" y="209" text-anchor="middle" font-size="21" font-weight="700" fill="#ffffff">Environment bindings + app runtime facts</text>
|
|
24
24
|
|
|
25
25
|
<rect x="95" y="330" width="300" height="190" rx="20" fill="#173c35" stroke="#3a9d82" stroke-width="2"/>
|
|
@@ -283,7 +283,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
283
283
|
route_inventory_parser.add_argument("--json", action="store_true")
|
|
284
284
|
|
|
285
285
|
route_register = route_sub.add_parser(
|
|
286
|
-
"register", help="Create or update one
|
|
286
|
+
"register", help="Create or update one Project/environment-owned Caddy + mDNS route"
|
|
287
287
|
)
|
|
288
288
|
route_register.add_argument("name")
|
|
289
289
|
route_register.add_argument("--owner-repo", required=True)
|
|
@@ -33,5 +33,5 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
33
33
|
print("Command group: local Loopback-only workstation application runtime")
|
|
34
34
|
print("Command group: registry Read-only exact-image registry access verification")
|
|
35
35
|
print("Command group: sqlite SQLite persistence import/backup/migration/rollback checks")
|
|
36
|
-
print("Command group: tear-down Scoped destructive
|
|
36
|
+
print("Command group: tear-down Scoped destructive Project environment/local cleanup")
|
|
37
37
|
return core_main(args)
|
|
@@ -14,7 +14,7 @@ from .app_runtime_workstation import apply_app_deploy_from_workstation
|
|
|
14
14
|
from .box_platform import platform_status
|
|
15
15
|
from .errors import DeploymentKitError
|
|
16
16
|
from .registry_access import normalize_registry_image
|
|
17
|
-
from .teardown import
|
|
17
|
+
from .teardown import tear_down_project
|
|
18
18
|
|
|
19
19
|
ENVIRONMENT_PROOF_WRITE_PHRASE = "[ENVIRONMENT PROOF WRITE]"
|
|
20
20
|
PRODUCTION_ENVIRONMENT_PROOF_WRITE_PHRASE = "[PRODUCTION ENVIRONMENT PROOF]"
|
|
@@ -171,7 +171,7 @@ def run_environment_proof(plan: dict[str, Any]) -> dict[str, Any]:
|
|
|
171
171
|
deploy_error = error
|
|
172
172
|
finally:
|
|
173
173
|
try:
|
|
174
|
-
cleanup =
|
|
174
|
+
cleanup = tear_down_project(
|
|
175
175
|
{
|
|
176
176
|
"ownerRepo": plan["ownerRepo"],
|
|
177
177
|
"appSlug": plan["probeAppSlug"],
|
|
@@ -270,7 +270,7 @@ def plan_route_registration(
|
|
|
270
270
|
owner_fields = ("ownerRepo", "environment", "appSlug")
|
|
271
271
|
if any(existing[field] != spec[field] for field in owner_fields):
|
|
272
272
|
raise DeploymentKitError(
|
|
273
|
-
f"Route ID {spec['routeId']} is already owned by another
|
|
273
|
+
f"Route ID {spec['routeId']} is already owned by another Project/environment; refusing takeover."
|
|
274
274
|
)
|
|
275
275
|
requested = set(spec["hostnames"])
|
|
276
276
|
for route in inventory["managedRoutes"]:
|
|
@@ -312,7 +312,7 @@ def plan_route_removal(
|
|
|
312
312
|
if existing is None:
|
|
313
313
|
raise DeploymentKitError(f"Managed route does not exist: {route_id}")
|
|
314
314
|
if existing["ownerRepo"] != owner_repo or existing["environment"] != environment or existing["appSlug"] != app_slug:
|
|
315
|
-
raise DeploymentKitError("Route removal ownership does not match the registered
|
|
315
|
+
raise DeploymentKitError("Route removal ownership does not match the registered Project/environment.")
|
|
316
316
|
return {
|
|
317
317
|
"targetName": name,
|
|
318
318
|
"action": "remove",
|
|
@@ -15,7 +15,7 @@ from .route_registry import apply_route_change, plan_route_removal, route_invent
|
|
|
15
15
|
from .ssh import ssh_args, verify_access
|
|
16
16
|
from .teardown_remote import REMOTE_SCRIPT
|
|
17
17
|
|
|
18
|
-
TEAR_DOWN_WRITE_PHRASE = "[
|
|
18
|
+
TEAR_DOWN_WRITE_PHRASE = "[PROJECT TEAR DOWN]"
|
|
19
19
|
PRODUCTION_DATA_DELETE_PHRASE = "[PRODUCTION DATA DELETE]"
|
|
20
20
|
RESERVED_SCOPES = ("local", "all")
|
|
21
21
|
|
|
@@ -167,13 +167,13 @@ def _tear_down_remote_environment(
|
|
|
167
167
|
stderr = completed.stderr.decode("utf-8", errors="replace").strip()
|
|
168
168
|
if completed.returncode != 0:
|
|
169
169
|
raise DeploymentKitError(
|
|
170
|
-
"Remote
|
|
170
|
+
"Remote Project tear-down failed: " + (stderr or stdout or f"exit {completed.returncode}")
|
|
171
171
|
)
|
|
172
172
|
parts = stdout.split("\t")
|
|
173
173
|
if len(parts) not in {4, 5} or parts[0] != "TEAR_DOWN" or parts[1] not in {"absent", "removed"}:
|
|
174
|
-
raise DeploymentKitError("Remote
|
|
174
|
+
raise DeploymentKitError("Remote Project tear-down returned malformed evidence.")
|
|
175
175
|
if parts[2] != app_slug or parts[3] != environment:
|
|
176
|
-
raise DeploymentKitError("Remote
|
|
176
|
+
raise DeploymentKitError("Remote Project tear-down returned mismatched app/environment evidence.")
|
|
177
177
|
result: dict[str, Any] = {"state": parts[1], "mutated": parts[1] == "removed"}
|
|
178
178
|
if len(parts) == 5:
|
|
179
179
|
result["containerName"] = parts[4]
|
|
@@ -219,7 +219,7 @@ def tear_down_workstation_package(package: str) -> dict[str, Any]:
|
|
|
219
219
|
removed = _run_local([docker, "rm", "-f", "-v", *containers])
|
|
220
220
|
if removed.returncode != 0:
|
|
221
221
|
raise DeploymentKitError(
|
|
222
|
-
"Local
|
|
222
|
+
"Local Project container removal failed: " + (removed.stderr or removed.stdout).strip()
|
|
223
223
|
)
|
|
224
224
|
|
|
225
225
|
images_result = _run_local([docker, "images", "--format", "{{.Repository}}:{{.Tag}}"])
|
|
@@ -238,7 +238,7 @@ def tear_down_workstation_package(package: str) -> dict[str, Any]:
|
|
|
238
238
|
removed = _run_local([docker, "image", "rm", "-f", *image_refs])
|
|
239
239
|
if removed.returncode != 0:
|
|
240
240
|
raise DeploymentKitError(
|
|
241
|
-
"Local
|
|
241
|
+
"Local Project image removal failed: " + (removed.stderr or removed.stdout).strip()
|
|
242
242
|
)
|
|
243
243
|
return {
|
|
244
244
|
"state": "removed" if containers or image_refs else "absent",
|
|
@@ -248,7 +248,7 @@ def tear_down_workstation_package(package: str) -> dict[str, Any]:
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
|
|
251
|
-
def
|
|
251
|
+
def tear_down_project(spec: dict[str, Any]) -> dict[str, Any]:
|
|
252
252
|
normalized = normalize_teardown_spec(
|
|
253
253
|
owner_repo=spec.get("ownerRepo"),
|
|
254
254
|
app_slug=spec.get("appSlug"),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""CLI for scoped destructive
|
|
1
|
+
"""CLI for scoped destructive Project tear-down."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ from .teardown import (
|
|
|
12
12
|
normalize_teardown_spec,
|
|
13
13
|
parse_environment_targets,
|
|
14
14
|
render_teardown_summary,
|
|
15
|
-
|
|
15
|
+
tear_down_project,
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
|
|
@@ -83,7 +83,7 @@ def _preview(spec: dict[str, object]) -> dict[str, object]:
|
|
|
83
83
|
"deletesPersistentData": bool(spec["environmentTargets"]),
|
|
84
84
|
"deletesProductionData": production,
|
|
85
85
|
"preservesSharedPlatform": True,
|
|
86
|
-
"
|
|
86
|
+
"preservesUnrelatedProjects": True,
|
|
87
87
|
"deletesGhcrPackage": False,
|
|
88
88
|
"requiredAuthorization": TEAR_DOWN_WRITE_PHRASE,
|
|
89
89
|
"requiredProductionDataAuthorization": PRODUCTION_DATA_DELETE_PHRASE if production else None,
|
|
@@ -111,7 +111,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
111
111
|
and args.production_data_authorization != PRODUCTION_DATA_DELETE_PHRASE
|
|
112
112
|
)
|
|
113
113
|
if missing_general or missing_production:
|
|
114
|
-
print("
|
|
114
|
+
print("PROJECT TEAR-DOWN PREVIEW")
|
|
115
115
|
print(render_teardown_summary(preview))
|
|
116
116
|
if missing_general:
|
|
117
117
|
print(
|
|
@@ -126,8 +126,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
126
126
|
)
|
|
127
127
|
return 2
|
|
128
128
|
|
|
129
|
-
result =
|
|
130
|
-
print("
|
|
129
|
+
result = tear_down_project(spec)
|
|
130
|
+
print("PROJECT TEAR-DOWN COMPLETE")
|
|
131
131
|
print(render_teardown_summary(result))
|
|
132
132
|
return 0
|
|
133
133
|
except DeploymentKitError as exc:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Remote destructive tear-down for one Kit-managed
|
|
1
|
+
"""Remote destructive tear-down for one Kit-managed Project environment."""
|
|
2
2
|
|
|
3
3
|
REMOTE_SCRIPT = r'''#!/usr/bin/env bash
|
|
4
4
|
set -Eeuo pipefail
|
|
@@ -37,7 +37,7 @@ if [[ ! -e "$ROOT" ]]; then
|
|
|
37
37
|
fi
|
|
38
38
|
|
|
39
39
|
[[ -d "$ROOT" && ! -L "$ROOT" ]] || {
|
|
40
|
-
echo "
|
|
40
|
+
echo "Project environment root is not a safe managed directory: $ROOT" >&2
|
|
41
41
|
exit 21
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -46,16 +46,16 @@ HAS_PERSISTENCE=false
|
|
|
46
46
|
[[ -f "$STATE" && ! -L "$STATE" ]] && HAS_STATE=true
|
|
47
47
|
[[ -f "$PERSISTENCE" && ! -L "$PERSISTENCE" ]] && HAS_PERSISTENCE=true
|
|
48
48
|
[[ "$HAS_STATE" == true || "$HAS_PERSISTENCE" == true ]] || {
|
|
49
|
-
echo "
|
|
49
|
+
echo "Project environment root has no managed ownership marker: $ROOT" >&2
|
|
50
50
|
exit 21
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
if [[ "$HAS_STATE" == true ]] && ! assert_owned_marker "$STATE"; then
|
|
54
|
-
echo "
|
|
54
|
+
echo "Project deployment ownership mismatch for $ROOT" >&2
|
|
55
55
|
exit 22
|
|
56
56
|
fi
|
|
57
57
|
if [[ "$HAS_PERSISTENCE" == true ]] && ! assert_owned_marker "$PERSISTENCE"; then
|
|
58
|
-
echo "
|
|
58
|
+
echo "Project persistence ownership mismatch for $ROOT" >&2
|
|
59
59
|
exit 22
|
|
60
60
|
fi
|
|
61
61
|
|
|
@@ -87,7 +87,7 @@ if [[ "$HAS_STATE" == true ]]; then
|
|
|
87
87
|
fi
|
|
88
88
|
fi
|
|
89
89
|
|
|
90
|
-
# The verified environment root is owned by this
|
|
90
|
+
# The verified environment root is owned by this Project/environment. Tear-down
|
|
91
91
|
# removes releases, evidence, persistent data, and backups together.
|
|
92
92
|
rm -rf --one-file-system -- "$ROOT"
|
|
93
93
|
|