@codeyam/codeyam-cli 0.1.0-staging.483fdc2 → 0.1.0-staging.62d4615
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/analyzer-template/.build-info.json +7 -7
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +3 -3
- package/analyzer-template/packages/ai/package.json +2 -2
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +9 -1
- package/analyzer-template/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.ts +10 -17
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +154 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +5 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +11 -2
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +2 -2
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.ts +70 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +70 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +20 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +84 -19
- package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +58 -3
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +14 -0
- package/analyzer-template/packages/ai/src/lib/isolateScopes.ts +51 -3
- package/analyzer-template/packages/analyze/index.ts +2 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +51 -3
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +5 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/TransformationTracer.ts +1315 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +4 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +9 -1
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +194 -15
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +260 -22
- package/analyzer-template/packages/analyze/src/lib/index.ts +1 -0
- package/analyzer-template/packages/database/package.json +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts +3 -0
- package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/types/src/types/ProjectMetadata.ts +1 -0
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts +3 -0
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
- package/analyzer-template/project/constructMockCode.ts +36 -1
- package/analyzer-template/project/writeMockDataTsx.ts +111 -17
- package/analyzer-template/project/writeScenarioComponents.ts +60 -12
- package/analyzer-template/project/writeSimpleRoot.ts +21 -11
- package/background/src/lib/virtualized/project/constructMockCode.js +30 -1
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +95 -13
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/background/src/lib/virtualized/project/writeScenarioComponents.js +60 -15
- package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
- package/background/src/lib/virtualized/project/writeSimpleRoot.js +21 -11
- package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +43 -9
- package/codeyam-cli/scripts/apply-setup.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +12 -21
- package/codeyam-cli/src/commands/memory.js.map +1 -1
- package/codeyam-cli/src/utils/backgroundServer.js +4 -0
- package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/utils/install-skills.js +23 -0
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/queue/job.js +4 -0
- package/codeyam-cli/src/utils/queue/job.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js +82 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +128 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js +67 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js +105 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js +34 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js +162 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js +75 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +285 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +83 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js +127 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js +50 -0
- package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +96 -0
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/index.js +5 -0
- package/codeyam-cli/src/utils/ruleReflection/index.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js +33 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js +85 -0
- package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/types.js +5 -0
- package/codeyam-cli/src/utils/ruleReflection/types.js.map +1 -0
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +293 -0
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -0
- package/codeyam-cli/src/utils/rules/index.js +1 -0
- package/codeyam-cli/src/utils/rules/index.js.map +1 -1
- package/codeyam-cli/src/utils/rules/parser.js +0 -28
- package/codeyam-cli/src/utils/rules/parser.js.map +1 -1
- package/codeyam-cli/src/utils/rules/ruleState.js +150 -0
- package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -0
- package/codeyam-cli/src/utils/rules/staleness.js +14 -9
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/database.js +1 -0
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CA3JxPb7.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-DsN1wKrm.js → EntityItem-B86KKU7e.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-DLqD3qNt.js → EntityTypeBadge-B5ctlSYt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-Ba2JVPzP.js → EntityTypeIcon-BqY8gDAW.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-C8lyxW9k.js → InlineSpinner-ClaLpuOo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-aht4aafF.js → InteractivePreview-BDhPilK7.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-CVtiBnY5.js → LibraryFunctionPreview-VeqEBv9v.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-B0GLXMsr.js → LoadingDots-Bs7Nn1Jr.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-xgeCVgSM.js → LogViewer-Bm3PmcCz.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-OApQuNyq.js → ReportIssueModal-C6PKeMYR.js} +3 -8
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-DuDvi0jm.js → SafeScreenshot-Gq3Ocjo6.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-DzccYyI8.js → ScenarioViewer-BNLaXBHR.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-DyFZkK0l.js → TruncatedFilePath-CiwXDxLh.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{_index-BwqWJOgH.js → _index-B3TDXxnk.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BwavGCpm.js → activity.(_tab)-DD1r_QU0.js} +6 -11
- package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DfKzxuoe.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.agent-transcripts-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.save-fixture-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/book-open-PttOB2SF.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-Cx24_aWc.js → chevron-down-TJp6ofnp.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-EPOLDU6W-CXRTFQ3F.js → chunk-JZWAC4HX-JE9ZIoBl.js} +12 -12
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-BOARzkeR.js → circle-check-CXhHQYrI.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-6y9ALfGT.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-BdhJEx6B.js → createLucideIcon-Ca9fAY46.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-BBnGWYga.js → dev.empty-C5lqplTC.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-BJUiQqZF.js → entity._sha._-n38keI1k.js} +10 -10
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-DavjRmOY.js → entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-D1T4TGjf.js → entity._sha_.create-scenario-DGgZjdFg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-CTBG2mmz.js → entity._sha_.edit._scenarioId-38yPijoD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-CS2cb_eZ.js → entry.client-BSHEfydn.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DMJ7zii9.js → fileTableUtils-DCPhhSMo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{files-CJ6lTdTA.js → files-Dk8wkAS7.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{git-CPTZZ-JZ.js → git-DXnyr8uP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-Bh6jH0cL.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-lzqtyFU8.js → index-CcsFv748.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-B1h680n5.js → index-ChN9-fAY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-BUvfJMNR.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-B7B9V-bu.js → loader-circle-CTqLEAGU.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-d4e77269.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-DCHBwHou.js +76 -0
- package/codeyam-cli/src/webserver/build/client/assets/pause-D6vreykR.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/root-D6oziHts.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-CxXUmBSd.js → search-B8VUL8nl.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{settings-CS5f3WzT.js → settings-B2X7lJgQ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-DwFIBT09.js → simulations-CPoAg7Zo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/terminal-BrCP7uQo.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-B6LgvRJg.js → triangle-alert-BZz2NjYa.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-C1v1PQzo.js → useCustomSizes-DNwUduNu.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-aSv48UbS.js → useLastLogLine-COky1GVF.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-DYxHZQuP.js → useReportContext-CpZgwliL.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-mBRpZPiu.js → useToast-Bv9JFvUO.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-TD1f-DHV.js → index-C0KrUQp-.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-C2h1v1XD.js +260 -0
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/templates/codeyam-memory-hook.sh +9 -10
- package/codeyam-cli/templates/codeyam:memory.md +10 -9
- package/codeyam-cli/templates/codeyam:new-rule.md +0 -39
- package/codeyam-cli/templates/rule-notification-hook.py +54 -0
- package/codeyam-cli/templates/rule-reflection-hook.py +356 -89
- package/codeyam-cli/templates/rules-instructions.md +19 -22
- package/package.json +2 -2
- package/packages/ai/src/lib/analyzeScope.js +7 -1
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.js +10 -14
- package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +134 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +5 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +11 -2
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +2 -2
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js +63 -0
- package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js.map +1 -0
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +63 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +15 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +78 -17
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
- package/packages/ai/src/lib/generateEntityDataStructure.js +46 -2
- package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +10 -0
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/isolateScopes.js +39 -3
- package/packages/ai/src/lib/isolateScopes.js.map +1 -1
- package/packages/analyze/index.js +1 -0
- package/packages/analyze/index.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +41 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +3 -0
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js +880 -0
- package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js.map +1 -0
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +5 -1
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +9 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +116 -13
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +231 -22
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/index.js +1 -0
- package/packages/analyze/src/lib/index.js.map +1 -1
- package/codeyam-cli/src/utils/reviewedRules.js +0 -92
- package/codeyam-cli/src/utils/reviewedRules.js.map +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-Bb-80kDT.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/file-code-Dhef1kWN.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/globals-CX9f-5xM.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-bba56ec1.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-DuTFSyJ2.js +0 -92
- package/codeyam-cli/src/webserver/build/client/assets/root-DTfSQARG.js +0 -62
- package/codeyam-cli/src/webserver/build/server/assets/server-build-BQ-1XyEa.js +0 -258
|
@@ -2,64 +2,199 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Rule reflection hook for Claude Code.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Two responsibilities, now split into independent agents:
|
|
6
|
+
1. Check for stale rules (files changed since rule was last reviewed) and prompt review
|
|
7
|
+
2. Review conversation for confusion signals (mistakes, corrections, interruptions)
|
|
8
|
+
|
|
9
|
+
Each fires as a separate `claude -p` invocation so the LLM can focus on one task at a time.
|
|
10
|
+
Stays silent if there's nothing to review.
|
|
11
|
+
|
|
12
|
+
Prompt text lives in templates/prompts/*.txt (single source of truth shared with TypeScript tests).
|
|
7
13
|
"""
|
|
8
14
|
|
|
9
15
|
import json
|
|
16
|
+
import os
|
|
17
|
+
import subprocess
|
|
10
18
|
import sys
|
|
11
19
|
from pathlib import Path
|
|
12
20
|
|
|
13
|
-
MIN_USER_TURNS =
|
|
21
|
+
MIN_USER_TURNS = 3 # Minimum user turns before checking for confusion
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
# Signals that indicate confusion, mistakes, or user corrections
|
|
24
|
+
CONFUSION_SIGNALS = [
|
|
25
|
+
'no,', 'no ', "that's not", "thats not", "that is not",
|
|
26
|
+
'wrong', 'incorrect', 'actually,', 'actually ',
|
|
27
|
+
"i meant", "i mean", "not what i", "stop", "wait",
|
|
28
|
+
"don't do", "dont do", "shouldn't", "should not",
|
|
29
|
+
"try again", "let me clarify", "to clarify",
|
|
30
|
+
"that broke", "that failed", "error", "bug",
|
|
31
|
+
]
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
stop_hook_active = hook_input.get('stop_hook_active', False)
|
|
33
|
+
# Prompt templates directory — installed alongside this hook in .codeyam/bin/prompts/
|
|
34
|
+
PROMPTS_DIR = Path(__file__).parent / 'prompts'
|
|
26
35
|
|
|
27
|
-
# Prevent infinite loops - if we're already in a stop hook continuation, exit silently
|
|
28
|
-
if stop_hook_active:
|
|
29
|
-
return
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
def load_prompt_template(name, **kwargs):
|
|
38
|
+
"""
|
|
39
|
+
Load a prompt template from the prompts/ directory and substitute placeholders.
|
|
40
|
+
Placeholders use {{KEY}} syntax (e.g., {{CONTEXT_FILE}}, {{PROJECT_DIR}}).
|
|
41
|
+
"""
|
|
42
|
+
template_path = PROMPTS_DIR / name
|
|
43
|
+
text = template_path.read_text()
|
|
44
|
+
for key, value in kwargs.items():
|
|
45
|
+
text = text.replace(f'{{{{{key}}}}}', str(value))
|
|
46
|
+
return text
|
|
33
47
|
|
|
34
|
-
# Marker file tracks last checked line per session
|
|
35
|
-
marker_dir = Path('/tmp/claude-rule-markers')
|
|
36
|
-
marker_dir.mkdir(exist_ok=True)
|
|
37
|
-
marker_file = marker_dir / f'{session_id}.marker'
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if
|
|
49
|
+
def has_confusion_signals(conversation_snippets):
|
|
50
|
+
"""
|
|
51
|
+
Check if the conversation contains signals of confusion or user corrections.
|
|
52
|
+
Returns True if confusion signals are detected.
|
|
53
|
+
"""
|
|
54
|
+
for snippet in conversation_snippets:
|
|
55
|
+
if snippet['role'] != 'user':
|
|
56
|
+
continue
|
|
57
|
+
content_lower = snippet['content'].lower()
|
|
58
|
+
for signal in CONFUSION_SIGNALS:
|
|
59
|
+
if signal in content_lower:
|
|
60
|
+
return True
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_file_diff(file_path, max_lines=50):
|
|
65
|
+
"""
|
|
66
|
+
Get git diff for a file. Tries staged diff first, then unstaged.
|
|
67
|
+
Returns truncated diff string or empty string.
|
|
68
|
+
"""
|
|
69
|
+
for diff_cmd in [
|
|
70
|
+
['git', 'diff', 'HEAD', '--', file_path],
|
|
71
|
+
['git', 'diff', '--', file_path],
|
|
72
|
+
]:
|
|
42
73
|
try:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
74
|
+
result = subprocess.run(
|
|
75
|
+
diff_cmd, capture_output=True, text=True, timeout=10
|
|
76
|
+
)
|
|
77
|
+
if result.stdout.strip():
|
|
78
|
+
lines = result.stdout.strip().split('\n')
|
|
79
|
+
# Skip the diff header (--- a/, +++ b/, @@ lines)
|
|
80
|
+
content_lines = [l for l in lines if not l.startswith('diff ') and
|
|
81
|
+
not l.startswith('index ') and not l.startswith('--- ') and
|
|
82
|
+
not l.startswith('+++ ')]
|
|
83
|
+
if len(content_lines) > max_lines:
|
|
84
|
+
content_lines = content_lines[:max_lines] + [f'... ({len(lines) - max_lines} more lines)']
|
|
85
|
+
return '\n'.join(content_lines)
|
|
86
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
87
|
+
continue
|
|
88
|
+
return ''
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def read_rule_content(rule_name):
|
|
92
|
+
"""
|
|
93
|
+
Read a rule file and return its content after YAML frontmatter.
|
|
94
|
+
Searches in .claude/rules/ directory.
|
|
95
|
+
"""
|
|
96
|
+
# Search for the rule file
|
|
97
|
+
rules_dir = Path('.claude/rules')
|
|
98
|
+
if not rules_dir.exists():
|
|
99
|
+
return ''
|
|
100
|
+
|
|
101
|
+
# Find the file - could be at any depth
|
|
102
|
+
matches = list(rules_dir.rglob(rule_name))
|
|
103
|
+
if not matches:
|
|
104
|
+
return ''
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
text = matches[0].read_text()
|
|
108
|
+
except IOError:
|
|
109
|
+
return ''
|
|
110
|
+
|
|
111
|
+
# Strip YAML frontmatter
|
|
112
|
+
if text.startswith('---'):
|
|
113
|
+
end = text.find('---', 3)
|
|
114
|
+
if end != -1:
|
|
115
|
+
text = text[end + 3:].strip()
|
|
116
|
+
|
|
117
|
+
return text
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_stale_rules():
|
|
121
|
+
"""
|
|
122
|
+
Run `codeyam memory status` and parse the output to find stale rules.
|
|
123
|
+
Returns a list of dicts with rule info, or empty list if none stale.
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
# Use the local codeyam CLI via node to avoid PATH issues
|
|
127
|
+
project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
|
|
128
|
+
codeyam_js = os.path.join(project_dir, 'codeyam-cli', 'dist', 'codeyam-cli', 'src', 'codeyam-cli.js')
|
|
129
|
+
if os.path.exists(codeyam_js):
|
|
130
|
+
cmd = ['node', '--no-warnings', codeyam_js, 'memory', 'status']
|
|
131
|
+
else:
|
|
132
|
+
cmd = ['codeyam', 'memory', 'status']
|
|
133
|
+
result = subprocess.run(
|
|
134
|
+
cmd,
|
|
135
|
+
capture_output=True,
|
|
136
|
+
text=True,
|
|
137
|
+
timeout=30
|
|
138
|
+
)
|
|
139
|
+
output = result.stdout
|
|
140
|
+
|
|
141
|
+
# Check if there are stale rules
|
|
142
|
+
if 'Found' not in output or 'stale rule' not in output:
|
|
143
|
+
return []
|
|
46
144
|
|
|
47
|
-
|
|
145
|
+
# Parse the output to extract stale rule information
|
|
146
|
+
stale_rules = []
|
|
147
|
+
lines = output.split('\n')
|
|
148
|
+
i = 0
|
|
149
|
+
while i < len(lines):
|
|
150
|
+
line = lines[i].strip()
|
|
151
|
+
# Look for rule filenames (lines that end with .md and aren't indented much)
|
|
152
|
+
if line.endswith('.md') and not line.startswith('Rule') and not line.startswith('Newest'):
|
|
153
|
+
rule_info = {'name': line}
|
|
154
|
+
# Look for the next few lines for details
|
|
155
|
+
for j in range(i + 1, min(i + 4, len(lines))):
|
|
156
|
+
detail = lines[j].strip()
|
|
157
|
+
if detail.startswith('Rule timestamp:'):
|
|
158
|
+
rule_info['rule_timestamp'] = detail.replace('Rule timestamp:', '').strip()
|
|
159
|
+
elif detail.startswith('Newest file:'):
|
|
160
|
+
rule_info['newest_file'] = detail.replace('Newest file:', '').strip()
|
|
161
|
+
elif detail.startswith('File modified:'):
|
|
162
|
+
rule_info['file_modified'] = detail.replace('File modified:', '').strip()
|
|
163
|
+
# Get diff for the changed file
|
|
164
|
+
if rule_info.get('newest_file'):
|
|
165
|
+
rule_info['diff'] = get_file_diff(rule_info['newest_file'])
|
|
166
|
+
|
|
167
|
+
# Get inline rule content
|
|
168
|
+
rule_info['rule_content'] = read_rule_content(rule_info['name'])
|
|
169
|
+
|
|
170
|
+
stale_rules.append(rule_info)
|
|
171
|
+
i += 1
|
|
172
|
+
|
|
173
|
+
return stale_rules
|
|
174
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, Exception):
|
|
175
|
+
return []
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def get_conversation_context(transcript_path, last_line):
|
|
179
|
+
"""
|
|
180
|
+
Extract conversation snippets and modified files from transcript for rule review.
|
|
181
|
+
Returns (user_turn_count, conversation_snippets, modified_files, current_line_count)
|
|
182
|
+
"""
|
|
48
183
|
try:
|
|
49
184
|
with open(transcript_path, 'r') as f:
|
|
50
185
|
all_lines = f.readlines()
|
|
51
186
|
except IOError:
|
|
52
|
-
return
|
|
187
|
+
return 0, [], set(), 0
|
|
53
188
|
|
|
54
189
|
current_line_count = len(all_lines)
|
|
55
190
|
new_lines = all_lines[last_line:]
|
|
56
191
|
|
|
57
192
|
if not new_lines:
|
|
58
|
-
return
|
|
193
|
+
return 0, [], set(), current_line_count
|
|
59
194
|
|
|
60
|
-
# Count user turns and extract conversation content from new lines
|
|
61
195
|
user_turn_count = 0
|
|
62
196
|
conversation_snippets = []
|
|
197
|
+
modified_files = set()
|
|
63
198
|
|
|
64
199
|
for line in new_lines:
|
|
65
200
|
try:
|
|
@@ -75,87 +210,219 @@ def main():
|
|
|
75
210
|
|
|
76
211
|
# Handle string content
|
|
77
212
|
if isinstance(content, str):
|
|
78
|
-
# Skip meta messages and very short content
|
|
79
213
|
if obj.get('isMeta') or len(content) < 20:
|
|
80
214
|
continue
|
|
81
|
-
# Skip tool results (they show up as user messages)
|
|
82
215
|
if content.startswith('[{') or '<tool_result' in content:
|
|
83
216
|
continue
|
|
84
217
|
|
|
85
|
-
# Count substantive user turns
|
|
86
218
|
if is_external_user and not content.startswith('<'):
|
|
87
219
|
user_turn_count += 1
|
|
88
220
|
|
|
89
221
|
conversation_snippets.append({
|
|
90
222
|
'role': message.get('role', msg_type),
|
|
91
|
-
'content': content
|
|
223
|
+
'content': content
|
|
92
224
|
})
|
|
93
225
|
|
|
94
|
-
# Handle array content (tool calls, etc.)
|
|
95
226
|
elif isinstance(content, list):
|
|
96
227
|
for item in content:
|
|
97
|
-
if isinstance(item, dict):
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
228
|
+
if not isinstance(item, dict):
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
# Extract text snippets
|
|
232
|
+
if item.get('type') == 'text':
|
|
233
|
+
text = item.get('text', '')
|
|
234
|
+
if len(text) > 20:
|
|
235
|
+
conversation_snippets.append({
|
|
236
|
+
'role': message.get('role', msg_type),
|
|
237
|
+
'content': text
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
# Track file modifications from tool_use entries
|
|
241
|
+
if item.get('type') == 'tool_use':
|
|
242
|
+
tool_name = item.get('name', '')
|
|
243
|
+
tool_input = item.get('input', {})
|
|
244
|
+
if tool_name in ('Edit', 'Write') and tool_input.get('file_path'):
|
|
245
|
+
modified_files.add((tool_input['file_path'], tool_name))
|
|
246
|
+
|
|
105
247
|
except (json.JSONDecodeError, KeyError):
|
|
106
248
|
continue
|
|
107
249
|
|
|
108
|
-
|
|
109
|
-
if user_turn_count < MIN_USER_TURNS:
|
|
110
|
-
return
|
|
250
|
+
return user_turn_count, conversation_snippets, modified_files, current_line_count
|
|
111
251
|
|
|
112
|
-
# Update marker with current line count
|
|
113
|
-
marker_file.write_text(str(current_line_count))
|
|
114
252
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
253
|
+
def build_stale_rules_context(stale_rules):
|
|
254
|
+
"""Build context content for stale rules review."""
|
|
255
|
+
parts = []
|
|
256
|
+
parts.append("# Reflection Step\n")
|
|
257
|
+
parts.append("Please review the stale rules below to determine if any need updating based on recent code changes.\n")
|
|
258
|
+
parts.append("Please show your thinking regarding the stale rules.\n")
|
|
259
|
+
parts.append("## Stale Rules to Review\n")
|
|
260
|
+
parts.append("The following rules have files that changed since the rule was last reviewed.")
|
|
261
|
+
parts.append("For each rule, review the rule content and the diff of changes, then:")
|
|
262
|
+
parts.append("1. Determine if the rule content needs updating based on the code changes")
|
|
263
|
+
parts.append("2. Update the rule if needed")
|
|
264
|
+
parts.append("3. ALWAYS update the timestamp (run `codeyam memory touch`)\n")
|
|
118
265
|
|
|
119
|
-
|
|
266
|
+
for rule in stale_rules:
|
|
267
|
+
parts.append(f"### {rule['name']}")
|
|
268
|
+
if rule.get('rule_content'):
|
|
269
|
+
parts.append(f" Rule content:")
|
|
270
|
+
for line in rule['rule_content'].split('\n'):
|
|
271
|
+
parts.append(f" {line}")
|
|
272
|
+
if rule.get('newest_file'):
|
|
273
|
+
parts.append(f" Changed file: {rule['newest_file']}")
|
|
274
|
+
if rule.get('file_modified'):
|
|
275
|
+
parts.append(f" File modified: {rule['file_modified']}")
|
|
276
|
+
if rule.get('rule_timestamp'):
|
|
277
|
+
parts.append(f" Rule timestamp: {rule['rule_timestamp']}")
|
|
278
|
+
if rule.get('diff'):
|
|
279
|
+
parts.append(f" Changes:")
|
|
280
|
+
for line in rule['diff'].split('\n'):
|
|
281
|
+
parts.append(f" {line}")
|
|
282
|
+
parts.append("")
|
|
283
|
+
|
|
284
|
+
return '\n'.join(parts)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def build_conversation_context(conversation_snippets, modified_files):
|
|
288
|
+
"""Build context content for conversation review."""
|
|
289
|
+
parts = []
|
|
290
|
+
parts.append("## Conversation Review\n")
|
|
291
|
+
parts.append(
|
|
292
|
+
"Review this session for rule-worthy learnings: architectural decisions, tribal knowledge, "
|
|
293
|
+
"confusion, mistakes, or corrections that future sessions would benefit from knowing.\n"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# Load guidance from shared template file
|
|
297
|
+
guidance = (PROMPTS_DIR / 'conversation-guidance.txt').read_text()
|
|
298
|
+
parts.append(guidance)
|
|
299
|
+
|
|
300
|
+
if modified_files:
|
|
301
|
+
parts.append("Files modified this session:")
|
|
302
|
+
for file_path, tool_name in sorted(modified_files):
|
|
303
|
+
parts.append(f"- {file_path} ({tool_name})")
|
|
304
|
+
parts.append("")
|
|
305
|
+
|
|
306
|
+
parts.append("### Session transcript\n")
|
|
120
307
|
summary_lines = []
|
|
121
|
-
for snippet in conversation_snippets
|
|
308
|
+
for snippet in conversation_snippets:
|
|
122
309
|
role = snippet['role']
|
|
123
|
-
content = snippet['content'].replace('\n', ' ')
|
|
310
|
+
content = snippet['content'].replace('\n', ' ')
|
|
124
311
|
summary_lines.append(f"[{role}]: {content}")
|
|
312
|
+
parts.append('\n'.join(summary_lines))
|
|
125
313
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
314
|
+
return '\n'.join(parts)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def spawn_claude_agent(prompt, log_file, project_dir):
|
|
318
|
+
"""Spawn a detached claude -p agent as a background process."""
|
|
319
|
+
try:
|
|
320
|
+
log_fh = open(log_file, 'w')
|
|
321
|
+
env = os.environ.copy()
|
|
322
|
+
env['CODEYAM_RULE_AGENT'] = '1'
|
|
323
|
+
subprocess.Popen(
|
|
324
|
+
['claude', '-p', prompt,
|
|
325
|
+
'--model', 'haiku',
|
|
326
|
+
'--output-format', 'stream-json', '--verbose',
|
|
327
|
+
'--allowedTools', 'Read,Edit,Write,Bash,Glob,Grep'],
|
|
328
|
+
cwd=project_dir,
|
|
329
|
+
stdout=log_fh,
|
|
330
|
+
stderr=log_fh,
|
|
331
|
+
env=env,
|
|
332
|
+
start_new_session=True,
|
|
333
|
+
)
|
|
334
|
+
except FileNotFoundError:
|
|
335
|
+
pass # claude CLI not available, skip silently
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def main():
|
|
339
|
+
# Read hook input from stdin
|
|
340
|
+
try:
|
|
341
|
+
hook_input = json.load(sys.stdin)
|
|
342
|
+
except json.JSONDecodeError:
|
|
343
|
+
return
|
|
344
|
+
|
|
345
|
+
session_id = hook_input.get('session_id', '')
|
|
346
|
+
transcript_path = hook_input.get('transcript_path', '')
|
|
347
|
+
stop_hook_active = hook_input.get('stop_hook_active', False)
|
|
348
|
+
|
|
349
|
+
# Prevent infinite loops — stop_hook_active covers same-process recursion,
|
|
350
|
+
# env var covers spawned subagent sessions triggering the hook on exit
|
|
351
|
+
if stop_hook_active or os.environ.get('CODEYAM_RULE_AGENT'):
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
if not session_id or not transcript_path:
|
|
355
|
+
return
|
|
356
|
+
|
|
357
|
+
marker_dir = Path('/tmp/claude-rule-markers')
|
|
358
|
+
marker_dir.mkdir(exist_ok=True)
|
|
359
|
+
marker_file = marker_dir / f'{session_id}.marker'
|
|
360
|
+
|
|
361
|
+
# Read last checked line
|
|
362
|
+
last_line = 0
|
|
363
|
+
if marker_file.exists():
|
|
364
|
+
try:
|
|
365
|
+
last_line = int(marker_file.read_text().strip())
|
|
366
|
+
except (ValueError, IOError):
|
|
367
|
+
last_line = 0
|
|
368
|
+
|
|
369
|
+
# Check for stale rules
|
|
370
|
+
stale_rules = get_stale_rules()
|
|
371
|
+
|
|
372
|
+
# Get conversation context
|
|
373
|
+
user_turn_count, conversation_snippets, modified_files, current_line_count = get_conversation_context(
|
|
374
|
+
transcript_path, last_line
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
# Determine what to include in review
|
|
378
|
+
has_stale_rules = len(stale_rules) > 0
|
|
379
|
+
has_conversation = len(conversation_snippets) > 0
|
|
380
|
+
|
|
381
|
+
# Only fire if there's something to review
|
|
382
|
+
if not has_stale_rules and not has_conversation:
|
|
383
|
+
return
|
|
384
|
+
|
|
385
|
+
# Update marker
|
|
386
|
+
marker_file.write_text(str(current_line_count))
|
|
387
|
+
|
|
388
|
+
project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
|
|
389
|
+
|
|
390
|
+
# Unique suffix per invocation so each Stop produces a distinct transcript
|
|
391
|
+
from datetime import datetime
|
|
392
|
+
invocation_ts = datetime.now().strftime('%Y%m%d-%H%M%S')
|
|
393
|
+
invocation_id = f'{session_id}-{invocation_ts}'
|
|
394
|
+
|
|
395
|
+
# Spawn independent agent for stale rules review
|
|
396
|
+
if has_stale_rules:
|
|
397
|
+
stale_context = build_stale_rules_context(stale_rules)
|
|
398
|
+
stale_context_file = marker_dir / f'{invocation_id}-stale.context'
|
|
399
|
+
stale_context_file.write_text(stale_context)
|
|
400
|
+
|
|
401
|
+
stale_log_file = marker_dir / f'{invocation_id}-stale.log'
|
|
402
|
+
stale_notification_file = marker_dir / 'rule-notification-stale.md'
|
|
403
|
+
stale_prompt = load_prompt_template(
|
|
404
|
+
'stale-rules-prompt.txt',
|
|
405
|
+
CONTEXT_FILE=str(stale_context_file),
|
|
406
|
+
NOTIFICATION_FILE=str(stale_notification_file),
|
|
407
|
+
PROJECT_DIR=project_dir,
|
|
408
|
+
)
|
|
409
|
+
spawn_claude_agent(stale_prompt, stale_log_file, project_dir)
|
|
410
|
+
|
|
411
|
+
# Spawn independent agent for conversation review
|
|
412
|
+
if has_conversation:
|
|
413
|
+
conv_context = build_conversation_context(conversation_snippets, modified_files)
|
|
414
|
+
conv_context_file = marker_dir / f'{invocation_id}-conversation.context'
|
|
415
|
+
conv_context_file.write_text(conv_context)
|
|
416
|
+
|
|
417
|
+
conv_log_file = marker_dir / f'{invocation_id}-conversation.log'
|
|
418
|
+
conv_notification_file = marker_dir / 'rule-notification-conversation.md'
|
|
419
|
+
conv_prompt = load_prompt_template(
|
|
420
|
+
'conversation-prompt.txt',
|
|
421
|
+
CONTEXT_FILE=str(conv_context_file),
|
|
422
|
+
NOTIFICATION_FILE=str(conv_notification_file),
|
|
423
|
+
PROJECT_DIR=project_dir,
|
|
424
|
+
)
|
|
425
|
+
spawn_claude_agent(conv_prompt, conv_log_file, project_dir)
|
|
159
426
|
|
|
160
427
|
if __name__ == '__main__':
|
|
161
428
|
main()
|
|
@@ -19,34 +19,33 @@ Create a new rule when:
|
|
|
19
19
|
|
|
20
20
|
## Before Creating: The Confusion Test
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Only create rules that document genuinely confusing aspects—not things Claude can figure out by reading code and will likely come up again in future sessions.
|
|
23
23
|
|
|
24
|
-
**
|
|
24
|
+
**Ask yourself:**
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
- If
|
|
26
|
+
1. **Could Claude figure this out by reading the code?**
|
|
27
|
+
- If YES → don't create the rule
|
|
28
|
+
- If NO → proceed
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
2. **Does this explain "why" not just "what"?**
|
|
31
|
+
- Good: Historical context, gotchas, non-obvious behavior, non-obvious architectural decisions
|
|
32
|
+
- Bad: Bug fixes, Limitations (unless the user requests the limitation be noted), What functions do (unless providing a high-level architectural overview)
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
**3. Would this have prevented a past mistake?**
|
|
35
|
-
|
|
36
|
-
- If you can point to a commit, bug, or confusion this would have prevented → create it
|
|
37
|
-
- If it's just "nice to know" information → skip it
|
|
34
|
+
3. **Would this have prevented a past mistake?**
|
|
35
|
+
- If you can point to a bug or confusion this would have prevented → create it
|
|
36
|
+
- If it's just "nice to know" → skip it
|
|
38
37
|
|
|
39
38
|
### Examples
|
|
40
39
|
|
|
41
40
|
**✅ Worth documenting:**
|
|
42
41
|
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
42
|
+
- Where to add new functionality
|
|
43
|
+
- An overview of all files, classes, functions, etc used in a particular part of the repo
|
|
44
|
+
- Debugging strategies for a particular area of the repo
|
|
45
|
+
- "Use `pnpm test` to run tests" (if there is more than one way to run tests and this way is preferred)
|
|
46
46
|
|
|
47
47
|
**❌ Not worth documenting:**
|
|
48
48
|
|
|
49
|
-
- "Use `pnpm jest` to run tests" (obvious from package.json)
|
|
50
49
|
- "The auth module handles authentication" (obvious from reading code)
|
|
51
50
|
- "This function takes X and returns Y" (Claude can read the signature)
|
|
52
51
|
|
|
@@ -80,16 +79,14 @@ Rules mirror the source code structure:
|
|
|
80
79
|
paths:
|
|
81
80
|
- 'specific/path/to/file.ts'
|
|
82
81
|
- 'another/specific/path/*.ts'
|
|
83
|
-
category: architecture | testing | faq
|
|
84
82
|
timestamp: 2026-01-30T00:00:00Z
|
|
85
83
|
---
|
|
86
84
|
```
|
|
87
85
|
|
|
88
|
-
| Field | Purpose
|
|
89
|
-
| ----------- |
|
|
90
|
-
| `paths` | Glob patterns - be specific to avoid loading rules unnecessarily
|
|
91
|
-
| `
|
|
92
|
-
| `timestamp` | ISO 8601 - update when rule is reviewed |
|
|
86
|
+
| Field | Purpose |
|
|
87
|
+
| ----------- | ---------------------------------------------------------------- |
|
|
88
|
+
| `paths` | Glob patterns - be specific to avoid loading rules unnecessarily |
|
|
89
|
+
| `timestamp` | ISO 8601 - update when rule is reviewed |
|
|
93
90
|
|
|
94
91
|
## Content Guidelines
|
|
95
92
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeyam/codeyam-cli",
|
|
3
|
-
"version": "0.1.0-staging.
|
|
3
|
+
"version": "0.1.0-staging.62d4615",
|
|
4
4
|
"description": "Local development CLI for CodeYam analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"pluralize": "^8.0.0",
|
|
53
53
|
"prompts": "^2.4.2",
|
|
54
54
|
"react": "^19.2.3",
|
|
55
|
-
"react-diff-viewer-continued": "
|
|
55
|
+
"react-diff-viewer-continued": "4.0.6",
|
|
56
56
|
"react-dom": "^19.2.3",
|
|
57
57
|
"react-markdown": "^10.1.0",
|
|
58
58
|
"react-resizable": "^3.0.5",
|
|
@@ -94,9 +94,14 @@ function ensureWorkerPool() {
|
|
|
94
94
|
}
|
|
95
95
|
// Note: WORKER_PATH is null when __mocks__/analyzeScope.ts is active
|
|
96
96
|
const { WORKER_PATH } = analyzeScopeWorkerPaths();
|
|
97
|
+
// Disable workers when tracing is enabled - we need access to ScopeDataStructure
|
|
98
|
+
// instance in the main thread to capture pre-serialization state
|
|
99
|
+
const tracingEnabled = process.env.CODEYAM_TRACE_TRANSFORMS === '1' ||
|
|
100
|
+
process.env.CODEYAM_TRACE_TRANSFORMS === 'true';
|
|
97
101
|
if (process.env.USE_WORKER_THREADS &&
|
|
98
102
|
WORKER_PATH &&
|
|
99
|
-
fs.existsSync(WORKER_PATH)
|
|
103
|
+
fs.existsSync(WORKER_PATH) &&
|
|
104
|
+
!tracingEnabled) {
|
|
100
105
|
console.log('CodeYam: Using worker threads for analyzeScope', {
|
|
101
106
|
WORKER_PATH,
|
|
102
107
|
});
|
|
@@ -124,6 +129,7 @@ function ensureWorkerPool() {
|
|
|
124
129
|
WORKER_PATH,
|
|
125
130
|
workerExists: WORKER_PATH ? fs.existsSync(WORKER_PATH) : false,
|
|
126
131
|
USE_WORKER_THREADS: process.env.USE_WORKER_THREADS,
|
|
132
|
+
tracingEnabled,
|
|
127
133
|
});
|
|
128
134
|
workerPool = null; // Explicitly set to indicate "no workers"
|
|
129
135
|
}
|