@matt82198/aesop 0.3.1 → 0.3.2

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/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to Aesop are 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
+ **Version scheme**: Stable releases are `0.x.y`; `0.x.0-beta.N` / `-rc.N` are pre-releases; `0.1.0-wave.N` were internal wave-milestone previews.
9
+
10
+ ## [0.3.2] - 2026-07-23
11
+
12
+ ### Fixed
13
+ - **Windows daemons no longer flash a console window**: ad-hoc Scheduled Tasks launched `bash.exe` with Interactive logon, popping a visible console every watchdog interval (5 min). New `daemons/install-tasks.ps1` registers the watchdog/monitor tasks through a hidden `wscript` launcher (`daemons/run-hidden.vbs`) — same cadence, zero window flash.
14
+
15
+ ### Added
16
+ - `daemons/install-tasks.ps1` — idempotent Windows task installer (install/uninstall/dry-run, configurable commands + intervals); shipped in the npm package.
17
+
8
18
  ## [0.3.1] - 2026-07-22 - Waves 28-31
9
19
 
10
20
  ### Added
@@ -373,6 +383,6 @@ This is the first public release of Aesop, a clean-room source-available impleme
373
383
  - Legacy TUI interface (bash + jq)
374
384
  - Configuration framework and examples
375
385
  - Comprehensive documentation and guides
376
- - MIT License (© 2026 Matt Culliton)
386
+ - PolyForm Strict License 1.0.0 (source-available, © 2026 Matt Culliton)
377
387
 
378
388
  Aesop is production-ready and implements the complete cardinal rules for cost-optimized, durable multi-agent coordination.
package/README.md CHANGED
@@ -48,7 +48,7 @@ python tools/health_score.py
48
48
  ```
49
49
  Outputs a scorecard of system readiness; --json for parsing.
50
50
 
51
- **Self-healing daemon** — Runs every 150s: backs up work, scans secrets, detects drift:
51
+ **Self-monitoring daemon** — Runs every 150s: backs up work, scans secrets, detects drift:
52
52
  ```bash
53
53
  npx @matt82198/aesop watch
54
54
  ```
@@ -60,6 +60,10 @@ python tools/secret_scan.py --staged # Blocks push if leak detected
60
60
  ```
61
61
  Exits with failure on file-read errors (not silently passing). CI validates every merge.
62
62
 
63
+ **Parallel test battery** — Run all four test harnesses concurrently with isolated logs and enforced timeouts (`tools/test_battery.py` — ~5.4 min vs ~10 serial).
64
+
65
+ **Windows CI green** — Full parity support on Windows-latest GitHub Actions: promoted to a required check after 6 consecutive green main runs.
66
+
63
67
  ## Proof Numbers
64
68
 
65
69
  Aesop builds itself. These numbers are live from git, verified by anyone who clones.
@@ -82,16 +86,19 @@ Aesop is built entirely by its own `/buildsystem` wave cycle—running parallel
82
86
 
83
87
  | Metric | Value |
84
88
  | --- | --- |
85
- | Merged PRs | 223 <!-- metrics-verified: self_stats.py (git log) --> |
86
- | Total Commits | 880 <!-- metrics-verified: self_stats.py (git log) --> |
87
- | Project Age | 10 days <!-- metrics-verified: self_stats.py (git log) --> |
89
+ | Merged PRs | 244 <!-- metrics-verified: self_stats.py (git log) --> |
90
+ | Total Commits | 1065 <!-- metrics-verified: self_stats.py (git log) --> |
91
+ | Project Age | 11 days <!-- metrics-verified: self_stats.py (git log) --> |
88
92
  | Waves | 30 <!-- metrics-verified: self_stats.py (git log) --> |
89
- | Insertions + Deletions | 161,064 <!-- metrics-verified: self_stats.py (git log) --> |
90
- | Files Tracked | 500 <!-- metrics-verified: self_stats.py (git log) --> |
91
- | Distinct Co-authors | 9 <!-- metrics-verified: self_stats.py (git log) --> |
93
+ | Insertions + Deletions | 185,174 <!-- metrics-verified: self_stats.py (git log) --> |
94
+ | Files Tracked | 541 <!-- metrics-verified: self_stats.py (git log) --> |
95
+ | Distinct Co-authors | 11 <!-- metrics-verified: self_stats.py (git log) --> |
92
96
 
93
97
  <!-- STATS:END -->
94
98
 
99
+ *Wave: one complete build cycle (intake → dispatch → verify → ship) run by the orchestration engine.*
100
+
101
+
95
102
 
96
103
 
97
104
 
@@ -101,7 +108,7 @@ Aesop is built entirely by its own `/buildsystem` wave cycle—running parallel
101
108
 
102
109
  ## Why Haiku-First Works
103
110
 
104
- The benchmark proves it: across 39 judgment tasks (code review, severity calibration, root-cause analysis, refactor equivalence, security spots), Haiku scored **39/39** vs Opus **38/39** at ~1/3 the per-token cost. See [`bench/results/2026-07-17-judgment-v3-haiku-sonnet-opus.md`](./bench/results/2026-07-17-judgment-v3-haiku-sonnet-opus.md). Honest caveat: curated set (N=39), not real-transcript sampled; the benchmark found no task where Opus beats Haiku, proving sufficiency for this workload, not parity at the reasoning frontier.
111
+ The benchmark proves it: across 39 judgment tasks (code review, severity calibration, root-cause analysis, refactor equivalence, security spots), Haiku scored **39/39** vs Opus **38/39** at ~1/3 the per-token cost. See [`bench/results/2026-07-17-judgment-v3-haiku-sonnet-opus.md`](./bench/results/2026-07-17-judgment-v3-haiku-sonnet-opus.md). **Curated set, N=39** Haiku 39/39 vs Opus 38/39; proves sufficiency for this workload, not frontier parity.
105
112
 
106
113
  ## Learn More
107
114
 
@@ -111,7 +118,7 @@ The benchmark proves it: across 39 judgment tasks (code review, severity calibra
111
118
  - **[docs/DISPATCH-MODEL.md](./docs/DISPATCH-MODEL.md)** — Cost analysis and scaling
112
119
  - **[docs/CARDINAL-RULES.md](./docs/CARDINAL-RULES.md)** — 10 foundational principles
113
120
  - **[docs/autonomous-swe.md](./docs/autonomous-swe.md)** — What "autonomous" means (and doesn't), evidence for all claims, honest limits
114
- - **[RELEASE-NOTES.md](./RELEASE-NOTES.md)** — Version 0.3.0: non-Claude core proof (Codex wave), refinement-loop convergence, Windows-green CI
121
+ - **[RELEASE-NOTES.md](./RELEASE-NOTES.md)** — Version 0.3.1 (the 0.3.0 milestone): non-Claude core proof (Codex wave), refinement-loop convergence, Windows-green CI
115
122
 
116
123
  ## Contributing
117
124
 
@@ -0,0 +1,193 @@
1
+ param(
2
+ [string]$BashExe = 'C:\Program Files\Git\bin\bash.exe',
3
+ [string]$WatchdogCommand = '',
4
+ [string]$MonitorCommand = '',
5
+ [int]$WatchdogIntervalMinutes = 5,
6
+ [int]$MonitorIntervalMinutes = 20,
7
+ [string]$TaskPrefix = 'Aesop',
8
+ [switch]$Uninstall,
9
+ [switch]$DryRun
10
+ )
11
+
12
+ # Enable strict error handling
13
+ $ErrorActionPreference = 'Stop'
14
+
15
+ function ConvertTo-PosixPath {
16
+ param([string]$WindowsPath)
17
+ # Convert C:\foo\bar to /c/foo/bar
18
+ # Rejects UNC paths (\\server\share) — error out instead of mangling
19
+ if ($WindowsPath -match '^\\\\') {
20
+ Write-Error "UNC paths are unsupported (got: $WindowsPath). Pass -WatchdogCommand explicitly with a valid path."
21
+ exit 1
22
+ }
23
+ $posixPath = $WindowsPath -replace '\\', '/'
24
+ $posixPath = $posixPath -replace '^([A-Za-z]):', '/$1'
25
+ return $posixPath
26
+ }
27
+
28
+ function Get-WorktreeRoot {
29
+ # Derive worktree root from $PSScriptRoot (daemons/)
30
+ # $PSScriptRoot is C:\...\aesop\daemons
31
+ # Parent is C:\...\aesop
32
+ $daemonsDir = $PSScriptRoot
33
+ $aesopRoot = Split-Path -Parent $daemonsDir
34
+ return $aesopRoot
35
+ }
36
+
37
+ function Register-DaemonTask {
38
+ param(
39
+ [string]$TaskName,
40
+ [string]$Command,
41
+ [int]$IntervalMinutes,
42
+ [string]$RunHiddenVbs,
43
+ [string]$BashExe
44
+ )
45
+
46
+ # Build the action: wscript.exe //B //Nologo "path\to\run-hidden.vbs" "<bash>" -lc "<command>"
47
+ $action = New-ScheduledTaskAction `
48
+ -Execute 'wscript.exe' `
49
+ -Argument "//B //Nologo ""$RunHiddenVbs"" ""$BashExe"" -lc ""$Command"""
50
+
51
+ # Build the trigger: Once, starting in 1 minute, repeating every N minutes for 10 years
52
+ $startTime = (Get-Date).AddMinutes(1)
53
+ $trigger = New-ScheduledTaskTrigger `
54
+ -Once `
55
+ -At $startTime `
56
+ -RepetitionInterval (New-TimeSpan -Minutes $IntervalMinutes) `
57
+ -RepetitionDuration (New-TimeSpan -Days 3650)
58
+
59
+ # Build the settings: Hidden, IgnoreNew for multiple instances, 1-hour timeout
60
+ $settings = New-ScheduledTaskSettingsSet `
61
+ -Hidden `
62
+ -MultipleInstances IgnoreNew `
63
+ -ExecutionTimeLimit (New-TimeSpan -Hours 1) `
64
+ -StartWhenAvailable
65
+
66
+ if ($DryRun) {
67
+ # Print DryRun output
68
+ Write-Host "DRYRUN: $TaskName -> wscript.exe //B //Nologo ""$RunHiddenVbs"" ""$BashExe"" -lc ""$Command"" (interval=$IntervalMinutes`m, Hidden=True)"
69
+ }
70
+ else {
71
+ # Register the task (force overwrite if exists)
72
+ try {
73
+ Register-ScheduledTask `
74
+ -TaskName $TaskName `
75
+ -Action $action `
76
+ -Trigger $trigger `
77
+ -Settings $settings `
78
+ -Force `
79
+ -ErrorAction Stop | Out-Null
80
+ Write-Host "Registered task: $TaskName (interval=$IntervalMinutes minutes)"
81
+ }
82
+ catch {
83
+ Write-Error "Failed to register task $TaskName : $_"
84
+ exit 1
85
+ }
86
+ }
87
+ }
88
+
89
+ function Unregister-DaemonTask {
90
+ param([string]$TaskName)
91
+
92
+ try {
93
+ $task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
94
+ if ($task) {
95
+ Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction Stop
96
+ Write-Host "Unregistered task: $TaskName"
97
+ return $true
98
+ }
99
+ else {
100
+ Write-Host "Task not found: $TaskName (already unregistered or never existed)"
101
+ return $true
102
+ }
103
+ }
104
+ catch {
105
+ Write-Error "Failed to unregister $TaskName : $_"
106
+ return $false
107
+ }
108
+ }
109
+
110
+ function Main {
111
+ # Resolve paths
112
+ $aesopRoot = Get-WorktreeRoot
113
+ $runHiddenVbs = Join-Path $PSScriptRoot 'run-hidden.vbs'
114
+
115
+ # VALIDATION: Check for double quotes in commands (contract violation)
116
+ # This check runs early and always, before any operations
117
+ if ($WatchdogCommand -like '*"*') {
118
+ Write-Error "WatchdogCommand contains double quotes, which are not allowed (vbs launcher contract violation)."
119
+ exit 1
120
+ }
121
+ if ($MonitorCommand -like '*"*') {
122
+ Write-Error "MonitorCommand contains double quotes, which are not allowed (vbs launcher contract violation)."
123
+ exit 1
124
+ }
125
+
126
+ # PATH VALIDATION: Only enforce file existence checks if not in DryRun mode
127
+ # In DryRun, downgrade to warnings so preview works on machines without Git Bash
128
+ if (-not $DryRun) {
129
+ if (-not (Test-Path $runHiddenVbs)) {
130
+ Write-Error "run-hidden.vbs not found at: $runHiddenVbs"
131
+ exit 1
132
+ }
133
+ if (-not (Test-Path $BashExe)) {
134
+ Write-Error "bash.exe not found at: $BashExe"
135
+ exit 1
136
+ }
137
+ }
138
+ else {
139
+ if (-not (Test-Path $runHiddenVbs)) {
140
+ Write-Warning "run-hidden.vbs not found at: $runHiddenVbs (DryRun mode)"
141
+ }
142
+ if (-not (Test-Path $BashExe)) {
143
+ Write-Warning "bash.exe not found at: $BashExe (DryRun mode)"
144
+ }
145
+ }
146
+
147
+ # Handle Uninstall mode
148
+ if ($Uninstall) {
149
+ $watchdog_ok = Unregister-DaemonTask -TaskName "${TaskPrefix}WatchdogDaemon"
150
+ $monitor_ok = Unregister-DaemonTask -TaskName "${TaskPrefix}RefinementMonitor"
151
+ if (-not $watchdog_ok -or -not $monitor_ok) {
152
+ exit 1
153
+ }
154
+ exit 0
155
+ }
156
+
157
+ # Derive default commands if not provided
158
+ if (-not $WatchdogCommand) {
159
+ $posixRoot = ConvertTo-PosixPath $aesopRoot
160
+
161
+ # P2: Detect apostrophe in derived path (breaks bash syntax if not escaped)
162
+ if ($posixRoot -like "*'*") {
163
+ Write-Error "Repository path contains apostrophe, which would break the derived command: $posixRoot`nPass -WatchdogCommand explicitly."
164
+ exit 1
165
+ }
166
+
167
+ $WatchdogCommand = "bash '$posixRoot/daemons/run-watchdog.sh' --once >> '$posixRoot/state/cron-watchdog.log' 2>&1"
168
+ }
169
+
170
+ # Register watchdog task
171
+ $watchdogTaskName = "${TaskPrefix}WatchdogDaemon"
172
+ Register-DaemonTask `
173
+ -TaskName $watchdogTaskName `
174
+ -Command $WatchdogCommand `
175
+ -IntervalMinutes $WatchdogIntervalMinutes `
176
+ -RunHiddenVbs $runHiddenVbs `
177
+ -BashExe $BashExe
178
+
179
+ # Register monitor task if command provided
180
+ if ($MonitorCommand) {
181
+ $monitorTaskName = "${TaskPrefix}RefinementMonitor"
182
+ Register-DaemonTask `
183
+ -TaskName $monitorTaskName `
184
+ -Command $MonitorCommand `
185
+ -IntervalMinutes $MonitorIntervalMinutes `
186
+ -RunHiddenVbs $runHiddenVbs `
187
+ -BashExe $BashExe
188
+ }
189
+
190
+ exit 0
191
+ }
192
+
193
+ Main
@@ -0,0 +1,39 @@
1
+ ' run-hidden.vbs — VBScript launcher for Windows Scheduled Tasks
2
+ '
3
+ ' Purpose: Execute a command with a hidden console window (window style 0) and
4
+ ' propagate its exit code.
5
+ '
6
+ ' Usage:
7
+ ' wscript.exe //B //Nologo run-hidden.vbs <bash-exe> -lc "<command>"
8
+ '
9
+ ' The script rebuilds a quoted command line from WScript.Arguments and runs it
10
+ ' via WScript.Shell.Run with window style 0 (hidden). CRITICAL: The task
11
+ ' instance lives as long as the child process (shell.Run waits), so that
12
+ ' - MultipleInstances IgnoreNew can prevent concurrent runs
13
+ ' - ExecutionTimeLimit can kill hung processes
14
+ ' - LastTaskResult reflects the actual child exit code (not always 0)
15
+ '
16
+ ' By contract, arguments never contain double quotes.
17
+
18
+ Dim shell, cmd, i, arg
19
+ Dim windowStyle, rc
20
+
21
+ Set shell = CreateObject("WScript.Shell")
22
+
23
+ ' Build command line from arguments
24
+ cmd = ""
25
+ For i = 0 To WScript.Arguments.Count - 1
26
+ arg = WScript.Arguments(i)
27
+ If i > 0 Then cmd = cmd & " "
28
+ ' Arguments never contain quotes by contract; wrap in quotes for safety
29
+ cmd = cmd & """" & arg & """"
30
+ Next
31
+
32
+ ' Window style 0 = hidden; wait for process exit (True = wait)
33
+ windowStyle = 0
34
+
35
+ ' Execute the command and wait for it to complete, capturing exit code
36
+ rc = shell.Run(cmd, windowStyle, True)
37
+
38
+ ' Exit with the child process's exit code
39
+ WScript.Quit rc
package/docs/INSTALL.md CHANGED
@@ -283,6 +283,50 @@ To bypass during testing: `git push --no-verify` (not recommended for production
283
283
 
284
284
  ---
285
285
 
286
+ ## Windows: Register Daemons as Hidden Scheduled Tasks
287
+
288
+ On Windows, the watchdog and refinement monitor daemons can run silently in the background without flashing a console window. Use the provided PowerShell installer:
289
+
290
+ ```powershell
291
+ # Register watchdog daemon (every 5m)
292
+ powershell -NoProfile -ExecutionPolicy Bypass -File daemons/install-tasks.ps1
293
+
294
+ # Register both watchdog and monitor daemons (monitor script is external, customize path as needed)
295
+ powershell -NoProfile -ExecutionPolicy Bypass -File daemons/install-tasks.ps1 `
296
+ -MonitorCommand "bash '/c/path/to/your/monitor/run-monitor.sh' --once"
297
+
298
+ # Customize intervals and task names
299
+ powershell -NoProfile -ExecutionPolicy Bypass -File daemons/install-tasks.ps1 `
300
+ -TaskPrefix MyFleet `
301
+ -WatchdogIntervalMinutes 10 `
302
+ -MonitorIntervalMinutes 30 `
303
+ -MonitorCommand "bash '/c/path/to/your/monitor/run-monitor.sh' --once"
304
+
305
+ # Uninstall tasks
306
+ powershell -NoProfile -ExecutionPolicy Bypass -File daemons/install-tasks.ps1 -Uninstall
307
+
308
+ # Preview without registering (dry-run mode)
309
+ powershell -NoProfile -ExecutionPolicy Bypass -File daemons/install-tasks.ps1 -DryRun
310
+ ```
311
+
312
+ **How it works**: The installer creates Scheduled Tasks that launch `wscript.exe` with a hidden VBScript launcher (`daemons/run-hidden.vbs`). This avoids the console window that appears when bash.exe is run directly as a Scheduled Task action.
313
+
314
+ **Parameters**:
315
+ - `-TaskPrefix AesopMyFleet` — Task names: `AesopMyFleetWatchdogDaemon`, `AesopMyFleetRefinementMonitor` (default: `Aesop`)
316
+ - `-WatchdogIntervalMinutes N` — Watchdog cycle interval in minutes (default: 5)
317
+ - `-MonitorIntervalMinutes N` — Monitor cycle interval in minutes (default: 20)
318
+ - `-WatchdogCommand "bash '...' ..."` — Custom watchdog command (default: `run-watchdog.sh --once >> state/cron-watchdog.log`)
319
+ - `-MonitorCommand "bash '...' ..."` — Custom monitor command; omit to skip registering the monitor task (default: empty)
320
+ - `-Uninstall` — Remove all registered tasks
321
+ - `-DryRun` — Preview task configuration without registering
322
+
323
+ **Constraints**:
324
+ - Commands (`-WatchdogCommand`, `-MonitorCommand`) must NOT contain double quotes (vbs launcher contract)
325
+ - UNC paths (e.g., `\\server\share`) are not supported; use local Windows or POSIX paths only
326
+ - `-DryRun` mode works even if `bash.exe` or run-hidden.vbs is missing (validation downgraded to warnings for preview)
327
+
328
+ ---
329
+
286
330
  ## Next Steps
287
331
 
288
332
  1. **Read [PORTING.md](PORTING.md)** — Step-by-step guide for adopting Aesop on a foreign repo (10 common failure modes)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matt82198/aesop",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Multi-agent orchestration for AI coding agents, designed to survive failure — a plain-file brain, git as the only durable layer, cheap subagent fleets, and guardrails enforced in code.",
5
5
  "bin": {
6
6
  "aesop": "bin/cli.js"
@@ -9,6 +9,8 @@
9
9
  "files": [
10
10
  "bin/*.js",
11
11
  "daemons/*.sh",
12
+ "daemons/*.ps1",
13
+ "daemons/*.vbs",
12
14
  "dash/*.mjs",
13
15
  "dash/*.sh",
14
16
  "monitor/collect-signals.mjs",