@mriekki/project-forge 0.0.0-stage → 2.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.
Files changed (117) hide show
  1. package/README.md +134 -2
  2. package/assets/components.json +33 -0
  3. package/assets/core/distribution.json +66 -0
  4. package/assets/deployment/distribution.json +54 -0
  5. package/assets/generated/ASSEMBLY.json +557 -0
  6. package/assets/generated/core/core/agents/coach.agent.md +69 -0
  7. package/assets/generated/core/core/agents/reviewer.agent.md +85 -0
  8. package/assets/generated/core/core/instructions/project-forge-docs.instructions.md +45 -0
  9. package/assets/generated/core/core/instructions/project-forge-workflow.instructions.md +79 -0
  10. package/assets/generated/core/core/learning/CODING_DRILLS.md +35 -0
  11. package/assets/generated/core/core/learning/DIAGRAM_GUIDE.md +59 -0
  12. package/assets/generated/core/core/learning/ENGINEERING_LEARNING_WORKBOOK.md +108 -0
  13. package/assets/generated/core/core/learning/LEARNING_MAP.md +108 -0
  14. package/assets/generated/core/core/learning/LEARNING_PROGRESS.md +39 -0
  15. package/assets/generated/core/core/learning/RESOURCE_CATALOG.md +25 -0
  16. package/assets/generated/core/core/learning/SQL_DRILLS.md +90 -0
  17. package/assets/generated/core/core/learning/SYSTEM_DESIGN_DRILLS.md +301 -0
  18. package/assets/generated/core/core/process/COACHING_GUIDE.md +92 -0
  19. package/assets/generated/core/core/process/DATABASE_LEARNING_WORKBENCH.md +397 -0
  20. package/assets/generated/core/core/process/DEPLOYMENT_ENABLEMENT.md +166 -0
  21. package/assets/generated/core/core/process/GUIDED_NEXT_STEPS.md +48 -0
  22. package/assets/generated/core/core/process/HUMAN_GATES.md +83 -0
  23. package/assets/generated/core/core/process/INTERACTIVE_SESSION_GUIDE.md +64 -0
  24. package/assets/generated/core/core/process/PROJECT_DOCUMENTATION_FRAMEWORK.md +326 -0
  25. package/assets/generated/core/core/process/PROJECT_FORGE_ENGINEERING_GUIDE.md +308 -0
  26. package/assets/generated/core/core/process/PR_WORKFLOW.md +55 -0
  27. package/assets/generated/core/core/process/SETUP_ACCEPTANCE_CHECKLIST.md +72 -0
  28. package/assets/generated/core/core/process/SYSTEM_DESIGN_LEARNING_WORKBENCH.md +520 -0
  29. package/assets/generated/core/core/process/WORK_ITEM_MODEL.md +56 -0
  30. package/assets/generated/core/core/skills/cleanup-branches/SKILL.md +190 -0
  31. package/assets/generated/core/core/skills/coach/SKILL.md +174 -0
  32. package/assets/generated/core/core/skills/code-walkthrough/SKILL.md +197 -0
  33. package/assets/generated/core/core/skills/core-sync/SKILL.md +178 -0
  34. package/assets/generated/core/core/skills/db-lab/SKILL.md +245 -0
  35. package/assets/generated/core/core/skills/define-feature/SKILL.md +144 -0
  36. package/assets/generated/core/core/skills/deliver/SKILL.md +397 -0
  37. package/assets/generated/core/core/skills/deploy/SKILL.md +188 -0
  38. package/assets/generated/core/core/skills/deployment-readiness/SKILL.md +234 -0
  39. package/assets/generated/core/core/skills/developer-env-mode/SKILL.md +231 -0
  40. package/assets/generated/core/core/skills/docs/SKILL.md +116 -0
  41. package/assets/generated/core/core/skills/grill-me/SKILL.md +77 -0
  42. package/assets/generated/core/core/skills/grill-with-docs/SKILL.md +90 -0
  43. package/assets/generated/core/core/skills/learning-review/SKILL.md +90 -0
  44. package/assets/generated/core/core/skills/next-step/SKILL.md +221 -0
  45. package/assets/generated/core/core/skills/progress/SKILL.md +207 -0
  46. package/assets/generated/core/core/skills/project-forge-update/SKILL.md +228 -0
  47. package/assets/generated/core/core/skills/pull-latest/SKILL.md +166 -0
  48. package/assets/generated/core/core/skills/refine-requirements/SKILL.md +207 -0
  49. package/assets/generated/core/core/skills/setup/SKILL.md +362 -0
  50. package/assets/generated/core/core/skills/start-work/SKILL.md +190 -0
  51. package/assets/generated/core/core/skills/system-lab/SKILL.md +333 -0
  52. package/assets/generated/core/core/skills/tear-down/SKILL.md +140 -0
  53. package/assets/generated/core/core/skills/upstream-fix/SKILL.md +221 -0
  54. package/assets/generated/core/core/skills/wait-what/SKILL.md +86 -0
  55. package/assets/generated/core/core/templates/ADR_TEMPLATE.md +41 -0
  56. package/assets/generated/core/core/templates/FEATURE_BRIEF_TEMPLATE.md +27 -0
  57. package/assets/generated/core/core/templates/PRODUCT_BRIEF_TEMPLATE.md +27 -0
  58. package/assets/generated/core/core/templates/PULL_REQUEST_TEMPLATE.md +37 -0
  59. package/assets/generated/core/core/templates/REQUIREMENTS_TEMPLATE.md +17 -0
  60. package/assets/generated/core/profiles/greenfield/project-forge-workspace.json +12 -0
  61. package/assets/generated/core/tools/db_lab/sqlite_workbench.py +463 -0
  62. package/assets/generated/core/tools/docs_site/docs_site.py +512 -0
  63. package/assets/generated/core/tools/package/check_baseline.py +102 -0
  64. package/assets/generated/core/tools/package/check_upstream.py +171 -0
  65. package/assets/generated/core/tools/system_lab/system_workbench.py +243 -0
  66. package/assets/generated/deployment/distribution/project-forge-deploy.py +8 -0
  67. package/assets/generated/deployment/docs/DEVELOPER_ENVIRONMENTS.md +335 -0
  68. package/assets/generated/deployment/docs/ENVIRONMENT_PROOF.md +95 -0
  69. package/assets/generated/deployment/docs/WORKSPACE_INSTANCES.md +154 -0
  70. package/assets/generated/deployment/docs/images/developer-environment-journey.svg +56 -0
  71. package/assets/generated/deployment/docs/images/personal-environment-architecture.svg +54 -0
  72. package/assets/generated/deployment/docs/images/poc-environment-model.svg +61 -0
  73. package/assets/generated/deployment/src/project_forge_deployment/__init__.py +3 -0
  74. package/assets/generated/deployment/src/project_forge_deployment/__main__.py +3 -0
  75. package/assets/generated/deployment/src/project_forge_deployment/app_cli.py +163 -0
  76. package/assets/generated/deployment/src/project_forge_deployment/app_runtime.py +455 -0
  77. package/assets/generated/deployment/src/project_forge_deployment/app_runtime_remote.py +416 -0
  78. package/assets/generated/deployment/src/project_forge_deployment/app_runtime_workstation.py +136 -0
  79. package/assets/generated/deployment/src/project_forge_deployment/box_platform.py +208 -0
  80. package/assets/generated/deployment/src/project_forge_deployment/box_platform_assets.py +100 -0
  81. package/assets/generated/deployment/src/project_forge_deployment/box_platform_remote.py +271 -0
  82. package/assets/generated/deployment/src/project_forge_deployment/cli.py +437 -0
  83. package/assets/generated/deployment/src/project_forge_deployment/doctor.py +121 -0
  84. package/assets/generated/deployment/src/project_forge_deployment/entrypoint.py +37 -0
  85. package/assets/generated/deployment/src/project_forge_deployment/environment_cli.py +271 -0
  86. package/assets/generated/deployment/src/project_forge_deployment/environment_probe.py +228 -0
  87. package/assets/generated/deployment/src/project_forge_deployment/errors.py +5 -0
  88. package/assets/generated/deployment/src/project_forge_deployment/home_lab.py +328 -0
  89. package/assets/generated/deployment/src/project_forge_deployment/image_transfer.py +105 -0
  90. package/assets/generated/deployment/src/project_forge_deployment/keys.py +171 -0
  91. package/assets/generated/deployment/src/project_forge_deployment/local_cli.py +189 -0
  92. package/assets/generated/deployment/src/project_forge_deployment/local_runtime.py +526 -0
  93. package/assets/generated/deployment/src/project_forge_deployment/local_spec.py +82 -0
  94. package/assets/generated/deployment/src/project_forge_deployment/local_sqlite.py +205 -0
  95. package/assets/generated/deployment/src/project_forge_deployment/portable_profile.py +181 -0
  96. package/assets/generated/deployment/src/project_forge_deployment/profile_migration.py +70 -0
  97. package/assets/generated/deployment/src/project_forge_deployment/profile_repository.py +348 -0
  98. package/assets/generated/deployment/src/project_forge_deployment/profiles.py +204 -0
  99. package/assets/generated/deployment/src/project_forge_deployment/registry_access.py +114 -0
  100. package/assets/generated/deployment/src/project_forge_deployment/registry_cli.py +51 -0
  101. package/assets/generated/deployment/src/project_forge_deployment/route_registry.py +367 -0
  102. package/assets/generated/deployment/src/project_forge_deployment/route_registry_remote.py +443 -0
  103. package/assets/generated/deployment/src/project_forge_deployment/security.py +290 -0
  104. package/assets/generated/deployment/src/project_forge_deployment/sqlite_adapter.py +335 -0
  105. package/assets/generated/deployment/src/project_forge_deployment/sqlite_adapter_remote.py +340 -0
  106. package/assets/generated/deployment/src/project_forge_deployment/sqlite_cli.py +86 -0
  107. package/assets/generated/deployment/src/project_forge_deployment/sqlite_import_recovery.py +437 -0
  108. package/assets/generated/deployment/src/project_forge_deployment/ssh.py +119 -0
  109. package/assets/generated/deployment/src/project_forge_deployment/teardown.py +300 -0
  110. package/assets/generated/deployment/src/project_forge_deployment/teardown_cli.py +139 -0
  111. package/assets/generated/deployment/src/project_forge_deployment/teardown_remote.py +100 -0
  112. package/assets/generated/deployment/src/project_forge_deployment/trust.py +278 -0
  113. package/bin/project-forge.mjs +9 -0
  114. package/package.json +31 -4
  115. package/src/cli.mjs +150 -0
  116. package/src/engine.mjs +243 -0
  117. package/src/package-data.mjs +18 -0
@@ -0,0 +1,189 @@
1
+ """CLI for loopback-only workstation application deployment."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+ from typing import Any
9
+
10
+ from .errors import DeploymentKitError
11
+ from .local_runtime import (
12
+ PRODUCTION_APP_DEPLOY_WRITE_PHRASE,
13
+ apply_local_deploy,
14
+ local_deploy_write_phrase,
15
+ local_inventory,
16
+ plan_local_deploy,
17
+ )
18
+ from .local_spec import normalize_workstation_spec
19
+ from .local_sqlite import ensure_local_sqlite, local_sqlite_status
20
+
21
+
22
+ LOCAL_SQLITE_ENSURE_WRITE_PHRASE = "[LOCAL SQLITE ENSURE]"
23
+
24
+
25
+ def _print(value: Any, *, as_json: bool) -> None:
26
+ if as_json:
27
+ print(json.dumps(value, indent=2, sort_keys=True))
28
+ elif isinstance(value, dict):
29
+ for key, item in value.items():
30
+ print(f"{key}: {json.dumps(item, sort_keys=True) if isinstance(item, (dict, list)) else item}")
31
+ else:
32
+ print(value)
33
+
34
+
35
+ def _parse_env(items: list[str]) -> list[tuple[str, str]]:
36
+ result: list[tuple[str, str]] = []
37
+ for item in items:
38
+ if "=" not in item:
39
+ raise DeploymentKitError("--env entries must use NAME=value form.")
40
+ key, value = item.split("=", 1)
41
+ result.append((key, value))
42
+ return result
43
+
44
+
45
+ def _confirm(args: argparse.Namespace, phrase: str, action: str) -> None:
46
+ if args.yes:
47
+ return
48
+ entered = input(f"Type {phrase} to {action}: ").strip()
49
+ if entered != phrase:
50
+ raise DeploymentKitError(f"{action.capitalize()} was not authorized.")
51
+
52
+
53
+ def _add_sqlite_identity(parser: argparse.ArgumentParser) -> None:
54
+ parser.add_argument("--owner-repo", required=True)
55
+ parser.add_argument("--environment", required=True)
56
+ parser.add_argument("--app-slug", required=True)
57
+ parser.add_argument("--database-file", required=True)
58
+ parser.add_argument("--json", action="store_true")
59
+
60
+
61
+ def build_parser() -> argparse.ArgumentParser:
62
+ parser = argparse.ArgumentParser(prog="project-forge-deploy local")
63
+ sub = parser.add_subparsers(dest="command", required=True)
64
+
65
+ inventory = sub.add_parser(
66
+ "inventory",
67
+ help="Read Project Forge-owned workstation application runtime evidence without writes",
68
+ )
69
+ inventory.add_argument("--json", action="store_true")
70
+
71
+ sqlite_status = sub.add_parser(
72
+ "sqlite-status",
73
+ help="Inspect one Project Forge-owned workstation SQLite database without writes",
74
+ )
75
+ _add_sqlite_identity(sqlite_status)
76
+
77
+ sqlite_ensure = sub.add_parser(
78
+ "sqlite-ensure",
79
+ help="Create a missing Project Forge-owned workstation SQLite database non-destructively",
80
+ )
81
+ _add_sqlite_identity(sqlite_ensure)
82
+ sqlite_ensure.add_argument("--yes", action="store_true")
83
+
84
+ deploy = sub.add_parser(
85
+ "deploy",
86
+ help="Deploy one immutable application container bound only to loopback",
87
+ )
88
+ deploy.add_argument("--owner-repo", required=True)
89
+ deploy.add_argument("--environment", required=True)
90
+ deploy.add_argument(
91
+ "--production",
92
+ action="store_true",
93
+ help="Classify this named environment as Production even when its name is not literally 'production'",
94
+ )
95
+ deploy.add_argument("--app-slug", required=True)
96
+ deploy.add_argument("--container-name", required=True)
97
+ deploy.add_argument("--image", required=True)
98
+ deploy.add_argument("--runtime-port", type=int, required=True)
99
+ deploy.add_argument("--host-port", type=int, required=True)
100
+ deploy.add_argument("--health-path", required=True)
101
+ deploy.add_argument("--run-as", required=True)
102
+ deploy.add_argument("--persistence-mode", choices=("none", "directory"), required=True)
103
+ deploy.add_argument("--data-container-path")
104
+ deploy.add_argument("--env", action="append", default=[])
105
+ deploy.add_argument("--json", action="store_true")
106
+ deploy.add_argument("--yes", action="store_true")
107
+ return parser
108
+
109
+
110
+ def main(argv: list[str] | None = None) -> int:
111
+ args = build_parser().parse_args(argv)
112
+ try:
113
+ if args.command == "inventory":
114
+ _print(local_inventory(), as_json=args.json)
115
+ return 0
116
+
117
+ if args.command == "sqlite-status":
118
+ _print(
119
+ local_sqlite_status(
120
+ owner_repo=args.owner_repo,
121
+ environment=args.environment,
122
+ app_slug=args.app_slug,
123
+ database_file=args.database_file,
124
+ ),
125
+ as_json=args.json,
126
+ )
127
+ return 0
128
+
129
+ if args.command == "sqlite-ensure":
130
+ status = local_sqlite_status(
131
+ owner_repo=args.owner_repo,
132
+ environment=args.environment,
133
+ app_slug=args.app_slug,
134
+ database_file=args.database_file,
135
+ )
136
+ if status["state"] == "ready":
137
+ _print(status, as_json=args.json)
138
+ return 0
139
+ if status["state"] == "unmanaged-existing":
140
+ raise DeploymentKitError(
141
+ "Refusing automatic adoption of an existing unmanaged local SQLite database."
142
+ )
143
+ _print(status, as_json=False)
144
+ _confirm(
145
+ args,
146
+ LOCAL_SQLITE_ENSURE_WRITE_PHRASE,
147
+ f"create local SQLite storage for {args.app_slug} ({args.environment})",
148
+ )
149
+ _print(
150
+ ensure_local_sqlite(
151
+ owner_repo=args.owner_repo,
152
+ environment=args.environment,
153
+ app_slug=args.app_slug,
154
+ database_file=args.database_file,
155
+ ),
156
+ as_json=args.json,
157
+ )
158
+ return 0
159
+
160
+ spec = normalize_workstation_spec(
161
+ owner_repo=args.owner_repo,
162
+ environment=args.environment,
163
+ app_slug=args.app_slug,
164
+ container_name=args.container_name,
165
+ image=args.image,
166
+ runtime_port=args.runtime_port,
167
+ host_port=args.host_port,
168
+ health_path=args.health_path,
169
+ run_as=args.run_as,
170
+ persistence_mode=args.persistence_mode,
171
+ data_container_path=args.data_container_path,
172
+ environment_variables=_parse_env(args.env),
173
+ )
174
+ plan = plan_local_deploy(spec)
175
+ production_classified = args.production or plan["environment"] == "production"
176
+ plan_view = {key: value for key, value in plan.items() if key != "spec"}
177
+ plan_view["productionClassified"] = production_classified
178
+ _print(plan_view, as_json=False)
179
+ phrase = PRODUCTION_APP_DEPLOY_WRITE_PHRASE if production_classified else local_deploy_write_phrase(plan)
180
+ _confirm(
181
+ args,
182
+ phrase,
183
+ f"deploy {plan['appSlug']} ({plan['environment']}) on this workstation",
184
+ )
185
+ _print(apply_local_deploy(plan), as_json=args.json)
186
+ return 0
187
+ except DeploymentKitError as error:
188
+ print(f"ERROR: {error}", file=sys.stderr)
189
+ return 2