all-hands-cli 0.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/.allhands/README.md +75 -0
- package/.allhands/agents/compounder.yaml +15 -0
- package/.allhands/agents/coordinator.yaml +17 -0
- package/.allhands/agents/documentor.yaml +15 -0
- package/.allhands/agents/e2e-test-planner.yaml +17 -0
- package/.allhands/agents/emergent.yaml +22 -0
- package/.allhands/agents/executor.yaml +14 -0
- package/.allhands/agents/ideation.yaml +11 -0
- package/.allhands/agents/initiative-steering.yaml +19 -0
- package/.allhands/agents/judge.yaml +13 -0
- package/.allhands/agents/planner.yaml +19 -0
- package/.allhands/agents/pr-reviewer.yaml +15 -0
- package/.allhands/docs.json +5 -0
- package/.allhands/docs.local.json +26 -0
- package/.allhands/flows/COMPOUNDING.md +203 -0
- package/.allhands/flows/COORDINATION.md +89 -0
- package/.allhands/flows/CORE.md +87 -0
- package/.allhands/flows/DOCUMENTATION.md +218 -0
- package/.allhands/flows/E2E_TEST_PLAN_BUILDING.md +140 -0
- package/.allhands/flows/EMERGENT_PLANNING.md +57 -0
- package/.allhands/flows/IDEATION_SCOPING.md +154 -0
- package/.allhands/flows/INITIATIVE_STEERING.md +110 -0
- package/.allhands/flows/JUDGE_REVIEWING.md +79 -0
- package/.allhands/flows/PROMPT_TASK_EXECUTION.md +68 -0
- package/.allhands/flows/PR_REVIEWING.md +43 -0
- package/.allhands/flows/SPEC_PLANNING.md +216 -0
- package/.allhands/flows/harness/WRITING_HARNESS_FLOWS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_KNOWLEDGE.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_ORCHESTRATION.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_SKILLS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_TOOLS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_VALIDATION_TOOLING.md +27 -0
- package/.allhands/flows/shared/CODEBASE_UNDERSTANDING.md +72 -0
- package/.allhands/flows/shared/CREATE_HARNESS_SPEC.md +48 -0
- package/.allhands/flows/shared/CREATE_SPEC.md +41 -0
- package/.allhands/flows/shared/CREATE_VALIDATION_TOOLING_SPEC.md +70 -0
- package/.allhands/flows/shared/DOCUMENTATION_DISCOVERY.md +123 -0
- package/.allhands/flows/shared/DOCUMENTATION_WRITER.md +101 -0
- package/.allhands/flows/shared/EMERGENT_REFINEMENT_ANALYSIS.md +76 -0
- package/.allhands/flows/shared/EXTERNAL_TECH_GUIDANCE.md +97 -0
- package/.allhands/flows/shared/IDEATION_CODEBASE_GROUNDING.md +49 -0
- package/.allhands/flows/shared/PLAN_DEEPENING.md +152 -0
- package/.allhands/flows/shared/PROMPT_TASKS_CURATION.md +113 -0
- package/.allhands/flows/shared/PROMPT_VALIDATION_REVIEW.MD +99 -0
- package/.allhands/flows/shared/QUICK_PREMORTEM.md +70 -0
- package/.allhands/flows/shared/RESEARCH_GUIDANCE.md +38 -0
- package/.allhands/flows/shared/REVIEW_OPTIONS_BREAKDOWN.md +68 -0
- package/.allhands/flows/shared/SKILL_EXTRACTION.md +84 -0
- package/.allhands/flows/shared/SPEC_FLOW_ANALYSIS.md +119 -0
- package/.allhands/flows/shared/TDD_WORKFLOW.md +109 -0
- package/.allhands/flows/shared/UTILIZE_VALIDATION_TOOLING.md +84 -0
- package/.allhands/flows/shared/WRITING_HARNESS_FLOWS.md +11 -0
- package/.allhands/flows/shared/WRITING_HARNESS_MCP_TOOLS.md +84 -0
- package/.allhands/flows/shared/jury/ARCHITECTURE_REVIEW.md +91 -0
- package/.allhands/flows/shared/jury/BEST_PRACTICES_REVIEW.md +80 -0
- package/.allhands/flows/shared/jury/CLAIM_VERIFICATION_REVIEW.md +101 -0
- package/.allhands/flows/shared/jury/EXPECTATIONS_FIT_REVIEW.md +78 -0
- package/.allhands/flows/shared/jury/MAINTAINABILITY_REVIEW.md +110 -0
- package/.allhands/flows/shared/jury/PROMPTS_EXPECTATIONS_FIT.md +74 -0
- package/.allhands/flows/shared/jury/PROMPTS_FLOW_ANALYSIS.md +92 -0
- package/.allhands/flows/shared/jury/PROMPTS_YAGNI.md +78 -0
- package/.allhands/flows/shared/jury/PROMPT_PREMORTEM.md +125 -0
- package/.allhands/flows/shared/jury/SECURITY_REVIEW.md +86 -0
- package/.allhands/flows/shared/jury/YAGNI_REVIEW.md +82 -0
- package/.allhands/flows/wip/DEBUG_INVESTIGATION.md +162 -0
- package/.allhands/flows/wip/MEMORY_RECALL.md +62 -0
- package/.allhands/harness/ah +131 -0
- package/.allhands/harness/package-lock.json +5292 -0
- package/.allhands/harness/package.json +52 -0
- package/.allhands/harness/src/__tests__/e2e/commands.test.ts +307 -0
- package/.allhands/harness/src/__tests__/e2e/event-loop.test.ts +539 -0
- package/.allhands/harness/src/__tests__/e2e/hooks.test.ts +427 -0
- package/.allhands/harness/src/__tests__/e2e/new-initiative-routing.test.ts +137 -0
- package/.allhands/harness/src/__tests__/e2e/run-e2e.ts +109 -0
- package/.allhands/harness/src/__tests__/e2e/specs-type.test.ts +210 -0
- package/.allhands/harness/src/__tests__/e2e/validation-hooks.test.ts +669 -0
- package/.allhands/harness/src/__tests__/e2e/validation-path-consistency.test.ts +354 -0
- package/.allhands/harness/src/__tests__/e2e/validation.test.ts +528 -0
- package/.allhands/harness/src/__tests__/harness/assertions.ts +318 -0
- package/.allhands/harness/src/__tests__/harness/cli-runner.ts +359 -0
- package/.allhands/harness/src/__tests__/harness/fixture.ts +384 -0
- package/.allhands/harness/src/__tests__/harness/hook-runner.ts +411 -0
- package/.allhands/harness/src/__tests__/harness/index.ts +122 -0
- package/.allhands/harness/src/cli.ts +36 -0
- package/.allhands/harness/src/commands/complexity.ts +177 -0
- package/.allhands/harness/src/commands/context7.ts +202 -0
- package/.allhands/harness/src/commands/docs.ts +557 -0
- package/.allhands/harness/src/commands/hooks.ts +24 -0
- package/.allhands/harness/src/commands/index.ts +51 -0
- package/.allhands/harness/src/commands/knowledge.ts +382 -0
- package/.allhands/harness/src/commands/memories.ts +302 -0
- package/.allhands/harness/src/commands/notify.ts +61 -0
- package/.allhands/harness/src/commands/oracle.ts +158 -0
- package/.allhands/harness/src/commands/perplexity.ts +220 -0
- package/.allhands/harness/src/commands/planning.ts +245 -0
- package/.allhands/harness/src/commands/schema.ts +73 -0
- package/.allhands/harness/src/commands/skills.ts +128 -0
- package/.allhands/harness/src/commands/solutions.ts +353 -0
- package/.allhands/harness/src/commands/spawn.ts +158 -0
- package/.allhands/harness/src/commands/specs.ts +532 -0
- package/.allhands/harness/src/commands/tavily.ts +226 -0
- package/.allhands/harness/src/commands/tools.ts +579 -0
- package/.allhands/harness/src/commands/trace.ts +327 -0
- package/.allhands/harness/src/commands/tui.ts +960 -0
- package/.allhands/harness/src/commands/validate.ts +143 -0
- package/.allhands/harness/src/commands/validation-tools.ts +108 -0
- package/.allhands/harness/src/hooks/context.ts +1442 -0
- package/.allhands/harness/src/hooks/enforcement.ts +170 -0
- package/.allhands/harness/src/hooks/index.ts +54 -0
- package/.allhands/harness/src/hooks/lifecycle.ts +229 -0
- package/.allhands/harness/src/hooks/notification.ts +104 -0
- package/.allhands/harness/src/hooks/observability.ts +551 -0
- package/.allhands/harness/src/hooks/session.ts +88 -0
- package/.allhands/harness/src/hooks/shared.ts +815 -0
- package/.allhands/harness/src/hooks/transcript-parser.ts +208 -0
- package/.allhands/harness/src/hooks/validation.ts +617 -0
- package/.allhands/harness/src/lib/__tests__/ctags.test.ts +244 -0
- package/.allhands/harness/src/lib/__tests__/docs-validation.test.ts +344 -0
- package/.allhands/harness/src/lib/__tests__/mcp-runtime.test.ts +190 -0
- package/.allhands/harness/src/lib/__tests__/schema.test.ts +861 -0
- package/.allhands/harness/src/lib/base-command.ts +198 -0
- package/.allhands/harness/src/lib/cli-daemon.ts +343 -0
- package/.allhands/harness/src/lib/compaction.ts +313 -0
- package/.allhands/harness/src/lib/ctags.ts +497 -0
- package/.allhands/harness/src/lib/docs-validation.ts +907 -0
- package/.allhands/harness/src/lib/event-loop.ts +662 -0
- package/.allhands/harness/src/lib/flows.ts +155 -0
- package/.allhands/harness/src/lib/git.ts +276 -0
- package/.allhands/harness/src/lib/knowledge-worker.ts +72 -0
- package/.allhands/harness/src/lib/knowledge.ts +810 -0
- package/.allhands/harness/src/lib/llm.ts +255 -0
- package/.allhands/harness/src/lib/mcp-client.ts +432 -0
- package/.allhands/harness/src/lib/mcp-daemon.ts +486 -0
- package/.allhands/harness/src/lib/mcp-runtime.ts +418 -0
- package/.allhands/harness/src/lib/notification.ts +115 -0
- package/.allhands/harness/src/lib/opencode/index.ts +70 -0
- package/.allhands/harness/src/lib/opencode/profiles.ts +300 -0
- package/.allhands/harness/src/lib/opencode/prompts/codesearch.md +98 -0
- package/.allhands/harness/src/lib/opencode/prompts/knowledge-aggregator.md +67 -0
- package/.allhands/harness/src/lib/opencode/runner.ts +281 -0
- package/.allhands/harness/src/lib/oracle.ts +926 -0
- package/.allhands/harness/src/lib/planning-utils.ts +150 -0
- package/.allhands/harness/src/lib/planning.ts +605 -0
- package/.allhands/harness/src/lib/pr-review.ts +225 -0
- package/.allhands/harness/src/lib/prompts.ts +522 -0
- package/.allhands/harness/src/lib/schema.ts +418 -0
- package/.allhands/harness/src/lib/schemas/agent-profile.ts +141 -0
- package/.allhands/harness/src/lib/schemas/template-vars.ts +138 -0
- package/.allhands/harness/src/lib/session.ts +164 -0
- package/.allhands/harness/src/lib/specs.ts +348 -0
- package/.allhands/harness/src/lib/tldr.ts +829 -0
- package/.allhands/harness/src/lib/tmux.ts +1051 -0
- package/.allhands/harness/src/lib/trace-store.ts +714 -0
- package/.allhands/harness/src/mcp/__tests__/index.test.ts +46 -0
- package/.allhands/harness/src/mcp/_template.ts +47 -0
- package/.allhands/harness/src/mcp/filesystem.ts +33 -0
- package/.allhands/harness/src/mcp/index.ts +69 -0
- package/.allhands/harness/src/mcp/playwright.ts +34 -0
- package/.allhands/harness/src/mcp/xcodebuild.ts +29 -0
- package/.allhands/harness/src/schemas/docs.schema.json +44 -0
- package/.allhands/harness/src/schemas/settings.schema.json +214 -0
- package/.allhands/harness/src/tui/actions.ts +227 -0
- package/.allhands/harness/src/tui/file-viewer-modal.ts +270 -0
- package/.allhands/harness/src/tui/index.ts +1574 -0
- package/.allhands/harness/src/tui/modal.ts +232 -0
- package/.allhands/harness/src/tui/prompts-pane.ts +186 -0
- package/.allhands/harness/src/tui/status-pane.ts +434 -0
- package/.allhands/harness/tsconfig.json +22 -0
- package/.allhands/harness/vitest.config.ts +13 -0
- package/.allhands/pillars.md +33 -0
- package/.allhands/principles.md +88 -0
- package/.allhands/schemas/alignment.yaml +51 -0
- package/.allhands/schemas/documentation.yaml +10 -0
- package/.allhands/schemas/prompt.yaml +92 -0
- package/.allhands/schemas/skill.yaml +34 -0
- package/.allhands/schemas/solution.yaml +131 -0
- package/.allhands/schemas/spec.yaml +67 -0
- package/.allhands/schemas/validation-suite.yaml +49 -0
- package/.allhands/schemas/workflow.yaml +51 -0
- package/.allhands/settings.json +57 -0
- package/.allhands/skills/claude-code-patterns/SKILL.md +60 -0
- package/.allhands/skills/claude-code-patterns/docs/context-hygiene.md +19 -0
- package/.allhands/skills/harness-maintenance/SKILL.md +449 -0
- package/.allhands/skills/harness-maintenance/references/core-architecture.md +187 -0
- package/.allhands/skills/harness-maintenance/references/harness-skills.md +87 -0
- package/.allhands/skills/harness-maintenance/references/knowledge-compounding.md +78 -0
- package/.allhands/skills/harness-maintenance/references/tools-commands-mcp-hooks.md +115 -0
- package/.allhands/skills/harness-maintenance/references/validation-tooling.md +77 -0
- package/.allhands/skills/harness-maintenance/references/writing-flows.md +84 -0
- package/.allhands/validation/browser-automation.md +109 -0
- package/.allhands/validation/xcode-automation.md +195 -0
- package/.allhands/workflows/documentation.md +86 -0
- package/.allhands/workflows/investigation.md +81 -0
- package/.allhands/workflows/milestone.md +91 -0
- package/.allhands/workflows/optimization.md +85 -0
- package/.allhands/workflows/refactor.md +99 -0
- package/.allhands/workflows/triage.md +81 -0
- package/.claude/README.md +1 -0
- package/.claude/agents/explorer.md +10 -0
- package/.claude/agents/researcher.md +11 -0
- package/.claude/agents/task-runner.md +8 -0
- package/.claude/settings.json +231 -0
- package/.env.ai.example +7 -0
- package/.github/workflows/npm-publish.yml +69 -0
- package/.internal.json +45 -0
- package/.tldr/config.json +11 -0
- package/.tldrignore +90 -0
- package/CLAUDE.md +6 -0
- package/README.md +98 -0
- package/bin/sync-cli.js +7552 -0
- package/concerns.md +7 -0
- package/docs/README.md +41 -0
- package/docs/agents/README.md +24 -0
- package/docs/agents/agent-configuration-system.md +86 -0
- package/docs/agents/execution-agents.md +50 -0
- package/docs/agents/knowledge-agents.md +61 -0
- package/docs/agents/orchestration-agent.md +57 -0
- package/docs/agents/planning-agents.md +84 -0
- package/docs/agents/quality-review-agents.md +67 -0
- package/docs/agents/workflow-agent-orchestration.md +69 -0
- package/docs/flows/README.md +44 -0
- package/docs/flows/compounding.md +126 -0
- package/docs/flows/coordination.md +72 -0
- package/docs/flows/core-harness-integration.md +63 -0
- package/docs/flows/documentation-orchestration.md +98 -0
- package/docs/flows/e2e-test-plan-building.md +83 -0
- package/docs/flows/emergent-refinement.md +104 -0
- package/docs/flows/flow-authoring-and-mcp-tools.md +89 -0
- package/docs/flows/judge-reviewing.md +112 -0
- package/docs/flows/plan-deepening-and-research.md +107 -0
- package/docs/flows/plan-review-jury.md +114 -0
- package/docs/flows/pr-reviewing.md +54 -0
- package/docs/flows/prompt-task-execution.md +119 -0
- package/docs/flows/spec-planning.md +162 -0
- package/docs/flows/type-specific-scoping-flows.md +49 -0
- package/docs/flows/validation-and-skills-integration.md +145 -0
- package/docs/flows/wip/wip-flows.md +102 -0
- package/docs/harness/README.md +23 -0
- package/docs/harness/agent-profiles.md +84 -0
- package/docs/harness/cli/README.md +24 -0
- package/docs/harness/cli/cli-entry-and-command-discovery.md +91 -0
- package/docs/harness/cli/docs-command.md +87 -0
- package/docs/harness/cli/knowledge-command.md +91 -0
- package/docs/harness/cli/minor-cli-commands.md +65 -0
- package/docs/harness/cli/oracle-command.md +113 -0
- package/docs/harness/cli/planning-command.md +95 -0
- package/docs/harness/cli/schema-and-validation-commands.md +154 -0
- package/docs/harness/cli/search-commands.md +97 -0
- package/docs/harness/cli/spawn-command.md +136 -0
- package/docs/harness/cli/specs-command.md +102 -0
- package/docs/harness/cli/tools-command.md +122 -0
- package/docs/harness/cli/trace-command.md +122 -0
- package/docs/harness/cli-daemon.md +92 -0
- package/docs/harness/event-loop.md +184 -0
- package/docs/harness/hooks/README.md +15 -0
- package/docs/harness/hooks/context-hooks.md +96 -0
- package/docs/harness/hooks/lifecycle-and-observability-hooks.md +135 -0
- package/docs/harness/hooks/validation-hooks.md +97 -0
- package/docs/harness/test-harness.md +149 -0
- package/docs/harness/tui.md +176 -0
- package/docs/memories.md +20 -0
- package/docs/solutions/agentic-issues/premature-agent-deletion-tui-action-dependency-20260130.md +49 -0
- package/docs/solutions/agentic-issues/ref-anchor-scope-mismatch-skill-references-20260131.md +55 -0
- package/docs/solutions/agentic-issues/tautological-tests-routing-20260131.md +52 -0
- package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md +52 -0
- package/docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md +66 -0
- package/docs/solutions/security-issues/unsanitized-domain-path-join-20260131.md +52 -0
- package/docs/solutions/test-failures/event-loop-mock-ordering-checkAgentWindows-20260130.md +63 -0
- package/docs/sync-cli/README.md +19 -0
- package/docs/sync-cli/cli-entrypoint-and-commands.md +39 -0
- package/docs/sync-cli/commands/README.md +11 -0
- package/docs/sync-cli/commands/pull-manifest-command.md +36 -0
- package/docs/sync-cli/commands/push-command.md +84 -0
- package/docs/sync-cli/commands/sync-command.md +71 -0
- package/docs/sync-cli/systems/README.md +14 -0
- package/docs/sync-cli/systems/git-and-github-integration.md +49 -0
- package/docs/sync-cli/systems/interactive-ui.md +43 -0
- package/docs/sync-cli/systems/manifest-and-distribution.md +51 -0
- package/docs/sync-cli/systems/path-resolution.md +42 -0
- package/package.json +46 -0
- package/scripts/install-shim.sh +40 -0
- package/scripts/pre-pack.sh +25 -0
- package/specs/harness-maintenance-skill.spec.md +138 -0
- package/specs/roadmap/git-spec-lifecycle-management.spec.md +113 -0
- package/specs/sync-init-flag.spec.md +117 -0
- package/specs/unified-workflow-orchestration.spec.md +250 -0
- package/specs/validation-tooling-practice.spec.md +98 -0
- package/specs/workflow-domain-configuration.spec.md +265 -0
- package/src/commands/pull-manifest.ts +31 -0
- package/src/commands/push.ts +344 -0
- package/src/commands/sync.ts +289 -0
- package/src/lib/constants.ts +10 -0
- package/src/lib/dotfiles.ts +36 -0
- package/src/lib/fs-utils.ts +18 -0
- package/src/lib/gh.ts +40 -0
- package/src/lib/git.ts +63 -0
- package/src/lib/gitignore.ts +167 -0
- package/src/lib/manifest.ts +121 -0
- package/src/lib/marker-sync.ts +39 -0
- package/src/lib/paths.ts +38 -0
- package/src/lib/target-lines.ts +66 -0
- package/src/lib/ui.ts +78 -0
- package/src/sync-cli.ts +120 -0
- package/target-lines.json +23 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability Hooks
|
|
3
|
+
*
|
|
4
|
+
* Centralized event tracking for debugging and analysis.
|
|
5
|
+
* All events are logged to SQLite + JSONL via trace-store.
|
|
6
|
+
*
|
|
7
|
+
* Events captured:
|
|
8
|
+
* - session-start: Agent session initialized
|
|
9
|
+
* - prompt-submit: User prompt submitted
|
|
10
|
+
* - tool-pre: Pre-tool use (filtered by inclusion list)
|
|
11
|
+
* - tool-post: Post-tool use (filtered by inclusion list)
|
|
12
|
+
* - task-spawn: Task/subagent spawned (special handling for rich metadata)
|
|
13
|
+
* - agent-stop: Agent stopped
|
|
14
|
+
*
|
|
15
|
+
* Filtering:
|
|
16
|
+
* - Bash commands are filtered to only log valuable commands (tldr, ast-grep, git, etc.)
|
|
17
|
+
* - Bash(ah*) is excluded to avoid recursion
|
|
18
|
+
* - Low-value tools (Glob, Grep, Read) are excluded
|
|
19
|
+
* - Task spawns are always logged with full metadata
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { Command } from 'commander';
|
|
23
|
+
import {
|
|
24
|
+
HookInput,
|
|
25
|
+
HookCategory,
|
|
26
|
+
RegisterFn,
|
|
27
|
+
allowTool,
|
|
28
|
+
registerCategory,
|
|
29
|
+
registerCategoryForDaemon,
|
|
30
|
+
} from './shared.js';
|
|
31
|
+
import { logEvent } from '../lib/trace-store.js';
|
|
32
|
+
|
|
33
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
// Filtering Configuration
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Tools to ALWAYS log (high-value orchestration)
|
|
39
|
+
*/
|
|
40
|
+
const ALWAYS_LOG_TOOLS = new Set([
|
|
41
|
+
'Task',
|
|
42
|
+
'EnterPlanMode',
|
|
43
|
+
'ExitPlanMode',
|
|
44
|
+
'AskUserQuestion',
|
|
45
|
+
'Write',
|
|
46
|
+
'Edit',
|
|
47
|
+
'NotebookEdit',
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Tools to NEVER log (high-frequency, low-value)
|
|
52
|
+
*/
|
|
53
|
+
const NEVER_LOG_TOOLS = new Set([
|
|
54
|
+
'Glob',
|
|
55
|
+
'Grep',
|
|
56
|
+
'Read',
|
|
57
|
+
'TaskList',
|
|
58
|
+
'TaskGet',
|
|
59
|
+
'TaskCreate',
|
|
60
|
+
'TaskUpdate',
|
|
61
|
+
'TaskOutput',
|
|
62
|
+
'TaskStop',
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Bash command prefixes to log (valuable for debugging)
|
|
67
|
+
*/
|
|
68
|
+
const BASH_LOG_PREFIXES = [
|
|
69
|
+
'tldr',
|
|
70
|
+
'ast-grep',
|
|
71
|
+
'sg', // ast-grep alias
|
|
72
|
+
'git',
|
|
73
|
+
'npm',
|
|
74
|
+
'pnpm',
|
|
75
|
+
'yarn',
|
|
76
|
+
'pytest',
|
|
77
|
+
'vitest',
|
|
78
|
+
'jest',
|
|
79
|
+
'docker',
|
|
80
|
+
'make',
|
|
81
|
+
'cargo',
|
|
82
|
+
'go ',
|
|
83
|
+
'python',
|
|
84
|
+
'node',
|
|
85
|
+
'uv',
|
|
86
|
+
'pip',
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Bash command prefixes to NEVER log (avoid recursion)
|
|
91
|
+
*/
|
|
92
|
+
const BASH_EXCLUDE_PREFIXES = [
|
|
93
|
+
'ah ',
|
|
94
|
+
'ah\t',
|
|
95
|
+
'echo ',
|
|
96
|
+
'cat ',
|
|
97
|
+
'ls ',
|
|
98
|
+
'cd ',
|
|
99
|
+
'pwd',
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
103
|
+
// Filtering Logic
|
|
104
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Determine if a tool use should be logged
|
|
108
|
+
*/
|
|
109
|
+
function shouldLogTool(toolName: string, toolInput: Record<string, unknown>): boolean {
|
|
110
|
+
// Always log these
|
|
111
|
+
if (ALWAYS_LOG_TOOLS.has(toolName)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Never log these
|
|
116
|
+
if (NEVER_LOG_TOOLS.has(toolName)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Special handling for Bash
|
|
121
|
+
if (toolName === 'Bash') {
|
|
122
|
+
const command = String(toolInput.command || '').trim().toLowerCase();
|
|
123
|
+
|
|
124
|
+
// Exclude certain prefixes
|
|
125
|
+
for (const prefix of BASH_EXCLUDE_PREFIXES) {
|
|
126
|
+
if (command.startsWith(prefix.toLowerCase())) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Include if matches valuable prefixes
|
|
132
|
+
for (const prefix of BASH_LOG_PREFIXES) {
|
|
133
|
+
if (command.startsWith(prefix.toLowerCase())) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Default: don't log unknown bash commands
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Default: log other tools (WebFetch, WebSearch, etc.)
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Extract a summary of the bash command for logging
|
|
148
|
+
*/
|
|
149
|
+
function summarizeBashCommand(command: string): string {
|
|
150
|
+
// Get first line only
|
|
151
|
+
const firstLine = command.split('\n')[0].trim();
|
|
152
|
+
|
|
153
|
+
// Truncate if too long
|
|
154
|
+
if (firstLine.length > 200) {
|
|
155
|
+
return firstLine.slice(0, 200) + '...';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return firstLine;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
162
|
+
// Hook Handlers
|
|
163
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Handle session start event
|
|
167
|
+
*/
|
|
168
|
+
function handleSessionStart(input: HookInput): void {
|
|
169
|
+
logEvent('session.start', {
|
|
170
|
+
session_id: input.session_id,
|
|
171
|
+
transcript_path: input.transcript_path,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Silent exit - don't modify session start
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Handle user prompt submit event
|
|
180
|
+
*/
|
|
181
|
+
function handlePromptSubmit(input: HookInput): void {
|
|
182
|
+
// Extract prompt from tool_input if present
|
|
183
|
+
const prompt = input.tool_input?.prompt || input.tool_input?.message || '(no prompt captured)';
|
|
184
|
+
|
|
185
|
+
logEvent('prompt.submit', {
|
|
186
|
+
session_id: input.session_id,
|
|
187
|
+
prompt,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Silent exit
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Handle pre-tool use event (filtered)
|
|
196
|
+
*/
|
|
197
|
+
function handleToolPre(input: HookInput): void {
|
|
198
|
+
const toolName = input.tool_name || 'unknown';
|
|
199
|
+
const toolInput = input.tool_input || {};
|
|
200
|
+
|
|
201
|
+
if (!shouldLogTool(toolName, toolInput)) {
|
|
202
|
+
// Silent exit - don't log this tool
|
|
203
|
+
allowTool();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Build payload
|
|
207
|
+
const payload: Record<string, unknown> = {
|
|
208
|
+
session_id: input.session_id,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Add tool-specific info
|
|
212
|
+
if (toolName === 'Bash') {
|
|
213
|
+
payload.command_summary = summarizeBashCommand(String(toolInput.command || ''));
|
|
214
|
+
payload.timeout = toolInput.timeout;
|
|
215
|
+
} else if (toolName === 'Task') {
|
|
216
|
+
// Rich metadata for Task spawns
|
|
217
|
+
payload.subagent_type = toolInput.subagent_type;
|
|
218
|
+
payload.description = toolInput.description;
|
|
219
|
+
payload.prompt_preview = String(toolInput.prompt || '').slice(0, 200);
|
|
220
|
+
payload.model = toolInput.model;
|
|
221
|
+
payload.run_in_background = toolInput.run_in_background;
|
|
222
|
+
} else if (toolName === 'Write' || toolName === 'Edit') {
|
|
223
|
+
payload.file_path = toolInput.file_path;
|
|
224
|
+
} else if (toolName === 'AskUserQuestion') {
|
|
225
|
+
payload.questions = toolInput.questions;
|
|
226
|
+
} else {
|
|
227
|
+
// Generic: include a subset of input keys
|
|
228
|
+
const inputKeys = Object.keys(toolInput).slice(0, 5);
|
|
229
|
+
for (const key of inputKeys) {
|
|
230
|
+
payload[key] = toolInput[key];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
logEvent('tool.pre', payload, toolName);
|
|
235
|
+
|
|
236
|
+
// Allow the tool
|
|
237
|
+
allowTool();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Detect if a bash result indicates an error
|
|
242
|
+
*/
|
|
243
|
+
function isBashError(toolResult: unknown): { isError: boolean; exitCode?: number; stderr?: string } {
|
|
244
|
+
if (typeof toolResult === 'string') {
|
|
245
|
+
// Check for common error patterns in output
|
|
246
|
+
const lowerResult = toolResult.toLowerCase();
|
|
247
|
+
if (
|
|
248
|
+
lowerResult.includes('error:') ||
|
|
249
|
+
lowerResult.includes('command not found') ||
|
|
250
|
+
lowerResult.includes('no such file or directory') ||
|
|
251
|
+
lowerResult.includes('permission denied') ||
|
|
252
|
+
lowerResult.includes('fatal:') ||
|
|
253
|
+
lowerResult.includes('traceback (most recent call last)') ||
|
|
254
|
+
lowerResult.includes('syntaxerror:') ||
|
|
255
|
+
lowerResult.includes('typeerror:') ||
|
|
256
|
+
lowerResult.includes('exception:')
|
|
257
|
+
) {
|
|
258
|
+
return { isError: true, stderr: toolResult.slice(0, 500) };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Check if result is an object with error info
|
|
263
|
+
if (typeof toolResult === 'object' && toolResult !== null) {
|
|
264
|
+
const result = toolResult as Record<string, unknown>;
|
|
265
|
+
if (result.exitCode && result.exitCode !== 0) {
|
|
266
|
+
return {
|
|
267
|
+
isError: true,
|
|
268
|
+
exitCode: result.exitCode as number,
|
|
269
|
+
stderr: result.stderr ? String(result.stderr).slice(0, 500) : undefined,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
if (result.error) {
|
|
273
|
+
return { isError: true, stderr: String(result.error).slice(0, 500) };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return { isError: false };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Handle post-tool use event (filtered)
|
|
282
|
+
*/
|
|
283
|
+
function handleToolPost(input: HookInput): void {
|
|
284
|
+
const toolName = input.tool_name || 'unknown';
|
|
285
|
+
const toolInput = input.tool_input || {};
|
|
286
|
+
|
|
287
|
+
if (!shouldLogTool(toolName, toolInput)) {
|
|
288
|
+
// Silent exit
|
|
289
|
+
process.exit(0);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check for bash errors
|
|
293
|
+
if (toolName === 'Bash') {
|
|
294
|
+
const errorCheck = isBashError(input.tool_result);
|
|
295
|
+
if (errorCheck.isError) {
|
|
296
|
+
// Log as bash.error instead of tool.post
|
|
297
|
+
logEvent('bash.error', {
|
|
298
|
+
session_id: input.session_id,
|
|
299
|
+
command_summary: summarizeBashCommand(String(toolInput.command || '')),
|
|
300
|
+
exit_code: errorCheck.exitCode,
|
|
301
|
+
stderr: errorCheck.stderr,
|
|
302
|
+
}, 'Bash');
|
|
303
|
+
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Build payload for successful execution
|
|
309
|
+
const payload: Record<string, unknown> = {
|
|
310
|
+
session_id: input.session_id,
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Add result summary (truncated)
|
|
314
|
+
if (input.tool_result !== undefined) {
|
|
315
|
+
const resultStr = typeof input.tool_result === 'string'
|
|
316
|
+
? input.tool_result
|
|
317
|
+
: JSON.stringify(input.tool_result);
|
|
318
|
+
|
|
319
|
+
payload.result_preview = resultStr.slice(0, 300);
|
|
320
|
+
payload.result_length = resultStr.length;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Add tool-specific info
|
|
324
|
+
if (toolName === 'Write' || toolName === 'Edit') {
|
|
325
|
+
payload.file_path = toolInput.file_path;
|
|
326
|
+
} else if (toolName === 'Task') {
|
|
327
|
+
payload.subagent_type = toolInput.subagent_type;
|
|
328
|
+
payload.description = toolInput.description;
|
|
329
|
+
} else if (toolName === 'Bash') {
|
|
330
|
+
payload.command_summary = summarizeBashCommand(String(toolInput.command || ''));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
logEvent('tool.post', payload, toolName);
|
|
334
|
+
|
|
335
|
+
// Silent exit
|
|
336
|
+
process.exit(0);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Handle tool failure event (PostToolUseFailure hook)
|
|
341
|
+
* This fires when a tool returns an error result
|
|
342
|
+
*/
|
|
343
|
+
function handleToolFailure(input: HookInput): void {
|
|
344
|
+
const toolName = input.tool_name || 'unknown';
|
|
345
|
+
const toolInput = input.tool_input || {};
|
|
346
|
+
|
|
347
|
+
// Log ALL failures (important for debugging)
|
|
348
|
+
const payload: Record<string, unknown> = {
|
|
349
|
+
session_id: input.session_id,
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// Add tool-specific context
|
|
353
|
+
if (toolName === 'Bash') {
|
|
354
|
+
payload.command_summary = summarizeBashCommand(String(toolInput.command || ''));
|
|
355
|
+
} else if (toolName === 'Write' || toolName === 'Edit' || toolName === 'Read') {
|
|
356
|
+
payload.file_path = toolInput.file_path;
|
|
357
|
+
} else if (toolName === 'Task') {
|
|
358
|
+
payload.subagent_type = toolInput.subagent_type;
|
|
359
|
+
payload.description = toolInput.description;
|
|
360
|
+
} else {
|
|
361
|
+
// For other tools, include a subset of input
|
|
362
|
+
const inputKeys = Object.keys(toolInput).slice(0, 5);
|
|
363
|
+
for (const key of inputKeys) {
|
|
364
|
+
payload[`input_${key}`] = toolInput[key];
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Add error from result
|
|
369
|
+
if (input.tool_result !== undefined) {
|
|
370
|
+
const resultStr = typeof input.tool_result === 'string'
|
|
371
|
+
? input.tool_result
|
|
372
|
+
: JSON.stringify(input.tool_result);
|
|
373
|
+
|
|
374
|
+
payload.error = resultStr.slice(0, 500);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
logEvent('tool.failure', payload, toolName);
|
|
378
|
+
|
|
379
|
+
// Silent exit
|
|
380
|
+
process.exit(0);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Handle tool denial event (when a PreToolUse hook denies the tool)
|
|
385
|
+
*/
|
|
386
|
+
function handleToolDenied(input: HookInput, reason: string): void {
|
|
387
|
+
const toolName = input.tool_name || 'unknown';
|
|
388
|
+
const toolInput = input.tool_input || {};
|
|
389
|
+
|
|
390
|
+
const payload: Record<string, unknown> = {
|
|
391
|
+
session_id: input.session_id,
|
|
392
|
+
denial_reason: reason,
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// Add tool-specific context
|
|
396
|
+
if (toolName === 'Bash') {
|
|
397
|
+
payload.command_summary = summarizeBashCommand(String(toolInput.command || ''));
|
|
398
|
+
} else if (toolName === 'Write' || toolName === 'Edit' || toolName === 'Read') {
|
|
399
|
+
payload.file_path = toolInput.file_path;
|
|
400
|
+
} else if (toolName === 'Task') {
|
|
401
|
+
payload.subagent_type = toolInput.subagent_type;
|
|
402
|
+
payload.description = toolInput.description;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
logEvent('tool.denied', payload, toolName);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Handle Task spawn event (special - always logged with rich metadata)
|
|
410
|
+
*
|
|
411
|
+
* This is separate from tool-pre because Task spawns are critical
|
|
412
|
+
* for understanding agent orchestration and should capture all metadata.
|
|
413
|
+
*/
|
|
414
|
+
function handleTaskSpawn(input: HookInput): void {
|
|
415
|
+
const toolInput = input.tool_input || {};
|
|
416
|
+
|
|
417
|
+
const payload: Record<string, unknown> = {
|
|
418
|
+
session_id: input.session_id,
|
|
419
|
+
subagent_type: toolInput.subagent_type,
|
|
420
|
+
description: toolInput.description,
|
|
421
|
+
prompt: toolInput.prompt, // Full prompt for Task spawns
|
|
422
|
+
model: toolInput.model,
|
|
423
|
+
run_in_background: toolInput.run_in_background,
|
|
424
|
+
allowed_tools: toolInput.allowed_tools,
|
|
425
|
+
max_turns: toolInput.max_turns,
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
logEvent('agent.spawn', payload, 'Task');
|
|
429
|
+
|
|
430
|
+
// Allow the task
|
|
431
|
+
allowTool();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Handle agent stop event
|
|
436
|
+
*/
|
|
437
|
+
function handleAgentStop(input: HookInput): void {
|
|
438
|
+
try {
|
|
439
|
+
logEvent('agent.stop', {
|
|
440
|
+
session_id: input.session_id,
|
|
441
|
+
transcript_path: input.transcript_path,
|
|
442
|
+
stop_hook_active: input.stop_hook_active,
|
|
443
|
+
});
|
|
444
|
+
} catch {
|
|
445
|
+
// Silent failure - don't break the stop hook
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Let the lifecycle hook handle the actual stop
|
|
449
|
+
process.exit(0);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Handle agent compact event
|
|
454
|
+
*/
|
|
455
|
+
function handleAgentCompact(input: HookInput): void {
|
|
456
|
+
try {
|
|
457
|
+
logEvent('agent.compact', {
|
|
458
|
+
session_id: input.session_id,
|
|
459
|
+
transcript_path: input.transcript_path,
|
|
460
|
+
});
|
|
461
|
+
} catch {
|
|
462
|
+
// Silent failure - don't break the compact hook
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Let the lifecycle hook handle the actual compaction
|
|
466
|
+
process.exit(0);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Handle pre-tool use (combined handler with Task routing)
|
|
471
|
+
*/
|
|
472
|
+
function handleToolPreWithTaskRouting(input: HookInput): void {
|
|
473
|
+
if (input.tool_name === 'Task') {
|
|
474
|
+
handleTaskSpawn(input);
|
|
475
|
+
} else {
|
|
476
|
+
handleToolPre(input);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
481
|
+
// Hook Category Definition
|
|
482
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
483
|
+
|
|
484
|
+
/** Observability hooks category */
|
|
485
|
+
export const category: HookCategory = {
|
|
486
|
+
name: 'observability',
|
|
487
|
+
description: 'Observability hooks for event tracking',
|
|
488
|
+
hooks: [
|
|
489
|
+
{
|
|
490
|
+
name: 'session-start',
|
|
491
|
+
description: 'Log session start event',
|
|
492
|
+
handler: handleSessionStart,
|
|
493
|
+
errorFallback: { type: 'silent' },
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
name: 'prompt-submit',
|
|
497
|
+
description: 'Log user prompt submit event',
|
|
498
|
+
handler: handlePromptSubmit,
|
|
499
|
+
errorFallback: { type: 'silent' },
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: 'tool-pre',
|
|
503
|
+
description: 'Log pre-tool use event (filtered)',
|
|
504
|
+
handler: handleToolPreWithTaskRouting,
|
|
505
|
+
errorFallback: { type: 'silent' },
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
name: 'tool-post',
|
|
509
|
+
description: 'Log post-tool use event (filtered)',
|
|
510
|
+
handler: handleToolPost,
|
|
511
|
+
errorFallback: { type: 'silent' },
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
name: 'tool-failure',
|
|
515
|
+
description: 'Log tool failure event',
|
|
516
|
+
handler: handleToolFailure,
|
|
517
|
+
errorFallback: { type: 'silent' },
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
name: 'agent-stop',
|
|
521
|
+
description: 'Log agent stop event',
|
|
522
|
+
handler: handleAgentStop,
|
|
523
|
+
errorFallback: { type: 'silent' },
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
name: 'agent-compact',
|
|
527
|
+
description: 'Log agent compact event',
|
|
528
|
+
handler: handleAgentCompact,
|
|
529
|
+
errorFallback: { type: 'silent' },
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
535
|
+
// Command Registration
|
|
536
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
537
|
+
|
|
538
|
+
export function register(parent: Command): void {
|
|
539
|
+
registerCategory(parent, category);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
543
|
+
// Daemon Handler Registration
|
|
544
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Register handlers for daemon mode.
|
|
548
|
+
*/
|
|
549
|
+
export function registerDaemonHandlers(register: RegisterFn): void {
|
|
550
|
+
registerCategoryForDaemon(category, register);
|
|
551
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Hooks - Session lifecycle management
|
|
3
|
+
*
|
|
4
|
+
* Hooks for session start/resume events:
|
|
5
|
+
* - TLDR cache warming (async, non-blocking)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Command } from 'commander';
|
|
9
|
+
import { readHookInput, getProjectDir } from './shared.js';
|
|
10
|
+
import { isTldrInstalled, isTldrDaemonRunning, warmIndex } from '../lib/tldr.js';
|
|
11
|
+
import { logHookStart, logHookSuccess } from '../lib/trace-store.js';
|
|
12
|
+
|
|
13
|
+
const HOOK_TLDR_WARM = 'session tldr-warm';
|
|
14
|
+
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// SessionStart: tldr-warm
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Warm TLDR cache on session start/resume.
|
|
21
|
+
*
|
|
22
|
+
* This hook runs asynchronously and non-blocking:
|
|
23
|
+
* - If TLDR is not installed, exits silently
|
|
24
|
+
* - If daemon is already running, exits silently
|
|
25
|
+
* - Otherwise, starts daemon in background
|
|
26
|
+
*
|
|
27
|
+
* Triggered by: SessionStart matcher "*"
|
|
28
|
+
*/
|
|
29
|
+
async function tldrWarm(): Promise<void> {
|
|
30
|
+
const projectDir = getProjectDir();
|
|
31
|
+
|
|
32
|
+
// Skip if TLDR not installed
|
|
33
|
+
if (!isTldrInstalled()) {
|
|
34
|
+
logHookSuccess(HOOK_TLDR_WARM, { action: 'skip', reason: 'not_installed' });
|
|
35
|
+
console.log('{}');
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Skip if daemon already running
|
|
40
|
+
if (isTldrDaemonRunning(projectDir)) {
|
|
41
|
+
logHookSuccess(HOOK_TLDR_WARM, { action: 'skip', reason: 'daemon_running' });
|
|
42
|
+
console.log('{}');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Start warming in background (non-blocking)
|
|
47
|
+
try {
|
|
48
|
+
await warmIndex(projectDir);
|
|
49
|
+
logHookSuccess(HOOK_TLDR_WARM, { action: 'warmed' });
|
|
50
|
+
} catch {
|
|
51
|
+
// Ignore errors - best effort warming
|
|
52
|
+
logHookSuccess(HOOK_TLDR_WARM, { action: 'skip', reason: 'error' });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Always succeed - don't block session start
|
|
56
|
+
console.log('{}');
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
61
|
+
// Command Registration
|
|
62
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Register session hook subcommands.
|
|
66
|
+
*/
|
|
67
|
+
export function register(parent: Command): void {
|
|
68
|
+
const session = parent
|
|
69
|
+
.command('session')
|
|
70
|
+
.description('Session lifecycle hooks');
|
|
71
|
+
|
|
72
|
+
session
|
|
73
|
+
.command('tldr-warm')
|
|
74
|
+
.description('Warm TLDR cache on session start (SessionStart)')
|
|
75
|
+
.action(async () => {
|
|
76
|
+
try {
|
|
77
|
+
// Read input but don't require it
|
|
78
|
+
await readHookInput().catch(() => ({}));
|
|
79
|
+
logHookStart(HOOK_TLDR_WARM, {});
|
|
80
|
+
await tldrWarm();
|
|
81
|
+
} catch {
|
|
82
|
+
// On any error, exit cleanly
|
|
83
|
+
logHookSuccess(HOOK_TLDR_WARM, { action: 'skip', reason: 'error' });
|
|
84
|
+
console.log('{}');
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|