feed-the-machine 1.6.0 → 1.7.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/LICENSE +21 -21
- package/README.md +170 -170
- package/bin/brain.py +1340 -0
- package/bin/convert_claude_skills_to_codex.py +490 -0
- package/bin/generate-manifest.mjs +463 -463
- package/bin/harden_codex_skills.py +141 -0
- package/bin/install.mjs +491 -491
- package/bin/migrate-eng-buddy-data.py +875 -0
- package/bin/playbook_engine/__init__.py +1 -0
- package/bin/playbook_engine/conftest.py +8 -0
- package/bin/playbook_engine/extractor.py +33 -0
- package/bin/playbook_engine/manager.py +102 -0
- package/bin/playbook_engine/models.py +84 -0
- package/bin/playbook_engine/registry.py +35 -0
- package/bin/playbook_engine/test_extractor.py +72 -0
- package/bin/playbook_engine/test_integration.py +129 -0
- package/bin/playbook_engine/test_manager.py +85 -0
- package/bin/playbook_engine/test_models.py +166 -0
- package/bin/playbook_engine/test_registry.py +67 -0
- package/bin/playbook_engine/test_tracer.py +86 -0
- package/bin/playbook_engine/tracer.py +93 -0
- package/bin/tasks_db.py +456 -0
- package/docs/HOOKS.md +243 -243
- package/docs/INBOX.md +233 -233
- package/ftm/SKILL.md +125 -122
- package/ftm-audit/SKILL.md +623 -623
- package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
- package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
- package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
- package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
- package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
- package/ftm-audit/scripts/run-knip.sh +23 -23
- package/ftm-audit.yml +2 -2
- package/ftm-brainstorm/SKILL.md +1003 -498
- package/ftm-brainstorm/evals/evals.json +180 -100
- package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
- package/ftm-brainstorm/references/agent-prompts.md +552 -224
- package/ftm-brainstorm/references/plan-template.md +209 -121
- package/ftm-brainstorm.yml +2 -2
- package/ftm-browse/SKILL.md +454 -454
- package/ftm-browse/daemon/browser-manager.ts +206 -206
- package/ftm-browse/daemon/bun.lock +30 -30
- package/ftm-browse/daemon/cli.ts +347 -347
- package/ftm-browse/daemon/commands.ts +410 -410
- package/ftm-browse/daemon/main.ts +357 -357
- package/ftm-browse/daemon/package.json +17 -17
- package/ftm-browse/daemon/server.ts +189 -189
- package/ftm-browse/daemon/snapshot.ts +519 -519
- package/ftm-browse/daemon/tsconfig.json +22 -22
- package/ftm-browse.yml +4 -4
- package/ftm-capture/SKILL.md +370 -370
- package/ftm-capture.yml +4 -4
- package/ftm-codex-gate/SKILL.md +361 -361
- package/ftm-codex-gate.yml +2 -2
- package/ftm-config/SKILL.md +422 -345
- package/ftm-config.default.yml +125 -82
- package/ftm-config.yml +44 -2
- package/ftm-council/SKILL.md +416 -416
- package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
- package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
- package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
- package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
- package/ftm-council.yml +2 -2
- package/ftm-dashboard/SKILL.md +163 -163
- package/ftm-dashboard.yml +4 -4
- package/ftm-debug/SKILL.md +1037 -1037
- package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
- package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
- package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
- package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
- package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
- package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
- package/ftm-debug.yml +2 -2
- package/ftm-diagram/SKILL.md +277 -277
- package/ftm-diagram.yml +2 -2
- package/ftm-executor/SKILL.md +777 -777
- package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
- package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
- package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
- package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
- package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -72
- package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
- package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
- package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
- package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -59
- package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
- package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
- package/ftm-executor/runtime/package.json +8 -8
- package/ftm-executor.yml +2 -2
- package/ftm-git/SKILL.md +441 -441
- package/ftm-git/evals/evals.json +26 -26
- package/ftm-git/evals/promptfoo.yaml +75 -75
- package/ftm-git/hooks/post-commit-experience.sh +92 -92
- package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
- package/ftm-git/references/protocols/REMEDIATION.md +139 -139
- package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
- package/ftm-git.yml +2 -2
- package/ftm-inbox/backend/__pycache__/main.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/adapters/_retry.py +64 -64
- package/ftm-inbox/backend/adapters/base.py +230 -230
- package/ftm-inbox/backend/adapters/freshservice.py +104 -104
- package/ftm-inbox/backend/adapters/gmail.py +125 -125
- package/ftm-inbox/backend/adapters/jira.py +136 -136
- package/ftm-inbox/backend/adapters/registry.py +192 -192
- package/ftm-inbox/backend/adapters/slack.py +110 -110
- package/ftm-inbox/backend/db/connection.py +54 -54
- package/ftm-inbox/backend/db/schema.py +78 -78
- package/ftm-inbox/backend/executor/__init__.py +7 -7
- package/ftm-inbox/backend/executor/engine.py +149 -149
- package/ftm-inbox/backend/executor/step_runner.py +98 -98
- package/ftm-inbox/backend/main.py +103 -103
- package/ftm-inbox/backend/models/__init__.py +1 -1
- package/ftm-inbox/backend/models/unified_task.py +36 -36
- package/ftm-inbox/backend/planner/__init__.py +6 -6
- package/ftm-inbox/backend/planner/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/__pycache__/generator.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/__pycache__/schema.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/generator.py +127 -127
- package/ftm-inbox/backend/planner/schema.py +34 -34
- package/ftm-inbox/backend/requirements.txt +5 -5
- package/ftm-inbox/backend/routes/__pycache__/plan.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/routes/execute.py +186 -186
- package/ftm-inbox/backend/routes/health.py +52 -52
- package/ftm-inbox/backend/routes/inbox.py +68 -68
- package/ftm-inbox/backend/routes/plan.py +271 -271
- package/ftm-inbox/bin/launchagent.mjs +91 -91
- package/ftm-inbox/bin/setup.mjs +188 -188
- package/ftm-inbox/bin/start.sh +10 -10
- package/ftm-inbox/bin/status.sh +17 -17
- package/ftm-inbox/bin/stop.sh +8 -8
- package/ftm-inbox/config.example.yml +55 -55
- package/ftm-inbox/package-lock.json +2898 -2898
- package/ftm-inbox/package.json +26 -26
- package/ftm-inbox/postcss.config.js +6 -6
- package/ftm-inbox/src/app.css +199 -199
- package/ftm-inbox/src/app.html +18 -18
- package/ftm-inbox/src/lib/api.ts +166 -166
- package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
- package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
- package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
- package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
- package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
- package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
- package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
- package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
- package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
- package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
- package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
- package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
- package/ftm-inbox/src/lib/theme.ts +47 -47
- package/ftm-inbox/src/routes/+layout.svelte +76 -76
- package/ftm-inbox/src/routes/+page.svelte +401 -401
- package/ftm-inbox/svelte.config.js +12 -12
- package/ftm-inbox/tailwind.config.ts +63 -63
- package/ftm-inbox/tsconfig.json +13 -13
- package/ftm-inbox/vite.config.ts +6 -6
- package/ftm-intent/SKILL.md +241 -241
- package/ftm-intent.yml +2 -2
- package/ftm-manifest.json +3794 -3794
- package/ftm-map/SKILL.md +291 -291
- package/ftm-map/scripts/db.py +712 -712
- package/ftm-map/scripts/index.py +415 -415
- package/ftm-map/scripts/parser.py +224 -224
- package/ftm-map/scripts/queries/go-tags.scm +20 -20
- package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
- package/ftm-map/scripts/queries/python-tags.scm +31 -31
- package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
- package/ftm-map/scripts/queries/rust-tags.scm +37 -37
- package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
- package/ftm-map/scripts/query.py +301 -301
- package/ftm-map/scripts/ranker.py +377 -377
- package/ftm-map/scripts/requirements.txt +5 -5
- package/ftm-map/scripts/setup-hooks.sh +27 -27
- package/ftm-map/scripts/setup.sh +56 -56
- package/ftm-map/scripts/test_db.py +364 -364
- package/ftm-map/scripts/test_parser.py +174 -174
- package/ftm-map/scripts/test_query.py +183 -183
- package/ftm-map/scripts/test_ranker.py +199 -199
- package/ftm-map/scripts/views.py +591 -591
- package/ftm-map.yml +2 -2
- package/ftm-mind/SKILL.md +201 -1943
- package/ftm-mind/evals/promptfoo.yaml +142 -142
- package/ftm-mind/references/blackboard-protocol.md +110 -0
- package/ftm-mind/references/blackboard-schema.md +328 -328
- package/ftm-mind/references/complexity-guide.md +110 -110
- package/ftm-mind/references/complexity-sizing.md +138 -0
- package/ftm-mind/references/decide-act-protocol.md +172 -0
- package/ftm-mind/references/direct-execution.md +51 -0
- package/ftm-mind/references/environment-discovery.md +77 -0
- package/ftm-mind/references/event-registry.md +319 -319
- package/ftm-mind/references/mcp-inventory.md +300 -296
- package/ftm-mind/references/ops-routing.md +47 -0
- package/ftm-mind/references/orient-protocol.md +234 -0
- package/ftm-mind/references/personality.md +40 -0
- package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
- package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
- package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
- package/ftm-mind/references/reflexion-protocol.md +249 -249
- package/ftm-mind/references/routing/SCENARIOS.md +22 -22
- package/ftm-mind/references/routing-scenarios.md +35 -35
- package/ftm-mind.yml +2 -2
- package/ftm-ops.yml +4 -0
- package/ftm-pause/SKILL.md +395 -395
- package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
- package/ftm-pause/references/protocols/VALIDATION.md +80 -80
- package/ftm-pause.yml +2 -2
- package/ftm-researcher/SKILL.md +275 -275
- package/ftm-researcher/evals/agent-diversity.yaml +17 -17
- package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
- package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
- package/ftm-researcher/references/adaptive-search.md +116 -116
- package/ftm-researcher/references/agent-prompts.md +193 -193
- package/ftm-researcher/references/council-integration.md +193 -193
- package/ftm-researcher/references/output-format.md +203 -203
- package/ftm-researcher/references/synthesis-pipeline.md +165 -165
- package/ftm-researcher/scripts/score_credibility.py +234 -234
- package/ftm-researcher/scripts/validate_research.py +92 -92
- package/ftm-researcher.yml +2 -2
- package/ftm-resume/SKILL.md +518 -518
- package/ftm-resume/references/protocols/VALIDATION.md +172 -172
- package/ftm-resume.yml +2 -2
- package/ftm-retro/SKILL.md +380 -380
- package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
- package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
- package/ftm-retro.yml +2 -2
- package/ftm-routine/SKILL.md +170 -170
- package/ftm-routine.yml +4 -4
- package/ftm-state/blackboard/capabilities.json +5 -5
- package/ftm-state/blackboard/capabilities.schema.json +27 -27
- package/ftm-state/blackboard/context.json +37 -23
- package/ftm-state/blackboard/experiences/doom-statusline-fix.json +26 -0
- package/ftm-state/blackboard/experiences/hackathon-pages-site.json +26 -0
- package/ftm-state/blackboard/experiences/hindsight-sso-kickoff.json +42 -0
- package/ftm-state/blackboard/experiences/index.json +58 -9
- package/ftm-state/blackboard/experiences/learning-ragnarok-api-access.json +23 -0
- package/ftm-state/blackboard/experiences/nordlayer-members-auto-assign.json +26 -0
- package/ftm-state/blackboard/experiences/saml2aws-stale-session-fix.json +41 -0
- package/ftm-state/blackboard/patterns.json +6 -6
- package/ftm-state/schemas/context.schema.json +130 -130
- package/ftm-state/schemas/experience-index.schema.json +77 -77
- package/ftm-state/schemas/experience.schema.json +78 -78
- package/ftm-state/schemas/patterns.schema.json +44 -44
- package/ftm-upgrade/SKILL.md +194 -194
- package/ftm-upgrade/scripts/check-version.sh +76 -76
- package/ftm-upgrade/scripts/upgrade.sh +143 -143
- package/ftm-upgrade.yml +2 -2
- package/ftm-verify.yml +2 -2
- package/ftm.yml +2 -2
- package/hooks/ftm-auto-log.sh +137 -0
- package/hooks/ftm-blackboard-enforcer.sh +93 -93
- package/hooks/ftm-discovery-reminder.sh +90 -90
- package/hooks/ftm-drafts-gate.sh +61 -61
- package/hooks/ftm-event-logger.mjs +107 -107
- package/hooks/ftm-install-hooks.sh +240 -0
- package/hooks/ftm-learning-capture.sh +117 -0
- package/hooks/ftm-map-autodetect.sh +79 -79
- package/hooks/ftm-pending-sync-check.sh +22 -22
- package/hooks/ftm-plan-gate.sh +92 -92
- package/hooks/ftm-post-commit-trigger.sh +57 -57
- package/hooks/ftm-post-compaction.sh +138 -0
- package/hooks/ftm-pre-compaction.sh +147 -0
- package/hooks/ftm-session-end.sh +52 -0
- package/hooks/ftm-session-snapshot.sh +213 -0
- package/hooks/settings-template.json +81 -81
- package/install.sh +363 -363
- package/package.json +84 -84
- package/uninstall.sh +25 -25
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# check-version.sh — Check for feed-the-machine updates via GitHub Releases
|
|
3
|
-
# Outputs: UP_TO_DATE | UPGRADE_AVAILABLE <version> <changelog_url> | CHECK_FAILED <reason>
|
|
4
|
-
|
|
5
|
-
set -uo pipefail
|
|
6
|
-
|
|
7
|
-
CACHE_DIR="${HOME}/.cache/ftm-brain"
|
|
8
|
-
CACHE_FILE="${CACHE_DIR}/version-check"
|
|
9
|
-
VERSION_FILE="${HOME}/.claude/skills/ftm-version.txt"
|
|
10
|
-
REPO="kkudumu/ftm-brain"
|
|
11
|
-
|
|
12
|
-
# Ensure cache directory exists
|
|
13
|
-
mkdir -p "${CACHE_DIR}"
|
|
14
|
-
|
|
15
|
-
# Check if cache is fresh (less than 60 minutes old)
|
|
16
|
-
if [ -f "${CACHE_FILE}" ]; then
|
|
17
|
-
STALE=$(find "${CACHE_FILE}" -mmin +60 2>/dev/null | wc -l | tr -d ' ')
|
|
18
|
-
if [ "${STALE}" = "0" ]; then
|
|
19
|
-
# Cache is fresh — return cached result
|
|
20
|
-
cat "${CACHE_FILE}"
|
|
21
|
-
exit 0
|
|
22
|
-
fi
|
|
23
|
-
fi
|
|
24
|
-
|
|
25
|
-
# Check that gh CLI is installed
|
|
26
|
-
if ! command -v gh >/dev/null 2>&1; then
|
|
27
|
-
RESULT="CHECK_FAILED gh_not_installed"
|
|
28
|
-
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
29
|
-
exit 0
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
# Query latest release from GitHub
|
|
33
|
-
RELEASE_OUTPUT=$(gh release list -R "${REPO}" --limit 1 2>&1)
|
|
34
|
-
GH_EXIT=$?
|
|
35
|
-
|
|
36
|
-
if [ ${GH_EXIT} -ne 0 ]; then
|
|
37
|
-
# Distinguish between network and repo errors
|
|
38
|
-
if printf '%s' "${RELEASE_OUTPUT}" | grep -qi "could not resolve\|network\|timeout\|no such host"; then
|
|
39
|
-
RESULT="CHECK_FAILED no_internet"
|
|
40
|
-
elif printf '%s' "${RELEASE_OUTPUT}" | grep -qi "not found\|404\|Could not find"; then
|
|
41
|
-
RESULT="CHECK_FAILED repo_not_found"
|
|
42
|
-
else
|
|
43
|
-
REASON=$(printf '%s' "${RELEASE_OUTPUT}" | tr '\n' ' ' | cut -c1-80)
|
|
44
|
-
RESULT="CHECK_FAILED ${REASON}"
|
|
45
|
-
fi
|
|
46
|
-
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
47
|
-
exit 0
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
# Parse latest release tag (first column of gh release list output)
|
|
51
|
-
LATEST_TAG=$(printf '%s' "${RELEASE_OUTPUT}" | awk 'NR==1{print $1}')
|
|
52
|
-
|
|
53
|
-
if [ -z "${LATEST_TAG}" ]; then
|
|
54
|
-
RESULT="CHECK_FAILED no_releases_found"
|
|
55
|
-
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
56
|
-
exit 0
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
# Read current installed version
|
|
60
|
-
if [ -f "${VERSION_FILE}" ]; then
|
|
61
|
-
CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
|
|
62
|
-
else
|
|
63
|
-
CURRENT_VERSION="unknown"
|
|
64
|
-
fi
|
|
65
|
-
|
|
66
|
-
# Compare versions
|
|
67
|
-
if [ "${CURRENT_VERSION}" = "${LATEST_TAG}" ]; then
|
|
68
|
-
RESULT="UP_TO_DATE"
|
|
69
|
-
else
|
|
70
|
-
CHANGELOG_URL="https://github.com/${REPO}/releases/tag/${LATEST_TAG}"
|
|
71
|
-
RESULT="UPGRADE_AVAILABLE ${LATEST_TAG} ${CHANGELOG_URL}"
|
|
72
|
-
fi
|
|
73
|
-
|
|
74
|
-
# Write to cache and output
|
|
75
|
-
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
76
|
-
exit 0
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# check-version.sh — Check for feed-the-machine updates via GitHub Releases
|
|
3
|
+
# Outputs: UP_TO_DATE | UPGRADE_AVAILABLE <version> <changelog_url> | CHECK_FAILED <reason>
|
|
4
|
+
|
|
5
|
+
set -uo pipefail
|
|
6
|
+
|
|
7
|
+
CACHE_DIR="${HOME}/.cache/ftm-brain"
|
|
8
|
+
CACHE_FILE="${CACHE_DIR}/version-check"
|
|
9
|
+
VERSION_FILE="${HOME}/.claude/skills/ftm-version.txt"
|
|
10
|
+
REPO="kkudumu/ftm-brain"
|
|
11
|
+
|
|
12
|
+
# Ensure cache directory exists
|
|
13
|
+
mkdir -p "${CACHE_DIR}"
|
|
14
|
+
|
|
15
|
+
# Check if cache is fresh (less than 60 minutes old)
|
|
16
|
+
if [ -f "${CACHE_FILE}" ]; then
|
|
17
|
+
STALE=$(find "${CACHE_FILE}" -mmin +60 2>/dev/null | wc -l | tr -d ' ')
|
|
18
|
+
if [ "${STALE}" = "0" ]; then
|
|
19
|
+
# Cache is fresh — return cached result
|
|
20
|
+
cat "${CACHE_FILE}"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Check that gh CLI is installed
|
|
26
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
27
|
+
RESULT="CHECK_FAILED gh_not_installed"
|
|
28
|
+
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Query latest release from GitHub
|
|
33
|
+
RELEASE_OUTPUT=$(gh release list -R "${REPO}" --limit 1 2>&1)
|
|
34
|
+
GH_EXIT=$?
|
|
35
|
+
|
|
36
|
+
if [ ${GH_EXIT} -ne 0 ]; then
|
|
37
|
+
# Distinguish between network and repo errors
|
|
38
|
+
if printf '%s' "${RELEASE_OUTPUT}" | grep -qi "could not resolve\|network\|timeout\|no such host"; then
|
|
39
|
+
RESULT="CHECK_FAILED no_internet"
|
|
40
|
+
elif printf '%s' "${RELEASE_OUTPUT}" | grep -qi "not found\|404\|Could not find"; then
|
|
41
|
+
RESULT="CHECK_FAILED repo_not_found"
|
|
42
|
+
else
|
|
43
|
+
REASON=$(printf '%s' "${RELEASE_OUTPUT}" | tr '\n' ' ' | cut -c1-80)
|
|
44
|
+
RESULT="CHECK_FAILED ${REASON}"
|
|
45
|
+
fi
|
|
46
|
+
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Parse latest release tag (first column of gh release list output)
|
|
51
|
+
LATEST_TAG=$(printf '%s' "${RELEASE_OUTPUT}" | awk 'NR==1{print $1}')
|
|
52
|
+
|
|
53
|
+
if [ -z "${LATEST_TAG}" ]; then
|
|
54
|
+
RESULT="CHECK_FAILED no_releases_found"
|
|
55
|
+
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
56
|
+
exit 0
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Read current installed version
|
|
60
|
+
if [ -f "${VERSION_FILE}" ]; then
|
|
61
|
+
CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
|
|
62
|
+
else
|
|
63
|
+
CURRENT_VERSION="unknown"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Compare versions
|
|
67
|
+
if [ "${CURRENT_VERSION}" = "${LATEST_TAG}" ]; then
|
|
68
|
+
RESULT="UP_TO_DATE"
|
|
69
|
+
else
|
|
70
|
+
CHANGELOG_URL="https://github.com/${REPO}/releases/tag/${LATEST_TAG}"
|
|
71
|
+
RESULT="UPGRADE_AVAILABLE ${LATEST_TAG} ${CHANGELOG_URL}"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# Write to cache and output
|
|
75
|
+
printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
|
|
76
|
+
exit 0
|
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# upgrade.sh — Download and install latest feed-the-machine release
|
|
3
|
-
# Usage: upgrade.sh [--version <tag>]
|
|
4
|
-
|
|
5
|
-
set -uo pipefail
|
|
6
|
-
|
|
7
|
-
REPO="kkudumu/ftm-brain"
|
|
8
|
-
SKILLS_DIR="${HOME}/.claude/skills"
|
|
9
|
-
VERSION_FILE="${SKILLS_DIR}/ftm-version.txt"
|
|
10
|
-
DOWNLOAD_DIR="/tmp/ftm-upgrade"
|
|
11
|
-
CACHE_FILE="${HOME}/.cache/ftm-brain/version-check"
|
|
12
|
-
|
|
13
|
-
# ── Helpers ──────────────────────────────────────────────────────────────────
|
|
14
|
-
|
|
15
|
-
log() { printf '[ftm-upgrade] %s\n' "$*"; }
|
|
16
|
-
die() { printf '[ftm-upgrade] ERROR: %s\n' "$*" >&2; exit 1; }
|
|
17
|
-
|
|
18
|
-
# ── Preflight checks ─────────────────────────────────────────────────────────
|
|
19
|
-
|
|
20
|
-
if ! command -v gh >/dev/null 2>&1; then
|
|
21
|
-
die "GitHub CLI (gh) is not installed. Install it with: brew install gh"
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
if ! command -v tar >/dev/null 2>&1; then
|
|
25
|
-
die "tar is required but not found."
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
# ── Determine target version ─────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
TARGET_VERSION=""
|
|
31
|
-
while [ $# -gt 0 ]; do
|
|
32
|
-
case "$1" in
|
|
33
|
-
--version) TARGET_VERSION="$2"; shift 2 ;;
|
|
34
|
-
*) die "Unknown argument: $1" ;;
|
|
35
|
-
esac
|
|
36
|
-
done
|
|
37
|
-
|
|
38
|
-
if [ -z "${TARGET_VERSION}" ]; then
|
|
39
|
-
log "Fetching latest release tag..."
|
|
40
|
-
TARGET_VERSION=$(gh release list -R "${REPO}" --limit 1 2>&1 | awk 'NR==1{print $1}')
|
|
41
|
-
if [ -z "${TARGET_VERSION}" ]; then
|
|
42
|
-
die "Could not determine latest release. Check GitHub access and repository name."
|
|
43
|
-
fi
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
log "Target version: ${TARGET_VERSION}"
|
|
47
|
-
|
|
48
|
-
# ── Read current version ─────────────────────────────────────────────────────
|
|
49
|
-
|
|
50
|
-
if [ -f "${VERSION_FILE}" ]; then
|
|
51
|
-
CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
|
|
52
|
-
else
|
|
53
|
-
CURRENT_VERSION="(not installed)"
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
log "Current version: ${CURRENT_VERSION}"
|
|
57
|
-
|
|
58
|
-
if [ "${CURRENT_VERSION}" = "${TARGET_VERSION}" ]; then
|
|
59
|
-
log "Already on the latest version (${TARGET_VERSION}). Nothing to do."
|
|
60
|
-
exit 0
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
# ── Download ──────────────────────────────────────────────────────────────────
|
|
64
|
-
|
|
65
|
-
rm -rf "${DOWNLOAD_DIR}"
|
|
66
|
-
mkdir -p "${DOWNLOAD_DIR}"
|
|
67
|
-
|
|
68
|
-
log "Downloading release archive for ${TARGET_VERSION}..."
|
|
69
|
-
|
|
70
|
-
gh release download "${TARGET_VERSION}" \
|
|
71
|
-
-R "${REPO}" \
|
|
72
|
-
--archive tar.gz \
|
|
73
|
-
-D "${DOWNLOAD_DIR}" 2>&1 || die "Download failed. Check your internet connection and repository access."
|
|
74
|
-
|
|
75
|
-
# Find the downloaded archive
|
|
76
|
-
ARCHIVE=$(find "${DOWNLOAD_DIR}" -maxdepth 1 -name '*.tar.gz' | head -1)
|
|
77
|
-
if [ -z "${ARCHIVE}" ]; then
|
|
78
|
-
die "No archive found in ${DOWNLOAD_DIR} after download."
|
|
79
|
-
fi
|
|
80
|
-
|
|
81
|
-
log "Downloaded: ${ARCHIVE}"
|
|
82
|
-
|
|
83
|
-
# ── Extract ───────────────────────────────────────────────────────────────────
|
|
84
|
-
|
|
85
|
-
EXTRACT_DIR="${DOWNLOAD_DIR}/extracted"
|
|
86
|
-
mkdir -p "${EXTRACT_DIR}"
|
|
87
|
-
|
|
88
|
-
log "Extracting archive..."
|
|
89
|
-
tar -xzf "${ARCHIVE}" -C "${EXTRACT_DIR}" 2>&1 || die "Extraction failed. Archive may be corrupt."
|
|
90
|
-
|
|
91
|
-
# GitHub archives typically extract into a directory named <repo>-<tag>/
|
|
92
|
-
REPO_DIR=$(find "${EXTRACT_DIR}" -maxdepth 1 -mindepth 1 -type d | head -1)
|
|
93
|
-
if [ -z "${REPO_DIR}" ]; then
|
|
94
|
-
die "Could not find extracted repository directory."
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
log "Extracted to: ${REPO_DIR}"
|
|
98
|
-
|
|
99
|
-
# ── Copy skill files ──────────────────────────────────────────────────────────
|
|
100
|
-
|
|
101
|
-
# Look for a skills/ subdirectory in the archive; fall back to root
|
|
102
|
-
SOURCE_SKILLS=""
|
|
103
|
-
if [ -d "${REPO_DIR}/skills" ]; then
|
|
104
|
-
SOURCE_SKILLS="${REPO_DIR}/skills"
|
|
105
|
-
elif [ -d "${REPO_DIR}" ]; then
|
|
106
|
-
# The repo root might itself contain SKILL.md files and .yml files
|
|
107
|
-
SOURCE_SKILLS="${REPO_DIR}"
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
if [ -z "${SOURCE_SKILLS}" ]; then
|
|
111
|
-
die "No skills directory found in release archive."
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
log "Copying skill files from ${SOURCE_SKILLS} to ${SKILLS_DIR}..."
|
|
115
|
-
|
|
116
|
-
# Use rsync if available for cleaner copy, else cp
|
|
117
|
-
if command -v rsync >/dev/null 2>&1; then
|
|
118
|
-
rsync -av --exclude='.git' "${SOURCE_SKILLS}/" "${SKILLS_DIR}/" 2>&1
|
|
119
|
-
else
|
|
120
|
-
cp -R "${SOURCE_SKILLS}/." "${SKILLS_DIR}/" 2>&1
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
# ── Update version file ───────────────────────────────────────────────────────
|
|
124
|
-
|
|
125
|
-
printf '%s\n' "${TARGET_VERSION}" > "${VERSION_FILE}"
|
|
126
|
-
|
|
127
|
-
# Invalidate version cache so next check-version.sh run is fresh
|
|
128
|
-
rm -f "${CACHE_FILE}"
|
|
129
|
-
|
|
130
|
-
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
log ""
|
|
133
|
-
log "Upgrade complete."
|
|
134
|
-
log " ${CURRENT_VERSION} → ${TARGET_VERSION}"
|
|
135
|
-
log " Changelog: https://github.com/${REPO}/releases/tag/${TARGET_VERSION}"
|
|
136
|
-
log ""
|
|
137
|
-
log "Installed files updated in: ${SKILLS_DIR}"
|
|
138
|
-
|
|
139
|
-
# ── Cleanup ───────────────────────────────────────────────────────────────────
|
|
140
|
-
|
|
141
|
-
rm -rf "${DOWNLOAD_DIR}"
|
|
142
|
-
|
|
143
|
-
exit 0
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# upgrade.sh — Download and install latest feed-the-machine release
|
|
3
|
+
# Usage: upgrade.sh [--version <tag>]
|
|
4
|
+
|
|
5
|
+
set -uo pipefail
|
|
6
|
+
|
|
7
|
+
REPO="kkudumu/ftm-brain"
|
|
8
|
+
SKILLS_DIR="${HOME}/.claude/skills"
|
|
9
|
+
VERSION_FILE="${SKILLS_DIR}/ftm-version.txt"
|
|
10
|
+
DOWNLOAD_DIR="/tmp/ftm-upgrade"
|
|
11
|
+
CACHE_FILE="${HOME}/.cache/ftm-brain/version-check"
|
|
12
|
+
|
|
13
|
+
# ── Helpers ──────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
log() { printf '[ftm-upgrade] %s\n' "$*"; }
|
|
16
|
+
die() { printf '[ftm-upgrade] ERROR: %s\n' "$*" >&2; exit 1; }
|
|
17
|
+
|
|
18
|
+
# ── Preflight checks ─────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
21
|
+
die "GitHub CLI (gh) is not installed. Install it with: brew install gh"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if ! command -v tar >/dev/null 2>&1; then
|
|
25
|
+
die "tar is required but not found."
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# ── Determine target version ─────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
TARGET_VERSION=""
|
|
31
|
+
while [ $# -gt 0 ]; do
|
|
32
|
+
case "$1" in
|
|
33
|
+
--version) TARGET_VERSION="$2"; shift 2 ;;
|
|
34
|
+
*) die "Unknown argument: $1" ;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [ -z "${TARGET_VERSION}" ]; then
|
|
39
|
+
log "Fetching latest release tag..."
|
|
40
|
+
TARGET_VERSION=$(gh release list -R "${REPO}" --limit 1 2>&1 | awk 'NR==1{print $1}')
|
|
41
|
+
if [ -z "${TARGET_VERSION}" ]; then
|
|
42
|
+
die "Could not determine latest release. Check GitHub access and repository name."
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
log "Target version: ${TARGET_VERSION}"
|
|
47
|
+
|
|
48
|
+
# ── Read current version ─────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
if [ -f "${VERSION_FILE}" ]; then
|
|
51
|
+
CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
|
|
52
|
+
else
|
|
53
|
+
CURRENT_VERSION="(not installed)"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
log "Current version: ${CURRENT_VERSION}"
|
|
57
|
+
|
|
58
|
+
if [ "${CURRENT_VERSION}" = "${TARGET_VERSION}" ]; then
|
|
59
|
+
log "Already on the latest version (${TARGET_VERSION}). Nothing to do."
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# ── Download ──────────────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
rm -rf "${DOWNLOAD_DIR}"
|
|
66
|
+
mkdir -p "${DOWNLOAD_DIR}"
|
|
67
|
+
|
|
68
|
+
log "Downloading release archive for ${TARGET_VERSION}..."
|
|
69
|
+
|
|
70
|
+
gh release download "${TARGET_VERSION}" \
|
|
71
|
+
-R "${REPO}" \
|
|
72
|
+
--archive tar.gz \
|
|
73
|
+
-D "${DOWNLOAD_DIR}" 2>&1 || die "Download failed. Check your internet connection and repository access."
|
|
74
|
+
|
|
75
|
+
# Find the downloaded archive
|
|
76
|
+
ARCHIVE=$(find "${DOWNLOAD_DIR}" -maxdepth 1 -name '*.tar.gz' | head -1)
|
|
77
|
+
if [ -z "${ARCHIVE}" ]; then
|
|
78
|
+
die "No archive found in ${DOWNLOAD_DIR} after download."
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
log "Downloaded: ${ARCHIVE}"
|
|
82
|
+
|
|
83
|
+
# ── Extract ───────────────────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
EXTRACT_DIR="${DOWNLOAD_DIR}/extracted"
|
|
86
|
+
mkdir -p "${EXTRACT_DIR}"
|
|
87
|
+
|
|
88
|
+
log "Extracting archive..."
|
|
89
|
+
tar -xzf "${ARCHIVE}" -C "${EXTRACT_DIR}" 2>&1 || die "Extraction failed. Archive may be corrupt."
|
|
90
|
+
|
|
91
|
+
# GitHub archives typically extract into a directory named <repo>-<tag>/
|
|
92
|
+
REPO_DIR=$(find "${EXTRACT_DIR}" -maxdepth 1 -mindepth 1 -type d | head -1)
|
|
93
|
+
if [ -z "${REPO_DIR}" ]; then
|
|
94
|
+
die "Could not find extracted repository directory."
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
log "Extracted to: ${REPO_DIR}"
|
|
98
|
+
|
|
99
|
+
# ── Copy skill files ──────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
# Look for a skills/ subdirectory in the archive; fall back to root
|
|
102
|
+
SOURCE_SKILLS=""
|
|
103
|
+
if [ -d "${REPO_DIR}/skills" ]; then
|
|
104
|
+
SOURCE_SKILLS="${REPO_DIR}/skills"
|
|
105
|
+
elif [ -d "${REPO_DIR}" ]; then
|
|
106
|
+
# The repo root might itself contain SKILL.md files and .yml files
|
|
107
|
+
SOURCE_SKILLS="${REPO_DIR}"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if [ -z "${SOURCE_SKILLS}" ]; then
|
|
111
|
+
die "No skills directory found in release archive."
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
log "Copying skill files from ${SOURCE_SKILLS} to ${SKILLS_DIR}..."
|
|
115
|
+
|
|
116
|
+
# Use rsync if available for cleaner copy, else cp
|
|
117
|
+
if command -v rsync >/dev/null 2>&1; then
|
|
118
|
+
rsync -av --exclude='.git' "${SOURCE_SKILLS}/" "${SKILLS_DIR}/" 2>&1
|
|
119
|
+
else
|
|
120
|
+
cp -R "${SOURCE_SKILLS}/." "${SKILLS_DIR}/" 2>&1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# ── Update version file ───────────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
printf '%s\n' "${TARGET_VERSION}" > "${VERSION_FILE}"
|
|
126
|
+
|
|
127
|
+
# Invalidate version cache so next check-version.sh run is fresh
|
|
128
|
+
rm -f "${CACHE_FILE}"
|
|
129
|
+
|
|
130
|
+
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
log ""
|
|
133
|
+
log "Upgrade complete."
|
|
134
|
+
log " ${CURRENT_VERSION} → ${TARGET_VERSION}"
|
|
135
|
+
log " Changelog: https://github.com/${REPO}/releases/tag/${TARGET_VERSION}"
|
|
136
|
+
log ""
|
|
137
|
+
log "Installed files updated in: ${SKILLS_DIR}"
|
|
138
|
+
|
|
139
|
+
# ── Cleanup ───────────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
rm -rf "${DOWNLOAD_DIR}"
|
|
142
|
+
|
|
143
|
+
exit 0
|
package/ftm-upgrade.yml
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
name: ftm-upgrade
|
|
2
|
-
description: Self-upgrade mechanism for ftm skills ecosystem. Checks GitHub Releases for new versions, caches results for 60min, shows changelog, and copies updated files. Use when user says "upgrade", "update skills", "new version", "check for updates", "ftm upgrade".
|
|
1
|
+
name: ftm-upgrade
|
|
2
|
+
description: Self-upgrade mechanism for ftm skills ecosystem. Checks GitHub Releases for new versions, caches results for 60min, shows changelog, and copies updated files. Use when user says "upgrade", "update skills", "new version", "check for updates", "ftm upgrade".
|
package/ftm-verify.yml
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
name: ftm-verify
|
|
2
|
-
description: Comprehensive post-execution verification and auto-remediation engine using dual-model adversarial analysis. Replaces ftm-retro. After ftm-executor completes a plan, this skill runs two independent verification passes in parallel — Codex (OpenAI) and Gemini (Google) — each reading the entire codebase to check plan fulfillment, documentation fidelity, build health, test quality, and wiring integrity. Falls back to Claude subagents if either CLI is unavailable. Reconciles findings from both models, auto-remediates with parallel fix agents, and reports what was found, disagreed on, and fixed. Use when user says "verify", "is the plan done", "check everything", "verify plan", "ftm-verify", "did we miss anything", "is it complete", "validate the build", "check the plan", "verify execution", "post-execution check", or after any ftm-executor run completes. Also triggers on "retro", "retrospective", "how did that go", "execution review" since this skill supersedes ftm-retro. Even if the user just says "are we good?" after a plan execution — this is the skill.
|
|
1
|
+
name: ftm-verify
|
|
2
|
+
description: Comprehensive post-execution verification and auto-remediation engine using dual-model adversarial analysis. Replaces ftm-retro. After ftm-executor completes a plan, this skill runs two independent verification passes in parallel — Codex (OpenAI) and Gemini (Google) — each reading the entire codebase to check plan fulfillment, documentation fidelity, build health, test quality, and wiring integrity. Falls back to Claude subagents if either CLI is unavailable. Reconciles findings from both models, auto-remediates with parallel fix agents, and reports what was found, disagreed on, and fixed. Use when user says "verify", "is the plan done", "check everything", "verify plan", "ftm-verify", "did we miss anything", "is it complete", "validate the build", "check the plan", "verify execution", "post-execution check", or after any ftm-executor run completes. Also triggers on "retro", "retrospective", "how did that go", "execution review" since this skill supersedes ftm-retro. Even if the user just says "are we good?" after a plan execution — this is the skill.
|
package/ftm.yml
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
name: ftm
|
|
2
|
-
description: Universal entry point for all ftm skills. Routes freeform text to the right ftm skill automatically. Use when user says "/ftm" followed by anything. ftm-mind is the default cognitive entry point for all unclassified input (OODA reasoning). Explicit prefixes route directly: brainstorm, execute, debug, audit, council, intent, diagram, codex-gate, pause, resume, browse, upgrade, retro, config, mind. Also use when user is unsure which ftm skill they need.
|
|
1
|
+
name: ftm
|
|
2
|
+
description: Universal entry point for all ftm skills. Routes freeform text to the right ftm skill automatically. Use when user says "/ftm" followed by anything. ftm-mind is the default cognitive entry point for all unclassified input (OODA reasoning). Explicit prefixes route directly: brainstorm, execute, debug, audit, council, intent, diagram, codex-gate, pause, resume, browse, upgrade, retro, config, mind. Also use when user is unsure which ftm skill they need.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Hook: Auto-log progress + heartbeat for ftm
|
|
3
|
+
# Triggers: UserPromptSubmit while an ftm session is active
|
|
4
|
+
#
|
|
5
|
+
# 1. Auto-log: reminds Claude to log progress when user reports completing something
|
|
6
|
+
# 2. Task inbox: surfaces unreviewed Slack/email tasks every 10 min
|
|
7
|
+
# 3. Heartbeat: every 30 min, scans task state for urgent items to surface
|
|
8
|
+
#
|
|
9
|
+
# Heartbeat inspired by OpenClaw's HEARTBEAT.md pattern (heartbeat.ts):
|
|
10
|
+
# Periodically checks task state and prompts Claude to surface time-sensitive
|
|
11
|
+
# items without the user asking.
|
|
12
|
+
#
|
|
13
|
+
# FILES:
|
|
14
|
+
# ~/.claude/ftm-state/blackboard/context.json - session gate (active_task check)
|
|
15
|
+
# ~/.claude/ftm-state/.last-heartbeat - timestamp of last heartbeat
|
|
16
|
+
# ~/.claude/ftm-state/HEARTBEAT.md - user-maintained alert/task config
|
|
17
|
+
|
|
18
|
+
FTM_STATE="$HOME/.claude/ftm-state"
|
|
19
|
+
CONTEXT_JSON="$FTM_STATE/blackboard/context.json"
|
|
20
|
+
|
|
21
|
+
# Check if an ftm session is active by reading context.json
|
|
22
|
+
FTM_ACTIVE=$(python3 -c "
|
|
23
|
+
import json, sys
|
|
24
|
+
try:
|
|
25
|
+
with open('$CONTEXT_JSON') as f:
|
|
26
|
+
d = json.load(f)
|
|
27
|
+
task = d.get('current_task', {})
|
|
28
|
+
status = task.get('status', '')
|
|
29
|
+
print('1' if status not in ('', 'completed', 'none') else '0')
|
|
30
|
+
except Exception:
|
|
31
|
+
print('0')
|
|
32
|
+
" 2>/dev/null)
|
|
33
|
+
|
|
34
|
+
if [ "$FTM_ACTIVE" != "1" ]; then
|
|
35
|
+
exit 0 # Not in active ftm session, skip
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Read payload from stdin (JSON) — extract prompt for action pattern matching
|
|
39
|
+
STDIN_DATA=$(cat)
|
|
40
|
+
USER_MESSAGE=$(echo "$STDIN_DATA" | python3 -c "
|
|
41
|
+
import sys, json
|
|
42
|
+
try:
|
|
43
|
+
d = json.load(sys.stdin)
|
|
44
|
+
print(d.get('prompt', ''))
|
|
45
|
+
except:
|
|
46
|
+
print('')
|
|
47
|
+
" 2>/dev/null)
|
|
48
|
+
# Fallback: treat stdin as raw message if JSON parse failed
|
|
49
|
+
if [ -z "$USER_MESSAGE" ]; then
|
|
50
|
+
USER_MESSAGE="$STDIN_DATA"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Action indicators (what users say when they've done something)
|
|
54
|
+
ACTION_PATTERNS=(
|
|
55
|
+
"^[Ii] (did|completed?|finished|fixed|sent|responded|closed|created|updated|deployed|merged|pushed|committed|tested|reviewed)"
|
|
56
|
+
"^[Jj]ust (did|completed?|finished|fixed|sent|responded|closed|created|updated|deployed|merged|pushed|committed|tested|reviewed)"
|
|
57
|
+
"^[Dd]one"
|
|
58
|
+
"^[Ff]inished"
|
|
59
|
+
"^[Cc]ompleted?"
|
|
60
|
+
"^[Ss]ent (email|message|response)"
|
|
61
|
+
"^[Rr]esponded to"
|
|
62
|
+
"^[Mm]erged"
|
|
63
|
+
"^[Pp]ushed to"
|
|
64
|
+
"^[Cc]ommitted"
|
|
65
|
+
"^[Dd]eployed"
|
|
66
|
+
"^[Ff]ixed"
|
|
67
|
+
"^[Cc]losed (ticket|issue|task)"
|
|
68
|
+
"[Tt]ask.*complete"
|
|
69
|
+
"[Tt]icket.*closed"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Check if message matches any action pattern
|
|
73
|
+
SHOULD_LOG=false
|
|
74
|
+
for pattern in "${ACTION_PATTERNS[@]}"; do
|
|
75
|
+
if echo "$USER_MESSAGE" | grep -qE "$pattern"; then
|
|
76
|
+
SHOULD_LOG=true
|
|
77
|
+
break
|
|
78
|
+
fi
|
|
79
|
+
done
|
|
80
|
+
|
|
81
|
+
# Also check for follow-up questions after taking action
|
|
82
|
+
if echo "$USER_MESSAGE" | grep -qE "(I|i) .* (what|should|next|now)\?"; then
|
|
83
|
+
SHOULD_LOG=true
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# If action detected, output logging reminder for Claude to see
|
|
87
|
+
if [ "$SHOULD_LOG" = true ]; then
|
|
88
|
+
echo ""
|
|
89
|
+
echo "[Auto-log] Detected progress update. Please log this to the ftm daily log."
|
|
90
|
+
echo ""
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# --- Dashboard sync: surface task-state changes made outside the chat ---
|
|
94
|
+
CLAUDE_SYNC_FILE="$FTM_STATE/blackboard/.runtime/claude-sync-events.txt"
|
|
95
|
+
if [ -s "$CLAUDE_SYNC_FILE" ]; then
|
|
96
|
+
echo ""
|
|
97
|
+
echo "[Dashboard sync] Recent dashboard updates were written to ftm-state:"
|
|
98
|
+
head -20 "$CLAUDE_SYNC_FILE"
|
|
99
|
+
echo "Please reload task state from ftm-state and treat those updates as authoritative."
|
|
100
|
+
echo ""
|
|
101
|
+
: > "$CLAUDE_SYNC_FILE"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# --- Heartbeat: periodic task/urgency check ---
|
|
105
|
+
# Fires every 30 minutes. Prompts Claude to scan for time-sensitive items.
|
|
106
|
+
HEARTBEAT_INTERVAL=1800 # 30 minutes in seconds
|
|
107
|
+
LAST_HEARTBEAT_FILE="$FTM_STATE/.last-heartbeat"
|
|
108
|
+
HEARTBEAT_MD="$FTM_STATE/HEARTBEAT.md"
|
|
109
|
+
|
|
110
|
+
SHOULD_HEARTBEAT=false
|
|
111
|
+
if [ -f "$LAST_HEARTBEAT_FILE" ]; then
|
|
112
|
+
LAST_BEAT=$(cat "$LAST_HEARTBEAT_FILE" 2>/dev/null || echo 0)
|
|
113
|
+
NOW=$(date +%s)
|
|
114
|
+
ELAPSED=$(( NOW - LAST_BEAT ))
|
|
115
|
+
if [ "$ELAPSED" -ge "$HEARTBEAT_INTERVAL" ]; then
|
|
116
|
+
SHOULD_HEARTBEAT=true
|
|
117
|
+
fi
|
|
118
|
+
else
|
|
119
|
+
# First message of session — no heartbeat on first message, just record time
|
|
120
|
+
echo "$(date +%s)" > "$LAST_HEARTBEAT_FILE"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if [ "$SHOULD_HEARTBEAT" = true ]; then
|
|
124
|
+
echo "$(date +%s)" > "$LAST_HEARTBEAT_FILE"
|
|
125
|
+
echo ""
|
|
126
|
+
echo "[HEARTBEAT — $(date '+%H:%M') check-in]: 30 minutes have passed. Briefly scan for anything time-sensitive:"
|
|
127
|
+
echo "- Check ftm-state/blackboard/context.json for deadlines or blockers that need attention."
|
|
128
|
+
if [ -f "$HEARTBEAT_MD" ]; then
|
|
129
|
+
HB_CONTENT=$(cat "$HEARTBEAT_MD" 2>/dev/null)
|
|
130
|
+
HB_ACTIONABLE=$(echo "$HB_CONTENT" | grep -v "^#" | grep -v "^[[:space:]]*$" | head -3)
|
|
131
|
+
if [ -n "$HB_ACTIONABLE" ]; then
|
|
132
|
+
echo "- HEARTBEAT.md has tasks configured — read it and follow any instructions."
|
|
133
|
+
fi
|
|
134
|
+
fi
|
|
135
|
+
echo "If nothing urgent, proceed normally. If something needs attention, surface it briefly."
|
|
136
|
+
echo ""
|
|
137
|
+
fi
|