@jaguilar87/gaia 5.1.0 → 5.1.1
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 +11 -0
- package/agents/gaia-orchestrator.md +4 -10
- package/bin/README.md +1 -1
- package/bin/cli/approvals.py +0 -144
- package/bin/cli/cleanup.py +1 -30
- package/bin/cli/context.py +379 -6
- package/bin/cli/doctor.py +1 -1
- package/bin/cli/history.py +18 -6
- package/bin/cli/install.py +4 -2
- package/bin/cli/memory.py +86 -10
- package/bin/cli/metrics.py +1216 -275
- package/bin/cli/query.py +89 -0
- package/bin/cli/scan.py +68 -2
- package/bin/cli/uninstall.py +9 -5
- package/bin/pre-publish-validate.js +7 -4
- package/gaia/project.py +49 -20
- package/gaia/store/reader.py +175 -11
- package/gaia/store/schema.sql +180 -1
- package/gaia/store/writer.py +1146 -165
- package/hooks/README.md +2 -2
- package/hooks/adapters/claude_code.py +6 -12
- package/hooks/elicitation_result.py +4 -9
- package/hooks/modules/agents/contract_validator.py +2 -1
- package/hooks/modules/agents/handoff_persister.py +5 -220
- package/hooks/modules/agents/task_info_builder.py +9 -2
- package/hooks/modules/agents/transcript_reader.py +41 -21
- package/hooks/modules/audit/logger.py +8 -3
- package/hooks/modules/context/context_injector.py +10 -3
- package/hooks/modules/core/__init__.py +5 -2
- package/hooks/modules/core/logging_setup.py +60 -0
- package/hooks/modules/core/paths.py +0 -12
- package/hooks/modules/security/approval_grants.py +24 -92
- package/hooks/modules/security/gaia_db_write_guard.py +7 -2
- package/hooks/modules/security/mutative_verbs.py +194 -11
- package/hooks/modules/session/pending_scanner.py +24 -222
- package/hooks/modules/session/session_manifest.py +13 -288
- package/hooks/post_compact.py +4 -9
- package/hooks/post_tool_use.py +4 -9
- package/hooks/pre_compact.py +5 -10
- package/hooks/pre_tool_use.py +4 -11
- package/hooks/session_end_hook.py +4 -9
- package/hooks/session_start.py +18 -21
- package/hooks/stop_hook.py +5 -10
- package/hooks/subagent_start.py +5 -10
- package/hooks/subagent_stop.py +9 -23
- package/hooks/task_completed.py +5 -10
- package/hooks/user_prompt_submit.py +4 -9
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/migrations/schema.checksum +2 -2
- package/scripts/migrations/v21_to_v22.sql +80 -0
- package/scripts/migrations/v22_to_v23.sql +20 -0
- package/scripts/migrations/v23_to_v24.sql +30 -0
- package/scripts/migrations/v24_to_v25.sql +77 -0
- package/scripts/migrations/v25_to_v26.sql +116 -0
- package/skills/README.md +8 -0
- package/skills/agent-approval-protocol/SKILL.md +27 -27
- package/skills/agent-approval-protocol/reference.md +20 -12
- package/skills/agent-protocol/SKILL.md +1 -1
- package/skills/agent-protocol/examples.md +17 -9
- package/skills/agent-response/SKILL.md +1 -1
- package/skills/diagram-builder/GLOSSARY.md +77 -0
- package/skills/diagram-builder/SKILL.md +156 -0
- package/skills/diagram-builder/assets/README.md +45 -0
- package/skills/diagram-builder/assets/data/data.generated.js +77 -0
- package/skills/diagram-builder/assets/data/document.yaml +12 -0
- package/skills/diagram-builder/assets/data/pages/overview.yaml +47 -0
- package/skills/diagram-builder/assets/engine/build-data.mjs +51 -0
- package/skills/diagram-builder/assets/engine/engine.js +863 -0
- package/skills/diagram-builder/assets/index.html +638 -0
- package/skills/diagram-builder/assets/package.json +15 -0
- package/skills/diagram-builder/assets/tools/verify.mjs +128 -0
- package/skills/diagram-builder/reference.md +444 -0
- package/skills/execution/SKILL.md +3 -3
- package/skills/gaia-patterns/reference.md +2 -2
- package/skills/memory/SKILL.md +49 -0
- package/skills/orchestrator-present-approval/SKILL.md +90 -79
- package/skills/orchestrator-present-approval/reference.md +59 -42
- package/skills/orchestrator-present-approval/template.md +16 -14
- package/skills/pending-approvals/SKILL.md +80 -29
- package/skills/pending-approvals/reference.md +48 -60
- package/skills/security-tiers/SKILL.md +1 -1
- package/skills/subagent-request-approval/SKILL.md +65 -68
- package/skills/subagent-request-approval/reference.md +63 -63
- package/skills/visual-verify/SKILL.md +107 -0
- package/skills/visual-verify/scripts/screenshot.js +210 -0
- package/tools/scan/classify.py +584 -15
- package/tools/scan/migrate_workspace.py +9 -4
- package/tools/scan/store_populator.py +231 -2
- package/tools/scan/tests/conftest.py +31 -0
package/bin/cli/memory.py
CHANGED
|
@@ -13,10 +13,17 @@ Mutating subcommands operate on the curated ``memory`` table in
|
|
|
13
13
|
``~/.gaia/gaia.db`` (the project-level / user-level / feedback notes):
|
|
14
14
|
|
|
15
15
|
add --name=<slug> --type=<project|user|feedback> --body="..."
|
|
16
|
-
[--description=...] [--workspace=<ws>]
|
|
16
|
+
[--description=...] [--workspace=<ws>]
|
|
17
|
+
[--project=<name> | --project-ref=<identity>] [--json]
|
|
17
18
|
DB-only writer; no filesystem side
|
|
18
19
|
effects (no .md under
|
|
19
20
|
~/.claude/projects/.../memory/).
|
|
21
|
+
--project anchors memory.project_ref
|
|
22
|
+
(N3, forward-only) by resolving a
|
|
23
|
+
project name within --workspace to
|
|
24
|
+
its stable project_identity; never
|
|
25
|
+
guesses (clear error if the project
|
|
26
|
+
does not exist or has no identity).
|
|
20
27
|
"""
|
|
21
28
|
|
|
22
29
|
from __future__ import annotations
|
|
@@ -706,6 +713,8 @@ def _cmd_add(args) -> int:
|
|
|
706
713
|
workspace = _resolve_workspace(getattr(args, "workspace", None))
|
|
707
714
|
class_flag = getattr(args, "class_", None)
|
|
708
715
|
status_flag = getattr(args, "status", None)
|
|
716
|
+
project_flag = getattr(args, "project", None)
|
|
717
|
+
project_ref_flag = getattr(args, "project_ref", None)
|
|
709
718
|
|
|
710
719
|
if not name:
|
|
711
720
|
return _err("--name is required", as_json)
|
|
@@ -731,7 +740,8 @@ def _cmd_add(args) -> int:
|
|
|
731
740
|
|
|
732
741
|
try:
|
|
733
742
|
from gaia.store.writer import (
|
|
734
|
-
upsert_memory, reclassify_memory,
|
|
743
|
+
upsert_memory, reclassify_memory, resolve_project_ref,
|
|
744
|
+
VALID_MEMORY_TYPES,
|
|
735
745
|
)
|
|
736
746
|
except ImportError as exc:
|
|
737
747
|
return _err(f"gaia.store.writer not importable: {exc}", as_json)
|
|
@@ -742,6 +752,19 @@ def _cmd_add(args) -> int:
|
|
|
742
752
|
as_json,
|
|
743
753
|
)
|
|
744
754
|
|
|
755
|
+
# N3: forward-only project_ref anchor. --project resolves a project name
|
|
756
|
+
# (within `workspace`) to its stable project_identity; --project-ref
|
|
757
|
+
# passes an already-known identity directly. Neither guesses: an
|
|
758
|
+
# unresolvable --project is a clear error, never a silent NULL.
|
|
759
|
+
project_ref = None
|
|
760
|
+
if project_flag is not None:
|
|
761
|
+
try:
|
|
762
|
+
project_ref = resolve_project_ref(workspace, project_flag)
|
|
763
|
+
except ValueError as exc:
|
|
764
|
+
return _err(str(exc), as_json)
|
|
765
|
+
elif project_ref_flag is not None:
|
|
766
|
+
project_ref = project_ref_flag
|
|
767
|
+
|
|
745
768
|
try:
|
|
746
769
|
res = upsert_memory(
|
|
747
770
|
workspace,
|
|
@@ -749,6 +772,7 @@ def _cmd_add(args) -> int:
|
|
|
749
772
|
type=mem_type,
|
|
750
773
|
body=body,
|
|
751
774
|
description=description,
|
|
775
|
+
project_ref=project_ref,
|
|
752
776
|
)
|
|
753
777
|
except ValueError as exc:
|
|
754
778
|
return _err(str(exc), as_json)
|
|
@@ -796,6 +820,8 @@ def _cmd_add(args) -> int:
|
|
|
796
820
|
"body_preview": snippet,
|
|
797
821
|
"updated_at": res.get("updated_at"),
|
|
798
822
|
}
|
|
823
|
+
if project_ref is not None:
|
|
824
|
+
out["project_ref"] = project_ref
|
|
799
825
|
if reclassify_result is not None:
|
|
800
826
|
out["class"] = reclassify_result["class"]
|
|
801
827
|
out["memory_status"] = reclassify_result["memory_status"]
|
|
@@ -805,6 +831,8 @@ def _cmd_add(args) -> int:
|
|
|
805
831
|
print(f"{verb} memory '{name}' (type={mem_type}, workspace={workspace})")
|
|
806
832
|
if description:
|
|
807
833
|
print(f" description: {description}")
|
|
834
|
+
if project_ref is not None:
|
|
835
|
+
print(f" project_ref: {project_ref}")
|
|
808
836
|
print(f" body: {snippet}")
|
|
809
837
|
if reclassify_result is not None:
|
|
810
838
|
print(
|
|
@@ -1004,6 +1032,9 @@ def _cmd_get_relevant(args) -> int:
|
|
|
1004
1032
|
"SELECT name, type, description, updated_at, class, status "
|
|
1005
1033
|
"FROM memory "
|
|
1006
1034
|
"WHERE workspace = ? "
|
|
1035
|
+
# scan-v2 SV3: a soft-deleted (tombstoned) row must not be
|
|
1036
|
+
# injected into the SessionStart memory block.
|
|
1037
|
+
" AND deleted_at IS NULL "
|
|
1007
1038
|
" AND name NOT IN ("
|
|
1008
1039
|
" SELECT dst_name FROM memory_links "
|
|
1009
1040
|
" WHERE workspace = ? AND kind = 'supersedes'"
|
|
@@ -1384,18 +1415,27 @@ def _cmd_curated_show(args) -> int:
|
|
|
1384
1415
|
|
|
1385
1416
|
|
|
1386
1417
|
def _cmd_delete(args) -> int:
|
|
1387
|
-
"""
|
|
1418
|
+
"""Soft-delete (tombstone) a curated memory row -- scan-v2 SV3.
|
|
1419
|
+
|
|
1420
|
+
By default this is a SOFT delete: the row's ``deleted_at`` is stamped so the
|
|
1421
|
+
row and its body survive (recoverable, invisible to reads). ``--hard``
|
|
1422
|
+
performs the irreversible physical DELETE, reserved for explicit human
|
|
1423
|
+
curation. Both paths keep the FTS5 mirror in sync via triggers.
|
|
1424
|
+
"""
|
|
1388
1425
|
as_json = getattr(args, "json", False)
|
|
1389
1426
|
workspace = _resolve_workspace(getattr(args, "workspace", None))
|
|
1390
1427
|
name = args.name
|
|
1391
1428
|
skip_confirm = getattr(args, "yes", False)
|
|
1429
|
+
hard = getattr(args, "hard", False)
|
|
1392
1430
|
|
|
1393
1431
|
try:
|
|
1394
1432
|
from gaia.store.writer import get_memory, delete_memory
|
|
1395
1433
|
except ImportError as exc:
|
|
1396
1434
|
return _err(f"gaia.store.writer not importable: {exc}", as_json)
|
|
1397
1435
|
|
|
1398
|
-
row
|
|
1436
|
+
# For a hard delete we may target a row that is already tombstoned; reach it
|
|
1437
|
+
# via include_deleted so a soft-then-hard flow works.
|
|
1438
|
+
row = get_memory(workspace, name, include_deleted=hard)
|
|
1399
1439
|
if row is None:
|
|
1400
1440
|
return _err(
|
|
1401
1441
|
f"memory '{name}' not found in workspace '{workspace}'",
|
|
@@ -1403,7 +1443,8 @@ def _cmd_delete(args) -> int:
|
|
|
1403
1443
|
)
|
|
1404
1444
|
|
|
1405
1445
|
if not skip_confirm:
|
|
1406
|
-
|
|
1446
|
+
verb = "HARD-delete (irreversible)" if hard else "delete (tombstone)"
|
|
1447
|
+
prompt = f"{verb} memory '{name}' (type={row['type']})? [y/N] "
|
|
1407
1448
|
try:
|
|
1408
1449
|
answer = input(prompt)
|
|
1409
1450
|
except EOFError:
|
|
@@ -1417,7 +1458,7 @@ def _cmd_delete(args) -> int:
|
|
|
1417
1458
|
return 0
|
|
1418
1459
|
|
|
1419
1460
|
try:
|
|
1420
|
-
deleted = delete_memory(workspace, name)
|
|
1461
|
+
deleted = delete_memory(workspace, name, hard=hard)
|
|
1421
1462
|
except PermissionError as exc:
|
|
1422
1463
|
return _err(str(exc), as_json)
|
|
1423
1464
|
if not deleted:
|
|
@@ -1426,15 +1467,18 @@ def _cmd_delete(args) -> int:
|
|
|
1426
1467
|
as_json,
|
|
1427
1468
|
)
|
|
1428
1469
|
|
|
1470
|
+
mode = "hard" if hard else "tombstone"
|
|
1429
1471
|
if as_json:
|
|
1430
1472
|
print(json.dumps({
|
|
1431
1473
|
"deleted": True,
|
|
1474
|
+
"mode": mode,
|
|
1432
1475
|
"name": name,
|
|
1433
1476
|
"workspace": workspace,
|
|
1434
1477
|
"previous_type": row["type"],
|
|
1435
1478
|
}, indent=2, default=str))
|
|
1436
1479
|
else:
|
|
1437
|
-
|
|
1480
|
+
verb = "Hard-deleted" if hard else "Tombstoned"
|
|
1481
|
+
print(f"{verb} memory '{name}' (workspace={workspace!r}, "
|
|
1438
1482
|
f"previous_type={row['type']!r})")
|
|
1439
1483
|
return 0
|
|
1440
1484
|
|
|
@@ -1937,10 +1981,18 @@ def register(subparsers):
|
|
|
1937
1981
|
# -- delete -------------------------------------------------------------
|
|
1938
1982
|
delete_p = actions.add_parser(
|
|
1939
1983
|
"delete",
|
|
1940
|
-
help="
|
|
1941
|
-
description=
|
|
1984
|
+
help="Soft-delete (tombstone) a curated memory row; --hard to purge",
|
|
1985
|
+
description=(
|
|
1986
|
+
"Tombstone the row by default (deleted_at stamped; row + body "
|
|
1987
|
+
"survive, invisible to reads, recoverable). Use --hard for the "
|
|
1988
|
+
"irreversible physical DELETE (explicit human curation only)."
|
|
1989
|
+
),
|
|
1942
1990
|
formatter_class=_argparse.RawDescriptionHelpFormatter,
|
|
1943
|
-
epilog=
|
|
1991
|
+
epilog=(
|
|
1992
|
+
"Examples:\n"
|
|
1993
|
+
" gaia memory delete project_old --yes\n"
|
|
1994
|
+
" gaia memory delete project_old --hard --yes\n"
|
|
1995
|
+
),
|
|
1944
1996
|
)
|
|
1945
1997
|
delete_p.add_argument("name", help="Curated memory slug.")
|
|
1946
1998
|
delete_p.add_argument("--workspace", default=None, metavar="W",
|
|
@@ -1949,6 +2001,11 @@ def register(subparsers):
|
|
|
1949
2001
|
"--yes", action="store_true", default=False,
|
|
1950
2002
|
help="Skip confirm prompt. bool. Default: false.",
|
|
1951
2003
|
)
|
|
2004
|
+
delete_p.add_argument(
|
|
2005
|
+
"--hard", action="store_true", default=False,
|
|
2006
|
+
help="Physically DELETE the row (irreversible). Default: false "
|
|
2007
|
+
"(soft-delete/tombstone).",
|
|
2008
|
+
)
|
|
1952
2009
|
delete_p.add_argument(
|
|
1953
2010
|
"--json", action="store_true", default=False,
|
|
1954
2011
|
help="Emit JSON. bool.",
|
|
@@ -2131,6 +2188,25 @@ def register(subparsers):
|
|
|
2131
2188
|
)
|
|
2132
2189
|
add_p.add_argument("--description", default=None,
|
|
2133
2190
|
help="Short summary. Shown in list.")
|
|
2191
|
+
_add_project_group = add_p.add_mutually_exclusive_group()
|
|
2192
|
+
_add_project_group.add_argument(
|
|
2193
|
+
"--project", default=None,
|
|
2194
|
+
help=(
|
|
2195
|
+
"N3: anchor this memory to a project by NAME (resolved within "
|
|
2196
|
+
"--workspace to its stable projects.project_identity, persisted "
|
|
2197
|
+
"as memory.project_ref). Forward-only: errors clearly if the "
|
|
2198
|
+
"project does not exist or has no project_identity yet -- never "
|
|
2199
|
+
"guesses. Mutually exclusive with --project-ref."
|
|
2200
|
+
),
|
|
2201
|
+
)
|
|
2202
|
+
_add_project_group.add_argument(
|
|
2203
|
+
"--project-ref", dest="project_ref", default=None,
|
|
2204
|
+
help=(
|
|
2205
|
+
"N3: anchor this memory directly to a known stable "
|
|
2206
|
+
"project_identity string, bypassing name resolution. Use "
|
|
2207
|
+
"--project instead unless you already hold the identity value."
|
|
2208
|
+
),
|
|
2209
|
+
)
|
|
2134
2210
|
add_p.add_argument(
|
|
2135
2211
|
"--class", dest="class_", default=None,
|
|
2136
2212
|
choices=("anchor", "thread", "log"),
|