holistic 0.5.3 → 0.5.5
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 +21 -0
- package/README.md +95 -12
- package/bin/holistic +10 -17
- package/bin/holistic.cmd +8 -23
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +84 -34
- package/dist/cli.js.map +1 -1
- package/dist/core/docs.d.ts.map +1 -1
- package/dist/core/docs.js +1 -3
- package/dist/core/docs.js.map +1 -1
- package/dist/core/git.d.ts +1 -0
- package/dist/core/git.d.ts.map +1 -1
- package/dist/core/git.js +16 -22
- package/dist/core/git.js.map +1 -1
- package/dist/core/setup.d.ts +7 -0
- package/dist/core/setup.d.ts.map +1 -1
- package/dist/core/setup.js +151 -16
- package/dist/core/setup.js.map +1 -1
- package/dist/core/state.js +2 -2
- package/dist/core/state.js.map +1 -1
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/sync.js +2 -2
- package/dist/core/sync.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.5 - 2026-04-10
|
|
4
|
+
|
|
5
|
+
Major Security & Trust Hardening (M005) to eliminate silent automation and improve auditability.
|
|
6
|
+
|
|
7
|
+
- Added **Consent Gating** to `holistic bootstrap`: The CLI now displays a summary of system-modifying actions (daemon, hooks, Claude setup) and requires an explicit `--yes` flag to apply them.
|
|
8
|
+
- Added `holistic doctor` command for repository setup diagnostics and background sync health monitoring.
|
|
9
|
+
- Implemented **Privacy-First Defaults**: Remote portable-state syncing is now disabled by default. Users must explicitly opt-in by setting `"portableState": true` in the repo config.
|
|
10
|
+
- Eliminated **Silent Error Suppression**: Background sync scripts (PowerShell & Bash) now use timestamped logging to `.holistic/system/sync.log`. Failures are now visible in `holistic doctor` and `holistic status`.
|
|
11
|
+
- Hardened **Git-Native Snapshotting**: Refactored repo snapshotting to use `git ls-files`, ensuring $O(\text{changes})$ performance and native `.gitignore` compliance.
|
|
12
|
+
- Gated **Handoff Commits by Default**: Removed automatic Git commits from the `handoff` command. Holistic now prepares a `pending-commit.txt` for manual review, with an optional `--commit` flag for automated workflows.
|
|
13
|
+
|
|
14
|
+
## 0.5.4 - 2026-04-09
|
|
15
|
+
|
|
16
|
+
Security hardening in response to socket.dev AI-based package scanner flags.
|
|
17
|
+
|
|
18
|
+
- Removed `-WindowStyle Hidden` from the Windows daemon startup `.cmd` — the daemon now runs in a visible window, consistent with how macOS and Linux handle it.
|
|
19
|
+
- Downgraded PowerShell execution policy from `-ExecutionPolicy Bypass` to `-ExecutionPolicy RemoteSigned` in all three generation sites (`setup.ts`, `sync.ts`, `bin/holistic.cmd`). `RemoteSigned` is sufficient for locally-generated scripts and does not suppress antivirus or security monitoring.
|
|
20
|
+
- Fixed a real code quality bug in `bin/holistic.cmd`: the `COMMIT_MSG` variable read from `pending-commit.txt` was used unquoted in a `git commit -m` call. Special characters (`&`, `|`, `>`, `<`, `"`) are now stripped before use to prevent cmd.exe argument injection.
|
|
21
|
+
- Added `SECURITY.md` with transparent disclosure of what Holistic installs (daemon, startup entries, git sync), what it does not do (no exfiltration, no credential access, no external services), and an explanation of known scanner false positives.
|
|
22
|
+
- Added Security & Privacy section to `README.md` linking to `SECURITY.md`.
|
|
23
|
+
|
|
3
24
|
## 0.5.3 - 2026-04-09
|
|
4
25
|
|
|
5
26
|
Hardened state management for fresh repos and path-moved environments, and added a repair command to regenerate stale machine-local helpers.
|
package/README.md
CHANGED
|
@@ -12,14 +12,32 @@ Your repo remembers, so your next agent doesn't have to guess.
|
|
|
12
12
|
Shared memory for AI agents, built into your repo.
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
[](https://www.npmjs.com/package/holistic)
|
|
16
|
+
[](https://github.com/lweiss01/holistic/actions)
|
|
17
|
+
[](./LICENSE)
|
|
18
|
+
[](./package.json)
|
|
19
|
+
|
|
15
20
|
### One command. Every agent. Zero re-explaining. ✨
|
|
16
21
|
|
|
17
22
|
Holistic gives your AI agents shared memory inside the repo itself. When you switch from Claude to Codex to Gemini, the next agent can see what happened last time, what not to break, and what should happen next.
|
|
18
23
|
|
|
19
|
-

|
|
20
24
|
|
|
21
25
|
---
|
|
22
26
|
|
|
27
|
+
|
|
28
|
+
### Why trust this?
|
|
29
|
+
|
|
30
|
+
- 🔐 No known security vulnerabilities
|
|
31
|
+
- 🧪 60+ automated tests covering core flows
|
|
32
|
+
- 🛠️ Actively maintained (frequent releases)
|
|
33
|
+
- 🔍 Transparent local setup (see `SECURITY.md`)
|
|
34
|
+
|
|
35
|
+
> Early beta, but built to be safe, inspectable, and predictable.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
|
|
23
41
|
## Get started in 30 seconds ⚡
|
|
24
42
|
|
|
25
43
|
Open your project repo in PowerShell, Terminal, Command Prompt, or whatever shell you normally use.
|
|
@@ -30,7 +48,7 @@ Run these two commands:
|
|
|
30
48
|
|
|
31
49
|
```bash
|
|
32
50
|
npm install -g holistic
|
|
33
|
-
holistic bootstrap
|
|
51
|
+
holistic bootstrap --yes
|
|
34
52
|
```
|
|
35
53
|
|
|
36
54
|
After that, open the repo in your agent app and use this startup prompt:
|
|
@@ -43,8 +61,10 @@ That is enough to get the basic Holistic workflow working.
|
|
|
43
61
|
|
|
44
62
|
If you want the fuller install and setup details, jump to [Quick start](#quick-start-).
|
|
45
63
|
|
|
64
|
+
|
|
46
65
|
---
|
|
47
66
|
|
|
67
|
+
|
|
48
68
|
## The problem 😵
|
|
49
69
|
|
|
50
70
|
If you use more than one AI coding assistant, the workflow usually falls apart:
|
|
@@ -57,8 +77,10 @@ If you use more than one AI coding assistant, the workflow usually falls apart:
|
|
|
57
77
|
|
|
58
78
|
Holistic fixes that by making the repo the source of truth.
|
|
59
79
|
|
|
80
|
+
|
|
60
81
|
---
|
|
61
82
|
|
|
83
|
+
|
|
62
84
|
## What it feels like with HOLISTIC 🌿
|
|
63
85
|
|
|
64
86
|
Run one setup command on a machine:
|
|
@@ -78,8 +100,10 @@ Most days, you do not need to keep a terminal process open or manually re-brief
|
|
|
78
100
|
|
|
79
101
|
`holistic bootstrap` is a machine setup command, not just a repo setup command. By default it can install local startup helpers and configure Claude Desktop MCP on that machine.
|
|
80
102
|
|
|
103
|
+
|
|
81
104
|
---
|
|
82
105
|
|
|
106
|
+
|
|
83
107
|
## How it works 🧭
|
|
84
108
|
|
|
85
109
|
```text
|
|
@@ -98,8 +122,10 @@ Holistic checkpoints and handoffs keep repo memory current
|
|
|
98
122
|
The next agent picks up without a long re-explanation
|
|
99
123
|
```
|
|
100
124
|
|
|
125
|
+
|
|
101
126
|
---
|
|
102
127
|
|
|
128
|
+
|
|
103
129
|
## Quick start 🚀
|
|
104
130
|
|
|
105
131
|
### Install 📦
|
|
@@ -138,8 +164,8 @@ npm link
|
|
|
138
164
|
|
|
139
165
|
```bash
|
|
140
166
|
cd my-project
|
|
141
|
-
holistic bootstrap --remote origin
|
|
142
|
-
git add .gitattributes HOLISTIC.md AGENTS.md CLAUDE.md GEMINI.md
|
|
167
|
+
holistic bootstrap --remote origin --yes
|
|
168
|
+
git add .gitattributes HOLISTIC.md AGENTS.md CLAUDE.md GEMINI.md
|
|
143
169
|
git add .holistic/config.json .holistic/state.json
|
|
144
170
|
git add .holistic/context/
|
|
145
171
|
git commit -m "feat: add holistic"
|
|
@@ -172,8 +198,10 @@ holistic bootstrap --install-daemon false --configure-mcp false
|
|
|
172
198
|
|
|
173
199
|
The portable repo memory is meant to be committed and synced. Machine-local helper scripts are generated for each machine and stay local.
|
|
174
200
|
|
|
201
|
+
|
|
175
202
|
---
|
|
176
203
|
|
|
204
|
+
|
|
177
205
|
## Daily workflow 🔄
|
|
178
206
|
|
|
179
207
|
One-time machine setup:
|
|
@@ -202,8 +230,10 @@ If `holistic` is not on `PATH` in a given shell, every bootstrapped repo also ha
|
|
|
202
230
|
- Windows: `.\.holistic\system\holistic.cmd <command>`
|
|
203
231
|
- macOS/Linux: `./.holistic/system/holistic <command>`
|
|
204
232
|
|
|
233
|
+
|
|
205
234
|
---
|
|
206
235
|
|
|
236
|
+
|
|
207
237
|
## Regression protection 🛡️
|
|
208
238
|
|
|
209
239
|
When an agent fixes something delicate, lock it in:
|
|
@@ -217,8 +247,10 @@ holistic checkpoint \
|
|
|
217
247
|
|
|
218
248
|
Future agents will see that warning in the repo docs before they touch the risky area again.
|
|
219
249
|
|
|
250
|
+
|
|
220
251
|
---
|
|
221
252
|
|
|
253
|
+
|
|
222
254
|
## Works with multiple agent apps 🤝
|
|
223
255
|
|
|
224
256
|
Holistic is model-agnostic. It works through repo files first, and can expose a thin MCP server where supported.
|
|
@@ -240,8 +272,10 @@ Use this table to decide whether startup should be automatic (MCP/tooling hook)
|
|
|
240
272
|
| Other VS Code forks | `AGENTS.md` and repo docs | ❌ No | Treat as manual-start and run `/holistic` |
|
|
241
273
|
| Web tools | repo docs pasted manually | ❌ No | Manual copy/paste recap from Holistic docs |
|
|
242
274
|
|
|
275
|
+
|
|
243
276
|
---
|
|
244
277
|
|
|
278
|
+
|
|
245
279
|
## What lives in your repo 🗂️
|
|
246
280
|
|
|
247
281
|
```text
|
|
@@ -250,7 +284,11 @@ my-project/
|
|
|
250
284
|
|- AGENTS.md
|
|
251
285
|
|- CLAUDE.md
|
|
252
286
|
|- GEMINI.md
|
|
253
|
-
|-
|
|
287
|
+
|- .cursorrules
|
|
288
|
+
|- .windsurfrules
|
|
289
|
+
|- .gitattributes
|
|
290
|
+
|- .github/
|
|
291
|
+
| `- copilot-instructions.md
|
|
254
292
|
`- .holistic/
|
|
255
293
|
|- config.json
|
|
256
294
|
|- state.json
|
|
@@ -263,20 +301,24 @@ my-project/
|
|
|
263
301
|
|
|
264
302
|
The portable repo memory (config, state, context, sessions) is meant to be committed and synced. Machine-local helper scripts and repo-local CLI fallbacks under `.holistic/system/` are generated for each machine and stay local (already in `.gitignore`).
|
|
265
303
|
|
|
304
|
+
|
|
266
305
|
---
|
|
267
306
|
|
|
307
|
+
|
|
268
308
|
## Commands
|
|
269
309
|
|
|
270
|
-
| Command | What it does |
|
|
271
|
-
|---|---|
|
|
272
310
|
| `holistic init` | Base repo setup and scaffolding |
|
|
273
|
-
| `holistic bootstrap` | One-step machine setup
|
|
274
|
-
| `holistic
|
|
311
|
+
| `holistic bootstrap` | One-step machine setup. Required `--yes` to apply system changes. |
|
|
312
|
+
| `holistic doctor` | Runs health checks on machine setup and sync logs |
|
|
313
|
+
| `holistic repair` | Regenerates `.holistic/system/` helpers |
|
|
314
|
+
| `holistic resume / start --agent <name>` | Loads project recap and prints state |
|
|
315
|
+
| `holistic start-new` | Starts a fresh session |
|
|
275
316
|
| `holistic checkpoint --reason "..."` | Saves progress and context |
|
|
276
|
-
| `holistic handoff` | Ends a session with a handoff |
|
|
277
|
-
| `holistic status` | Shows
|
|
317
|
+
| `holistic handoff` | Ends a session with a handoff message |
|
|
318
|
+
| `holistic status` | Shows current state and recent sync activity |
|
|
278
319
|
| `holistic diff --from <id> --to <id>` | Compares two sessions |
|
|
279
|
-
| `holistic
|
|
320
|
+
| `holistic search --id <session-id>` | Finds and reactivates an archived session |
|
|
321
|
+
| `holistic serve` | Runs the thin MCP server |
|
|
280
322
|
| `holistic watch` | Foreground daemon mode for automatic checkpoints |
|
|
281
323
|
|
|
282
324
|
### Slash command helper text (agent-facing)
|
|
@@ -297,8 +339,10 @@ holistic handoff \
|
|
|
297
339
|
--blocker "Need refresh token endpoint from backend team"
|
|
298
340
|
```
|
|
299
341
|
|
|
342
|
+
|
|
300
343
|
---
|
|
301
344
|
|
|
345
|
+
|
|
302
346
|
## Architecture
|
|
303
347
|
|
|
304
348
|
Holistic is intentionally repo-first, not machine-first.
|
|
@@ -337,8 +381,10 @@ When you do run `holistic serve` manually in a terminal, Holistic prints its ASC
|
|
|
337
381
|
}
|
|
338
382
|
```
|
|
339
383
|
|
|
384
|
+
|
|
340
385
|
---
|
|
341
386
|
|
|
387
|
+
|
|
342
388
|
## Why this matters
|
|
343
389
|
|
|
344
390
|
If you are already using more than one AI coding assistant, you already have the continuity problem.
|
|
@@ -351,23 +397,60 @@ Holistic gives you:
|
|
|
351
397
|
- A durable record of what changed and why
|
|
352
398
|
- Agents that can get to work quickly
|
|
353
399
|
|
|
400
|
+
|
|
354
401
|
---
|
|
355
402
|
|
|
403
|
+
|
|
356
404
|
## Beta Feedback Welcome 🙏
|
|
357
405
|
|
|
358
406
|
Holistic is in early beta. If you hit rough edges, unexpected behavior, or have ideas for improvement, please [open an issue](https://github.com/lweiss01/holistic/issues). Early adopter feedback directly shapes the direction of the project.
|
|
359
407
|
|
|
360
408
|
For support and troubleshooting, see [SUPPORT.md](./SUPPORT.md).
|
|
361
409
|
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
## Security, Privacy, and Trust 🔒
|
|
415
|
+
|
|
416
|
+
Holistic is designed to be **transparent, audit-safe, and consent-first**. It is a shared memory layer that stays in your repo, not a cloud service that watches your screen.
|
|
417
|
+
|
|
418
|
+
### Trust Architecture:
|
|
419
|
+
- **Explicit Consent**: `holistic bootstrap` will show you exactly what changes it wants to make to your machine (daemon installation, git hooks, Claude setup) and requires an explicit `--yes` to proceed.
|
|
420
|
+
- **Privacy First**: Remote syncing is **disabled by default**. Set `"portableState": true` in `.holistic/config.json` only if you want to share memory across devices using a hidden git ref.
|
|
421
|
+
- **Traceable Activity**: Background sync operations (PowerShell/Bash) are no longer silent. All activity is logged with timestamps and error details to `.holistic/system/sync.log`.
|
|
422
|
+
- **Health Checks**: Use `holistic doctor` at any time to audit your machine-local setup and verify sync log health.
|
|
423
|
+
- **Git-Native Snapshotting**: The repo snapshot logic uses native `git ls-files`, ensuring that your `.gitignore` rules are perfectly respected and performance stays $O(\text{repo size})$.
|
|
424
|
+
- **Zero Shell Injection**: Internal commit logic has been stripped of shell wrappers to eliminate command injection risks.
|
|
425
|
+
|
|
426
|
+
### What it does:
|
|
427
|
+
- Writes session state into `.holistic/` inside your repo (committed files you control)
|
|
428
|
+
- Installs a daemon via standard OS autostart (Windows Startup folder, macOS LaunchAgents, Linux systemd user)
|
|
429
|
+
- Can push Holistic state to a hidden git ref on your configured remote (opt-in, your repo only)
|
|
430
|
+
|
|
431
|
+
### What it does NOT do:
|
|
432
|
+
- Does not read or transmit file contents outside your repo
|
|
433
|
+
- Does not access credentials or tokens
|
|
434
|
+
- Does not phone home to any external service
|
|
435
|
+
- Does not use obfuscated scripts or hidden windows
|
|
436
|
+
|
|
437
|
+
For the full technical disclosure, see [SECURITY.md](./SECURITY.md).
|
|
438
|
+
|
|
439
|
+
|
|
362
440
|
---
|
|
363
441
|
|
|
442
|
+
|
|
364
443
|
## Quick links
|
|
365
444
|
|
|
366
445
|
- [Walkthrough](./docs/handoff-walkthrough.md)
|
|
446
|
+
- [Security & Privacy](./SECURITY.md)
|
|
367
447
|
- [Changelog](./CHANGELOG.md)
|
|
368
448
|
- [Contributing](./CONTRIBUTING.md)
|
|
369
449
|
- [License](./LICENSE)
|
|
370
450
|
|
|
451
|
+
|
|
452
|
+
|
|
371
453
|
---
|
|
372
454
|
|
|
455
|
+
|
|
373
456
|
<p align="center"><em>Built for people who use more than one AI assistant and are tired of paying the context tax.</em></p>
|
package/bin/holistic
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
3
|
-
node --experimental-strip-types "$SCRIPT_DIR/../src/cli.ts" "$@"
|
|
4
|
-
status=$?
|
|
5
|
-
if [ "$status" -ne 0 ]; then
|
|
6
|
-
exit "$status"
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
git add -- HOLISTIC.md AGENTS.md .holistic && git commit -m "$message"
|
|
12
|
-
if [ "$?" -eq 0 ] && [ -f "$PWD/.holistic/system/sync-state.sh" ]; then
|
|
13
|
-
/bin/sh "$PWD/.holistic/system/sync-state.sh" || true
|
|
14
|
-
node --experimental-strip-types "$SCRIPT_DIR/../src/cli.ts" internal-mark-commit --message "$message"
|
|
15
|
-
fi
|
|
16
|
-
fi
|
|
17
|
-
fi
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
3
|
+
node --experimental-strip-types "$SCRIPT_DIR/../src/cli.ts" "$@"
|
|
4
|
+
status=$?
|
|
5
|
+
if [ "$status" -ne 0 ]; then
|
|
6
|
+
exit "$status"
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
# Holistic: Sync logic is now handled inside the Node CLI or gated behind explicit flags.
|
|
10
|
+
# This wrapper is kept simple to avoid shell variable expansion vulnerabilities.
|
package/bin/holistic.cmd
CHANGED
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
setlocal
|
|
3
|
-
set SCRIPT_DIR=%~dp0
|
|
4
|
-
node --experimental-strip-types "%SCRIPT_DIR%..\src\cli.ts" %*
|
|
5
|
-
if errorlevel 1 exit /b %errorlevel%
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
set /p COMMIT_MSG=<"%PENDING_FILE%"
|
|
10
|
-
if defined COMMIT_MSG (
|
|
11
|
-
git add -- HOLISTIC.md AGENTS.md .holistic
|
|
12
|
-
if not errorlevel 1 (
|
|
13
|
-
git commit -m "%COMMIT_MSG%"
|
|
14
|
-
if not errorlevel 1 (
|
|
15
|
-
if exist "%CD%\.holistic\system\sync-state.ps1" (
|
|
16
|
-
powershell -NoProfile -ExecutionPolicy Bypass -File "%CD%\.holistic\system\sync-state.ps1"
|
|
17
|
-
)
|
|
18
|
-
node --experimental-strip-types "%SCRIPT_DIR%..\src\cli.ts" internal-mark-commit --message "%COMMIT_MSG%"
|
|
19
|
-
)
|
|
20
|
-
)
|
|
21
|
-
)
|
|
22
|
-
)
|
|
23
|
-
)
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal
|
|
3
|
+
set SCRIPT_DIR=%~dp0
|
|
4
|
+
node --experimental-strip-types "%SCRIPT_DIR%..\src\cli.ts" %*
|
|
5
|
+
if errorlevel 1 exit /b %errorlevel%
|
|
6
|
+
|
|
7
|
+
rem Holistic: Sync logic is now handled inside the Node CLI or gated behind explicit flags.
|
|
8
|
+
rem This wrapper is kept simple to avoid shell variable injection vulnerabilities.
|
package/dist/cli.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export declare function renderHelpText(): string;
|
|
|
3
3
|
export declare function renderResumeOutput(body: string): string;
|
|
4
4
|
export declare function finalizeDraftHandoffInput(session: SessionRecord, input: HandoffInput): HandoffInput;
|
|
5
5
|
export declare function renderDiff(fromSession: SessionRecord, toSession: SessionRecord, diff: SessionDiff): string;
|
|
6
|
-
export declare function renderStatus(state: HolisticState): string;
|
|
6
|
+
export declare function renderStatus(rootDir: string, state: HolisticState): string;
|
|
7
7
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAA4C,YAAY,EAAE,aAAa,EAAgB,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA2EvJ,wBAAgB,cAAc,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAA4C,YAAY,EAAE,aAAa,EAAgB,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA2EvJ,wBAAgB,cAAc,IAAI,MAAM,CA4BvC;AAMD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AA4ED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,CAcnG;AAMD,wBAAgB,UAAU,CAAC,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,CAoE1G;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CA8D1E"}
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
6
6
|
import { renderRepoLocalCliCommands } from './core/cli-fallback.js';
|
|
7
7
|
import { captureRepoSnapshot, clearPendingCommit, commitPendingChanges, writePendingCommit } from './core/git.js';
|
|
8
8
|
import { writeDerivedDocs } from './core/docs.js';
|
|
9
|
-
import { bootstrapHolistic, initializeHolistic, refreshHolisticHooks, repairHolistic } from './core/setup.js';
|
|
9
|
+
import { bootstrapHolistic, getSetupStatus, initializeHolistic, refreshHolisticHooks, repairHolistic } from './core/setup.js';
|
|
10
10
|
import { printSplash, printSplashError, renderSplash } from './core/splash.js';
|
|
11
11
|
import { requestAutoSync } from './core/sync.js';
|
|
12
12
|
import { runDaemonTick } from './daemon.js';
|
|
@@ -73,14 +73,15 @@ export function renderHelpText() {
|
|
|
73
73
|
|
|
74
74
|
Usage:
|
|
75
75
|
holistic init [--install-daemon] [--install-hooks] [--platform win32|darwin|linux] [--interval 30] [--remote origin] [--state-ref refs/holistic/state] [--state-branch holistic/state]
|
|
76
|
-
holistic bootstrap [--platform win32|darwin|linux] [--interval 30] [--
|
|
76
|
+
holistic bootstrap [--platform win32|darwin|linux] [--interval 30] [--yes]
|
|
77
|
+
holistic doctor
|
|
77
78
|
holistic repair [--platform win32|darwin|linux] [--refresh-hooks false] [--install-daemon true] [--configure-mcp true]
|
|
78
79
|
holistic start [--agent codex|claude|antigravity|gemini|copilot|cursor|goose|gsd|gsd2] [--continue] [--json]
|
|
79
80
|
holistic resume [--agent codex|claude|antigravity|gemini|copilot|cursor|goose|gsd|gsd2] [--continue] [--json]
|
|
80
|
-
holistic checkpoint --reason "<reason>" [--
|
|
81
|
+
holistic checkpoint --reason "<reason>" [--status "<status>"] [--plan "<step>"]... [--completion-kind natural-breakpoint|task-complete|slice-complete|milestone-complete] [--completion-source agent|system] [--completion-recorded-at <iso8601>]
|
|
81
82
|
holistic checkpoint --fixed "<bug>" [--fix-files "<file>"] [--fix-risk "<what reintroduces it>"]
|
|
82
|
-
holistic handoff [--draft] [--summary "<summary>"] [--next "<step>"]...
|
|
83
|
-
holistic start-new --goal "<goal>" [--title "<title>"] [--plan "<step>"]...
|
|
83
|
+
holistic handoff [--draft] [--summary "<summary>"] [--next "<step>"]... [--commit]
|
|
84
|
+
holistic start-new [--goal "<goal>"] [--title "<title>"] [--plan "<step>"]...
|
|
84
85
|
holistic status
|
|
85
86
|
holistic diff --from "<session-id>" --to "<session-id>" [--format text|json]
|
|
86
87
|
holistic search --id "<session-id>" [--format text|json]
|
|
@@ -245,10 +246,12 @@ export function renderDiff(fromSession, toSession, diff) {
|
|
|
245
246
|
}
|
|
246
247
|
return lines.join("\n") + "\n";
|
|
247
248
|
}
|
|
248
|
-
export function renderStatus(state) {
|
|
249
|
+
export function renderStatus(rootDir, state) {
|
|
249
250
|
const lines = [];
|
|
250
251
|
lines.push("Holistic Status");
|
|
251
252
|
lines.push("");
|
|
253
|
+
lines.push(renderSyncStatus(rootDir));
|
|
254
|
+
lines.push("");
|
|
252
255
|
if (!state.activeSession) {
|
|
253
256
|
lines.push("No active session.");
|
|
254
257
|
if (state.lastHandoff) {
|
|
@@ -256,7 +259,7 @@ export function renderStatus(state) {
|
|
|
256
259
|
lines.push(`Last handoff: ${state.lastHandoff.summary}`);
|
|
257
260
|
lines.push(`Next action: ${state.lastHandoff.nextAction}`);
|
|
258
261
|
}
|
|
259
|
-
if (state.pendingWork.length > 0) {
|
|
262
|
+
if (state.pendingWork && state.pendingWork.length > 0) {
|
|
260
263
|
lines.push("");
|
|
261
264
|
lines.push(`Pending work: ${state.pendingWork.length} item(s)`);
|
|
262
265
|
for (const item of state.pendingWork.slice(0, 3)) {
|
|
@@ -341,12 +344,27 @@ Repo-local CLI: ${initFallback}
|
|
|
341
344
|
return 0;
|
|
342
345
|
}
|
|
343
346
|
async function handleBootstrap(rootDir, parsed) {
|
|
344
|
-
printSplash({
|
|
345
|
-
message: "bootstrapping holistic on this machine...",
|
|
346
|
-
});
|
|
347
347
|
const platformFlag = firstFlag(parsed.flags, "platform", process.platform);
|
|
348
348
|
const platform = platformFlag === "windows" ? "win32" : platformFlag === "macos" ? "darwin" : platformFlag === "linux" ? "linux" : platformFlag;
|
|
349
349
|
const intervalSeconds = Number.parseInt(firstFlag(parsed.flags, "interval", "30"), 10);
|
|
350
|
+
const confirmed = firstFlag(parsed.flags, "yes") === "true";
|
|
351
|
+
const status = getSetupStatus(rootDir, {
|
|
352
|
+
platform: platform,
|
|
353
|
+
intervalSeconds,
|
|
354
|
+
});
|
|
355
|
+
const pending = status.filter(s => s.status !== "ok");
|
|
356
|
+
if (pending.length > 0 && !confirmed) {
|
|
357
|
+
printSplash({
|
|
358
|
+
message: "bootstrap pre-flight: pending actions",
|
|
359
|
+
});
|
|
360
|
+
process.stdout.write("\nHolistic needs to make the following changes to your system:\n\n");
|
|
361
|
+
printSetupStatusTable(status);
|
|
362
|
+
process.stdout.write("\nRun with --yes to apply these changes.\n");
|
|
363
|
+
return 1;
|
|
364
|
+
}
|
|
365
|
+
printSplash({
|
|
366
|
+
message: "bootstrapping holistic on this machine...",
|
|
367
|
+
});
|
|
350
368
|
const result = bootstrapHolistic(rootDir, {
|
|
351
369
|
installDaemon: firstFlag(parsed.flags, "install-daemon", "true") !== "false",
|
|
352
370
|
installGitHooks: firstFlag(parsed.flags, "install-hooks", "true") !== "false",
|
|
@@ -382,9 +400,37 @@ Git hooks: ${result.gitHooksInstalled ? result.gitHooks.join(", ") : "not instal
|
|
|
382
400
|
MCP config: ${result.mcpConfigured ? result.mcpConfigFile : "skipped"}
|
|
383
401
|
Checks: ${result.checks.join(", ")}
|
|
384
402
|
Repo-local CLI: ${bootstrapFallback}
|
|
403
|
+
|
|
404
|
+
[TIP] To enable remote syncing (Portable State), set "portableState": true in .holistic/config.json
|
|
385
405
|
`);
|
|
386
406
|
return 0;
|
|
387
407
|
}
|
|
408
|
+
async function handleDoctor(rootDir, parsed) {
|
|
409
|
+
printSplash({
|
|
410
|
+
message: "running holistic health check...",
|
|
411
|
+
});
|
|
412
|
+
const status = getSetupStatus(rootDir);
|
|
413
|
+
process.stdout.write("\nSystem Configuration:\n\n");
|
|
414
|
+
printSetupStatusTable(status);
|
|
415
|
+
process.stdout.write("\nSync Diagnostics:\n\n");
|
|
416
|
+
process.stdout.write(renderSyncStatus(rootDir));
|
|
417
|
+
const healthy = status.every(s => s.status === "ok");
|
|
418
|
+
if (healthy) {
|
|
419
|
+
process.stdout.write("\n\u2713 Holistic is healthy and correctly configured on this machine.\n");
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
process.stdout.write("\n\u26A0 Some components require attention. Run 'holistic bootstrap' to fix.\n");
|
|
423
|
+
}
|
|
424
|
+
return 0;
|
|
425
|
+
}
|
|
426
|
+
function printSetupStatusTable(status) {
|
|
427
|
+
for (const s of status) {
|
|
428
|
+
const icon = s.status === "ok" ? "\u2713" : s.status === "missing" ? "\u25CB" : s.status === "outdated" ? "\u21BB" : s.status === "info" ? "\u2139" : "!";
|
|
429
|
+
const label = `${icon} ${s.component.padEnd(20)}`;
|
|
430
|
+
process.stdout.write(`${label} | ${s.status.padEnd(10)} | ${s.details}\n`);
|
|
431
|
+
process.stdout.write(` ${s.description}\n\n`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
388
434
|
async function handleRepair(rootDir, parsed) {
|
|
389
435
|
printSplash({
|
|
390
436
|
message: "repairing holistic machine-local helpers...",
|
|
@@ -515,23 +561,16 @@ async function handleCheckpoint(rootDir, parsed) {
|
|
|
515
561
|
async function handleStartNew(rootDir, parsed) {
|
|
516
562
|
refreshHooksBeforeCommand(rootDir);
|
|
517
563
|
const agent = asAgent(firstFlag(parsed.flags, "agent", "unknown"));
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (!mutateResult.success || !mutateResult.state) {
|
|
526
|
-
process.stderr.write(`Error: Failed to start session: ${mutateResult.error}\n`);
|
|
527
|
-
return 1;
|
|
528
|
-
}
|
|
529
|
-
process.stdout.write(`Started ${mutateResult.state.activeSession?.id} for goal: ${mutateResult.state.activeSession?.currentGoal}\n`);
|
|
530
|
-
return 0;
|
|
531
|
-
}
|
|
532
|
-
finally {
|
|
533
|
-
rl.close();
|
|
564
|
+
const goal = firstFlag(parsed.flags, "goal");
|
|
565
|
+
const title = firstFlag(parsed.flags, "title");
|
|
566
|
+
const plan = listFlag(parsed.flags, "plan");
|
|
567
|
+
const mutateResult = mutateState(rootDir, (state) => startNewSession(rootDir, state, agent, goal, plan, title));
|
|
568
|
+
if (!mutateResult.success || !mutateResult.state) {
|
|
569
|
+
process.stderr.write(`Error: Failed to start session: ${mutateResult.error}\n`);
|
|
570
|
+
return 1;
|
|
534
571
|
}
|
|
572
|
+
process.stdout.write(`Started ${mutateResult.state.activeSession?.id} for goal: ${mutateResult.state.activeSession?.currentGoal}\n`);
|
|
573
|
+
return 0;
|
|
535
574
|
}
|
|
536
575
|
async function handleHandoff(rootDir, parsed) {
|
|
537
576
|
refreshHooksBeforeCommand(rootDir);
|
|
@@ -610,22 +649,33 @@ async function handleHandoff(rootDir, parsed) {
|
|
|
610
649
|
process.exit(1);
|
|
611
650
|
}
|
|
612
651
|
const nextState = mutateResult.state;
|
|
652
|
+
const shouldCommit = firstFlag(parsed.flags, "commit") === "true";
|
|
613
653
|
let commitResult = null;
|
|
614
|
-
if (nextState.pendingCommit) {
|
|
654
|
+
if (nextState.pendingCommit && shouldCommit) {
|
|
615
655
|
commitResult = commitPendingChanges(rootDir, nextState.pendingCommit.message, nextState.pendingCommit.files);
|
|
616
656
|
if (commitResult.success) {
|
|
617
|
-
|
|
657
|
+
mutateState(rootDir, (latestState, paths) => {
|
|
618
658
|
clearPendingCommit(paths);
|
|
619
659
|
return {
|
|
620
660
|
...latestState,
|
|
621
661
|
pendingCommit: null,
|
|
622
662
|
};
|
|
623
663
|
});
|
|
624
|
-
if (!clearResult.success) {
|
|
625
|
-
process.stderr.write(`Warning: Failed to clear pending commit state: ${clearResult.error}\n`);
|
|
626
|
-
}
|
|
627
664
|
}
|
|
628
665
|
}
|
|
666
|
+
if (nextState.pendingCommit && !shouldCommit) {
|
|
667
|
+
process.stdout.write(`
|
|
668
|
+
Handoff prepared successfully!
|
|
669
|
+
Docs updated: ${nextState.pendingCommit.files.join(", ")}
|
|
670
|
+
|
|
671
|
+
To complete the handoff, review your changes and commit:
|
|
672
|
+
git add .
|
|
673
|
+
git commit -F .holistic/context/pending-commit.txt
|
|
674
|
+
|
|
675
|
+
Use 'holistic handoff --commit' next time to automate this step safely.
|
|
676
|
+
`);
|
|
677
|
+
return 0;
|
|
678
|
+
}
|
|
629
679
|
process.stdout.write(`Handoff complete.\nSummary: ${nextState.lastHandoff?.summary ?? "n/a"}\n`);
|
|
630
680
|
if (commitResult) {
|
|
631
681
|
if (commitResult.success) {
|
|
@@ -686,9 +736,7 @@ function renderSyncStatus(rootDir) {
|
|
|
686
736
|
async function handleStatus(rootDir) {
|
|
687
737
|
refreshHooksBeforeCommand(rootDir);
|
|
688
738
|
const { state } = loadState(rootDir);
|
|
689
|
-
process.stdout.write(renderStatus(state));
|
|
690
|
-
process.stdout.write("\n");
|
|
691
|
-
process.stdout.write(renderSyncStatus(rootDir));
|
|
739
|
+
process.stdout.write(renderStatus(rootDir, state));
|
|
692
740
|
return 0;
|
|
693
741
|
}
|
|
694
742
|
async function handleDiff(rootDir, parsed) {
|
|
@@ -822,6 +870,8 @@ async function main() {
|
|
|
822
870
|
return handleInit(rootDir, parsed);
|
|
823
871
|
case "bootstrap":
|
|
824
872
|
return handleBootstrap(rootDir, parsed);
|
|
873
|
+
case "doctor":
|
|
874
|
+
return handleDoctor(rootDir, parsed);
|
|
825
875
|
case "repair":
|
|
826
876
|
return handleRepair(rootDir, parsed);
|
|
827
877
|
case "start":
|