development-engine-vector 0.3.1__tar.gz → 0.5.1__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.
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/PKG-INFO +26 -16
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/changelog.md +66 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/contributing.md +6 -2
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/__init__.py +1 -1
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/cli/cli.py +201 -45
- development_engine_vector-0.5.1/dev/kernel/kernel_core.py +388 -0
- development_engine_vector-0.5.1/dev/kernel/otk_kernel.py +274 -0
- development_engine_vector-0.5.1/dev/kernel/pmf_kernel.py +24 -0
- development_engine_vector-0.5.1/dev/ui/actions.py +111 -0
- development_engine_vector-0.5.1/dev/ui/routes.py +298 -0
- development_engine_vector-0.5.1/dev/ui/static/web.js +940 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/templates.py +138 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/workflow/release.py +2 -2
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/workflow/versioning.py +7 -3
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/docs/architecture.md +9 -3
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/pyproject.toml +1 -1
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/readme.md +25 -15
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/tests/test_dev_cli.py +4 -6
- development_engine_vector-0.5.1/version +1 -0
- development_engine_vector-0.3.1/dev/kernel/pmf_kernel.py +0 -432
- development_engine_vector-0.3.1/dev/ui/actions.py +0 -47
- development_engine_vector-0.3.1/dev/ui/routes.py +0 -114
- development_engine_vector-0.3.1/dev/ui/static/web.js +0 -528
- development_engine_vector-0.3.1/version +0 -1
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/.flake8 +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/.gitignore +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/__main__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/cli/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/kernel/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/kernel/config.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/kernel/db.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/kernel/paths.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/kernel/selfcheck.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/base.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/checks.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/events.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/health.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/identity.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/manifest.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/overview.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/db/runs.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/static/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/static/web.css +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/ui/web.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/utils.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/vcs/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/vcs/git.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/vcs/github.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/workflow/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/workflow/cda.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/workflow/changelog.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev/workflow/preflight.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/dev-cli.toml.example +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/license +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/tests/__init__.py +0 -0
- {development_engine_vector-0.3.1 → development_engine_vector-0.5.1}/tests/test_cda_preflight.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: development-engine-vector
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Development Engine Vector — internal developer workflow CLI.
|
|
5
5
|
Author-email: Ernie Butcher <ernie@fiosii.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -187,35 +187,45 @@ dev ui status # show pid, started time, log path
|
|
|
187
187
|
dev ui restart # restart
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
### `dev
|
|
190
|
+
### `dev otk`
|
|
191
191
|
|
|
192
|
-
Manage the
|
|
192
|
+
Manage the **Ops Tool Kernel (OTK)** and background services/tasks.
|
|
193
193
|
|
|
194
194
|
```bash
|
|
195
|
-
dev
|
|
196
|
-
dev
|
|
197
|
-
dev
|
|
198
|
-
dev
|
|
199
|
-
dev
|
|
200
|
-
dev
|
|
201
|
-
dev
|
|
202
|
-
dev
|
|
203
|
-
dev
|
|
195
|
+
dev otk services # list services/tasks and status
|
|
196
|
+
dev otk status [service_id] # detailed status for one or all
|
|
197
|
+
dev otk start ui # start daemon service
|
|
198
|
+
dev otk start preflight --project <path> # run preflight task service
|
|
199
|
+
dev otk start vet # run control vet task service
|
|
200
|
+
dev otk start build --project <path> # run build task service
|
|
201
|
+
dev otk start publish-check # run dry-run publish validation
|
|
202
|
+
dev otk start release-dryrun --project <path> # run full dry-run release workflow
|
|
203
|
+
dev otk stop ui # stop daemon service
|
|
204
|
+
dev otk restart ui # restart daemon service
|
|
205
|
+
dev otk logs vet --tail 100 # tail service/task logs
|
|
206
|
+
dev otk events --tail 20 # inspect kernel event journal
|
|
207
|
+
dev otk up # start default runtime services
|
|
208
|
+
dev otk install # register macOS LaunchAgent (auto-start)
|
|
209
|
+
dev otk uninstall # remove LaunchAgent
|
|
204
210
|
```
|
|
205
211
|
|
|
212
|
+
`dev pmf ...` remains available as a legacy alias for backward compatibility.
|
|
213
|
+
|
|
206
214
|
### `dev setup`
|
|
207
215
|
|
|
208
216
|
Full onboarding wizard — run once after install.
|
|
209
217
|
|
|
210
218
|
```bash
|
|
211
|
-
dev setup # init dirs +
|
|
219
|
+
dev setup # init dirs + otk install + ui start + open browser
|
|
212
220
|
dev setup --no-browser # same, skip browser
|
|
221
|
+
dev setup --run-otk-chain # also run the OTK preflight → vet chain
|
|
213
222
|
```
|
|
214
223
|
|
|
215
224
|
Steps:
|
|
216
225
|
1. **Init** — create `~/Library/goCosmix/tools/dev/` and all runtime subdirs; patch `~/.zprofile` if `dev` is not on PATH
|
|
217
|
-
2. **
|
|
218
|
-
3. **Up** — start the web UI via
|
|
226
|
+
2. **OTK install** — register `com.gocosmix.dev` LaunchAgent so `dev` starts automatically on every login
|
|
227
|
+
3. **Up** — start the web UI via OTK kernel, open browser at `http://127.0.0.1:9001`
|
|
228
|
+
4. **Phase 2** — optionally run `preflight → vet` against the dev source tree for a fresh post-setup validation pass
|
|
219
229
|
|
|
220
230
|
## ⚙️ Configuration
|
|
221
231
|
|
|
@@ -251,7 +261,7 @@ dev --config ./custom.dev-cli.toml release --project /Volumes/intel/systems/cda/
|
|
|
251
261
|
|
|
252
262
|
```
|
|
253
263
|
dev/
|
|
254
|
-
├── kernel/ — runtime foundation (
|
|
264
|
+
├── kernel/ — runtime foundation (OTK kernel, shared core, paths, DB, config, self-check)
|
|
255
265
|
├── workflow/ — business logic (versioning, changelog, preflight, release)
|
|
256
266
|
├── vcs/ — version control ops (git, GitHub API)
|
|
257
267
|
├── ui/ — embedded WSGI dashboard (port 9001, indigo theme)
|
|
@@ -5,6 +5,72 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.1] - 2026-05-12
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- UI service status stuck on `"starting"` — `_refresh()` now advances to `"running"` and persists state when the process is confirmed alive
|
|
12
|
+
- `VersionManager.get_sync_targets()` removed stale `vscode_ark/__init__.py` and `setup.py` targets; now resolves `dev/__init__.py` from the project tree
|
|
13
|
+
- `ReleaseOrchestrator.commit_and_tag()` staged `vscode_ark/__init__.py` and `setup.py` (copy-paste from cda); corrected to `dev/__init__.py`
|
|
14
|
+
- `get_recent_runs` unused import in `routes.py` removed (lint failure)
|
|
15
|
+
- Release page showed always-empty kernel run history; now shows real action states (pass/fail, exit code, timestamps)
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `/api/kernel/logs?service=X&lines=N` endpoint — tails any service log file from the UI
|
|
19
|
+
- OTK page **Logs** button per service opens a modal with the last 100 log lines
|
|
20
|
+
- Action buttons now poll to completion and display a result toast with exit code and captured output
|
|
21
|
+
- Raw Query page has a database selector: `control.db` (vet history) or `dev.db` (kernel/projects)
|
|
22
|
+
- `sync` OTK task service added — bootstrap/editable-install from the OTK page
|
|
23
|
+
- Setup page shows `dev otk install` guidance when the LaunchAgent is not installed
|
|
24
|
+
- Git page shows "Clean — no commits since vX.Y.Z" on a clean repo instead of a blank panel
|
|
25
|
+
- `vet.py` writes `vet.start` / `vet.pass` / `vet.fail` events to the `events` table and refreshes `identity.version` on every passing run
|
|
26
|
+
|
|
27
|
+
## [0.5.0] - 2026-05-11
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **Full UI expansion** — 7 new dashboard pages surfacing the entire `dev` command surface:
|
|
31
|
+
- **OTK** — live service/task table with Start / Stop / Restart controls per service
|
|
32
|
+
- **Selfcheck** — editable install path, DB state, tool availability, dependency status
|
|
33
|
+
- **Version** — version file vs package version, sync target map
|
|
34
|
+
- **Release** — release run history, registered project registry, one-click workflow buttons (Preflight, Vet, Build, Publish Check, Release Dry-Run)
|
|
35
|
+
- **Project** — project dir, config file, package/changelog sync state
|
|
36
|
+
- **Git** — branch, last tag, dirty state, remote URL, commits since tag
|
|
37
|
+
- **Setup** — DEV_HOME, launch agent install status, all runtime path table
|
|
38
|
+
- New backend summary APIs: `/api/dev/selfcheck`, `/api/dev/version`, `/api/dev/changelog`, `/api/dev/git`, `/api/dev/project`, `/api/dev/release`, `/api/dev/setup`
|
|
39
|
+
- Background action runner now distinguishes task vs daemon services: tasks run synchronously to completion and capture full output before updating action state
|
|
40
|
+
- Navigation expanded with new groups: OTK under Core; Selfcheck/Version/Release under Config; Project/Git under Inventory; Setup under System
|
|
41
|
+
|
|
42
|
+
## [0.4.1] - 2026-05-11
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- Optional Phase 2 onboarding flow: `dev setup --run-otk-chain` runs the OTK preflight → vet task chain after startup
|
|
46
|
+
- Dashboard now renders the OTK kernel brain directly on the default page:
|
|
47
|
+
- runtime service table
|
|
48
|
+
- recent kernel event feed
|
|
49
|
+
- Added synchronous task execution support in the shared kernel core for onboarding and orchestration
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
- Dashboard overview now includes kernel-state visibility in addition to vet stats
|
|
53
|
+
- OTK task events are recorded in the runtime journal and surfaced through the UI
|
|
54
|
+
|
|
55
|
+
## [0.4.0] - 2026-05-11
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- **Ops Tool Kernel (OTK)** architecture for `dev`:
|
|
59
|
+
- `kernel_core.py` shared kernel base (service lifecycle, persistent runtime state, event journal)
|
|
60
|
+
- `otk_kernel.py` system-adapted kernel (daemon + task service catalog)
|
|
61
|
+
- `pmf_kernel.py` compatibility shim preserving PMF imports
|
|
62
|
+
- New OTK task services: `preflight`, `vet`, `build`, `publish-check`, `release-dryrun`
|
|
63
|
+
- New runtime events command: `dev otk events` (also available through legacy `dev pmf events`)
|
|
64
|
+
- New web API endpoints for kernel state and actions:
|
|
65
|
+
- `GET /api/kernel/services`, `GET /api/kernel/status`, `GET /api/kernel/events`
|
|
66
|
+
- `POST /api/kernel/start`, `POST /api/kernel/stop`, `POST /api/kernel/restart`
|
|
67
|
+
- `GET /api/actions`, `GET /api/action/status`
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
- LaunchAgent now calls `dev otk up` (legacy `dev pmf ...` remains as an alias)
|
|
71
|
+
- `dev setup` language updated from PMF-first to OTK-first flow
|
|
72
|
+
- Control data seed metadata updated for PyPI package name: `development-engine-vector`
|
|
73
|
+
|
|
8
74
|
## [0.3.1] - 2026-05-11
|
|
9
75
|
|
|
10
76
|
### Changed
|
|
@@ -87,7 +87,9 @@ dev/
|
|
|
87
87
|
│ ├── dev/ # Python package
|
|
88
88
|
│ │ ├── kernel/ # runtime foundation
|
|
89
89
|
│ │ │ ├── paths.py # DEV_HOME = ~/Library/goCosmix/tools/dev
|
|
90
|
-
│ │ │ ├──
|
|
90
|
+
│ │ │ ├── kernel_core.py # shared kernel DNA (service lifecycle + events)
|
|
91
|
+
│ │ │ ├── otk_kernel.py # Ops Tool Kernel (dev-specific services/tasks)
|
|
92
|
+
│ │ │ ├── pmf_kernel.py # compatibility shim over OTK symbols
|
|
91
93
|
│ │ │ ├── db.py # WAL SQLite — runs + projects
|
|
92
94
|
│ │ │ ├── config.py # DevConfig — reads .dev-cli.toml
|
|
93
95
|
│ │ │ └── selfcheck.py # engine self-diagnostics
|
|
@@ -128,7 +130,9 @@ Thin click wrappers. All logic delegates to `workflow/` and `vcs/` modules.
|
|
|
128
130
|
|
|
129
131
|
### Kernel (`dev/kernel/`)
|
|
130
132
|
- `paths.py` — canonical path constants; `DEV_HOME = ~/Library/goCosmix/tools/dev`
|
|
131
|
-
- `
|
|
133
|
+
- `kernel_core.py` — shared kernel base (`ServiceSpec`, lifecycle, state persistence, event journal)
|
|
134
|
+
- `otk_kernel.py` — `OTKKernel`: Ops Tool Kernel service/task catalog (`ui`, `preflight`, `vet`, `build`, `publish-check`, `release-dryrun`) and launchd integration
|
|
135
|
+
- `pmf_kernel.py` — backward-compatible alias layer for existing PMF imports
|
|
132
136
|
- `db.py` — WAL SQLite; `record_run`, `finish_run`, `upsert_project`, `get_recent_runs`
|
|
133
137
|
- `config.py` — loads `.dev-cli.toml` / `dev-cli.toml` from project root
|
|
134
138
|
- `selfcheck.py` — five checks: version, install path, DB, tools, dependencies
|
|
@@ -10,8 +10,8 @@ import click
|
|
|
10
10
|
|
|
11
11
|
from dev.kernel.config import DevConfig
|
|
12
12
|
from dev.kernel.paths import ensure_dirs
|
|
13
|
-
from dev.kernel.
|
|
14
|
-
|
|
13
|
+
from dev.kernel.otk_kernel import (
|
|
14
|
+
OTKKernel, OTKKernelError,
|
|
15
15
|
install_launchd, uninstall_launchd, plist_path,
|
|
16
16
|
wait_for_port_and_open_browser,
|
|
17
17
|
)
|
|
@@ -272,7 +272,7 @@ def selfcheck():
|
|
|
272
272
|
print(f" {result['passed']} passed, {result['failed']} failed")
|
|
273
273
|
|
|
274
274
|
|
|
275
|
-
_kernel =
|
|
275
|
+
_kernel = OTKKernel()
|
|
276
276
|
|
|
277
277
|
|
|
278
278
|
# ── helper ────────────────────────────────────────────────────────────────────
|
|
@@ -300,7 +300,7 @@ def _hr():
|
|
|
300
300
|
|
|
301
301
|
def _pmf_warn_if_not_installed():
|
|
302
302
|
if not plist_path().exists():
|
|
303
|
-
click.echo(_yellow(" ⚠ LaunchAgent not installed — run `dev pmf install` to auto-start on login."))
|
|
303
|
+
click.echo(_yellow(" ⚠ LaunchAgent not installed — run `dev otk install` (or `dev pmf install`) to auto-start on login."))
|
|
304
304
|
|
|
305
305
|
|
|
306
306
|
# ── ui group ─────────────────────────────────────────────────────────────────
|
|
@@ -317,7 +317,7 @@ def ui():
|
|
|
317
317
|
@click.option("--no-browser", "no_browser", is_flag=True, default=False,
|
|
318
318
|
help="Don't open browser automatically")
|
|
319
319
|
def ui_start(host, port, no_browser):
|
|
320
|
-
"""Start the web UI via
|
|
320
|
+
"""Start the web UI via OTK."""
|
|
321
321
|
_pmf_warn_if_not_installed()
|
|
322
322
|
try:
|
|
323
323
|
result = _kernel.start_service("ui", options={"host": host, "port": port})
|
|
@@ -326,7 +326,7 @@ def ui_start(host, port, no_browser):
|
|
|
326
326
|
url = f"http://{host}:{port}"
|
|
327
327
|
click.echo(_dim(" Opening browser when server is ready..."))
|
|
328
328
|
wait_for_port_and_open_browser(url, host, port)
|
|
329
|
-
except
|
|
329
|
+
except OTKKernelError as exc:
|
|
330
330
|
click.echo(_red(f" {exc}"))
|
|
331
331
|
|
|
332
332
|
|
|
@@ -336,7 +336,7 @@ def ui_stop():
|
|
|
336
336
|
try:
|
|
337
337
|
result = _kernel.stop_service("ui")
|
|
338
338
|
click.echo(green(f" Stopped {result['label']}"))
|
|
339
|
-
except
|
|
339
|
+
except OTKKernelError as exc:
|
|
340
340
|
click.echo(_red(f" {exc}"))
|
|
341
341
|
|
|
342
342
|
|
|
@@ -367,7 +367,7 @@ def ui_restart(host, port, no_browser):
|
|
|
367
367
|
url = f"http://{host}:{port}"
|
|
368
368
|
click.echo(_dim(" Opening browser when server is ready..."))
|
|
369
369
|
wait_for_port_and_open_browser(url, host, port)
|
|
370
|
-
except
|
|
370
|
+
except OTKKernelError as exc:
|
|
371
371
|
click.echo(_red(f" {exc}"))
|
|
372
372
|
|
|
373
373
|
|
|
@@ -375,16 +375,16 @@ def ui_restart(host, port, no_browser):
|
|
|
375
375
|
|
|
376
376
|
@cli.group()
|
|
377
377
|
def pmf():
|
|
378
|
-
"""
|
|
378
|
+
"""Legacy alias for OTK commands (kept for backward compatibility)."""
|
|
379
379
|
pass
|
|
380
380
|
|
|
381
381
|
|
|
382
382
|
@pmf.command("services")
|
|
383
383
|
def pmf_services():
|
|
384
|
-
"""List
|
|
384
|
+
"""List OTK services and runtime status."""
|
|
385
385
|
rows = _kernel.services()
|
|
386
386
|
click.echo()
|
|
387
|
-
click.echo(_bold("
|
|
387
|
+
click.echo(_bold(" OTK Runtime Services"))
|
|
388
388
|
click.echo(_hr())
|
|
389
389
|
for svc in rows:
|
|
390
390
|
status_str = green(svc["status"]) if svc["status"] == "running" else _yellow(svc["status"])
|
|
@@ -396,7 +396,7 @@ def pmf_services():
|
|
|
396
396
|
@pmf.command("status")
|
|
397
397
|
@click.argument("service_id", required=False)
|
|
398
398
|
def pmf_status(service_id):
|
|
399
|
-
"""Show
|
|
399
|
+
"""Show OTK runtime status for one or all services."""
|
|
400
400
|
if service_id:
|
|
401
401
|
try:
|
|
402
402
|
svc = _kernel.service_status(service_id)
|
|
@@ -407,7 +407,7 @@ def pmf_status(service_id):
|
|
|
407
407
|
click.echo(f" Started: {svc['started_at'] or '—'}")
|
|
408
408
|
click.echo(f" Log: {svc['log_file'] or '—'}")
|
|
409
409
|
click.echo()
|
|
410
|
-
except
|
|
410
|
+
except OTKKernelError as exc:
|
|
411
411
|
click.echo(_red(f" {exc}"))
|
|
412
412
|
else:
|
|
413
413
|
ctx = click.get_current_context()
|
|
@@ -418,10 +418,15 @@ def pmf_status(service_id):
|
|
|
418
418
|
@click.argument("service_id")
|
|
419
419
|
@click.option("--host", default="127.0.0.1", help="Host override for UI service")
|
|
420
420
|
@click.option("--port", default=9001, help="Port override for UI service")
|
|
421
|
+
@click.option("--project", default=".", help="Project path override for task services")
|
|
421
422
|
@click.option("--no-browser", "no_browser", is_flag=True, default=False)
|
|
422
|
-
def pmf_start(service_id, host, port, no_browser):
|
|
423
|
-
"""Start
|
|
424
|
-
options = {
|
|
423
|
+
def pmf_start(service_id, host, port, project, no_browser):
|
|
424
|
+
"""Start an OTK-managed service."""
|
|
425
|
+
options = {
|
|
426
|
+
"host": host,
|
|
427
|
+
"port": port,
|
|
428
|
+
"project": str(Path(project).resolve()),
|
|
429
|
+
}
|
|
425
430
|
try:
|
|
426
431
|
result = _kernel.start_service(service_id, options=options)
|
|
427
432
|
click.echo(green(f" Started {result['label']} pid={result['pid']}"))
|
|
@@ -429,29 +434,35 @@ def pmf_start(service_id, host, port, no_browser):
|
|
|
429
434
|
url = f"http://{host}:{port}"
|
|
430
435
|
click.echo(_dim(" Opening browser when server is ready..."))
|
|
431
436
|
wait_for_port_and_open_browser(url, host, port)
|
|
432
|
-
except
|
|
437
|
+
except OTKKernelError as exc:
|
|
433
438
|
click.echo(_red(f" {exc}"))
|
|
434
439
|
|
|
435
440
|
|
|
436
441
|
@pmf.command("stop")
|
|
437
442
|
@click.argument("service_id")
|
|
438
443
|
def pmf_stop(service_id):
|
|
439
|
-
"""Stop
|
|
444
|
+
"""Stop an OTK-managed service."""
|
|
440
445
|
try:
|
|
441
446
|
result = _kernel.stop_service(service_id)
|
|
442
447
|
click.echo(green(f" Stopped {result['label']}"))
|
|
443
|
-
except
|
|
448
|
+
except OTKKernelError as exc:
|
|
444
449
|
click.echo(_red(f" {exc}"))
|
|
445
450
|
|
|
446
451
|
|
|
447
452
|
@pmf.command("restart")
|
|
448
453
|
@click.argument("service_id")
|
|
449
|
-
|
|
450
|
-
|
|
454
|
+
@click.option("--host", default="127.0.0.1", help="Host override for UI service")
|
|
455
|
+
@click.option("--port", default=9001, help="Port override for UI service")
|
|
456
|
+
@click.option("--project", default=".", help="Project path override for task services")
|
|
457
|
+
def pmf_restart(service_id, host, port, project):
|
|
458
|
+
"""Restart an OTK-managed service."""
|
|
451
459
|
try:
|
|
452
|
-
result = _kernel.restart_service(
|
|
460
|
+
result = _kernel.restart_service(
|
|
461
|
+
service_id,
|
|
462
|
+
options={"host": host, "port": port, "project": str(Path(project).resolve())},
|
|
463
|
+
)
|
|
453
464
|
click.echo(green(f" Restarted {result['label']} pid={result['pid']}"))
|
|
454
|
-
except
|
|
465
|
+
except OTKKernelError as exc:
|
|
455
466
|
click.echo(_red(f" {exc}"))
|
|
456
467
|
|
|
457
468
|
|
|
@@ -459,20 +470,35 @@ def pmf_restart(service_id):
|
|
|
459
470
|
@click.argument("service_id")
|
|
460
471
|
@click.option("--tail", default=50, show_default=True, help="Lines to tail")
|
|
461
472
|
def pmf_logs(service_id, tail):
|
|
462
|
-
"""Display the last lines from
|
|
473
|
+
"""Display the last lines from an OTK service log."""
|
|
463
474
|
try:
|
|
464
475
|
output = _kernel.tail_log(service_id, lines=tail)
|
|
465
476
|
click.echo(output)
|
|
466
|
-
except
|
|
477
|
+
except OTKKernelError as exc:
|
|
467
478
|
click.echo(_red(f" {exc}"))
|
|
468
479
|
|
|
469
480
|
|
|
481
|
+
@pmf.command("events")
|
|
482
|
+
@click.option("--tail", default=20, show_default=True, help="Number of recent kernel events")
|
|
483
|
+
def pmf_events(tail):
|
|
484
|
+
"""Show recent OTK kernel runtime events."""
|
|
485
|
+
events = _kernel.recent_events(limit=tail)
|
|
486
|
+
click.echo()
|
|
487
|
+
click.echo(_bold(" OTK Kernel Events"))
|
|
488
|
+
click.echo(_hr())
|
|
489
|
+
if not events:
|
|
490
|
+
click.echo(_dim(" (no events)"))
|
|
491
|
+
for ev in events:
|
|
492
|
+
click.echo(f" {ev.get('ts', '—')} {_bold(ev.get('kind', 'event')):<18} {ev.get('service_id', '—'):<14} {ev.get('detail', '')}")
|
|
493
|
+
click.echo()
|
|
494
|
+
|
|
495
|
+
|
|
470
496
|
@pmf.command("up")
|
|
471
497
|
@click.option("--host", default="127.0.0.1", show_default=True)
|
|
472
498
|
@click.option("--port", default=9001, show_default=True)
|
|
473
499
|
@click.option("--no-browser", "no_browser", is_flag=True, default=False)
|
|
474
500
|
def pmf_up(host, port, no_browser):
|
|
475
|
-
"""Start
|
|
501
|
+
"""Start default OTK services (web UI). Called by launchd on login."""
|
|
476
502
|
url = f"http://{host}:{port}"
|
|
477
503
|
click.echo(_bold(" Development Engine Vector — starting services"))
|
|
478
504
|
click.echo(_hr())
|
|
@@ -483,7 +509,7 @@ def pmf_up(host, port, no_browser):
|
|
|
483
509
|
if not no_browser:
|
|
484
510
|
click.echo(_dim(" Opening browser when server is ready..."))
|
|
485
511
|
wait_for_port_and_open_browser(url, host, port)
|
|
486
|
-
except
|
|
512
|
+
except OTKKernelError as exc:
|
|
487
513
|
click.echo(_yellow(f" Web UI {exc}"))
|
|
488
514
|
|
|
489
515
|
click.echo()
|
|
@@ -503,9 +529,10 @@ def pmf_install():
|
|
|
503
529
|
click.echo(green(" Loaded: yes — dev will start automatically on next login"))
|
|
504
530
|
click.echo()
|
|
505
531
|
click.echo(_dim(" To start services now without logging out:"))
|
|
506
|
-
click.echo(_dim(" dev
|
|
532
|
+
click.echo(_dim(" dev otk up"))
|
|
533
|
+
click.echo(_dim(" (legacy alias: dev pmf up)"))
|
|
507
534
|
click.echo()
|
|
508
|
-
except
|
|
535
|
+
except OTKKernelError as exc:
|
|
509
536
|
click.echo(_red(f" {exc}"))
|
|
510
537
|
click.echo(_yellow(" Make sure `dev` is on PATH: export PATH=\"$HOME/Library/Python/3.9/bin:$PATH\""))
|
|
511
538
|
click.echo()
|
|
@@ -523,29 +550,134 @@ def pmf_uninstall():
|
|
|
523
550
|
click.echo(green(" dev will no longer start automatically on login."))
|
|
524
551
|
|
|
525
552
|
|
|
553
|
+
@cli.group()
|
|
554
|
+
def otk():
|
|
555
|
+
"""Manage the Ops Tool Kernel (OTK) and dev runtime services."""
|
|
556
|
+
pass
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
@otk.command("services")
|
|
560
|
+
@click.pass_context
|
|
561
|
+
def otk_services(ctx):
|
|
562
|
+
"""List OTK services and runtime status."""
|
|
563
|
+
ctx.invoke(pmf_services)
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
@otk.command("status")
|
|
567
|
+
@click.argument("service_id", required=False)
|
|
568
|
+
@click.pass_context
|
|
569
|
+
def otk_status(ctx, service_id):
|
|
570
|
+
"""Show OTK runtime status for one or all services."""
|
|
571
|
+
ctx.invoke(pmf_status, service_id=service_id)
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
@otk.command("start")
|
|
575
|
+
@click.argument("service_id")
|
|
576
|
+
@click.option("--host", default="127.0.0.1", help="Host override for UI service")
|
|
577
|
+
@click.option("--port", default=9001, help="Port override for UI service")
|
|
578
|
+
@click.option("--project", default=".", help="Project path override for task services")
|
|
579
|
+
@click.option("--no-browser", "no_browser", is_flag=True, default=False)
|
|
580
|
+
@click.pass_context
|
|
581
|
+
def otk_start(ctx, service_id, host, port, project, no_browser):
|
|
582
|
+
"""Start an OTK-managed service or task."""
|
|
583
|
+
ctx.invoke(
|
|
584
|
+
pmf_start,
|
|
585
|
+
service_id=service_id,
|
|
586
|
+
host=host,
|
|
587
|
+
port=port,
|
|
588
|
+
project=project,
|
|
589
|
+
no_browser=no_browser,
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
@otk.command("stop")
|
|
594
|
+
@click.argument("service_id")
|
|
595
|
+
@click.pass_context
|
|
596
|
+
def otk_stop(ctx, service_id):
|
|
597
|
+
"""Stop an OTK-managed service."""
|
|
598
|
+
ctx.invoke(pmf_stop, service_id=service_id)
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
@otk.command("restart")
|
|
602
|
+
@click.argument("service_id")
|
|
603
|
+
@click.option("--host", default="127.0.0.1", help="Host override for UI service")
|
|
604
|
+
@click.option("--port", default=9001, help="Port override for UI service")
|
|
605
|
+
@click.option("--project", default=".", help="Project path override for task services")
|
|
606
|
+
@click.pass_context
|
|
607
|
+
def otk_restart(ctx, service_id, host, port, project):
|
|
608
|
+
"""Restart an OTK-managed service or task."""
|
|
609
|
+
ctx.invoke(pmf_restart, service_id=service_id, host=host, port=port, project=project)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
@otk.command("logs")
|
|
613
|
+
@click.argument("service_id")
|
|
614
|
+
@click.option("--tail", default=50, show_default=True, help="Lines to tail")
|
|
615
|
+
@click.pass_context
|
|
616
|
+
def otk_logs(ctx, service_id, tail):
|
|
617
|
+
"""Tail logs for an OTK service or task."""
|
|
618
|
+
ctx.invoke(pmf_logs, service_id=service_id, tail=tail)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
@otk.command("events")
|
|
622
|
+
@click.option("--tail", default=20, show_default=True, help="Number of recent kernel events")
|
|
623
|
+
@click.pass_context
|
|
624
|
+
def otk_events(ctx, tail):
|
|
625
|
+
"""Show recent OTK events."""
|
|
626
|
+
ctx.invoke(pmf_events, tail=tail)
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
@otk.command("up")
|
|
630
|
+
@click.option("--host", default="127.0.0.1", show_default=True)
|
|
631
|
+
@click.option("--port", default=9001, show_default=True)
|
|
632
|
+
@click.option("--no-browser", "no_browser", is_flag=True, default=False)
|
|
633
|
+
@click.pass_context
|
|
634
|
+
def otk_up(ctx, host, port, no_browser):
|
|
635
|
+
"""Start default OTK services (web UI)."""
|
|
636
|
+
ctx.invoke(pmf_up, host=host, port=port, no_browser=no_browser)
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
@otk.command("install")
|
|
640
|
+
@click.pass_context
|
|
641
|
+
def otk_install(ctx):
|
|
642
|
+
"""Install OTK launchd registration for auto-start on login."""
|
|
643
|
+
ctx.invoke(pmf_install)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
@otk.command("uninstall")
|
|
647
|
+
@click.pass_context
|
|
648
|
+
def otk_uninstall(ctx):
|
|
649
|
+
"""Uninstall OTK launchd registration."""
|
|
650
|
+
ctx.invoke(pmf_uninstall)
|
|
651
|
+
|
|
652
|
+
|
|
526
653
|
# ── setup ─────────────────────────────────────────────────────────────────────
|
|
527
654
|
|
|
528
655
|
@cli.command("setup")
|
|
529
656
|
@click.option("--no-browser", "no_browser", is_flag=True, default=False,
|
|
530
657
|
help="Don't open browser when the web UI starts")
|
|
531
|
-
|
|
658
|
+
@click.option("--run-otk-chain/--skip-otk-chain", default=False,
|
|
659
|
+
help="Run the first OTK task chain (preflight → vet) after startup")
|
|
660
|
+
def setup(no_browser, run_otk_chain):
|
|
532
661
|
"""
|
|
533
|
-
Full onboarding in three steps: init →
|
|
662
|
+
Full onboarding in three steps: init → otk install → up.
|
|
534
663
|
|
|
535
664
|
\b
|
|
536
|
-
|
|
537
|
-
If `dev` isn't on PATH yet, use the fallback:
|
|
665
|
+
3. Up — start the web UI via OTK, open browser
|
|
538
666
|
|
|
539
|
-
|
|
667
|
+
Optional phase 2:
|
|
668
|
+
- Run the first OTK task chain (preflight → vet) against the dev source tree.
|
|
669
|
+
If `dev` isn't on PATH yet, use the fallback:
|
|
670
|
+
All processes are managed by the OTK kernel. The LaunchAgent calls
|
|
671
|
+
`dev otk up` on every login — no manual interaction needed after setup.
|
|
540
672
|
|
|
541
673
|
\b
|
|
542
674
|
What each step does:
|
|
543
675
|
1. Init — create ~/Library/goCosmix/tools/dev/, patch PATH
|
|
544
676
|
2. Install — register a macOS LaunchAgent so dev starts on every login
|
|
545
|
-
|
|
677
|
+
3. Up — start the web UI via OTK, open browser
|
|
546
678
|
|
|
547
|
-
|
|
548
|
-
|
|
679
|
+
All processes are managed by the OTK kernel. The LaunchAgent calls
|
|
680
|
+
`dev otk up` on every login — no manual interaction needed after setup.
|
|
549
681
|
"""
|
|
550
682
|
import os as _os
|
|
551
683
|
import shutil as _shutil
|
|
@@ -569,7 +701,9 @@ def setup(no_browser):
|
|
|
569
701
|
click.echo(_dim(" Three steps to a fully operational dev installation:"))
|
|
570
702
|
click.echo(_dim(f" 1. Init — create {DEV_HOME}"))
|
|
571
703
|
click.echo(_dim(" 2. Install — register macOS LaunchAgent (auto-start on login)"))
|
|
572
|
-
click.echo(_dim(" 3. Up — start web UI via
|
|
704
|
+
click.echo(_dim(" 3. Up — start web UI via OTK, open browser"))
|
|
705
|
+
if run_otk_chain:
|
|
706
|
+
click.echo(_dim(" 4. Phase 2 — run OTK preflight → vet task chain"))
|
|
573
707
|
click.echo()
|
|
574
708
|
|
|
575
709
|
# ── Step 1: Init ─────────────────────────────────────────────
|
|
@@ -616,13 +750,13 @@ def setup(no_browser):
|
|
|
616
750
|
|
|
617
751
|
click.echo()
|
|
618
752
|
|
|
619
|
-
# ── Step 2:
|
|
753
|
+
# ── Step 2: OTK install ──────────────────────────────────────
|
|
620
754
|
click.echo(_bold(bar))
|
|
621
|
-
click.echo(_bold(" Step 2/3 —
|
|
755
|
+
click.echo(_bold(" Step 2/3 — OTK install"))
|
|
622
756
|
click.echo(_bold(bar))
|
|
623
757
|
click.echo()
|
|
624
758
|
click.echo(_dim(" The LaunchAgent registers dev with macOS launchd. On every login,"))
|
|
625
|
-
click.echo(_dim(" launchd calls `dev
|
|
759
|
+
click.echo(_dim(" launchd calls `dev otk up` — starts the web UI via OTK kernel."))
|
|
626
760
|
click.echo(_dim(" No terminal required after this."))
|
|
627
761
|
click.echo()
|
|
628
762
|
|
|
@@ -632,9 +766,9 @@ def setup(no_browser):
|
|
|
632
766
|
click.echo(f" {green('✓')} LaunchAgent: {target}")
|
|
633
767
|
click.echo(f" {green('✓')} Loaded — dev starts automatically on every login")
|
|
634
768
|
pmf_ok = True
|
|
635
|
-
except
|
|
769
|
+
except OTKKernelError as exc:
|
|
636
770
|
click.echo(f" {_yellow('⚠')} LaunchAgent registration failed: {exc}")
|
|
637
|
-
click.echo(_yellow(" Fix PATH then run `dev pmf install` to retry."))
|
|
771
|
+
click.echo(_yellow(" Fix PATH then run `dev otk install` (or `dev pmf install`) to retry."))
|
|
638
772
|
click.echo()
|
|
639
773
|
|
|
640
774
|
# ── Step 3: Up ───────────────────────────────────────────────
|
|
@@ -651,9 +785,31 @@ def setup(no_browser):
|
|
|
651
785
|
if not no_browser:
|
|
652
786
|
click.echo(_dim(" Opening browser when server is ready..."))
|
|
653
787
|
wait_for_port_and_open_browser(url, host, port)
|
|
654
|
-
except
|
|
788
|
+
except OTKKernelError as exc:
|
|
655
789
|
click.echo(f" {_yellow('⚠')} Web UI: {exc}")
|
|
656
|
-
click.echo(_dim(" Try `dev ui start` once
|
|
790
|
+
click.echo(_dim(" Try `dev ui start` once OTK is installed."))
|
|
791
|
+
|
|
792
|
+
if run_otk_chain:
|
|
793
|
+
source_root = Path(__file__).resolve().parents[2]
|
|
794
|
+
click.echo()
|
|
795
|
+
click.echo(_bold(bar))
|
|
796
|
+
click.echo(_bold(" Phase 2 — OTK task chain"))
|
|
797
|
+
click.echo(_bold(bar))
|
|
798
|
+
click.echo()
|
|
799
|
+
|
|
800
|
+
try:
|
|
801
|
+
preflight_result = _kernel.run_task("preflight", options={"project": str(source_root)}, timeout=600)
|
|
802
|
+
preflight_status = green("✓") if preflight_result["returncode"] == 0 else _yellow("⚠")
|
|
803
|
+
click.echo(f" {preflight_status} preflight exit={preflight_result['returncode']}")
|
|
804
|
+
except OTKKernelError as exc:
|
|
805
|
+
click.echo(f" {_yellow('⚠')} preflight: {exc}")
|
|
806
|
+
|
|
807
|
+
try:
|
|
808
|
+
vet_result = _kernel.run_task("vet", timeout=900)
|
|
809
|
+
vet_status = green("✓") if vet_result["returncode"] == 0 else _yellow("⚠")
|
|
810
|
+
click.echo(f" {vet_status} vet exit={vet_result['returncode']}")
|
|
811
|
+
except OTKKernelError as exc:
|
|
812
|
+
click.echo(f" {_yellow('⚠')} vet: {exc}")
|
|
657
813
|
|
|
658
814
|
click.echo()
|
|
659
815
|
click.echo(_bold(BAR))
|