@codeyam/codeyam-cli 0.1.0-staging.62d4615 → 0.1.0-staging.73a4bf4
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 +1 -1
- package/analyzer-template/packages/ai/index.ts +1 -0
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +14 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +101 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/sharedPatterns.ts +28 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +6 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +176 -8
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +70 -13
- package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +33 -15
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +32 -5
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +38 -2
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +359 -142
- package/analyzer-template/packages/ai/src/lib/mergeJsonTypeDefinitions.ts +5 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/collapseNullableObjects.ts +118 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +24 -4
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +18 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +50 -25
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +153 -76
- package/analyzer-template/packages/database/src/lib/analysisBranchToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/analysisToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/branchToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/commitBranchToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/commitToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/fileToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/kysely/db.ts +6 -0
- package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +1 -1
- package/analyzer-template/packages/database/src/lib/kysely/tables/labsRequestsTable.ts +52 -0
- package/analyzer-template/packages/database/src/lib/projectToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/saveFiles.ts +1 -1
- package/analyzer-template/packages/database/src/lib/scenarioToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/userScenarioToDb.ts +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +3 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts +23 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts.map +1 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
- package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts +4 -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 +7 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts +4 -0
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +93 -2
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +108 -2
- package/analyzer-template/project/constructMockCode.ts +2 -2
- package/analyzer-template/project/writeMockDataTsx.ts +14 -6
- package/background/src/lib/local/createLocalAnalyzer.js +1 -1
- package/background/src/lib/local/createLocalAnalyzer.js.map +1 -1
- package/background/src/lib/virtualized/project/constructMockCode.js +2 -2
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +13 -6
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +1 -1
- package/codeyam-cli/src/cli.js +2 -0
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/codeyam-cli.js +18 -2
- package/codeyam-cli/src/codeyam-cli.js.map +1 -1
- package/codeyam-cli/src/commands/analyze.js +4 -2
- package/codeyam-cli/src/commands/analyze.js.map +1 -1
- package/codeyam-cli/src/commands/baseline.js +2 -0
- package/codeyam-cli/src/commands/baseline.js.map +1 -1
- package/codeyam-cli/src/commands/debug.js +2 -0
- package/codeyam-cli/src/commands/debug.js.map +1 -1
- package/codeyam-cli/src/commands/default.js +31 -20
- package/codeyam-cli/src/commands/default.js.map +1 -1
- package/codeyam-cli/src/commands/detect-universal-mocks.js +2 -0
- package/codeyam-cli/src/commands/detect-universal-mocks.js.map +1 -1
- package/codeyam-cli/src/commands/init.js +49 -257
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +9 -9
- package/codeyam-cli/src/commands/memory.js.map +1 -1
- package/codeyam-cli/src/commands/recapture.js +2 -0
- package/codeyam-cli/src/commands/recapture.js.map +1 -1
- package/codeyam-cli/src/commands/setup-sandbox.js +2 -0
- package/codeyam-cli/src/commands/setup-sandbox.js.map +1 -1
- package/codeyam-cli/src/commands/setup-simulations.js +284 -0
- package/codeyam-cli/src/commands/setup-simulations.js.map +1 -0
- package/codeyam-cli/src/commands/test-startup.js +2 -0
- package/codeyam-cli/src/commands/test-startup.js.map +1 -1
- package/codeyam-cli/src/commands/verify.js +14 -2
- package/codeyam-cli/src/commands/verify.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +128 -86
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
- package/codeyam-cli/src/utils/analyzer.js +7 -0
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/backgroundServer.js +107 -23
- package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/utils/generateReport.js +2 -2
- package/codeyam-cli/src/utils/install-skills.js +43 -63
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/labsAutoCheck.js +19 -0
- package/codeyam-cli/src/utils/labsAutoCheck.js.map +1 -0
- package/codeyam-cli/src/utils/progress.js +7 -0
- package/codeyam-cli/src/utils/progress.js.map +1 -1
- package/codeyam-cli/src/utils/requireSimulations.js +10 -0
- package/codeyam-cli/src/utils/requireSimulations.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +106 -4
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +95 -2
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +37 -5
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +23 -3
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/index.js +2 -2
- package/codeyam-cli/src/utils/ruleReflection/index.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js +11 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js.map +1 -1
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +23 -23
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -1
- package/codeyam-cli/src/utils/rules/parser.js +5 -0
- package/codeyam-cli/src/utils/rules/parser.js.map +1 -1
- package/codeyam-cli/src/utils/rules/ruleState.js +10 -10
- package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -1
- package/codeyam-cli/src/utils/rules/staleness.js +6 -6
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
- package/codeyam-cli/src/utils/serverState.js +37 -10
- package/codeyam-cli/src/utils/serverState.js.map +1 -1
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +21 -44
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/database.js +14 -3
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
- package/codeyam-cli/src/webserver/backgroundServer.js +50 -0
- package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-D9i_zSlY.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-B86KKU7e.js → EntityItem-BLlhOa3C.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-B5ctlSYt.js → EntityTypeBadge-De5b5pC7.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BqY8gDAW.js → EntityTypeIcon-CzdG5I7z.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-ClaLpuOo.js → InlineSpinner-Bclf8Hka.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-BDhPilK7.js → InteractivePreview-Ce-byqKl.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-VeqEBv9v.js → LibraryFunctionPreview-DEMHrl7v.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-Bs7Nn1Jr.js → LoadingDots-B1LNGboS.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-Bm3PmcCz.js → LogViewer-B0Ll1DjK.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-C6PKeMYR.js → ReportIssueModal-CVOvmCKb.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-Gq3Ocjo6.js → SafeScreenshot-L0DWHa_L.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-BNLaXBHR.js → ScenarioViewer-D54Mmpwi.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-CiwXDxLh.js → TruncatedFilePath-C7PFQfXy.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{_index-B3TDXxnk.js → _index-CKTtYlBU.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-DD1r_QU0.js → activity.(_tab)-CdziRIWU.js} +6 -6
- package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-CPXtdaWm.js +17 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.labs-unlock-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{book-open-PttOB2SF.js → book-open-Ch8b7GyQ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-TJp6ofnp.js → chevron-down-vJHJExlT.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-JZWAC4HX-JE9ZIoBl.js → chunk-JZWAC4HX-BEyX4X6_.js} +7 -7
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-CXhHQYrI.js → circle-check-rwynPZTW.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{copy-6y9ALfGT.js → copy-BBSpeBYf.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Ca9fAY46.js → createLucideIcon-DHVDauuc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-C5lqplTC.js → dev.empty-B9_ZqelV.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-BOPComvD.js +16 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js → entity._sha.scenarios._scenarioId.fullscreen-Cfw__yQa.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-DGgZjdFg.js → entity._sha_.create-scenario-BIDUUrI3.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-38yPijoD.js → entity._sha_.edit._scenarioId-BEqewwtZ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-BSHEfydn.js → entry.client-Dxqz8ygt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DCPhhSMo.js → fileTableUtils-CYnF5KWN.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{files-Dk8wkAS7.js → files-B_dAq2PQ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{git-DXnyr8uP.js → git-BHPqH3Ch.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-BJGhRykz.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-CcsFv748.js → index-DgAAopZk.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-ChN9-fAY.js → index-viijWaN6.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-ChoAe3xq.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-CTqLEAGU.js → loader-circle-LGi2eKI5.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-87493a32.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-D9eA6kTo.js +78 -0
- package/codeyam-cli/src/webserver/build/client/assets/{pause-D6vreykR.js → pause-DxJFmMsK.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/root-C3r0p_7H.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-B8VUL8nl.js → search-Cu3QE9E5.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/settings-KH9TdArD.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-CPoAg7Zo.js → simulations-D9Fkx0-d.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{terminal-BrCP7uQo.js → terminal-dAhIBEcd.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BZz2NjYa.js → triangle-alert-C4CYTEeP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-DNwUduNu.js → useCustomSizes-CLPnITMB.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-COky1GVF.js → useLastLogLine-DmGI38Et.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CpZgwliL.js → useReportContext-BK0S88PB.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-Bv9JFvUO.js → useToast-CJ-JqR0l.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-C0KrUQp-.js → index-CkkmL6r5.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-iBGjHYtO.js +259 -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:debug.md → codeyam-debug.md} +1 -1
- package/codeyam-cli/templates/codeyam-diagnose.md +481 -0
- package/codeyam-cli/templates/codeyam-memory-hook.sh +14 -14
- package/codeyam-cli/templates/{codeyam:memory.md → codeyam-memory.md} +16 -24
- package/codeyam-cli/templates/{codeyam:new-rule.md → codeyam-new-rule.md} +1 -1
- package/codeyam-cli/templates/{codeyam:setup.md → codeyam-setup.md} +13 -1
- package/codeyam-cli/templates/{codeyam:sim.md → codeyam-sim.md} +1 -1
- package/codeyam-cli/templates/{codeyam:test.md → codeyam-test.md} +1 -1
- package/codeyam-cli/templates/{codeyam:verify.md → codeyam-verify.md} +1 -1
- package/codeyam-cli/templates/rule-notification-hook.py +3 -1
- package/codeyam-cli/templates/rule-reflection-hook.py +265 -66
- package/codeyam-cli/templates/rules-instructions.md +50 -41
- package/package.json +9 -9
- package/packages/ai/index.js +1 -1
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +14 -0
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/processExpression.js +78 -1
- package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
- package/packages/ai/src/lib/astScopes/sharedPatterns.js +25 -0
- package/packages/ai/src/lib/astScopes/sharedPatterns.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +128 -7
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +59 -11
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
- package/packages/ai/src/lib/dataStructureChunking.js +26 -11
- package/packages/ai/src/lib/dataStructureChunking.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +22 -3
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +16 -2
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +242 -81
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
- package/packages/ai/src/lib/mergeJsonTypeDefinitions.js +5 -0
- package/packages/ai/src/lib/mergeJsonTypeDefinitions.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js +97 -0
- package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js.map +1 -0
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +17 -2
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +11 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +42 -13
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +123 -67
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/database/src/lib/analysisBranchToDb.js +1 -1
- package/packages/database/src/lib/analysisBranchToDb.js.map +1 -1
- package/packages/database/src/lib/analysisToDb.js +1 -1
- package/packages/database/src/lib/analysisToDb.js.map +1 -1
- package/packages/database/src/lib/branchToDb.js +1 -1
- package/packages/database/src/lib/branchToDb.js.map +1 -1
- package/packages/database/src/lib/commitBranchToDb.js +1 -1
- package/packages/database/src/lib/commitBranchToDb.js.map +1 -1
- package/packages/database/src/lib/commitToDb.js +1 -1
- package/packages/database/src/lib/commitToDb.js.map +1 -1
- package/packages/database/src/lib/fileToDb.js +1 -1
- package/packages/database/src/lib/fileToDb.js.map +1 -1
- package/packages/database/src/lib/kysely/db.js +3 -0
- package/packages/database/src/lib/kysely/db.js.map +1 -1
- package/packages/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
- package/packages/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
- package/packages/database/src/lib/projectToDb.js +1 -1
- package/packages/database/src/lib/projectToDb.js.map +1 -1
- package/packages/database/src/lib/saveFiles.js +1 -1
- package/packages/database/src/lib/saveFiles.js.map +1 -1
- package/packages/database/src/lib/scenarioToDb.js +1 -1
- package/packages/database/src/lib/scenarioToDb.js.map +1 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js +93 -2
- package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/scripts/finalize-analyzer.cjs +8 -76
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CA3JxPb7.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DfKzxuoe.js +0 -11
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-n38keI1k.js +0 -23
- package/codeyam-cli/src/webserver/build/client/assets/globals-Bh6jH0cL.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-BUvfJMNR.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-d4e77269.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-DCHBwHou.js +0 -76
- package/codeyam-cli/src/webserver/build/client/assets/root-D6oziHts.js +0 -62
- package/codeyam-cli/src/webserver/build/client/assets/settings-B2X7lJgQ.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-C2h1v1XD.js +0 -260
- package/codeyam-cli/templates/codeyam:diagnose.md +0 -803
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: codeyam
|
|
2
|
+
name: codeyam-memory
|
|
3
3
|
autoApprove: true
|
|
4
4
|
description: |
|
|
5
5
|
Generate and maintain Claude Rules for your codebase based on thorough analysis.
|
|
@@ -13,19 +13,14 @@ This skill helps you generate and maintain Claude Rules (`.claude/rules/`) that
|
|
|
13
13
|
|
|
14
14
|
## Core Principle: Document Confusion, Not Information
|
|
15
15
|
|
|
16
|
-
**
|
|
16
|
+
**Valuable rules** capture knowledge that reading the code alone wouldn't reveal:
|
|
17
17
|
|
|
18
18
|
- Historical context (why code evolved this way)
|
|
19
19
|
- Hidden relationships (files that must change together)
|
|
20
20
|
- Gotchas that caused bugs
|
|
21
21
|
- Non-obvious conventions
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- What functions do (Claude can read the code)
|
|
26
|
-
- Type definitions (Claude can see them)
|
|
27
|
-
- Directory structure (Claude can explore it)
|
|
28
|
-
- Basic patterns (Claude knows common patterns)
|
|
23
|
+
Skip documenting things Claude can determine by reading code: function signatures, type definitions, directory structure, and common patterns.
|
|
29
24
|
|
|
30
25
|
## When to Use This Skill
|
|
31
26
|
|
|
@@ -41,7 +36,9 @@ Check if this is the first time running memory.
|
|
|
41
36
|
|
|
42
37
|
### 1A. Add Documentation Section to CLAUDE.md
|
|
43
38
|
|
|
44
|
-
If CLAUDE.md
|
|
39
|
+
If CLAUDE.md already contains a "Documenting Confusion / Mistakes" section, skip this step entirely.
|
|
40
|
+
|
|
41
|
+
Otherwise, add **only** the section below — do not modify or add any other content to CLAUDE.md. If CLAUDE.md doesn't exist, create it with just a `# Project` heading followed by this section:
|
|
45
42
|
|
|
46
43
|
```markdown
|
|
47
44
|
## Continuous Documentation
|
|
@@ -61,6 +58,8 @@ It is very important to document any tribal knowledge, complex architectural dec
|
|
|
61
58
|
Please see `.codeyam/rules/instructions.md` for guidance.
|
|
62
59
|
```
|
|
63
60
|
|
|
61
|
+
**Important:** Do not add project descriptions, architecture summaries, or any other content to CLAUDE.md. Only add the exact section above.
|
|
62
|
+
|
|
64
63
|
### 1B. Verify Instructions File
|
|
65
64
|
|
|
66
65
|
Check that `.codeyam/rules/instructions.md` exists (it should be created during `codeyam init`). If missing, copy it from `codeyam-cli/templates/rules-instructions.md`.
|
|
@@ -275,7 +274,7 @@ Before generating each rule, verify it passes these tests:
|
|
|
275
274
|
|
|
276
275
|
**2. Code-derivable check**: Read the files the rule will cover. Could the rule's content be determined by reading those files alone?
|
|
277
276
|
|
|
278
|
-
- If YES →
|
|
277
|
+
- If YES → the code is its own documentation — prefer keeping rules for non-derivable insights
|
|
279
278
|
- If NO (historical context, edge cases, non-obvious behavior) → rule is valuable
|
|
280
279
|
|
|
281
280
|
**3. Prevention check**: Would this rule have prevented one of the confusion commits you found?
|
|
@@ -301,7 +300,7 @@ This caused a bug where `entity` matched `entityCode` (siblings, not parent-chil
|
|
|
301
300
|
- Not code-derivable: Code doesn't explain why boundary checking matters
|
|
302
301
|
- Prevention: Would prevent future prefix-matching bugs
|
|
303
302
|
|
|
304
|
-
|
|
303
|
+
**Compare with a weaker alternative** (fails the checks):
|
|
305
304
|
|
|
306
305
|
```markdown
|
|
307
306
|
## Running Tests
|
|
@@ -309,9 +308,7 @@ This caused a bug where `entity` matched `entityCode` (siblings, not parent-chil
|
|
|
309
308
|
Use `pnpm jest` to run tests. Configuration is in `jest.config.ts`.
|
|
310
309
|
```
|
|
311
310
|
|
|
312
|
-
- No confusion evidence
|
|
313
|
-
- Code-derivable: Anyone can see `jest.config.ts` exists
|
|
314
|
-
- Doesn't prevent any confusion
|
|
311
|
+
- No confusion evidence, code-derivable, and wouldn't prevent future mistakes
|
|
315
312
|
|
|
316
313
|
### 5B. Rule File Guidelines
|
|
317
314
|
|
|
@@ -319,17 +316,13 @@ Use `pnpm jest` to run tests. Configuration is in `jest.config.ts`.
|
|
|
319
316
|
- Rule for `src/api/` → `.claude/rules/src/api/architecture.md`
|
|
320
317
|
- Rule for testing patterns → `.claude/rules/testing-patterns.md`
|
|
321
318
|
|
|
322
|
-
2. **Paths must be specific**
|
|
323
|
-
- Good: `paths: ['src/api/**/*.ts']`
|
|
324
|
-
- Bad: `paths: ['**/*.ts']` (too broad, wastes context)
|
|
319
|
+
2. **Paths must be specific** — use `paths: ['src/api/**/*.ts']` rather than `'**/*.ts'` (too broad wastes context)
|
|
325
320
|
|
|
326
321
|
3. **Content should explain "why" not just "what"**
|
|
327
322
|
- Focus on the reasoning, history, or gotcha
|
|
328
323
|
- Be concise - every word costs context
|
|
329
324
|
|
|
330
|
-
4. **
|
|
331
|
-
- Use ISO 8601 format: `2026-01-27T15:30:00Z`
|
|
332
|
-
- This enables the pre-commit hook enforcement
|
|
325
|
+
4. **Audit dates live in `.claude/codeyam-rule-state.json`** (managed by `codeyam memory touch`). Keep rule frontmatter limited to `paths`.
|
|
333
326
|
|
|
334
327
|
### Rule Template
|
|
335
328
|
|
|
@@ -337,7 +330,6 @@ Use `pnpm jest` to run tests. Configuration is in `jest.config.ts`.
|
|
|
337
330
|
---
|
|
338
331
|
paths:
|
|
339
332
|
- 'specific/path/**/*.ts'
|
|
340
|
-
timestamp: [CURRENT_ISO_TIMESTAMP]
|
|
341
333
|
---
|
|
342
334
|
|
|
343
335
|
## [Clear, Descriptive Title]
|
|
@@ -374,7 +366,7 @@ After generating rules based on your analysis and user answers:
|
|
|
374
366
|
5. **Remind the user** to commit the new rules:
|
|
375
367
|
```
|
|
376
368
|
git add .claude/rules/ .codeyam/rules/
|
|
377
|
-
git commit -m "Add rules for Claude Code (generated via /codeyam
|
|
369
|
+
git commit -m "Add rules for Claude Code (generated via /codeyam-memory)"
|
|
378
370
|
```
|
|
379
371
|
|
|
380
372
|
---
|
|
@@ -394,11 +386,11 @@ After generating rules based on your analysis and user answers:
|
|
|
394
386
|
The pre-commit hook **blocks commits** when:
|
|
395
387
|
|
|
396
388
|
- Code files matching a rule's `paths` are modified
|
|
397
|
-
- The rule's `
|
|
389
|
+
- The rule's `lastAuditedAt` in `.claude/codeyam-rule-state.json` is older than the code changes
|
|
398
390
|
|
|
399
391
|
To proceed:
|
|
400
392
|
|
|
401
393
|
1. Review the flagged rule(s)
|
|
402
394
|
2. Update content if needed
|
|
403
|
-
3.
|
|
395
|
+
3. Run `codeyam memory touch` to mark rules as audited in `.claude/codeyam-rule-state.json`
|
|
404
396
|
4. Stage and commit
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: codeyam
|
|
2
|
+
name: codeyam-setup
|
|
3
3
|
autoApprove: true
|
|
4
4
|
description: |
|
|
5
5
|
Use this skill when the user asks to "setup CodeYam" or needs to configure CodeYam for their project.
|
|
@@ -52,6 +52,18 @@ codeyam validate-mock .codeyam/universal-mocks/{path-to-your-mock}
|
|
|
52
52
|
|
|
53
53
|
## Setup Workflow
|
|
54
54
|
|
|
55
|
+
### Step 0: Ensure Simulation Infrastructure
|
|
56
|
+
|
|
57
|
+
Before configuring the dev server or mocks, ensure the simulation infrastructure is installed.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
codeyam setup-simulations
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This is **idempotent** — if already set up, each step is detected and skipped. On first run it installs analyzer dependencies, Playwright chromium, and creates baseline entities (several minutes). Subsequent runs complete in seconds.
|
|
64
|
+
|
|
65
|
+
If it fails with "No web applications found", the project doesn't support simulations — inform the user and stop.
|
|
66
|
+
|
|
55
67
|
### Step 1: Configure Webapp Start Command
|
|
56
68
|
|
|
57
69
|
**ACTION 1:** Read configuration files:
|
|
@@ -7,10 +7,11 @@ in /tmp/claude-rule-markers/ when they create or update rules.
|
|
|
7
7
|
This hook checks for those files on each user message, prints them to stdout
|
|
8
8
|
(which Claude sees as injected context), and deletes them.
|
|
9
9
|
|
|
10
|
-
Supports
|
|
10
|
+
Supports four notification files (legacy combined + split agents):
|
|
11
11
|
- rule-notification.md (legacy/backward-compat)
|
|
12
12
|
- rule-notification-stale.md (stale rules agent)
|
|
13
13
|
- rule-notification-conversation.md (conversation review agent)
|
|
14
|
+
- rule-notification-interruption.md (interruption review agent)
|
|
14
15
|
"""
|
|
15
16
|
|
|
16
17
|
import os
|
|
@@ -21,6 +22,7 @@ NOTIFICATION_FILES = [
|
|
|
21
22
|
'rule-notification.md',
|
|
22
23
|
'rule-notification-stale.md',
|
|
23
24
|
'rule-notification-conversation.md',
|
|
25
|
+
'rule-notification-interruption.md',
|
|
24
26
|
]
|
|
25
27
|
|
|
26
28
|
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Rule reflection hook for Claude Code.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
1.
|
|
7
|
-
2.
|
|
5
|
+
Handles two hook events:
|
|
6
|
+
1. Stop — Reviews completed turns for stale rules and conversation confusion signals
|
|
7
|
+
2. UserPromptSubmit — Detects user interruptions (Escape/Ctrl+C) by checking if the
|
|
8
|
+
Stop hook's marker file is stale, then spawns a rule-reflection agent focused on
|
|
9
|
+
the interruption signal
|
|
8
10
|
|
|
9
|
-
Each fires as a separate `claude -p` invocation so the LLM can focus on one task at a time.
|
|
11
|
+
Each review fires as a separate `claude -p` invocation so the LLM can focus on one task at a time.
|
|
10
12
|
Stays silent if there's nothing to review.
|
|
11
13
|
|
|
12
14
|
Prompt text lives in templates/prompts/*.txt (single source of truth shared with TypeScript tests).
|
|
@@ -16,6 +18,7 @@ import json
|
|
|
16
18
|
import os
|
|
17
19
|
import subprocess
|
|
18
20
|
import sys
|
|
21
|
+
from datetime import datetime
|
|
19
22
|
from pathlib import Path
|
|
20
23
|
|
|
21
24
|
MIN_USER_TURNS = 3 # Minimum user turns before checking for confusion
|
|
@@ -117,6 +120,33 @@ def read_rule_content(rule_name):
|
|
|
117
120
|
return text
|
|
118
121
|
|
|
119
122
|
|
|
123
|
+
def load_memory_settings():
|
|
124
|
+
"""
|
|
125
|
+
Load memory settings from .codeyam/config.json.
|
|
126
|
+
Returns dict with safe defaults when absent or malformed.
|
|
127
|
+
"""
|
|
128
|
+
defaults = {
|
|
129
|
+
'conversationReflection': True,
|
|
130
|
+
'ruleMaintenance': True,
|
|
131
|
+
'promptModel': 'haiku',
|
|
132
|
+
}
|
|
133
|
+
try:
|
|
134
|
+
project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
|
|
135
|
+
config_path = os.path.join(project_dir, '.codeyam', 'config.json')
|
|
136
|
+
with open(config_path, 'r') as f:
|
|
137
|
+
config = json.load(f)
|
|
138
|
+
memory = config.get('memory', {})
|
|
139
|
+
if not isinstance(memory, dict):
|
|
140
|
+
return defaults
|
|
141
|
+
return {
|
|
142
|
+
'conversationReflection': memory.get('conversationReflection', True),
|
|
143
|
+
'ruleMaintenance': memory.get('ruleMaintenance', True),
|
|
144
|
+
'promptModel': memory.get('promptModel', 'haiku'),
|
|
145
|
+
}
|
|
146
|
+
except (IOError, json.JSONDecodeError, KeyError):
|
|
147
|
+
return defaults
|
|
148
|
+
|
|
149
|
+
|
|
120
150
|
def get_stale_rules():
|
|
121
151
|
"""
|
|
122
152
|
Run `codeyam memory status` and parse the output to find stale rules.
|
|
@@ -154,8 +184,8 @@ def get_stale_rules():
|
|
|
154
184
|
# Look for the next few lines for details
|
|
155
185
|
for j in range(i + 1, min(i + 4, len(lines))):
|
|
156
186
|
detail = lines[j].strip()
|
|
157
|
-
if detail.startswith('
|
|
158
|
-
rule_info['
|
|
187
|
+
if detail.startswith('Last audited:'):
|
|
188
|
+
rule_info['last_audited'] = detail.replace('Last audited:', '').strip()
|
|
159
189
|
elif detail.startswith('Newest file:'):
|
|
160
190
|
rule_info['newest_file'] = detail.replace('Newest file:', '').strip()
|
|
161
191
|
elif detail.startswith('File modified:'):
|
|
@@ -250,6 +280,28 @@ def get_conversation_context(transcript_path, last_line):
|
|
|
250
280
|
return user_turn_count, conversation_snippets, modified_files, current_line_count
|
|
251
281
|
|
|
252
282
|
|
|
283
|
+
def has_assistant_messages(transcript_path, start_line):
|
|
284
|
+
"""
|
|
285
|
+
Check if there are any assistant messages in the transcript after start_line.
|
|
286
|
+
Used to confirm Claude actually started responding before treating a gap as an interruption.
|
|
287
|
+
"""
|
|
288
|
+
try:
|
|
289
|
+
with open(transcript_path, 'r') as f:
|
|
290
|
+
all_lines = f.readlines()
|
|
291
|
+
except IOError:
|
|
292
|
+
return False
|
|
293
|
+
|
|
294
|
+
for line in all_lines[start_line:]:
|
|
295
|
+
try:
|
|
296
|
+
obj = json.loads(line)
|
|
297
|
+
if obj.get('type') == 'assistant':
|
|
298
|
+
return True
|
|
299
|
+
except (json.JSONDecodeError, KeyError):
|
|
300
|
+
continue
|
|
301
|
+
|
|
302
|
+
return False
|
|
303
|
+
|
|
304
|
+
|
|
253
305
|
def build_stale_rules_context(stale_rules):
|
|
254
306
|
"""Build context content for stale rules review."""
|
|
255
307
|
parts = []
|
|
@@ -261,7 +313,7 @@ def build_stale_rules_context(stale_rules):
|
|
|
261
313
|
parts.append("For each rule, review the rule content and the diff of changes, then:")
|
|
262
314
|
parts.append("1. Determine if the rule content needs updating based on the code changes")
|
|
263
315
|
parts.append("2. Update the rule if needed")
|
|
264
|
-
parts.append("3. ALWAYS
|
|
316
|
+
parts.append("3. ALWAYS run `codeyam memory touch` to mark rules as audited\n")
|
|
265
317
|
|
|
266
318
|
for rule in stale_rules:
|
|
267
319
|
parts.append(f"### {rule['name']}")
|
|
@@ -273,8 +325,8 @@ def build_stale_rules_context(stale_rules):
|
|
|
273
325
|
parts.append(f" Changed file: {rule['newest_file']}")
|
|
274
326
|
if rule.get('file_modified'):
|
|
275
327
|
parts.append(f" File modified: {rule['file_modified']}")
|
|
276
|
-
if rule.get('
|
|
277
|
-
parts.append(f"
|
|
328
|
+
if rule.get('last_audited'):
|
|
329
|
+
parts.append(f" Last audited: {rule['last_audited']}")
|
|
278
330
|
if rule.get('diff'):
|
|
279
331
|
parts.append(f" Changes:")
|
|
280
332
|
for line in rule['diff'].split('\n'):
|
|
@@ -314,7 +366,41 @@ def build_conversation_context(conversation_snippets, modified_files):
|
|
|
314
366
|
return '\n'.join(parts)
|
|
315
367
|
|
|
316
368
|
|
|
317
|
-
def
|
|
369
|
+
def build_interruption_context(conversation_snippets, follow_up_prompt, modified_files):
|
|
370
|
+
"""Build context content for an interrupted session review."""
|
|
371
|
+
parts = []
|
|
372
|
+
parts.append("## Interruption Review\n")
|
|
373
|
+
parts.append(
|
|
374
|
+
"The user interrupted Claude mid-response — a strong signal of confusion or misunderstanding. "
|
|
375
|
+
"Review the interrupted conversation and the user's follow-up to identify rule-worthy learnings.\n"
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Load guidance from shared template file
|
|
379
|
+
guidance = (PROMPTS_DIR / 'conversation-guidance.txt').read_text()
|
|
380
|
+
parts.append(guidance)
|
|
381
|
+
|
|
382
|
+
if modified_files:
|
|
383
|
+
parts.append("Files modified this session:")
|
|
384
|
+
for file_path, tool_name in sorted(modified_files):
|
|
385
|
+
parts.append(f"- {file_path} ({tool_name})")
|
|
386
|
+
parts.append("")
|
|
387
|
+
|
|
388
|
+
parts.append("### Session transcript\n")
|
|
389
|
+
summary_lines = []
|
|
390
|
+
for snippet in conversation_snippets:
|
|
391
|
+
role = snippet['role']
|
|
392
|
+
content = snippet['content'].replace('\n', ' ')
|
|
393
|
+
summary_lines.append(f"[{role}]: {content}")
|
|
394
|
+
parts.append('\n'.join(summary_lines))
|
|
395
|
+
|
|
396
|
+
parts.append("")
|
|
397
|
+
parts.append("### User's follow-up after interruption\n")
|
|
398
|
+
parts.append(follow_up_prompt)
|
|
399
|
+
|
|
400
|
+
return '\n'.join(parts)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def spawn_claude_agent(prompt, log_file, project_dir, model='haiku'):
|
|
318
404
|
"""Spawn a detached claude -p agent as a background process."""
|
|
319
405
|
try:
|
|
320
406
|
log_fh = open(log_file, 'w')
|
|
@@ -322,7 +408,8 @@ def spawn_claude_agent(prompt, log_file, project_dir):
|
|
|
322
408
|
env['CODEYAM_RULE_AGENT'] = '1'
|
|
323
409
|
subprocess.Popen(
|
|
324
410
|
['claude', '-p', prompt,
|
|
325
|
-
'--model',
|
|
411
|
+
'--model', model,
|
|
412
|
+
'--no-session-persistence',
|
|
326
413
|
'--output-format', 'stream-json', '--verbose',
|
|
327
414
|
'--allowedTools', 'Read,Edit,Write,Bash,Glob,Grep'],
|
|
328
415
|
cwd=project_dir,
|
|
@@ -335,21 +422,43 @@ def spawn_claude_agent(prompt, log_file, project_dir):
|
|
|
335
422
|
pass # claude CLI not available, skip silently
|
|
336
423
|
|
|
337
424
|
|
|
338
|
-
def
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
425
|
+
def read_marker(marker_file):
|
|
426
|
+
"""
|
|
427
|
+
Read marker file. Returns (last_line, written_by_stop).
|
|
428
|
+
Format: "<line_count>" or "<line_count> stop" — the suffix distinguishes
|
|
429
|
+
whether the Stop hook wrote this marker (normal completion) vs the
|
|
430
|
+
UserPromptSubmit handler (interruption detection).
|
|
431
|
+
"""
|
|
432
|
+
if marker_file.exists():
|
|
433
|
+
try:
|
|
434
|
+
text = marker_file.read_text().strip()
|
|
435
|
+
parts = text.split()
|
|
436
|
+
line_count = int(parts[0])
|
|
437
|
+
was_stop = len(parts) > 1 and parts[1] == 'stop'
|
|
438
|
+
return line_count, was_stop
|
|
439
|
+
except (ValueError, IOError):
|
|
440
|
+
pass
|
|
441
|
+
return 0, False
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def write_marker(marker_file, line_count, source='submit'):
|
|
445
|
+
"""Write marker with source tag. source is 'stop' or 'submit'."""
|
|
446
|
+
marker_file.write_text(f'{line_count} {source}')
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def handle_stop(hook_input):
|
|
450
|
+
"""
|
|
451
|
+
Handle the Stop hook event.
|
|
452
|
+
Reviews completed turns for stale rules and conversation confusion signals.
|
|
453
|
+
|
|
454
|
+
Important: the fast work (transcript parsing, marker update, conversation
|
|
455
|
+
agent spawn) runs first. The slow `get_stale_rules()` call (~10s) runs last
|
|
456
|
+
so the hook timeout doesn't kill us before the critical work is done.
|
|
457
|
+
"""
|
|
458
|
+
settings = load_memory_settings()
|
|
344
459
|
|
|
345
460
|
session_id = hook_input.get('session_id', '')
|
|
346
461
|
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
462
|
|
|
354
463
|
if not session_id or not transcript_path:
|
|
355
464
|
return
|
|
@@ -358,58 +467,23 @@ def main():
|
|
|
358
467
|
marker_dir.mkdir(exist_ok=True)
|
|
359
468
|
marker_file = marker_dir / f'{session_id}.marker'
|
|
360
469
|
|
|
361
|
-
|
|
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
|
|
470
|
+
last_line, _ = read_marker(marker_file)
|
|
368
471
|
|
|
369
|
-
#
|
|
370
|
-
stale_rules = get_stale_rules()
|
|
371
|
-
|
|
372
|
-
# Get conversation context
|
|
472
|
+
# Fast: parse transcript for conversation context
|
|
373
473
|
user_turn_count, conversation_snippets, modified_files, current_line_count = get_conversation_context(
|
|
374
474
|
transcript_path, last_line
|
|
375
475
|
)
|
|
376
476
|
|
|
377
|
-
#
|
|
378
|
-
|
|
379
|
-
|
|
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))
|
|
477
|
+
# Update marker immediately so UserPromptSubmit knows Stop ran,
|
|
478
|
+
# even if we get killed during the slow stale rules check below
|
|
479
|
+
write_marker(marker_file, current_line_count, 'stop')
|
|
387
480
|
|
|
388
481
|
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
482
|
invocation_ts = datetime.now().strftime('%Y%m%d-%H%M%S')
|
|
393
483
|
invocation_id = f'{session_id}-{invocation_ts}'
|
|
394
484
|
|
|
395
|
-
#
|
|
396
|
-
if
|
|
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:
|
|
485
|
+
# Fast: spawn conversation review agent first (if enabled)
|
|
486
|
+
if settings['conversationReflection'] and len(conversation_snippets) > 0:
|
|
413
487
|
conv_context = build_conversation_context(conversation_snippets, modified_files)
|
|
414
488
|
conv_context_file = marker_dir / f'{invocation_id}-conversation.context'
|
|
415
489
|
conv_context_file.write_text(conv_context)
|
|
@@ -422,7 +496,132 @@ def main():
|
|
|
422
496
|
NOTIFICATION_FILE=str(conv_notification_file),
|
|
423
497
|
PROJECT_DIR=project_dir,
|
|
424
498
|
)
|
|
425
|
-
spawn_claude_agent(conv_prompt, conv_log_file, project_dir)
|
|
499
|
+
spawn_claude_agent(conv_prompt, conv_log_file, project_dir, model=settings['promptModel'])
|
|
500
|
+
|
|
501
|
+
# Slow (~10s): check for stale rules last — if the hook timeout kills us
|
|
502
|
+
# here, the conversation agent and marker are already handled
|
|
503
|
+
if settings['ruleMaintenance']:
|
|
504
|
+
stale_rules = get_stale_rules()
|
|
505
|
+
|
|
506
|
+
if len(stale_rules) > 0:
|
|
507
|
+
stale_context = build_stale_rules_context(stale_rules)
|
|
508
|
+
stale_context_file = marker_dir / f'{invocation_id}-stale.context'
|
|
509
|
+
stale_context_file.write_text(stale_context)
|
|
510
|
+
|
|
511
|
+
stale_log_file = marker_dir / f'{invocation_id}-stale.log'
|
|
512
|
+
stale_notification_file = marker_dir / 'rule-notification-stale.md'
|
|
513
|
+
stale_prompt = load_prompt_template(
|
|
514
|
+
'stale-rules-prompt.txt',
|
|
515
|
+
CONTEXT_FILE=str(stale_context_file),
|
|
516
|
+
NOTIFICATION_FILE=str(stale_notification_file),
|
|
517
|
+
PROJECT_DIR=project_dir,
|
|
518
|
+
)
|
|
519
|
+
spawn_claude_agent(stale_prompt, stale_log_file, project_dir, model=settings['promptModel'])
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def handle_user_prompt_submit(hook_input):
|
|
523
|
+
"""
|
|
524
|
+
Handle the UserPromptSubmit hook event.
|
|
525
|
+
Detects whether the previous turn was interrupted by checking if the Stop hook's
|
|
526
|
+
marker file is stale (transcript has lines beyond the marker). If so, spawns a
|
|
527
|
+
rule-reflection agent focused on the interruption.
|
|
528
|
+
"""
|
|
529
|
+
settings = load_memory_settings()
|
|
530
|
+
|
|
531
|
+
# Interruption detection is part of conversation reflection
|
|
532
|
+
if not settings['conversationReflection']:
|
|
533
|
+
return
|
|
534
|
+
|
|
535
|
+
session_id = hook_input.get('session_id', '')
|
|
536
|
+
transcript_path = hook_input.get('transcript_path', '')
|
|
537
|
+
follow_up_prompt = hook_input.get('prompt', '')
|
|
538
|
+
|
|
539
|
+
if not session_id or not transcript_path:
|
|
540
|
+
return
|
|
541
|
+
|
|
542
|
+
marker_dir = Path('/tmp/claude-rule-markers')
|
|
543
|
+
marker_dir.mkdir(exist_ok=True)
|
|
544
|
+
marker_file = marker_dir / f'{session_id}.marker'
|
|
545
|
+
|
|
546
|
+
last_line, was_stop = read_marker(marker_file)
|
|
547
|
+
|
|
548
|
+
# If the Stop hook already ran for the previous turn, this is a normal
|
|
549
|
+
# completion — not an interruption. The Stop hook tags the marker with
|
|
550
|
+
# 'stop' when it writes it.
|
|
551
|
+
if was_stop:
|
|
552
|
+
return
|
|
553
|
+
|
|
554
|
+
# Count current transcript lines
|
|
555
|
+
try:
|
|
556
|
+
with open(transcript_path, 'r') as f:
|
|
557
|
+
current_line_count = sum(1 for _ in f)
|
|
558
|
+
except IOError:
|
|
559
|
+
return
|
|
560
|
+
|
|
561
|
+
# Quick exit: if nothing new since the marker, definitely no interruption
|
|
562
|
+
if current_line_count <= last_line:
|
|
563
|
+
return
|
|
564
|
+
|
|
565
|
+
# Verify Claude actually started responding in the unprocessed lines.
|
|
566
|
+
# Guards against false positives on first prompt (no assistant yet) or
|
|
567
|
+
# if the user hit Escape before Claude produced any output.
|
|
568
|
+
if not has_assistant_messages(transcript_path, last_line):
|
|
569
|
+
return
|
|
570
|
+
|
|
571
|
+
# Interruption detected! Build context and spawn agent.
|
|
572
|
+
_, conversation_snippets, modified_files, _ = get_conversation_context(
|
|
573
|
+
transcript_path, last_line
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
if not conversation_snippets:
|
|
577
|
+
return
|
|
578
|
+
|
|
579
|
+
# Update marker so we don't re-process these lines
|
|
580
|
+
write_marker(marker_file, current_line_count, 'submit')
|
|
581
|
+
|
|
582
|
+
project_dir = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
|
|
583
|
+
|
|
584
|
+
invocation_ts = datetime.now().strftime('%Y%m%d-%H%M%S')
|
|
585
|
+
invocation_id = f'{session_id}-{invocation_ts}'
|
|
586
|
+
|
|
587
|
+
interruption_context = build_interruption_context(
|
|
588
|
+
conversation_snippets, follow_up_prompt, modified_files
|
|
589
|
+
)
|
|
590
|
+
context_file = marker_dir / f'{invocation_id}-interruption.context'
|
|
591
|
+
context_file.write_text(interruption_context)
|
|
592
|
+
|
|
593
|
+
log_file = marker_dir / f'{invocation_id}-interruption.log'
|
|
594
|
+
notification_file = marker_dir / 'rule-notification-interruption.md'
|
|
595
|
+
prompt = load_prompt_template(
|
|
596
|
+
'interruption-prompt.txt',
|
|
597
|
+
CONTEXT_FILE=str(context_file),
|
|
598
|
+
NOTIFICATION_FILE=str(notification_file),
|
|
599
|
+
PROJECT_DIR=project_dir,
|
|
600
|
+
)
|
|
601
|
+
spawn_claude_agent(prompt, log_file, project_dir, model=settings['promptModel'])
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
def main():
|
|
605
|
+
# Read hook input from stdin
|
|
606
|
+
try:
|
|
607
|
+
hook_input = json.load(sys.stdin)
|
|
608
|
+
except json.JSONDecodeError:
|
|
609
|
+
return
|
|
610
|
+
|
|
611
|
+
stop_hook_active = hook_input.get('stop_hook_active', False)
|
|
612
|
+
|
|
613
|
+
# Prevent infinite loops — stop_hook_active covers same-process recursion,
|
|
614
|
+
# env var covers spawned subagent sessions triggering the hook on exit
|
|
615
|
+
if stop_hook_active or os.environ.get('CODEYAM_RULE_AGENT'):
|
|
616
|
+
return
|
|
617
|
+
|
|
618
|
+
# Detect event type: UserPromptSubmit has a 'prompt' field, Stop does not
|
|
619
|
+
is_user_prompt = 'prompt' in hook_input
|
|
620
|
+
if is_user_prompt:
|
|
621
|
+
handle_user_prompt_submit(hook_input)
|
|
622
|
+
else:
|
|
623
|
+
handle_stop(hook_input)
|
|
624
|
+
|
|
426
625
|
|
|
427
626
|
if __name__ == '__main__':
|
|
428
627
|
main()
|