@a-company/paradigm 5.34.0 → 5.37.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/{accept-orchestration-MIRBLRUJ.js → accept-orchestration-36AP7HTX.js} +1 -1
- package/dist/{add-P76GEMGF.js → add-FGKNJS3F.js} +1 -1
- package/dist/agent-E7LDKJ4O.js +33 -0
- package/dist/{agent-loader-5255KNM7.js → agent-loader-2HXKVL6J.js} +1 -1
- package/dist/{agent-loader-A5FMBAFJ.js → agent-loader-XS6LIMUG.js} +1 -1
- package/dist/{agent-state-KSQ3S7OB.js → agent-state-L7LCPRC3.js} +1 -1
- package/dist/{agents-suggest-HYTFMQD3.js → agents-suggest-Y5D6AALG.js} +1 -1
- package/dist/{aggregate-W66DM3GA.js → aggregate-OZJRRAQR.js} +1 -1
- package/dist/ambient-4NSPAQDJ.js +35 -0
- package/dist/{assess-UFPYEJKP.js → assess-AMPVSWK7.js} +1 -1
- package/dist/{auto-RHJXOZFL.js → auto-A7VUHCUC.js} +1 -1
- package/dist/{beacon-5QVYV5DF.js → beacon-YBLUUTYY.js} +1 -1
- package/dist/{calibration-OLJYB5HN.js → calibration-FQ4YVOE4.js} +1 -1
- package/dist/{check-THVGY4R5.js → check-46QL3KMQ.js} +1 -1
- package/dist/{chunk-AGSUX2GJ.js → chunk-3OMJI5TT.js} +2 -2
- package/dist/chunk-3QMRDN65.js +29 -0
- package/dist/{chunk-QNZEG7IT.js → chunk-3XGNXXCT.js} +1 -1
- package/dist/{chunk-VG7FN2TU.js → chunk-4W5TBL3O.js} +1 -1
- package/dist/{chunk-UDUHSHO4.js → chunk-5YHR77AL.js} +1 -1
- package/dist/chunk-6PP2RPIZ.js +3 -0
- package/dist/{chunk-VCKKJDLP.js → chunk-6QKCUEEY.js} +1 -1
- package/dist/{chunk-JBDMCRPP.js → chunk-77WX6HGV.js} +1 -1
- package/dist/{chunk-A7KFOJ2F.js → chunk-7PB7AXQE.js} +1 -1
- package/dist/chunk-7SGNNVE5.js +3 -0
- package/dist/{chunk-WS2N27RX.js → chunk-7YTAA6XA.js} +1 -1
- package/dist/chunk-BCOPNVPY.js +11 -0
- package/dist/chunk-BRHQJLTG.js +2 -0
- package/dist/{chunk-W5IWDW4Y.js → chunk-DG3VCY43.js} +1 -1
- package/dist/{chunk-HMQ5BHP2.js → chunk-DOCDDDTD.js} +10 -10
- package/dist/chunk-DSYEGRQ2.js +3 -0
- package/dist/chunk-EMMMBAID.js +2 -0
- package/dist/chunk-F5BSUC2L.js +3 -0
- package/dist/chunk-GE3GQALR.js +2 -0
- package/dist/chunk-IW5K3RNR.js +8 -0
- package/dist/chunk-JIF7OSGH.js +8 -0
- package/dist/{chunk-HPAHK4AJ.js → chunk-JUOOVKK6.js} +1 -1
- package/dist/chunk-NFQLONFY.js +3 -0
- package/dist/chunk-OVDYPOHR.js +2 -0
- package/dist/{chunk-33LKBMVK.js → chunk-RLJ5K3J5.js} +1 -1
- package/dist/{chunk-HXGYVS2N.js → chunk-RN35IVA2.js} +1 -1
- package/dist/{chunk-ODVKPZZ4.js → chunk-W6WVJLHO.js} +1 -1
- package/dist/chunk-X54WXWCX.js +111 -0
- package/dist/chunk-XHJ27CER.js +2 -0
- package/dist/{chunk-32RBX5YV.js → chunk-XNB4TZTD.js} +1 -1
- package/dist/chunk-YG5G5GEQ.js +456 -0
- package/dist/chunk-Z72SDTBJ.js +3 -0
- package/dist/{claude-4LR3LJQZ.js → claude-OX54QSLC.js} +1 -1
- package/dist/{claude-cli-UP6HGH7C.js → claude-cli-FHLJQVJC.js} +1 -1
- package/dist/{claude-code-RLJ4GX77.js → claude-code-GVGU3A3B.js} +1 -1
- package/dist/{claude-code-teams-R37HJY3Y.js → claude-code-teams-ZRHPTGPP.js} +1 -1
- package/dist/{compliance-Q676YALK.js → compliance-PHSPVYK2.js} +3 -3
- package/dist/{compliance-health-JNP3P35P.js → compliance-health-HCZTJDN7.js} +1 -1
- package/dist/{conductor-Y5IXELTL.js → conductor-LYBMM66Z.js} +1 -1
- package/dist/{config-schema-GUQY2QN7.js → config-schema-URJW6UZH.js} +1 -1
- package/dist/{constellation-CG7C4WFE.js → constellation-PX3ZKMWQ.js} +1 -1
- package/dist/{context-audit-XRPT3OU2.js → context-audit-APFKELFT.js} +2 -2
- package/dist/{cost-IDNVMAEV.js → cost-B5SAHPOJ.js} +1 -1
- package/dist/{cost-PK4KIF7R.js → cost-MMWUDGZC.js} +1 -1
- package/dist/{cursor-cli-QKF7Z6M2.js → cursor-cli-Q2HLQ5TE.js} +1 -1
- package/dist/{cursorrules-U5O4G5T4.js → cursorrules-3BW6K6D5.js} +1 -1
- package/dist/{decision-loader-2XPZE4EZ.js → decision-loader-4KMQVAXZ.js} +1 -1
- package/dist/{delete-P5VULXR4.js → delete-7PQZUERZ.js} +1 -1
- package/dist/{diff-QHQWLM3L.js → diff-F2HUO2H3.js} +1 -1
- package/dist/{discipline-H7LDI6NT.js → discipline-ARFFIXQL.js} +1 -1
- package/dist/{dist-W3XCATBJ.js → dist-5IUWRFG6.js} +1 -1
- package/dist/{dist-KGRCLBJP-2QAPFYNF.js → dist-KGRCLBJP-R5CCPPXN.js} +1 -1
- package/dist/{dist-3ZCH25SG.js → dist-MRZDZ5SX.js} +1 -1
- package/dist/{dist-VGFSP3XM.js → dist-OKM6BXTH.js} +1 -1
- package/dist/{dist-VXCZWVVJ.js → dist-VWC6FA46.js} +1 -1
- package/dist/dist-YUXXIXB3.js +3 -0
- package/dist/{docs-EDQ2STFK.js → docs-6WOQILZS.js} +1 -1
- package/dist/{docs-5BX2YWYK.js → docs-BI2DO7B2.js} +2 -2
- package/dist/doctor-JLTCBMS4.js +2 -0
- package/dist/{drift-ILZE5BFJ.js → drift-6QPDKKUO.js} +1 -1
- package/dist/{echo-UPTQUEDU.js → echo-3JJDKCNF.js} +1 -1
- package/dist/{edit-GUU3HBVW.js → edit-PLCGL5OV.js} +1 -1
- package/dist/{enforcement-BEGPQIUN.js → enforcement-5MHSQAXE.js} +1 -1
- package/dist/{enforcement-46XWPNSA.js → enforcement-IWABOHMY.js} +1 -1
- package/dist/{event-Y3VXC2RV.js → event-5J3GBWKT.js} +1 -1
- package/dist/{explain-files-3GPZUETV.js → explain-files-LPHTJL4N.js} +1 -1
- package/dist/{export-CV5KCTPS.js → export-NXUFTFPW.js} +1 -1
- package/dist/{flow-POQP27WA.js → flow-IT2IVXXT.js} +1 -1
- package/dist/{gap-narrator-NTXLUI7I.js → gap-narrator-DVXPWNFN.js} +1 -1
- package/dist/{global-C44FW4G2.js → global-J2VTYKCC.js} +1 -1
- package/dist/{graduate-3BBSC27A.js → graduate-N2HF4JT6.js} +1 -1
- package/dist/graph-VLMP6DW2.js +2 -0
- package/dist/{graph-server-COZR5C3Z.js → graph-server-TBHHBFOM.js} +1 -1
- package/dist/{habits-GICVMTJL.js → habits-JTMWGVPH.js} +3 -3
- package/dist/{history-UW454SDP.js → history-FHS7EC3Z.js} +1 -1
- package/dist/{hooks-BNWRGACA.js → hooks-BL6CXRVK.js} +1 -1
- package/dist/index.js +9 -9
- package/dist/init-ZS7RAR7L.js +2 -0
- package/dist/{integrity-UYDOOJDP.js → integrity-UBMZCB77.js} +1 -1
- package/dist/{integrity-checker-DHGMZQDG.js → integrity-checker-VSR3ITBL.js} +1 -1
- package/dist/journal-loader-EELDB4P2.js +2 -0
- package/dist/{lint-IGKE6UPS.js → lint-KQQ2RMSJ.js} +1 -1
- package/dist/{list-5IUGP3ZB.js → list-37UCWCOQ.js} +1 -1
- package/dist/{list-YKIQNKGB.js → list-6WY4CFUR.js} +1 -1
- package/dist/lore-loader-CP5RUJ4A.js +2 -0
- package/dist/{lore-loader-XY5MZRR2.js → lore-loader-PBUDKXAJ.js} +1 -1
- package/dist/{lore-server-FC2GMDLT.js → lore-server-A3KKZLSY.js} +1 -1
- package/dist/{manual-RXSPSFLL.js → manual-HKI6OXB4.js} +1 -1
- package/dist/mcp.js +17 -449
- package/dist/{migrate-YQG2FG3J.js → migrate-W3KCXLDS.js} +2 -2
- package/dist/{migrate-assessments-GEI5WMI2.js → migrate-assessments-D2TOBJ5V.js} +1 -1
- package/dist/{model-discovery-HMB3YI4L.js → model-discovery-TWX4A4YD.js} +1 -1
- package/dist/{nomination-engine-W6QTQX2P.js → nomination-engine-A24774W4.js} +1 -1
- package/dist/{notebook-PE3JSYZI.js → notebook-LXJ2LHUA.js} +1 -1
- package/dist/notebook-loader-CF52PNZC.js +2 -0
- package/dist/{orchestrate-7CJWHLBA.js → orchestrate-WFCNV2II.js} +1 -1
- package/dist/{peers-P2KXU7ZK.js → peers-7TPZTKH7.js} +1 -1
- package/dist/{persona-STQWZH5P.js → persona-UGTCFEGT.js} +1 -1
- package/dist/{pipeline-MZUITRVN.js → pipeline-7PZ6ILWX.js} +1 -1
- package/dist/{platform-server-G6MJIAJS.js → platform-server-YIBX4YDJ.js} +2 -2
- package/dist/{plugin-update-checker-M7PW434O.js → plugin-update-checker-2EM4K45U.js} +1 -1
- package/dist/{portal-check-Z3OCQEQR.js → portal-check-YSDJRZUR.js} +1 -1
- package/dist/{portal-compliance-4MG5F2GI.js → portal-compliance-OBPK2IR5.js} +1 -1
- package/dist/{probe-5L5BQDGE.js → probe-WKXR3IN4.js} +1 -1
- package/dist/{project-type-AGO6VUKF.js → project-type-MRBJAKC7.js} +1 -1
- package/dist/{promote-NJQDZBZA.js → promote-VHBA56KW.js} +2 -2
- package/dist/{providers-TBPOE4DI.js → providers-RX7SBLHZ.js} +1 -1
- package/dist/{quiz-FE5UGAY2.js → quiz-3SQNPRJ3.js} +1 -1
- package/dist/{record-YXPB34MY.js → record-7QJPZZP7.js} +1 -1
- package/dist/registry-LR5QACRK.js +20 -0
- package/dist/reindex-F7EV3Z34.js +2 -0
- package/dist/{remember-MJRNTXYS.js → remember-SFGBTTEE.js} +1 -1
- package/dist/{retag-N5XF3KXP.js → retag-GFXUYP7S.js} +1 -1
- package/dist/{review-6UAH6V3R.js → review-6KKZWV3A.js} +1 -1
- package/dist/{review-77QI6VOC.js → review-GEBSYOZB.js} +1 -1
- package/dist/{ripple-ZGDITCGB.js → ripple-4F5ZCXS4.js} +1 -1
- package/dist/{roster-TA2GFDR7.js → roster-RI3UC2YI.js} +1 -1
- package/dist/scaffold-WA4L2K7J.js +18 -0
- package/dist/{scopes-commands-3V5G6NYV.js → scopes-commands-5FFIUDRC.js} +1 -1
- package/dist/{sentinel-HYAZ3CO5.js → sentinel-37ZEEWT7.js} +2 -2
- package/dist/{sentinel-bridge-VR357PKL.js → sentinel-bridge-EZGFRVFH.js} +1 -1
- package/dist/{serve-L52ZUTU6.js → serve-2BXDL35A.js} +2 -2
- package/dist/{serve-ZJ3EXVA5.js → serve-2LSTQFFQ.js} +2 -2
- package/dist/{serve-OY6XYL7F.js → serve-5JME5QEM.js} +2 -2
- package/dist/{server-4YNUIK4W.js → server-AIXFROYL.js} +1 -1
- package/dist/{server-2MNROHF6.js → server-XLHIYDTZ.js} +1 -1
- package/dist/session-tracker-VSFRNFRL.js +2 -0
- package/dist/{session-work-log-SLAPEP3M.js → session-work-log-6GKGUQ5C.js} +1 -1
- package/dist/{session-work-log-5UJTJJ22.js → session-work-log-UYMIWWOX.js} +1 -1
- package/dist/{setup-KPIMRZ4Q.js → setup-F2N4LUR7.js} +1 -1
- package/dist/{setup-3F5IK7MO.js → setup-ZM4JFV5D.js} +2 -2
- package/dist/{shift-IKTWYSEQ.js → shift-DDYVQJ75.js} +5 -5
- package/dist/{show-PJ5LFLIL.js → show-CZLVYLM5.js} +1 -1
- package/dist/{show-BOAVWZPZ.js → show-RFOIR2GQ.js} +1 -1
- package/dist/{snapshot-L2G56RPL.js → snapshot-6N564OUJ.js} +1 -1
- package/dist/{spawn-7TCAMD6H.js → spawn-HYARN3RL.js} +1 -1
- package/dist/{status-A37ECYNJ.js → status-CUG3PKGC.js} +1 -1
- package/dist/{status-77M3SDIF.js → status-WBJ6D7BD.js} +1 -1
- package/dist/{summary-ZJLQ6KHB.js → summary-2AM4QVPW.js} +1 -1
- package/dist/{sweep-HU74OPVW.js → sweep-WHDT7ENV.js} +1 -1
- package/dist/{switch-CTW4PDGI.js → switch-HBGIFNF6.js} +1 -1
- package/dist/{symphony-IS5TYPXY.js → symphony-CWKKMFAS.js} +25 -25
- package/dist/symphony-VTHVTE57.js +2 -0
- package/dist/symphony-loader-RYFZOQJS.js +2 -0
- package/dist/{symphony-peers-X5NGWXFP.js → symphony-peers-ISJPKX7W.js} +1 -1
- package/dist/{symphony-peers-U4KHMKGI.js → symphony-peers-LWBUQ3T4.js} +1 -1
- package/dist/symphony-relay-L3BY6RGM.js +3 -0
- package/dist/sync-WIFD7UCL.js +2 -0
- package/dist/{sync-llms-HL5PPW3M.js → sync-llms-MZ3RQWFX.js} +1 -1
- package/dist/{task-loader-NZFDTUQ5.js → task-loader-EU7JLTR3.js} +1 -1
- package/dist/team-C3PWO7XL.js +2 -0
- package/dist/{test-BQJMS4Y2.js → test-6MUL4EXS.js} +1 -1
- package/dist/{thread-HFXK65D4.js → thread-K6UHDIUW.js} +1 -1
- package/dist/{timeline-K3ZFKJ3R.js → timeline-S26CQWHT.js} +1 -1
- package/dist/tools-4WKLLDFU.js +2 -0
- package/dist/{triage-FCWOZASE.js → triage-YF6WYZY4.js} +1 -1
- package/dist/{tutorial-UC6YQMNN.js → tutorial-UEBX7Z2G.js} +1 -1
- package/dist/{university-FJ7OCOA3.js → university-UMT7PAKE.js} +1 -1
- package/dist/university-content/courses/para-201.json +5 -5
- package/dist/university-content/courses/para-301.json +10 -10
- package/dist/university-content/courses/para-401.json +3 -3
- package/dist/university-content/courses/para-501.json +5 -5
- package/dist/university-content/courses/para-601.json +1 -1
- package/dist/university-content/plsat/v2.0.json +7 -7
- package/dist/university-content/plsat/v3.0.json +9 -9
- package/dist/university-content/reference.json +4 -4
- package/dist/university-ui/assets/{index-DmiLQehB.js → index-CecQrfSn.js} +2 -2
- package/dist/university-ui/assets/{index-DmiLQehB.js.map → index-CecQrfSn.js.map} +1 -1
- package/dist/university-ui/index.html +1 -1
- package/dist/{upgrade-B4IOLZYK.js → upgrade-USW7YJEX.js} +1 -1
- package/dist/{validate-LSCDOLBO.js → validate-2PZTNYSS.js} +1 -1
- package/dist/{validate-VZXTJHGO.js → validate-KW3YFGTV.js} +1 -1
- package/dist/{validate-C6SMKGYD.js → validate-VZGBVTPM.js} +1 -1
- package/dist/{watch-LRM5XD46.js → watch-HL3ZOALL.js} +1 -1
- package/dist/{watch-PZCCUP6K.js → watch-KQU3S7KE.js} +1 -1
- package/dist/{wisdom-XZ3QKPNP.js → wisdom-UU7HOE3M.js} +1 -1
- package/dist/{work-log-loader-DL5GZ2BQ.js → work-log-loader-J27XSFCE.js} +1 -1
- package/dist/workspace-CE6LNXVI.js +2 -0
- package/package.json +5 -1
- package/templates/paradigm/specs/context-tracking.md +4 -4
- package/dist/agent-UUTYOFTH.js +0 -33
- package/dist/ambient-2JZTNXUL.js +0 -35
- package/dist/chunk-2Q7RGCJH.js +0 -3
- package/dist/chunk-5TAVYPOV.js +0 -2
- package/dist/chunk-73R63P7K.js +0 -2
- package/dist/chunk-C7ZCCKJT.js +0 -3
- package/dist/chunk-CUOEZAVL.js +0 -8
- package/dist/chunk-EAZ3EMOZ.js +0 -29
- package/dist/chunk-LKFBDUCV.js +0 -11
- package/dist/chunk-QGZRM6ZB.js +0 -2
- package/dist/chunk-S7K7UPXL.js +0 -3
- package/dist/chunk-TXBSTT64.js +0 -111
- package/dist/chunk-TZZNHUAR.js +0 -2
- package/dist/chunk-UHQLYIRI.js +0 -3
- package/dist/chunk-VZLGBGU3.js +0 -8
- package/dist/doctor-R4UGMR5N.js +0 -2
- package/dist/graph-CNDE5TAT.js +0 -2
- package/dist/init-24MAQJFM.js +0 -2
- package/dist/journal-loader-GLH7XFTK.js +0 -2
- package/dist/lore-loader-RVQI5GXL.js +0 -2
- package/dist/notebook-loader-CENTDDUJ.js +0 -2
- package/dist/reindex-2MRCAIZG.js +0 -2
- package/dist/session-tracker-WSTRV7UP.js +0 -2
- package/dist/symphony-43N4R6C2.js +0 -2
- package/dist/symphony-loader-XJT43FOS.js +0 -2
- package/dist/symphony-relay-CIMRXQHI.js +0 -3
- package/dist/sync-QRDSFETO.js +0 -2
- package/dist/team-WIJVWLII.js +0 -2
- package/dist/workspace-2ODL5WLY.js +0 -2
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
Found ${i
|
|
2
|
+
import {d,k,j,h,c,e as e$1,f,s,m,g,q as q$1,v,w,i,r,o,p as p$1,u,t,z,x,C,y,A,B}from'./chunk-JIF7OSGH.js';import'./chunk-7SWEOPWF.js';import'./chunk-DSYEGRQ2.js';import'./chunk-XHJ27CER.js';import e from'chalk';import*as b from'path';import*as p from'fs';import*as q from'os';async function te(s){let o=process.cwd();if(s.remote){await Y(o,s.remote);return}let r=d(o);console.log(e.green(`\u2713 Joined as ${e.bold(r.id)}`));let i=k().filter(l=>l.id!==r.id);if(i.length>0){console.log(e.cyan(`
|
|
3
|
+
Found ${i.length} other session${i.length!==1?"s":""}:`));for(let l of i){let t=j(l)?e.yellow("asleep"):e.green("awake");console.log(` ${e.white(l.id)} \u2014 ${l.name} [${t}]`);}}else console.log(e.gray(`
|
|
4
4
|
No other sessions found. Open another terminal and run "paradigm symphony join".`));console.log(e.gray(`
|
|
5
|
-
Tip: Set up polling with: /loop 10s paradigm_symphony_poll`));}async function Y(s,o){let{SymphonyRelay:r}=await import('./symphony-relay-
|
|
5
|
+
Tip: Set up polling with: /loop 10s paradigm_symphony_poll`));}async function Y(s,o){let{SymphonyRelay:r}=await import('./symphony-relay-L3BY6RGM.js'),n,i;if(o.includes("#")){let c=o.split("#");n=c[0],i=c[1];}else n=o;n.includes(":")||(n=`${n}:3939`);let l=h(s);l||(l=d(s));let t;if(i)t=i,console.log(e.cyan(`
|
|
6
6
|
Connecting to ${n} with embedded pairing code...`));else if(console.log(e.cyan(`
|
|
7
7
|
Connecting to ${n}...`)),console.log(e.white(" Enter the 6-digit pairing code shown on the host:")),t=await K(" Code: "),t=t.trim(),!/^\d{6}$/.test(t)){console.log(e.red(" Invalid code. Must be 6 digits."));return}let a=new r({mode:"client",peerId:l.id,events:{onPeerConnected:(c,g)=>{console.log(e.green(` \u2713 Connected to ${e.bold(g)} (${c})`));},onPeerDisconnected:c=>{console.log(e.yellow(` Peer ${c} disconnected. Reconnecting...`));},onMessageRelayed:(c,g,y)=>{console.log(e.gray(` \u2190 Message ${c.slice(0,8)} from ${g} \u2192 ${y}`));},onError:c=>{console.log(e.red(` Error: ${c.message}`));}}});try{await a.connectToServer(n,t),console.log(e.green(`
|
|
8
8
|
\u2713 Paired and connected!`)),console.log(e.gray(" Messages from remote agents will appear in your inbox.")),console.log(e.gray(` Press Ctrl+C to disconnect.
|
|
9
9
|
`)),process.on("SIGINT",()=>{console.log(e.yellow(`
|
|
10
|
-
Disconnecting...`)),a.stop(),process.exit(0);}),await new Promise(()=>{});}catch(c){console.log(e.red(` Failed to connect: ${c.message}`)),a.stop();}}function K(s){return new Promise(o=>{process.stdout.write(s);let r="";process.stdin.setEncoding("utf-8"),process.stdin.resume(),process.stdin.once("data",n=>{r=n.toString(),process.stdin.pause(),o(r);});})}async function se(){let s=process.cwd(),o=
|
|
10
|
+
Disconnecting...`)),a.stop(),process.exit(0);}),await new Promise(()=>{});}catch(c){console.log(e.red(` Failed to connect: ${c.message}`)),a.stop();}}function K(s){return new Promise(o=>{process.stdout.write(s);let r="";process.stdin.setEncoding("utf-8"),process.stdin.resume(),process.stdin.once("data",n=>{r=n.toString(),process.stdin.pause(),o(r);});})}async function se(){let s=process.cwd(),o=c(s),r=e$1(o);console.log(r?e.green(`\u2713 Left the score: ${o}`):e.yellow("No active part found for this project."));}async function re(){let s$1=process.cwd(),o=h(s$1);if(!o){console.log(e.yellow('Not joined. Run "paradigm symphony join" first.'));return}let n=f().filter(t=>t.id!==o.id),i=s("active"),l=m(o.id);console.log(e.cyan(`
|
|
11
11
|
${e.bold(o.id)}`)),console.log(e.gray(` Project: ${o.project}`)),console.log(e.gray(` Role: ${o.role}`)),console.log(e.gray(` PID: ${o.pid}`)),console.log(e.gray(` Started: ${o.startedAt}`)),o.statusBlurb&&console.log(e.white(` Status: ${o.statusBlurb}`)),console.log(`
|
|
12
|
-
${e.white(`${n.length} linked peer${n.length!==1?"s":""}`)} \u2014 ${e.white(`${i.length} active thread${i.length!==1?"s":""}`)} \u2014 ${e.white(`${l.length} unread`)}`);}async function ie(s){
|
|
12
|
+
${e.white(`${n.length} linked peer${n.length!==1?"s":""}`)} \u2014 ${e.white(`${i.length} active thread${i.length!==1?"s":""}`)} \u2014 ${e.white(`${l.length} unread`)}`);}async function ie(s){g();let o=f(),{loadPeers:r}=await import('./symphony-peers-ISJPKX7W.js'),n=r(),i=[];for(let t of n)if(!t.revoked)for(let a of t.agents||[])i.push({...a,peerId:t.id});let l=o.length+i.length;if(s.json){console.log(JSON.stringify({local:o,remote:i},null,2));return}if(l===0){console.log(e.yellow('No agents joined. Run "paradigm symphony join" in each terminal.'));return}console.log(e.cyan(`
|
|
13
13
|
Symphony Agents (${l})
|
|
14
|
-
`)),console.log(e.gray(` ${"AGENT ID".padEnd(30)} ${"PROJECT".padEnd(15)} ${"ROLE".padEnd(10)} STATUS`)),console.log(e.gray(` ${"\u2500".repeat(30)} ${"\u2500".repeat(15)} ${"\u2500".repeat(10)} ${"\u2500".repeat(8)}`));for(let t of o){let a=
|
|
14
|
+
`)),console.log(e.gray(` ${"AGENT ID".padEnd(30)} ${"PROJECT".padEnd(15)} ${"ROLE".padEnd(10)} STATUS`)),console.log(e.gray(` ${"\u2500".repeat(30)} ${"\u2500".repeat(15)} ${"\u2500".repeat(10)} ${"\u2500".repeat(8)}`));for(let t of o){let a=j(t)?e.yellow("asleep"):e.green("awake");console.log(` ${e.white(t.id.padEnd(30))} ${t.project.padEnd(15)} ${t.role.padEnd(10)} ${a}`),t.statusBlurb&&console.log(` ${e.gray(` \u2514 ${t.statusBlurb}`)}`);}if(i.length>0){console.log(e.gray(`
|
|
15
15
|
${"\u2500".repeat(65)}`)),console.log(e.cyan(` Remote Agents (${i.length})
|
|
16
|
-
`));for(let t of i){let a=t.status==="awake"?e.green("awake"):e.yellow("asleep"),c=e.magenta(`(remote: ${t.peerId})`);console.log(` ${e.white(t.id.padEnd(30))} ${t.project.padEnd(15)} ${t.role.padEnd(10)} ${a} ${c}`);}}console.log();}async function le(s,o
|
|
16
|
+
`));for(let t of i){let a=t.status==="awake"?e.green("awake"):e.yellow("asleep"),c=e.magenta(`(remote: ${t.peerId})`);console.log(` ${e.white(t.id.padEnd(30))} ${t.project.padEnd(15)} ${t.role.padEnd(10)} ${a} ${c}`);}}console.log();}async function le(s,o){let r=process.cwd(),n=h(r);n||(n=d(r),console.log(e.gray(`Auto-joined as ${n.id}`)));let i={id:n.id,name:n.name,type:"human",project:n.project,role:n.role},l;o.to&&(l=[{id:o.to,name:o.to,type:"agent"}]);let t=o.thread;if(!t){let g=s.length>60?s.slice(0,60)+"...":s;t=q$1(g,i).id;}let a=v({sender:i,recipients:l,intent:"context",text:s,threadRoot:t}),c=w(a);console.log(e.green(`\u2713 Sent to ${c} agent${c!==1?"s":""}`)),console.log(e.gray(` Thread: ${t}`)),console.log(e.gray(` Note: ${a.id}`));}async function ce(){let s=process.cwd(),o$1=h(s);if(!o$1){console.log(e.yellow('Not joined. Run "paradigm symphony join" first.'));return}i(o$1.id);let r$1=m(o$1.id);if(r$1.length===0){console.log(e.gray(`
|
|
17
17
|
No unread notes.
|
|
18
|
-
`));return}let n
|
|
19
|
-
${r.length} unread note${r.length!==1?"s":""}
|
|
20
|
-
`));for(let[l,t]of n
|
|
21
|
-
`),m=y?" ":" \u2502 ";for(let $ of u)console.log(`${m}${$}`);g.symbols.length>0&&console.log(`${m}${e.gray(`Symbols: ${g.symbols.join(", ")}`)}`);}console.log();}let i=r[r.length-1].id;
|
|
18
|
+
`));return}let n=new Map;for(let l of r$1){let t=l.threadRoot||"direct";n.has(t)||n.set(t,[]),n.get(t).push(l);}console.log(e.cyan(`
|
|
19
|
+
${r$1.length} unread note${r$1.length!==1?"s":""}
|
|
20
|
+
`));for(let[l,t]of n){let a=l;if(l!=="direct"){let c=r(l);c&&(a=`${c.topic} (${l})`);}console.log(e.white(` \u250C\u2500 ${a}`));for(let c=0;c<t.length;c++){let g=t[c],y=c===t.length-1,d=y?" \u2514\u2500":" \u251C\u2500",h=new Date(g.timestamp).toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit"});console.log(`${d} ${e.cyan(g.sender.name)} ${e.gray(`[${g.intent}]`)} ${e.gray(h)}`);let u=g.content.text.split(`
|
|
21
|
+
`),m=y?" ":" \u2502 ";for(let $ of u)console.log(`${m}${$}`);g.symbols.length>0&&console.log(`${m}${e.gray(`Symbols: ${g.symbols.join(", ")}`)}`);}console.log();}let i$1=r$1[r$1.length-1].id;o(o$1.id,i$1),p$1(o$1.id);}async function ae(s$1){let o=s();if(s$1.json){console.log(JSON.stringify(o,null,2));return}if(o.length===0){console.log(e.gray(`
|
|
22
22
|
No threads.
|
|
23
23
|
`));return}console.log(e.cyan(`
|
|
24
24
|
Threads (${o.length})
|
|
25
|
-
`)),console.log(e.gray(` ${"ID".padEnd(14)} ${"TOPIC".padEnd(35)} ${"MSGS".padEnd(6)} ${"STATUS".padEnd(10)} LAST ACTIVITY`)),console.log(e.gray(` ${"\u2500".repeat(14)} ${"\u2500".repeat(35)} ${"\u2500".repeat(6)} ${"\u2500".repeat(10)} ${"\u2500".repeat(20)}`));for(let r of o){let n=r.topic.length>33?r.topic.slice(0,33)+"..":r.topic,i=r.status==="active"?e.green("active"):e.gray("resolved"),l=new Date(r.lastActivity).toLocaleString(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});console.log(` ${e.white(r.id.padEnd(14))} ${n.padEnd(35)} ${String(r.messageCount).padEnd(6)} ${i.padEnd(10)} ${e.gray(l)}`);}console.log();}async function ge(s
|
|
25
|
+
`)),console.log(e.gray(` ${"ID".padEnd(14)} ${"TOPIC".padEnd(35)} ${"MSGS".padEnd(6)} ${"STATUS".padEnd(10)} LAST ACTIVITY`)),console.log(e.gray(` ${"\u2500".repeat(14)} ${"\u2500".repeat(35)} ${"\u2500".repeat(6)} ${"\u2500".repeat(10)} ${"\u2500".repeat(20)}`));for(let r of o){let n=r.topic.length>33?r.topic.slice(0,33)+"..":r.topic,i=r.status==="active"?e.green("active"):e.gray("resolved"),l=new Date(r.lastActivity).toLocaleString(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});console.log(` ${e.white(r.id.padEnd(14))} ${n.padEnd(35)} ${String(r.messageCount).padEnd(6)} ${i.padEnd(10)} ${e.gray(l)}`);}console.log();}async function ge(s){let o=r(s);if(!o){console.log(e.red(`Thread not found: ${s}`));return}let r$1=u(s);console.log(e.cyan(`
|
|
26
26
|
Thread: ${o.topic}`)),console.log(e.gray(` ID: ${o.id} | Status: ${o.status} | Notes: ${o.messageCount}`)),console.log(e.gray(` Participants: ${o.participants.map(n=>n.name).join(", ")}`)),o.decision&&console.log(e.green(` Decision: ${o.decision}`)),console.log(e.gray(`
|
|
27
27
|
${"\u2500".repeat(60)}
|
|
28
|
-
`));for(let n of r){let i=new Date(n.timestamp).toLocaleString(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});console.log(` ${e.cyan(n.sender.name)} ${e.gray(`[${n.intent}]`)} ${e.gray(i)}`);let l=n.content.text.split(`
|
|
29
|
-
`);for(let t of l)console.log(` ${t}`);n.symbols.length>0&&console.log(` ${e.gray(`Symbols: ${n.symbols.join(", ")}`)}`),n.content.decision&&console.log(` ${e.green(`Decision: ${n.content.decision}`)}`),console.log();}}async function de(s,o){let r$1=
|
|
28
|
+
`));for(let n of r$1){let i=new Date(n.timestamp).toLocaleString(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});console.log(` ${e.cyan(n.sender.name)} ${e.gray(`[${n.intent}]`)} ${e.gray(i)}`);let l=n.content.text.split(`
|
|
29
|
+
`);for(let t of l)console.log(` ${t}`);n.symbols.length>0&&console.log(` ${e.gray(`Symbols: ${n.symbols.join(", ")}`)}`),n.content.decision&&console.log(` ${e.green(`Decision: ${n.content.decision}`)}`),console.log();}}async function de(s,o){let r$1=r(s);if(!r$1){console.log(e.red(`Thread not found: ${s}`));return}t(s,o.decision)?(console.log(e.green(`\u2713 Thread resolved: ${r$1.topic}`)),o.decision&&console.log(e.gray(` Decision: ${o.decision}`)),console.log(e.gray(` Tip: Record this as lore with "paradigm lore record --title 'Thread: ${r$1.topic}'"`))):console.log(e.red("Failed to resolve thread."));}async function ye(s$1){g();let o=process.cwd(),r=h(o),n=f(),i=s("active"),l=z("pending"),t=r?m(r.id):[],{loadPeers:a}=await import('./symphony-peers-ISJPKX7W.js'),g$1=a().filter(d=>!d.revoked);if(s$1.json){console.log(JSON.stringify({identity:r?{id:r.id,project:r.project,role:r.role}:null,agents:n.map(d=>({id:d.id,status:j(d)?"asleep":"awake",statusBlurb:d.statusBlurb})),peers:g$1.map(d=>({id:d.id,address:d.address,agents:d.agents?.length??0,lastSeen:d.lastSeen})),activeThreads:i.length,unreadMessages:t.length,pendingFileRequests:l.length},null,2));return}console.log(e.cyan(`
|
|
30
30
|
Symphony Status
|
|
31
|
-
`)),console.log(r?` ${e.white("Identity:")} ${r.id}`:` ${e.yellow("Not joined.")} Run "paradigm symphony join" to join.`);let y=n.filter(d=>!
|
|
31
|
+
`)),console.log(r?` ${e.white("Identity:")} ${r.id}`:` ${e.yellow("Not joined.")} Run "paradigm symphony join" to join.`);let y=n.filter(d=>!j(d)).length;console.log(` ${e.white("Agents:")} ${n.length} joined (${y} awake)`);for(let d of n){let h=j(d)?e.yellow("asleep"):e.green("awake"),u=d.statusBlurb?e.gray(` \u2014 ${d.statusBlurb}`):"";console.log(` ${e.white(d.id)} [${h}]${u}`);}if(g$1.length>0){let d=g$1.reduce((h,u)=>h+(u.agents?.length??0),0);console.log(` ${e.white("Peers:")} ${g$1.length} connected (${d} remote agents)`);for(let h of g$1){let u=h.agents?.length??0;console.log(` ${e.white(h.id)} at ${h.address} (${u} agent${u!==1?"s":""})`);}}else console.log(` ${e.white("Peers:")} ${e.gray('none (run "paradigm symphony serve" to accept connections)')}`);console.log(` ${e.white("Threads:")} ${i.length} active`),console.log(` ${e.white("Unread:")} ${t.length} note${t.length!==1?"s":""}`),console.log(` ${e.white("File Requests:")} ${l.length} pending`),console.log();}async function pe(s){let o=parseInt(s.port||"3939",10),r=process.cwd(),{SymphonyRelay:n}=await import('./symphony-relay-L3BY6RGM.js'),i=h(r);i||(i=d(r)),console.log(e.cyan(`
|
|
32
32
|
Starting Symphony relay server...
|
|
33
33
|
`));let l=new n({mode:"server",peerId:i.id,port:o,events:{onPeerConnected:(t,a)=>{console.log(e.green(` \u2713 Peer connected: ${e.bold(a)} (${t})`));let c=l.getRemoteAgents();c.length>0&&console.log(e.gray(` Remote agents: ${c.map(g=>g.id).join(", ")}`));},onPeerDisconnected:t=>{console.log(e.yellow(` Peer disconnected: ${t}`));},onPeerAuthFailed:(t,a)=>{console.log(e.red(` Auth failed from ${t}: ${a}`));},onMessageRelayed:(t,a,c)=>{console.log(e.gray(` \u2194 Relayed ${t.slice(0,8)} from ${a} to ${c}`));},onError:t=>{console.log(e.red(` Error: ${t.message}`));}}});try{let t=await l.startServer(),a=Q();if(console.log(e.green(` \u2713 Symphony relay listening on port ${o}`)),console.log(),console.log(e.white(" Pairing Code:")),console.log(),console.log(e.bold.cyan(` ${t.code.slice(0,3)} ${t.code.slice(3)}`)),console.log(),console.log(e.gray(" Share this code with the person connecting.")),console.log(e.gray(` Code rotates every 5 minutes.
|
|
34
34
|
`)),console.log(e.white(" LAN connect:")),console.log(e.gray(` paradigm symphony join --remote ${a}:${o}`)),s.public){let g=`${a}:${o}#${t.code}`;console.log(),console.log(e.white(" Internet connect (connection string):")),console.log(e.cyan(` paradigm symphony join --remote ${g}`)),console.log(e.gray(" (Requires port 3939 reachable: port forward, VPN, or SSH tunnel)"));}console.log(e.gray(`
|
|
35
35
|
Press Ctrl+C to stop.
|
|
36
36
|
`));let c=setInterval(()=>{let g=l.rotatePairingCode();console.log(e.cyan(` Code rotated: ${g.code.slice(0,3)} ${g.code.slice(3)}`));},300*1e3);process.on("SIGINT",()=>{console.log(e.yellow(`
|
|
37
|
-
Shutting down relay...`)),clearInterval(c),l.stop(),process.exit(0);}),await new Promise(()=>{});}catch(t){console.log(e.red(` Failed to start server: ${t.message}`)),l.stop();}}function Q(){let s=q.networkInterfaces();for(let o of Object.keys(s))for(let r of s[o]||[])if(r.family==="IPv4"&&!r.internal)return r.address;return "127.0.0.1"}async function he(s,o){let r=process.cwd(),n=
|
|
38
|
-
Available agents:`));for(let y of g)console.log(e.gray(` ${y.id}`));}return}let t
|
|
39
|
-
Reason: ${l}`,symbols:[]});
|
|
40
|
-
The owning agent's human must approve with:`)),console.log(e.white(` paradigm symphony approve ${a.request.requestId}`));}async function ue(){let s=
|
|
37
|
+
Shutting down relay...`)),clearInterval(c),l.stop(),process.exit(0);}),await new Promise(()=>{});}catch(t){console.log(e.red(` Failed to start server: ${t.message}`)),l.stop();}}function Q(){let s=q.networkInterfaces();for(let o of Object.keys(s))for(let r of s[o]||[])if(r.family==="IPv4"&&!r.internal)return r.address;return "127.0.0.1"}async function he(s,o){let r=process.cwd(),n=h(r);n||(n=d(r));let i=o.from,l=o.reason||"Needed for current task";if(!i){console.log(e.red("--from is required. Specify which agent to request from."));let g=f().filter(y=>y.id!==n.id);if(g.length>0){console.log(e.gray(`
|
|
38
|
+
Available agents:`));for(let y of g)console.log(e.gray(` ${y.id}`));}return}let t=x();if(C(s,t)){console.log(e.red(`\u2717 "${s}" is on the hard-deny list and cannot be requested.`));return}let a=y({filePath:s,requester:{id:n.id,name:n.name,type:"agent",project:n.project,role:n.role},reason:l}),c=v({sender:{id:n.id,name:n.name,type:"agent",project:n.project,role:n.role},recipients:[{id:i,name:i,type:"agent"}],intent:"fileRequest",text:`File request: ${s}
|
|
39
|
+
Reason: ${l}`,symbols:[]});w(c),console.log(e.green(`\u2713 File request created: ${a.request.requestId}`)),console.log(e.gray(` File: ${s}`)),console.log(e.gray(` From: ${i}`)),console.log(e.gray(` Reason: ${l}`)),console.log(e.gray(`
|
|
40
|
+
The owning agent's human must approve with:`)),console.log(e.white(` paradigm symphony approve ${a.request.requestId}`));}async function ue(){let s=z("pending");if(s.length===0){console.log(e.gray(`
|
|
41
41
|
No pending file requests.
|
|
42
42
|
`));return}console.log(e.cyan(`
|
|
43
43
|
Pending File Requests (${s.length})
|
|
44
|
-
`));for(let o of s){let r=Date.now()-new Date(o.createdAt).getTime(),n=Math.round(r/6e4);console.log(` ${e.white(o.request.requestId)}`),console.log(` File: ${o.request.filePath}`),console.log(` From: ${o.request.requester.name} (${o.request.requester.id})`),console.log(` Reason: ${o.request.reason}`),console.log(e.gray(` ${n}m ago`)),console.log(e.gray(` \u2192 paradigm symphony approve ${o.request.requestId}`)),console.log(e.gray(` \u2192 paradigm symphony deny ${o.request.requestId}`)),console.log();}}async function me(s,o){let r=process.cwd(),n=
|
|
44
|
+
`));for(let o of s){let r=Date.now()-new Date(o.createdAt).getTime(),n=Math.round(r/6e4);console.log(` ${e.white(o.request.requestId)}`),console.log(` File: ${o.request.filePath}`),console.log(` From: ${o.request.requester.name} (${o.request.requester.id})`),console.log(` Reason: ${o.request.reason}`),console.log(e.gray(` ${n}m ago`)),console.log(e.gray(` \u2192 paradigm symphony approve ${o.request.requestId}`)),console.log(e.gray(` \u2192 paradigm symphony deny ${o.request.requestId}`)),console.log();}}async function me(s,o){let r=process.cwd(),n=A(s,r,o.redact);if(!n.success){console.log(e.red(`\u2717 ${n.error}`));return}let i=o.redact?"approved (redacted)":"approved";console.log(e.green(`\u2713 File request ${i}`)),console.log(e.gray(` File: ${n.delivery?.filePath}`)),console.log(e.gray(` Size: ${n.delivery?.size} bytes`)),console.log(e.gray(` SHA-256: ${n.delivery?.hash?.slice(0,16)}...`));}async function fe(s,o){B(s,o.reason)?(console.log(e.green(`\u2713 File request denied: ${s}`)),o.reason&&console.log(e.gray(` Reason: ${o.reason}`))):console.log(e.red(`\u2717 File request not found or already resolved: ${s}`));}var X={question:e.blue,context:e.gray,clarification:e.blue,proposal:e.cyan,verification:e.blue,action:e.cyan,decision:e.yellow,alert:e.red,approval:e.green,rejection:e.red,reference:e.gray,handoff:e.magenta,fileRequest:e.green,fileApproved:e.green,fileDenied:e.red,fileDelivery:e.green};function Z(s){let o=new Date(s.timestamp).toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit",second:"2-digit"}),n=(X[s.intent]||e.white)(`[${s.intent}]`),i=e.cyan(s.sender.name),l=s.threadRoot?e.gray(` (${s.threadRoot})`):"",t=[];t.push(` ${e.gray(o)} ${i} ${n}${l}`);let a=s.content.text.split(`
|
|
45
45
|
`);for(let c of a)t.push(` ${c}`);return s.symbols.length>0&&t.push(` ${e.gray(`Symbols: ${s.symbols.join(", ")}`)}`),s.content.decision&&t.push(` ${e.yellow(`Decision: ${s.content.decision}`)}`),s.content.diff&&t.push(` ${e.gray("[diff attached]")}`),t.join(`
|
|
46
|
-
`)}async function $e(s){let o=process.cwd(),r=
|
|
47
|
-
`).filter($=>$.trim().length>0).length,g
|
|
48
|
-
Symphony Watch`)),console.log(e.gray(` Agent: ${r.id}`)),console.log(e.gray(` Inbox: ${a}`)),console.log(e.gray(` Poll: ${n}ms`)),i&&console.log(e.gray(` Filter: thread ${i}`)),console.log(e.gray(` Press Ctrl+C to stop
|
|
46
|
+
`)}async function $e(s){let o=process.cwd(),r=h(o);r||(r=d(o),console.log(e.gray(`Auto-joined as ${r.id}`)));let n=parseInt(s.interval||"2000",10),i$1=s.thread,l=s.quiet,t=b.join(q.homedir(),".paradigm","score"),a=b.join(t,"agents",...r.id.split("/"),"inbox.jsonl"),c=0,g=0;p.existsSync(a)&&(c=p.readFileSync(a,"utf-8").split(`
|
|
47
|
+
`).filter($=>$.trim().length>0).length,g=p.statSync(a).size),l||(console.log(e.cyan(`
|
|
48
|
+
Symphony Watch`)),console.log(e.gray(` Agent: ${r.id}`)),console.log(e.gray(` Inbox: ${a}`)),console.log(e.gray(` Poll: ${n}ms`)),i$1&&console.log(e.gray(` Filter: thread ${i$1}`)),console.log(e.gray(` Press Ctrl+C to stop
|
|
49
49
|
`)),console.log(e.gray(` ${"\u2500".repeat(60)}
|
|
50
|
-
`)));let y=b.join(t,"threads"),d=new Set;if(p.existsSync(y))for(let m of p.readdirSync(y))d.add(m);let h=()=>{try{if(p.existsSync(a)){let m=p.statSync(a);if(m.size>g
|
|
51
|
-
`).filter(T=>T.trim().length>0);if(w.length>c){let T=w.slice(c);for(let V of T)try{let F=JSON.parse(V);if(i&&F.threadRoot!==i)continue;console.log(Z(F)),console.log();}catch{}c=w.length;}g
|
|
50
|
+
`)));let y=b.join(t,"threads"),d$1=new Set;if(p.existsSync(y))for(let m of p.readdirSync(y))d$1.add(m);let h$1=()=>{try{if(p.existsSync(a)){let m=p.statSync(a);if(m.size>g){let w=p.readFileSync(a,"utf-8").split(`
|
|
51
|
+
`).filter(T=>T.trim().length>0);if(w.length>c){let T=w.slice(c);for(let V of T)try{let F=JSON.parse(V);if(i$1&&F.threadRoot!==i$1)continue;console.log(Z(F)),console.log();}catch{}c=w.length;}g=m.size;}}if(p.existsSync(y)){let m=p.readdirSync(y);for(let $ of m)if(!d$1.has($)){d$1.add($);try{let w=JSON.parse(p.readFileSync(b.join(y,$),"utf-8"));l||(console.log(` ${e.green("+")} ${e.white("New thread:")} ${w.topic||w.id}`),console.log(` ${e.gray(`by ${w.initiator?.name||"unknown"} \u2014 ${w.id}`)}`),console.log());}catch{}}}i(r.id);}catch{}};h$1();let u=setInterval(h$1,n);process.on("SIGINT",()=>{clearInterval(u),l||console.log(e.gray(`
|
|
52
52
|
Watch stopped.
|
|
53
53
|
`)),process.exit(0);}),await new Promise(()=>{});}export{me as symphonyApproveCommand,fe as symphonyDenyCommand,te as symphonyJoinCommand,se as symphonyLeaveCommand,ie as symphonyListCommand,ce as symphonyReadCommand,he as symphonyRequestCommand,ue as symphonyRequestsCommand,de as symphonyResolveCommand,le as symphonySendCommand,pe as symphonyServeCommand,ye as symphonyStatusCommand,ge as symphonyThreadCommand,ae as symphonyThreadsCommand,$e as symphonyWatchCommand,re as symphonyWhoamiCommand};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {g,f,k,j,h,s,r,u,t,c,q,v,w,m,D,z,B,A}from'./chunk-JIF7OSGH.js';import'./chunk-7SWEOPWF.js';import'./chunk-DSYEGRQ2.js';import'./chunk-XHJ27CER.js';import {Router}from'express';function G(u$1,p){let d=Router();return d.get("/agents",(i,s)=>{try{g();let e=f(),n=k(),a=new Set(e.map(t=>t.id));for(let t of n)a.has(t.id)||e.push(t);let r=e.map(t=>({id:t.id,name:t.name,project:t.project,role:t.role,status:j(t)?"asleep":"awake",lastPoll:t.lastPoll,startedAt:t.startedAt,statusBlurb:t.statusBlurb}));s.json({agents:r});}catch(e){s.status(500).json({error:"Failed to list agents",detail:String(e)});}}),d.get("/agents/me",(i,s)=>{try{let e=h(u$1);s.json({identity:e||null});}catch(e){s.status(500).json({error:"Failed to get identity",detail:String(e)});}}),d.get("/peers",async(i,s)=>{try{let{loadPeers:e}=await import('./symphony-peers-ISJPKX7W.js'),a=e().map(r=>({id:r.id,displayName:r.displayName,address:r.address,connectedAt:r.connectedAt,lastSeen:r.lastSeen,revoked:r.revoked,agents:r.agents||[]}));s.json({peers:a});}catch(e){s.status(500).json({error:"Failed to list peers",detail:String(e)});}}),d.get("/threads",(i,s$1)=>{try{let e=i.query.status,n;(e==="active"||e==="resolved")&&(n=e);let r=s(n).map(t=>({id:t.id,topic:t.topic,status:t.status,participants:t.participants.map(o=>({id:o.id,name:o.name,type:o.type})),messageCount:t.messageCount,lastActivity:t.lastActivity,decision:t.decision}));s$1.json({threads:r});}catch(e){s$1.status(500).json({error:"Failed to list threads",detail:String(e)});}}),d.get("/threads/:threadId",(i,s)=>{try{let{threadId:e}=i.params,n=r(e);if(!n){s.status(404).json({error:`Thread not found: ${e}`});return}let a=u(e),r$1=new Set;for(let t of a)for(let o of t.symbols)r$1.add(o);s.json({thread:{id:n.id,topic:n.topic,status:n.status,participants:n.participants.map(t=>({id:t.id,name:t.name,type:t.type})),messageCount:n.messageCount,lastActivity:n.lastActivity,decision:n.decision},messages:a.map(t=>({id:t.id,sender:{id:t.sender.id,name:t.sender.name,type:t.sender.type},intent:t.intent,text:t.content.text,timestamp:t.timestamp,symbols:t.symbols,diff:t.content.diff,decision:t.content.decision,recipients:t.recipients?.map(o=>({id:o.id,name:o.name}))})),symbolsDiscussed:[...r$1]});}catch(e){s.status(500).json({error:"Failed to load thread",detail:String(e)});}}),d.post("/threads/:threadId/resolve",(i,s)=>{try{let{threadId:e}=i.params,{decision:n}=i.body;if(!t(e,n)){s.status(404).json({error:`Thread not found: ${e}`});return}p&&p({type:"symphony:thread_resolved",threadId:e,decision:n}),s.json({resolved:!0,threadId:e,decision:n});}catch(e){s.status(500).json({error:"Failed to resolve thread",detail:String(e)});}}),d.post("/messages",(i,s)=>{try{let{intent:e,text:n,threadRoot:a,recipients:r,symbols:t,diff:o,decision:f$1}=i.body;if(!e||!n){s.status(400).json({error:"intent and text are required"});return}let l={id:`human/${c(u$1)}`,name:"Human (Platform UI)",type:"human"},g=a,b=!1;if(!a){let q$1=n.length>60?n.slice(0,60)+"...":n;g=q(q$1,l).id,b=!0;}let x;if(r&&r.length>0){let q=f();x=r.map(y=>{let R=q.find(H=>H.id===y);return R?{id:R.id,name:R.name,type:"agent"}:{id:y,name:y,type:"agent"}});}let c$1=v({sender:l,recipients:x,intent:e,text:n,threadRoot:g,symbols:t,diff:o,decision:f$1}),N=w(c$1);p&&p({type:"symphony:message",message:{id:c$1.id,sender:{id:l.id,name:l.name,type:l.type},intent:c$1.intent,text:c$1.content.text,timestamp:c$1.timestamp,symbols:c$1.symbols,diff:c$1.content.diff,decision:c$1.content.decision},threadId:g}),s.json({sent:!0,messageId:c$1.id,threadId:g,threadCreated:b,deliveredTo:N});}catch(e){s.status(500).json({error:"Failed to send message",detail:String(e)});}}),d.get("/inbox",(i,s)=>{try{let e=c(u$1),n=m(e);s.json({agentId:e,messages:n.map(a=>({id:a.id,sender:{id:a.sender.id,name:a.sender.name,type:a.sender.type},intent:a.intent,text:a.content.text,timestamp:a.timestamp,threadRoot:a.threadRoot,symbols:a.symbols}))});}catch(e){s.status(500).json({error:"Failed to read inbox",detail:String(e)});}}),d.get("/file-requests",(i,s)=>{try{D();let e=i.query.status,n;(e==="pending"||e==="approved"||e==="denied"||e==="expired")&&(n=e);let r=z(n).map(t=>({requestId:t.request.requestId,filePath:t.request.filePath,reason:t.request.reason,requester:{id:t.request.requester.id,name:t.request.requester.name},urgency:t.request.urgency,snippet:t.request.snippet,status:t.status,createdAt:t.createdAt,resolvedAt:t.resolvedAt,denyReason:t.denyReason}));s.json({fileRequests:r});}catch(e){s.status(500).json({error:"Failed to list file requests",detail:String(e)});}}),d.post("/file-requests/:requestId/action",(i,s)=>{try{let{requestId:e}=i.params,{action:n,reason:a}=i.body;if(!n){s.status(400).json({error:"action is required"});return}if(n==="deny"){let o=B(e,a);s.json({success:o,requestId:e,action:"denied",reason:a});return}let r=n==="approve-redacted",t=A(e,u$1,r);if(!t.success){s.status(400).json({success:!1,requestId:e,error:t.error});return}s.json({success:!0,requestId:e,action:r?"approved-redacted":"approved",filePath:t.delivery?.filePath,size:t.delivery?.size});}catch(e){s.status(500).json({error:"Failed to handle file request",detail:String(e)});}}),d.get("/status",(i,s$1)=>{try{g();let e=f(),n=e.filter(f=>!j(f)).length,a=s("active"),r=c(u$1),t=m(r),o=z("pending");s$1.json({agentCount:e.length,awakeCount:n,asleepCount:e.length-n,activeThreadCount:a.length,unreadCount:t.length,pendingFileRequests:o.length});}catch(e){s$1.status(500).json({error:"Failed to get status",detail:String(e)});}}),d}export{G as createSymphonyRouter};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export{c as SCORE_DIR,z as acknowledgeMessages,h as appendJsonlLine,u as appendToInbox,w as appendToOutbox,O as approveFileRequest,I as buildMessage,m as cleanStaleAgents,L as createFileRequest,C as createThread,P as denyFileRequest,r as discoverClaudeCodeSessions,e as ensureMailDirs,d as ensureScoreDirs,S as expireOldRequests,B as garbageCollect,f as getAgentDir,n as getMyIdentity,H as getThreadMessages,q as isAgentAsleep,R as isPathAutoApproved,Q as isPathDenied,a as isRing1Content,l as listAgents,N as listFileRequests,E as listThreads,M as loadFileRequest,D as loadThread,K as loadTrustConfig,o as markAgentPollTime,s as peekInbox,A as readAck,v as readInbox,g as readJsonlFile,y as readOutbox,x as readOutboxRaw,t as recordAckSize,b as recordRing1Interception,j as registerAgent,i as resolveAgentIdentity,G as resolveThread,J as routeMessage,k as unregisterAgent,p as updateAgentStatus,F as updateThread}from'./chunk-IW5K3RNR.js';import'./chunk-EMMMBAID.js';import'./chunk-F5BSUC2L.js';import'./chunk-XHJ27CER.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export{b as PAIRING_TTL_MS,a as PEERS_FILE,f as addPeer,m as computeHmacProof,e as findPeer,h as forgetAllPeers,k as generatePairing,c as loadPeers,g as revokePeer,d as savePeers,j as updatePeerAgents,i as updatePeerLastSeen,n as verifyHmacProof,l as verifyPairingCode}from'./chunk-J32OPJEX.js';import'./chunk-
|
|
2
|
+
export{b as PAIRING_TTL_MS,a as PEERS_FILE,f as addPeer,m as computeHmacProof,e as findPeer,h as forgetAllPeers,k as generatePairing,c as loadPeers,g as revokePeer,d as savePeers,j as updatePeerAgents,i as updatePeerLastSeen,n as verifyHmacProof,l as verifyPairingCode}from'./chunk-J32OPJEX.js';import'./chunk-XHJ27CER.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import'./chunk-
|
|
2
|
+
import'./chunk-XHJ27CER.js';import*as n from'fs';import*as f from'path';import*as p from'os';import*as s from'crypto';var d=f.join(p.homedir(),".paradigm","score"),a=f.join(d,"peers.json"),g=300*1e3;function i(){try{if(!n.existsSync(a))return [];let r=n.readFileSync(a,"utf-8"),e=JSON.parse(r);return Array.isArray(e)?e:[]}catch{return []}}function c(r){n.existsSync(d)||n.mkdirSync(d,{recursive:true}),n.writeFileSync(a,JSON.stringify(r,null,2),{mode:384});}function S(r){return i().find(t=>t.id===r)??null}function l(r){let e=i(),t=e.findIndex(o=>o.id===r.id);t>=0?e[t]=r:e.push(r),c(e);}function m(r){let e=i(),t=e.find(o=>o.id===r);return t?(t.revoked=true,c(e),true):false}function x(){let e=i().length;return n.existsSync(a)&&n.unlinkSync(a),e}function y(r){let e=i(),t=e.find(o=>o.id===r);t&&(t.lastSeen=new Date().toISOString(),c(e));}function P(r,e){let t=i(),o=t.find(u=>u.id===r);o&&(o.agents=e,c(t));}function A(){let r=s.randomBytes(32).toString("hex"),e=(parseInt(s.randomBytes(3).toString("hex"),16)%1e6).toString().padStart(6,"0"),t=s.createHash("sha256").update(e).digest("hex");return {code:e,codeHash:t,sharedSecret:r,createdAt:Date.now()}}function v(r,e){return Date.now()-r.createdAt>g?false:s.createHash("sha256").update(e).digest("hex")===r.codeHash}function h(r,e){return s.createHmac("sha256",e).update(r).digest("hex")}function R(r,e,t){let o=h(r,e);if(o.length!==t.length)return false;try{return s.timingSafeEqual(Buffer.from(o,"hex"),Buffer.from(t,"hex"))}catch{return false}}export{g as PAIRING_TTL_MS,a as PEERS_FILE,l as addPeer,h as computeHmacProof,S as findPeer,x as forgetAllPeers,A as generatePairing,i as loadPeers,m as revokePeer,c as savePeers,P as updatePeerAgents,y as updatePeerLastSeen,R as verifyHmacProof,v as verifyPairingCode};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {k,l,n,f as f$1,m as m$1,c as c$1,j,i}from'./chunk-J32OPJEX.js';import {a,b,f as f$2,l as l$1,n as n$1,j as j$1}from'./chunk-JIF7OSGH.js';import'./chunk-7SWEOPWF.js';import'./chunk-DSYEGRQ2.js';import'./chunk-XHJ27CER.js';import*as v from'fs';import*as m from'path';import*as A from'os';import*as f from'crypto';import {WebSocketServer,WebSocket}from'ws';var J=m.join(A.homedir(),".paradigm","score"),D=2e3,N=3e4,L=1e4,H=3,U=6e4,R=1e3,K=3e4;function c(p,e){p.readyState===WebSocket.OPEN&&p.send(JSON.stringify(e));}function C(p){try{let e=typeof p=="string"?p:String(p);return JSON.parse(e)}catch{return null}}var F=class p{wss=null;wsClient=null;mode;pairingState=null;connectedPeers=new Map;seenMessageIds=new Set;outboxWatchInterval=null;keepaliveInterval=null;reconnectTimer=null;reconnectDelay=R;outboxPositions=new Map;events;myPeerId;port;stopped=false;failedAuthAttempts=new Map;pongTimers=new Map;serverAddress=null;serverCode=null;static MAX_SEEN_IDS=1e4;constructor(e){this.mode=e.mode,this.myPeerId=e.peerId,this.port=e.port??3939,this.events=e.events??{};}async startServer(){if(this.mode!=="server")throw new Error('startServer() requires mode "server"');return this.pairingState=k(),this.wss=new WebSocketServer({port:this.port}),this.wss.on("connection",(e,t)=>{let n=t.socket.remoteAddress??"unknown";if(this.isRateLimited(n)){c(e,{type:"auth_fail",reason:"Too many failed attempts \u2014 try again later"}),e.close();return}let s=f.randomBytes(32).toString("hex");c(e,{type:"hello",version:"1.0",peerId:this.myPeerId,challenge:s});let i=false;e.on("message",r=>{let o=C(r);if(o){if(!i){this.handleServerAuth(e,o,s,n).then(a=>{a&&(i=true,this.registerPeerConnection(a,e));}).catch(a=>{this.events.onError?.(a instanceof Error?a:new Error(String(a)));});return}this.handleAuthenticatedFrame(e,o);}}),e.on("close",()=>{i&&this.handlePeerDisconnect(e);}),e.on("error",r=>{this.events.onError?.(r);});}),this.wss.on("error",e=>{this.events.onError?.(e);}),await new Promise((e,t)=>{this.wss.on("listening",e),this.wss.on("error",t);}),this.startOutboxWatcher(),this.startKeepalive(),this.pairingState}async handleServerAuth(e,t,n$1,s){if(t.type!=="auth")return c(e,{type:"auth_fail",reason:"Expected auth frame"}),e.close(),null;if(!this.pairingState||!l(this.pairingState,t.code)){this.recordFailedAuth(s);let a="Invalid or expired pairing code";return c(e,{type:"auth_fail",reason:a}),this.events.onPeerAuthFailed?.(s,a),e.close(),null}let i=this.pairingState.codeHash;if(!n(n$1,i,t.proof)){this.recordFailedAuth(s);let a="HMAC proof verification failed";return c(e,{type:"auth_fail",reason:a}),this.events.onPeerAuthFailed?.(s,a),e.close(),null}let r=this.getLocalAgentSummaries(),o=this.myPeerId;return c(e,{type:"auth_ok",peerId:this.myPeerId,displayName:o,agents:r}),f$1({id:t.peerId,displayName:t.peerId,address:s,sharedSecret:this.pairingState.sharedSecret,connectedAt:new Date().toISOString(),lastSeen:new Date().toISOString(),revoked:false,agents:[]}),t.peerId}async connectToServer(e,t){if(this.mode!=="client")throw new Error('connectToServer() requires mode "client"');this.serverAddress=e,this.serverCode=t,await this.attemptConnection(e,t);}attemptConnection(e,t){return new Promise((n,s)=>{if(this.stopped){s(new Error("Relay has been stopped"));return}let i=e.includes("://")?e:`ws://${e}`,r=new WebSocket(i),o=false;r.on("open",()=>{this.wsClient=r;}),r.on("message",a=>{let d=C(a);if(d)switch(d.type){case "hello":{let x=f.createHash("sha256").update(t).digest("hex"),O=m$1(d.challenge,x);c(r,{type:"auth",peerId:this.myPeerId,code:t,proof:O});break}case "auth_ok":{f$1({id:d.peerId,displayName:d.displayName,address:e,sharedSecret:t,connectedAt:new Date().toISOString(),lastSeen:new Date().toISOString(),revoked:false,agents:d.agents}),c(r,{type:"agents_sync",agents:this.getLocalAgentSummaries()}),this.registerPeerConnection(d.peerId,r),this.startOutboxWatcher(),this.startKeepalive(),this.reconnectDelay=R,o||(o=true,n());break}case "auth_fail":{o||(o=true,s(new Error(`Auth failed: ${d.reason}`))),r.close();break}default:this.handleAuthenticatedFrame(r,d);break}}),r.on("close",()=>{this.handlePeerDisconnect(r),o?this.stopped||this.scheduleReconnect():(o=true,s(new Error("Connection closed before auth completed")));}),r.on("error",a=>{this.events.onError?.(a),o||(o=true,s(a));});})}handleAuthenticatedFrame(e,t){switch(t.type){case "message":this.handleIncomingMessage(e,t.message,t.origin);break;case "message_ack":break;case "nomination_forward":this.handleNominationForward(e,t.nomination,t.origin);break;case "agents_sync":this.handleAgentsSync(e,t.agents);break;case "agent_joined":{let n=this.peerIdForSocket(e);if(n){let i=c$1().find(r=>r.id===n);if(i){let r=[...i.agents||[],t.agent];j(n,r);}}break}case "agent_left":{let n=this.peerIdForSocket(e);if(n){let i=c$1().find(r=>r.id===n);if(i){let r=(i.agents||[]).filter(o=>o.id!==t.agentId);j(n,r);}}break}case "peer_leaving":this.handlePeerDisconnect(e),e.close();break;case "ping":c(e,{type:"pong"});break;case "pong":this.handlePong(e);break;}}handleIncomingMessage(e,t,n){if(a(t)){b(t.sender.id,t,"cross-project-transfer"),c(e,{type:"message_ack",messageId:t.id});return}if(this.seenMessageIds.has(t.id)){c(e,{type:"message_ack",messageId:t.id});return}this.addToSeenIds(t.id);let s=f$2();if(t.recipients&&t.recipients.length>0)for(let i of t.recipients){let r=s.find(o=>o.id===i.id);r&&(l$1(r.id,t),this.events.onMessageRelayed?.(t.id,n,r.id));}else for(let i of s)l$1(i.id,t),this.events.onMessageRelayed?.(t.id,n,i.id);if(this.mode==="server"){let i=this.peerIdForSocket(e);for(let[r,o]of this.connectedPeers)r!==i&&r!==n&&c(o,{type:"message",message:t,origin:n});}c(e,{type:"message_ack",messageId:t.id});}handleNominationForward(e,t,n){if(!t?.id)return;let s={...t,remote_origin:n,forwarded_at:new Date().toISOString()};try{let i=m.join(A.homedir(),".paradigm","events");v.mkdirSync(i,{recursive:!0});let r=m.join(i,"nominations.jsonl");v.appendFileSync(r,JSON.stringify(s)+`
|
|
3
|
+
`,"utf8");}catch{}if(this.mode==="server")for(let[i,r]of this.connectedPeers)r!==e&&r.readyState===WebSocket.OPEN&&c(r,{type:"nomination_forward",nomination:s,origin:n});c(e,{type:"nomination_ack",nominationId:t.id});}handleAgentsSync(e,t){let n=this.peerIdForSocket(e);n&&(j(n,t),i(n));}startOutboxWatcher(){this.outboxWatchInterval||(this.outboxWatchInterval=setInterval(()=>{if(this.connectedPeers.size!==0)try{let e=f$2();for(let t of e){let n=n$1(t.id),s=this.outboxPositions.get(t.id)??0;if(n.length<=s){this.outboxPositions.set(t.id,n.length);continue}this.outboxPositions.set(t.id,n.length);let i=n.slice(s);for(let r of i){if(a(r)||this.seenMessageIds.has(r.id))continue;this.addToSeenIds(r.id);let o={type:"message",message:r,origin:this.myPeerId};for(let[a,d]of this.connectedPeers)c(d,o);}}}catch(e){this.events.onError?.(e instanceof Error?e:new Error(String(e)));}},D));}stopOutboxWatcher(){this.outboxWatchInterval&&(clearInterval(this.outboxWatchInterval),this.outboxWatchInterval=null);}startKeepalive(){this.keepaliveInterval||(this.keepaliveInterval=setInterval(()=>{for(let[e,t]of this.connectedPeers){c(t,{type:"ping"});let n=setTimeout(()=>{this.handlePeerDisconnect(t),t.terminate();},L);this.pongTimers.set(e,n);}},N));}stopKeepalive(){this.keepaliveInterval&&(clearInterval(this.keepaliveInterval),this.keepaliveInterval=null);for(let e of this.pongTimers.values())clearTimeout(e);this.pongTimers.clear();}handlePong(e){let t=this.peerIdForSocket(e);if(t){let n=this.pongTimers.get(t);n&&(clearTimeout(n),this.pongTimers.delete(t)),i(t);}}registerPeerConnection(e,t){let n=this.connectedPeers.get(e);n&&n!==t&&n.close(),this.connectedPeers.set(e,t),i(e),this.events.onPeerConnected?.(e,e);}handlePeerDisconnect(e){let t=this.peerIdForSocket(e);if(!t)return;this.connectedPeers.delete(t);let n=this.pongTimers.get(t);n&&(clearTimeout(n),this.pongTimers.delete(t)),this.events.onPeerDisconnected?.(t);}peerIdForSocket(e){for(let[t,n]of this.connectedPeers)if(n===e)return t;return null}scheduleReconnect(){if(this.stopped||this.mode!=="client"||!this.serverAddress||!this.serverCode)return;this.stopOutboxWatcher(),this.stopKeepalive(),this.wsClient=null;let e=this.reconnectDelay;this.reconnectDelay=Math.min(this.reconnectDelay*2,K),this.reconnectTimer=setTimeout(()=>{this.stopped||this.attemptConnection(this.serverAddress,this.serverCode).catch(t=>{this.events.onError?.(t instanceof Error?t:new Error(String(t)));});},e);}isRateLimited(e){let t=this.failedAuthAttempts.get(e);return t?Date.now()<t.cooldownUntil?true:t.count>=H?(t.cooldownUntil=Date.now()+U,true):false:false}recordFailedAuth(e){let t=this.failedAuthAttempts.get(e);t?t.count++:this.failedAuthAttempts.set(e,{count:1,cooldownUntil:0});}addToSeenIds(e){if(this.seenMessageIds.add(e),this.seenMessageIds.size>p.MAX_SEEN_IDS){let t=Array.from(this.seenMessageIds),n=Math.floor(t.length/2);this.seenMessageIds=new Set(t.slice(n));}}getLocalAgentSummaries(){return f$2().map(e=>({id:e.id,project:e.project,role:e.role,status:j$1(e)?"asleep":"awake"}))}stop(){this.stopped=true;for(let[e,t]of this.connectedPeers)c(t,{type:"peer_leaving"}),t.close();this.connectedPeers.clear(),this.wsClient&&(this.wsClient.close(),this.wsClient=null),this.stopOutboxWatcher(),this.stopKeepalive(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.wss&&(this.wss.close(),this.wss=null);}getConnectedPeers(){return Array.from(this.connectedPeers.keys())}getRemoteAgents(){let e=[],t=c$1();for(let n of this.connectedPeers.keys()){let s=t.find(i=>i.id===n);if(s?.agents)for(let i of s.agents)e.push({...i,peerId:n});}return e}rotatePairingCode(){if(this.mode!=="server")throw new Error('rotatePairingCode() requires mode "server"');return this.pairingState=k(),this.pairingState}};export{J as SCORE_DIR,F as SymphonyRelay};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {d}from'./chunk-
|
|
2
|
+
import {d}from'./chunk-DOCDDDTD.js';import'./chunk-JQKKVAAN.js';import {a as a$1}from'./chunk-LKAT7IAK.js';import'./chunk-XHJ27CER.js';import*as a from'fs';import*as c from'path';import*as j from'js-yaml';import p from'chalk';import $ from'ora';async function x(y){let r=process.cwd(),e=$();console.log(p.blue(`
|
|
3
3
|
Paradigm Sync LLMs
|
|
4
4
|
`)),e.start("Loading .paradigm/ configuration...");let i=d(r);i||(e.fail("No .paradigm/ directory found"),console.log(p.gray("\nRun `paradigm init` to initialize Paradigm in this project.\n")),a$1.command("sync-llms").error("Missing .paradigm/ directory"),process.exit(1)),e.succeed(`Loaded configuration for ${p.cyan(i.projectName)}`),a$1.command("sync-llms").debug("Configuration loaded",{projectName:i.projectName}),e.start("Reading navigator.yaml...");let g=null,h=c.join(r,".paradigm","navigator.yaml");if(a.existsSync(h))try{let n=a.readFileSync(h,"utf8");g=j.load(n),e.succeed("Loaded navigator.yaml");}catch{e.warn("Could not parse navigator.yaml, skipping key files section"),a$1.command("sync-llms").warn("Failed to parse navigator.yaml");}else e.info("No navigator.yaml found, skipping key files section");let o=null,f=c.join(r,".paradigm","flows.yaml");if(a.existsSync(f))try{let n=a.readFileSync(f,"utf8");o=j.load(n);}catch{a$1.command("sync-llms").warn("Failed to parse flows.yaml");}let d$1=null,m=c.join(r,"portal.yaml");if(a.existsSync(m))try{let n=a.readFileSync(m,"utf8");d$1=j.load(n);}catch{a$1.command("sync-llms").warn("Failed to parse portal.yaml");}e.start("Generating llms.txt...");let w=b(i,g,o,d$1),t=y.output?c.resolve(r,y.output):c.join(r,"llms.txt");try{a.writeFileSync(t,w,"utf8"),e.succeed(p.green("Generated llms.txt")),console.log(p.gray(`
|
|
5
5
|
Path: ${c.relative(r,t)}`)),console.log(""),a$1.command("sync-llms").success("llms.txt generated",{path:t});}catch(n){e.fail(p.red("Failed to write llms.txt")),a$1.command("sync-llms").error("Write failed",{error:n.message}),process.exit(1);}}function b(y,r,e,i){let{config:g,projectName:h}=y,o=[];o.push(`# ${g.project||h}`);let f=g["agent-guidelines"]?.overview?.trim();f&&o.push(`> ${f.replace(/\n/g,`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export{e as completeTask,c as createTask,b as loadTask,a as loadTasks,g as rebuildTaskIndex,f as shelveTask,d as updateTask}from'./chunk-DVZWCXB6.js';import'./chunk-
|
|
2
|
+
export{e as completeTask,c as createTask,b as loadTask,a as loadTasks,g as rebuildTaskIndex,f as shelveTask,d as updateTask}from'./chunk-DVZWCXB6.js';import'./chunk-XHJ27CER.js';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export{e as teamAcceptCommand,f as teamCheckCommand,d as teamHandoffCommand,g as teamHistoryCommand,b as teamInitCommand,a as teamModelsCommand,h as teamResetCommand,c as teamStatusCommand}from'./chunk-JUOOVKK6.js';import'./chunk-7PB7AXQE.js';import'./chunk-TYWB5IQJ.js';import'./chunk-5YHR77AL.js';import'./chunk-RN35IVA2.js';import'./chunk-AO7ZSRME.js';import'./chunk-FYDRENK7.js';import'./chunk-Y4XFVDZC.js';import'./chunk-EKZDFEJW.js';import'./chunk-SHD27BQX.js';import'./chunk-T6IDXUUA.js';import'./chunk-JIXHEBGK.js';import'./chunk-QT2LKB3P.js';import'./chunk-XHJ27CER.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {a}from'./chunk-QT2LKB3P.js';import'./chunk-
|
|
2
|
+
import {a}from'./chunk-QT2LKB3P.js';import'./chunk-XHJ27CER.js';import*as y from'path';import*as h from'fs';import p from'chalk';var R=null;function G(e){R=e;}function k(){return R}async function O(e,s,t){let n=t||k();if(!n)return {passed:false,results:[],errors:["No gate client configured"]};let o=[],r=[];for(let i of s)try{let c=await n.check(e,i.entity),u=c.passed===i.expected;if(i.expectedPrizes&&c.passed){let a=c.triggeredPrizes.map(l=>l.id),f=i.expectedPrizes.filter(l=>!a.includes(l));f.length>0&&r.push(`Test "${i.name}": Expected prizes not triggered: ${f.join(", ")}`);}o.push({testCase:i,result:c,passed:u}),u||r.push(`Test "${i.name}": Expected ${i.expected?"pass":"fail"}, got ${c.passed?"pass":"fail"}`);}catch(c){r.push(`Test "${i.name}": ${c.message}`),o.push({testCase:i,result:{gate:{id:e,locks:[],prizes:[]},passed:false,lockResults:[],triggeredPrizes:[],timestamp:Date.now()},passed:false});}return {passed:r.length===0,results:o,errors:r}}async function T(e,s={}){let{outputDir:t="tests/gates",framework:n="jest",includeFlows:o=true}=s,r=await a(e),i=[],c=y.resolve(t);h.existsSync(c)||h.mkdirSync(c,{recursive:true});for(let u of r.gates){let a=N(u,n),f=`${u.id.replace(/[^a-z0-9]/gi,"-")}.test.ts`,l=y.join(c,f);h.writeFileSync(l,a,"utf8"),i.push(l);}if(o&&r.flows.length>0){let u=y.join(c,"..","flows");h.existsSync(u)||h.mkdirSync(u,{recursive:true});for(let a of r.flows){let f=z(a,r.gates,n),l=`${a.id.replace(/[^a-z0-9]/gi,"-")}.test.ts`,d=y.join(u,l);h.writeFileSync(d,f,"utf8"),i.push(d);}}return i}function N(e,s){let t=s==="mocha"||s==="vitest"?"it":"test",n=e.id,o=e.description||n,r=e.locks.map(i=>{let c=i.keys.map((u,a)=>` ${t}('should check key: ${u.description||`Key ${a+1}`}', async () => {
|
|
3
3
|
const entity = {
|
|
4
4
|
// TODO: Add entity properties needed for this key
|
|
5
5
|
// Key expression: ${u.expression}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import'./chunk-
|
|
2
|
+
import'./chunk-XHJ27CER.js';import*as o from'fs';import*as f from'path';import c from'chalk';import*as p from'js-yaml';var b=`# Thread - Session Continuity
|
|
3
3
|
|
|
4
4
|
> Pass context between AI agent sessions. Updated by \`paradigm thread save\`.
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {d}from'./chunk-
|
|
2
|
+
import {d}from'./chunk-7YTAA6XA.js';import'./chunk-XHJ27CER.js';import n from'chalk';async function w(c){let y=process.cwd(),h=parseInt(c.limit||"20",10),i=await d(y,{limit:h});if(i.length===0){c.json?console.log(JSON.stringify({entries:[],byDate:{},hotSymbols:[],authors:[]},null,2)):console.log(n.gray(`
|
|
3
3
|
No lore entries found.
|
|
4
4
|
`));return}let r=new Map;for(let o of i){let t=o.timestamp.slice(0,10);r.has(t)||r.set(t,[]),r.get(t).push(o);}let a=new Map;for(let o of i)for(let t of o.symbols_touched||[])a.set(t,(a.get(t)||0)+1);let g=Array.from(a.entries()).sort(([,o],[,t])=>t-o).slice(0,10).map(([o,t])=>({symbol:o,count:t})),l=new Map;for(let o of i){let t=o.author,e=l.get(t);e?(e.count++,o.agent&&(e.hasAgent=true),o.timestamp>e.lastActive&&(e.lastActive=o.timestamp)):l.set(t,{count:1,hasAgent:o.agent!=null,lastActive:o.timestamp});}if(c.json){let o={};for(let[t,e]of r)o[t]=e.map(s=>({id:s.id,type:s.type||"note",title:s.title,author:s.author,symbols:s.symbols_touched||[]}));console.log(JSON.stringify({total:i.length,byDate:o,hotSymbols:g,authors:Array.from(l.entries()).map(([t,e])=>({id:t,hasAgent:e.hasAgent,entries:e.count,lastActive:e.lastActive}))},null,2));return}let f={"agent-session":n.hex("#818cf8"),"human-note":n.hex("#34d399"),decision:n.hex("#fbbf24"),review:n.hex("#c084fc"),incident:n.hex("#f87171"),milestone:n.hex("#60a5fa")};console.log(n.magenta(`
|
|
5
5
|
Lore Timeline (${i.length} entries)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export{h as registerTools}from'./chunk-YG5G5GEQ.js';import'./chunk-4UJ4NIEQ.js';import'./chunk-3QMRDN65.js';import'./chunk-KLBH26PA.js';import'./chunk-JNSJVCTU.js';import'./chunk-Q2J542ST.js';import'./chunk-XROULIQN.js';import'./chunk-IW5K3RNR.js';import'./chunk-EMMMBAID.js';import'./chunk-X54WXWCX.js';import'./chunk-M4UMM6DC.js';import'./chunk-W6WVJLHO.js';import'./chunk-6PP2RPIZ.js';import'./chunk-NFQLONFY.js';import'./chunk-F5BSUC2L.js';import'./chunk-3OMJI5TT.js';import'./chunk-DVZWCXB6.js';import'./chunk-OVDYPOHR.js';import'./chunk-4W5TBL3O.js';import'./chunk-XHJ27CER.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {f,p,o,r,i,s}from'./chunk-4QADCWPU.js';import {a}from'./chunk-NKYNHSA5.js';import'./chunk-
|
|
2
|
+
import {f,p,o,r,i,s}from'./chunk-4QADCWPU.js';import {a}from'./chunk-NKYNHSA5.js';import'./chunk-XHJ27CER.js';import t from'chalk';import S from'ora';import*as h from'fs';function I(){return `
|
|
3
3
|
${t.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}
|
|
4
4
|
${t.cyan("\u2551")} ${t.bold.white("PARADIGM SENTINEL TRIAGE")} ${t.cyan("\u2551")}
|
|
5
5
|
${t.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import'./chunk-
|
|
2
|
+
import'./chunk-XHJ27CER.js';import*as c from'path';import*as i from'fs';import*as d from'js-yaml';import o from'chalk';import {execSync}from'child_process';var f=".paradigm/tutorial/state.json",h=".paradigm/tutorial/curriculum.yaml";function p(n){let e=c.join(n,f);if(i.existsSync(e))try{return JSON.parse(i.readFileSync(e,"utf8"))}catch{}return {currentStep:null,completedSteps:[],fixedBugs:[]}}function g(n,e){let s=c.join(n,f),t=c.dirname(s);i.existsSync(t)||i.mkdirSync(t,{recursive:true}),i.writeFileSync(s,JSON.stringify(e,null,2),"utf8");}function y(n){let e=c.join(n,".paradigm/tutorial");i.existsSync(e)||i.mkdirSync(e,{recursive:true});let s={title:"Paradigm Tutorial - ShopFlow Example",description:"Learn Paradigm by exploring the ShopFlow e-commerce example",steps:[{id:"step-1-explore-structure",title:"Explore Project Structure",description:"Understand how Paradigm organizes project knowledge",file:"step-1-explore-structure.md",checkpoints:[{type:"file-exists",path:".purpose"},{type:"file-exists",path:"portal.yaml"},{type:"file-exists",path:".paradigm/config.yaml"}]},{id:"step-2-understand-purpose",title:"Understanding Purpose Files",description:"Learn how Purpose files define features and components",file:"step-2-understand-purpose.md",checkpoints:[{type:"file-exists",path:".purpose"}]},{id:"step-3-understand-gates",title:"Understanding Gates",description:"Learn how Gates define authorization and access control",file:"step-3-understand-gates.md",checkpoints:[{type:"file-exists",path:"portal.yaml"}]},{id:"step-4-explore-symbols",title:"Exploring Symbols",description:"Understand Paradigm's symbol system and how they connect",file:"step-4-explore-symbols.md",checkpoints:[{type:"command-success",command:"paradigm status"}]},{id:"step-5-visualize",title:"Visualize in Dreamscape",description:"See your project knowledge visualized in the Dreamscape",file:"step-5-visualize.md",checkpoints:[{type:"command-success",command:"paradigm dream aggregate"}]}],bugs:[]},t=c.join(e,"curriculum.yaml");i.writeFileSync(t,d.dump(s),"utf8");let r=[{file:"step-1-explore-structure.md",content:`# Step 1: Explore Project Structure
|
|
3
3
|
|
|
4
4
|
Welcome to the Paradigm tutorial! In this step, you'll explore how Paradigm organizes project knowledge.
|
|
5
5
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import'./chunk-
|
|
2
|
+
import'./chunk-XHJ27CER.js';import {Router}from'express';import*as n from'fs';import*as o from'path';function m(p){let i=Router(),u=o.join(__dirname,"..","..","university-content");return i.get("/courses",(a,e)=>{try{let s=o.join(u,"courses");if(!n.existsSync(s))return e.json({courses:[]});let l=n.readdirSync(s).filter(r=>r.endsWith(".json")).map(r=>{let t=JSON.parse(n.readFileSync(o.join(s,r),"utf-8"));return {id:t.id,title:t.title,description:t.description,lessonCount:t.lessons?.length||0,quizCount:t.quizzes?.length||0,lessons:(t.lessons||[]).map(d=>({id:d.id,title:d.title}))}});return l.sort((r,t)=>r.id.localeCompare(t.id)),e.json({courses:l})}catch(s){e.status(500).json({error:"Failed to list courses",detail:String(s)});}}),i.get("/courses/:id",(a,e)=>{try{let s=o.join(u,"courses",`${a.params.id}.json`);if(!n.existsSync(s))return e.status(404).json({error:`Course '${a.params.id}' not found`});let c=JSON.parse(n.readFileSync(s,"utf-8"));return e.json(c)}catch(s){e.status(500).json({error:"Failed to load course",detail:String(s)});}}),i.get("/plsat",(a,e)=>{try{let s=o.join(u,"plsat");if(!n.existsSync(s))return e.json({versions:[]});let l=n.readdirSync(s).filter(r=>r.endsWith(".json")).map(r=>{let t=JSON.parse(n.readFileSync(o.join(s,r),"utf-8"));return {version:t.version||r.replace(".json",""),frameworkVersion:t.frameworkVersion,questionCount:t.questions?.length||0,timeLimit:t.timeLimit,passThreshold:t.passThreshold}});return e.json({versions:l})}catch(s){e.status(500).json({error:"Failed to list PLSAT versions",detail:String(s)});}}),i.get("/diplomas",(a,e)=>{try{let s=o.join(p,".paradigm","university","diplomas");if(!n.existsSync(s))return e.json({diplomas:[]});let l=n.readdirSync(s).filter(r=>r.endsWith(".json")||r.endsWith(".yaml")).map(r=>{let t=n.readFileSync(o.join(s,r),"utf-8");return r.endsWith(".json")?JSON.parse(t):t}).filter(Boolean);return e.json({diplomas:l})}catch(s){e.status(500).json({error:"Failed to load diplomas",detail:String(s)});}}),i.get("/reference",(a,e)=>{try{let s=o.join(u,"reference.json");if(!n.existsSync(s))return e.json({});let c=JSON.parse(n.readFileSync(s,"utf-8"));return e.json(c)}catch(s){e.status(500).json({error:"Failed to load reference",detail:String(s)});}}),i}export{m as createUniversityRouter};
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
{
|
|
7
7
|
"id": "flows-deep-dive",
|
|
8
8
|
"title": "Flows in Depth",
|
|
9
|
-
"content": "## When to Create a Flow\n\nNot every process needs a `$flow`. The rule of thumb is: **create a flow when logic spans three or more components in a specific order**. A two-component interaction (service A calls service B) is simple enough to document in the component's `.purpose` entry. But once a third component enters the picture — and the order matters — a flow captures the choreography that no single component can describe.\n\nConsider these scenarios:\n- User clicks \"Buy\" → cart validates → payment charges → order creates → email sends. That is four components in sequence. This needs a `$checkout-flow`.\n- A cron job triggers → data fetches → report generates → file uploads → Slack notifies. Five components. This needs a `$daily-report-flow`.\n- A controller calls a service which returns data. Two components, no sequence ambiguity. This does NOT need a flow.\n\n## Flow Step Structure\n\nEach step in a flow is a `component + action` pair. The component references a `#component` defined in a `.purpose` file, and the action describes what that component does in this step:\n\n```yaml\nflows:\n $onboarding:\n description: New user setup from registration to first project\n steps:\n - component: \"#auth-handler\"\n action: create-account\n description: Validates email, hashes password, creates user record\n - component: \"#email-service\"\n action: send-welcome\n description: Sends welcome email with verification link\n - component: \"#project-service\"\n action: create-default-project\n description: Creates a starter project for the new user\n - component: \"#notification-service\"\n action: notify-team\n description: Alerts the team Slack channel about the new signup\n signals: [\"!user-created\", \"!welcome-email-sent\"]\n gates: []\n```\n\nThe `description` on each step is optional but valuable — it tells AI agents what happens at each point without reading the source code.\n\n## Documenting Flows in .purpose Files\n\nFlows are defined in the `flows` section of a `.purpose` file, usually in the directory of the *initiating* component. If the checkout flow starts in the cart module, define `$checkout-flow` in `src/cart/.purpose`. The flow references components from other directories — that is expected and correct.\n\nYou can also reference flows from component definitions:\n\n```yaml\ncomponents:\n #cart-service:\n description: Shopping cart management\n flows: [\"$checkout-flow\", \"$cart-abandonment-flow\"]\n```\n\nThis bidirectional referencing lets `paradigm_ripple` calculate the full impact when you modify a component — it knows which flows pass through it.\n\n## Flow Validation\n\nParadigm provides `
|
|
9
|
+
"content": "## When to Create a Flow\n\nNot every process needs a `$flow`. The rule of thumb is: **create a flow when logic spans three or more components in a specific order**. A two-component interaction (service A calls service B) is simple enough to document in the component's `.purpose` entry. But once a third component enters the picture — and the order matters — a flow captures the choreography that no single component can describe.\n\nConsider these scenarios:\n- User clicks \"Buy\" → cart validates → payment charges → order creates → email sends. That is four components in sequence. This needs a `$checkout-flow`.\n- A cron job triggers → data fetches → report generates → file uploads → Slack notifies. Five components. This needs a `$daily-report-flow`.\n- A controller calls a service which returns data. Two components, no sequence ambiguity. This does NOT need a flow.\n\n## Flow Step Structure\n\nEach step in a flow is a `component + action` pair. The component references a `#component` defined in a `.purpose` file, and the action describes what that component does in this step:\n\n```yaml\nflows:\n $onboarding:\n description: New user setup from registration to first project\n steps:\n - component: \"#auth-handler\"\n action: create-account\n description: Validates email, hashes password, creates user record\n - component: \"#email-service\"\n action: send-welcome\n description: Sends welcome email with verification link\n - component: \"#project-service\"\n action: create-default-project\n description: Creates a starter project for the new user\n - component: \"#notification-service\"\n action: notify-team\n description: Alerts the team Slack channel about the new signup\n signals: [\"!user-created\", \"!welcome-email-sent\"]\n gates: []\n```\n\nThe `description` on each step is optional but valuable — it tells AI agents what happens at each point without reading the source code.\n\n## Documenting Flows in .purpose Files\n\nFlows are defined in the `flows` section of a `.purpose` file, usually in the directory of the *initiating* component. If the checkout flow starts in the cart module, define `$checkout-flow` in `src/cart/.purpose`. The flow references components from other directories — that is expected and correct.\n\nYou can also reference flows from component definitions:\n\n```yaml\ncomponents:\n #cart-service:\n description: Shopping cart management\n flows: [\"$checkout-flow\", \"$cart-abandonment-flow\"]\n```\n\nThis bidirectional referencing lets `paradigm_ripple` calculate the full impact when you modify a component — it knows which flows pass through it.\n\n## Flow Validation\n\nParadigm provides `paradigm_flow_check` to check that your flow definitions are consistent:\n\n```\nparadigm_flow_check({ flowId: \"$checkout-flow\", checkImplementation: true })\n```\n\nWith `checkImplementation: true`, the validator goes beyond schema checks — it verifies that the referenced components exist in `.purpose` files, that the actions are implemented in the codebase, and that any signals listed are actually emitted. This catches drift between documentation and code.\n\nYou can also validate all flows at once by omitting the `flowId` parameter. This is useful as a pre-commit check or CI step.\n\n## Circular Dependency Detection\n\nWhen flows reference each other via `relatedFlows` or step-level `$flow` symbols, they form a dependency graph. Paradigm automatically detects circular dependencies in this graph using depth-first search.\n\nA circular dependency looks like this:\n\n```yaml\n$checkout-flow:\n relatedFlows: [$payment-flow]\n$payment-flow:\n relatedFlows: [$checkout-flow] # Creates a cycle!\n```\n\nWhen you run `paradigm_flow_check({})` (validate all flows), the output includes a `circularDependencies` section:\n\n```\n⚠ Circular Dependencies (1)\n\n $checkout-flow → $payment-flow → $checkout-flow\n\n Resolution: Break the cycle by extracting shared logic into a\n separate flow, or remove one direction of the dependency.\n```\n\nTo resolve circular dependencies:\n1. **Extract shared logic** into a new flow that both original flows reference\n2. **Remove one direction** if only one flow truly depends on the other\n3. **Replace with signals** — use `!signal` communication instead of direct flow references\n\nCircular dependencies are not just a documentation problem — they indicate architectural coupling that can lead to cascading failures and maintenance difficulty.\n\n## Flows Are Documentation, Not Orchestration\n\nA critical distinction: flows describe *what happens*, not *how to make it happen*. They are not workflow engines or saga orchestrators. Your code still calls services, handles errors, and manages state however it needs to. The flow definition is metadata that helps humans and AI agents understand the sequence — it does not replace your implementation.",
|
|
10
10
|
"keyConcepts": [
|
|
11
11
|
"Create flows when 3+ components are involved in sequence",
|
|
12
12
|
"Steps are component + action pairs",
|
|
13
13
|
"Define flows in the .purpose file of the initiating component",
|
|
14
|
-
"
|
|
14
|
+
"paradigm_flow_check checks consistency with codebase",
|
|
15
15
|
"Circular dependency detection catches cycles in flow relatedFlows references",
|
|
16
16
|
"Flows are documentation, not orchestration code",
|
|
17
17
|
"'paradigm flow diagram $flowId' generates Mermaid flowcharts — gates as diamonds, actions as rectangles, signals as rounded boxes"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"id": "q3",
|
|
48
|
-
"question": "What does `
|
|
48
|
+
"question": "What does `paradigm_flow_check` with `checkImplementation: true` verify?",
|
|
49
49
|
"choices": {
|
|
50
50
|
"A": "That the flow executes correctly at runtime",
|
|
51
51
|
"B": "That referenced components exist in .purpose files, actions are implemented, and signals are emitted",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"id": "q5",
|
|
74
|
-
"question": "`$checkout-flow` lists `relatedFlows: [$payment-flow]` and `$payment-flow` lists `relatedFlows: [$checkout-flow]`. What does `
|
|
74
|
+
"question": "`$checkout-flow` lists `relatedFlows: [$payment-flow]` and `$payment-flow` lists `relatedFlows: [$checkout-flow]`. What does `paradigm_flow_check` report?",
|
|
75
75
|
"choices": {
|
|
76
76
|
"A": "No issues — bidirectional references are valid",
|
|
77
77
|
"B": "A circular dependency: $checkout-flow → $payment-flow → $checkout-flow",
|
|
@@ -714,7 +714,7 @@
|
|
|
714
714
|
{
|
|
715
715
|
"id": "architecture-review",
|
|
716
716
|
"title": "Putting It All Together",
|
|
717
|
-
"content": "## Building a Complete Feature\n\nYou have learned flows, gates, aspects, disciplines, naming conventions, component patterns, signal patterns, and cross-cutting concerns. Now let us walk through building a complete feature from scratch, using every tool in the Paradigm toolkit. The feature: **a team invitation system** where team admins can invite new members via email.\n\n## Step 1: Identify Components\n\nStart by listing the code units you will need:\n\n```yaml\n#invitation-service:\n description: Creates and manages team invitations\n tags: [feature, teams]\n\n#invitation-email:\n description: Sends invitation emails via SendGrid\n tags: [integration, sendgrid, email]\n\n#invitation-token:\n description: Generates and validates secure invitation tokens\n tags: [infrastructure, security]\n\n#invitation-store:\n description: Persists invitations with status tracking\n tags: [state, teams]\n```\n\nFour components — one feature, one integration, one infrastructure, one state. Each has a clear responsibility and appropriate tags.\n\n## Step 2: Define the Flow\n\nThe invitation process spans all four components in sequence:\n\n```yaml\n$team-invitation-flow:\n description: Admin invites a user, email is sent, user accepts and joins team\n steps:\n - component: \"#invitation-service\"\n action: create-invitation\n description: Validates admin permissions and creates invitation record\n - component: \"#invitation-token\"\n action: generate-token\n description: Creates a cryptographically secure token with 7-day expiry\n - component: \"#invitation-store\"\n action: persist-invitation\n description: Saves invitation with pending status\n - component: \"#invitation-email\"\n action: send-invite\n description: Sends email with accept link containing the token\n signals: [\"!invitation-sent\", \"!invitation-accepted\"]\n gates: [\"^authenticated\", \"^team-admin\"]\n```\n\n## Step 3: Add Gates\n\nTwo gates are needed. First, check `portal.yaml` for existing gates. `^authenticated` likely exists. `^team-admin` may need to be created:\n\n```yaml\n# In portal.yaml\ngates:\n ^team-admin:\n description: User must be an admin of the specified team\n check: team.admins.includes(req.user.id)\n type: role\n requires: [^authenticated]\n effects: []\n\nroutes:\n \"POST /api/teams/:id/invitations\": [^authenticated, ^team-admin]\n \"POST /api/invitations/:token/accept\": [^authenticated]\n \"GET /api/teams/:id/invitations\": [^authenticated, ^team-admin]\n \"DELETE /api/invitations/:id\": [^authenticated, ^team-admin]\n```\n\nNotice that accepting an invitation only requires `^authenticated` — any logged-in user with a valid token can accept. But creating, listing, and deleting invitations requires `^team-admin`.\n\n## Step 4: Define Signals\n\n```yaml\n!invitation-sent:\n description: An invitation email was successfully sent to a prospective team member\n emitters: [\"#invitation-service\"]\n category: business\n data:\n invitationId: string\n teamId: string\n email: string\n\n!invitation-accepted:\n description: A user accepted a team invitation and joined the team\n emitters: [\"#invitation-service\"]\n category: business\n data:\n invitationId: string\n teamId: string\n userId: string\n```\n\nThese business signals enable decoupled side effects — an analytics tracker can listen for `!invitation-accepted` to track conversion rates, and a notification service can alert existing team members.\n\n## Step 5: Apply Aspects\n\nCheck which aspects apply to the new components:\n\n- `~audit-required` applies to `#*Service` → `#invitation-service` is covered. Ensure the audit middleware is applied.\n- `~rate-limited` applies to `#*-handler` → Not directly applicable here (no handler component), but the API route should go through the rate limiter.\n- `~validated` applies to `#*-handler` → The invitation endpoint should validate input (email format, team existence).\n\n## Step 6: Write the .purpose File\n\nAssemble everything into `src/invitations/.purpose`:\n\n```yaml\nname: Team Invitations\ndescription: Team admin invitation system with email delivery and token-based acceptance\ncontext:\n - Invitation tokens expire after 7 days\n - Maximum 50 pending invitations per team\n - Uses SendGrid for email delivery\n\ncomponents:\n #invitation-service:\n description: Creates and manages team invitations\n file: invitation-service.ts\n tags: [feature, teams]\n flows: [\"$team-invitation-flow\"]\n signals: [\"!invitation-sent\", \"!invitation-accepted\"]\n gates: [\"^authenticated\", \"^team-admin\"]\n aspects: [\"~audit-required\"]\n # ... (remaining components)\n\nflows:\n $team-invitation-flow:\n # ... (as defined above)\n\nsignals:\n !invitation-sent:\n # ... (as defined above)\n !invitation-accepted:\n # ... (as defined above)\n```\n\n## Step 7: Validate\n\nBefore writing any implementation code, validate the Paradigm definitions:\n\n1. `paradigm_purpose_validate` — Checks the .purpose file for schema errors.\n2. `
|
|
717
|
+
"content": "## Building a Complete Feature\n\nYou have learned flows, gates, aspects, disciplines, naming conventions, component patterns, signal patterns, and cross-cutting concerns. Now let us walk through building a complete feature from scratch, using every tool in the Paradigm toolkit. The feature: **a team invitation system** where team admins can invite new members via email.\n\n## Step 1: Identify Components\n\nStart by listing the code units you will need:\n\n```yaml\n#invitation-service:\n description: Creates and manages team invitations\n tags: [feature, teams]\n\n#invitation-email:\n description: Sends invitation emails via SendGrid\n tags: [integration, sendgrid, email]\n\n#invitation-token:\n description: Generates and validates secure invitation tokens\n tags: [infrastructure, security]\n\n#invitation-store:\n description: Persists invitations with status tracking\n tags: [state, teams]\n```\n\nFour components — one feature, one integration, one infrastructure, one state. Each has a clear responsibility and appropriate tags.\n\n## Step 2: Define the Flow\n\nThe invitation process spans all four components in sequence:\n\n```yaml\n$team-invitation-flow:\n description: Admin invites a user, email is sent, user accepts and joins team\n steps:\n - component: \"#invitation-service\"\n action: create-invitation\n description: Validates admin permissions and creates invitation record\n - component: \"#invitation-token\"\n action: generate-token\n description: Creates a cryptographically secure token with 7-day expiry\n - component: \"#invitation-store\"\n action: persist-invitation\n description: Saves invitation with pending status\n - component: \"#invitation-email\"\n action: send-invite\n description: Sends email with accept link containing the token\n signals: [\"!invitation-sent\", \"!invitation-accepted\"]\n gates: [\"^authenticated\", \"^team-admin\"]\n```\n\n## Step 3: Add Gates\n\nTwo gates are needed. First, check `portal.yaml` for existing gates. `^authenticated` likely exists. `^team-admin` may need to be created:\n\n```yaml\n# In portal.yaml\ngates:\n ^team-admin:\n description: User must be an admin of the specified team\n check: team.admins.includes(req.user.id)\n type: role\n requires: [^authenticated]\n effects: []\n\nroutes:\n \"POST /api/teams/:id/invitations\": [^authenticated, ^team-admin]\n \"POST /api/invitations/:token/accept\": [^authenticated]\n \"GET /api/teams/:id/invitations\": [^authenticated, ^team-admin]\n \"DELETE /api/invitations/:id\": [^authenticated, ^team-admin]\n```\n\nNotice that accepting an invitation only requires `^authenticated` — any logged-in user with a valid token can accept. But creating, listing, and deleting invitations requires `^team-admin`.\n\n## Step 4: Define Signals\n\n```yaml\n!invitation-sent:\n description: An invitation email was successfully sent to a prospective team member\n emitters: [\"#invitation-service\"]\n category: business\n data:\n invitationId: string\n teamId: string\n email: string\n\n!invitation-accepted:\n description: A user accepted a team invitation and joined the team\n emitters: [\"#invitation-service\"]\n category: business\n data:\n invitationId: string\n teamId: string\n userId: string\n```\n\nThese business signals enable decoupled side effects — an analytics tracker can listen for `!invitation-accepted` to track conversion rates, and a notification service can alert existing team members.\n\n## Step 5: Apply Aspects\n\nCheck which aspects apply to the new components:\n\n- `~audit-required` applies to `#*Service` → `#invitation-service` is covered. Ensure the audit middleware is applied.\n- `~rate-limited` applies to `#*-handler` → Not directly applicable here (no handler component), but the API route should go through the rate limiter.\n- `~validated` applies to `#*-handler` → The invitation endpoint should validate input (email format, team existence).\n\n## Step 6: Write the .purpose File\n\nAssemble everything into `src/invitations/.purpose`:\n\n```yaml\nname: Team Invitations\ndescription: Team admin invitation system with email delivery and token-based acceptance\ncontext:\n - Invitation tokens expire after 7 days\n - Maximum 50 pending invitations per team\n - Uses SendGrid for email delivery\n\ncomponents:\n #invitation-service:\n description: Creates and manages team invitations\n file: invitation-service.ts\n tags: [feature, teams]\n flows: [\"$team-invitation-flow\"]\n signals: [\"!invitation-sent\", \"!invitation-accepted\"]\n gates: [\"^authenticated\", \"^team-admin\"]\n aspects: [\"~audit-required\"]\n # ... (remaining components)\n\nflows:\n $team-invitation-flow:\n # ... (as defined above)\n\nsignals:\n !invitation-sent:\n # ... (as defined above)\n !invitation-accepted:\n # ... (as defined above)\n```\n\n## Step 7: Validate\n\nBefore writing any implementation code, validate the Paradigm definitions:\n\n1. `paradigm_purpose_validate` — Checks the .purpose file for schema errors.\n2. `paradigm_flow_check` — Verifies the flow references valid components.\n3. `paradigm_aspect_check` — Confirms aspect anchors are valid for applied aspects.\n4. `paradigm_ripple` — Shows what existing code is affected by the new components.\n\n## The Pattern\n\nEvery feature follows this pattern: **identify components** → **define flows** → **add gates** → **define signals** → **apply aspects** → **write .purpose** → **validate** → **implement**. The implementation comes last — after the architecture is documented and validated. This front-loaded documentation pays dividends: AI agents can navigate the new feature immediately, security is defined before code, and the team has a clear map of what will be built.",
|
|
718
718
|
"keyConcepts": [
|
|
719
719
|
"Feature building follows: components → flows → gates → signals → aspects → .purpose → validate → implement",
|
|
720
720
|
"Implementation comes LAST, after architecture is documented",
|
|
@@ -257,11 +257,11 @@
|
|
|
257
257
|
{
|
|
258
258
|
"id": "doctor-and-validation",
|
|
259
259
|
"title": "Doctor & Validation",
|
|
260
|
-
"content": "## Doctor & Validation\n\nAs a Paradigm project evolves, its metadata can drift out of sync with the actual code. A component gets renamed but its `.purpose` file still references the old name. A gate is added to `portal.yaml` but never implemented. An aspect loses its code anchor when someone refactors the file it pointed to. Paradigm's validation tools catch these inconsistencies before they cause confusion.\n\nThe `paradigm doctor` CLI command runs a comprehensive health check across your entire project. It validates several categories of issues:\n\n- **Purpose file integrity**: Are all `.purpose` files valid YAML? Do all symbol references use correct prefixes?\n- **Portal.yaml consistency**: Do routes reference gates that are actually defined? Are there gates defined but never used?\n- **Aspect anchor verification**: Do all `~aspect` symbols have anchors? Do those anchors point to files and lines that still exist?\n- **Orphaned symbol detection**: Are there symbols defined in `.purpose` files that are never referenced anywhere else?\n- **Cross-reference validation**: When `#checkout-form` says it uses `$checkout-flow`, does that flow actually exist?\n\n```bash\n$ paradigm doctor\n\nChecking .purpose files...\n src/features/checkout/.purpose - OK\n src/features/auth/.purpose - WARNING: #legacy-login referenced but not defined\n src/services/.purpose - OK\n\nChecking portal.yaml...\n ^authenticated - OK (used in 12 routes)\n ^project-admin - WARNING: defined but used in 0 routes\n\nChecking aspects...\n ~audit-required - ERROR: anchor src/middleware/audit.ts:15-35 not found\n ~rate-limited - OK\n\nResults: 2 warnings, 1 error\n```\n\nFor more targeted validation, the MCP tool `paradigm_purpose_validate` lets you check a specific `.purpose` file or validate all files. You can also include portal.yaml validation with the `includePortal` parameter. This is useful after making changes to a specific area -- run validation on just the files you touched rather than the entire project.\n\nThe `
|
|
260
|
+
"content": "## Doctor & Validation\n\nAs a Paradigm project evolves, its metadata can drift out of sync with the actual code. A component gets renamed but its `.purpose` file still references the old name. A gate is added to `portal.yaml` but never implemented. An aspect loses its code anchor when someone refactors the file it pointed to. Paradigm's validation tools catch these inconsistencies before they cause confusion.\n\nThe `paradigm doctor` CLI command runs a comprehensive health check across your entire project. It validates several categories of issues:\n\n- **Purpose file integrity**: Are all `.purpose` files valid YAML? Do all symbol references use correct prefixes?\n- **Portal.yaml consistency**: Do routes reference gates that are actually defined? Are there gates defined but never used?\n- **Aspect anchor verification**: Do all `~aspect` symbols have anchors? Do those anchors point to files and lines that still exist?\n- **Orphaned symbol detection**: Are there symbols defined in `.purpose` files that are never referenced anywhere else?\n- **Cross-reference validation**: When `#checkout-form` says it uses `$checkout-flow`, does that flow actually exist?\n\n```bash\n$ paradigm doctor\n\nChecking .purpose files...\n src/features/checkout/.purpose - OK\n src/features/auth/.purpose - WARNING: #legacy-login referenced but not defined\n src/services/.purpose - OK\n\nChecking portal.yaml...\n ^authenticated - OK (used in 12 routes)\n ^project-admin - WARNING: defined but used in 0 routes\n\nChecking aspects...\n ~audit-required - ERROR: anchor src/middleware/audit.ts:15-35 not found\n ~rate-limited - OK\n\nResults: 2 warnings, 1 error\n```\n\nFor more targeted validation, the MCP tool `paradigm_purpose_validate` lets you check a specific `.purpose` file or validate all files. You can also include portal.yaml validation with the `includePortal` parameter. This is useful after making changes to a specific area -- run validation on just the files you touched rather than the entire project.\n\nThe `paradigm_flow_check` tool specifically validates flow definitions. It checks that gates referenced in flow steps exist in `portal.yaml`, that actions described in steps have corresponding implementations in the codebase (when `checkImplementation` is true), and that signals emitted during the flow are properly defined.\n\nA good rhythm is to run `paradigm doctor` after major changes (adding features, refactoring, renaming symbols) and before committing. Many teams integrate it into their pre-commit hooks or CI pipelines. Think of it as a linter for your Paradigm metadata -- catching problems early is always cheaper than debugging them later.\n\n### Clarification Markers\n\nWhen a requirement is ambiguous or incomplete in a `.purpose` file, use the `[NEEDS CLARIFICATION: ...]` marker format instead of guessing. For example:\n\n```yaml\ncomponents:\n payment-processor:\n description: \"Processes payments via Stripe [NEEDS CLARIFICATION: should this support PayPal fallback?]\"\n```\n\nClarification markers are reported as **warnings** (not errors) by both `paradigm doctor` and `paradigm_purpose_validate`. They do not block validation or break builds, but they surface during health checks to remind the team that a design question remains open. The exact format `[NEEDS CLARIFICATION: <question>]` is required -- the tooling scans for this specific prefix in all description fields across `.purpose` files. Resolve all markers before shipping by replacing them with the clarified text.",
|
|
261
261
|
"keyConcepts": [
|
|
262
262
|
"paradigm doctor CLI command",
|
|
263
263
|
"paradigm_purpose_validate MCP tool",
|
|
264
|
-
"
|
|
264
|
+
"paradigm_flow_check",
|
|
265
265
|
"Aspect anchor verification",
|
|
266
266
|
"Orphaned symbol detection"
|
|
267
267
|
],
|
|
@@ -307,7 +307,7 @@
|
|
|
307
307
|
},
|
|
308
308
|
{
|
|
309
309
|
"id": "q4",
|
|
310
|
-
"question": "What does
|
|
310
|
+
"question": "What does paradigm_flow_check check when checkImplementation is set to true?",
|
|
311
311
|
"choices": {
|
|
312
312
|
"A": "Only YAML syntax of the flow definition",
|
|
313
313
|
"B": "That flow steps reference existing gates, actions are implemented in code, and signals are defined",
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
"E": "Only that gate names match portal.yaml"
|
|
317
317
|
},
|
|
318
318
|
"correct": "B",
|
|
319
|
-
"explanation": "With checkImplementation enabled,
|
|
319
|
+
"explanation": "With checkImplementation enabled, paradigm_flow_check performs a deep check: verifying that gates exist in portal.yaml, that actions described in flow steps have corresponding implementations in the codebase, and that emitted signals are properly defined."
|
|
320
320
|
},
|
|
321
321
|
{
|
|
322
322
|
"id": "q5",
|
|
@@ -617,9 +617,9 @@
|
|
|
617
617
|
{
|
|
618
618
|
"id": "context-management",
|
|
619
619
|
"title": "Context Management",
|
|
620
|
-
"content": "## Context Management\n\nAI agents operate within a finite context window. Every file read, every tool call response, and every message in the conversation consumes tokens from that budget. When the context fills up, the agent loses the ability to recall earlier information, make coherent plans, or maintain awareness of all the changes it has made. Paradigm provides tools to monitor, manage, and gracefully handle context limits.\n\n**`
|
|
620
|
+
"content": "## Context Management\n\nAI agents operate within a finite context window. Every file read, every tool call response, and every message in the conversation consumes tokens from that budget. When the context fills up, the agent loses the ability to recall earlier information, make coherent plans, or maintain awareness of all the changes it has made. Paradigm provides tools to monitor, manage, and gracefully handle context limits.\n\n**`paradigm_session_health`** monitors current context usage. Call it periodically during long sessions (every 10-15 tool calls is a good cadence) to get a recommendation. The response tells you whether to \"continue\" (plenty of room), \"be-cautious\" (usage is climbing), or \"handoff-soon\" (>85% consumed). You can optionally pass your estimated total tokens and context window size for more accurate assessment.\n\n```\nparadigm_session_health({\n contextWindowSize: 200000,\n estimatedTotalTokens: 150000\n})\n// Recommendation: \"handoff-soon\" -- context at ~75%, prepare handoff\n```\n\nWhen a handoff is needed, **`paradigm_handoff_prepare`** creates a structured summary of the current session. It captures what was done, which symbols were touched, which files were modified, what still needs to happen, and any open questions. This summary becomes the starting point for the next session.\n\n```\nparadigm_handoff_prepare({\n summary: \"Implemented Apple Pay in checkout flow\",\n symbolsTouched: [\"#payment-service\", \"$checkout-flow\", \"#apple-pay-button\"],\n modifiedFiles: [\"src/services/payment.ts\", \"src/components/checkout/ApplePayButton.tsx\"],\n nextSteps: [\"Add unit tests for Apple Pay handler\", \"Update portal.yaml with new gates\"],\n openQuestions: [\"Should we support Apple Pay in the mobile app too?\"]\n})\n```\n\nOn the receiving end, **`paradigm_session_recover`** loads breadcrumbs from the previous session. A new agent session calls this at startup to understand what was done before, pick up where the last session left off, and avoid redoing work.\n\nFor cost awareness, **`paradigm_session_stats`** shows the current session's MCP interactions, estimated token usage, and cost breakdown. This is useful for understanding which operations are expensive and optimizing your workflow.\n\nThe context management workflow forms a cycle: **monitor** usage with context_check, **prepare** handoff when limits approach, **recover** in new sessions with session_recover, and **track** costs with session_stats. Mastering this cycle means you can handle tasks that are larger than any single context window by splitting them across multiple sessions without losing progress.",
|
|
621
621
|
"keyConcepts": [
|
|
622
|
-
"
|
|
622
|
+
"paradigm_session_health for monitoring",
|
|
623
623
|
"paradigm_handoff_prepare for session transfer",
|
|
624
624
|
"paradigm_session_recover for continuity",
|
|
625
625
|
"paradigm_session_stats for cost tracking",
|
|
@@ -628,7 +628,7 @@
|
|
|
628
628
|
"quiz": [
|
|
629
629
|
{
|
|
630
630
|
"id": "q1",
|
|
631
|
-
"question": "How often should you call
|
|
631
|
+
"question": "How often should you call paradigm_session_health during a long session?",
|
|
632
632
|
"choices": {
|
|
633
633
|
"A": "Only at the start of the session",
|
|
634
634
|
"B": "Every 10-15 tool calls",
|
|
@@ -641,7 +641,7 @@
|
|
|
641
641
|
},
|
|
642
642
|
{
|
|
643
643
|
"id": "q2",
|
|
644
|
-
"question": "
|
|
644
|
+
"question": "paradigm_session_health returns 'handoff-soon'. What should you do?",
|
|
645
645
|
"choices": {
|
|
646
646
|
"A": "Ignore it and keep working",
|
|
647
647
|
"B": "Immediately stop all work",
|
|
@@ -750,7 +750,7 @@
|
|
|
750
750
|
{
|
|
751
751
|
"id": "operations-review",
|
|
752
752
|
"title": "Operational Excellence",
|
|
753
|
-
"content": "## Operational Excellence\n\nThis lesson brings together everything from PARA 301 into a cohesive daily workflow. Operational excellence in Paradigm is not about memorizing individual tools -- it is about building habits that keep your project healthy, your metadata accurate, and your development sessions productive.\n\n### The Operational Loop\n\nEvery development session follows a predictable pattern:\n\n**1. Orient** -- Start by calling `paradigm_status` to see the project overview: how many symbols are defined, recent changes, any outstanding issues. If this is a continuation session, call `paradigm_session_recover` to load context from the previous session.\n\n**2. Discover** -- Before touching code, check for existing protocols: call `paradigm_protocol_search` with your task description. If a match exists, follow its steps and skip exploration. Otherwise, call `paradigm_wisdom_context` with the symbols you plan to modify to learn team conventions and avoid known pitfalls. Use `paradigm_navigate` with the \"context\" intent to find all relevant files for your task.\n\n**3. Assess Risk** -- Run `paradigm_ripple` on every symbol you plan to modify to understand the blast radius. Check `paradigm_history_fragility` on anything flagged as a dependency. If the task is complex (3+ files, security + implementation), call `paradigm_orchestrate_inline` with mode=\"plan\" to get the right agent team.\n\n**4. Implement** -- Write code, updating `.purpose` files as you go. If you add routes, update `portal.yaml`. If you add signals, register them. Do not defer metadata updates to \"later\" -- later never comes.\n\n**5. Validate** -- Run `paradigm doctor` or `paradigm_purpose_validate` to catch any drift. Use `
|
|
753
|
+
"content": "## Operational Excellence\n\nThis lesson brings together everything from PARA 301 into a cohesive daily workflow. Operational excellence in Paradigm is not about memorizing individual tools -- it is about building habits that keep your project healthy, your metadata accurate, and your development sessions productive.\n\n### The Operational Loop\n\nEvery development session follows a predictable pattern:\n\n**1. Orient** -- Start by calling `paradigm_status` to see the project overview: how many symbols are defined, recent changes, any outstanding issues. If this is a continuation session, call `paradigm_session_recover` to load context from the previous session.\n\n**2. Discover** -- Before touching code, check for existing protocols: call `paradigm_protocol_search` with your task description. If a match exists, follow its steps and skip exploration. Otherwise, call `paradigm_wisdom_context` with the symbols you plan to modify to learn team conventions and avoid known pitfalls. Use `paradigm_navigate` with the \"context\" intent to find all relevant files for your task.\n\n**3. Assess Risk** -- Run `paradigm_ripple` on every symbol you plan to modify to understand the blast radius. Check `paradigm_history_fragility` on anything flagged as a dependency. If the task is complex (3+ files, security + implementation), call `paradigm_orchestrate_inline` with mode=\"plan\" to get the right agent team.\n\n**4. Implement** -- Write code, updating `.purpose` files as you go. If you add routes, update `portal.yaml`. If you add signals, register them. Do not defer metadata updates to \"later\" -- later never comes.\n\n**5. Validate** -- Run `paradigm doctor` or `paradigm_purpose_validate` to catch any drift. Use `paradigm_flow_check` if you modified flows. Record the implementation with `paradigm_history_record`.\n\n**6. Capture Knowledge** -- Did you discover an antipattern? Record it with `paradigm_wisdom_record`. Did you make an architectural decision? Record that too. Did the implementation follow a repeatable pattern? Record a protocol with `paradigm_protocol_record`. Did the implementation reveal a fragile area? Note it for the team.\n\n**7. Monitor Context** -- Check `paradigm_session_health` periodically. If approaching limits, prepare a handoff.\n\n### Common Pitfalls\n\n- **Skipping wisdom checks**: Leads to repeating mistakes the team already knows about\n- **Skipping ripple analysis**: Leads to breaking downstream dependencies\n- **Deferring metadata updates**: Leads to stale `.purpose` files and misleading navigation\n- **Ignoring fragility warnings**: Leads to cascading failures in unstable areas\n- **Not recording history**: Loses the trail that fragility analysis depends on\n\n### The Measure of Excellence\n\nA well-operated Paradigm project has: accurate `.purpose` files that match the code, a `portal.yaml` that reflects all protected routes, wisdom entries that prevent repeated mistakes, history records that enable fragility analysis, and context handoffs that allow seamless multi-session work. When all of these are in place, every AI agent session starts with full context and every change is informed by the project's complete institutional knowledge.",
|
|
754
754
|
"keyConcepts": [
|
|
755
755
|
"The operational loop: orient, discover, assess, implement, validate, capture, monitor",
|
|
756
756
|
"Combining tools for comprehensive safety",
|
|
@@ -793,7 +793,7 @@
|
|
|
793
793
|
"B": "Recording too much history",
|
|
794
794
|
"C": "Deferring .purpose file updates to 'later', causing metadata to go stale",
|
|
795
795
|
"D": "Using paradigm_navigate instead of reading files",
|
|
796
|
-
"E": "Calling
|
|
796
|
+
"E": "Calling paradigm_session_health every 10 tool calls"
|
|
797
797
|
},
|
|
798
798
|
"correct": "C",
|
|
799
799
|
"explanation": "Deferring metadata updates is one of the most common pitfalls. When .purpose files go stale, navigation becomes misleading, ripple analysis produces incorrect results, and doctor generates false positives. The rule is: update metadata as you code, not after."
|