aether-colony 5.0.0 → 5.1.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/.aether/aether-utils.sh +3150 -3349
- package/.aether/agents-claude/aether-ambassador.md +265 -0
- package/.aether/agents-claude/aether-archaeologist.md +327 -0
- package/.aether/agents-claude/aether-architect.md +236 -0
- package/.aether/agents-claude/aether-auditor.md +271 -0
- package/.aether/agents-claude/aether-builder.md +224 -0
- package/.aether/agents-claude/aether-chaos.md +269 -0
- package/.aether/agents-claude/aether-chronicler.md +305 -0
- package/.aether/agents-claude/aether-gatekeeper.md +330 -0
- package/.aether/agents-claude/aether-includer.md +374 -0
- package/.aether/agents-claude/aether-keeper.md +272 -0
- package/.aether/agents-claude/aether-measurer.md +322 -0
- package/.aether/agents-claude/aether-oracle.md +237 -0
- package/.aether/agents-claude/aether-probe.md +211 -0
- package/.aether/agents-claude/aether-queen.md +330 -0
- package/.aether/agents-claude/aether-route-setter.md +178 -0
- package/.aether/agents-claude/aether-sage.md +418 -0
- package/.aether/agents-claude/aether-scout.md +179 -0
- package/.aether/agents-claude/aether-surveyor-disciplines.md +417 -0
- package/.aether/agents-claude/aether-surveyor-nest.md +355 -0
- package/.aether/agents-claude/aether-surveyor-pathogens.md +289 -0
- package/.aether/agents-claude/aether-surveyor-provisions.md +360 -0
- package/.aether/agents-claude/aether-tracker.md +270 -0
- package/.aether/agents-claude/aether-watcher.md +280 -0
- package/.aether/agents-claude/aether-weaver.md +248 -0
- package/.aether/commands/archaeology.yaml +653 -0
- package/.aether/commands/build.yaml +1221 -0
- package/.aether/commands/chaos.yaml +653 -0
- package/.aether/commands/colonize.yaml +438 -0
- package/.aether/commands/continue.yaml +1484 -0
- package/.aether/commands/council.yaml +304 -0
- package/.aether/commands/data-clean.yaml +80 -0
- package/.aether/commands/dream.yaml +275 -0
- package/.aether/commands/entomb.yaml +863 -0
- package/.aether/commands/export-signals.yaml +64 -0
- package/.aether/commands/feedback.yaml +158 -0
- package/.aether/commands/flag.yaml +160 -0
- package/.aether/commands/flags.yaml +177 -0
- package/.aether/commands/focus.yaml +112 -0
- package/.aether/commands/help.yaml +167 -0
- package/.aether/commands/history.yaml +137 -0
- package/.aether/commands/import-signals.yaml +79 -0
- package/.aether/commands/init.yaml +469 -0
- package/.aether/commands/insert-phase.yaml +98 -0
- package/.aether/commands/interpret.yaml +285 -0
- package/.aether/commands/lay-eggs.yaml +224 -0
- package/.aether/commands/maturity.yaml +122 -0
- package/.aether/commands/memory-details.yaml +74 -0
- package/.aether/commands/migrate-state.yaml +174 -0
- package/.aether/commands/oracle.yaml +1224 -0
- package/.aether/commands/organize.yaml +446 -0
- package/.aether/commands/patrol.yaml +621 -0
- package/.aether/commands/pause-colony.yaml +424 -0
- package/.aether/commands/phase.yaml +124 -0
- package/.aether/commands/pheromones.yaml +153 -0
- package/.aether/commands/plan.yaml +1313 -0
- package/.aether/commands/preferences.yaml +63 -0
- package/.aether/commands/redirect.yaml +123 -0
- package/.aether/commands/resume-colony.yaml +373 -0
- package/.aether/commands/resume.yaml +398 -0
- package/.aether/commands/run.yaml +193 -0
- package/.aether/commands/seal.yaml +1205 -0
- package/.aether/commands/skill-create.yaml +337 -0
- package/.aether/commands/status.yaml +364 -0
- package/.aether/commands/swarm.yaml +352 -0
- package/.aether/commands/tunnels.yaml +814 -0
- package/.aether/commands/update.yaml +131 -0
- package/.aether/commands/verify-castes.yaml +159 -0
- package/.aether/commands/watch.yaml +454 -0
- package/.aether/docs/INCIDENT_TEMPLATE.md +32 -0
- package/.aether/docs/QUEEN-SYSTEM.md +11 -11
- package/.aether/docs/README.md +32 -2
- package/.aether/docs/command-playbooks/README.md +23 -0
- package/.aether/docs/command-playbooks/build-complete.md +349 -0
- package/.aether/docs/command-playbooks/build-context.md +282 -0
- package/.aether/docs/command-playbooks/build-full.md +1682 -0
- package/.aether/docs/command-playbooks/build-prep.md +283 -0
- package/.aether/docs/command-playbooks/build-verify.md +405 -0
- package/.aether/docs/command-playbooks/build-wave.md +749 -0
- package/.aether/docs/command-playbooks/continue-advance.md +524 -0
- package/.aether/docs/command-playbooks/continue-finalize.md +447 -0
- package/.aether/docs/command-playbooks/continue-full.md +1724 -0
- package/.aether/docs/command-playbooks/continue-gates.md +686 -0
- package/.aether/docs/command-playbooks/continue-verify.md +406 -0
- package/.aether/docs/context-continuity.md +84 -0
- package/.aether/docs/disciplines/DISCIPLINES.md +9 -7
- package/.aether/docs/error-codes.md +1 -1
- package/.aether/docs/known-issues.md +34 -173
- package/.aether/docs/pheromones.md +86 -6
- package/.aether/docs/plans/pheromone-display-plan.md +257 -0
- package/.aether/docs/queen-commands.md +10 -9
- package/.aether/docs/source-of-truth-map.md +132 -0
- package/.aether/docs/xml-utilities.md +47 -0
- package/.aether/rules/aether-colony.md +23 -13
- package/.aether/scripts/incident-test-add.sh +47 -0
- package/.aether/scripts/weekly-audit.sh +79 -0
- package/.aether/skills/.index.json +649 -0
- package/.aether/skills/colony/.manifest.json +16 -0
- package/.aether/skills/colony/build-discipline/SKILL.md +78 -0
- package/.aether/skills/colony/colony-interaction/SKILL.md +56 -0
- package/.aether/skills/colony/colony-lifecycle/SKILL.md +77 -0
- package/.aether/skills/colony/colony-visuals/SKILL.md +112 -0
- package/.aether/skills/colony/context-management/SKILL.md +80 -0
- package/.aether/skills/colony/error-presentation/SKILL.md +99 -0
- package/.aether/skills/colony/pheromone-protocol/SKILL.md +79 -0
- package/.aether/skills/colony/pheromone-visibility/SKILL.md +81 -0
- package/.aether/skills/colony/state-safety/SKILL.md +84 -0
- package/.aether/skills/colony/worker-priming/SKILL.md +82 -0
- package/.aether/skills/domain/.manifest.json +24 -0
- package/.aether/skills/domain/README.md +33 -0
- package/.aether/skills/domain/django/SKILL.md +49 -0
- package/.aether/skills/domain/docker/SKILL.md +52 -0
- package/.aether/skills/domain/golang/SKILL.md +52 -0
- package/.aether/skills/domain/graphql/SKILL.md +51 -0
- package/.aether/skills/domain/html-css/SKILL.md +48 -0
- package/.aether/skills/domain/nextjs/SKILL.md +45 -0
- package/.aether/skills/domain/nodejs/SKILL.md +53 -0
- package/.aether/skills/domain/postgresql/SKILL.md +53 -0
- package/.aether/skills/domain/prisma/SKILL.md +59 -0
- package/.aether/skills/domain/python/SKILL.md +50 -0
- package/.aether/skills/domain/rails/SKILL.md +52 -0
- package/.aether/skills/domain/react/SKILL.md +45 -0
- package/.aether/skills/domain/rest-api/SKILL.md +58 -0
- package/.aether/skills/domain/svelte/SKILL.md +47 -0
- package/.aether/skills/domain/tailwind/SKILL.md +45 -0
- package/.aether/skills/domain/testing/SKILL.md +53 -0
- package/.aether/skills/domain/typescript/SKILL.md +58 -0
- package/.aether/skills/domain/vue/SKILL.md +49 -0
- package/.aether/templates/QUEEN.md.template +23 -41
- package/.aether/templates/colony-state-reset.jq.template +1 -0
- package/.aether/templates/colony-state.template.json +4 -0
- package/.aether/templates/learning-observations.template.json +6 -0
- package/.aether/templates/midden.template.json +13 -0
- package/.aether/templates/pheromones.template.json +6 -0
- package/.aether/templates/session.template.json +9 -0
- package/.aether/utils/atomic-write.sh +63 -17
- package/.aether/utils/chamber-utils.sh +145 -2
- package/.aether/utils/emoji-audit.sh +166 -0
- package/.aether/utils/error-handler.sh +21 -7
- package/.aether/utils/file-lock.sh +182 -27
- package/.aether/utils/flag.sh +267 -0
- package/.aether/utils/hive.sh +572 -0
- package/.aether/utils/learning.sh +1928 -0
- package/.aether/utils/midden.sh +342 -0
- package/.aether/utils/oracle/oracle.md +168 -0
- package/.aether/utils/oracle/oracle.sh +1023 -0
- package/.aether/utils/pheromone.sh +2029 -0
- package/.aether/utils/queen.sh +1698 -0
- package/.aether/utils/scan.sh +860 -0
- package/.aether/utils/semantic-cli.sh +10 -8
- package/.aether/utils/session.sh +552 -0
- package/.aether/utils/skills.sh +509 -0
- package/.aether/utils/spawn-tree.sh +103 -271
- package/.aether/utils/spawn.sh +260 -0
- package/.aether/utils/state-api.sh +199 -0
- package/.aether/utils/state-loader.sh +8 -6
- package/.aether/utils/suggest.sh +611 -0
- package/.aether/utils/swarm-display.sh +10 -1
- package/.aether/utils/swarm.sh +1004 -0
- package/.aether/utils/watch-spawn-tree.sh +11 -2
- package/.aether/utils/xml-compose.sh +2 -2
- package/.aether/utils/xml-convert.sh +9 -5
- package/.aether/utils/xml-core.sh +5 -9
- package/.aether/utils/xml-query.sh +4 -4
- package/.aether/workers.md +86 -67
- package/.claude/agents/ant/aether-ambassador.md +2 -1
- package/.claude/agents/ant/aether-archaeologist.md +6 -1
- package/.claude/agents/ant/aether-architect.md +236 -0
- package/.claude/agents/ant/aether-auditor.md +6 -1
- package/.claude/agents/ant/aether-builder.md +38 -1
- package/.claude/agents/ant/aether-chaos.md +2 -1
- package/.claude/agents/ant/aether-chronicler.md +1 -0
- package/.claude/agents/ant/aether-gatekeeper.md +6 -1
- package/.claude/agents/ant/aether-includer.md +1 -0
- package/.claude/agents/ant/aether-keeper.md +1 -0
- package/.claude/agents/ant/aether-measurer.md +6 -1
- package/.claude/agents/ant/aether-oracle.md +237 -0
- package/.claude/agents/ant/aether-probe.md +2 -1
- package/.claude/agents/ant/aether-queen.md +6 -1
- package/.claude/agents/ant/aether-route-setter.md +6 -1
- package/.claude/agents/ant/aether-sage.md +68 -3
- package/.claude/agents/ant/aether-scout.md +38 -1
- package/.claude/agents/ant/aether-surveyor-disciplines.md +2 -1
- package/.claude/agents/ant/aether-surveyor-nest.md +2 -1
- package/.claude/agents/ant/aether-surveyor-pathogens.md +2 -1
- package/.claude/agents/ant/aether-surveyor-provisions.md +2 -1
- package/.claude/agents/ant/aether-tracker.md +6 -1
- package/.claude/agents/ant/aether-watcher.md +37 -1
- package/.claude/agents/ant/aether-weaver.md +2 -1
- package/.claude/commands/ant/archaeology.md +1 -8
- package/.claude/commands/ant/build.md +43 -1159
- package/.claude/commands/ant/chaos.md +1 -14
- package/.claude/commands/ant/colonize.md +1 -14
- package/.claude/commands/ant/continue.md +40 -1026
- package/.claude/commands/ant/council.md +9 -16
- package/.claude/commands/ant/data-clean.md +81 -0
- package/.claude/commands/ant/dream.md +12 -9
- package/.claude/commands/ant/entomb.md +62 -87
- package/.claude/commands/ant/export-signals.md +57 -0
- package/.claude/commands/ant/feedback.md +18 -0
- package/.claude/commands/ant/flag.md +12 -0
- package/.claude/commands/ant/flags.md +22 -8
- package/.claude/commands/ant/focus.md +18 -0
- package/.claude/commands/ant/help.md +40 -8
- package/.claude/commands/ant/history.md +3 -0
- package/.claude/commands/ant/import-signals.md +71 -0
- package/.claude/commands/ant/init.md +316 -191
- package/.claude/commands/ant/insert-phase.md +101 -0
- package/.claude/commands/ant/interpret.md +11 -0
- package/.claude/commands/ant/lay-eggs.md +167 -158
- package/.claude/commands/ant/maturity.md +22 -11
- package/.claude/commands/ant/memory-details.md +77 -0
- package/.claude/commands/ant/migrate-state.md +6 -0
- package/.claude/commands/ant/oracle.md +317 -62
- package/.claude/commands/ant/organize.md +10 -5
- package/.claude/commands/ant/patrol.md +620 -0
- package/.claude/commands/ant/pause-colony.md +8 -22
- package/.claude/commands/ant/phase.md +26 -37
- package/.claude/commands/ant/pheromones.md +156 -0
- package/.claude/commands/ant/plan.md +175 -52
- package/.claude/commands/ant/preferences.md +65 -0
- package/.claude/commands/ant/redirect.md +18 -0
- package/.claude/commands/ant/resume-colony.md +34 -20
- package/.claude/commands/ant/resume.md +51 -7
- package/.claude/commands/ant/run.md +195 -0
- package/.claude/commands/ant/seal.md +497 -78
- package/.claude/commands/ant/skill-create.md +286 -0
- package/.claude/commands/ant/status.md +127 -1
- package/.claude/commands/ant/swarm.md +11 -23
- package/.claude/commands/ant/tunnels.md +1 -0
- package/.claude/commands/ant/update.md +58 -135
- package/.claude/commands/ant/verify-castes.md +90 -42
- package/.claude/commands/ant/watch.md +1 -0
- package/.opencode/agents/aether-ambassador.md +1 -1
- package/.opencode/agents/aether-architect.md +133 -0
- package/.opencode/agents/aether-builder.md +3 -3
- package/.opencode/agents/aether-oracle.md +137 -0
- package/.opencode/agents/aether-queen.md +1 -1
- package/.opencode/agents/aether-route-setter.md +1 -1
- package/.opencode/agents/aether-scout.md +1 -1
- package/.opencode/agents/aether-surveyor-disciplines.md +6 -1
- package/.opencode/agents/aether-surveyor-nest.md +6 -1
- package/.opencode/agents/aether-surveyor-pathogens.md +6 -1
- package/.opencode/agents/aether-surveyor-provisions.md +6 -1
- package/.opencode/agents/aether-tracker.md +1 -1
- package/.opencode/agents/aether-watcher.md +1 -1
- package/.opencode/agents/aether-weaver.md +1 -1
- package/.opencode/commands/ant/archaeology.md +7 -14
- package/.opencode/commands/ant/build.md +54 -88
- package/.opencode/commands/ant/chaos.md +7 -24
- package/.opencode/commands/ant/colonize.md +8 -17
- package/.opencode/commands/ant/continue.md +595 -66
- package/.opencode/commands/ant/council.md +11 -22
- package/.opencode/commands/ant/data-clean.md +77 -0
- package/.opencode/commands/ant/dream.md +15 -17
- package/.opencode/commands/ant/entomb.md +28 -18
- package/.opencode/commands/ant/export-signals.md +54 -0
- package/.opencode/commands/ant/feedback.md +24 -5
- package/.opencode/commands/ant/flag.md +16 -4
- package/.opencode/commands/ant/flags.md +24 -10
- package/.opencode/commands/ant/focus.md +22 -5
- package/.opencode/commands/ant/help.md +41 -8
- package/.opencode/commands/ant/history.md +9 -0
- package/.opencode/commands/ant/import-signals.md +68 -0
- package/.opencode/commands/ant/init.md +365 -156
- package/.opencode/commands/ant/insert-phase.md +107 -0
- package/.opencode/commands/ant/interpret.md +16 -0
- package/.opencode/commands/ant/lay-eggs.md +184 -112
- package/.opencode/commands/ant/maturity.md +18 -2
- package/.opencode/commands/ant/memory-details.md +83 -0
- package/.opencode/commands/ant/migrate-state.md +12 -0
- package/.opencode/commands/ant/oracle.md +322 -67
- package/.opencode/commands/ant/organize.md +14 -12
- package/.opencode/commands/ant/patrol.md +626 -0
- package/.opencode/commands/ant/pause-colony.md +12 -29
- package/.opencode/commands/ant/phase.md +30 -40
- package/.opencode/commands/ant/pheromones.md +162 -0
- package/.opencode/commands/ant/plan.md +184 -56
- package/.opencode/commands/ant/preferences.md +71 -0
- package/.opencode/commands/ant/redirect.md +22 -5
- package/.opencode/commands/ant/resume-colony.md +38 -27
- package/.opencode/commands/ant/resume.md +71 -20
- package/.opencode/commands/ant/run.md +201 -0
- package/.opencode/commands/ant/seal.md +230 -25
- package/.opencode/commands/ant/skill-create.md +63 -0
- package/.opencode/commands/ant/status.md +124 -31
- package/.opencode/commands/ant/swarm.md +3 -345
- package/.opencode/commands/ant/tunnels.md +3 -9
- package/.opencode/commands/ant/update.md +63 -127
- package/.opencode/commands/ant/verify-castes.md +96 -42
- package/.opencode/commands/ant/watch.md +7 -0
- package/CHANGELOG.md +278 -1
- package/README.md +188 -340
- package/bin/cli.js +236 -429
- package/bin/generate-commands.js +186 -0
- package/bin/generate-commands.sh +128 -89
- package/bin/lib/spawn-logger.js +0 -15
- package/bin/lib/update-transaction.js +285 -35
- package/bin/npx-install.js +178 -0
- package/bin/validate-package.sh +85 -3
- package/package.json +7 -3
- package/.aether/CONTEXT.md +0 -160
- package/.aether/docs/QUEEN.md +0 -84
- package/.aether/exchange/colony-registry.xml +0 -11
- package/.aether/exchange/pheromones.xml +0 -87
- package/.aether/exchange/queen-wisdom.xml +0 -14
- package/.aether/model-profiles.yaml +0 -100
- package/.aether/utils/spawn-with-model.sh +0 -56
- package/bin/lib/model-profiles.js +0 -445
- package/bin/lib/model-verify.js +0 -288
- package/bin/lib/proxy-health.js +0 -253
- package/bin/lib/telemetry.js +0 -441
|
@@ -74,7 +74,7 @@ semantic-index() {
|
|
|
74
74
|
local entry_id="${3:-}"
|
|
75
75
|
|
|
76
76
|
if [[ -z "$text" ]]; then
|
|
77
|
-
|
|
77
|
+
semantic_json_err 1 "semantic-index requires text argument"
|
|
78
78
|
return 1
|
|
79
79
|
fi
|
|
80
80
|
|
|
@@ -161,12 +161,12 @@ semantic-search() {
|
|
|
161
161
|
local source_filter="${4:-}"
|
|
162
162
|
|
|
163
163
|
if [[ -z "$query" ]]; then
|
|
164
|
-
|
|
164
|
+
semantic_json_err 1 "semantic-search requires query argument"
|
|
165
165
|
return 1
|
|
166
166
|
fi
|
|
167
167
|
|
|
168
168
|
if [[ ! -f "$SEMANTIC_EMBEDDINGS_FILE" ]]; then
|
|
169
|
-
|
|
169
|
+
semantic_json_ok '{"results":[]}' "No semantic index found. Run semantic-init first."
|
|
170
170
|
return 0
|
|
171
171
|
fi
|
|
172
172
|
|
|
@@ -236,7 +236,7 @@ semantic-find-duplicate() {
|
|
|
236
236
|
local threshold="${2:-0.85}"
|
|
237
237
|
|
|
238
238
|
if [[ -z "$text" ]]; then
|
|
239
|
-
|
|
239
|
+
semantic_json_err 1 "semantic-find-duplicate requires text argument"
|
|
240
240
|
return 1
|
|
241
241
|
fi
|
|
242
242
|
|
|
@@ -249,7 +249,7 @@ semantic-find-duplicate() {
|
|
|
249
249
|
if [[ "$count" -gt 0 ]]; then
|
|
250
250
|
echo "$result" | jq '. + {"is_duplicate": true}'
|
|
251
251
|
else
|
|
252
|
-
|
|
252
|
+
semantic_json_ok "[]" "No duplicates found"
|
|
253
253
|
fi
|
|
254
254
|
}
|
|
255
255
|
|
|
@@ -368,7 +368,7 @@ semantic-get-context() {
|
|
|
368
368
|
# Check semantic layer status
|
|
369
369
|
semantic-status() {
|
|
370
370
|
if [[ ! -f "$SEMANTIC_DATA_DIR/index.json" ]]; then
|
|
371
|
-
|
|
371
|
+
semantic_json_ok '{"initialized": false, "message": "Run semantic-init to initialize"}'
|
|
372
372
|
return 0
|
|
373
373
|
fi
|
|
374
374
|
|
|
@@ -387,7 +387,7 @@ semantic-status() {
|
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
# Helper: Output JSON OK response
|
|
390
|
-
|
|
390
|
+
semantic_json_ok() {
|
|
391
391
|
local result="${1:-}"
|
|
392
392
|
local message="${2:-}"
|
|
393
393
|
jq -n --argjson result "$result" --arg message "$message" \
|
|
@@ -395,7 +395,7 @@ json_ok() {
|
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
# Helper: Output JSON error response
|
|
398
|
-
|
|
398
|
+
semantic_json_err() {
|
|
399
399
|
local code="${1:-1}"
|
|
400
400
|
local message="${2:-Unknown error}"
|
|
401
401
|
jq -n --arg code "$code" --arg message "$message" \
|
|
@@ -411,3 +411,5 @@ export -f semantic-rebuild
|
|
|
411
411
|
export -f semantic-get-context
|
|
412
412
|
export -f semantic-status
|
|
413
413
|
export -f semantic-check-deps
|
|
414
|
+
export -f semantic_json_ok
|
|
415
|
+
export -f semantic_json_err
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Session utility functions -- extracted from aether-utils.sh
|
|
3
|
+
# Provides: _session_verify_fresh, _session_clear, _session_init, _session_update,
|
|
4
|
+
# _session_read, _session_is_stale, _session_clear_context,
|
|
5
|
+
# _session_mark_resumed, _session_summary
|
|
6
|
+
# Also includes: _rotate_spawn_tree (helper used only by _session_init)
|
|
7
|
+
|
|
8
|
+
# ============================================================================
|
|
9
|
+
# _session_verify_fresh
|
|
10
|
+
# Generic session freshness verification
|
|
11
|
+
# Usage: _session_verify_fresh [args...] (same args as before: --command <name> [--force] <session_start_unixtime>)
|
|
12
|
+
# Returns: JSON with pass/fail status and file details
|
|
13
|
+
# ============================================================================
|
|
14
|
+
_session_verify_fresh() {
|
|
15
|
+
# Parse arguments
|
|
16
|
+
local command_name=""
|
|
17
|
+
local force_mode=""
|
|
18
|
+
local session_start_time=""
|
|
19
|
+
|
|
20
|
+
while [[ $# -gt 0 ]]; do
|
|
21
|
+
case "$1" in
|
|
22
|
+
--command) command_name="$2"; shift 2 ;;
|
|
23
|
+
--force) force_mode="--force"; shift ;;
|
|
24
|
+
*) session_start_time="$1"; shift ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
|
|
28
|
+
# Validate command name
|
|
29
|
+
[[ -z "$command_name" ]] && json_err "$E_VALIDATION_FAILED" "Usage: session-verify-fresh --command <name> [--force] <session_start>"
|
|
30
|
+
|
|
31
|
+
# Map command to directory and files (using env var override pattern)
|
|
32
|
+
local session_dir required_docs
|
|
33
|
+
case "$command_name" in
|
|
34
|
+
survey)
|
|
35
|
+
session_dir="${SURVEY_DIR:-.aether/data/survey}"
|
|
36
|
+
required_docs="PROVISIONS.md TRAILS.md BLUEPRINT.md CHAMBERS.md DISCIPLINES.md SENTINEL-PROTOCOLS.md PATHOGENS.md"
|
|
37
|
+
;;
|
|
38
|
+
oracle)
|
|
39
|
+
session_dir="${ORACLE_DIR:-.aether/oracle}"
|
|
40
|
+
required_docs="state.json plan.json gaps.md synthesis.md research-plan.md"
|
|
41
|
+
;;
|
|
42
|
+
watch)
|
|
43
|
+
session_dir="${WATCH_DIR:-.aether/data}"
|
|
44
|
+
required_docs="watch-status.txt watch-progress.txt"
|
|
45
|
+
;;
|
|
46
|
+
swarm)
|
|
47
|
+
session_dir="${SWARM_DIR:-.aether/data/swarm}"
|
|
48
|
+
required_docs="findings.json"
|
|
49
|
+
;;
|
|
50
|
+
init)
|
|
51
|
+
session_dir="${INIT_DIR:-.aether/data}"
|
|
52
|
+
required_docs="COLONY_STATE.json constraints.json"
|
|
53
|
+
;;
|
|
54
|
+
seal|entomb)
|
|
55
|
+
session_dir="${ARCHIVE_DIR:-.aether/data/archive}"
|
|
56
|
+
required_docs="manifest.json"
|
|
57
|
+
;;
|
|
58
|
+
*)
|
|
59
|
+
json_err "$E_VALIDATION_FAILED" "Unknown command: $command_name" '{"commands":["survey","oracle","watch","swarm","init","seal","entomb"]}'
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
|
|
63
|
+
# Initialize result arrays
|
|
64
|
+
local fresh_docs=""
|
|
65
|
+
local stale_docs=""
|
|
66
|
+
local missing_docs=""
|
|
67
|
+
local total_lines=0
|
|
68
|
+
|
|
69
|
+
for doc in $required_docs; do
|
|
70
|
+
local doc_path="$session_dir/$doc"
|
|
71
|
+
|
|
72
|
+
if [[ ! -f "$doc_path" ]]; then
|
|
73
|
+
missing_docs="${missing_docs:+$missing_docs }$doc"
|
|
74
|
+
continue
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Get line count
|
|
78
|
+
local lines
|
|
79
|
+
lines=$(wc -l < "$doc_path" 2>/dev/null | tr -d ' ' || echo "0") # SUPPRESS:OK -- read-default: file may not exist
|
|
80
|
+
total_lines=$((total_lines + lines))
|
|
81
|
+
|
|
82
|
+
# In force mode, accept any existing file
|
|
83
|
+
if [[ "$force_mode" == "--force" ]]; then
|
|
84
|
+
fresh_docs="${fresh_docs:+$fresh_docs }$doc"
|
|
85
|
+
continue
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Check timestamp if session_start_time provided
|
|
89
|
+
if [[ -n "$session_start_time" ]]; then
|
|
90
|
+
# Cross-platform stat: macOS uses -f %m, Linux uses -c %Y
|
|
91
|
+
local file_mtime
|
|
92
|
+
file_mtime=$(stat -f %m "$doc_path" 2>/dev/null || stat -c %Y "$doc_path" 2>/dev/null || echo "0") # SUPPRESS:OK -- cross-platform: macOS stat syntax
|
|
93
|
+
|
|
94
|
+
if [[ "$file_mtime" -ge "$session_start_time" ]]; then
|
|
95
|
+
fresh_docs="${fresh_docs:+$fresh_docs }$doc"
|
|
96
|
+
else
|
|
97
|
+
stale_docs="${stale_docs:+$stale_docs }$doc"
|
|
98
|
+
fi
|
|
99
|
+
else
|
|
100
|
+
# No start time provided - accept existing file (backward compatible)
|
|
101
|
+
fresh_docs="${fresh_docs:+$fresh_docs }$doc"
|
|
102
|
+
fi
|
|
103
|
+
done
|
|
104
|
+
|
|
105
|
+
# Determine pass/fail
|
|
106
|
+
# pass = true if: no stale files (fresh files can coexist with missing files)
|
|
107
|
+
# missing files are ok - they will be created during the session
|
|
108
|
+
local pass=false
|
|
109
|
+
if [[ "$force_mode" == "--force" ]] || [[ -z "$stale_docs" ]]; then
|
|
110
|
+
pass=true
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Build JSON response
|
|
114
|
+
local fresh_json=""
|
|
115
|
+
for item in $fresh_docs; do fresh_json="$fresh_json\"$item\","; done
|
|
116
|
+
fresh_json="[${fresh_json%,}]"
|
|
117
|
+
|
|
118
|
+
local stale_json=""
|
|
119
|
+
for item in $stale_docs; do stale_json="$stale_json\"$item\","; done
|
|
120
|
+
stale_json="[${stale_json%,}]"
|
|
121
|
+
|
|
122
|
+
local missing_json=""
|
|
123
|
+
for item in $missing_docs; do missing_json="$missing_json\"$item\","; done
|
|
124
|
+
missing_json="[${missing_json%,}]"
|
|
125
|
+
|
|
126
|
+
echo "$(jq -n --argjson ok "$pass" --arg command "$command_name" \
|
|
127
|
+
--argjson fresh "$fresh_json" --argjson stale "$stale_json" \
|
|
128
|
+
--argjson missing "$missing_json" --argjson total_lines "$total_lines" \
|
|
129
|
+
'{ok: $ok, command: $command, fresh: $fresh, stale: $stale, missing: $missing, total_lines: $total_lines}')"
|
|
130
|
+
exit 0
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# ============================================================================
|
|
134
|
+
# _session_clear
|
|
135
|
+
# Generic session file clearing
|
|
136
|
+
# Usage: _session_clear [args...] (same args as before: --command <name> [--dry-run])
|
|
137
|
+
# ============================================================================
|
|
138
|
+
_session_clear() {
|
|
139
|
+
# Parse arguments
|
|
140
|
+
local command_name=""
|
|
141
|
+
local dry_run=""
|
|
142
|
+
|
|
143
|
+
while [[ $# -gt 0 ]]; do
|
|
144
|
+
case "$1" in
|
|
145
|
+
--command) command_name="$2"; shift 2 ;;
|
|
146
|
+
--dry-run) dry_run="--dry-run"; shift ;;
|
|
147
|
+
*) shift ;;
|
|
148
|
+
esac
|
|
149
|
+
done
|
|
150
|
+
|
|
151
|
+
[[ -z "$command_name" ]] && json_err "$E_VALIDATION_FAILED" "Usage: session-clear --command <name> [--dry-run]"
|
|
152
|
+
|
|
153
|
+
# Map command to directory and files
|
|
154
|
+
local session_dir="" files="" subdir_files=""
|
|
155
|
+
case "$command_name" in
|
|
156
|
+
survey)
|
|
157
|
+
session_dir="${SURVEY_DIR:-.aether/data/survey}"
|
|
158
|
+
files="PROVISIONS.md TRAILS.md BLUEPRINT.md CHAMBERS.md DISCIPLINES.md SENTINEL-PROTOCOLS.md PATHOGENS.md"
|
|
159
|
+
;;
|
|
160
|
+
oracle)
|
|
161
|
+
session_dir="${ORACLE_DIR:-.aether/oracle}"
|
|
162
|
+
files="state.json plan.json gaps.md synthesis.md research-plan.md .stop .last-topic"
|
|
163
|
+
# Also clear discoveries subdirectory
|
|
164
|
+
subdir_files="discoveries/*"
|
|
165
|
+
;;
|
|
166
|
+
watch)
|
|
167
|
+
session_dir="${WATCH_DIR:-.aether/data}"
|
|
168
|
+
files="watch-status.txt watch-progress.txt"
|
|
169
|
+
;;
|
|
170
|
+
swarm)
|
|
171
|
+
session_dir="${SWARM_DIR:-.aether/data/swarm}"
|
|
172
|
+
files="findings.json display.json timing.json"
|
|
173
|
+
;;
|
|
174
|
+
init)
|
|
175
|
+
# Init clear is destructive - blocked for auto-clear
|
|
176
|
+
json_err "$E_VALIDATION_FAILED" "Command 'init' is protected and cannot be auto-cleared. Use manual removal of COLONY_STATE.json if absolutely necessary."
|
|
177
|
+
;;
|
|
178
|
+
seal|entomb)
|
|
179
|
+
# Archive operations should never be auto-cleared
|
|
180
|
+
json_err "$E_VALIDATION_FAILED" "Command '$command_name' is protected and cannot be auto-cleared. Archives and chambers must be managed manually."
|
|
181
|
+
;;
|
|
182
|
+
*)
|
|
183
|
+
json_err "$E_VALIDATION_FAILED" "Unknown command: $command_name"
|
|
184
|
+
;;
|
|
185
|
+
esac
|
|
186
|
+
|
|
187
|
+
local cleared=""
|
|
188
|
+
local errors=""
|
|
189
|
+
|
|
190
|
+
if [[ -d "$session_dir" && -n "$files" ]]; then
|
|
191
|
+
for doc in $files; do
|
|
192
|
+
local doc_path="$session_dir/$doc"
|
|
193
|
+
if [[ -f "$doc_path" ]]; then
|
|
194
|
+
if [[ "$dry_run" == "--dry-run" ]]; then
|
|
195
|
+
cleared="$cleared $doc"
|
|
196
|
+
else
|
|
197
|
+
if rm -f "$doc_path" 2>/dev/null; then # SUPPRESS:OK -- cleanup: file may not exist
|
|
198
|
+
cleared="$cleared $doc"
|
|
199
|
+
else
|
|
200
|
+
errors="$errors $doc"
|
|
201
|
+
fi
|
|
202
|
+
fi
|
|
203
|
+
fi
|
|
204
|
+
done
|
|
205
|
+
|
|
206
|
+
# Handle oracle discoveries subdirectory
|
|
207
|
+
if [[ "$command_name" == "oracle" && -d "$session_dir/discoveries" ]]; then
|
|
208
|
+
if [[ "$dry_run" == "--dry-run" ]]; then
|
|
209
|
+
cleared="$cleared discoveries/"
|
|
210
|
+
else
|
|
211
|
+
# SUPPRESS:OK -- cleanup: file may not exist
|
|
212
|
+
rm -rf "$session_dir/discoveries" 2>/dev/null && cleared="$cleared discoveries/" || errors="$errors discoveries/"
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
local dry_run_bool=$([[ "$dry_run" == "--dry-run" ]] && echo "true" || echo "false")
|
|
218
|
+
json_ok "$(jq -n --arg command "$command_name" --arg cleared "${cleared// /}" \
|
|
219
|
+
--arg errors "${errors// /}" --argjson dry_run "$dry_run_bool" \
|
|
220
|
+
'{command: $command, cleared: $cleared, errors: $errors, dry_run: $dry_run}')"
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# ============================================================================
|
|
224
|
+
# _rotate_spawn_tree (helper -- used only by _session_init)
|
|
225
|
+
# ARCH-03: Rotate spawn-tree.txt at session start to prevent unbounded growth.
|
|
226
|
+
# Archives previous session's tree to a timestamped file; caps archive count at 5.
|
|
227
|
+
# ============================================================================
|
|
228
|
+
_rotate_spawn_tree() {
|
|
229
|
+
local tree_file="$COLONY_DATA_DIR/spawn-tree.txt"
|
|
230
|
+
[[ -f "$tree_file" ]] && [[ -s "$tree_file" ]] || return 0
|
|
231
|
+
mkdir -p "$COLONY_DATA_DIR/spawn-tree-archive"
|
|
232
|
+
local archive_ts
|
|
233
|
+
archive_ts=$(date +%Y%m%d_%H%M%S)
|
|
234
|
+
if ! cp "$tree_file" "$COLONY_DATA_DIR/spawn-tree-archive/spawn-tree.${archive_ts}.txt" 2>/dev/null; then # SUPPRESS:OK -- cleanup: backup copy is best-effort
|
|
235
|
+
_aether_log_error "Could not archive spawn-tree before rotation"
|
|
236
|
+
fi
|
|
237
|
+
> "$tree_file" # Truncate in-place — preserves file handle for tail -f watchers
|
|
238
|
+
# Keep only 5 archives
|
|
239
|
+
# SUPPRESS:OK -- read-default: directory may not exist
|
|
240
|
+
# SUPPRESS:OK -- cleanup: rotation cleanup is best-effort
|
|
241
|
+
ls -t "$COLONY_DATA_DIR/spawn-tree-archive"/spawn-tree.*.txt 2>/dev/null \
|
|
242
|
+
| tail -n +6 | while IFS= read -r file; do rm -f "$file"; done 2>/dev/null || true # SUPPRESS:OK -- cleanup: file may not exist
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
# ============================================================================
|
|
246
|
+
# _session_init
|
|
247
|
+
# Initialize a new session tracking file
|
|
248
|
+
# Usage: _session_init [session_id] [goal]
|
|
249
|
+
# ============================================================================
|
|
250
|
+
_session_init() {
|
|
251
|
+
local session_id="${1:-$(date +%s)_$(openssl rand -hex 4 2>/dev/null || echo $$)}" # SUPPRESS:OK -- read-default: openssl may not be available
|
|
252
|
+
local goal="${2:-}"
|
|
253
|
+
|
|
254
|
+
_rotate_spawn_tree
|
|
255
|
+
|
|
256
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
257
|
+
local baseline
|
|
258
|
+
baseline=$(git rev-parse HEAD 2>/dev/null || echo "") # SUPPRESS:OK -- read-default: may not have commits yet
|
|
259
|
+
|
|
260
|
+
jq -n --arg sid "$session_id" --arg started "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
261
|
+
--arg goal "$goal" --arg baseline "$baseline" \
|
|
262
|
+
'{
|
|
263
|
+
session_id: $sid,
|
|
264
|
+
started_at: $started,
|
|
265
|
+
last_command: null,
|
|
266
|
+
last_command_at: null,
|
|
267
|
+
colony_goal: $goal,
|
|
268
|
+
current_phase: 0,
|
|
269
|
+
current_milestone: "First Mound",
|
|
270
|
+
suggested_next: "/ant:plan",
|
|
271
|
+
context_cleared: false,
|
|
272
|
+
baseline_commit: $baseline,
|
|
273
|
+
resumed_at: null,
|
|
274
|
+
active_todos: [],
|
|
275
|
+
summary: "Session initialized"
|
|
276
|
+
}' > "$session_file.tmp"
|
|
277
|
+
mv "$session_file.tmp" "$session_file"
|
|
278
|
+
json_ok "$(jq -n --arg sid "$session_id" --arg goal "$goal" --arg file "$session_file" \
|
|
279
|
+
'{session_id: $sid, goal: $goal, file: $file}')"
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# ============================================================================
|
|
283
|
+
# _session_update
|
|
284
|
+
# Update session with latest activity
|
|
285
|
+
# Usage: _session_update <command> [suggested_next] [summary]
|
|
286
|
+
# ============================================================================
|
|
287
|
+
_session_update() {
|
|
288
|
+
local cmd_run="${1:-}"
|
|
289
|
+
local suggested="${2:-}"
|
|
290
|
+
local summary="${3:-}"
|
|
291
|
+
|
|
292
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
293
|
+
|
|
294
|
+
if [[ ! -f "$session_file" ]]; then
|
|
295
|
+
# Auto-initialize if doesn't exist
|
|
296
|
+
bash "$SCRIPT_DIR/aether-utils.sh" session-init "auto_$(date +%s)" ""
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
# Read current session
|
|
300
|
+
local current_session
|
|
301
|
+
current_session=$(cat "$session_file" 2>/dev/null || echo '{}') # SUPPRESS:OK -- read-default: file may not exist yet
|
|
302
|
+
|
|
303
|
+
# Extract current values for preservation
|
|
304
|
+
local current_goal current_phase current_milestone
|
|
305
|
+
current_goal=$(sanitize_read_value "$(echo "$current_session" | jq -r '.colony_goal // empty')")
|
|
306
|
+
current_phase=$(echo "$current_session" | jq -r '.current_phase // 0')
|
|
307
|
+
current_milestone=$(echo "$current_session" | jq -r '.current_milestone // "First Mound"')
|
|
308
|
+
|
|
309
|
+
# Get top 3 TODOs if TO-DOs.md exists
|
|
310
|
+
local todos="[]"
|
|
311
|
+
if [[ -f "TO-DOs.md" ]]; then
|
|
312
|
+
todos=$(grep "^### " TO-DOs.md 2>/dev/null | head -3 | sed 's/^### //' | jq -R . | jq -s .) # SUPPRESS:OK -- existence-test: file may not exist
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
# MIGRATE: direct COLONY_STATE.json access -- use _state_read_field instead
|
|
316
|
+
# Get colony state if exists
|
|
317
|
+
if [[ -f "$DATA_DIR/COLONY_STATE.json" ]]; then
|
|
318
|
+
# SUPPRESS:OK -- read-default: query may return empty
|
|
319
|
+
current_goal=$(sanitize_read_value "$(jq -r '.goal // empty' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null || echo "$current_goal")")
|
|
320
|
+
# SUPPRESS:OK -- read-default: query may return empty
|
|
321
|
+
current_phase=$(jq -r '.current_phase // 0' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null || echo "$current_phase")
|
|
322
|
+
# SUPPRESS:OK -- read-default: query may return empty
|
|
323
|
+
current_milestone=$(jq -r '.milestone // "First Mound"' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null || echo "$current_milestone")
|
|
324
|
+
fi
|
|
325
|
+
|
|
326
|
+
# Capture current git HEAD for drift detection
|
|
327
|
+
local baseline
|
|
328
|
+
baseline=$(git rev-parse HEAD 2>/dev/null || echo "") # SUPPRESS:OK -- read-default: may not have commits yet
|
|
329
|
+
|
|
330
|
+
# Build updated session
|
|
331
|
+
echo "$current_session" | jq --arg cmd "$cmd_run" \
|
|
332
|
+
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
333
|
+
--arg suggested "$suggested" \
|
|
334
|
+
--arg summary "$summary" \
|
|
335
|
+
--arg goal "$current_goal" \
|
|
336
|
+
--argjson phase "$current_phase" \
|
|
337
|
+
--arg milestone "$current_milestone" \
|
|
338
|
+
--argjson todos "$todos" \
|
|
339
|
+
--arg baseline "$baseline" \
|
|
340
|
+
'.last_command = $cmd |
|
|
341
|
+
.last_command_at = $ts |
|
|
342
|
+
.suggested_next = $suggested |
|
|
343
|
+
.summary = $summary |
|
|
344
|
+
.colony_goal = $goal |
|
|
345
|
+
.current_phase = $phase |
|
|
346
|
+
.current_milestone = $milestone |
|
|
347
|
+
.active_todos = $todos |
|
|
348
|
+
.baseline_commit = $baseline' > "$session_file.tmp" || {
|
|
349
|
+
_aether_log_error "Could not process session update"
|
|
350
|
+
rm -f "$session_file.tmp"
|
|
351
|
+
json_err "$E_UNKNOWN" "Failed to update session file"
|
|
352
|
+
}
|
|
353
|
+
[[ -s "$session_file.tmp" ]] || {
|
|
354
|
+
_aether_log_error "Session update produced empty result -- not overwriting"
|
|
355
|
+
rm -f "$session_file.tmp"
|
|
356
|
+
json_err "$E_JSON_INVALID" "Session update produced empty result"
|
|
357
|
+
}
|
|
358
|
+
mv "$session_file.tmp" "$session_file" || {
|
|
359
|
+
_aether_log_error "Could not finalize session file update"
|
|
360
|
+
rm -f "$session_file.tmp"
|
|
361
|
+
json_err "$E_UNKNOWN" "Failed to rename temporary session file"
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
json_ok "$(jq -n --arg cmd "$cmd_run" '{updated: true, command: $cmd}')"
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
# ============================================================================
|
|
368
|
+
# _session_read
|
|
369
|
+
# Read and return current session state
|
|
370
|
+
# ============================================================================
|
|
371
|
+
_session_read() {
|
|
372
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
373
|
+
|
|
374
|
+
if [[ ! -f "$session_file" ]]; then
|
|
375
|
+
json_ok "{\"exists\":false,\"session\":null}"
|
|
376
|
+
exit 0
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
local session_data
|
|
380
|
+
session_data=$(cat "$session_file" 2>/dev/null || echo '{}') # SUPPRESS:OK -- read-default: file may not exist yet
|
|
381
|
+
|
|
382
|
+
# Check if stale (> 24 hours)
|
|
383
|
+
local last_cmd_ts="" is_stale="" age_hours=""
|
|
384
|
+
last_cmd_ts=$(echo "$session_data" | jq -r '.last_command_at // .started_at // empty')
|
|
385
|
+
if [[ -n "$last_cmd_ts" ]]; then
|
|
386
|
+
local last_epoch=0 now_epoch=0
|
|
387
|
+
# SUPPRESS:OK -- cross-platform: macOS date syntax
|
|
388
|
+
# SUPPRESS:OK -- cross-platform: macOS vs Linux date/stat flags
|
|
389
|
+
last_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$last_cmd_ts" +%s 2>/dev/null \
|
|
390
|
+
|| date -d "$last_cmd_ts" +%s 2>/dev/null \
|
|
391
|
+
|| echo 0)
|
|
392
|
+
now_epoch=$(date +%s)
|
|
393
|
+
age_hours=$(( (now_epoch - last_epoch) / 3600 ))
|
|
394
|
+
[[ $age_hours -gt 24 ]] && is_stale=true || is_stale=false
|
|
395
|
+
else
|
|
396
|
+
is_stale="false"
|
|
397
|
+
age_hours="unknown"
|
|
398
|
+
fi
|
|
399
|
+
|
|
400
|
+
json_ok "$(jq -n --argjson is_stale "$is_stale" --argjson age "$age_hours" \
|
|
401
|
+
--argjson session "$session_data" \
|
|
402
|
+
'{exists: true, is_stale: $is_stale, age_hours: $age, session: $session}')"
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
# ============================================================================
|
|
406
|
+
# _session_is_stale
|
|
407
|
+
# Check if session is stale (returns JSON with is_stale boolean)
|
|
408
|
+
# ============================================================================
|
|
409
|
+
_session_is_stale() {
|
|
410
|
+
_deprecation_warning "session-is-stale"
|
|
411
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
412
|
+
|
|
413
|
+
if [[ ! -f "$session_file" ]]; then
|
|
414
|
+
json_ok '{"is_stale":true}'
|
|
415
|
+
exit 0
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
local last_cmd_ts
|
|
419
|
+
last_cmd_ts=$(jq -r '.last_command_at // .started_at // empty' "$session_file" 2>/dev/null) # SUPPRESS:OK -- read-default: file may not exist yet
|
|
420
|
+
|
|
421
|
+
if [[ -z "$last_cmd_ts" ]]; then
|
|
422
|
+
json_ok '{"is_stale":true}'
|
|
423
|
+
exit 0
|
|
424
|
+
fi
|
|
425
|
+
|
|
426
|
+
# macOS uses -j -f, Linux uses -d
|
|
427
|
+
# SUPPRESS:OK -- cross-platform: macOS date syntax
|
|
428
|
+
# SUPPRESS:OK -- cross-platform: macOS vs Linux date/stat flags
|
|
429
|
+
local last_epoch now_epoch age_hours
|
|
430
|
+
last_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$last_cmd_ts" +%s 2>/dev/null \
|
|
431
|
+
|| date -d "$last_cmd_ts" +%s 2>/dev/null \
|
|
432
|
+
|| echo 0)
|
|
433
|
+
now_epoch=$(date +%s)
|
|
434
|
+
age_hours=$(( (now_epoch - last_epoch) / 3600 ))
|
|
435
|
+
|
|
436
|
+
if [[ $age_hours -gt 24 ]]; then
|
|
437
|
+
json_ok '{"is_stale":true}'
|
|
438
|
+
else
|
|
439
|
+
json_ok '{"is_stale":false}'
|
|
440
|
+
fi
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
# ============================================================================
|
|
444
|
+
# _session_clear_context
|
|
445
|
+
# Mark session context as cleared (preserves file but marks context_cleared)
|
|
446
|
+
# ============================================================================
|
|
447
|
+
_session_clear_context() {
|
|
448
|
+
_deprecation_warning "session-clear-context"
|
|
449
|
+
local preserve="${1:-false}"
|
|
450
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
451
|
+
|
|
452
|
+
if [[ -f "$session_file" ]]; then
|
|
453
|
+
if [[ "$preserve" == "true" ]]; then
|
|
454
|
+
# Just mark as cleared
|
|
455
|
+
jq '.context_cleared = true' "$session_file" > "$session_file.tmp" || {
|
|
456
|
+
_aether_log_error "Could not mark session as cleared"
|
|
457
|
+
rm -f "$session_file.tmp"
|
|
458
|
+
}
|
|
459
|
+
if [[ -s "$session_file.tmp" ]]; then
|
|
460
|
+
mv "$session_file.tmp" "$session_file" || _aether_log_error "Could not finalize session clear"
|
|
461
|
+
fi
|
|
462
|
+
json_ok "{\"cleared\":true,\"preserved\":true}"
|
|
463
|
+
else
|
|
464
|
+
# Remove file entirely
|
|
465
|
+
rm -f "$session_file"
|
|
466
|
+
json_ok "{\"cleared\":true,\"preserved\":false}"
|
|
467
|
+
fi
|
|
468
|
+
else
|
|
469
|
+
json_ok "{\"cleared\":false,\"reason\":\"no_session_exists\"}"
|
|
470
|
+
fi
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
# ============================================================================
|
|
474
|
+
# _session_mark_resumed
|
|
475
|
+
# Mark session as resumed
|
|
476
|
+
# ============================================================================
|
|
477
|
+
_session_mark_resumed() {
|
|
478
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
479
|
+
|
|
480
|
+
if [[ -f "$session_file" ]]; then
|
|
481
|
+
jq --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
482
|
+
'.resumed_at = $ts | .context_cleared = false' "$session_file" > "$session_file.tmp" || {
|
|
483
|
+
_aether_log_error "Could not process session resume update"
|
|
484
|
+
rm -f "$session_file.tmp"
|
|
485
|
+
}
|
|
486
|
+
if [[ -s "$session_file.tmp" ]]; then
|
|
487
|
+
mv "$session_file.tmp" "$session_file" || _aether_log_error "Could not finalize session resume"
|
|
488
|
+
fi
|
|
489
|
+
json_ok "$(jq -n --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" '{resumed: true, timestamp: $ts}')"
|
|
490
|
+
else
|
|
491
|
+
json_err "$E_RESOURCE_NOT_FOUND" "No active session to mark as resumed. Try: run /ant:init to start a new session."
|
|
492
|
+
fi
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
# ============================================================================
|
|
496
|
+
# _session_summary
|
|
497
|
+
# Get session summary (human-readable or JSON)
|
|
498
|
+
# ============================================================================
|
|
499
|
+
_session_summary() {
|
|
500
|
+
_deprecation_warning "session-summary"
|
|
501
|
+
local session_file="$COLONY_DATA_DIR/session.json"
|
|
502
|
+
local json_mode="false"
|
|
503
|
+
|
|
504
|
+
# Parse --json flag (command name already shifted by main dispatch)
|
|
505
|
+
while [[ $# -gt 0 ]]; do
|
|
506
|
+
case "$1" in
|
|
507
|
+
--json)
|
|
508
|
+
json_mode="true"
|
|
509
|
+
shift
|
|
510
|
+
;;
|
|
511
|
+
*)
|
|
512
|
+
shift
|
|
513
|
+
;;
|
|
514
|
+
esac
|
|
515
|
+
done
|
|
516
|
+
|
|
517
|
+
if [[ ! -f "$session_file" ]]; then
|
|
518
|
+
if [[ "$json_mode" == "true" ]]; then
|
|
519
|
+
json_ok '{"exists":false,"goal":null,"phase":0}'
|
|
520
|
+
else
|
|
521
|
+
echo "No active session found."
|
|
522
|
+
fi
|
|
523
|
+
exit 0
|
|
524
|
+
fi
|
|
525
|
+
|
|
526
|
+
local goal phase milestone last_cmd last_at suggested cleared
|
|
527
|
+
goal=$(sanitize_read_value "$(jq -r '.colony_goal // "No goal set"' "$session_file")")
|
|
528
|
+
phase=$(jq -r '.current_phase // 0' "$session_file")
|
|
529
|
+
milestone=$(jq -r '.current_milestone // "First Mound"' "$session_file")
|
|
530
|
+
last_cmd=$(jq -r '.last_command // "None"' "$session_file")
|
|
531
|
+
last_at=$(jq -r '.last_command_at // "Unknown"' "$session_file")
|
|
532
|
+
suggested=$(jq -r '.suggested_next // "None"' "$session_file")
|
|
533
|
+
cleared=$(jq -r '.context_cleared // false' "$session_file")
|
|
534
|
+
|
|
535
|
+
if [[ "$json_mode" == "true" ]]; then
|
|
536
|
+
json_ok "$(jq -n --arg goal "$goal" --argjson phase "$phase" \
|
|
537
|
+
--arg milestone "$milestone" --arg last_cmd "$last_cmd" \
|
|
538
|
+
--arg last_at "$last_at" --arg suggested "$suggested" \
|
|
539
|
+
--argjson cleared "$cleared" \
|
|
540
|
+
'{exists: true, goal: $goal, phase: $phase, milestone: $milestone, last_command: $last_cmd, last_active: $last_at, suggested_next: $suggested, context_cleared: $cleared}')"
|
|
541
|
+
else
|
|
542
|
+
echo "Session Summary"
|
|
543
|
+
echo "=================="
|
|
544
|
+
echo "Goal: $goal"
|
|
545
|
+
[[ "$phase" != "0" ]] && echo "Phase: $phase"
|
|
546
|
+
echo "Milestone: $milestone"
|
|
547
|
+
echo "Last Command: $last_cmd"
|
|
548
|
+
echo "Last Active: $last_at"
|
|
549
|
+
[[ "$suggested" != "None" ]] && echo "Suggested Next: $suggested"
|
|
550
|
+
[[ "$cleared" == "true" ]] && echo "Status: Context was cleared"
|
|
551
|
+
fi
|
|
552
|
+
}
|