@jaguilar87/gaia 5.2.0-rc.1 → 5.2.0-rc.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +2 -0
- package/bin/cli/doctor.py +20 -1
- package/bin/cli/install.py +201 -23
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/gaia-patterns/reference.md +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "gaia",
|
|
11
11
|
"description": "Security-first multi-agent orchestration for Claude Code. Specialized agents cover the full development lifecycle — analysis, planning, execution, deployment — with codebase-aware context injection. Every command is risk-classified: read-only runs freely, state changes pause for your approval, and irreversible operations are permanently blocked.",
|
|
12
|
-
"version": "5.2.0-rc.
|
|
12
|
+
"version": "5.2.0-rc.2",
|
|
13
13
|
"category": "devops",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "jaguilar87",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"source": {
|
|
20
20
|
"source": "github",
|
|
21
21
|
"repo": "metraton/gaia",
|
|
22
|
-
"ref": "v5.2.0-rc.
|
|
22
|
+
"ref": "v5.2.0-rc.2"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gaia",
|
|
3
|
-
"version": "5.2.0-rc.
|
|
3
|
+
"version": "5.2.0-rc.2",
|
|
4
4
|
"description": "Security-first multi-agent orchestration for Claude Code. Agents span the full lifecycle; commands are risk-classified \u2014 reads run free, state changes need approval, irreversible ops blocked.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "jaguilar87",
|
package/CHANGELOG.md
CHANGED
|
@@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
29
29
|
- `gaia context prune-workspaces --yes` is now correctly classified T3 (state-mutating): it hard-deletes `workspaces` rows, but the `context` group carried no mutative verb and classified read-only by elimination. Only the destructive subcommand is anchored (`COMMAND_SUBCOMMAND_MUTATIVE_UPGRADES[("gaia","context")]`); other `context` subcommands stay read-only. Separately, the Step 5 ALWAYS-dangerous flag scan now runs before the read-only-verb early return, so `git fetch --prune` (a read-only verb with a destructive flag) escalates to T3 instead of being skipped.
|
|
30
30
|
- SubagentStop M4 fence footgun: a turn that built its contract via the `gaia contract` CLI and ran `gaia contract finalize` (valid terminal row) but forgot to echo the fenced `agent_contract_handoff` in its response text was hard-rejected by the full-verdict gate. `adapt_subagent_stop` now reconstructs the envelope from the agent's own finalized draft when the fence is missing, so the gate parses the completed contract; non-fatal (falls back to the unchanged gate when no finalized row exists). The minted-agent-id resolver was factored into a shared `resolve_minted_agent_id` reused by the backstop, truncation salvage, and this path.
|
|
31
31
|
|
|
32
|
+
## [5.2.0-rc.2] - 2026-07-17
|
|
33
|
+
|
|
32
34
|
## [5.2.0-rc.1] - 2026-07-17
|
|
33
35
|
|
|
34
36
|
## [5.1.3] - 2026-07-07
|
package/bin/cli/doctor.py
CHANGED
|
@@ -103,7 +103,16 @@ def _derive_workspace(override: str = None) -> Path:
|
|
|
103
103
|
Algorithm
|
|
104
104
|
---------
|
|
105
105
|
1. If *override* is given (from --workspace), validate it has .claude/
|
|
106
|
-
and return it directly.
|
|
106
|
+
and return it directly. (Highest priority -- always wins.)
|
|
107
|
+
1b. Else if the ``GAIA_WORKSPACE_PATH`` env var is set AND points at a dir
|
|
108
|
+
containing ``.claude/``, return it. This is set by the Windows launcher
|
|
109
|
+
(see install.py Step 6.5), which bakes the resolved workspace so a
|
|
110
|
+
global-shim invocation resolves the SAME workspace POSIX derives from
|
|
111
|
+
``__file__``. Without this, the npm global ``gaia.cmd`` runs ``bin/gaia``
|
|
112
|
+
from the npm prefix, ``__file__`` lands there, and the derivation below
|
|
113
|
+
yields the npm prefix as the "workspace" -- a false CRITICAL. An env var
|
|
114
|
+
that is unset OR points at a dir without ``.claude/`` falls through to
|
|
115
|
+
the ``__file__`` derivation (it is a hint, not an override).
|
|
107
116
|
2. Resolve Path(__file__) to its realpath and find the FIRST (leftmost)
|
|
108
117
|
``node_modules`` path segment; the workspace is everything before it.
|
|
109
118
|
3. Sanity-check that ``@jaguilar87`` and ``gaia`` both appear somewhere
|
|
@@ -148,6 +157,16 @@ def _derive_workspace(override: str = None) -> Path:
|
|
|
148
157
|
sys.exit(2)
|
|
149
158
|
return ws
|
|
150
159
|
|
|
160
|
+
# --- GAIA_WORKSPACE_PATH env (baked by the Windows launcher) ---
|
|
161
|
+
# Consulted BEFORE the __file__ derivation but AFTER --workspace. Only
|
|
162
|
+
# honored when it resolves to a dir with .claude/; otherwise fall through
|
|
163
|
+
# (never a cwd walk-up -- that was removed on purpose). See docstring 1b.
|
|
164
|
+
env_ws = os.environ.get("GAIA_WORKSPACE_PATH")
|
|
165
|
+
if env_ws:
|
|
166
|
+
candidate = Path(env_ws).expanduser().resolve()
|
|
167
|
+
if (candidate / ".claude").is_dir():
|
|
168
|
+
return candidate
|
|
169
|
+
|
|
151
170
|
# --- Derive from __file__ realpath ---
|
|
152
171
|
script_path = Path(__file__).resolve()
|
|
153
172
|
parts = script_path.parts
|
package/bin/cli/install.py
CHANGED
|
@@ -61,8 +61,9 @@ Flags:
|
|
|
61
61
|
Useful when running install just to refresh the DB
|
|
62
62
|
schema from a non-Gaia directory.
|
|
63
63
|
--no-path Skip creating the ~/.local/bin/gaia launcher. By default
|
|
64
|
-
install writes a workspace-aware
|
|
65
|
-
|
|
64
|
+
install writes a workspace-aware launcher so `gaia` is
|
|
65
|
+
callable from any cwd: a bash launcher on POSIX, and
|
|
66
|
+
`gaia.cmd` + `gaia.ps1` on Windows.
|
|
66
67
|
"""
|
|
67
68
|
|
|
68
69
|
from __future__ import annotations
|
|
@@ -92,30 +93,90 @@ _SEED_SURFACE_ROUTING = _PACKAGE_ROOT / "tools" / "scan" / "seed_surface_routing
|
|
|
92
93
|
|
|
93
94
|
|
|
94
95
|
# ---------------------------------------------------------------------------
|
|
95
|
-
# PATH launcher (~/.local/bin/gaia -- workspace-bound
|
|
96
|
+
# PATH launcher (~/.local/bin/gaia -- workspace-bound launcher)
|
|
96
97
|
# ---------------------------------------------------------------------------
|
|
97
|
-
|
|
98
|
-
# Hardcoded launcher template. The workspace path is resolved at install time
|
|
99
|
-
# (the cwd of `gaia install`) and baked into the script verbatim. No discovery,
|
|
100
|
-
# no env vars, no fallbacks -- the shim is a 3-line exec to a fixed path.
|
|
101
98
|
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
99
|
+
# Platform split (Step 6.5): the launcher form is chosen by platform. This is a
|
|
100
|
+
# hard guard, not a preference -- a bash script has no meaning to the Windows
|
|
101
|
+
# shell (PowerShell opens an "open with" dialog on an extensionless file), and
|
|
102
|
+
# the POSIX shim's ``{workspace}/node_modules/...`` target does not exist under
|
|
103
|
+
# ``npm install -g`` on any platform. So:
|
|
104
|
+
#
|
|
105
|
+
# * POSIX -> one bash launcher at ``<link>`` (unchanged behavior).
|
|
106
|
+
# * Windows -> ``<link>.cmd`` and ``<link>.ps1``, each of which
|
|
107
|
+
# (a) bakes the resolved workspace path,
|
|
108
|
+
# (b) exports ``GAIA_WORKSPACE_PATH`` so `gaia doctor` resolves the
|
|
109
|
+
# correct workspace from the env instead of deriving it from
|
|
110
|
+
# ``__file__`` (which, via the npm global shim, lands in the npm
|
|
111
|
+
# prefix and yields a false CRITICAL -- see doctor._derive_workspace),
|
|
112
|
+
# (c) execs the ACTUAL installed ``bin/gaia`` dispatcher
|
|
113
|
+
# (``_gaia_entrypoint()`` = ``<package_root>/bin/gaia``), which is
|
|
114
|
+
# valid for BOTH a global (`-g`) and a local install, unlike the
|
|
115
|
+
# POSIX shim's workspace-relative ``node_modules`` path.
|
|
106
116
|
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
117
|
+
# PATH precedence vs npm's own shim (Windows): `npm install -g @jaguilar87/gaia`
|
|
118
|
+
# writes its own ``gaia.cmd`` into the npm global prefix (on PATH), and that
|
|
119
|
+
# shim execs ``bin/gaia`` WITHOUT setting GAIA_WORKSPACE_PATH -- which is
|
|
120
|
+
# exactly the origin of the false-CRITICAL bug. Gaia's launcher coexists with
|
|
121
|
+
# and wins over npm's by being written to Gaia's own bin dir (default
|
|
122
|
+
# ``~/.local/bin``): when that dir precedes the npm prefix on PATH, cmd.exe /
|
|
123
|
+
# PowerShell resolve ``gaia`` (``gaia.cmd`` / ``gaia.ps1``) to Gaia's launcher,
|
|
124
|
+
# which sets GAIA_WORKSPACE_PATH before dispatching. Where Gaia's dir is NOT
|
|
125
|
+
# ahead of the npm prefix, npm's shim still runs and still dispatches correctly
|
|
126
|
+
# for workspace-independent subcommands; only the workspace-derivation path
|
|
127
|
+
# needs the env var, and the doctor `__file__` fallback keeps working. The
|
|
128
|
+
# env-var contract is the load-bearing coupling, not the PATH order.
|
|
129
|
+
#
|
|
130
|
+
# Re-running `gaia install` from a different workspace rewrites the launcher(s)
|
|
131
|
+
# to point at that workspace -- the install action is what selects which
|
|
132
|
+
# workspace the launcher targets.
|
|
133
|
+
|
|
134
|
+
# POSIX bash launcher. The workspace path is resolved at install time and baked
|
|
135
|
+
# in verbatim. No discovery, no env vars, no fallbacks -- a 3-line exec.
|
|
110
136
|
_LAUNCHER_TEMPLATE = """#!/bin/bash
|
|
111
137
|
# gaia -- workspace-bound launcher (workspace path hardcoded at install time)
|
|
112
138
|
# Generated by `gaia install`. Re-run install from another workspace to retarget.
|
|
113
139
|
exec python3 "{workspace_path}/node_modules/@jaguilar87/gaia/bin/gaia" "$@"
|
|
114
140
|
"""
|
|
115
141
|
|
|
142
|
+
# Windows launchers. Both bake the resolved workspace, export GAIA_WORKSPACE_PATH,
|
|
143
|
+
# and dispatch to the ACTUAL installed bin/gaia (global- or local-install safe).
|
|
144
|
+
_CMD_LAUNCHER_TEMPLATE = """@echo off
|
|
145
|
+
REM gaia -- workspace-bound launcher (generated by `gaia install`)
|
|
146
|
+
REM Re-run install from another workspace to retarget. Exports GAIA_WORKSPACE_PATH
|
|
147
|
+
REM so `gaia doctor` resolves this workspace instead of deriving from __file__.
|
|
148
|
+
set "GAIA_WORKSPACE_PATH={workspace_path}"
|
|
149
|
+
python "{gaia_bin}" %*
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
_PS1_LAUNCHER_TEMPLATE = """# gaia -- workspace-bound launcher (generated by `gaia install`)
|
|
153
|
+
# Re-run install from another workspace to retarget. Exports GAIA_WORKSPACE_PATH
|
|
154
|
+
# so `gaia doctor` resolves this workspace instead of deriving from __file__.
|
|
155
|
+
$env:GAIA_WORKSPACE_PATH = "{workspace_path}"
|
|
156
|
+
& python "{gaia_bin}" @args
|
|
157
|
+
exit $LASTEXITCODE
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _is_windows() -> bool:
|
|
162
|
+
"""True on Windows. Isolated so the platform guard is trivially patchable."""
|
|
163
|
+
return sys.platform == "win32"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _gaia_entrypoint() -> Path:
|
|
167
|
+
"""Absolute path to the installed ``bin/gaia`` dispatcher.
|
|
168
|
+
|
|
169
|
+
This is ``<package_root>/bin/gaia`` -- the real location of the running
|
|
170
|
+
Gaia package, which resolves correctly under both a global (`npm i -g`)
|
|
171
|
+
and a local install. The POSIX shim's ``{workspace}/node_modules/...``
|
|
172
|
+
assumption breaks under `-g` (there is no workspace-relative node_modules);
|
|
173
|
+
the Windows launchers bake this resolved path instead.
|
|
174
|
+
"""
|
|
175
|
+
return _PACKAGE_ROOT / "bin" / "gaia"
|
|
176
|
+
|
|
116
177
|
|
|
117
178
|
def _render_launcher(workspace: Path) -> str:
|
|
118
|
-
"""Render the launcher
|
|
179
|
+
"""Render the POSIX bash launcher with the workspace path baked in.
|
|
119
180
|
|
|
120
181
|
The workspace must be an absolute, resolved path -- the rendered script
|
|
121
182
|
references it verbatim. Quoting in the template uses double quotes so
|
|
@@ -124,21 +185,40 @@ def _render_launcher(workspace: Path) -> str:
|
|
|
124
185
|
return _LAUNCHER_TEMPLATE.format(workspace_path=str(workspace))
|
|
125
186
|
|
|
126
187
|
|
|
188
|
+
def _render_cmd_launcher(workspace: Path, gaia_bin: Path) -> str:
|
|
189
|
+
"""Render the Windows ``gaia.cmd`` launcher (workspace + bin baked in)."""
|
|
190
|
+
return _CMD_LAUNCHER_TEMPLATE.format(
|
|
191
|
+
workspace_path=str(workspace), gaia_bin=str(gaia_bin)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _render_ps1_launcher(workspace: Path, gaia_bin: Path) -> str:
|
|
196
|
+
"""Render the Windows ``gaia.ps1`` launcher (workspace + bin baked in)."""
|
|
197
|
+
return _PS1_LAUNCHER_TEMPLATE.format(
|
|
198
|
+
workspace_path=str(workspace), gaia_bin=str(gaia_bin)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
127
202
|
def _install_path_launcher(
|
|
128
203
|
target_path: Path | None = None,
|
|
129
204
|
link_path: Path | str = "~/.local/bin/gaia",
|
|
130
205
|
overwrite: bool = False,
|
|
131
206
|
workspace: Path | str | None = None,
|
|
207
|
+
gaia_bin: Path | str | None = None,
|
|
132
208
|
) -> dict:
|
|
133
|
-
"""Install the workspace-bound
|
|
209
|
+
"""Install the workspace-bound launcher at `link_path`.
|
|
210
|
+
|
|
211
|
+
Platform-guarded (Step 6.5): on Windows this writes ``<link>.cmd`` and
|
|
212
|
+
``<link>.ps1`` (see ``_install_windows_launchers``); on POSIX it writes a
|
|
213
|
+
single bash launcher at ``<link>``. The POSIX behavior below is unchanged.
|
|
134
214
|
|
|
135
|
-
The launcher is a 3-line script that execs into a hardcoded absolute
|
|
136
|
-
pointing at ``<workspace>/node_modules/@jaguilar87/gaia/bin/gaia``.
|
|
137
|
-
is no discovery logic, no env-var override, no fallback chain -- the
|
|
138
|
-
is fixed at install time and only changes when ``gaia install`` runs
|
|
139
|
-
from a different workspace.
|
|
215
|
+
The POSIX launcher is a 3-line script that execs into a hardcoded absolute
|
|
216
|
+
path pointing at ``<workspace>/node_modules/@jaguilar87/gaia/bin/gaia``.
|
|
217
|
+
There is no discovery logic, no env-var override, no fallback chain -- the
|
|
218
|
+
path is fixed at install time and only changes when ``gaia install`` runs
|
|
219
|
+
again from a different workspace.
|
|
140
220
|
|
|
141
|
-
Behavior:
|
|
221
|
+
Behavior (POSIX):
|
|
142
222
|
- If `link_path` is a symlink (legacy install): unlink, write launcher.
|
|
143
223
|
- If `link_path` is a regular file with the expected content: noop.
|
|
144
224
|
- If `link_path` is a regular file with different content and
|
|
@@ -151,10 +231,14 @@ def _install_path_launcher(
|
|
|
151
231
|
target_path: accepted for API compatibility; the launcher embeds the
|
|
152
232
|
workspace path instead. Ignored.
|
|
153
233
|
link_path: where the shim is written (default ``~/.local/bin/gaia``).
|
|
234
|
+
On Windows, ``.cmd``/``.ps1`` suffixes are derived from this base.
|
|
154
235
|
overwrite: replace existing different-content files when True.
|
|
155
236
|
workspace: absolute path to the consumer workspace (the directory
|
|
156
237
|
that contains ``node_modules/@jaguilar87/gaia/``). Resolved with
|
|
157
238
|
``Path.cwd().resolve()`` when None.
|
|
239
|
+
gaia_bin: Windows only -- the ``bin/gaia`` dispatcher the launchers
|
|
240
|
+
exec. Defaults to ``_gaia_entrypoint()`` (the installed package's
|
|
241
|
+
``bin/gaia``, valid for global and local installs). Ignored on POSIX.
|
|
158
242
|
|
|
159
243
|
Returns a dict with `action`, `path`, and `details`. `action` is one
|
|
160
244
|
of: created, replaced, migrated, noop, skipped, error.
|
|
@@ -167,6 +251,20 @@ def _install_path_launcher(
|
|
|
167
251
|
else:
|
|
168
252
|
workspace_resolved = Path(workspace).expanduser().resolve()
|
|
169
253
|
|
|
254
|
+
# Windows: emit gaia.cmd + gaia.ps1 instead of a bash shim. The POSIX path
|
|
255
|
+
# below is left entirely unchanged.
|
|
256
|
+
if _is_windows():
|
|
257
|
+
entry = (
|
|
258
|
+
Path(gaia_bin).expanduser() if gaia_bin is not None
|
|
259
|
+
else _gaia_entrypoint()
|
|
260
|
+
)
|
|
261
|
+
return _install_windows_launchers(
|
|
262
|
+
link=link,
|
|
263
|
+
workspace=workspace_resolved,
|
|
264
|
+
gaia_bin=entry,
|
|
265
|
+
overwrite=overwrite,
|
|
266
|
+
)
|
|
267
|
+
|
|
170
268
|
parent = link.parent
|
|
171
269
|
try:
|
|
172
270
|
parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -268,6 +366,86 @@ def _install_path_launcher(
|
|
|
268
366
|
}
|
|
269
367
|
|
|
270
368
|
|
|
369
|
+
def _install_windows_launchers(
|
|
370
|
+
link: Path,
|
|
371
|
+
workspace: Path,
|
|
372
|
+
gaia_bin: Path,
|
|
373
|
+
overwrite: bool = False,
|
|
374
|
+
) -> dict:
|
|
375
|
+
"""Write the Windows ``gaia.cmd`` + ``gaia.ps1`` launchers.
|
|
376
|
+
|
|
377
|
+
Both are derived from ``link`` by suffix: ``<link>.cmd`` and ``<link>.ps1``
|
|
378
|
+
(so a default ``~/.local/bin/gaia`` yields ``gaia.cmd`` / ``gaia.ps1``).
|
|
379
|
+
Each bakes the resolved ``workspace``, exports ``GAIA_WORKSPACE_PATH``, and
|
|
380
|
+
dispatches to ``gaia_bin`` (the actual installed ``bin/gaia``).
|
|
381
|
+
|
|
382
|
+
Idempotent and non-destructive, mirroring the POSIX branch:
|
|
383
|
+
- missing -> created
|
|
384
|
+
- present, matches -> noop
|
|
385
|
+
- present, drifted -> replaced (overwrite=True) / skipped (overwrite=False)
|
|
386
|
+
- a directory in the way -> skipped
|
|
387
|
+
|
|
388
|
+
The aggregate ``action`` is the "strongest" over the two files: error >
|
|
389
|
+
skipped > replaced > created > noop. ``path`` lists both files.
|
|
390
|
+
"""
|
|
391
|
+
parent = link.parent
|
|
392
|
+
try:
|
|
393
|
+
parent.mkdir(parents=True, exist_ok=True)
|
|
394
|
+
except OSError as exc:
|
|
395
|
+
return {
|
|
396
|
+
"action": "error",
|
|
397
|
+
"path": str(link),
|
|
398
|
+
"details": f"failed to create parent {parent}: {exc}",
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
targets = [
|
|
402
|
+
(link.with_suffix(".cmd"), _render_cmd_launcher(workspace, gaia_bin)),
|
|
403
|
+
(link.with_suffix(".ps1"), _render_ps1_launcher(workspace, gaia_bin)),
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
# Rank so the aggregate reports the most significant per-file outcome.
|
|
407
|
+
rank = {"noop": 0, "created": 1, "replaced": 2, "skipped": 3, "error": 4}
|
|
408
|
+
per_file: list[str] = []
|
|
409
|
+
worst = "noop"
|
|
410
|
+
|
|
411
|
+
for path, content in targets:
|
|
412
|
+
action = _write_windows_launcher_file(path, content, overwrite=overwrite)
|
|
413
|
+
per_file.append(f"{path.name}={action}")
|
|
414
|
+
if rank[action] > rank[worst]:
|
|
415
|
+
worst = action
|
|
416
|
+
|
|
417
|
+
return {
|
|
418
|
+
"action": worst,
|
|
419
|
+
"path": ", ".join(str(p) for p, _ in targets),
|
|
420
|
+
"details": "; ".join(per_file),
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _write_windows_launcher_file(path: Path, content: str, overwrite: bool) -> str:
|
|
425
|
+
"""Write one Windows launcher file idempotently. Returns the action string."""
|
|
426
|
+
if path.is_dir():
|
|
427
|
+
return "skipped"
|
|
428
|
+
if path.exists():
|
|
429
|
+
try:
|
|
430
|
+
current = path.read_text()
|
|
431
|
+
except OSError:
|
|
432
|
+
return "error"
|
|
433
|
+
if current == content:
|
|
434
|
+
return "noop"
|
|
435
|
+
if not overwrite:
|
|
436
|
+
return "skipped"
|
|
437
|
+
try:
|
|
438
|
+
path.write_text(content)
|
|
439
|
+
except OSError:
|
|
440
|
+
return "error"
|
|
441
|
+
return "replaced"
|
|
442
|
+
try:
|
|
443
|
+
path.write_text(content)
|
|
444
|
+
except OSError:
|
|
445
|
+
return "error"
|
|
446
|
+
return "created"
|
|
447
|
+
|
|
448
|
+
|
|
271
449
|
# Backward-compatible alias -- existing tests/imports continue to work
|
|
272
450
|
# while migrating to the new name.
|
|
273
451
|
_create_path_symlink = _install_path_launcher
|
|
@@ -632,7 +810,7 @@ def register(subparsers: argparse._SubParsersAction) -> argparse.ArgumentParser:
|
|
|
632
810
|
dest="no_path",
|
|
633
811
|
action="store_true",
|
|
634
812
|
default=False,
|
|
635
|
-
help="Skip creating the ~/.local/bin/gaia
|
|
813
|
+
help="Skip creating the ~/.local/bin/gaia launcher",
|
|
636
814
|
)
|
|
637
815
|
return p
|
|
638
816
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -169,7 +169,7 @@ There is **no npm postinstall hook**. `package.json` carries an explicit `_insta
|
|
|
169
169
|
4. Merge hooks from `hooks.json` into `settings.local.json`.
|
|
170
170
|
5. Create `.claude/{agents, tools, hooks, config, skills}` symlinks (5) plus a `CHANGELOG.md` file link.
|
|
171
171
|
6. Write `plugin-registry.json` with `installed[].name == "gaia"` (the single unified plugin identity).
|
|
172
|
-
7. Write the `~/.local/bin/gaia`
|
|
172
|
+
7. Write the PATH launcher unless `--no-path`: POSIX still gets the `~/.local/bin/gaia` bash shim; Windows instead gets `gaia.cmd` + `gaia.ps1` (`_install_windows_launchers` / `_render_cmd_launcher` / `_render_ps1_launcher` in `bin/cli/install.py`), each baking in the resolved workspace and exporting `GAIA_WORKSPACE_PATH` before dispatching to `bin/gaia`.
|
|
173
173
|
|
|
174
174
|
Note: no `project-context.json` is written. Project context lives in `~/.gaia/gaia.db`. Run `gaia scan` separately to populate it -- install never triggers a scan.
|
|
175
175
|
|