chainlesschain 0.166.105 → 0.166.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -8
- package/package.json +2 -2
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-CcD-AVDw.js → AIOps-DCx6L_HW.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CYy-g36A.js → ActionButton-DYm1CN3Z.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DPFDNaBL.js → Analytics-D5ItUS_y.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-PVIuRdgN.js → AppLayout-Cb7XeRdH.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BXGD3bM-.js → Artifacts-DDDeqCDQ.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Bu5s_4tu.js → Audit-BRt3x13w.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BHmgpnzo.js → BackgroundAgents-C_oNALMd.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-C872jURx.js → Backup-PSU2p6CR.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Bh7xO30H.js → BaseInput-G3oL4hcX.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DaacK53T.js → Chat-C2cLI10b.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-PYrSKMM_.js → ChatBubbleRenderer-KX1OITf8.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Cnt7_8I2.js → Checkbox-CHLnEgFD.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-AZRz6kmW.js → Codegen-DZm9g_Bc.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BtOXzMFt.js → Col-D5Z4zSay.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BFmFygS7.js → Community-DHw69NSk.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-2z5CfKpR.js → Compact-B-vjYNWz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-B5hKrPVF.js → Compliance-DaIYVZQY.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CxEyp2ww.js → Cowork-CoA9U-gF.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B-8f9_qF.js → Cron-DXqmxlRC.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-XARMOcc4.js → Crosschain-Cdkc3ue1.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DwLtEKAe.js → DID-oKfYyNSR.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cjw0L_iA.js → Dashboard-n_ycvgWu.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BBGWIP7l.js → Dropdown-D38rZ8WY.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DG4kZFkm.js → EmailListRenderer-BjreeBQ1.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-D8vuNDde.js → EvolutionSettings-CTxA_SIq.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-COXCzDXI.js → FamilyGuardDashboard-DmECNwV5.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Btb-aMhW.js → Federation-B2IaaDmQ.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-TO-E6l6e.js → FormItemContext-DgcgqUIk.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BWXdJCT0.js → GenericCardRenderer-B1-du6Qm.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B6icGhEv.js → Git-XceM21Il.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C5Y__K6S.js → Governance-CV97iz3z.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DZGEKnbN.js → Inference-CI7fj305.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph--Kga5yvm.js → KnowledgeGraph-B5mekWRy.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BXs3EPKj.js → Logs-BlxFA0xY.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-rDE-XyMY.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-JSEAu0su.js → Marketplace-DL1BVCiX.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BUBifkKP.js → McpTools-BPtwrO3c.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Cb7sE4a-.js → Memory-DuSNw4E-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BOzmmNV2.js → MobileBridge-DTgY9ywI.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-CTpVHJMa.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-DmMWErG1.js → Mtc-h4fCLjXw.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DnGkRVXF.js → MtcAudit-fqMDY3-w.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-C3mzascL.js → Multisig-Do3FehBL.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CrmMZZ1t.js → NLProgramming-CQVY0kQF.js} +1 -1
- package/src/assets/web-panel/assets/Notes-4c3oNvWh.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-gn3UrWwW.js → NotificationSettings-BKr2JD4k.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Bq4jgzRt.js +1 -0
- package/src/assets/web-panel/assets/{Organization-fMlkdgpW.js → Organization-Dy3XidyA.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DGwCUPU1.js → Overflow-DFF0qN5K.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BDGcpPmf.js → P2P-DAgYYykd.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CccRPAB9.js → PdhVaultBrowser-DgNHa8b1.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C33dNECx.js → Permissions-Cev6uSBc.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BeqbCStc.js → PersonalDataHub-DJzbN06K.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CTmasgbQ.js → Pipeline-CoJWvbQ5.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-ktd37BSp.js → Privacy-DZxV6etm.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-KOGvQtBX.js → ProjectInit-BFW87JnM.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CUvH_hC6.js → ProjectSettings-LBrRT27p.js} +2 -2
- package/src/assets/web-panel/assets/Projects-O3uz76R1.js +1 -0
- package/src/assets/web-panel/assets/{Providers-C-hmLXlO.js → Providers-CnRbjOYk.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DzG_rbSL.js → QrScannerModal-BVFnIS3r.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-ShwiATg4.js → QuickAsk-DrcHx5f1.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DkV8Ruep.js → Recommend-CbRgrSJm.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Ca2dOx_G.js → RemoteSession-B2Uz_ElB.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DYA5BJ6A.js → Reputation-DS0ljTxL.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DvGDgxLS.js → Row-ClLobFht.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DbwTBSPw.js → RssFeed-DxxcTD0x.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C5XAMQ9T.js → Search-BbHN0Fik.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CKWT60Qt.js → Security-BAVU_EcY.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CZvASlWL.js → Services-CtqRSVq_.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DFkMVqws.js → Skeleton-IJ8ZKdSZ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-hslZ_GyP.js → Skills-DXxcznnO.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BLW5rmZ5.js → Sla-fRkhnA3i.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cn4ffCi5.js → SpeechSettings-Bi8sYJ-I.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-D1K0nJuo.js → SyncSettings-CjeplUtS.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CCRu0xoN.js → Tasks-D4KB2Hbx.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-L19GYuS4.js → Templates-BwVugi8n.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CZ6HE3PF.js → Tenant-CsPuu5xK.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BiAwzaBT.js → Terminal-DuaeOPjY.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DRHSWQT5.js → TimelineRenderer-D-PMrFxO.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Cm-XATgh.js → Tokens-BXZuiQPZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BVXtx3kn.js → Trigger-DgpTaHL3.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Bb0TmkLJ.js → Trust-Bn7lEGRY.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Dbt9R7l0.js → UkeySign-zz-8JAAQ.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-z0-Ti8eJ.js → VideoEditing-DCzfQGTc.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BZh31tI-.js → Wallet-BiRHM_zB.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DQ0yIr5K.js → WebAuthn-QmPo2JwU.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DCt_yuWG.js → WorkflowEditor-gL7SsPnY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BLgtmFeS.js → chat-BysvK4hk.js} +1 -1
- package/src/assets/web-panel/assets/{colors-xU4UH8M1.js → colors-CQq20vqN.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C4w4v16T.js → compact-item-CAHlOf1X.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CZM9hAaj.js → createContext-BeF3ESj_.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-D-Iugqxv.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DvHqEpE7.js → hasIn-CiqnRf-U.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkTKWAgq.js → index-4a0Lmz_y.js} +1 -1
- package/src/assets/web-panel/assets/index-B0Oz2_rQ.js +1 -0
- package/src/assets/web-panel/assets/{index-B0IvKEVO.js → index-B2AOvjgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaQZvM4m.js → index-B2xbtl_c.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRhD9RMV.js → index-B5941vyo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqDiY-jl.js → index-BHpHGGmB.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQEzxnYS.js → index-BOiyW31p.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTxhDCtg.js → index-BcVmt6u_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPDw21XY.js → index-BfJabF_8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CExiTobS.js → index-Br5tGVbC.js} +1 -1
- package/src/assets/web-panel/assets/{index-QHmhwgfc.js → index-BsnLkZjz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlN5KPq6.js → index-BtWchYfW.js} +1 -1
- package/src/assets/web-panel/assets/{index-SNV95Zen.js → index-Bvkbj3x-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHK3CQHq.js → index-CCX0daFQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPC7OGCe.js → index-CImCEo8S.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKugxsw3.js → index-CTp89vmg.js} +1 -1
- package/src/assets/web-panel/assets/{index-55Rkd1KA.js → index-CcccefJc.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds6wKTMh.js → index-CeIL3-nY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DifMvnMQ.js → index-CgkUkmEJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bf8Wm4ks.js → index-CowbNBJs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cm00787d.js → index-Cp3IRTDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9YnZFv2.js → index-D7q5VH2n.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHg9NoJ5.js → index-DBmGQHEz.js} +3 -3
- package/src/assets/web-panel/assets/{index-B6AQ2b5U.js → index-DHGtFwwR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYrQnkqA.js → index-DKYbru3i.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyV8fNBg.js → index-DTPUVm71.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4jIcYSv.js → index-DXT7MKkD.js} +1 -1
- package/src/assets/web-panel/assets/{index-B64Vf-8H.js → index-DXsXhR7p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpiuuIww.js → index-Dqkls2_6.js} +1 -1
- package/src/assets/web-panel/assets/index-DwoycEQa.js +1 -0
- package/src/assets/web-panel/assets/{index-DGdLkss8.js → index-QALafVsT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds1tM734.js → index-TdVEaJfk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bh14b1k0.js → index-ZBuJ6O6g.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6ZrTSw5.js → index-i9aJV9qk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF9ebAIB.js → index-jJhemX1R.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIWumeQl.js → index-qjaCk1Mj.js} +1 -1
- package/src/assets/web-panel/assets/{index-n6SAUmmI.js → index-xwtRrgVY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRLP56-W.js → index-yFQWSRoW.js} +1 -1
- package/src/assets/web-panel/assets/{index-wYRjvvbl.js → index-zNkw0IY7.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C44ZER6c.js → initDefaultProps-BQR2HnKb.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DbNzzScd.js → motion-gAz6l-nZ.js} +1 -1
- package/src/assets/web-panel/assets/{move-BrRrDH2u.js → move-Cy5TN856.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DZ_T_Pw8.js → mtc-parser-BeT7VrGi.js} +1 -1
- package/src/assets/web-panel/assets/{omit-5QHHk_V3.js → omit-BLN3mlgK.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BdxEl0G2.js → pickAttrs-DtwZ8u2d.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CGyD615D.js → placementArrow-ViMwQSa-.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-QqcWAQmN.js → responsiveObserve-dEL3u4E7.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BumQrJ5R.js → slide-l05us-Gz.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Pf64olM7.js → statusUtils-Bk-Qn2Og.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DNwm5SQZ.js → styleChecker-Bn186qeY.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-c3gLKs6e.js → useFlexGapSupport-WP-ugR3H.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-TzTd6NDM.js → useFs-1SvoeSCL.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BP5E_0Fe.js → usePersonalDataHub-CfNU8N3z.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CVEkRfZU.js → vnode-Bd2Ya101.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-C18X_8TJ.js → zoom-Def_MeZv.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agent.js +20 -20
- package/src/commands/goal.js +299 -1
- package/src/commands/plugin.js +129 -68
- package/src/constants.js +2 -2
- package/src/data/changelog.json +26 -0
- package/src/lib/cli-goal-catalog.js +129 -0
- package/src/lib/cli-goal-source.js +119 -0
- package/src/lib/coding-task-guidance.js +3 -1
- package/src/lib/config-schema.js +1 -1
- package/src/lib/eval/stream-terminal.js +27 -2
- package/src/lib/evolution/evolution-artifact-ports.js +22 -11
- package/src/lib/evolution/evolution-file-witness.js +86 -63
- package/src/lib/evolution/evolution-ledger-file-backend.js +22 -0
- package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +34 -35
- package/src/lib/evolution/evolution-ledger-file-manifest-head-store.js +32 -39
- package/src/lib/evolution/evolution-ledger.js +367 -169
- package/src/lib/evolution/evolution-manifest-state-reader.js +58 -0
- package/src/lib/evolution/evolution-physical-state-reader.js +308 -0
- package/src/lib/evolution/evolution-witness-segments.js +12 -13
- package/src/lib/evolution/governed-wiki-pruning-ledger-adapter.js +82 -56
- package/src/lib/evolution/rrsi-observed-text-index.js +17 -1
- package/src/lib/evolution/rrsi-tenant-index-anchor-history.js +5 -0
- package/src/lib/execution-location-failure-site.js +20 -3
- package/src/lib/goal-store.js +8 -1
- package/src/lib/image-input.js +43 -14
- package/src/lib/llm-providers.js +1 -0
- package/src/lib/plugin-runtime/capabilities.js +10 -0
- package/src/lib/plugin-runtime/cli-goal-draft-request.js +138 -0
- package/src/lib/plugin-runtime/cli-goal-drafts.js +413 -0
- package/src/lib/plugin-runtime/cli-goal-extension-host.js +234 -0
- package/src/lib/plugin-runtime/examples/goal-description-drafter/plugin.json +17 -0
- package/src/lib/plugin-runtime/examples/goal-evidence-viewer/plugin.json +25 -0
- package/src/lib/plugin-runtime/examples/goal-progress-viewer/plugin.json +21 -0
- package/src/lib/plugin-runtime/examples/project-delivery-assistant/plugin.json +38 -0
- package/src/lib/plugin-runtime/goal-extension-contract.js +190 -0
- package/src/lib/plugin-runtime/goal-extensions.js +277 -0
- package/src/lib/plugin-runtime/install.js +40 -40
- package/src/lib/plugin-runtime/manifest.js +12 -0
- package/src/lib/plugin-runtime/policy.js +1 -0
- package/src/lib/project-goal-connection.js +225 -0
- package/src/lib/project-goal-draft-connection.js +217 -0
- package/src/lib/provider-http-error.js +4 -5
- package/src/lib/task-model-selector.js +1 -1
- package/src/repl/agent-repl.js +14 -7
- package/src/repl/config-summary.js +1 -1
- package/src/runtime/agent-core.js +1 -1
- package/src/runtime/coding-agent-contract-shared.cjs +3 -2
- package/src/runtime/headless-stream.js +4 -6
- package/src/runtime/policies/agent-policy.js +1 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-BsSiyE-A.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-ClRlavdF.js +0 -1
- package/src/assets/web-panel/assets/Notes-4S6uts9Q.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-CDVAlBUf.js +0 -1
- package/src/assets/web-panel/assets/Projects-BvP_Os-1.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BZUZgMkO.js +0 -1
- package/src/assets/web-panel/assets/index--_-pNhk0.js +0 -1
- package/src/assets/web-panel/assets/index-ftwO31cp.js +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "goal-progress-viewer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Read-only summary of an explicitly selected standalone CLI goal",
|
|
5
|
+
"permissions": { "goalExtension": ["panel:goal.summary"] },
|
|
6
|
+
"goalExtension": {
|
|
7
|
+
"apiVersion": "1.0.0",
|
|
8
|
+
"hosts": { "cli": ">=0.166.104" },
|
|
9
|
+
"events": [],
|
|
10
|
+
"panels": [
|
|
11
|
+
{
|
|
12
|
+
"id": "goal-progress",
|
|
13
|
+
"title": "Goal progress",
|
|
14
|
+
"slot": "goal.summary",
|
|
15
|
+
"fields": ["objective", "status"],
|
|
16
|
+
"fallback": "text"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"proposals": []
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "project-delivery-assistant",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Declarative project delivery assistant prototype; requires a goal extension host adapter",
|
|
5
|
+
"permissions": {
|
|
6
|
+
"goalExtension": [
|
|
7
|
+
"event:goal.status.changed",
|
|
8
|
+
"event:risk.review.completed",
|
|
9
|
+
"event:action.receipt.updated",
|
|
10
|
+
"panel:goal.evidence",
|
|
11
|
+
"proposal:task.create",
|
|
12
|
+
"proposal:task.description.update"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"goalExtension": {
|
|
16
|
+
"apiVersion": "1.0.0",
|
|
17
|
+
"hosts": {
|
|
18
|
+
"cli": ">=0.166.104",
|
|
19
|
+
"vscode": ">=0.37.149",
|
|
20
|
+
"jetbrains": ">=0.4.166"
|
|
21
|
+
},
|
|
22
|
+
"events": [
|
|
23
|
+
"goal.status.changed",
|
|
24
|
+
"risk.review.completed",
|
|
25
|
+
"action.receipt.updated"
|
|
26
|
+
],
|
|
27
|
+
"panels": [
|
|
28
|
+
{
|
|
29
|
+
"id": "delivery-evidence",
|
|
30
|
+
"title": "Project delivery evidence",
|
|
31
|
+
"slot": "goal.evidence",
|
|
32
|
+
"fields": ["objective", "status", "riskSummary", "receiptSummary"],
|
|
33
|
+
"fallback": "text"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"proposals": ["task.create", "task.description.update"]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/** DMM-07: data-only declarations. Compatibility never grants execution. */
|
|
2
|
+
import semver from "semver";
|
|
3
|
+
|
|
4
|
+
export const GOAL_EXTENSION_API_VERSION = "1.0.0";
|
|
5
|
+
export const GOAL_EXTENSION_HOSTS = Object.freeze([
|
|
6
|
+
"cli",
|
|
7
|
+
"vscode",
|
|
8
|
+
"jetbrains",
|
|
9
|
+
"desktop",
|
|
10
|
+
]);
|
|
11
|
+
export const GOAL_EXTENSION_EVENTS = Object.freeze([
|
|
12
|
+
"goal.status.changed",
|
|
13
|
+
"risk.review.completed",
|
|
14
|
+
"action.receipt.updated",
|
|
15
|
+
]);
|
|
16
|
+
export const GOAL_EXTENSION_SLOTS = Object.freeze([
|
|
17
|
+
"goal.summary",
|
|
18
|
+
"goal.evidence",
|
|
19
|
+
"goal.actions",
|
|
20
|
+
]);
|
|
21
|
+
export const GOAL_EXTENSION_PROPOSALS = Object.freeze([
|
|
22
|
+
"task.create",
|
|
23
|
+
"task.description.update",
|
|
24
|
+
]);
|
|
25
|
+
const PANEL_FIELDS = ["objective", "status", "riskSummary", "receiptSummary"];
|
|
26
|
+
|
|
27
|
+
function object(value, keys, label) {
|
|
28
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
29
|
+
throw new Error(`${label} must be an object`);
|
|
30
|
+
for (const key of Object.keys(value)) {
|
|
31
|
+
if (!keys.includes(key))
|
|
32
|
+
throw new Error(`${label}: unsupported field ${key}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function text(value, label, max = 128) {
|
|
37
|
+
if (
|
|
38
|
+
typeof value !== "string" ||
|
|
39
|
+
!value.trim() ||
|
|
40
|
+
value.length > max ||
|
|
41
|
+
/[\u0000-\u001f\u007f]/.test(value)
|
|
42
|
+
)
|
|
43
|
+
throw new Error(`${label} must be non-empty text (max ${max})`);
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function list(value, allowed, label) {
|
|
48
|
+
if (
|
|
49
|
+
!Array.isArray(value) ||
|
|
50
|
+
value.length > 16 ||
|
|
51
|
+
value.some((entry) => !allowed.includes(entry)) ||
|
|
52
|
+
new Set(value).size !== value.length
|
|
53
|
+
)
|
|
54
|
+
throw new Error(
|
|
55
|
+
`${label} must be a unique list of supported values (max 16)`,
|
|
56
|
+
);
|
|
57
|
+
return [...value];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function requiredGoalExtensionCapabilities(extension) {
|
|
61
|
+
return [
|
|
62
|
+
...new Set([
|
|
63
|
+
...extension.events.map((event) => `event:${event}`),
|
|
64
|
+
...extension.panels.map((panel) => `panel:${panel.slot}`),
|
|
65
|
+
...extension.proposals.map((action) => `proposal:${action}`),
|
|
66
|
+
]),
|
|
67
|
+
].sort();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Unknown fields include code entrypoints, approval claims and receipt writers. */
|
|
71
|
+
export function normalizeGoalExtension(raw, permissions) {
|
|
72
|
+
if (raw === undefined) return null;
|
|
73
|
+
object(
|
|
74
|
+
raw,
|
|
75
|
+
["apiVersion", "hosts", "events", "panels", "proposals"],
|
|
76
|
+
"goalExtension",
|
|
77
|
+
);
|
|
78
|
+
const apiVersion = text(raw.apiVersion, "goalExtension.apiVersion");
|
|
79
|
+
if (!semver.valid(apiVersion))
|
|
80
|
+
throw new Error("goalExtension.apiVersion must be semver");
|
|
81
|
+
object(raw.hosts, GOAL_EXTENSION_HOSTS, "goalExtension.hosts");
|
|
82
|
+
if (!Object.keys(raw.hosts).length)
|
|
83
|
+
throw new Error("goalExtension.hosts must declare a host");
|
|
84
|
+
const hosts = {};
|
|
85
|
+
for (const [host, range] of Object.entries(raw.hosts)) {
|
|
86
|
+
text(range, `goalExtension.hosts.${host}`);
|
|
87
|
+
if (!semver.validRange(range))
|
|
88
|
+
throw new Error(`goalExtension.hosts.${host} must be a semver range`);
|
|
89
|
+
hosts[host] = range;
|
|
90
|
+
}
|
|
91
|
+
const events = list(
|
|
92
|
+
raw.events ?? [],
|
|
93
|
+
GOAL_EXTENSION_EVENTS,
|
|
94
|
+
"goalExtension.events",
|
|
95
|
+
);
|
|
96
|
+
const proposals = list(
|
|
97
|
+
raw.proposals ?? [],
|
|
98
|
+
GOAL_EXTENSION_PROPOSALS,
|
|
99
|
+
"goalExtension.proposals",
|
|
100
|
+
);
|
|
101
|
+
if (!Array.isArray(raw.panels ?? []) || (raw.panels ?? []).length > 16)
|
|
102
|
+
throw new Error("goalExtension.panels must be a list (max 16)");
|
|
103
|
+
const ids = new Set();
|
|
104
|
+
const panels = (raw.panels ?? []).map((panel) => {
|
|
105
|
+
object(
|
|
106
|
+
panel,
|
|
107
|
+
["id", "title", "slot", "fields", "fallback"],
|
|
108
|
+
"goalExtension.panel",
|
|
109
|
+
);
|
|
110
|
+
const id = text(panel.id, "goalExtension.panel.id", 64);
|
|
111
|
+
if (!/^[a-z][a-z0-9-]*$/.test(id) || ids.has(id))
|
|
112
|
+
throw new Error("goalExtension.panel.id must be unique kebab-case");
|
|
113
|
+
ids.add(id);
|
|
114
|
+
if (!GOAL_EXTENSION_SLOTS.includes(panel.slot))
|
|
115
|
+
throw new Error("goalExtension.panel.slot is unsupported");
|
|
116
|
+
if (panel.fallback !== "text")
|
|
117
|
+
throw new Error("goalExtension.panel.fallback must be text");
|
|
118
|
+
return {
|
|
119
|
+
id,
|
|
120
|
+
title: text(panel.title, "goalExtension.panel.title"),
|
|
121
|
+
slot: panel.slot,
|
|
122
|
+
fields: list(panel.fields, PANEL_FIELDS, "goalExtension.panel.fields"),
|
|
123
|
+
fallback: "text",
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
const extension = { apiVersion, hosts, events, panels, proposals };
|
|
127
|
+
const allowed = [
|
|
128
|
+
...GOAL_EXTENSION_EVENTS.map((event) => `event:${event}`),
|
|
129
|
+
...GOAL_EXTENSION_SLOTS.map((slot) => `panel:${slot}`),
|
|
130
|
+
...GOAL_EXTENSION_PROPOSALS.map((action) => `proposal:${action}`),
|
|
131
|
+
];
|
|
132
|
+
// Validate RAW permissions: permissive legacy coercion cannot admit this API.
|
|
133
|
+
object(permissions, Object.keys(permissions || {}), "permissions");
|
|
134
|
+
const grants = list(
|
|
135
|
+
permissions.goalExtension,
|
|
136
|
+
allowed,
|
|
137
|
+
"permissions.goalExtension",
|
|
138
|
+
);
|
|
139
|
+
for (const required of requiredGoalExtensionCapabilities(extension)) {
|
|
140
|
+
if (!grants.includes(required))
|
|
141
|
+
throw new Error(
|
|
142
|
+
`goalExtension requires permissions.goalExtension: ${required}`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return extension;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Pure version/capability check; callers must still check current authorization. */
|
|
149
|
+
export function checkGoalExtensionCompatibility(extension, host = {}) {
|
|
150
|
+
if (!extension) return { compatible: false, reason: "legacy_unsupported" };
|
|
151
|
+
if (!semver.eq(extension.apiVersion, GOAL_EXTENSION_API_VERSION))
|
|
152
|
+
return { compatible: false, reason: "unsupported_api" };
|
|
153
|
+
if (!Object.hasOwn(extension.hosts, host.id))
|
|
154
|
+
return { compatible: false, reason: "unsupported_host" };
|
|
155
|
+
if (
|
|
156
|
+
!semver.valid(host.version) ||
|
|
157
|
+
!semver.satisfies(host.version, extension.hosts[host.id])
|
|
158
|
+
)
|
|
159
|
+
return { compatible: false, reason: "host_version_mismatch" };
|
|
160
|
+
const supported = Array.isArray(host.capabilities) ? host.capabilities : [];
|
|
161
|
+
const missing = requiredGoalExtensionCapabilities(extension).filter(
|
|
162
|
+
(cap) => !supported.includes(cap),
|
|
163
|
+
);
|
|
164
|
+
return missing.length
|
|
165
|
+
? { compatible: false, reason: "unsupported_capabilities", missing }
|
|
166
|
+
: { compatible: true, reason: "compatible" };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Safe management summary; never an admission token or a claim of a live host. */
|
|
170
|
+
export function summarizeGoalExtension(manifest) {
|
|
171
|
+
const extension = manifest?.goalExtension;
|
|
172
|
+
if (!extension)
|
|
173
|
+
return {
|
|
174
|
+
status: manifest?.goalExtensionDeclared ? "invalid" : "legacy",
|
|
175
|
+
runtimeAvailable: false,
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
status: "declaration-only",
|
|
179
|
+
runtimeAvailable: false,
|
|
180
|
+
apiVersion: extension.apiVersion,
|
|
181
|
+
apiCompatible: semver.eq(extension.apiVersion, GOAL_EXTENSION_API_VERSION),
|
|
182
|
+
hosts: { ...extension.hosts },
|
|
183
|
+
events: [...extension.events],
|
|
184
|
+
panels: extension.panels.map((panel) => ({
|
|
185
|
+
...panel,
|
|
186
|
+
fields: [...panel.fields],
|
|
187
|
+
})),
|
|
188
|
+
proposals: [...extension.proposals],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import {
|
|
2
|
+
goalExtensionRef as goalRef,
|
|
3
|
+
normalizeGoalExtensionProposal,
|
|
4
|
+
} from "@chainlesschain/session-core/goal-extension-proposal-contract";
|
|
5
|
+
/**
|
|
6
|
+
* DMM-07 host boundary. Only trusted host code calls this module; plugins supply
|
|
7
|
+
* declarations, never callbacks. Re-discover for every delivery/proposal so a
|
|
8
|
+
* retained session cannot outlive disable, uninstall, policy or consent changes.
|
|
9
|
+
*/
|
|
10
|
+
import { discoverPlugins } from "./scopes.js";
|
|
11
|
+
import { loadManagedPluginPolicy, filterByManagedPolicy } from "./policy.js";
|
|
12
|
+
import { isPluginTrusted } from "./trust.js";
|
|
13
|
+
import { isPluginCapabilityConsented } from "./capability-consent.js";
|
|
14
|
+
import { checkGoalExtensionCompatibility } from "./goal-extension-contract.js";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { managedSettingsPath } from "../settings-loader.cjs";
|
|
17
|
+
|
|
18
|
+
export const _deps = {
|
|
19
|
+
discoverPlugins,
|
|
20
|
+
loadManagedPluginPolicy,
|
|
21
|
+
filterByManagedPolicy,
|
|
22
|
+
isPluginTrusted,
|
|
23
|
+
isPluginCapabilityConsented,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function fixedHostOptions(options) {
|
|
27
|
+
const env = Object.freeze({ ...(options.env || process.env) });
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
cwd: path.resolve(options.cwd || process.cwd()),
|
|
30
|
+
env,
|
|
31
|
+
managedSettingsFile: managedSettingsPath({
|
|
32
|
+
env,
|
|
33
|
+
managedSettingsFile: options.managedSettingsFile,
|
|
34
|
+
}),
|
|
35
|
+
host: Object.freeze({
|
|
36
|
+
id: options.host?.id,
|
|
37
|
+
version: options.host?.version,
|
|
38
|
+
capabilities: Object.freeze([...(options.host?.capabilities || [])]),
|
|
39
|
+
}),
|
|
40
|
+
authorize: options.authorize,
|
|
41
|
+
readEvent: options.readEvent,
|
|
42
|
+
readPanel: options.readPanel,
|
|
43
|
+
enqueueProposal: options.enqueueProposal,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Compatibility and mandatory consent are independent of legacy policy flags. */
|
|
48
|
+
export function collectGoalExtensions(options = {}) {
|
|
49
|
+
const extensions = [];
|
|
50
|
+
const dropped = [];
|
|
51
|
+
try {
|
|
52
|
+
const { cwd, env, managedSettingsFile, host } = fixedHostOptions(options);
|
|
53
|
+
const managed = _deps.loadManagedPluginPolicy({
|
|
54
|
+
env,
|
|
55
|
+
managedSettingsFile,
|
|
56
|
+
fresh: true,
|
|
57
|
+
});
|
|
58
|
+
const plugins = _deps.discoverPlugins({
|
|
59
|
+
cwd,
|
|
60
|
+
env,
|
|
61
|
+
managedSettingsFile,
|
|
62
|
+
skipPolicy: true,
|
|
63
|
+
includeDisabled: true,
|
|
64
|
+
includeBlocked: true,
|
|
65
|
+
});
|
|
66
|
+
for (const plugin of plugins) {
|
|
67
|
+
let reason = null;
|
|
68
|
+
try {
|
|
69
|
+
if (plugin.runtimeBlocked || plugin.manifest?.ok !== true)
|
|
70
|
+
reason = "invalid_plugin";
|
|
71
|
+
else if (plugin.enabled === false) reason = "disabled";
|
|
72
|
+
else if (!_deps.filterByManagedPolicy([plugin], managed).kept.length)
|
|
73
|
+
reason = "policy_blocked";
|
|
74
|
+
else {
|
|
75
|
+
const compatibility = checkGoalExtensionCompatibility(
|
|
76
|
+
plugin.manifest.goalExtension,
|
|
77
|
+
host,
|
|
78
|
+
);
|
|
79
|
+
if (!compatibility.compatible) reason = compatibility.reason;
|
|
80
|
+
else if (plugin.manifest.capabilitiesDeclared !== true)
|
|
81
|
+
reason = "capabilities_undeclared";
|
|
82
|
+
else if (
|
|
83
|
+
!_deps.isPluginTrusted({
|
|
84
|
+
...plugin,
|
|
85
|
+
workspaceRoot: cwd || process.cwd(),
|
|
86
|
+
})
|
|
87
|
+
)
|
|
88
|
+
reason = "untrusted";
|
|
89
|
+
else if (
|
|
90
|
+
!_deps.isPluginCapabilityConsented(
|
|
91
|
+
plugin,
|
|
92
|
+
plugin.manifest.capabilities,
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
reason = "consent_required";
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
reason = "authorization_unavailable";
|
|
99
|
+
}
|
|
100
|
+
if (reason)
|
|
101
|
+
dropped.push({ name: plugin.name, scope: plugin.scope, reason });
|
|
102
|
+
else
|
|
103
|
+
extensions.push({
|
|
104
|
+
name: plugin.name,
|
|
105
|
+
scope: plugin.scope,
|
|
106
|
+
version: plugin.version,
|
|
107
|
+
declaration: JSON.parse(
|
|
108
|
+
JSON.stringify(plugin.manifest.goalExtension),
|
|
109
|
+
),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
// Management I/O failure is never permission to continue with old state.
|
|
114
|
+
return { extensions: [], dropped: [{ reason: "discovery_unavailable" }] };
|
|
115
|
+
}
|
|
116
|
+
return { extensions, dropped };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function admittedPlugin(ref, options, kind, value) {
|
|
120
|
+
const plugin = collectGoalExtensions(options).extensions.find(
|
|
121
|
+
(entry) =>
|
|
122
|
+
entry.name === ref?.name &&
|
|
123
|
+
entry.scope === ref?.scope &&
|
|
124
|
+
entry.version === ref?.version,
|
|
125
|
+
);
|
|
126
|
+
if (!plugin) throw new Error("goal extension is not currently admitted");
|
|
127
|
+
if (kind && !plugin.declaration[kind].includes(value))
|
|
128
|
+
throw new Error(`goal extension ${kind} is undeclared`);
|
|
129
|
+
return plugin;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function authorize(callback, context) {
|
|
133
|
+
if (typeof callback !== "function" || (await callback(context)) !== true)
|
|
134
|
+
throw new Error("goal extension source authorization denied");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Deliver a bounded read-only view, checking source access again after I/O. */
|
|
138
|
+
export async function projectGoalExtensionEvent(ref, request, options = {}) {
|
|
139
|
+
options = fixedHostOptions(options);
|
|
140
|
+
const type = request?.type;
|
|
141
|
+
const plugin = admittedPlugin(ref, options, "events", type);
|
|
142
|
+
const source = goalRef(request.goalRef);
|
|
143
|
+
const context = Object.freeze({
|
|
144
|
+
plugin: Object.freeze({
|
|
145
|
+
name: plugin.name,
|
|
146
|
+
scope: plugin.scope,
|
|
147
|
+
version: plugin.version,
|
|
148
|
+
}),
|
|
149
|
+
goalRef: source,
|
|
150
|
+
operation: "read-event",
|
|
151
|
+
type,
|
|
152
|
+
});
|
|
153
|
+
await authorize(options.authorize, context);
|
|
154
|
+
if (typeof options.readEvent !== "function")
|
|
155
|
+
throw new Error("host event reader unavailable");
|
|
156
|
+
const data = await options.readEvent(context);
|
|
157
|
+
await authorize(options.authorize, context);
|
|
158
|
+
admittedPlugin(context.plugin, options, "events", type);
|
|
159
|
+
// The host reader owns object access. Never spread raw goal/memory/receipt data.
|
|
160
|
+
if (
|
|
161
|
+
!data ||
|
|
162
|
+
typeof data.summary !== "string" ||
|
|
163
|
+
data.summary.length > 4096 ||
|
|
164
|
+
typeof data.occurredAt !== "string" ||
|
|
165
|
+
data.occurredAt.length > 64 ||
|
|
166
|
+
!Number.isFinite(Date.parse(data.occurredAt))
|
|
167
|
+
)
|
|
168
|
+
throw new Error("invalid host event projection");
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
type,
|
|
171
|
+
goalRef: source,
|
|
172
|
+
summary: data.summary,
|
|
173
|
+
occurredAt: data.occurredAt,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Fixed-slot UI has a plain-text fallback; extensions cannot supply markup. */
|
|
178
|
+
export async function projectGoalExtensionPanel(ref, request, options = {}) {
|
|
179
|
+
options = fixedHostOptions(options);
|
|
180
|
+
const plugin = admittedPlugin(ref, options);
|
|
181
|
+
const panel = plugin.declaration.panels.find(
|
|
182
|
+
(entry) => entry.id === request?.panelId,
|
|
183
|
+
);
|
|
184
|
+
if (!panel) throw new Error("goal extension panel is undeclared");
|
|
185
|
+
const source = goalRef(request.goalRef);
|
|
186
|
+
const context = Object.freeze({
|
|
187
|
+
plugin: Object.freeze({
|
|
188
|
+
name: plugin.name,
|
|
189
|
+
scope: plugin.scope,
|
|
190
|
+
version: plugin.version,
|
|
191
|
+
}),
|
|
192
|
+
goalRef: source,
|
|
193
|
+
operation: "read-panel",
|
|
194
|
+
panel: Object.freeze({
|
|
195
|
+
...panel,
|
|
196
|
+
fields: Object.freeze([...panel.fields]),
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
await authorize(options.authorize, context);
|
|
200
|
+
if (typeof options.readPanel !== "function")
|
|
201
|
+
throw new Error("host panel reader unavailable");
|
|
202
|
+
const data = await options.readPanel(context);
|
|
203
|
+
await authorize(options.authorize, context);
|
|
204
|
+
const current = admittedPlugin(context.plugin, options);
|
|
205
|
+
if (
|
|
206
|
+
!current.declaration.panels.some(
|
|
207
|
+
(entry) => JSON.stringify(entry) === JSON.stringify(panel),
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
throw new Error("goal extension panel changed during projection");
|
|
211
|
+
const lines = [panel.title];
|
|
212
|
+
for (const field of panel.fields) {
|
|
213
|
+
if (typeof data?.[field] !== "string" || data[field].length > 4096)
|
|
214
|
+
throw new Error(`invalid host panel field ${field}`);
|
|
215
|
+
lines.push(`${field}: ${data[field]}`);
|
|
216
|
+
}
|
|
217
|
+
return Object.freeze({
|
|
218
|
+
id: panel.id,
|
|
219
|
+
slot: panel.slot,
|
|
220
|
+
format: "text",
|
|
221
|
+
text: lines.join("\n"),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Queue an unapproved proposal through a host adapter; no action execution API. */
|
|
226
|
+
export async function proposeGoalExtensionAction(ref, raw, options = {}) {
|
|
227
|
+
options = fixedHostOptions(options);
|
|
228
|
+
const plugin = admittedPlugin(ref, options);
|
|
229
|
+
raw = normalizeGoalExtensionProposal(raw);
|
|
230
|
+
if (!plugin.declaration.proposals.includes(raw.type))
|
|
231
|
+
throw new Error("goal extension proposal is undeclared");
|
|
232
|
+
const source = raw.goalRef;
|
|
233
|
+
const title = raw.title;
|
|
234
|
+
const description = raw.description;
|
|
235
|
+
const context = Object.freeze({
|
|
236
|
+
plugin: Object.freeze({
|
|
237
|
+
name: plugin.name,
|
|
238
|
+
scope: plugin.scope,
|
|
239
|
+
version: plugin.version,
|
|
240
|
+
}),
|
|
241
|
+
goalRef: source,
|
|
242
|
+
operation: "propose-action",
|
|
243
|
+
type: raw.type,
|
|
244
|
+
sourceRef: raw.sourceRef,
|
|
245
|
+
requestId: raw.requestId,
|
|
246
|
+
});
|
|
247
|
+
await authorize(options.authorize, context);
|
|
248
|
+
if (typeof options.enqueueProposal !== "function")
|
|
249
|
+
throw new Error("host proposal queue unavailable");
|
|
250
|
+
admittedPlugin(context.plugin, options, "proposals", context.type);
|
|
251
|
+
// The host queue must revalidate source revision/control generation in its
|
|
252
|
+
// transaction, and deduplicate requestId within plugin/version/goal identity.
|
|
253
|
+
// It stores a pending suggestion; native confirmation stays later.
|
|
254
|
+
const result = await options.enqueueProposal(
|
|
255
|
+
Object.freeze({
|
|
256
|
+
...context,
|
|
257
|
+
title,
|
|
258
|
+
description,
|
|
259
|
+
state: "pending-confirmation",
|
|
260
|
+
}),
|
|
261
|
+
);
|
|
262
|
+
if (
|
|
263
|
+
!result ||
|
|
264
|
+
typeof result !== "object" ||
|
|
265
|
+
Array.isArray(result) ||
|
|
266
|
+
Object.keys(result).some((key) => !["proposalId", "state"].includes(key)) ||
|
|
267
|
+
result.state !== "pending-confirmation" ||
|
|
268
|
+
typeof result.proposalId !== "string" ||
|
|
269
|
+
!result.proposalId ||
|
|
270
|
+
result.proposalId.length > 256
|
|
271
|
+
)
|
|
272
|
+
throw new Error("invalid host proposal receipt");
|
|
273
|
+
return Object.freeze({
|
|
274
|
+
proposalId: result.proposalId,
|
|
275
|
+
state: "pending-confirmation",
|
|
276
|
+
});
|
|
277
|
+
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import fs from "fs";
|
|
20
|
+
import { summarizeGoalExtension } from "./goal-extension-contract.js";
|
|
20
21
|
import os from "os";
|
|
21
22
|
import path from "path";
|
|
22
23
|
import crypto from "node:crypto";
|
|
@@ -2115,6 +2116,7 @@ export function listInstalled(opts = {}) {
|
|
|
2115
2116
|
scope: p.scope,
|
|
2116
2117
|
dir: p.root,
|
|
2117
2118
|
ok: p.manifest?.ok === true,
|
|
2119
|
+
goalExtension: summarizeGoalExtension(p.manifest),
|
|
2118
2120
|
enabled: p.enabled !== false,
|
|
2119
2121
|
runtimeBlocked: p.runtimeBlocked === true,
|
|
2120
2122
|
activePointer: {
|
|
@@ -3388,17 +3390,17 @@ function sameSourceAuthority(current, candidate) {
|
|
|
3388
3390
|
if (current.type === "registry") {
|
|
3389
3391
|
return Boolean(
|
|
3390
3392
|
current.sourceDigest &&
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3393
|
+
candidate.sourceDigest &&
|
|
3394
|
+
current.sourceDigest === candidate.sourceDigest &&
|
|
3395
|
+
current.resolvedSourceDigest &&
|
|
3396
|
+
candidate.resolvedSourceDigest &&
|
|
3397
|
+
current.resolvedSourceDigest === candidate.resolvedSourceDigest,
|
|
3396
3398
|
);
|
|
3397
3399
|
}
|
|
3398
3400
|
return Boolean(
|
|
3399
3401
|
current.sourceDigest &&
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
+
candidate.sourceDigest &&
|
|
3403
|
+
current.sourceDigest === candidate.sourceDigest,
|
|
3402
3404
|
);
|
|
3403
3405
|
}
|
|
3404
3406
|
|
|
@@ -3661,11 +3663,7 @@ function normalizeSourceMetadata(value) {
|
|
|
3661
3663
|
value.resolvedSource,
|
|
3662
3664
|
catalogAuthority.commandSource,
|
|
3663
3665
|
)
|
|
3664
|
-
: pluginSourceAuthorityDigest(
|
|
3665
|
-
value.resolvedSource,
|
|
3666
|
-
"git",
|
|
3667
|
-
value.ref,
|
|
3668
|
-
)
|
|
3666
|
+
: pluginSourceAuthorityDigest(value.resolvedSource, "git", value.ref)
|
|
3669
3667
|
: null);
|
|
3670
3668
|
const policyDigest = normalizeSourceAuthorityDigest(value.policyDigest);
|
|
3671
3669
|
if (resolvedSourceDigest) {
|
|
@@ -3998,8 +3996,8 @@ function assertCatalogRemoteArtifactBindings(metadata) {
|
|
|
3998
3996
|
const expectedSignature = expectations.signature || {};
|
|
3999
3997
|
const expectsRemoteSignature = Boolean(
|
|
4000
3998
|
expectedSignature.url &&
|
|
4001
|
-
|
|
4002
|
-
|
|
3999
|
+
expectedSignature.publicKeyUrl &&
|
|
4000
|
+
expectedSignature.publicKeySha256,
|
|
4003
4001
|
);
|
|
4004
4002
|
if (expectsRemoteSignature !== Boolean(evidence.signature)) {
|
|
4005
4003
|
throw new Error(
|
|
@@ -5628,9 +5626,9 @@ function samePointerState(left, right) {
|
|
|
5628
5626
|
if (!left.present) return true;
|
|
5629
5627
|
return Boolean(
|
|
5630
5628
|
Buffer.isBuffer(left.bytes) &&
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5629
|
+
Buffer.isBuffer(right.bytes) &&
|
|
5630
|
+
left.bytes.equals(right.bytes) &&
|
|
5631
|
+
sameFileGeneration(left.generation, right.generation),
|
|
5634
5632
|
);
|
|
5635
5633
|
}
|
|
5636
5634
|
|
|
@@ -5668,9 +5666,9 @@ function sameLifecycleFileState(left, right) {
|
|
|
5668
5666
|
if (!left.present) return true;
|
|
5669
5667
|
return Boolean(
|
|
5670
5668
|
Buffer.isBuffer(left.bytes) &&
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5669
|
+
Buffer.isBuffer(right.bytes) &&
|
|
5670
|
+
left.bytes.equals(right.bytes) &&
|
|
5671
|
+
sameFileGeneration(left.generation, right.generation),
|
|
5674
5672
|
);
|
|
5675
5673
|
}
|
|
5676
5674
|
|
|
@@ -5718,11 +5716,11 @@ function serializePluginNameState(state) {
|
|
|
5718
5716
|
function samePluginNameState(left, right) {
|
|
5719
5717
|
return Boolean(
|
|
5720
5718
|
left &&
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5719
|
+
right &&
|
|
5720
|
+
sameFileGeneration(left.generation, right.generation) &&
|
|
5721
|
+
left.payloadDigest === right.payloadDigest &&
|
|
5722
|
+
left.fileCount === right.fileCount &&
|
|
5723
|
+
left.totalBytes === right.totalBytes,
|
|
5726
5724
|
);
|
|
5727
5725
|
}
|
|
5728
5726
|
|
|
@@ -5745,8 +5743,8 @@ function lifecycleFileContentMatches(left, right) {
|
|
|
5745
5743
|
if (!left.present) return true;
|
|
5746
5744
|
return Boolean(
|
|
5747
5745
|
Buffer.isBuffer(left.bytes) &&
|
|
5748
|
-
|
|
5749
|
-
|
|
5746
|
+
Buffer.isBuffer(right.bytes) &&
|
|
5747
|
+
left.bytes.equals(right.bytes),
|
|
5750
5748
|
);
|
|
5751
5749
|
}
|
|
5752
5750
|
|
|
@@ -5812,7 +5810,9 @@ function hasRetainedLifecycleRecovery(nameDir) {
|
|
|
5812
5810
|
function authoritativeTransactionCleanupPending(cleanup) {
|
|
5813
5811
|
return Boolean(
|
|
5814
5812
|
cleanup?.cleanupPending === true &&
|
|
5815
|
-
|
|
5813
|
+
/^\.(?:install|uninstall)-/u.test(
|
|
5814
|
+
path.basename(cleanup.cleanupPath || ""),
|
|
5815
|
+
),
|
|
5816
5816
|
);
|
|
5817
5817
|
}
|
|
5818
5818
|
|
|
@@ -5902,22 +5902,22 @@ function fileGeneration(stat) {
|
|
|
5902
5902
|
function sameFileGeneration(left, right) {
|
|
5903
5903
|
return Boolean(
|
|
5904
5904
|
left &&
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5905
|
+
right &&
|
|
5906
|
+
left.dev === right.dev &&
|
|
5907
|
+
left.ino === right.ino &&
|
|
5908
|
+
left.birthtimeMs === right.birthtimeMs &&
|
|
5909
|
+
left.mtimeMs === right.mtimeMs &&
|
|
5910
|
+
left.size === right.size,
|
|
5911
5911
|
);
|
|
5912
5912
|
}
|
|
5913
5913
|
|
|
5914
5914
|
function sameInstalledVersionState(left, right) {
|
|
5915
5915
|
return Boolean(
|
|
5916
5916
|
left &&
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5917
|
+
right &&
|
|
5918
|
+
sameFileGeneration(left.generation, right.generation) &&
|
|
5919
|
+
left.payloadDigest === right.payloadDigest &&
|
|
5920
|
+
left.sourceDigest === right.sourceDigest,
|
|
5921
5921
|
);
|
|
5922
5922
|
}
|
|
5923
5923
|
|
|
@@ -5999,8 +5999,8 @@ function activePointerMatchesSnapshot(transaction) {
|
|
|
5999
5999
|
if (!snapshot.present) return true;
|
|
6000
6000
|
return Boolean(
|
|
6001
6001
|
Buffer.isBuffer(current.bytes) &&
|
|
6002
|
-
|
|
6003
|
-
|
|
6002
|
+
Buffer.isBuffer(snapshot.bytes) &&
|
|
6003
|
+
current.bytes.equals(snapshot.bytes),
|
|
6004
6004
|
);
|
|
6005
6005
|
}
|
|
6006
6006
|
|