jfl 0.4.3 → 0.5.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/README.md +15 -5
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +818 -39
- 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 +1218 -2
- 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/status.d.ts.map +1 -1
- package/dist/commands/status.js +22 -4
- package/dist/commands/status.js.map +1 -1
- 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-B6b867Pv.js +121 -0
- package/dist/dashboard-static/assets/index-Y4BrqxV-.css +1 -0
- package/dist/dashboard-static/index.html +2 -2
- package/dist/index.js +228 -62
- 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 +627 -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/policy-head.d.ts +25 -0
- package/dist/lib/policy-head.d.ts.map +1 -0
- package/dist/lib/policy-head.js +136 -0
- package/dist/lib/policy-head.js.map +1 -0
- 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/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 +151 -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/hud-tool.ts +145 -0
- package/packages/pi/extensions/index.ts +392 -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 +68 -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 +90 -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 +352 -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-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/.github/workflows/jfl-eval.yml +105 -8
- package/template/.github/workflows/jfl-review.yml +4 -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/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,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Journal Extension
|
|
3
|
+
*
|
|
4
|
+
* Detects git commits via tool_execution_end, prompts for journal entries,
|
|
5
|
+
* registers the /journal command with interactive type selection,
|
|
6
|
+
* shows themed journal stream in below-editor widget.
|
|
7
|
+
*
|
|
8
|
+
* @purpose Auto-journal detection + interactive /journal command + themed widget
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs"
|
|
12
|
+
import { join } from "path"
|
|
13
|
+
import { execSync } from "child_process"
|
|
14
|
+
import type { PiContext, PiTheme, JflConfig, AgentEndEvent, ToolExecutionEvent } from "./types.js"
|
|
15
|
+
import { getCurrentBranch } from "./session.js"
|
|
16
|
+
import { emitCustomEvent } from "./map-bridge.js"
|
|
17
|
+
|
|
18
|
+
let projectRoot = ""
|
|
19
|
+
|
|
20
|
+
interface JournalEntry {
|
|
21
|
+
v: number
|
|
22
|
+
ts: string
|
|
23
|
+
session: string
|
|
24
|
+
type: string
|
|
25
|
+
status: string
|
|
26
|
+
title: string
|
|
27
|
+
summary: string
|
|
28
|
+
detail?: string
|
|
29
|
+
files?: string[]
|
|
30
|
+
incomplete?: string[]
|
|
31
|
+
next?: string
|
|
32
|
+
learned?: string[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getJournalPath(root: string): string {
|
|
36
|
+
const branch = getCurrentBranch(root)
|
|
37
|
+
return join(root, ".jfl", "journal", `${branch}.jsonl`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function appendJournalEntry(root: string, entry: JournalEntry): void {
|
|
41
|
+
const journalPath = getJournalPath(root)
|
|
42
|
+
mkdirSync(join(root, ".jfl", "journal"), { recursive: true })
|
|
43
|
+
appendFileSync(journalPath, JSON.stringify(entry) + "\n")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readRecentEntries(root: string, count = 5): JournalEntry[] {
|
|
47
|
+
const journalPath = getJournalPath(root)
|
|
48
|
+
if (!existsSync(journalPath)) return []
|
|
49
|
+
try {
|
|
50
|
+
const lines = readFileSync(journalPath, "utf-8")
|
|
51
|
+
.split("\n")
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
.slice(-count)
|
|
54
|
+
return lines.map(l => JSON.parse(l) as JournalEntry)
|
|
55
|
+
} catch {
|
|
56
|
+
return []
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function hasJournalEntryForSession(root: string, sessionBranch: string): boolean {
|
|
61
|
+
const journalPath = join(root, ".jfl", "journal", `${sessionBranch}.jsonl`)
|
|
62
|
+
if (!existsSync(journalPath)) return false
|
|
63
|
+
const content = readFileSync(journalPath, "utf-8").trim()
|
|
64
|
+
return content.length > 0
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const TYPE_ICONS: Record<string, string> = {
|
|
68
|
+
feature: "✦",
|
|
69
|
+
fix: "✧",
|
|
70
|
+
decision: "◆",
|
|
71
|
+
discovery: "◇",
|
|
72
|
+
milestone: "★",
|
|
73
|
+
"session-end": "●",
|
|
74
|
+
spec: "□",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const TYPE_COLORS: Record<string, string> = {
|
|
78
|
+
feature: "success",
|
|
79
|
+
fix: "error",
|
|
80
|
+
decision: "warning",
|
|
81
|
+
discovery: "accent",
|
|
82
|
+
milestone: "warning",
|
|
83
|
+
"session-end": "dim",
|
|
84
|
+
spec: "muted",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function showRecentJournal(_ctx: PiContext): void {
|
|
88
|
+
// Widget removed — journal entries visible via /journal or Ctrl+Shift+J
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function setupJournal(ctx: PiContext, _config: JflConfig): Promise<void> {
|
|
92
|
+
projectRoot = ctx.session.projectRoot
|
|
93
|
+
|
|
94
|
+
showRecentJournal(ctx)
|
|
95
|
+
|
|
96
|
+
ctx.registerCommand({
|
|
97
|
+
name: "journal",
|
|
98
|
+
description: "Write a journal entry for the current session",
|
|
99
|
+
async handler(_args, ctx) {
|
|
100
|
+
if (ctx.ui.hasUI) {
|
|
101
|
+
const types = [
|
|
102
|
+
{ value: "feature" as const, label: "✦ Feature", description: "Something built or completed" },
|
|
103
|
+
{ value: "fix" as const, label: "✧ Fix", description: "Bug found and fixed" },
|
|
104
|
+
{ value: "decision" as const, label: "◆ Decision", description: "Choice made between options" },
|
|
105
|
+
{ value: "discovery" as const, label: "◇ Discovery", description: "Insight or learning" },
|
|
106
|
+
{ value: "milestone" as const, label: "★ Milestone", description: "Major goal reached" },
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
const type = await ctx.ui.select("Journal Entry Type", types)
|
|
110
|
+
if (!type) return
|
|
111
|
+
|
|
112
|
+
const title = await ctx.ui.input("Title", "What happened?")
|
|
113
|
+
if (!title?.trim()) return
|
|
114
|
+
|
|
115
|
+
const summary = await ctx.ui.input("Summary (2-3 sentences)", "Brief description")
|
|
116
|
+
|
|
117
|
+
const entry: JournalEntry = {
|
|
118
|
+
v: 1,
|
|
119
|
+
ts: new Date().toISOString(),
|
|
120
|
+
session: getCurrentBranch(projectRoot),
|
|
121
|
+
type,
|
|
122
|
+
status: "complete",
|
|
123
|
+
title: title.trim(),
|
|
124
|
+
summary: summary?.trim() ?? title.trim(),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
appendJournalEntry(projectRoot, entry)
|
|
128
|
+
await emitCustomEvent(ctx, "journal:entry", entry)
|
|
129
|
+
ctx.emit("journal:written", entry)
|
|
130
|
+
showRecentJournal(ctx)
|
|
131
|
+
ctx.ui.notify(`${TYPE_ICONS[type] ?? "·"} Journal: ${title.trim()}`, { level: "success" })
|
|
132
|
+
ctx.ui.setStatus("journal", undefined)
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Fallback: raw JSON input for non-interactive mode
|
|
137
|
+
const branch = getCurrentBranch(projectRoot)
|
|
138
|
+
const template = JSON.stringify({
|
|
139
|
+
v: 1,
|
|
140
|
+
ts: new Date().toISOString(),
|
|
141
|
+
session: branch,
|
|
142
|
+
type: "feature",
|
|
143
|
+
status: "complete",
|
|
144
|
+
title: "",
|
|
145
|
+
summary: "",
|
|
146
|
+
detail: "",
|
|
147
|
+
files: [],
|
|
148
|
+
}, null, 2)
|
|
149
|
+
|
|
150
|
+
const content = await ctx.ui.input("Journal Entry (paste JSON)", template)
|
|
151
|
+
if (!content?.trim()) return
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const entry = JSON.parse(content) as JournalEntry
|
|
155
|
+
appendJournalEntry(projectRoot, entry)
|
|
156
|
+
await emitCustomEvent(ctx, "journal:entry", entry)
|
|
157
|
+
ctx.emit("journal:written", entry)
|
|
158
|
+
showRecentJournal(ctx)
|
|
159
|
+
ctx.ui.notify("Journal entry saved", { level: "success" })
|
|
160
|
+
} catch {
|
|
161
|
+
ctx.ui.notify("Invalid JSON — entry not saved. Use /journal and paste valid JSON.", { level: "warn" })
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
ctx.on("map:journal:entry", () => showRecentJournal(ctx))
|
|
167
|
+
ctx.on("journal:written", () => showRecentJournal(ctx))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function onToolExecutionEnd(
|
|
171
|
+
ctx: PiContext,
|
|
172
|
+
event: ToolExecutionEvent
|
|
173
|
+
): Promise<void> {
|
|
174
|
+
const toolName = event.toolName ?? event.tool ?? ""
|
|
175
|
+
if (toolName.toLowerCase() !== "bash") return
|
|
176
|
+
|
|
177
|
+
const result = String(event.result ?? "")
|
|
178
|
+
const isGitCommit = /\[[\w/.-]+\s+[0-9a-f]{7,}\]/.test(result)
|
|
179
|
+
if (!isGitCommit) return
|
|
180
|
+
|
|
181
|
+
let commitMsg = ""
|
|
182
|
+
let commitFiles = ""
|
|
183
|
+
try {
|
|
184
|
+
commitMsg = execSync("git log -1 --pretty=%B", { cwd: projectRoot }).toString().trim()
|
|
185
|
+
commitFiles = execSync("git diff-tree --no-commit-id --name-only -r HEAD", { cwd: projectRoot })
|
|
186
|
+
.toString().trim()
|
|
187
|
+
} catch {}
|
|
188
|
+
|
|
189
|
+
ctx.emit("pi:git-commit-detected", { message: commitMsg, files: commitFiles })
|
|
190
|
+
|
|
191
|
+
ctx.ui.notify([
|
|
192
|
+
"Git commit detected — Ctrl+Shift+J for quick journal or /journal",
|
|
193
|
+
commitMsg ? `Commit: ${commitMsg.split("\n")[0]}` : "",
|
|
194
|
+
commitFiles ? `Files: ${commitFiles.split("\n").slice(0, 3).join(", ")}` : "",
|
|
195
|
+
].filter(Boolean).join("\n"), { level: "info" })
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function onJournalAgentEnd(
|
|
199
|
+
_ctx: PiContext,
|
|
200
|
+
_event: AgentEndEvent
|
|
201
|
+
): Promise<void> {
|
|
202
|
+
// Removed: "Journal entry recommended" nudge (noisy)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export async function checkJournalBeforeCompact(
|
|
206
|
+
ctx: PiContext
|
|
207
|
+
): Promise<{ cancel: true } | void> {
|
|
208
|
+
const branch = getCurrentBranch(projectRoot)
|
|
209
|
+
if (!hasJournalEntryForSession(projectRoot, branch)) {
|
|
210
|
+
if (ctx.ui.hasUI) {
|
|
211
|
+
const ok = await ctx.ui.confirm(
|
|
212
|
+
"No Journal Entry",
|
|
213
|
+
"No journal entry for this session. Compacting without one loses context.\n\nContinue anyway?"
|
|
214
|
+
)
|
|
215
|
+
if (!ok) return ctx.cancel()
|
|
216
|
+
} else {
|
|
217
|
+
ctx.ui.notify(
|
|
218
|
+
"No journal entry for this session. Write one with /journal before compacting.",
|
|
219
|
+
{ level: "warn" }
|
|
220
|
+
)
|
|
221
|
+
return ctx.cancel()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MAP Event Bridge Extension
|
|
3
|
+
*
|
|
4
|
+
* Translates Pi lifecycle events → MAP event bus (Context Hub HTTP).
|
|
5
|
+
* Also subscribes to hub SSE stream and re-emits as Pi custom events.
|
|
6
|
+
* Enforces scope filtering from .jfl/config.json context_scope.
|
|
7
|
+
*
|
|
8
|
+
* @purpose Pi lifecycle → MAP bus bridge with scope enforcement
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFileSync, existsSync } from "fs"
|
|
12
|
+
import { join } from "path"
|
|
13
|
+
import type { PiContext, JflConfig, AgentEndEvent, ToolExecutionEvent } from "./types.js"
|
|
14
|
+
|
|
15
|
+
interface MAPEvent {
|
|
16
|
+
type: string
|
|
17
|
+
source: string
|
|
18
|
+
data?: unknown
|
|
19
|
+
ts?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface ContextScope {
|
|
23
|
+
produces?: string[]
|
|
24
|
+
consumes?: string[]
|
|
25
|
+
denied?: string[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let hubUrl = "http://localhost:4242"
|
|
29
|
+
let authToken: string | null = null
|
|
30
|
+
let scope: ContextScope = {}
|
|
31
|
+
let sseAbort: AbortController | null = null
|
|
32
|
+
|
|
33
|
+
const PI_TO_MAP: Record<string, string> = {
|
|
34
|
+
"hook:session-start": "hook:session-start",
|
|
35
|
+
"hook:session-end": "hook:session-end",
|
|
36
|
+
"task:started": "task:started",
|
|
37
|
+
"task:completed": "task:completed",
|
|
38
|
+
"hook:tool-use": "hook:tool-use",
|
|
39
|
+
"hook:tool-result": "hook:tool-result",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readToken(root: string): string | null {
|
|
43
|
+
const tokenPath = join(root, ".jfl", "context-hub.token")
|
|
44
|
+
if (existsSync(tokenPath)) {
|
|
45
|
+
return readFileSync(tokenPath, "utf-8").trim()
|
|
46
|
+
}
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function matchPattern(pattern: string, value: string): boolean {
|
|
51
|
+
if (pattern === "*") return true
|
|
52
|
+
if (pattern === value) return true
|
|
53
|
+
if (pattern.includes("*")) {
|
|
54
|
+
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$")
|
|
55
|
+
return regex.test(value)
|
|
56
|
+
}
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isEventAllowedToEmit(eventType: string, src: ContextScope): boolean {
|
|
61
|
+
if (!src.produces || src.produces.length === 0) return true
|
|
62
|
+
return src.produces.some(p => matchPattern(p, eventType))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isEventDenied(eventType: string, src: ContextScope): boolean {
|
|
66
|
+
if (!src.denied || src.denied.length === 0) return false
|
|
67
|
+
return src.denied.some(d => matchPattern(d, eventType))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function postToHub(event: MAPEvent): Promise<void> {
|
|
71
|
+
if (isEventDenied(event.type, scope)) return
|
|
72
|
+
if (!isEventAllowedToEmit(event.type, scope)) return
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const response = await fetch(`${hubUrl}/api/events`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
80
|
+
},
|
|
81
|
+
body: JSON.stringify(event),
|
|
82
|
+
})
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
// Silently ignore hub connectivity issues — it may not be running
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
// Hub not available — non-fatal
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function subscribeToHubSSE(ctx: PiContext): Promise<void> {
|
|
92
|
+
sseAbort = new AbortController()
|
|
93
|
+
|
|
94
|
+
const consumesPatterns = scope.consumes ?? ["*"]
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const patternsParam = consumesPatterns.join(",")
|
|
98
|
+
const url = `${hubUrl}/api/events/stream?pattern=${encodeURIComponent(patternsParam)}`
|
|
99
|
+
|
|
100
|
+
const resp = await fetch(url, {
|
|
101
|
+
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},
|
|
102
|
+
signal: sseAbort.signal,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
if (!resp.ok || !resp.body) return
|
|
106
|
+
|
|
107
|
+
const reader = resp.body.getReader()
|
|
108
|
+
const decoder = new TextDecoder()
|
|
109
|
+
let buffer = ""
|
|
110
|
+
|
|
111
|
+
while (true) {
|
|
112
|
+
const { done, value } = await reader.read()
|
|
113
|
+
if (done) break
|
|
114
|
+
|
|
115
|
+
buffer += decoder.decode(value, { stream: true })
|
|
116
|
+
const lines = buffer.split("\n")
|
|
117
|
+
buffer = lines.pop() ?? ""
|
|
118
|
+
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
if (!line.startsWith("data: ")) continue
|
|
121
|
+
try {
|
|
122
|
+
const event = JSON.parse(line.slice(6)) as MAPEvent
|
|
123
|
+
if (isEventDenied(event.type, scope)) continue
|
|
124
|
+
ctx.emit(`map:${event.type}`, event)
|
|
125
|
+
} catch {}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch (err: unknown) {
|
|
129
|
+
if ((err as { name?: string }).name === "AbortError") return
|
|
130
|
+
// Silently ignore — Context Hub may not be running
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function setupMapBridge(ctx: PiContext, config: JflConfig): Promise<void> {
|
|
135
|
+
const root = ctx.session.projectRoot
|
|
136
|
+
|
|
137
|
+
authToken = readToken(root)
|
|
138
|
+
scope = config.context_scope ?? {}
|
|
139
|
+
|
|
140
|
+
const portFile = join(root, ".jfl", "context-hub.port")
|
|
141
|
+
if (existsSync(portFile)) {
|
|
142
|
+
const port = readFileSync(portFile, "utf-8").trim()
|
|
143
|
+
if (port) hubUrl = `http://localhost:${port}`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
ctx.on("hook:session-start", (data) => postToHub({ type: "hook:session-start", source: "pi-session", data, ts: new Date().toISOString() }))
|
|
147
|
+
ctx.on("hook:session-end", (data) => postToHub({ type: "hook:session-end", source: "pi-session", data, ts: new Date().toISOString() }))
|
|
148
|
+
|
|
149
|
+
subscribeToHubSSE(ctx).catch(() => {})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function onMapBridgeShutdown(_ctx: PiContext): Promise<void> {
|
|
153
|
+
sseAbort?.abort()
|
|
154
|
+
sseAbort = null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function emitAgentStart(ctx: PiContext, event: unknown): Promise<void> {
|
|
158
|
+
await postToHub({ type: "task:started", source: `pi-agent:${ctx.session.id}`, data: event, ts: new Date().toISOString() })
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function emitAgentEnd(ctx: PiContext, event: AgentEndEvent): Promise<void> {
|
|
162
|
+
await postToHub({ type: "task:completed", source: `pi-agent:${ctx.session.id}`, data: event, ts: new Date().toISOString() })
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function onMapToolEnd(ctx: PiContext, event: ToolExecutionEvent): Promise<void> {
|
|
166
|
+
await postToHub({
|
|
167
|
+
type: "hook:tool-result",
|
|
168
|
+
source: `pi-agent:${ctx.session.id}`,
|
|
169
|
+
data: { tool: event.toolName ?? event.tool, duration: event.duration },
|
|
170
|
+
ts: new Date().toISOString(),
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export async function emitCustomEvent(ctx: PiContext, type: string, data: unknown): Promise<void> {
|
|
175
|
+
await postToHub({ type, source: `pi:${ctx.session.id}`, data, ts: new Date().toISOString() })
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { hubUrl, authToken }
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Tool Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers jfl_memory_search tool with custom TUI rendering.
|
|
5
|
+
* Queries Context Hub memory API and renders results with
|
|
6
|
+
* type-colored headers and collapsible sections.
|
|
7
|
+
*
|
|
8
|
+
* @purpose jfl_memory_search tool — themed semantic memory search results
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PiContext } from "./types.js"
|
|
12
|
+
import { hubUrl, authToken } from "./map-bridge.js"
|
|
13
|
+
import { memoryRenderCall, memoryRenderResult } from "./tool-renderers.js"
|
|
14
|
+
|
|
15
|
+
export function setupMemoryTool(ctx: PiContext): void {
|
|
16
|
+
ctx.registerTool({
|
|
17
|
+
name: "jfl_memory_search",
|
|
18
|
+
description: "Search JFL project memory — find past decisions, learnings, and patterns across all sessions",
|
|
19
|
+
promptSnippet: "Search project memory for decisions, learnings, and session history",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
query: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Search query to find relevant memories",
|
|
26
|
+
},
|
|
27
|
+
limit: {
|
|
28
|
+
type: "number",
|
|
29
|
+
description: "Maximum results (default: 10)",
|
|
30
|
+
},
|
|
31
|
+
type: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Filter by entry type: feature, fix, decision, discovery, milestone, all",
|
|
34
|
+
enum: ["feature", "fix", "decision", "discovery", "milestone", "all"],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ["query"],
|
|
38
|
+
},
|
|
39
|
+
async handler(input) {
|
|
40
|
+
const { query, limit, type } = input as { query: string; limit?: number; type?: string }
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const params = new URLSearchParams({ query, limit: String(limit ?? 10) })
|
|
44
|
+
if (type && type !== "all") params.set("type", type)
|
|
45
|
+
|
|
46
|
+
const resp = await fetch(`${hubUrl}/api/memory/search?${params}`, {
|
|
47
|
+
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
if (!resp.ok) return "Memory search unavailable."
|
|
51
|
+
const data = await resp.json() as { results?: Array<{ content: string; title?: string; ts?: string; type?: string }> }
|
|
52
|
+
|
|
53
|
+
if (!data.results?.length) return "No memories found."
|
|
54
|
+
|
|
55
|
+
return data.results
|
|
56
|
+
.map(r => {
|
|
57
|
+
const header = [r.type && `[${r.type}]`, r.title].filter(Boolean).join(" ")
|
|
58
|
+
return [header, r.content].filter(Boolean).join("\n")
|
|
59
|
+
})
|
|
60
|
+
.join("\n\n---\n\n")
|
|
61
|
+
} catch {
|
|
62
|
+
return "Memory search unavailable — Context Hub may not be running."
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
renderCall: memoryRenderCall,
|
|
66
|
+
renderResult: memoryRenderResult,
|
|
67
|
+
})
|
|
68
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Notifications Extension
|
|
3
|
+
*
|
|
4
|
+
* Sends terminal notifications (OSC 777/99) when:
|
|
5
|
+
* - Agent finishes a long task (>10s)
|
|
6
|
+
* - Journal entry is recommended
|
|
7
|
+
* - Eval score changes significantly
|
|
8
|
+
*
|
|
9
|
+
* Supports Ghostty, iTerm2, WezTerm, Kitty, Windows Terminal.
|
|
10
|
+
*
|
|
11
|
+
* @purpose Terminal-native notifications for key JFL events
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { PiContext, JflConfig } from "./types.js"
|
|
15
|
+
|
|
16
|
+
let enabled = true
|
|
17
|
+
let agentStartTime = 0
|
|
18
|
+
const LONG_TASK_THRESHOLD_MS = 10000
|
|
19
|
+
|
|
20
|
+
function notifyOSC777(title: string, body: string): void {
|
|
21
|
+
process.stdout.write(`\x1b]777;notify;${title};${body}\x07`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function notifyOSC99(title: string, body: string): void {
|
|
25
|
+
process.stdout.write(`\x1b]99;i=1:d=0;${title}\x1b\\`)
|
|
26
|
+
process.stdout.write(`\x1b]99;i=1:p=body;${body}\x1b\\`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function notify(title: string, body: string): void {
|
|
30
|
+
if (!enabled) return
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
if (process.env.KITTY_WINDOW_ID) {
|
|
34
|
+
notifyOSC99(title, body)
|
|
35
|
+
} else {
|
|
36
|
+
notifyOSC777(title, body)
|
|
37
|
+
}
|
|
38
|
+
} catch {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function setupNotifications(ctx: PiContext, config: JflConfig): void {
|
|
42
|
+
if (config.pi?.disable_notifications) {
|
|
43
|
+
enabled = false
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
ctx.on("agent:start", () => {
|
|
48
|
+
agentStartTime = Date.now()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
ctx.on("agent:end", (data: any) => {
|
|
52
|
+
const elapsed = Date.now() - agentStartTime
|
|
53
|
+
if (elapsed > LONG_TASK_THRESHOLD_MS) {
|
|
54
|
+
const seconds = Math.floor(elapsed / 1000)
|
|
55
|
+
const reason = data?.exitReason ?? "done"
|
|
56
|
+
notify("JFL", `Agent finished (${seconds}s) — ${reason}`)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
ctx.on("journal:written", (data: any) => {
|
|
61
|
+
const title = data?.title ?? "entry"
|
|
62
|
+
notify("JFL Journal", title)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
ctx.registerCommand({
|
|
66
|
+
name: "notify",
|
|
67
|
+
description: "Toggle native terminal notifications",
|
|
68
|
+
async handler(_args, ctx) {
|
|
69
|
+
enabled = !enabled
|
|
70
|
+
ctx.ui.notify(`Notifications ${enabled ? "enabled" : "disabled"}`, { level: "info" })
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
}
|