holistic 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -1
- package/README.md +81 -21
- package/bin/holistic +10 -17
- package/bin/holistic.cmd +3 -24
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +114 -39
- 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-hooks.d.ts +1 -0
- package/dist/core/git-hooks.d.ts.map +1 -1
- package/dist/core/git-hooks.js +52 -0
- package/dist/core/git-hooks.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 +10 -0
- package/dist/core/setup.d.ts.map +1 -1
- package/dist/core/setup.js +166 -19
- 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 +1 -1
- package/dist/core/sync.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +8 -5
- package/dist/mcp-server.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 - 2026-04-11
|
|
4
|
+
|
|
5
|
+
Comprehensive Reliability & UX Refinement (M005). This release finalizes the security hardening milestone, introduces granular bootstrap controls, and adds support for explicit portable-state management.
|
|
6
|
+
|
|
7
|
+
- Added **Granular Bootstrap Flags**: Users can now surgically enable setup items with `--yes-hooks`, `--yes-daemon`, `--yes-mcp`, `--yes-attr`, and `--yes-claude`.
|
|
8
|
+
- Added `--portable` flag to `init` and `bootstrap` to explicitly toggle **Portable State (Privacy Mode)** during setup.
|
|
9
|
+
- Refined **Bootstrap Pre-flight UX**: The pre-flight check now clearly differentiates between "Core Configuration" (covered by `--yes`) and "Optional/Explicit" items.
|
|
10
|
+
- Fixed **Runtime Script Resolution**: Resolved a critical production bug where the CLI incorrectly searched for `.ts` files in built environments; now correctly resolves `.js` files when TypeScript stripping is unavailable.
|
|
11
|
+
- Hardened **Read-Only Diagnostics**: Refactored `holistic doctor` and `getSetupStatus` to be strictly read-only, ensuring health checks never inadvertently modify Git hooks or repository state.
|
|
12
|
+
- Improved **MCP Server Transparency**: Sanitized startup logging to prevent context leakage in system logs while maintaining full context availability via the `holistic_resume` tool.
|
|
13
|
+
- Aligned **Claude Code Hook Detection**: Fixed a bug where `holistic doctor` misreported Claude hook status by incorrectly checking the filesystem instead of `settings.json`.
|
|
14
|
+
|
|
15
|
+
## 0.5.5 - 2026-04-10
|
|
16
|
+
|
|
17
|
+
Major Security & Trust Hardening (M005) to eliminate silent automation and improve auditability.
|
|
18
|
+
|
|
19
|
+
- 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.
|
|
20
|
+
- Added `holistic doctor` command for repository setup diagnostics and background sync health monitoring.
|
|
21
|
+
- 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.
|
|
22
|
+
- 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`.
|
|
23
|
+
- Hardened **Git-Native Snapshotting**: Refactored repo snapshotting to use `git ls-files`, ensuring $O(\text{changes})$ performance and native `.gitignore` compliance.
|
|
24
|
+
- 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.
|
|
25
|
+
|
|
3
26
|
## 0.5.4 - 2026-04-09
|
|
4
27
|
|
|
5
|
-
Security hardening in response to
|
|
28
|
+
Security hardening in response to socket.dev AI-based package scanner flags.
|
|
6
29
|
|
|
7
30
|
- 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.
|
|
8
31
|
- 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.
|
package/README.md
CHANGED
|
@@ -12,12 +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
|
|
|
24
|
+
|
|
19
25
|
---
|
|
20
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
|
+
|
|
21
41
|
## Get started in 30 seconds ⚡
|
|
22
42
|
|
|
23
43
|
Open your project repo in PowerShell, Terminal, Command Prompt, or whatever shell you normally use.
|
|
@@ -28,7 +48,7 @@ Run these two commands:
|
|
|
28
48
|
|
|
29
49
|
```bash
|
|
30
50
|
npm install -g holistic
|
|
31
|
-
holistic bootstrap
|
|
51
|
+
holistic bootstrap --yes
|
|
32
52
|
```
|
|
33
53
|
|
|
34
54
|
After that, open the repo in your agent app and use this startup prompt:
|
|
@@ -41,8 +61,10 @@ That is enough to get the basic Holistic workflow working.
|
|
|
41
61
|
|
|
42
62
|
If you want the fuller install and setup details, jump to [Quick start](#quick-start-).
|
|
43
63
|
|
|
64
|
+
|
|
44
65
|
---
|
|
45
66
|
|
|
67
|
+
|
|
46
68
|
## The problem 😵
|
|
47
69
|
|
|
48
70
|
If you use more than one AI coding assistant, the workflow usually falls apart:
|
|
@@ -55,8 +77,10 @@ If you use more than one AI coding assistant, the workflow usually falls apart:
|
|
|
55
77
|
|
|
56
78
|
Holistic fixes that by making the repo the source of truth.
|
|
57
79
|
|
|
80
|
+
|
|
58
81
|
---
|
|
59
82
|
|
|
83
|
+
|
|
60
84
|
## What it feels like with HOLISTIC 🌿
|
|
61
85
|
|
|
62
86
|
Run one setup command on a machine:
|
|
@@ -76,8 +100,10 @@ Most days, you do not need to keep a terminal process open or manually re-brief
|
|
|
76
100
|
|
|
77
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.
|
|
78
102
|
|
|
103
|
+
|
|
79
104
|
---
|
|
80
105
|
|
|
106
|
+
|
|
81
107
|
## How it works 🧭
|
|
82
108
|
|
|
83
109
|
```text
|
|
@@ -96,8 +122,10 @@ Holistic checkpoints and handoffs keep repo memory current
|
|
|
96
122
|
The next agent picks up without a long re-explanation
|
|
97
123
|
```
|
|
98
124
|
|
|
125
|
+
|
|
99
126
|
---
|
|
100
127
|
|
|
128
|
+
|
|
101
129
|
## Quick start 🚀
|
|
102
130
|
|
|
103
131
|
### Install 📦
|
|
@@ -136,7 +164,7 @@ npm link
|
|
|
136
164
|
|
|
137
165
|
```bash
|
|
138
166
|
cd my-project
|
|
139
|
-
holistic bootstrap --remote origin
|
|
167
|
+
holistic bootstrap --remote origin --yes
|
|
140
168
|
git add .gitattributes HOLISTIC.md AGENTS.md CLAUDE.md GEMINI.md
|
|
141
169
|
git add .holistic/config.json .holistic/state.json
|
|
142
170
|
git add .holistic/context/
|
|
@@ -150,12 +178,14 @@ Advanced overrides:
|
|
|
150
178
|
```bash
|
|
151
179
|
holistic bootstrap --state-ref refs/holistic/state
|
|
152
180
|
holistic bootstrap --state-branch holistic/state
|
|
181
|
+
holistic bootstrap --portable
|
|
153
182
|
```
|
|
154
183
|
|
|
155
|
-
If you want repo scaffolding without changing local desktop integrations or daemon startup on the current machine, use:
|
|
184
|
+
If you want repo scaffolding without changing local desktop integrations or daemon startup on the current machine, you can use granular flags to be surgical:
|
|
156
185
|
|
|
157
186
|
```bash
|
|
158
|
-
|
|
187
|
+
# Only install Git hooks and managed attributes
|
|
188
|
+
holistic bootstrap --yes-hooks --yes-attr
|
|
159
189
|
```
|
|
160
190
|
|
|
161
191
|
**What to commit:**
|
|
@@ -170,15 +200,17 @@ holistic bootstrap --install-daemon false --configure-mcp false
|
|
|
170
200
|
|
|
171
201
|
The portable repo memory is meant to be committed and synced. Machine-local helper scripts are generated for each machine and stay local.
|
|
172
202
|
|
|
203
|
+
|
|
173
204
|
---
|
|
174
205
|
|
|
206
|
+
|
|
175
207
|
## Daily workflow 🔄
|
|
176
208
|
|
|
177
209
|
One-time machine setup:
|
|
178
210
|
|
|
179
211
|
- Run `holistic bootstrap`.
|
|
180
212
|
- By default it scaffolds repo files, installs hooks, sets up daemon startup, and configures supported integrations such as Claude Desktop MCP on the current machine.
|
|
181
|
-
-
|
|
213
|
+
- To be surgical about what is applied, use granular flags like `--yes-hooks`, `--yes-daemon`, or `--yes-mcp`.
|
|
182
214
|
|
|
183
215
|
Normal use:
|
|
184
216
|
|
|
@@ -200,8 +232,10 @@ If `holistic` is not on `PATH` in a given shell, every bootstrapped repo also ha
|
|
|
200
232
|
- Windows: `.\.holistic\system\holistic.cmd <command>`
|
|
201
233
|
- macOS/Linux: `./.holistic/system/holistic <command>`
|
|
202
234
|
|
|
235
|
+
|
|
203
236
|
---
|
|
204
237
|
|
|
238
|
+
|
|
205
239
|
## Regression protection 🛡️
|
|
206
240
|
|
|
207
241
|
When an agent fixes something delicate, lock it in:
|
|
@@ -215,8 +249,10 @@ holistic checkpoint \
|
|
|
215
249
|
|
|
216
250
|
Future agents will see that warning in the repo docs before they touch the risky area again.
|
|
217
251
|
|
|
252
|
+
|
|
218
253
|
---
|
|
219
254
|
|
|
255
|
+
|
|
220
256
|
## Works with multiple agent apps 🤝
|
|
221
257
|
|
|
222
258
|
Holistic is model-agnostic. It works through repo files first, and can expose a thin MCP server where supported.
|
|
@@ -238,8 +274,10 @@ Use this table to decide whether startup should be automatic (MCP/tooling hook)
|
|
|
238
274
|
| Other VS Code forks | `AGENTS.md` and repo docs | ❌ No | Treat as manual-start and run `/holistic` |
|
|
239
275
|
| Web tools | repo docs pasted manually | ❌ No | Manual copy/paste recap from Holistic docs |
|
|
240
276
|
|
|
277
|
+
|
|
241
278
|
---
|
|
242
279
|
|
|
280
|
+
|
|
243
281
|
## What lives in your repo 🗂️
|
|
244
282
|
|
|
245
283
|
```text
|
|
@@ -265,23 +303,24 @@ my-project/
|
|
|
265
303
|
|
|
266
304
|
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`).
|
|
267
305
|
|
|
306
|
+
|
|
268
307
|
---
|
|
269
308
|
|
|
309
|
+
|
|
270
310
|
## Commands
|
|
271
311
|
|
|
272
|
-
| Command | What it does |
|
|
273
|
-
|---|---|
|
|
274
312
|
| `holistic init` | Base repo setup and scaffolding |
|
|
275
|
-
| `holistic bootstrap` | One-step machine setup for
|
|
276
|
-
| `holistic
|
|
277
|
-
| `holistic
|
|
278
|
-
| `holistic start
|
|
313
|
+
| `holistic bootstrap` | One-step machine setup. Required `--yes` for Core Setup, or granular `--yes-*` flags. |
|
|
314
|
+
| `holistic doctor` | Runs health checks on machine setup and sync logs |
|
|
315
|
+
| `holistic repair` | Regenerates `.holistic/system/` helpers |
|
|
316
|
+
| `holistic resume / start --agent <name>` | Loads project recap and prints state |
|
|
317
|
+
| `holistic start-new` | Starts a fresh session |
|
|
279
318
|
| `holistic checkpoint --reason "..."` | Saves progress and context |
|
|
280
|
-
| `holistic handoff` | Ends a session with a handoff |
|
|
281
|
-
| `holistic status` | Shows
|
|
319
|
+
| `holistic handoff` | Ends a session with a handoff message |
|
|
320
|
+
| `holistic status` | Shows current state and recent sync activity |
|
|
282
321
|
| `holistic diff --from <id> --to <id>` | Compares two sessions |
|
|
283
|
-
| `holistic search --id <session-id>` | Finds and reactivates an archived session
|
|
284
|
-
| `holistic serve` | Runs the thin MCP server
|
|
322
|
+
| `holistic search --id <session-id>` | Finds and reactivates an archived session |
|
|
323
|
+
| `holistic serve` | Runs the thin MCP server |
|
|
285
324
|
| `holistic watch` | Foreground daemon mode for automatic checkpoints |
|
|
286
325
|
|
|
287
326
|
### Slash command helper text (agent-facing)
|
|
@@ -302,8 +341,10 @@ holistic handoff \
|
|
|
302
341
|
--blocker "Need refresh token endpoint from backend team"
|
|
303
342
|
```
|
|
304
343
|
|
|
344
|
+
|
|
305
345
|
---
|
|
306
346
|
|
|
347
|
+
|
|
307
348
|
## Architecture
|
|
308
349
|
|
|
309
350
|
Holistic is intentionally repo-first, not machine-first.
|
|
@@ -342,8 +383,10 @@ When you do run `holistic serve` manually in a terminal, Holistic prints its ASC
|
|
|
342
383
|
}
|
|
343
384
|
```
|
|
344
385
|
|
|
386
|
+
|
|
345
387
|
---
|
|
346
388
|
|
|
389
|
+
|
|
347
390
|
## Why this matters
|
|
348
391
|
|
|
349
392
|
If you are already using more than one AI coding assistant, you already have the continuity problem.
|
|
@@ -356,35 +399,50 @@ Holistic gives you:
|
|
|
356
399
|
- A durable record of what changed and why
|
|
357
400
|
- Agents that can get to work quickly
|
|
358
401
|
|
|
402
|
+
|
|
359
403
|
---
|
|
360
404
|
|
|
405
|
+
|
|
361
406
|
## Beta Feedback Welcome 🙏
|
|
362
407
|
|
|
363
408
|
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.
|
|
364
409
|
|
|
365
410
|
For support and troubleshooting, see [SUPPORT.md](./SUPPORT.md).
|
|
366
411
|
|
|
412
|
+
|
|
367
413
|
---
|
|
368
414
|
|
|
369
|
-
## Security & Privacy 🔒
|
|
370
415
|
|
|
371
|
-
|
|
416
|
+
## Security, Privacy, and Trust 🔒
|
|
417
|
+
|
|
418
|
+
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.
|
|
372
419
|
|
|
373
|
-
|
|
420
|
+
### Trust Architecture:
|
|
421
|
+
- **Granular Consent**: `holistic bootstrap` now uses a "Consent-First" model. It displays a summary of system-modifying actions and requires an explicit `--yes` for the Core Setup (hooks, daemon, MCP, attributes).
|
|
422
|
+
- **Surgical Control**: Use granular flags (`--yes-hooks`, `--yes-daemon`, `--yes-mcp`, `--yes-attr`, `--yes-claude`) to apply only the specific integrations you want.
|
|
423
|
+
- **Privacy Mode vs. Portable Mode**: Holistic defaults to **Privacy Mode** (local-only state). To enable cross-device sync, use the `--portable` flag or set `"portableState": true` in the repo config.
|
|
424
|
+
- **Read-Only Diagnostics**: The `holistic doctor` command and bootstrap pre-flight checks are strictly non-mutating. They audit your environment without making unexpected changes.
|
|
425
|
+
- **Traceable Activity**: Background sync operations (PowerShell/Bash) are visible and logged with timestamps to `.holistic/system/sync.log`.
|
|
426
|
+
- **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})$.
|
|
427
|
+
- **Zero Shell Injection**: Internal commit logic has been stripped of shell wrappers to eliminate command injection risks.
|
|
428
|
+
|
|
429
|
+
### What it does:
|
|
374
430
|
- Writes session state into `.holistic/` inside your repo (committed files you control)
|
|
375
431
|
- Installs a daemon via standard OS autostart (Windows Startup folder, macOS LaunchAgents, Linux systemd user)
|
|
376
432
|
- Can push Holistic state to a hidden git ref on your configured remote (opt-in, your repo only)
|
|
377
433
|
|
|
378
|
-
|
|
434
|
+
### What it does NOT do:
|
|
379
435
|
- Does not read or transmit file contents outside your repo
|
|
380
436
|
- Does not access credentials or tokens
|
|
381
437
|
- Does not phone home to any external service
|
|
382
|
-
- Does not use
|
|
438
|
+
- Does not use obfuscated scripts or hidden windows
|
|
439
|
+
|
|
440
|
+
For the full technical disclosure, see [SECURITY.md](./SECURITY.md).
|
|
383
441
|
|
|
384
|
-
For the full disclosure, see [SECURITY.md](./SECURITY.md).
|
|
385
442
|
|
|
386
443
|
---
|
|
387
444
|
|
|
445
|
+
|
|
388
446
|
## Quick links
|
|
389
447
|
|
|
390
448
|
- [Walkthrough](./docs/handoff-walkthrough.md)
|
|
@@ -394,6 +452,8 @@ For the full disclosure, see [SECURITY.md](./SECURITY.md).
|
|
|
394
452
|
- [License](./LICENSE)
|
|
395
453
|
|
|
396
454
|
|
|
455
|
+
|
|
397
456
|
---
|
|
398
457
|
|
|
458
|
+
|
|
399
459
|
<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
|
@@ -3,27 +3,6 @@ setlocal
|
|
|
3
3
|
set SCRIPT_DIR=%~dp0
|
|
4
4
|
node --experimental-strip-types "%SCRIPT_DIR%..\src\cli.ts" %*
|
|
5
5
|
if errorlevel 1 exit /b %errorlevel%
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
set /p COMMIT_MSG=<"%PENDING_FILE%"
|
|
10
|
-
if defined COMMIT_MSG (
|
|
11
|
-
rem Sanitize COMMIT_MSG: strip characters that can break cmd.exe argument quoting
|
|
12
|
-
set COMMIT_MSG=%COMMIT_MSG:&= %
|
|
13
|
-
set COMMIT_MSG=%COMMIT_MSG:|= %
|
|
14
|
-
set COMMIT_MSG=%COMMIT_MSG:>= %
|
|
15
|
-
set COMMIT_MSG=%COMMIT_MSG:<= %
|
|
16
|
-
set COMMIT_MSG=%COMMIT_MSG:"=%
|
|
17
|
-
git add -- HOLISTIC.md AGENTS.md .holistic
|
|
18
|
-
if not errorlevel 1 (
|
|
19
|
-
git commit -m "%COMMIT_MSG%"
|
|
20
|
-
if not errorlevel 1 (
|
|
21
|
-
if exist "%CD%\.holistic\system\sync-state.ps1" (
|
|
22
|
-
powershell -NoProfile -ExecutionPolicy RemoteSigned -File "%CD%\.holistic\system\sync-state.ps1"
|
|
23
|
-
)
|
|
24
|
-
node --experimental-strip-types "%SCRIPT_DIR%..\src\cli.ts" internal-mark-commit --message "%COMMIT_MSG%"
|
|
25
|
-
)
|
|
26
|
-
)
|
|
27
|
-
)
|
|
28
|
-
)
|
|
29
|
-
)
|
|
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]
|
|
@@ -134,7 +135,7 @@ function runtimeScript(name) {
|
|
|
134
135
|
const runtimeDir = path.dirname(currentFile);
|
|
135
136
|
const useStripTypes = extension === ".ts";
|
|
136
137
|
return {
|
|
137
|
-
scriptPath: path.resolve(runtimeDir, `${name}${useStripTypes ? ".ts" : ".
|
|
138
|
+
scriptPath: path.resolve(runtimeDir, `${name}${useStripTypes ? ".ts" : ".js"}`),
|
|
138
139
|
useStripTypes,
|
|
139
140
|
};
|
|
140
141
|
}
|
|
@@ -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)) {
|
|
@@ -304,14 +307,17 @@ async function handleInit(rootDir, parsed) {
|
|
|
304
307
|
const platformFlag = firstFlag(parsed.flags, "platform", process.platform);
|
|
305
308
|
const platform = platformFlag === "windows" ? "win32" : platformFlag === "macos" ? "darwin" : platformFlag === "linux" ? "linux" : platformFlag;
|
|
306
309
|
const intervalSeconds = Number.parseInt(firstFlag(parsed.flags, "interval", "30"), 10);
|
|
310
|
+
const portableState = firstFlag(parsed.flags, "portable") === "true" ? true : firstFlag(parsed.flags, "portable") === "false" ? false : undefined;
|
|
307
311
|
const result = initializeHolistic(rootDir, {
|
|
308
|
-
installDaemon: firstFlag(parsed.flags, "
|
|
309
|
-
installGitHooks: firstFlag(parsed.flags, "
|
|
312
|
+
installDaemon: firstFlag(parsed.flags, "yes-daemon") === "true",
|
|
313
|
+
installGitHooks: firstFlag(parsed.flags, "yes-hooks") === "true",
|
|
314
|
+
installGitAttributes: firstFlag(parsed.flags, "yes-attr", "true") !== "false",
|
|
310
315
|
platform: platform,
|
|
311
316
|
intervalSeconds,
|
|
312
317
|
remote: firstFlag(parsed.flags, "remote", "origin"),
|
|
313
318
|
stateRef: firstFlag(parsed.flags, "state-ref"),
|
|
314
319
|
stateBranch: firstFlag(parsed.flags, "state-branch"),
|
|
320
|
+
portableState,
|
|
315
321
|
});
|
|
316
322
|
reportHookWarnings(result.gitHookWarnings);
|
|
317
323
|
const statusItems = [];
|
|
@@ -341,16 +347,46 @@ Repo-local CLI: ${initFallback}
|
|
|
341
347
|
return 0;
|
|
342
348
|
}
|
|
343
349
|
async function handleBootstrap(rootDir, parsed) {
|
|
344
|
-
printSplash({
|
|
345
|
-
message: "bootstrapping holistic on this machine...",
|
|
346
|
-
});
|
|
347
350
|
const platformFlag = firstFlag(parsed.flags, "platform", process.platform);
|
|
348
351
|
const platform = platformFlag === "windows" ? "win32" : platformFlag === "macos" ? "darwin" : platformFlag === "linux" ? "linux" : platformFlag;
|
|
349
352
|
const intervalSeconds = Number.parseInt(firstFlag(parsed.flags, "interval", "30"), 10);
|
|
353
|
+
const confirmed = firstFlag(parsed.flags, "yes") === "true";
|
|
354
|
+
const status = getSetupStatus(rootDir, {
|
|
355
|
+
platform: platform,
|
|
356
|
+
intervalSeconds,
|
|
357
|
+
});
|
|
358
|
+
const pending = status.filter(s => s.status !== "ok");
|
|
359
|
+
if (pending.length > 0 && !confirmed) {
|
|
360
|
+
printSplash({
|
|
361
|
+
message: "bootstrap pre-flight: pending actions",
|
|
362
|
+
});
|
|
363
|
+
process.stdout.write("\nHolistic needs to make the following changes to your system (some outside this repo):\n\n");
|
|
364
|
+
printSetupStatusTable(status);
|
|
365
|
+
process.stdout.write("\nRun with --yes to apply the Core Configuration:\n");
|
|
366
|
+
process.stdout.write(" ✓ Git hooks, Background daemon, MCP config, Git attributes\n");
|
|
367
|
+
process.stdout.write("\nOptional / Explicit flags:\n");
|
|
368
|
+
process.stdout.write(" --yes-claude Install Claude Code SessionStart hooks\n");
|
|
369
|
+
process.stdout.write(" --portable Enable Portable State (remote-sync via git ref)\n");
|
|
370
|
+
process.stdout.write("\nGranular overrides:\n");
|
|
371
|
+
process.stdout.write(" --yes-hooks, --yes-daemon, --yes-mcp, --yes-attr\n");
|
|
372
|
+
return 1;
|
|
373
|
+
}
|
|
374
|
+
printSplash({
|
|
375
|
+
message: "bootstrapping holistic on this machine...",
|
|
376
|
+
});
|
|
377
|
+
const installDaemon = firstFlag(parsed.flags, "yes-daemon") === "true" || (confirmed && firstFlag(parsed.flags, "install-daemon", "true") !== "false");
|
|
378
|
+
const installGitHooks = firstFlag(parsed.flags, "yes-hooks") === "true" || (confirmed && firstFlag(parsed.flags, "install-hooks", "true") !== "false");
|
|
379
|
+
const configureMcp = firstFlag(parsed.flags, "yes-mcp") === "true" || (confirmed && firstFlag(parsed.flags, "configure-mcp", "true") !== "false");
|
|
380
|
+
const installGitAttributes = firstFlag(parsed.flags, "yes-attr") === "true" || confirmed;
|
|
381
|
+
const installClaudeHooks = firstFlag(parsed.flags, "yes-claude") === "true";
|
|
382
|
+
const portableState = firstFlag(parsed.flags, "portable") === "true" ? true : firstFlag(parsed.flags, "portable") === "false" ? false : undefined;
|
|
350
383
|
const result = bootstrapHolistic(rootDir, {
|
|
351
|
-
installDaemon
|
|
352
|
-
installGitHooks
|
|
353
|
-
|
|
384
|
+
installDaemon,
|
|
385
|
+
installGitHooks,
|
|
386
|
+
installGitAttributes,
|
|
387
|
+
installClaudeHooks,
|
|
388
|
+
configureMcp,
|
|
389
|
+
portableState,
|
|
354
390
|
platform: platform,
|
|
355
391
|
intervalSeconds,
|
|
356
392
|
remote: firstFlag(parsed.flags, "remote", "origin"),
|
|
@@ -382,9 +418,37 @@ Git hooks: ${result.gitHooksInstalled ? result.gitHooks.join(", ") : "not instal
|
|
|
382
418
|
MCP config: ${result.mcpConfigured ? result.mcpConfigFile : "skipped"}
|
|
383
419
|
Checks: ${result.checks.join(", ")}
|
|
384
420
|
Repo-local CLI: ${bootstrapFallback}
|
|
421
|
+
|
|
422
|
+
[TIP] To enable remote syncing (Portable State), set "portableState": true in .holistic/config.json
|
|
385
423
|
`);
|
|
386
424
|
return 0;
|
|
387
425
|
}
|
|
426
|
+
async function handleDoctor(rootDir, parsed) {
|
|
427
|
+
printSplash({
|
|
428
|
+
message: "running holistic health check...",
|
|
429
|
+
});
|
|
430
|
+
const status = getSetupStatus(rootDir);
|
|
431
|
+
process.stdout.write("\nSystem Configuration:\n\n");
|
|
432
|
+
printSetupStatusTable(status);
|
|
433
|
+
process.stdout.write("\nSync Diagnostics:\n\n");
|
|
434
|
+
process.stdout.write(renderSyncStatus(rootDir));
|
|
435
|
+
const healthy = status.every(s => s.status === "ok");
|
|
436
|
+
if (healthy) {
|
|
437
|
+
process.stdout.write("\n\u2713 Holistic is healthy and correctly configured on this machine.\n");
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
process.stdout.write("\n\u26A0 Some components require attention. Run 'holistic bootstrap' to fix.\n");
|
|
441
|
+
}
|
|
442
|
+
return 0;
|
|
443
|
+
}
|
|
444
|
+
function printSetupStatusTable(status) {
|
|
445
|
+
for (const s of status) {
|
|
446
|
+
const icon = s.status === "ok" ? "\u2713" : s.status === "missing" ? "\u25CB" : s.status === "outdated" ? "\u21BB" : s.status === "info" ? "\u2139" : "!";
|
|
447
|
+
const label = `${icon} ${s.component.padEnd(20)}`;
|
|
448
|
+
process.stdout.write(`${label} | ${s.status.padEnd(10)} | ${s.details}\n`);
|
|
449
|
+
process.stdout.write(` ${s.description}\n\n`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
388
452
|
async function handleRepair(rootDir, parsed) {
|
|
389
453
|
printSplash({
|
|
390
454
|
message: "repairing holistic machine-local helpers...",
|
|
@@ -515,23 +579,23 @@ async function handleCheckpoint(rootDir, parsed) {
|
|
|
515
579
|
async function handleStartNew(rootDir, parsed) {
|
|
516
580
|
refreshHooksBeforeCommand(rootDir);
|
|
517
581
|
const agent = asAgent(firstFlag(parsed.flags, "agent", "unknown"));
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
return 1;
|
|
528
|
-
}
|
|
529
|
-
process.stdout.write(`Started ${mutateResult.state.activeSession?.id} for goal: ${mutateResult.state.activeSession?.currentGoal}\n`);
|
|
530
|
-
return 0;
|
|
582
|
+
let goal = firstFlag(parsed.flags, "goal");
|
|
583
|
+
const title = firstFlag(parsed.flags, "title");
|
|
584
|
+
const plan = listFlag(parsed.flags, "plan");
|
|
585
|
+
if (!goal) {
|
|
586
|
+
goal = await ask("Current objective / goal");
|
|
587
|
+
}
|
|
588
|
+
if (!goal) {
|
|
589
|
+
process.stderr.write("Error: A goal is required to start a new session.\n");
|
|
590
|
+
return 1;
|
|
531
591
|
}
|
|
532
|
-
|
|
533
|
-
|
|
592
|
+
const mutateResult = mutateState(rootDir, (state) => startNewSession(rootDir, state, agent, goal, plan, title));
|
|
593
|
+
if (!mutateResult.success || !mutateResult.state) {
|
|
594
|
+
process.stderr.write(`Error: Failed to start session: ${mutateResult.error}\n`);
|
|
595
|
+
return 1;
|
|
534
596
|
}
|
|
597
|
+
process.stdout.write(`Started ${mutateResult.state.activeSession?.id} for goal: ${mutateResult.state.activeSession?.currentGoal}\n`);
|
|
598
|
+
return 0;
|
|
535
599
|
}
|
|
536
600
|
async function handleHandoff(rootDir, parsed) {
|
|
537
601
|
refreshHooksBeforeCommand(rootDir);
|
|
@@ -610,22 +674,33 @@ async function handleHandoff(rootDir, parsed) {
|
|
|
610
674
|
process.exit(1);
|
|
611
675
|
}
|
|
612
676
|
const nextState = mutateResult.state;
|
|
677
|
+
const shouldCommit = firstFlag(parsed.flags, "commit") === "true";
|
|
613
678
|
let commitResult = null;
|
|
614
|
-
if (nextState.pendingCommit) {
|
|
679
|
+
if (nextState.pendingCommit && shouldCommit) {
|
|
615
680
|
commitResult = commitPendingChanges(rootDir, nextState.pendingCommit.message, nextState.pendingCommit.files);
|
|
616
681
|
if (commitResult.success) {
|
|
617
|
-
|
|
682
|
+
mutateState(rootDir, (latestState, paths) => {
|
|
618
683
|
clearPendingCommit(paths);
|
|
619
684
|
return {
|
|
620
685
|
...latestState,
|
|
621
686
|
pendingCommit: null,
|
|
622
687
|
};
|
|
623
688
|
});
|
|
624
|
-
if (!clearResult.success) {
|
|
625
|
-
process.stderr.write(`Warning: Failed to clear pending commit state: ${clearResult.error}\n`);
|
|
626
|
-
}
|
|
627
689
|
}
|
|
628
690
|
}
|
|
691
|
+
if (nextState.pendingCommit && !shouldCommit) {
|
|
692
|
+
process.stdout.write(`
|
|
693
|
+
Handoff prepared successfully!
|
|
694
|
+
Docs updated: ${nextState.pendingCommit.files.join(", ")}
|
|
695
|
+
|
|
696
|
+
To complete the handoff, review your changes and commit:
|
|
697
|
+
git add .
|
|
698
|
+
git commit -F .holistic/context/pending-commit.txt
|
|
699
|
+
|
|
700
|
+
Use 'holistic handoff --commit' next time to automate this step safely.
|
|
701
|
+
`);
|
|
702
|
+
return 0;
|
|
703
|
+
}
|
|
629
704
|
process.stdout.write(`Handoff complete.\nSummary: ${nextState.lastHandoff?.summary ?? "n/a"}\n`);
|
|
630
705
|
if (commitResult) {
|
|
631
706
|
if (commitResult.success) {
|
|
@@ -686,9 +761,7 @@ function renderSyncStatus(rootDir) {
|
|
|
686
761
|
async function handleStatus(rootDir) {
|
|
687
762
|
refreshHooksBeforeCommand(rootDir);
|
|
688
763
|
const { state } = loadState(rootDir);
|
|
689
|
-
process.stdout.write(renderStatus(state));
|
|
690
|
-
process.stdout.write("\n");
|
|
691
|
-
process.stdout.write(renderSyncStatus(rootDir));
|
|
764
|
+
process.stdout.write(renderStatus(rootDir, state));
|
|
692
765
|
return 0;
|
|
693
766
|
}
|
|
694
767
|
async function handleDiff(rootDir, parsed) {
|
|
@@ -822,6 +895,8 @@ async function main() {
|
|
|
822
895
|
return handleInit(rootDir, parsed);
|
|
823
896
|
case "bootstrap":
|
|
824
897
|
return handleBootstrap(rootDir, parsed);
|
|
898
|
+
case "doctor":
|
|
899
|
+
return handleDoctor(rootDir, parsed);
|
|
825
900
|
case "repair":
|
|
826
901
|
return handleRepair(rootDir, parsed);
|
|
827
902
|
case "start":
|