jfl 0.4.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/context-hub.d.ts +1 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +1064 -41
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/eval.d.ts +1 -1
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +192 -1
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/findings.d.ts +6 -0
- package/dist/commands/findings.d.ts.map +1 -0
- package/dist/commands/findings.js +203 -0
- package/dist/commands/findings.js.map +1 -0
- package/dist/commands/hud.d.ts.map +1 -1
- package/dist/commands/hud.js +47 -9
- package/dist/commands/hud.js.map +1 -1
- package/dist/commands/ide.d.ts +27 -0
- package/dist/commands/ide.d.ts.map +1 -0
- package/dist/commands/ide.js +546 -0
- package/dist/commands/ide.js.map +1 -0
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +212 -2
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/openclaw.d.ts +3 -0
- package/dist/commands/openclaw.d.ts.map +1 -1
- package/dist/commands/openclaw.js +76 -2
- package/dist/commands/openclaw.js.map +1 -1
- package/dist/commands/peter.d.ts +3 -0
- package/dist/commands/peter.d.ts.map +1 -1
- package/dist/commands/peter.js +1168 -58
- package/dist/commands/peter.js.map +1 -1
- package/dist/commands/pi-fleet.d.ts +18 -0
- package/dist/commands/pi-fleet.d.ts.map +1 -0
- package/dist/commands/pi-fleet.js +382 -0
- package/dist/commands/pi-fleet.js.map +1 -0
- package/dist/commands/pi.d.ts.map +1 -1
- package/dist/commands/pi.js +18 -3
- package/dist/commands/pi.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +90 -1
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/services.d.ts.map +1 -1
- package/dist/commands/services.js +18 -0
- package/dist/commands/services.js.map +1 -1
- package/dist/commands/setup.d.ts +12 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +322 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +22 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/train.d.ts +33 -0
- package/dist/commands/train.d.ts.map +1 -0
- package/dist/commands/train.js +510 -0
- package/dist/commands/train.js.map +1 -0
- package/dist/commands/verify.d.ts +14 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +276 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/viz.d.ts.map +1 -1
- package/dist/commands/viz.js +417 -0
- package/dist/commands/viz.js.map +1 -1
- package/dist/dashboard-static/assets/index-CW9ZxqX8.css +1 -0
- package/dist/dashboard-static/assets/index-DNN__p4K.js +121 -0
- package/dist/dashboard-static/index.html +2 -2
- package/dist/index.js +324 -64
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-config.d.ts +52 -0
- package/dist/lib/agent-config.d.ts.map +1 -0
- package/dist/lib/agent-config.js +231 -0
- package/dist/lib/agent-config.js.map +1 -0
- package/dist/lib/agent-generator.d.ts +10 -0
- package/dist/lib/agent-generator.d.ts.map +1 -1
- package/dist/lib/agent-generator.js +64 -10
- package/dist/lib/agent-generator.js.map +1 -1
- package/dist/lib/agent-session.d.ts +104 -0
- package/dist/lib/agent-session.d.ts.map +1 -0
- package/dist/lib/agent-session.js +635 -0
- package/dist/lib/agent-session.js.map +1 -0
- package/dist/lib/eval-snapshot.d.ts +47 -0
- package/dist/lib/eval-snapshot.d.ts.map +1 -0
- package/dist/lib/eval-snapshot.js +315 -0
- package/dist/lib/eval-snapshot.js.map +1 -0
- package/dist/lib/eval-store.d.ts +5 -0
- package/dist/lib/eval-store.d.ts.map +1 -1
- package/dist/lib/eval-store.js +33 -3
- package/dist/lib/eval-store.js.map +1 -1
- package/dist/lib/findings-engine.d.ts +51 -0
- package/dist/lib/findings-engine.d.ts.map +1 -0
- package/dist/lib/findings-engine.js +338 -0
- package/dist/lib/findings-engine.js.map +1 -0
- package/dist/lib/flow-engine.d.ts +8 -0
- package/dist/lib/flow-engine.d.ts.map +1 -1
- package/dist/lib/flow-engine.js +84 -2
- package/dist/lib/flow-engine.js.map +1 -1
- package/dist/lib/hub-client.d.ts +1 -0
- package/dist/lib/hub-client.d.ts.map +1 -1
- package/dist/lib/hub-client.js +33 -6
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/ide-panes.d.ts +58 -0
- package/dist/lib/ide-panes.d.ts.map +1 -0
- package/dist/lib/ide-panes.js +508 -0
- package/dist/lib/ide-panes.js.map +1 -0
- package/dist/lib/memory-db.js +4 -4
- package/dist/lib/memory-db.js.map +1 -1
- package/dist/lib/memory-indexer.d.ts.map +1 -1
- package/dist/lib/memory-indexer.js +3 -0
- package/dist/lib/memory-indexer.js.map +1 -1
- package/dist/lib/memory-search.d.ts +148 -4
- package/dist/lib/memory-search.d.ts.map +1 -1
- package/dist/lib/memory-search.js +496 -58
- package/dist/lib/memory-search.js.map +1 -1
- package/dist/lib/meta-orchestrator.d.ts +104 -0
- package/dist/lib/meta-orchestrator.d.ts.map +1 -0
- package/dist/lib/meta-orchestrator.js +373 -0
- package/dist/lib/meta-orchestrator.js.map +1 -0
- package/dist/lib/peer-agent-generator.d.ts.map +1 -1
- package/dist/lib/peer-agent-generator.js +43 -19
- package/dist/lib/peer-agent-generator.js.map +1 -1
- package/dist/lib/pi-sky/bridge.d.ts +55 -0
- package/dist/lib/pi-sky/bridge.d.ts.map +1 -0
- package/dist/lib/pi-sky/bridge.js +264 -0
- package/dist/lib/pi-sky/bridge.js.map +1 -0
- package/dist/lib/pi-sky/cost-monitor.d.ts +21 -0
- package/dist/lib/pi-sky/cost-monitor.d.ts.map +1 -0
- package/dist/lib/pi-sky/cost-monitor.js +126 -0
- package/dist/lib/pi-sky/cost-monitor.js.map +1 -0
- package/dist/lib/pi-sky/eval-sweep.d.ts +27 -0
- package/dist/lib/pi-sky/eval-sweep.d.ts.map +1 -0
- package/dist/lib/pi-sky/eval-sweep.js +141 -0
- package/dist/lib/pi-sky/eval-sweep.js.map +1 -0
- package/dist/lib/pi-sky/event-router.d.ts +32 -0
- package/dist/lib/pi-sky/event-router.d.ts.map +1 -0
- package/dist/lib/pi-sky/event-router.js +176 -0
- package/dist/lib/pi-sky/event-router.js.map +1 -0
- package/dist/lib/pi-sky/experiment.d.ts +9 -0
- package/dist/lib/pi-sky/experiment.d.ts.map +1 -0
- package/dist/lib/pi-sky/experiment.js +83 -0
- package/dist/lib/pi-sky/experiment.js.map +1 -0
- package/dist/lib/pi-sky/index.d.ts +16 -0
- package/dist/lib/pi-sky/index.d.ts.map +1 -0
- package/dist/lib/pi-sky/index.js +16 -0
- package/dist/lib/pi-sky/index.js.map +1 -0
- package/dist/lib/pi-sky/stratus-gate.d.ts +28 -0
- package/dist/lib/pi-sky/stratus-gate.d.ts.map +1 -0
- package/dist/lib/pi-sky/stratus-gate.js +61 -0
- package/dist/lib/pi-sky/stratus-gate.js.map +1 -0
- package/dist/lib/pi-sky/swarm.d.ts +28 -0
- package/dist/lib/pi-sky/swarm.d.ts.map +1 -0
- package/dist/lib/pi-sky/swarm.js +208 -0
- package/dist/lib/pi-sky/swarm.js.map +1 -0
- package/dist/lib/pi-sky/types.d.ts +139 -0
- package/dist/lib/pi-sky/types.d.ts.map +1 -0
- package/dist/lib/pi-sky/types.js +2 -0
- package/dist/lib/pi-sky/types.js.map +1 -0
- package/dist/lib/pi-sky/voice-bridge.d.ts +20 -0
- package/dist/lib/pi-sky/voice-bridge.d.ts.map +1 -0
- package/dist/lib/pi-sky/voice-bridge.js +91 -0
- package/dist/lib/pi-sky/voice-bridge.js.map +1 -0
- package/dist/lib/policy-head.d.ts +40 -0
- package/dist/lib/policy-head.d.ts.map +1 -0
- package/dist/lib/policy-head.js +234 -0
- package/dist/lib/policy-head.js.map +1 -0
- package/dist/lib/predictor.d.ts +10 -0
- package/dist/lib/predictor.d.ts.map +1 -1
- package/dist/lib/predictor.js +46 -7
- package/dist/lib/predictor.js.map +1 -1
- package/dist/lib/replay-buffer.d.ts +93 -0
- package/dist/lib/replay-buffer.d.ts.map +1 -0
- package/dist/lib/replay-buffer.js +302 -0
- package/dist/lib/replay-buffer.js.map +1 -0
- package/dist/lib/sentinel-rl.d.ts +97 -0
- package/dist/lib/sentinel-rl.d.ts.map +1 -0
- package/dist/lib/sentinel-rl.js +430 -0
- package/dist/lib/sentinel-rl.js.map +1 -0
- package/dist/lib/session-lock.d.ts +61 -0
- package/dist/lib/session-lock.d.ts.map +1 -0
- package/dist/lib/session-lock.js +438 -0
- package/dist/lib/session-lock.js.map +1 -0
- package/dist/lib/setup/agent-generator.d.ts +18 -0
- package/dist/lib/setup/agent-generator.d.ts.map +1 -0
- package/dist/lib/setup/agent-generator.js +114 -0
- package/dist/lib/setup/agent-generator.js.map +1 -0
- package/dist/lib/setup/context-analyzer.d.ts +16 -0
- package/dist/lib/setup/context-analyzer.d.ts.map +1 -0
- package/dist/lib/setup/context-analyzer.js +112 -0
- package/dist/lib/setup/context-analyzer.js.map +1 -0
- package/dist/lib/setup/doc-auditor.d.ts +54 -0
- package/dist/lib/setup/doc-auditor.d.ts.map +1 -0
- package/dist/lib/setup/doc-auditor.js +629 -0
- package/dist/lib/setup/doc-auditor.js.map +1 -0
- package/dist/lib/setup/domain-generator.d.ts +7 -0
- package/dist/lib/setup/domain-generator.d.ts.map +1 -0
- package/dist/lib/setup/domain-generator.js +58 -0
- package/dist/lib/setup/domain-generator.js.map +1 -0
- package/dist/lib/setup/smart-eval-generator.d.ts +38 -0
- package/dist/lib/setup/smart-eval-generator.d.ts.map +1 -0
- package/dist/lib/setup/smart-eval-generator.js +378 -0
- package/dist/lib/setup/smart-eval-generator.js.map +1 -0
- package/dist/lib/setup/smart-recommender.d.ts +63 -0
- package/dist/lib/setup/smart-recommender.d.ts.map +1 -0
- package/dist/lib/setup/smart-recommender.js +329 -0
- package/dist/lib/setup/smart-recommender.js.map +1 -0
- package/dist/lib/setup/spec-generator.d.ts +63 -0
- package/dist/lib/setup/spec-generator.d.ts.map +1 -0
- package/dist/lib/setup/spec-generator.js +310 -0
- package/dist/lib/setup/spec-generator.js.map +1 -0
- package/dist/lib/setup/violation-agent-generator.d.ts +32 -0
- package/dist/lib/setup/violation-agent-generator.d.ts.map +1 -0
- package/dist/lib/setup/violation-agent-generator.js +255 -0
- package/dist/lib/setup/violation-agent-generator.js.map +1 -0
- package/dist/lib/stratus-client.d.ts +1 -0
- package/dist/lib/stratus-client.d.ts.map +1 -1
- package/dist/lib/stratus-client.js +24 -2
- package/dist/lib/stratus-client.js.map +1 -1
- package/dist/lib/telemetry-agent-v2.d.ts +128 -0
- package/dist/lib/telemetry-agent-v2.d.ts.map +1 -0
- package/dist/lib/telemetry-agent-v2.js +1042 -0
- package/dist/lib/telemetry-agent-v2.js.map +1 -0
- package/dist/lib/telemetry-agent.d.ts.map +1 -1
- package/dist/lib/telemetry-agent.js +27 -6
- package/dist/lib/telemetry-agent.js.map +1 -1
- package/dist/lib/telemetry-digest.d.ts.map +1 -1
- package/dist/lib/telemetry-digest.js +27 -5
- package/dist/lib/telemetry-digest.js.map +1 -1
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/telemetry.js +29 -4
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/lib/text-preprocessing.d.ts +83 -0
- package/dist/lib/text-preprocessing.d.ts.map +1 -0
- package/dist/lib/text-preprocessing.js +261 -0
- package/dist/lib/text-preprocessing.js.map +1 -0
- package/dist/lib/training-buffer.d.ts +86 -0
- package/dist/lib/training-buffer.d.ts.map +1 -0
- package/dist/lib/training-buffer.js +139 -0
- package/dist/lib/training-buffer.js.map +1 -0
- package/dist/lib/tuple-miner.d.ts +30 -0
- package/dist/lib/tuple-miner.d.ts.map +1 -0
- package/dist/lib/tuple-miner.js +427 -0
- package/dist/lib/tuple-miner.js.map +1 -0
- package/dist/lib/vm-backend.d.ts +72 -0
- package/dist/lib/vm-backend.d.ts.map +1 -0
- package/dist/lib/vm-backend.js +175 -0
- package/dist/lib/vm-backend.js.map +1 -0
- package/dist/lib/workspace/backend.d.ts +53 -0
- package/dist/lib/workspace/backend.d.ts.map +1 -0
- package/dist/lib/workspace/backend.js +37 -0
- package/dist/lib/workspace/backend.js.map +1 -0
- package/dist/lib/workspace/cmux-adapter.d.ts +46 -0
- package/dist/lib/workspace/cmux-adapter.d.ts.map +1 -0
- package/dist/lib/workspace/cmux-adapter.js +261 -0
- package/dist/lib/workspace/cmux-adapter.js.map +1 -0
- package/dist/lib/workspace/data-pipeline.d.ts +35 -0
- package/dist/lib/workspace/data-pipeline.d.ts.map +1 -0
- package/dist/lib/workspace/data-pipeline.js +463 -0
- package/dist/lib/workspace/data-pipeline.js.map +1 -0
- package/dist/lib/workspace/engine.d.ts +64 -0
- package/dist/lib/workspace/engine.d.ts.map +1 -0
- package/dist/lib/workspace/engine.js +397 -0
- package/dist/lib/workspace/engine.js.map +1 -0
- package/dist/lib/workspace/notifications.d.ts +14 -0
- package/dist/lib/workspace/notifications.d.ts.map +1 -0
- package/dist/lib/workspace/notifications.js +41 -0
- package/dist/lib/workspace/notifications.js.map +1 -0
- package/dist/lib/workspace/surface-registry.d.ts +49 -0
- package/dist/lib/workspace/surface-registry.d.ts.map +1 -0
- package/dist/lib/workspace/surface-registry.js +217 -0
- package/dist/lib/workspace/surface-registry.js.map +1 -0
- package/dist/lib/workspace/surface-type.d.ts +153 -0
- package/dist/lib/workspace/surface-type.d.ts.map +1 -0
- package/dist/lib/workspace/surface-type.js +9 -0
- package/dist/lib/workspace/surface-type.js.map +1 -0
- package/dist/lib/workspace/surfaces/agent-overview.d.ts +16 -0
- package/dist/lib/workspace/surfaces/agent-overview.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/agent-overview.js +116 -0
- package/dist/lib/workspace/surfaces/agent-overview.js.map +1 -0
- package/dist/lib/workspace/surfaces/agent.d.ts +16 -0
- package/dist/lib/workspace/surfaces/agent.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/agent.js +112 -0
- package/dist/lib/workspace/surfaces/agent.js.map +1 -0
- package/dist/lib/workspace/surfaces/claude.d.ts +15 -0
- package/dist/lib/workspace/surfaces/claude.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/claude.js +23 -0
- package/dist/lib/workspace/surfaces/claude.js.map +1 -0
- package/dist/lib/workspace/surfaces/dashboard.d.ts +21 -0
- package/dist/lib/workspace/surfaces/dashboard.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/dashboard.js +32 -0
- package/dist/lib/workspace/surfaces/dashboard.js.map +1 -0
- package/dist/lib/workspace/surfaces/eval.d.ts +15 -0
- package/dist/lib/workspace/surfaces/eval.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/eval.js +42 -0
- package/dist/lib/workspace/surfaces/eval.js.map +1 -0
- package/dist/lib/workspace/surfaces/event-stream.d.ts +16 -0
- package/dist/lib/workspace/surfaces/event-stream.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/event-stream.js +40 -0
- package/dist/lib/workspace/surfaces/event-stream.js.map +1 -0
- package/dist/lib/workspace/surfaces/flow.d.ts +16 -0
- package/dist/lib/workspace/surfaces/flow.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/flow.js +49 -0
- package/dist/lib/workspace/surfaces/flow.js.map +1 -0
- package/dist/lib/workspace/surfaces/index.d.ts +16 -0
- package/dist/lib/workspace/surfaces/index.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/index.js +16 -0
- package/dist/lib/workspace/surfaces/index.js.map +1 -0
- package/dist/lib/workspace/surfaces/portfolio.d.ts +16 -0
- package/dist/lib/workspace/surfaces/portfolio.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/portfolio.js +102 -0
- package/dist/lib/workspace/surfaces/portfolio.js.map +1 -0
- package/dist/lib/workspace/surfaces/service.d.ts +16 -0
- package/dist/lib/workspace/surfaces/service.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/service.js +45 -0
- package/dist/lib/workspace/surfaces/service.js.map +1 -0
- package/dist/lib/workspace/surfaces/shell.d.ts +15 -0
- package/dist/lib/workspace/surfaces/shell.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/shell.js +19 -0
- package/dist/lib/workspace/surfaces/shell.js.map +1 -0
- package/dist/lib/workspace/surfaces/telemetry.d.ts +16 -0
- package/dist/lib/workspace/surfaces/telemetry.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/telemetry.js +48 -0
- package/dist/lib/workspace/surfaces/telemetry.js.map +1 -0
- package/dist/lib/workspace/surfaces/topology.d.ts +15 -0
- package/dist/lib/workspace/surfaces/topology.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/topology.js +19 -0
- package/dist/lib/workspace/surfaces/topology.js.map +1 -0
- package/dist/lib/workspace/surfaces/training.d.ts +16 -0
- package/dist/lib/workspace/surfaces/training.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/training.js +22 -0
- package/dist/lib/workspace/surfaces/training.js.map +1 -0
- package/dist/lib/workspace/tmux-adapter.d.ts +27 -0
- package/dist/lib/workspace/tmux-adapter.d.ts.map +1 -0
- package/dist/lib/workspace/tmux-adapter.js +106 -0
- package/dist/lib/workspace/tmux-adapter.js.map +1 -0
- package/dist/mcp/context-hub-mcp.js +7 -24
- package/dist/mcp/context-hub-mcp.js.map +1 -1
- package/dist/types/flows.d.ts +2 -0
- package/dist/types/flows.d.ts.map +1 -1
- package/dist/types/ide.d.ts +49 -0
- package/dist/types/ide.d.ts.map +1 -0
- package/dist/types/ide.js +5 -0
- package/dist/types/ide.js.map +1 -0
- package/dist/types/platform-digest.d.ts +228 -0
- package/dist/types/platform-digest.d.ts.map +1 -0
- package/dist/types/platform-digest.js +5 -0
- package/dist/types/platform-digest.js.map +1 -0
- package/dist/types/telemetry-digest.d.ts +2 -0
- package/dist/types/telemetry-digest.d.ts.map +1 -1
- package/dist/utils/ensure-project.d.ts +1 -0
- package/dist/utils/ensure-project.d.ts.map +1 -1
- package/dist/utils/ensure-project.js +19 -7
- package/dist/utils/ensure-project.js.map +1 -1
- package/dist/utils/jfl-config.d.ts +1 -0
- package/dist/utils/jfl-config.d.ts.map +1 -1
- package/dist/utils/jfl-config.js +19 -1
- package/dist/utils/jfl-config.js.map +1 -1
- package/dist/utils/jfl-paths.d.ts +5 -0
- package/dist/utils/jfl-paths.d.ts.map +1 -1
- package/dist/utils/jfl-paths.js +25 -3
- package/dist/utils/jfl-paths.js.map +1 -1
- package/package.json +3 -2
- package/packages/pi/AGENTS.md +112 -0
- package/packages/pi/extensions/agent-grid.ts +191 -0
- package/packages/pi/extensions/agent-names.ts +178 -0
- package/packages/pi/extensions/autoresearch.ts +427 -0
- package/packages/pi/extensions/bookmarks.ts +85 -0
- package/packages/pi/extensions/context.ts +184 -0
- package/packages/pi/extensions/crm-tool.ts +61 -0
- package/packages/pi/extensions/eval-tool.ts +224 -0
- package/packages/pi/extensions/eval.ts +60 -0
- package/packages/pi/extensions/footer.ts +239 -0
- package/packages/pi/extensions/hub-resolver.ts +63 -0
- package/packages/pi/extensions/hud-tool.ts +145 -0
- package/packages/pi/extensions/index.ts +405 -0
- package/packages/pi/extensions/journal.ts +224 -0
- package/packages/pi/extensions/map-bridge.ts +178 -0
- package/packages/pi/extensions/memory-tool.ts +73 -0
- package/packages/pi/extensions/notifications.ts +73 -0
- package/packages/pi/extensions/peter-parker.ts +202 -0
- package/packages/pi/extensions/policy-head-tool.ts +276 -0
- package/packages/pi/extensions/portfolio-bridge.ts +90 -0
- package/packages/pi/extensions/session.ts +142 -0
- package/packages/pi/extensions/shortcuts.ts +259 -0
- package/packages/pi/extensions/stratus-bridge.ts +115 -0
- package/packages/pi/extensions/synopsis-tool.ts +83 -0
- package/packages/pi/extensions/tool-renderers.ts +353 -0
- package/packages/pi/extensions/training-buffer-tool.ts +368 -0
- package/packages/pi/extensions/types.ts +163 -0
- package/packages/pi/package-lock.json +346 -0
- package/packages/pi/package.json +44 -0
- package/packages/pi/skills/agent-browser/SKILL.md +116 -0
- package/packages/pi/skills/brand-architect/SKILL.md +240 -0
- package/packages/pi/skills/brand-architect/config.yaml +137 -0
- package/packages/pi/skills/campaign-hud/config.yaml +112 -0
- package/packages/pi/skills/content-creator/SKILL.md +294 -0
- package/packages/pi/skills/context/SKILL.md +65 -0
- package/packages/pi/skills/debug/MULTI_AGENT.md +360 -0
- package/packages/pi/skills/debug/SKILL.md +554 -0
- package/packages/pi/skills/end/SKILL.md +1782 -0
- package/packages/pi/skills/eval/SKILL.md +75 -0
- package/packages/pi/skills/fly-deploy/SKILL.md +676 -0
- package/packages/pi/skills/founder-video/SKILL.md +467 -0
- package/packages/pi/skills/hud/SKILL.md +160 -0
- package/packages/pi/skills/orchestrate/SKILL.md +74 -0
- package/packages/pi/skills/pi-agents/SKILL.md +78 -0
- package/packages/pi/skills/react-best-practices/AGENTS.md +2249 -0
- package/packages/pi/skills/react-best-practices/README.md +123 -0
- package/packages/pi/skills/react-best-practices/SKILL.md +125 -0
- package/packages/pi/skills/react-best-practices/metadata.json +15 -0
- package/packages/pi/skills/react-best-practices/rules/_sections.md +46 -0
- package/packages/pi/skills/react-best-practices/rules/_template.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/packages/pi/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/packages/pi/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/packages/pi/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/packages/pi/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/packages/pi/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/packages/pi/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/packages/pi/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/packages/pi/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/packages/pi/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/packages/pi/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/packages/pi/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/packages/pi/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/packages/pi/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/packages/pi/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/packages/pi/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/packages/pi/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/packages/pi/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/packages/pi/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/packages/pi/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/packages/pi/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/packages/pi/skills/react-best-practices/rules/server-cache-react.md +26 -0
- package/packages/pi/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
- package/packages/pi/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/packages/pi/skills/remotion-best-practices/SKILL.md +43 -0
- package/packages/pi/skills/remotion-best-practices/rules/3d.md +86 -0
- package/packages/pi/skills/remotion-best-practices/rules/animations.md +29 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets.md +78 -0
- package/packages/pi/skills/remotion-best-practices/rules/audio.md +172 -0
- package/packages/pi/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
- package/packages/pi/skills/remotion-best-practices/rules/can-decode.md +75 -0
- package/packages/pi/skills/remotion-best-practices/rules/charts.md +58 -0
- package/packages/pi/skills/remotion-best-practices/rules/compositions.md +146 -0
- package/packages/pi/skills/remotion-best-practices/rules/display-captions.md +126 -0
- package/packages/pi/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/packages/pi/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/packages/pi/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/packages/pi/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/packages/pi/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
- package/packages/pi/skills/remotion-best-practices/rules/gifs.md +138 -0
- package/packages/pi/skills/remotion-best-practices/rules/images.md +130 -0
- package/packages/pi/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
- package/packages/pi/skills/remotion-best-practices/rules/lottie.md +68 -0
- package/packages/pi/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
- package/packages/pi/skills/remotion-best-practices/rules/measuring-text.md +143 -0
- package/packages/pi/skills/remotion-best-practices/rules/sequencing.md +106 -0
- package/packages/pi/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/packages/pi/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/packages/pi/skills/remotion-best-practices/rules/timing.md +179 -0
- package/packages/pi/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
- package/packages/pi/skills/remotion-best-practices/rules/transitions.md +122 -0
- package/packages/pi/skills/remotion-best-practices/rules/trimming.md +53 -0
- package/packages/pi/skills/remotion-best-practices/rules/videos.md +171 -0
- package/packages/pi/skills/search/SKILL.md +220 -0
- package/packages/pi/skills/spec/SKILL.md +377 -0
- package/packages/pi/skills/startup/SKILL.md +315 -0
- package/packages/pi/skills/web-architect/SKILL.md +309 -0
- package/packages/pi/skills/x-algorithm/SKILL.md +305 -0
- package/packages/pi/teams/dev-team.yaml +63 -0
- package/packages/pi/teams/gtm-team.yaml +79 -0
- package/packages/pi/themes/jfl.theme.json +76 -0
- package/packages/pi/tsconfig.json +21 -0
- package/scripts/collect-tuples.sh +124 -0
- package/scripts/destroy-fleet.sh +37 -0
- package/scripts/jfl-ide.sh +48 -0
- package/scripts/session/session-cleanup.sh +4 -11
- package/scripts/session/session-init.sh +6 -0
- package/scripts/session/session-sync.sh +25 -0
- package/scripts/setup-branch-protection.sh +106 -0
- package/scripts/spawn-fleet.sh +144 -0
- package/scripts/train/requirements.txt +5 -0
- package/scripts/train/train-policy-head.py +477 -0
- package/scripts/train/v2/dataset.py +81 -0
- package/scripts/train/v2/domain.json +18 -0
- package/scripts/train/v2/eval.py +196 -0
- package/scripts/train/v2/generate_data.py +219 -0
- package/scripts/train/v2/infer.py +188 -0
- package/scripts/train/v2/model.py +112 -0
- package/scripts/train/v2/precompute.py +132 -0
- package/scripts/train/v2/train.py +302 -0
- package/scripts/train/v2/transform_buffer.py +227 -0
- package/scripts/train/v2/validate_data.py +115 -0
- package/scripts/train-policy-head.py +434 -0
- package/scripts/vm-swarm/README.md +301 -0
- package/scripts/vm-swarm/collect-tuples.sh +331 -0
- package/scripts/vm-swarm/create-base-template.sh +339 -0
- package/scripts/vm-swarm/kill-fleet.sh +204 -0
- package/scripts/vm-swarm/monitor-fleet.sh +346 -0
- package/scripts/vm-swarm/spawn-fleet.sh +304 -0
- package/template/.claude/settings.json +2 -15
- package/template/.github/workflows/jfl-eval.yml +6 -1
- package/template/.github/workflows/jfl-review.yml +4 -0
- package/template/scripts/session/session-cleanup.sh +2 -11
- package/template/scripts/session/session-end-hub.sh +72 -0
- package/template/scripts/session/session-end.sh +69 -6
- package/template/scripts/session/session-init.sh +55 -30
- package/template/scripts/session/session-lock.sh +464 -0
- package/template/scripts/session/session-start-hub.sh +105 -0
- package/template/templates/service-agent/workflows/jfl-eval.yml +19 -0
- package/dist/dashboard-static/assets/index-B6kRK9Rq.js +0 -116
- package/dist/dashboard-static/assets/index-BpdKJPLu.css +0 -1
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @purpose Audit GTM workspace docs — bifurcated: framework vs customer docs
|
|
3
|
+
*
|
|
4
|
+
* Framework docs: came from templates/skills, compare to upstream, track version drift
|
|
5
|
+
* Customer docs: PRDs, knowledge, custom content — analyze for staleness, token cost, relevance
|
|
6
|
+
*
|
|
7
|
+
* Core insight: "this doc costs you $X per day and adds zero value" > "this doc is long, split it"
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
10
|
+
import { join, relative, basename } from "path";
|
|
11
|
+
// Markers that indicate a doc came from a framework/template
|
|
12
|
+
const FRAMEWORK_MARKERS = [
|
|
13
|
+
"<!-- jfl-template",
|
|
14
|
+
"<!-- generated by jfl",
|
|
15
|
+
"# generated by jfl",
|
|
16
|
+
"<!-- skill:",
|
|
17
|
+
"<!-- managed by",
|
|
18
|
+
"DO NOT EDIT — managed by",
|
|
19
|
+
"Auto-generated from template",
|
|
20
|
+
];
|
|
21
|
+
// Directories that typically contain framework-managed content
|
|
22
|
+
const FRAMEWORK_DIRS = [
|
|
23
|
+
".claude/skills",
|
|
24
|
+
".claude/commands",
|
|
25
|
+
".cursor/rules",
|
|
26
|
+
"skills/",
|
|
27
|
+
];
|
|
28
|
+
// Directories that typically contain customer content
|
|
29
|
+
const CUSTOMER_DIRS = [
|
|
30
|
+
"knowledge/",
|
|
31
|
+
"docs/",
|
|
32
|
+
"prds/",
|
|
33
|
+
"specs/",
|
|
34
|
+
"rfcs/",
|
|
35
|
+
"design/",
|
|
36
|
+
"decisions/",
|
|
37
|
+
];
|
|
38
|
+
// Well-known framework files
|
|
39
|
+
const FRAMEWORK_FILES = new Set([
|
|
40
|
+
"CLAUDE.md",
|
|
41
|
+
"AGENTS.md",
|
|
42
|
+
".cursorrules",
|
|
43
|
+
".claude/settings.json",
|
|
44
|
+
"CONVENTIONS.md",
|
|
45
|
+
"CONTRIBUTING.md",
|
|
46
|
+
]);
|
|
47
|
+
const MAX_DOC_LINES = 300;
|
|
48
|
+
const STALE_DAYS = 14;
|
|
49
|
+
const TOKENS_PER_CHAR = 0.25; // rough estimate
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Main audit
|
|
52
|
+
// ============================================================================
|
|
53
|
+
export function auditDocs(projectRoot, insight) {
|
|
54
|
+
const result = {
|
|
55
|
+
docs: [],
|
|
56
|
+
totalDocs: 0,
|
|
57
|
+
totalLines: 0,
|
|
58
|
+
totalBytes: 0,
|
|
59
|
+
totalTokens: 0,
|
|
60
|
+
frameworkDocs: [],
|
|
61
|
+
customerDocs: [],
|
|
62
|
+
staleDocs: [],
|
|
63
|
+
bloatedDocs: [],
|
|
64
|
+
missingDocs: [],
|
|
65
|
+
unreferencedDocs: [],
|
|
66
|
+
recommendations: [],
|
|
67
|
+
};
|
|
68
|
+
const mdFiles = findMarkdownFiles(projectRoot);
|
|
69
|
+
const now = new Date();
|
|
70
|
+
// Build reference index from journals — which docs/paths get mentioned?
|
|
71
|
+
const journalReferences = buildJournalReferenceIndex(insight);
|
|
72
|
+
// Check for manifest (tracks what came from templates)
|
|
73
|
+
const manifest = loadManifest(projectRoot);
|
|
74
|
+
for (const filePath of mdFiles) {
|
|
75
|
+
const stat = statSync(filePath);
|
|
76
|
+
const content = readFileSync(filePath, "utf-8");
|
|
77
|
+
const lines = content.split("\n").length;
|
|
78
|
+
const relPath = relative(projectRoot, filePath);
|
|
79
|
+
const daysSinceModified = (now.getTime() - stat.mtime.getTime()) / (1000 * 60 * 60 * 24);
|
|
80
|
+
const tokenEstimate = Math.ceil(content.length * TOKENS_PER_CHAR);
|
|
81
|
+
// Classify origin
|
|
82
|
+
const origin = classifyOrigin(relPath, content, manifest);
|
|
83
|
+
// Calculate stale score
|
|
84
|
+
let staleScore = 0;
|
|
85
|
+
if (daysSinceModified > STALE_DAYS * 3)
|
|
86
|
+
staleScore = 1.0;
|
|
87
|
+
else if (daysSinceModified > STALE_DAYS * 2)
|
|
88
|
+
staleScore = 0.8;
|
|
89
|
+
else if (daysSinceModified > STALE_DAYS)
|
|
90
|
+
staleScore = 0.5;
|
|
91
|
+
else
|
|
92
|
+
staleScore = daysSinceModified / STALE_DAYS * 0.3;
|
|
93
|
+
// Calculate bloat score
|
|
94
|
+
let bloatScore = 0;
|
|
95
|
+
if (lines > MAX_DOC_LINES * 3)
|
|
96
|
+
bloatScore = 1.0;
|
|
97
|
+
else if (lines > MAX_DOC_LINES * 2)
|
|
98
|
+
bloatScore = 0.8;
|
|
99
|
+
else if (lines > MAX_DOC_LINES)
|
|
100
|
+
bloatScore = 0.5;
|
|
101
|
+
// Calculate relevance from journal references
|
|
102
|
+
const refCount = countReferences(relPath, journalReferences);
|
|
103
|
+
const relevanceScore = Math.min(1, refCount / 5); // 5+ references = fully relevant
|
|
104
|
+
// Extract sections (H1/H2)
|
|
105
|
+
const sections = extractSections(content);
|
|
106
|
+
// Count TODOs
|
|
107
|
+
const todoMatches = content.match(/\bTODO\b|\bFIXME\b|\bHACK\b|\bXXX\b/gi) || [];
|
|
108
|
+
const todoCount = todoMatches.length;
|
|
109
|
+
// Find dead links
|
|
110
|
+
const deadLinks = findDeadLinks(content, projectRoot);
|
|
111
|
+
// Build issues list
|
|
112
|
+
const issues = [];
|
|
113
|
+
if (staleScore > 0.5)
|
|
114
|
+
issues.push(`Not modified in ${Math.floor(daysSinceModified)} days`);
|
|
115
|
+
if (bloatScore > 0.5)
|
|
116
|
+
issues.push(`${lines} lines (${tokenEstimate} tokens)`);
|
|
117
|
+
if (relevanceScore < 0.1 && lines > 50)
|
|
118
|
+
issues.push("Never referenced in journals");
|
|
119
|
+
if (todoCount > 3)
|
|
120
|
+
issues.push(`${todoCount} unresolved TODOs`);
|
|
121
|
+
if (deadLinks.length > 0)
|
|
122
|
+
issues.push(`${deadLinks.length} dead link(s)`);
|
|
123
|
+
// Framework-specific: check for version drift
|
|
124
|
+
if (origin === "framework" && manifest) {
|
|
125
|
+
const entry = manifest.files?.[relPath];
|
|
126
|
+
if (entry?.templateVersion && entry?.currentHash) {
|
|
127
|
+
issues.push(`Template version: ${entry.templateVersion}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Customer-specific: token cost awareness
|
|
131
|
+
if (origin === "customer" && relevanceScore < 0.2 && tokenEstimate > 1000) {
|
|
132
|
+
issues.push(`Costs ~${tokenEstimate} tokens/session with 0 journal references`);
|
|
133
|
+
}
|
|
134
|
+
const doc = {
|
|
135
|
+
path: filePath,
|
|
136
|
+
relativePath: relPath,
|
|
137
|
+
sizeBytes: stat.size,
|
|
138
|
+
lines,
|
|
139
|
+
lastModified: stat.mtime,
|
|
140
|
+
staleScore,
|
|
141
|
+
bloatScore,
|
|
142
|
+
relevanceScore,
|
|
143
|
+
origin,
|
|
144
|
+
tokenEstimate,
|
|
145
|
+
issues,
|
|
146
|
+
sections,
|
|
147
|
+
todoCount,
|
|
148
|
+
deadLinks,
|
|
149
|
+
referenceCount: refCount,
|
|
150
|
+
};
|
|
151
|
+
result.docs.push(doc);
|
|
152
|
+
result.totalDocs++;
|
|
153
|
+
result.totalLines += lines;
|
|
154
|
+
result.totalBytes += stat.size;
|
|
155
|
+
result.totalTokens += tokenEstimate;
|
|
156
|
+
if (origin === "framework")
|
|
157
|
+
result.frameworkDocs.push(doc);
|
|
158
|
+
else
|
|
159
|
+
result.customerDocs.push(doc);
|
|
160
|
+
if (staleScore > 0.5)
|
|
161
|
+
result.staleDocs.push(doc);
|
|
162
|
+
if (bloatScore > 0.5)
|
|
163
|
+
result.bloatedDocs.push(doc);
|
|
164
|
+
if (refCount === 0 && lines > 30)
|
|
165
|
+
result.unreferencedDocs.push(doc);
|
|
166
|
+
}
|
|
167
|
+
// Check for missing expected docs
|
|
168
|
+
checkMissingDocs(projectRoot, result);
|
|
169
|
+
// Generate bifurcated recommendations
|
|
170
|
+
result.recommendations = generateRecommendations(result, insight);
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Origin classification
|
|
175
|
+
// ============================================================================
|
|
176
|
+
function classifyOrigin(relPath, content, manifest) {
|
|
177
|
+
// Check manifest first (most reliable)
|
|
178
|
+
if (manifest?.files?.[relPath])
|
|
179
|
+
return "framework";
|
|
180
|
+
// Check for framework markers in content
|
|
181
|
+
const contentLower = content.toLowerCase();
|
|
182
|
+
for (const marker of FRAMEWORK_MARKERS) {
|
|
183
|
+
if (contentLower.includes(marker.toLowerCase()))
|
|
184
|
+
return "framework";
|
|
185
|
+
}
|
|
186
|
+
// Check well-known framework files
|
|
187
|
+
if (FRAMEWORK_FILES.has(basename(relPath)) || FRAMEWORK_FILES.has(relPath)) {
|
|
188
|
+
return "framework";
|
|
189
|
+
}
|
|
190
|
+
// Check directory-based heuristics
|
|
191
|
+
for (const dir of FRAMEWORK_DIRS) {
|
|
192
|
+
if (relPath.startsWith(dir))
|
|
193
|
+
return "framework";
|
|
194
|
+
}
|
|
195
|
+
for (const dir of CUSTOMER_DIRS) {
|
|
196
|
+
if (relPath.startsWith(dir))
|
|
197
|
+
return "customer";
|
|
198
|
+
}
|
|
199
|
+
// Default: if it's in the root, probably framework; if nested, probably customer
|
|
200
|
+
if (!relPath.includes("/"))
|
|
201
|
+
return "framework";
|
|
202
|
+
return "customer";
|
|
203
|
+
}
|
|
204
|
+
function buildJournalReferenceIndex(insight) {
|
|
205
|
+
const pathMentions = new Map();
|
|
206
|
+
const termMentions = new Map();
|
|
207
|
+
// File hotspots from journal analysis
|
|
208
|
+
for (const hotspot of insight.fileHotspots) {
|
|
209
|
+
pathMentions.set(hotspot.path, hotspot.touches);
|
|
210
|
+
}
|
|
211
|
+
// Common patterns → terms
|
|
212
|
+
for (const pattern of insight.commonPatterns) {
|
|
213
|
+
const words = pattern.toLowerCase().split(/\s+/).filter(w => w.length > 4);
|
|
214
|
+
for (const w of words) {
|
|
215
|
+
termMentions.set(w, (termMentions.get(w) || 0) + 1);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return { pathMentions, termMentions };
|
|
219
|
+
}
|
|
220
|
+
function countReferences(relPath, index) {
|
|
221
|
+
let count = 0;
|
|
222
|
+
// Direct path mentions
|
|
223
|
+
for (const [path, touches] of index.pathMentions) {
|
|
224
|
+
if (relPath.includes(path) || path.includes(relPath.replace(/\.md$/, ""))) {
|
|
225
|
+
count += touches;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Term overlap (weaker signal)
|
|
229
|
+
const pathTerms = relPath.toLowerCase().replace(/[/_.-]/g, " ").split(/\s+/).filter(t => t.length > 4);
|
|
230
|
+
for (const term of pathTerms) {
|
|
231
|
+
count += (index.termMentions.get(term) || 0) * 0.2;
|
|
232
|
+
}
|
|
233
|
+
return Math.round(count);
|
|
234
|
+
}
|
|
235
|
+
// ============================================================================
|
|
236
|
+
// Recommendations — bifurcated by origin
|
|
237
|
+
// ============================================================================
|
|
238
|
+
function generateRecommendations(audit, insight) {
|
|
239
|
+
const recs = [];
|
|
240
|
+
// ---- Framework doc recommendations ----
|
|
241
|
+
for (const doc of audit.frameworkDocs) {
|
|
242
|
+
// Bloated framework docs → specific split guidance
|
|
243
|
+
if (doc.bloatScore > 0.5 && doc.sections.length > 3) {
|
|
244
|
+
const sectionList = doc.sections.slice(0, 6).join(", ");
|
|
245
|
+
recs.push({
|
|
246
|
+
type: "split",
|
|
247
|
+
target: doc.relativePath,
|
|
248
|
+
rationale: `${doc.lines} lines with ${doc.sections.length} sections (${sectionList}). Split by purpose: setup instructions, coding standards, and reference material should be separate files.`,
|
|
249
|
+
priority: doc.bloatScore > 0.8 ? 1 : 2,
|
|
250
|
+
estimatedSavings: `~${doc.tokenEstimate} tokens/session → ${Math.floor(doc.tokenEstimate * 0.4)} after split (agents only load relevant sections)`,
|
|
251
|
+
origin: "framework",
|
|
252
|
+
action: `Split into ${Math.min(doc.sections.length, 4)} focused files by section topic`,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
else if (doc.bloatScore > 0.5) {
|
|
256
|
+
recs.push({
|
|
257
|
+
type: "trim",
|
|
258
|
+
target: doc.relativePath,
|
|
259
|
+
rationale: `${doc.lines} lines but only ${doc.sections.length || 1} section(s). Likely has verbose explanations that could be condensed.`,
|
|
260
|
+
priority: 2,
|
|
261
|
+
estimatedSavings: `~${Math.floor(doc.tokenEstimate * 0.3)} tokens removable`,
|
|
262
|
+
origin: "framework",
|
|
263
|
+
action: "Remove verbose explanations, convert prose to bullet points, eliminate redundant examples",
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// Framework docs with many TODOs → template needs updating
|
|
267
|
+
if (doc.todoCount > 3) {
|
|
268
|
+
recs.push({
|
|
269
|
+
type: "update",
|
|
270
|
+
target: doc.relativePath,
|
|
271
|
+
rationale: `Framework doc has ${doc.todoCount} unresolved TODOs — template is shipping incomplete scaffolding`,
|
|
272
|
+
priority: 1,
|
|
273
|
+
origin: "framework",
|
|
274
|
+
action: "Resolve TODOs or remove placeholder sections that aren't actionable",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
// Dead links in framework docs → broken template
|
|
278
|
+
if (doc.deadLinks.length > 0) {
|
|
279
|
+
recs.push({
|
|
280
|
+
type: "update",
|
|
281
|
+
target: doc.relativePath,
|
|
282
|
+
rationale: `${doc.deadLinks.length} dead link(s): ${doc.deadLinks.slice(0, 3).join(", ")}`,
|
|
283
|
+
priority: 1,
|
|
284
|
+
origin: "framework",
|
|
285
|
+
action: "Fix or remove broken references — these mislead agents",
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// ---- Customer doc recommendations ----
|
|
290
|
+
for (const doc of audit.customerDocs) {
|
|
291
|
+
// Customer doc never referenced + large → biggest win
|
|
292
|
+
if (doc.referenceCount === 0 && doc.tokenEstimate > 500) {
|
|
293
|
+
const daysSinceModified = Math.floor((new Date().getTime() - doc.lastModified.getTime()) / (1000 * 60 * 60 * 24));
|
|
294
|
+
if (daysSinceModified > STALE_DAYS) {
|
|
295
|
+
recs.push({
|
|
296
|
+
type: "archive",
|
|
297
|
+
target: doc.relativePath,
|
|
298
|
+
rationale: `Costs ~${doc.tokenEstimate} tokens/session but has 0 journal references in ${insight.totalSessions} sessions. Last modified ${daysSinceModified} days ago. Archiving saves tokens without losing anything agents use.`,
|
|
299
|
+
priority: 1,
|
|
300
|
+
estimatedSavings: `${doc.tokenEstimate} tokens/session (~$${(doc.tokenEstimate * 0.000003 * 30).toFixed(2)}/month at typical rates)`,
|
|
301
|
+
origin: "customer",
|
|
302
|
+
action: `Move to archive/ or .jfl/archived-docs/ — recoverable but out of context window`,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
recs.push({
|
|
307
|
+
type: "archive",
|
|
308
|
+
target: doc.relativePath,
|
|
309
|
+
rationale: `${doc.tokenEstimate} tokens/session, 0 journal references across ${insight.totalSessions} sessions. Recently modified but agents aren't using it.`,
|
|
310
|
+
priority: 2,
|
|
311
|
+
estimatedSavings: `${doc.tokenEstimate} tokens/session`,
|
|
312
|
+
origin: "customer",
|
|
313
|
+
action: "Verify this doc is actually loaded into agent context. If not needed, archive it.",
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Customer doc with high reference count but stale → needs refresh
|
|
318
|
+
if (doc.referenceCount > 3 && doc.staleScore > 0.5) {
|
|
319
|
+
recs.push({
|
|
320
|
+
type: "refresh",
|
|
321
|
+
target: doc.relativePath,
|
|
322
|
+
rationale: `Referenced ${doc.referenceCount} times in journals but not updated in ${Math.floor((new Date().getTime() - doc.lastModified.getTime()) / (1000 * 60 * 60 * 24))} days. Agents rely on this — make sure it's accurate.`,
|
|
323
|
+
priority: 1,
|
|
324
|
+
origin: "customer",
|
|
325
|
+
action: "Review against current system state. Update or confirm accuracy.",
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
// Customer doc that's bloated → specific guidance based on sections
|
|
329
|
+
if (doc.bloatScore > 0.5) {
|
|
330
|
+
if (doc.sections.length >= 4) {
|
|
331
|
+
// Has clear section structure → can split meaningfully
|
|
332
|
+
const topicGroups = groupSections(doc.sections);
|
|
333
|
+
recs.push({
|
|
334
|
+
type: "split",
|
|
335
|
+
target: doc.relativePath,
|
|
336
|
+
rationale: `${doc.lines} lines across ${doc.sections.length} sections. Topics: ${topicGroups.join("; ")}. Splitting lets agents load only relevant context.`,
|
|
337
|
+
priority: 2,
|
|
338
|
+
estimatedSavings: `${doc.tokenEstimate} tokens → ~${Math.floor(doc.tokenEstimate / doc.sections.length)} per split file`,
|
|
339
|
+
origin: "customer",
|
|
340
|
+
action: `Split into ${Math.min(topicGroups.length, 4)} files by topic area`,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
// No clear sections → trim
|
|
345
|
+
recs.push({
|
|
346
|
+
type: "trim",
|
|
347
|
+
target: doc.relativePath,
|
|
348
|
+
rationale: `${doc.lines} lines but lacks clear section structure. Likely has redundant content or could be condensed.`,
|
|
349
|
+
priority: 3,
|
|
350
|
+
estimatedSavings: `~${Math.floor(doc.tokenEstimate * 0.3)} tokens removable`,
|
|
351
|
+
origin: "customer",
|
|
352
|
+
action: "Add section headers, remove redundant explanations, extract examples to separate files",
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// Old TODOs in customer docs → stale promises
|
|
357
|
+
if (doc.todoCount > 0 && doc.staleScore > 0.3) {
|
|
358
|
+
recs.push({
|
|
359
|
+
type: "update",
|
|
360
|
+
target: doc.relativePath,
|
|
361
|
+
rationale: `${doc.todoCount} TODOs in a doc not updated in ${Math.floor((new Date().getTime() - doc.lastModified.getTime()) / (1000 * 60 * 60 * 24))} days — these are likely stale or completed`,
|
|
362
|
+
priority: 3,
|
|
363
|
+
origin: "customer",
|
|
364
|
+
action: "Resolve, remove, or convert stale TODOs to done items",
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// ---- Cross-origin: duplication detection ----
|
|
369
|
+
const duplicateGroups = findPotentialDuplicates(audit.docs);
|
|
370
|
+
for (const group of duplicateGroups) {
|
|
371
|
+
recs.push({
|
|
372
|
+
type: "dedupe",
|
|
373
|
+
target: group.map(d => d.relativePath).join(" + "),
|
|
374
|
+
rationale: `These docs share similar topics (${group[0].sections.filter(s => group[1]?.sections.includes(s)).join(", ") || "similar content"}). Merge or deduplicate to reduce token cost.`,
|
|
375
|
+
priority: 2,
|
|
376
|
+
estimatedSavings: `~${group.reduce((sum, d) => sum + d.tokenEstimate, 0)} combined tokens → could halve with merge`,
|
|
377
|
+
origin: "unknown",
|
|
378
|
+
action: "Review for overlap. Keep one authoritative version.",
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
// ---- Missing docs for active areas ----
|
|
382
|
+
checkMissingDocsForActivity(audit, insight, recs);
|
|
383
|
+
// ---- Token budget summary ----
|
|
384
|
+
const unreferencedTokens = audit.unreferencedDocs.reduce((sum, d) => sum + d.tokenEstimate, 0);
|
|
385
|
+
if (unreferencedTokens > 5000) {
|
|
386
|
+
recs.unshift({
|
|
387
|
+
type: "archive",
|
|
388
|
+
target: `${audit.unreferencedDocs.length} unreferenced docs`,
|
|
389
|
+
rationale: `${audit.unreferencedDocs.length} docs (${unreferencedTokens} tokens) are never referenced in journals. Archiving all would save ~${unreferencedTokens} tokens/session.`,
|
|
390
|
+
priority: 1,
|
|
391
|
+
estimatedSavings: `${unreferencedTokens} tokens/session (~$${(unreferencedTokens * 0.000003 * 30 * 20).toFixed(2)}/month at 20 sessions/day)`,
|
|
392
|
+
origin: "unknown",
|
|
393
|
+
action: "Review list and archive docs that aren't needed in agent context",
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return recs.sort((a, b) => a.priority - b.priority);
|
|
397
|
+
}
|
|
398
|
+
// ============================================================================
|
|
399
|
+
// Duplication detection
|
|
400
|
+
// ============================================================================
|
|
401
|
+
function findPotentialDuplicates(docs) {
|
|
402
|
+
const groups = [];
|
|
403
|
+
const seen = new Set();
|
|
404
|
+
for (let i = 0; i < docs.length; i++) {
|
|
405
|
+
if (seen.has(docs[i].relativePath))
|
|
406
|
+
continue;
|
|
407
|
+
if (docs[i].sections.length < 2)
|
|
408
|
+
continue;
|
|
409
|
+
const group = [docs[i]];
|
|
410
|
+
for (let j = i + 1; j < docs.length; j++) {
|
|
411
|
+
if (seen.has(docs[j].relativePath))
|
|
412
|
+
continue;
|
|
413
|
+
if (docs[j].sections.length < 2)
|
|
414
|
+
continue;
|
|
415
|
+
// Check section overlap
|
|
416
|
+
const overlap = docs[i].sections.filter(s => docs[j].sections.some(s2 => sectionsSimilar(s, s2)));
|
|
417
|
+
const overlapRatio = overlap.length / Math.min(docs[i].sections.length, docs[j].sections.length);
|
|
418
|
+
if (overlapRatio > 0.5) {
|
|
419
|
+
group.push(docs[j]);
|
|
420
|
+
seen.add(docs[j].relativePath);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (group.length > 1) {
|
|
424
|
+
seen.add(docs[i].relativePath);
|
|
425
|
+
groups.push(group);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return groups.slice(0, 5); // cap at 5 groups
|
|
429
|
+
}
|
|
430
|
+
function sectionsSimilar(a, b) {
|
|
431
|
+
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, " ").trim();
|
|
432
|
+
const na = normalize(a);
|
|
433
|
+
const nb = normalize(b);
|
|
434
|
+
if (na === nb)
|
|
435
|
+
return true;
|
|
436
|
+
// Check word overlap
|
|
437
|
+
const wa = new Set(na.split(/\s+/));
|
|
438
|
+
const wb = new Set(nb.split(/\s+/));
|
|
439
|
+
const intersection = [...wa].filter(w => wb.has(w) && w.length > 3);
|
|
440
|
+
return intersection.length >= 2;
|
|
441
|
+
}
|
|
442
|
+
// ============================================================================
|
|
443
|
+
// Helpers
|
|
444
|
+
// ============================================================================
|
|
445
|
+
function extractSections(content) {
|
|
446
|
+
const sections = [];
|
|
447
|
+
for (const line of content.split("\n")) {
|
|
448
|
+
const match = line.match(/^#{1,2}\s+(.+)/);
|
|
449
|
+
if (match)
|
|
450
|
+
sections.push(match[1].trim());
|
|
451
|
+
}
|
|
452
|
+
return sections;
|
|
453
|
+
}
|
|
454
|
+
function groupSections(sections) {
|
|
455
|
+
// Group sections by topic keywords
|
|
456
|
+
const topics = new Map();
|
|
457
|
+
for (const s of sections) {
|
|
458
|
+
const words = s.toLowerCase().split(/\s+/);
|
|
459
|
+
const key = words.find(w => w.length > 4) || words[0] || "misc";
|
|
460
|
+
if (!topics.has(key))
|
|
461
|
+
topics.set(key, []);
|
|
462
|
+
topics.get(key).push(s);
|
|
463
|
+
}
|
|
464
|
+
return [...topics.entries()].map(([topic, secs]) => `${topic} (${secs.length} sections)`).slice(0, 5);
|
|
465
|
+
}
|
|
466
|
+
function findDeadLinks(content, projectRoot) {
|
|
467
|
+
const dead = [];
|
|
468
|
+
const linkMatches = content.match(/\[([^\]]+)\]\(([^)]+)\)/g) || [];
|
|
469
|
+
for (const link of linkMatches) {
|
|
470
|
+
const match = link.match(/\]\(([^)]+)\)/);
|
|
471
|
+
if (!match || match[1].startsWith("http") || match[1].startsWith("#"))
|
|
472
|
+
continue;
|
|
473
|
+
const target = join(projectRoot, match[1]);
|
|
474
|
+
if (!existsSync(target))
|
|
475
|
+
dead.push(match[1]);
|
|
476
|
+
}
|
|
477
|
+
return dead;
|
|
478
|
+
}
|
|
479
|
+
function loadManifest(projectRoot) {
|
|
480
|
+
const paths = [
|
|
481
|
+
join(projectRoot, ".jfl", "manifest.json"),
|
|
482
|
+
join(projectRoot, ".jfl", "template-manifest.json"),
|
|
483
|
+
];
|
|
484
|
+
for (const p of paths) {
|
|
485
|
+
if (existsSync(p)) {
|
|
486
|
+
try {
|
|
487
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
function checkMissingDocs(projectRoot, result) {
|
|
497
|
+
const expected = [
|
|
498
|
+
{ name: "VISION.md", purpose: "North star and product direction" },
|
|
499
|
+
{ name: "ROADMAP.md", purpose: "Current priorities and milestones" },
|
|
500
|
+
{ name: "ARCHITECTURE.md", purpose: "System design and service map" },
|
|
501
|
+
{ name: "CHANGELOG.md", purpose: "What shipped and when" },
|
|
502
|
+
];
|
|
503
|
+
const knowledgeDir = join(projectRoot, "knowledge");
|
|
504
|
+
for (const exp of expected) {
|
|
505
|
+
const paths = [
|
|
506
|
+
join(projectRoot, exp.name),
|
|
507
|
+
join(knowledgeDir, exp.name),
|
|
508
|
+
];
|
|
509
|
+
if (!paths.some(p => existsSync(p))) {
|
|
510
|
+
result.missingDocs.push(`${exp.name} — ${exp.purpose}`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
function checkMissingDocsForActivity(audit, insight, recs) {
|
|
515
|
+
for (const hotspot of insight.fileHotspots.slice(0, 5)) {
|
|
516
|
+
const dir = hotspot.path.split("/").slice(0, 2).join("/");
|
|
517
|
+
const hasDocs = audit.docs.some(d => d.relativePath.startsWith(dir));
|
|
518
|
+
if (!hasDocs && hotspot.touches > 10) {
|
|
519
|
+
recs.push({
|
|
520
|
+
type: "create",
|
|
521
|
+
target: `${dir}/README.md`,
|
|
522
|
+
rationale: `${hotspot.path} has ${hotspot.touches} touches across sessions but no documentation. Agents working here have no context.`,
|
|
523
|
+
priority: 2,
|
|
524
|
+
origin: "customer",
|
|
525
|
+
action: "Create a README explaining the purpose, key files, and conventions for this directory",
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
// ============================================================================
|
|
531
|
+
// Stratus-powered deep analysis
|
|
532
|
+
// ============================================================================
|
|
533
|
+
export function buildDocAuditPrompt(audit, insight) {
|
|
534
|
+
return `You are an expert at maintaining lean, effective workspace documentation for AI-assisted development.
|
|
535
|
+
|
|
536
|
+
## Context
|
|
537
|
+
Total docs: ${audit.totalDocs} (${audit.totalLines} lines, ${audit.totalTokens} tokens, ${(audit.totalBytes / 1024).toFixed(0)}KB)
|
|
538
|
+
Framework docs: ${audit.frameworkDocs.length} (${audit.frameworkDocs.reduce((s, d) => s + d.tokenEstimate, 0)} tokens)
|
|
539
|
+
Customer docs: ${audit.customerDocs.length} (${audit.customerDocs.reduce((s, d) => s + d.tokenEstimate, 0)} tokens)
|
|
540
|
+
Unreferenced docs: ${audit.unreferencedDocs.length} (${audit.unreferencedDocs.reduce((s, d) => s + d.tokenEstimate, 0)} tokens wasted)
|
|
541
|
+
|
|
542
|
+
## Framework Docs (from templates/skills — JFL manages these)
|
|
543
|
+
${audit.frameworkDocs.filter(d => d.issues.length > 0).slice(0, 10).map(d => `- ${d.relativePath}: ${d.lines} lines, ${d.tokenEstimate} tokens, refs=${d.referenceCount}, sections=[${d.sections.slice(0, 4).join(", ")}] ${d.issues.length > 0 ? "⚠ " + d.issues.join("; ") : ""}`).join("\n") || "All clean"}
|
|
544
|
+
|
|
545
|
+
## Customer Docs (PRDs, knowledge, roadmaps — user manages these)
|
|
546
|
+
${audit.customerDocs.filter(d => d.issues.length > 0).slice(0, 15).map(d => `- ${d.relativePath}: ${d.lines} lines, ${d.tokenEstimate} tokens, refs=${d.referenceCount}, age=${Math.floor((new Date().getTime() - d.lastModified.getTime()) / 86400000)}d, sections=[${d.sections.slice(0, 4).join(", ")}] ${d.issues.length > 0 ? "⚠ " + d.issues.join("; ") : ""}`).join("\n") || "All clean"}
|
|
547
|
+
|
|
548
|
+
## Unreferenced (never mentioned in ${insight.totalSessions} journal sessions)
|
|
549
|
+
${audit.unreferencedDocs.slice(0, 10).map(d => `- ${d.relativePath}: ${d.tokenEstimate} tokens, origin=${d.origin}, age=${Math.floor((new Date().getTime() - d.lastModified.getTime()) / 86400000)}d`).join("\n") || "None"}
|
|
550
|
+
|
|
551
|
+
## What agents actually work on (journal patterns)
|
|
552
|
+
${insight.commonPatterns.slice(0, 8).join("\n") || "No patterns"}
|
|
553
|
+
|
|
554
|
+
## Sessions: ${insight.totalSessions}, Entries: ${insight.totalEntries}
|
|
555
|
+
|
|
556
|
+
## Instructions
|
|
557
|
+
|
|
558
|
+
Give specific, actionable recommendations. For each:
|
|
559
|
+
1. **type**: "trim" | "update" | "create" | "archive" | "split" | "merge" | "refresh" | "dedupe"
|
|
560
|
+
2. **target**: file path
|
|
561
|
+
3. **rationale**: why, citing token costs and reference counts
|
|
562
|
+
4. **priority**: 1-3
|
|
563
|
+
5. **action**: exactly what to do (not generic "split into sections" — say which sections and why)
|
|
564
|
+
6. **origin**: "framework" or "customer"
|
|
565
|
+
7. **estimatedSavings**: token count saved
|
|
566
|
+
|
|
567
|
+
Key principle: "this doc costs N tokens/session and has 0 journal references" > "this doc is long"
|
|
568
|
+
|
|
569
|
+
Respond ONLY with valid JSON array. No markdown wrapping.`;
|
|
570
|
+
}
|
|
571
|
+
export async function getSmartDocRecommendations(projectRoot, insight) {
|
|
572
|
+
const audit = auditDocs(projectRoot, insight);
|
|
573
|
+
const prompt = buildDocAuditPrompt(audit, insight);
|
|
574
|
+
const apiKey = process.env.STRATUS_API_KEY;
|
|
575
|
+
const apiUrl = process.env.STRATUS_API_URL || "https://api.stratus.run/v1/chat/completions";
|
|
576
|
+
if (!apiKey)
|
|
577
|
+
return audit.recommendations;
|
|
578
|
+
try {
|
|
579
|
+
const response = await fetch(apiUrl, {
|
|
580
|
+
method: "POST",
|
|
581
|
+
headers: {
|
|
582
|
+
"Content-Type": "application/json",
|
|
583
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
584
|
+
},
|
|
585
|
+
body: JSON.stringify({
|
|
586
|
+
model: "stratus-x1ac-base-claude-haiku-4-5",
|
|
587
|
+
messages: [{ role: "user", content: prompt }],
|
|
588
|
+
max_tokens: 3000,
|
|
589
|
+
temperature: 0.3,
|
|
590
|
+
}),
|
|
591
|
+
});
|
|
592
|
+
if (!response.ok)
|
|
593
|
+
return audit.recommendations;
|
|
594
|
+
const data = await response.json();
|
|
595
|
+
const content = data.choices?.[0]?.message?.content || "";
|
|
596
|
+
const jsonStr = content.replace(/^```json?\n?/, "").replace(/\n?```$/, "").trim();
|
|
597
|
+
const smartRecs = JSON.parse(jsonStr);
|
|
598
|
+
// Merge: smart recs first, then any heuristic recs not covered
|
|
599
|
+
return [...smartRecs, ...audit.recommendations.filter(r => !smartRecs.some(s => s.target === r.target && s.type === r.type))];
|
|
600
|
+
}
|
|
601
|
+
catch {
|
|
602
|
+
return audit.recommendations;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
// ============================================================================
|
|
606
|
+
// File discovery
|
|
607
|
+
// ============================================================================
|
|
608
|
+
function findMarkdownFiles(dir, depth = 0) {
|
|
609
|
+
if (depth > 3)
|
|
610
|
+
return [];
|
|
611
|
+
const files = [];
|
|
612
|
+
const skip = new Set(["node_modules", ".git", ".jfl", "dist", "build", ".next", "__pycache__", "archive", "archived-docs"]);
|
|
613
|
+
try {
|
|
614
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
615
|
+
if (skip.has(entry.name))
|
|
616
|
+
continue;
|
|
617
|
+
const fullPath = join(dir, entry.name);
|
|
618
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
619
|
+
files.push(fullPath);
|
|
620
|
+
}
|
|
621
|
+
else if (entry.isDirectory()) {
|
|
622
|
+
files.push(...findMarkdownFiles(fullPath, depth + 1));
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
catch { /* permission errors */ }
|
|
627
|
+
return files;
|
|
628
|
+
}
|
|
629
|
+
//# sourceMappingURL=doc-auditor.js.map
|