@rubytech/create-maxy-code 0.1.470 → 0.1.471
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/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-18-graph-native-ledger.md +807 -0
- package/payload/platform/docs/superpowers/specs/2026-07-18-graph-native-ledger-design.md +241 -0
- package/payload/platform/lib/ledger-core/dist/ageing.d.ts +14 -0
- package/payload/platform/lib/ledger-core/dist/ageing.d.ts.map +1 -0
- package/payload/platform/lib/ledger-core/dist/ageing.js +38 -0
- package/payload/platform/lib/ledger-core/dist/ageing.js.map +1 -0
- package/payload/platform/lib/ledger-core/dist/balance.d.ts +25 -0
- package/payload/platform/lib/ledger-core/dist/balance.d.ts.map +1 -0
- package/payload/platform/lib/ledger-core/dist/balance.js +38 -0
- package/payload/platform/lib/ledger-core/dist/balance.js.map +1 -0
- package/payload/platform/lib/ledger-core/dist/index.d.ts +5 -0
- package/payload/platform/lib/ledger-core/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/ledger-core/dist/index.js +5 -0
- package/payload/platform/lib/ledger-core/dist/index.js.map +1 -0
- package/payload/platform/lib/ledger-core/dist/money.d.ts +12 -0
- package/payload/platform/lib/ledger-core/dist/money.d.ts.map +1 -0
- package/payload/platform/lib/ledger-core/dist/money.js +16 -0
- package/payload/platform/lib/ledger-core/dist/money.js.map +1 -0
- package/payload/platform/lib/ledger-core/dist/reconcile.d.ts +51 -0
- package/payload/platform/lib/ledger-core/dist/reconcile.d.ts.map +1 -0
- package/payload/platform/lib/ledger-core/dist/reconcile.js +77 -0
- package/payload/platform/lib/ledger-core/dist/reconcile.js.map +1 -0
- package/payload/platform/lib/ledger-core/package.json +16 -0
- package/payload/platform/lib/ledger-core/src/__tests__/ageing.test.ts +42 -0
- package/payload/platform/lib/ledger-core/src/__tests__/balance.test.ts +48 -0
- package/payload/platform/lib/ledger-core/src/__tests__/reconcile.test.ts +87 -0
- package/payload/platform/lib/ledger-core/src/ageing.ts +51 -0
- package/payload/platform/lib/ledger-core/src/balance.ts +52 -0
- package/payload/platform/lib/ledger-core/src/index.ts +4 -0
- package/payload/platform/lib/ledger-core/src/money.ts +17 -0
- package/payload/platform/lib/ledger-core/src/reconcile.ts +109 -0
- package/payload/platform/lib/ledger-core/tsconfig.json +6 -0
- package/payload/platform/neo4j/schema.cypher +16 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +98 -2
- package/payload/platform/plugins/cloudflare/bin/__tests__/portal-brand-css.test.sh +139 -0
- package/payload/platform/plugins/cloudflare/bin/portal-brand-css.mjs +128 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +1 -1
- package/payload/platform/plugins/cloudflare/mcp/__tests__/skill-contract.test.ts +25 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/template-config.test.ts +55 -3
- package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +38 -3
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/{public/portal.css → portal.css} +13 -2
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/wrangler.toml +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +48 -0
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/plugins/docs/references/ledger.md +43 -0
- package/payload/platform/plugins/email/PLUGIN.md +4 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/display-truncation.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/display-truncation.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/display-truncation.test.js +196 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/display-truncation.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/source-fetch-efficiency.test.js +10 -8
- package/payload/platform/plugins/email/mcp/dist/__tests__/source-fetch-efficiency.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/truncation-tool-output.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/truncation-tool-output.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/truncation-tool-output.test.js +110 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/truncation-tool-output.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +22 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +90 -36
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-read.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-read.js +6 -2
- package/payload/platform/plugins/email/mcp/dist/tools/email-read.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-search.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-search.js +6 -2
- package/payload/platform/plugins/email/mcp/dist/tools/email-search.js.map +1 -1
- package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +4 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +60 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/calendar-tools.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/calendar-tools.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/calendar-tools.test.js +48 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/calendar-tools.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.js +25 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.js +40 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-store.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-store.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-store.test.js +35 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-store.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/token-store.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/token-store.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/token-store.test.js +85 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/token-store.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts +25 -0
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.js +87 -0
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/token-store.d.ts +46 -0
- package/payload/platform/plugins/google/mcp/dist/auth/token-store.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/token-store.js +138 -0
- package/payload/platform/plugins/google/mcp/dist/auth/token-store.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/index.d.ts +25 -0
- package/payload/platform/plugins/google/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/index.js +300 -0
- package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/lib/google-client.d.ts +28 -0
- package/payload/platform/plugins/google/mcp/dist/lib/google-client.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/lib/google-client.js +102 -0
- package/payload/platform/plugins/google/mcp/dist/lib/google-client.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/lib/log.d.ts +3 -0
- package/payload/platform/plugins/google/mcp/dist/lib/log.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/lib/log.js +16 -0
- package/payload/platform/plugins/google/mcp/dist/lib/log.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-info.d.ts +12 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-info.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-info.js +23 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-info.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-list.d.ts +12 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-list.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-list.js +9 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-list.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +42 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +102 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-cancel.d.ts +10 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-cancel.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-cancel.js +9 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-cancel.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-create.d.ts +20 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-create.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-create.js +25 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-create.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-event.d.ts +6 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-event.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-event.js +7 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-event.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-freebusy.d.ts +14 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-freebusy.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-freebusy.js +16 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-freebusy.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-list.d.ts +44 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-list.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-list.js +36 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-list.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-respond.d.ts +16 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-respond.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-respond.js +29 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-respond.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-update.d.ts +16 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-update.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-update.js +32 -0
- package/payload/platform/plugins/google/mcp/dist/tools/calendar-update.js.map +1 -0
- package/payload/platform/plugins/google/references/auth.md +35 -0
- package/payload/platform/plugins/ledger/.claude-plugin/plugin.json +21 -0
- package/payload/platform/plugins/ledger/PLUGIN.md +82 -0
- package/payload/platform/plugins/ledger/lib/mcp-spawn-tee/index.js +193 -0
- package/payload/platform/plugins/ledger/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/ledger/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/ledger/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/index.js +168 -0
- package/payload/platform/plugins/ledger/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/ids.d.ts +4 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/ids.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/ids.js +0 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/ids.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/neo4j.js +40 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/read.d.ts +29 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/read.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/read.js +138 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/read.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/types.d.ts +47 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/types.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/types.js +14 -0
- package/payload/platform/plugins/ledger/mcp/dist/lib/types.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/balance.d.ts +18 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/balance.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/balance.js +23 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/balance.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.d.ts +26 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.js +33 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.d.ts +27 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.js +40 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.d.ts +46 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.js +68 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.d.ts +20 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.js +30 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/statement.d.ts +26 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/statement.d.ts.map +1 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/statement.js +35 -0
- package/payload/platform/plugins/ledger/mcp/dist/tools/statement.js.map +1 -0
- package/payload/platform/plugins/ledger/mcp/package.json +21 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/ledger-vertical-coverage.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/ledger-vertical-coverage.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/ledger-vertical-coverage.test.js +81 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/ledger-vertical-coverage.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts +9 -7
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js +10 -8
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +22 -0
- package/payload/platform/plugins/memory/references/schema-construction.md +0 -18
- package/payload/platform/plugins/scheduling/PLUGIN.md +20 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.js +11 -2
- package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +3 -3
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +138 -0
- package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/activity-rows.js +268 -0
- package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +42 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +10 -1
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +80 -6
- package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-census.js +96 -20
- package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +5 -1
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -1
- package/payload/platform/templates/specialists/agents/database-operator.md +1 -1
- package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
- package/payload/server/{chunk-JRIBGO45.js → chunk-BSTIQX52.js} +44 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/activity.html +17 -0
- package/payload/server/public/assets/AdminLoginScreens-Rf94VD9w.js +1 -0
- package/payload/server/public/assets/AdminShell-CyGKg7MG.js +2 -0
- package/payload/server/public/assets/Checkbox-B0jmI2y2.js +1 -0
- package/payload/server/public/assets/HeaderMenu-BnTYGNaB.js +9 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-pu0jjLCz.css → HeaderMenu-DtIEBHOU.css} +1 -1
- package/payload/server/public/assets/activity-BOBTWFr-.js +1 -0
- package/payload/server/public/assets/admin-HDLzwbLl.js +1 -0
- package/payload/server/public/assets/{arc-qKfXIt8v.js → arc-CFMJyMm-.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Cypt5qHL.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DkVrGn7G.js → architectureDiagram-Q4EWVU46-CmOpXLsH.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DqavswGH.js → blockDiagram-DXYQGD6D-CmS8f9YF.js} +1 -1
- package/payload/server/public/assets/browser-D4_XLSSm.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-B7fyKiXe.js → c4Diagram-AHTNJAMY-BXIjMl6A.js} +1 -1
- package/payload/server/public/assets/calendar-s5V_gbI7.js +1 -0
- package/payload/server/public/assets/channel-DhrFAm7m.js +1 -0
- package/payload/server/public/assets/chat-40WyKzGb.js +1 -0
- package/payload/server/public/assets/chevron-left-C35qGP5f.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-DsgMtGkv.js → chunk-2KRD3SAO-D4fktAwW.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-CkdISfNt.js → chunk-336JU56O-C2MKnRTj.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-BhU7-TyS.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-CYpiF2bl.js → chunk-4BX2VUAB-C13Wz3zS.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-CWyc_F7v.js → chunk-4TB4RGXK-CalYahTR.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BbzKMw2Z.js → chunk-55IACEB6-TmOKdy8a.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-u19Nai9e.js → chunk-5FUZZQ4R-C-i0BVag.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-Ba8by6Uy.js → chunk-5PVQY5BW-D6bJMLnf.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-BwUuxtyb.js → chunk-67CJDMHE-Cif9Uu5C.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BRH9iM9L.js → chunk-7N4EOEYR-WjTHCXnd.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-BGoztgLL.js → chunk-AA7GKIK3-CwCfdQmb.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-C5GDAZTl.js → chunk-BSJP7CBP-9A67yXwT.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-ChY32VPS.js → chunk-CIAEETIT-DPMiWSBi.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CPSD3p6p.js → chunk-EDXVE4YY-B9PBdwiT.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-D1oL-iUr.js → chunk-ENJZ2VHE-CM5OqcQ5.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-CPvYEr54.js → chunk-FMBD7UC4-Bmt_ZRlV.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-9Yyj7Vbz.js → chunk-FOC6F5B3-DfGJGxpX.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BaYgh8FR.js → chunk-ICPOFSXX-D6M89DA0.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-5ucpeRvm.js → chunk-K5T4RW27-DMpoaqw2.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-DW-FHk7T.js → chunk-KGLVRYIC-DYUFgri2.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-CGGVfAyG.js → chunk-LIHQZDEY-x3LmeKmx.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-Bv8EUa5d.js → chunk-ORNJ4GCN-BeuNAWkW.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C1mXJnyw.js → chunk-OYMX7WX6-Bv6gisQ6.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-7_kS3RBy.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-PwSQz6EP.js → chunk-U2HBQHQK-C2iT9Av2.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP--NPHTBlU.js → chunk-X2U36JSP-Bd6bv87A.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Bbc7Da32.js → chunk-XPW4576I-ByFnN4JO.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-D-9v8e--.js → chunk-YZCP3GAM-Bt8I6ZDb.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CMPg670Q.js → chunk-ZZ45TVLE-DBMPgZ_A.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BrWqm88p.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D0wzG5Fd.js +1 -0
- package/payload/server/public/assets/clone-DQA-nNrl.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-NVSb1Bhy.js → cose-bilkent-S5V4N54A-DgLEaApT.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-V2Ai1DFl.js → dagre-KV5264BT-kWVPgmmL.js} +1 -1
- package/payload/server/public/assets/{dagre-QfLcO-1j.js → dagre-mSazqXgG.js} +1 -1
- package/payload/server/public/assets/data-Bq0vU3qJ.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-Caw21693.js → diagram-5BDNPKRD-BHe_omJD.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-CgwVkT2q.js → diagram-G4DWMVQ6-fUFsmM3x.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DFUrLZhs.js → diagram-MMDJMWI5-DmujPLlM.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CEEiEuZJ.js → diagram-TYMM5635-B7Aoas89.js} +1 -1
- package/payload/server/public/assets/{dist-Cvgxm7qv.js → dist-C9D_xz81.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-CG10NrT3.js → erDiagram-SMLLAGMA-6hS1rGiO.js} +1 -1
- package/payload/server/public/assets/{flatten-DAO0sfCM.js → flatten-BXzaHgtL.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BqkV9Okv.js → flowDiagram-DWJPFMVM-Bqhr_r5b.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DRiCDQF6.js → ganttDiagram-T4ZO3ILL-B8kjyN4o.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-C_-XjxLd.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BZV2voyy.js → gitGraphDiagram-UUTBAWPF--TTRq4ir.js} +1 -1
- package/payload/server/public/assets/{graph-BZiudUGr.js → graph-C252ZHjp.js} +3 -3
- package/payload/server/public/assets/graph-labels-DzPbbhLc.js +1 -0
- package/payload/server/public/assets/{graphlib-DGPThX8M.js → graphlib-CWkjawc5.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BH8yDCfL.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-D8U4M0pK.js +2 -0
- package/payload/server/public/assets/{isEmpty-Cb_U81C6.js → isEmpty-uB1dEu_Z.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BKsAxSvp.js → ishikawaDiagram-UXIWVN3A-CR8B7VzM.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CmliuOd-.js → journeyDiagram-VCZTEJTY-45lWAvtq.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DAlElMb-.js → kanban-definition-6JOO6SKY-DkrPXLVb.js} +1 -1
- package/payload/server/public/assets/{line-DKZqLKAC.js → line-Db0H446a.js} +1 -1
- package/payload/server/public/assets/{linear-CbSGdh1x.js → linear-X3O7lwK3.js} +1 -1
- package/payload/server/public/assets/maximize-2-CEbXFpQT.js +1 -0
- package/payload/server/public/assets/{mermaid-parser.core-DFvbao9C.js → mermaid-parser.core-CixBHOya.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-C0vEBxDm.js → mermaid.core-BGQq98L7.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CShASUKd.js → mindmap-definition-QFDTVHPH-v9cJl1mj.js} +1 -1
- package/payload/server/public/assets/operator-zKk4HMdX.js +1 -0
- package/payload/server/public/assets/{ordinal-H0tVmBDP.js → ordinal-CZY9laxg.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Bajcns4r.js +1 -0
- package/payload/server/public/assets/page-BrmN_vzV.js +1 -0
- package/payload/server/public/assets/page-Cts-ESBe.js +32 -0
- package/payload/server/public/assets/{pdf-render-jAQU0nXt.js → pdf-render-7HZBTZ0_.js} +1 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-D7hjM5w1.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CBZHpDAJ.js → pieDiagram-DEJITSTG-DQ0b6edX.js} +1 -1
- package/payload/server/public/assets/public-BItzHBc0.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-n3bB3K91.js → quadrantDiagram-34T5L4WZ-B64mj7Ei.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-B46d5x7a.js +1 -0
- package/payload/server/public/assets/{reduce-DAvwat-a.js → reduce-BGQzAenn.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DiDvQK3c.js → requirementDiagram-MS252O5E-CE2JIEWo.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-B0EYGhGx.js +1 -0
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DWDQQZmd.js → sankeyDiagram-XADWPNL6-Cmt5cfCz.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DmAqRlBT.js → sequenceDiagram-FGHM5R23-B5vVn_sw.js} +1 -1
- package/payload/server/public/assets/{src-DV4LKv2E.js → src-BTKk8KAG.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-D4R-n6bZ.js → stateDiagram-FHFEXIEX-DiUEJ-RZ.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DIm3XuAD.js +1 -0
- package/payload/server/public/assets/tasks-ClE8-be8.js +1 -0
- package/payload/server/public/assets/time-entry-format-BwjGLnXu.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CjiHGP4l.js → timeline-definition-GMOUNBTQ-C9jprDVw.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-3XQh5xQ1.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-DwR-_l5z.js +1 -0
- package/payload/server/public/assets/triangle-alert-DejWYn1x.js +1 -0
- package/payload/server/public/assets/useCopyFeedback-CpSgOavK.js +1 -0
- package/payload/server/public/assets/useSelectionMode-ZQZQUgze.js +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DuRLvCfO.js +1 -0
- package/payload/server/public/assets/useVoiceRecorder-BTYYeUJW.js +2 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CBdDQ7c-.js → vennDiagram-DHZGUBPP-DWqQJ9X0.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DZp9oCGv.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BlIQPKLb.js → wardleyDiagram-NUSXRM2D-Dg6c2Voh.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CslKgh9B.js → xychartDiagram-5P7HB3ND-EhN-zeDj.js} +1 -1
- package/payload/server/public/browser.html +7 -6
- package/payload/server/public/calendar.html +8 -7
- package/payload/server/public/chat.html +15 -14
- package/payload/server/public/data.html +14 -12
- package/payload/server/public/graph.html +13 -12
- package/payload/server/public/index.html +17 -15
- package/payload/server/public/operator.html +17 -16
- package/payload/server/public/public.html +15 -14
- package/payload/server/public/tasks.html +7 -6
- package/payload/server/server.js +525 -244
- package/payload/server/public/assets/AdminLoginScreens-Bed8SDxY.js +0 -1
- package/payload/server/public/assets/AdminShell-BLh9O6dn.js +0 -2
- package/payload/server/public/assets/Checkbox-BC_KSbpS.js +0 -1
- package/payload/server/public/assets/admin-DfWgJVI3.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-FPHT7s-C.js +0 -1
- package/payload/server/public/assets/browser-C0vkv-hH.js +0 -1
- package/payload/server/public/assets/calendar-_pfHw0Hp.js +0 -1
- package/payload/server/public/assets/channel-j70eMvcL.js +0 -1
- package/payload/server/public/assets/chat-DYT5H81o.js +0 -1
- package/payload/server/public/assets/chevron-left-BnpVBu51.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-D-NcAlTW.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CAwbQBtf.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Ct6Rn0vt.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B_2XCIFv.js +0 -1
- package/payload/server/public/assets/clone-DjPWA_NH.js +0 -1
- package/payload/server/public/assets/data-CR-fbPWr.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-B8Hx7f-D.js +0 -1
- package/payload/server/public/assets/graph-labels-BzmmJwCR.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-BicCJTqU.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-tf-8rOez.js +0 -2
- package/payload/server/public/assets/maximize-2-Bhdsv0U-.js +0 -1
- package/payload/server/public/assets/operator-gm2eP4r6.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Ckn_5hq0.js +0 -1
- package/payload/server/public/assets/page-8AB3jUa_.js +0 -1
- package/payload/server/public/assets/page-BoPorLg-.js +0 -32
- package/payload/server/public/assets/pie-ZZUOXDRM-DzlGQW3J.js +0 -1
- package/payload/server/public/assets/public-DqJk6qgW.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BHo2YD8b.js +0 -1
- package/payload/server/public/assets/rotate-ccw-D_5cETGt.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BcFRbGRu.js +0 -1
- package/payload/server/public/assets/tasks-EyKLXINi.js +0 -1
- package/payload/server/public/assets/time-entry-format-DAwmmR3i.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BtRr5vXp.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-D8p0sbyo.js +0 -1
- package/payload/server/public/assets/useCopyFeedback-rOWd_lzl.js +0 -1
- package/payload/server/public/assets/useSelectionMode-DDmLmPph.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-CU-lOxTd.js +0 -9
- package/payload/server/public/assets/useVoiceRecorder-azG8zSUI.js +0 -2
- package/payload/server/public/assets/wardley-RL74JXVD-DgMn-9ZJ.js +0 -1
- /package/payload/platform/plugins/cloudflare/skills/data-portal/{template/schema.sql → schema.sql} +0 -0
- /package/payload/platform/plugins/cloudflare/skills/data-portal/template/{public/index.html → index.html} +0 -0
- /package/payload/platform/plugins/cloudflare/skills/data-portal/template/{public/portal.js → portal.js} +0 -0
- /package/payload/server/public/assets/{_baseFor-D3BqAOBr.js → _baseFor-CMWvz0uA.js} +0 -0
- /package/payload/server/public/assets/{array-iYP9fzJp.js → array-Cny_NT6T.js} +0 -0
- /package/payload/server/public/assets/{chunk-Ck5AOu5v.js → chunk-TPjIAO9U.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-BQSBzPsB.js → cytoscape.esm-De0CCmB2.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-BrdA1gDi.js → defaultLocale-BahRht8U.js} +0 -0
- /package/payload/server/public/assets/{init-Bx0S6pkp.js → init-DoIvjoJ_.js} +0 -0
- /package/payload/server/public/assets/{katex-BsiH_a6d.js → katex-Bfn1OZEl.js} +0 -0
- /package/payload/server/public/assets/{path-BLSgTy3w.js → path-CTezU8L5.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-ClBMtM1g.js → preload-helper-CT1Z6Pdu.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-BMOtDaaS.js → rough.esm-BJo4pvXu.js} +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { computeOutstanding, applyPayment } from '../balance.js'
|
|
3
|
+
|
|
4
|
+
describe('computeOutstanding', () => {
|
|
5
|
+
it('reports the full total when nothing is applied', () => {
|
|
6
|
+
expect(computeOutstanding(6400, [], [])).toBe(6400)
|
|
7
|
+
})
|
|
8
|
+
it('leaves the exact remainder after a part payment', () => {
|
|
9
|
+
expect(computeOutstanding(6400, [2000], [])).toBe(4400)
|
|
10
|
+
})
|
|
11
|
+
it('reaches zero when payments sum to the total', () => {
|
|
12
|
+
expect(computeOutstanding(6400, [2000, 4400], [])).toBe(0)
|
|
13
|
+
})
|
|
14
|
+
it('treats a credit identically to a payment', () => {
|
|
15
|
+
expect(computeOutstanding(6400, [], [2000])).toBe(4400)
|
|
16
|
+
expect(computeOutstanding(6400, [1000], [1000])).toBe(computeOutstanding(6400, [2000], []))
|
|
17
|
+
})
|
|
18
|
+
it('does not drift on repeating decimals', () => {
|
|
19
|
+
expect(computeOutstanding(100, [33.33, 33.33, 33.34], [])).toBe(0)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('applyPayment', () => {
|
|
24
|
+
it('accepts a payment within the outstanding amount', () => {
|
|
25
|
+
expect(applyPayment(6400, [], [], 2000)).toEqual({ accepted: true, outstandingAfter: 4400 })
|
|
26
|
+
})
|
|
27
|
+
it('accepts a payment that exactly settles the invoice', () => {
|
|
28
|
+
expect(applyPayment(6400, [2000], [], 4400)).toEqual({ accepted: true, outstandingAfter: 0 })
|
|
29
|
+
})
|
|
30
|
+
it('rejects over-application and reports the remaining amount', () => {
|
|
31
|
+
expect(applyPayment(6400, [2000], [], 5000)).toEqual({
|
|
32
|
+
accepted: false,
|
|
33
|
+
reason: 'over-application',
|
|
34
|
+
remaining: 4400,
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
it('rejects any payment against a zero-total invoice', () => {
|
|
38
|
+
expect(applyPayment(0, [], [], 1)).toEqual({
|
|
39
|
+
accepted: false,
|
|
40
|
+
reason: 'over-application',
|
|
41
|
+
remaining: 0,
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
it('rejects a zero or negative candidate', () => {
|
|
45
|
+
expect(applyPayment(6400, [], [], 0).accepted).toBe(false)
|
|
46
|
+
expect(applyPayment(6400, [], [], -5).accepted).toBe(false)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { reconcileLedger, formatCensusLine, LEDGER_INDEX_NAMES } from '../reconcile.js'
|
|
3
|
+
|
|
4
|
+
const clean = {
|
|
5
|
+
invoices: 12,
|
|
6
|
+
payments: 20,
|
|
7
|
+
orphanPayments: 0,
|
|
8
|
+
storedBalanceProps: 0,
|
|
9
|
+
paymentKeys: [],
|
|
10
|
+
declaredNotLive: [],
|
|
11
|
+
}
|
|
12
|
+
const NOW = Date.parse('2026-07-18T00:00:00Z')
|
|
13
|
+
|
|
14
|
+
describe('reconcileLedger', () => {
|
|
15
|
+
it('does not alarm on a clean ledger', () => {
|
|
16
|
+
expect(reconcileLedger(clean, NOW).alarm).toBe(false)
|
|
17
|
+
})
|
|
18
|
+
it('alarms on an orphan payment', () => {
|
|
19
|
+
expect(reconcileLedger({ ...clean, orphanPayments: 1 }, NOW).alarm).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
it('alarms on a stored balance property', () => {
|
|
22
|
+
expect(reconcileLedger({ ...clean, storedBalanceProps: 1 }, NOW).alarm).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
it('alarms when a declared label is not live', () => {
|
|
25
|
+
expect(reconcileLedger({ ...clean, declaredNotLive: ['CashEntry'] }, NOW).alarm).toBe(true)
|
|
26
|
+
})
|
|
27
|
+
it('counts n-1 duplicates per colliding group', () => {
|
|
28
|
+
const paymentKeys = [
|
|
29
|
+
{ invoiceId: 'i1', paymentId: 'p1', amount: 100, date: '2026-07-01' },
|
|
30
|
+
{ invoiceId: 'i1', paymentId: 'p2', amount: 100, date: '2026-07-01' },
|
|
31
|
+
{ invoiceId: 'i1', paymentId: 'p3', amount: 100, date: '2026-07-01' },
|
|
32
|
+
]
|
|
33
|
+
const f = reconcileLedger({ ...clean, paymentKeys }, NOW)
|
|
34
|
+
expect(f.suspectDuplicates).toBe(2)
|
|
35
|
+
expect(f.alarm).toBe(true)
|
|
36
|
+
})
|
|
37
|
+
it('does not flag the same paymentId seen once', () => {
|
|
38
|
+
const paymentKeys = [{ invoiceId: 'i1', paymentId: 'p1', amount: 100, date: '2026-07-01' }]
|
|
39
|
+
expect(reconcileLedger({ ...clean, paymentKeys }, NOW).suspectDuplicates).toBe(0)
|
|
40
|
+
})
|
|
41
|
+
it('does not flag two genuine same-day payments of different amounts', () => {
|
|
42
|
+
const paymentKeys = [
|
|
43
|
+
{ invoiceId: 'i1', paymentId: 'p1', amount: 100, date: '2026-07-01' },
|
|
44
|
+
{ invoiceId: 'i1', paymentId: 'p2', amount: 250, date: '2026-07-01' },
|
|
45
|
+
]
|
|
46
|
+
expect(reconcileLedger({ ...clean, paymentKeys }, NOW).suspectDuplicates).toBe(0)
|
|
47
|
+
})
|
|
48
|
+
it('does not flag the same key repeated under one paymentId', () => {
|
|
49
|
+
const paymentKeys = [
|
|
50
|
+
{ invoiceId: 'i1', paymentId: 'p1', amount: 100, date: '2026-07-01' },
|
|
51
|
+
{ invoiceId: 'i1', paymentId: 'p1', amount: 100, date: '2026-07-01' },
|
|
52
|
+
]
|
|
53
|
+
expect(reconcileLedger({ ...clean, paymentKeys }, NOW).suspectDuplicates).toBe(0)
|
|
54
|
+
})
|
|
55
|
+
it('separates groups by invoice', () => {
|
|
56
|
+
const paymentKeys = [
|
|
57
|
+
{ invoiceId: 'i1', paymentId: 'p1', amount: 100, date: '2026-07-01' },
|
|
58
|
+
{ invoiceId: 'i2', paymentId: 'p2', amount: 100, date: '2026-07-01' },
|
|
59
|
+
]
|
|
60
|
+
expect(reconcileLedger({ ...clean, paymentKeys }, NOW).suspectDuplicates).toBe(0)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('formats one census line carrying every counter', () => {
|
|
64
|
+
const line = formatCensusLine(reconcileLedger(clean, NOW))
|
|
65
|
+
for (const field of [
|
|
66
|
+
'[ledger-census]',
|
|
67
|
+
'invoices=12',
|
|
68
|
+
'payments=20',
|
|
69
|
+
'orphanPayments=0',
|
|
70
|
+
'storedBalanceProps=0',
|
|
71
|
+
'suspectDuplicates=0',
|
|
72
|
+
'declaredNotLive=none',
|
|
73
|
+
]) {
|
|
74
|
+
expect(line).toContain(field)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('names the missing indexes in the line when some are absent', () => {
|
|
79
|
+
const f = reconcileLedger({ ...clean, declaredNotLive: ['cash_entry_account'] }, NOW)
|
|
80
|
+
expect(formatCensusLine(f)).toContain('declaredNotLive=cash_entry_account')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('declares the six ledger index names schema.cypher creates', () => {
|
|
84
|
+
expect(LEDGER_INDEX_NAMES).toHaveLength(6)
|
|
85
|
+
expect(LEDGER_INDEX_NAMES).toContain('cash_entry_account_entryid_unique')
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 1771 — receivables and payables ageing.
|
|
3
|
+
*
|
|
4
|
+
* Buckets are inclusive-lower on whole days past the due date: 0-30 is
|
|
5
|
+
* `current`, 31-60, 61-90, and 91 and above is `d90plus`. An invoice not yet
|
|
6
|
+
* due has a negative age, which clamps to 0 and lands in `current`.
|
|
7
|
+
*
|
|
8
|
+
* Every bucket is a summed money amount, not a count of invoices. Summing is
|
|
9
|
+
* done in minor units so a statement of many decimal amounts does not drift.
|
|
10
|
+
*/
|
|
11
|
+
import { toMinor, fromMinor } from './money.js'
|
|
12
|
+
|
|
13
|
+
const DAY_MS = 86_400_000
|
|
14
|
+
|
|
15
|
+
export interface OpenInvoice {
|
|
16
|
+
ref: string
|
|
17
|
+
dueDateMs: number
|
|
18
|
+
outstanding: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface AgeBuckets {
|
|
22
|
+
current: number
|
|
23
|
+
d31to60: number
|
|
24
|
+
d61to90: number
|
|
25
|
+
d90plus: number
|
|
26
|
+
total: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function ageBuckets(invoices: readonly OpenInvoice[], now: number): AgeBuckets {
|
|
30
|
+
let current = 0
|
|
31
|
+
let d31to60 = 0
|
|
32
|
+
let d61to90 = 0
|
|
33
|
+
let d90plus = 0
|
|
34
|
+
|
|
35
|
+
for (const inv of invoices) {
|
|
36
|
+
const ageDays = Math.max(0, Math.floor((now - inv.dueDateMs) / DAY_MS))
|
|
37
|
+
const minor = toMinor(inv.outstanding)
|
|
38
|
+
if (ageDays <= 30) current += minor
|
|
39
|
+
else if (ageDays <= 60) d31to60 += minor
|
|
40
|
+
else if (ageDays <= 90) d61to90 += minor
|
|
41
|
+
else d90plus += minor
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
current: fromMinor(current),
|
|
46
|
+
d31to60: fromMinor(d31to60),
|
|
47
|
+
d61to90: fromMinor(d61to90),
|
|
48
|
+
d90plus: fromMinor(d90plus),
|
|
49
|
+
total: fromMinor(current + d31to60 + d61to90 + d90plus),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 1771 — the outstanding invariant, defined exactly once.
|
|
3
|
+
*
|
|
4
|
+
* Nothing stores a balance. `outstanding`, `balance` and `amountPaid` are
|
|
5
|
+
* forbidden properties on :Invoice and :InboundInvoice (schema-base.md
|
|
6
|
+
* § Forbidden Properties), because a stored figure drifts silently the moment
|
|
7
|
+
* a payment lands by any other path. Every consumer computes from this module.
|
|
8
|
+
*/
|
|
9
|
+
import { toMinor, fromMinor } from './money.js'
|
|
10
|
+
|
|
11
|
+
export type ApplyResult =
|
|
12
|
+
| { accepted: true; outstandingAfter: number }
|
|
13
|
+
| { accepted: false; reason: 'over-application'; remaining: number }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* outstanding = totalPaymentDue - sum(payments) - sum(credits).
|
|
17
|
+
*
|
|
18
|
+
* A credit reduces what is owed exactly as a payment does; the two differ in
|
|
19
|
+
* provenance, not arithmetic, which is why they are summed together here.
|
|
20
|
+
*/
|
|
21
|
+
export function computeOutstanding(
|
|
22
|
+
totalPaymentDue: number,
|
|
23
|
+
payments: readonly number[],
|
|
24
|
+
credits: readonly number[],
|
|
25
|
+
): number {
|
|
26
|
+
const applied = [...payments, ...credits].reduce((acc, a) => acc + toMinor(a), 0)
|
|
27
|
+
return fromMinor(toMinor(totalPaymentDue) - applied)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Validates one candidate payment or credit against what is still outstanding.
|
|
32
|
+
*
|
|
33
|
+
* Never clamps. A candidate that would take applied-to-date above the invoice
|
|
34
|
+
* total is rejected outright and the caller reports it, rather than silently
|
|
35
|
+
* recording a figure that does not reconcile. A non-positive candidate is
|
|
36
|
+
* rejected for the same reason: it is not a payment.
|
|
37
|
+
*/
|
|
38
|
+
export function applyPayment(
|
|
39
|
+
totalPaymentDue: number,
|
|
40
|
+
payments: readonly number[],
|
|
41
|
+
credits: readonly number[],
|
|
42
|
+
candidate: number,
|
|
43
|
+
): ApplyResult {
|
|
44
|
+
const remaining = computeOutstanding(totalPaymentDue, payments, credits)
|
|
45
|
+
if (toMinor(candidate) <= 0) {
|
|
46
|
+
return { accepted: false, reason: 'over-application', remaining }
|
|
47
|
+
}
|
|
48
|
+
if (toMinor(candidate) > toMinor(remaining)) {
|
|
49
|
+
return { accepted: false, reason: 'over-application', remaining }
|
|
50
|
+
}
|
|
51
|
+
return { accepted: true, outstandingAfter: fromMinor(toMinor(remaining) - toMinor(candidate)) }
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 1771 — money is compared and summed in integer minor units so the
|
|
3
|
+
* outstanding invariant is exact and never subject to float drift. Graph
|
|
4
|
+
* storage is unchanged: `amount` and `totalPaymentDue` stay decimal numbers,
|
|
5
|
+
* matching the existing JobLogic-exact construction rows. Conversion happens
|
|
6
|
+
* here, at the boundary, so no stored value changes shape.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Decimal major units to integer minor units. */
|
|
10
|
+
export function toMinor(n: number): number {
|
|
11
|
+
return Math.round(n * 100)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Integer minor units back to decimal major units. */
|
|
15
|
+
export function fromMinor(n: number): number {
|
|
16
|
+
return n / 100
|
|
17
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 1771 — the ledger census finding.
|
|
3
|
+
*
|
|
4
|
+
* Four of the ledger's failure modes emit no event of their own: a write that
|
|
5
|
+
* was narrated but never landed, a payment with no parent invoice, a stored
|
|
6
|
+
* balance property that has drifted, and a duplicate payment created by a
|
|
7
|
+
* non-deterministic paymentId. None of them can be caught by logging an
|
|
8
|
+
* action, because no action occurs. This reconcile is the substitute, and it
|
|
9
|
+
* is called from two places: the `ledger-reconcile` tool (on demand) and the
|
|
10
|
+
* standing interval in the UI server. Both share this function so the two
|
|
11
|
+
* forms cannot report different things.
|
|
12
|
+
*
|
|
13
|
+
* Pure: no I/O, and `now` is a parameter rather than a Date.now() call.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The index names schema.cypher declares for the ledger. Their absence from a
|
|
17
|
+
* live database means schema.cypher was edited but seed-neo4j.sh never re-ran
|
|
18
|
+
* on that install, which emits nothing on its own. Defined here because both
|
|
19
|
+
* the on-demand tool and the standing census check the same list; two copies
|
|
20
|
+
* would let them disagree about whether the schema is applied. */
|
|
21
|
+
export const LEDGER_INDEX_NAMES: readonly string[] = [
|
|
22
|
+
"invoice_account_confirmation_unique",
|
|
23
|
+
"cash_entry_account_entryid_unique",
|
|
24
|
+
"cash_entry_account",
|
|
25
|
+
"invoice_line_account",
|
|
26
|
+
"invoice_payment_account",
|
|
27
|
+
"credit_account",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
export interface PaymentKey {
|
|
31
|
+
invoiceId: string
|
|
32
|
+
paymentId: string
|
|
33
|
+
amount: number
|
|
34
|
+
date: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LedgerCensusRows {
|
|
38
|
+
invoices: number
|
|
39
|
+
payments: number
|
|
40
|
+
orphanPayments: number
|
|
41
|
+
storedBalanceProps: number
|
|
42
|
+
paymentKeys: readonly PaymentKey[]
|
|
43
|
+
declaredNotLive: readonly string[]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface LedgerCensusFinding {
|
|
47
|
+
invoices: number
|
|
48
|
+
payments: number
|
|
49
|
+
orphanPayments: number
|
|
50
|
+
storedBalanceProps: number
|
|
51
|
+
suspectDuplicates: number
|
|
52
|
+
declaredNotLive: readonly string[]
|
|
53
|
+
alarm: boolean
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Counts payments that share (invoiceId, amount, date) across two or more
|
|
58
|
+
* distinct paymentId values. For a group of n distinct ids the contribution is
|
|
59
|
+
* n-1, because exactly one member of the group is the legitimate payment.
|
|
60
|
+
*
|
|
61
|
+
* Grouping on distinct ids, not on row count, is what keeps a genuine retry
|
|
62
|
+
* quiet: a retry that MERGEs onto the same deterministic paymentId appears
|
|
63
|
+
* twice in the rows but once in the id set, and is not a duplicate.
|
|
64
|
+
*/
|
|
65
|
+
function countSuspectDuplicates(keys: readonly PaymentKey[]): number {
|
|
66
|
+
const groups = new Map<string, Set<string>>()
|
|
67
|
+
for (const k of keys) {
|
|
68
|
+
const composite = `${k.invoiceId}|${k.amount}|${k.date}`
|
|
69
|
+
const ids = groups.get(composite) ?? new Set<string>()
|
|
70
|
+
ids.add(k.paymentId)
|
|
71
|
+
groups.set(composite, ids)
|
|
72
|
+
}
|
|
73
|
+
let total = 0
|
|
74
|
+
for (const ids of groups.values()) total += Math.max(0, ids.size - 1)
|
|
75
|
+
return total
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function reconcileLedger(rows: LedgerCensusRows, _now: number): LedgerCensusFinding {
|
|
79
|
+
const suspectDuplicates = countSuspectDuplicates(rows.paymentKeys)
|
|
80
|
+
const alarm =
|
|
81
|
+
rows.orphanPayments > 0 ||
|
|
82
|
+
rows.storedBalanceProps > 0 ||
|
|
83
|
+
suspectDuplicates > 0 ||
|
|
84
|
+
rows.declaredNotLive.length > 0
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
invoices: rows.invoices,
|
|
88
|
+
payments: rows.payments,
|
|
89
|
+
orphanPayments: rows.orphanPayments,
|
|
90
|
+
storedBalanceProps: rows.storedBalanceProps,
|
|
91
|
+
suspectDuplicates,
|
|
92
|
+
declaredNotLive: rows.declaredNotLive,
|
|
93
|
+
alarm,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The one `[ledger-census]` line format. Shared by the on-demand tool and the
|
|
99
|
+
* standing interval so a log search finds both, and so a new counter cannot be
|
|
100
|
+
* added to one emission and missed by the other.
|
|
101
|
+
*/
|
|
102
|
+
export function formatCensusLine(f: LedgerCensusFinding): string {
|
|
103
|
+
return (
|
|
104
|
+
`[ledger-census] invoices=${f.invoices} payments=${f.payments} ` +
|
|
105
|
+
`orphanPayments=${f.orphanPayments} storedBalanceProps=${f.storedBalanceProps} ` +
|
|
106
|
+
`suspectDuplicates=${f.suspectDuplicates} ` +
|
|
107
|
+
`declaredNotLive=${f.declaredNotLive.length === 0 ? "none" : f.declaredNotLive.join(",")}`
|
|
108
|
+
)
|
|
109
|
+
}
|
|
@@ -467,6 +467,7 @@ FOR (n:LocalBusiness|Service|PriceSpecification|OpeningHoursSpecification|Organi
|
|
|
467
467
|
|Listing|Property|Viewing|Offer|PostalAddress|Sale|Chain|ChainLink
|
|
468
468
|
|Job|Quote|QuoteLine|Valuation|Milestone|VariationNote|Invoice|InboundInvoice|JobCost|WhatsAppGroup
|
|
469
469
|
|Customer|Site|Asset|Visit|Part|PurchaseOrder|PpmContract|Contact|PurchaseOrderLine|InvoiceLine|InvoicePayment|Credit|Note
|
|
470
|
+
|CashEntry
|
|
470
471
|
|Person|UserProfile|Preference|AdminUser|AccessGrant
|
|
471
472
|
|KnowledgeDocument|ConversationArchive|Section|Chunk|DigitalDocument|CreativeWork|Question|FAQPage|DefinedTerm|Review|ImageObject
|
|
472
473
|
|Conversation|AdminConversation|PublicConversation|Message|UserMessage|AssistantMessage|ToolCall
|
|
@@ -1563,9 +1564,24 @@ FOR (ii:InboundInvoice) REQUIRE (ii.accountId, ii.supplier, ii.confirmationNumbe
|
|
|
1563
1564
|
CREATE INDEX inbound_invoice_account IF NOT EXISTS
|
|
1564
1565
|
FOR (ii:InboundInvoice) ON (ii.accountId);
|
|
1565
1566
|
|
|
1567
|
+
// Task 1771 — :Invoice gained the uniqueness constraint schema-base.md already
|
|
1568
|
+
// claimed as its natural key but never declared, so a second write of the same
|
|
1569
|
+
// confirmationNumber merges rather than creating a rival invoice that would
|
|
1570
|
+
// split a payment history in two.
|
|
1571
|
+
CREATE CONSTRAINT invoice_account_confirmation_unique IF NOT EXISTS
|
|
1572
|
+
FOR (i:Invoice) REQUIRE (i.accountId, i.confirmationNumber) IS UNIQUE;
|
|
1573
|
+
|
|
1566
1574
|
CREATE INDEX invoice_account IF NOT EXISTS
|
|
1567
1575
|
FOR (i:Invoice) ON (i.accountId);
|
|
1568
1576
|
|
|
1577
|
+
// :CashEntry (Task 1771) — one movement of money not attached to any invoice.
|
|
1578
|
+
// Direction lives on the node because there is no parent label to derive it
|
|
1579
|
+
// from, unlike :InvoicePayment.
|
|
1580
|
+
CREATE CONSTRAINT cash_entry_account_entryid_unique IF NOT EXISTS
|
|
1581
|
+
FOR (ce:CashEntry) REQUIRE (ce.accountId, ce.entryId) IS UNIQUE;
|
|
1582
|
+
CREATE INDEX cash_entry_account IF NOT EXISTS
|
|
1583
|
+
FOR (ce:CashEntry) ON (ce.accountId);
|
|
1584
|
+
|
|
1569
1585
|
// :CheckIn -> :JobCost (Task 1084). A logged labour day is an incurred labour
|
|
1570
1586
|
// cost (costType:'labour'); JobCost also carries material/travel/mileage/
|
|
1571
1587
|
// expense/subcontractor/scheduleOfRates lines. Clean natural key (costId).
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"services/*"
|
|
7
7
|
],
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "tsc -p lib/models/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p services/claude-session-manager/tsconfig.json && tsc -p services/whatsapp-channel/tsconfig.json && tsc -p services/webchat-channel/tsconfig.json && tsc -p services/telegram-channel/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
|
|
10
|
-
"build:lib": "tsc -p lib/models/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json",
|
|
9
|
+
"build": "tsc -p lib/models/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p services/claude-session-manager/tsconfig.json && tsc -p services/whatsapp-channel/tsconfig.json && tsc -p services/webchat-channel/tsconfig.json && tsc -p services/telegram-channel/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
|
|
10
|
+
"build:lib": "tsc -p lib/models/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json",
|
|
11
11
|
"gen:canonical-tools": "node scripts/generate-canonical-tool-names.mjs",
|
|
12
12
|
"build:memory": "tsc -p plugins/memory/mcp/tsconfig.json",
|
|
13
13
|
"build:contacts": "tsc -p plugins/contacts/mcp/tsconfig.json",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:46e07a18921b711849e53f63b8c29b72f3324f91bc682eb5be585ccd64c98971
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -606,6 +606,54 @@ Pausing keeps a workflow but stops it running. Editing replaces the steps or the
|
|
|
606
606
|
|
|
607
607
|
A workflow can run on a schedule instead of on demand. Tell Maxy when you want it to run, for example "run the daily summary workflow every morning at eight," and it sets up the schedule. Scheduled runs happen with no one present, so a workflow that needs you to supply inputs is best run on demand rather than scheduled.
|
|
608
608
|
|
|
609
|
+
---
|
|
610
|
+
# Cash Book + AR/AP Ledger
|
|
611
|
+
Source: https://docs.getmaxy.com/ledger.md
|
|
612
|
+
|
|
613
|
+
# Ledger
|
|
614
|
+
|
|
615
|
+
A cash book with receivables and payables. It records what you invoiced, what you were billed, what was paid, and money that moved without an invoice, then tells you what is still outstanding.
|
|
616
|
+
|
|
617
|
+
## What it is not
|
|
618
|
+
|
|
619
|
+
It is not double-entry bookkeeping. There is no chart of accounts, no journals, no trial balance. It computes no VAT and handles a single currency. It does not read bank feeds and it does not talk to QuickBooks.
|
|
620
|
+
|
|
621
|
+
If you need statutory accounts, this is not that. It is the answer to "who owes me what, what do I owe, and where did the money go".
|
|
622
|
+
|
|
623
|
+
## The seven things you can ask for
|
|
624
|
+
|
|
625
|
+
**Record an invoice you raised.** A reference, who owes you, the amount, and when it is due.
|
|
626
|
+
|
|
627
|
+
**Record a bill you received.** The same, in the other direction.
|
|
628
|
+
|
|
629
|
+
**Record a payment.** Against either an invoice or a bill. You give the reference, the amount, the date and how it was paid.
|
|
630
|
+
|
|
631
|
+
**Record a credit.** Against an invoice you raised. It reduces what is owed exactly as a payment does.
|
|
632
|
+
|
|
633
|
+
**Record a cash movement.** Money in or out that belongs to no invoice: bank charges, a cash sale, drawings, a refund.
|
|
634
|
+
|
|
635
|
+
**Ask what is outstanding on one document.** You get the total, what has been paid, what has been credited, and what remains.
|
|
636
|
+
|
|
637
|
+
**Ask for a statement.** Everything owed to you and everything you owe, sorted into 0-30, 31-60, 61-90 and 90+ days overdue, plus net cash.
|
|
638
|
+
|
|
639
|
+
## Three behaviours worth knowing about
|
|
640
|
+
|
|
641
|
+
**What is outstanding is never stored.** It is worked out from the payments each time you ask. This means the figure cannot fall out of step with the payments behind it. If it were stored, a payment recorded by any route that forgot to update it would leave the invoice quietly reporting a wrong number, and nothing would fail.
|
|
642
|
+
|
|
643
|
+
**Paying more than is owed is refused.** If an invoice has 4,400 left and you try to record 5,000, nothing is written and you are told the figure that would settle it. It is not rounded down to 4,400 and it is not recorded anyway. A ledger that quietly accepts an impossible payment is worse than one that says no.
|
|
644
|
+
|
|
645
|
+
**Every payment is read back.** After a payment is written, the invoice is re-read from the graph and the outstanding figure is checked against what was expected. If they disagree you are told to stop recording against that invoice until it is sorted out. Writing something is not the same as it having landed.
|
|
646
|
+
|
|
647
|
+
## The health check
|
|
648
|
+
|
|
649
|
+
Some ways this can go wrong announce themselves. Others do not: a payment that ends up attached to no invoice, a stale balance field reappearing, or the same payment recorded twice under two different ids. None of those produce an error at the time, because nothing goes wrong at the moment they happen.
|
|
650
|
+
|
|
651
|
+
So there is a check that runs by itself every fifteen minutes and writes one line to the log beginning `[ledger-census]`. When it is healthy the counters are all zero. When something is wrong the line ends with `alarm=true` and says which of the four it found.
|
|
652
|
+
|
|
653
|
+
You can also ask for that check on demand at any time, and it reports the same thing in plain words.
|
|
654
|
+
|
|
655
|
+
If you never see the line at all, that is itself the problem: it means the periodic check is not running.
|
|
656
|
+
|
|
609
657
|
---
|
|
610
658
|
# Install Overview
|
|
611
659
|
Source: https://docs.getmaxy.com/install.md
|
|
@@ -3138,6 +3186,54 @@ A 0.000 reading that persists across many polls while `top` shows load
|
|
|
3138
3186
|
is the delta-cache regression signature (the single-flight promise was
|
|
3139
3187
|
not released).
|
|
3140
3188
|
|
|
3189
|
+
## Activity view
|
|
3190
|
+
|
|
3191
|
+
Source:
|
|
3192
|
+
[`server/routes/admin/activity.ts`](../../../ui/server/routes/admin/activity.ts)
|
|
3193
|
+
(house-gated proxy) and
|
|
3194
|
+
[`platform/ui/app/activity/page.tsx`](../../../ui/app/activity/page.tsx)
|
|
3195
|
+
(page). CSS lives under `.activity*` in
|
|
3196
|
+
[`platform/ui/app/globals.css`](../../../ui/app/globals.css).
|
|
3197
|
+
|
|
3198
|
+
**What it shows.** `/activity` lists every live session across every account
|
|
3199
|
+
in the install, one row per session: account, title, model, status, age, idle,
|
|
3200
|
+
turn count, RSS, CPU %, cumulative tokens, and imputed GBP cost. Columns sort
|
|
3201
|
+
on click. The sidebar session list is scoped to the caller's own account, so
|
|
3202
|
+
this is the only surface that answers "where is the activity" install-wide.
|
|
3203
|
+
|
|
3204
|
+
**House account only.** The manager binds loopback and gates nothing, so the
|
|
3205
|
+
scoping lives on the admin route. The house is resolved by the same three-arm
|
|
3206
|
+
predicate the spawn path uses (`resolveAccountDir`): exactly one `role:"house"`
|
|
3207
|
+
account, else a sole account declaring no role, else deny — two houses is
|
|
3208
|
+
corruption and denies rather than picking one. Both operands are null-checked,
|
|
3209
|
+
because `caller === house` alone is true for two nulls. A caller pinned
|
|
3210
|
+
elsewhere receives 403 and a logged `op=gate decision=deny` carrying its
|
|
3211
|
+
reason. The `HeaderMenu` item is admin-variant only for the same reason.
|
|
3212
|
+
|
|
3213
|
+
Be precise about what this is. Under the install-wide access model every
|
|
3214
|
+
authenticated install admin can re-pin to any account via
|
|
3215
|
+
`POST /api/admin/session/switch-account`, so the gate is a scope selector, not
|
|
3216
|
+
an authority boundary between privilege levels.
|
|
3217
|
+
|
|
3218
|
+
**Where the numbers come from.** The manager assembles them at its own
|
|
3219
|
+
`GET /activity`, joining the live PTY set, the watcher's per-row `accountId`,
|
|
3220
|
+
the JSONL enumerator (turns, model, tokens, last message), the PTY census
|
|
3221
|
+
(RSS and CPU), and a bounded metering fan-out. The admin route adds the one
|
|
3222
|
+
fact the manager cannot see: the `data/accounts` directory count, taken
|
|
3223
|
+
independently of `listValidAccounts()` so a rejected account shows as
|
|
3224
|
+
`onDisk > valid` rather than silently shortening the list.
|
|
3225
|
+
|
|
3226
|
+
**Reading the cells.** A dash means unmeasured, never zero — an unmeasured CPU
|
|
3227
|
+
is not an idle session. Cost is the price arm matching the row's own model,
|
|
3228
|
+
because the metering core prices one token count under both Opus and Sonnet
|
|
3229
|
+
assumptions without knowing which ran; a model in neither family shows a dash.
|
|
3230
|
+
Every dashed cost carries its reason as a tooltip, so an unpriced model, a
|
|
3231
|
+
failed parse and a session with no transcript are distinguishable rather than
|
|
3232
|
+
three readings of the same glyph.
|
|
3233
|
+
A session whose sidecar carries no account shows `untagged` rather than being
|
|
3234
|
+
folded into the house. The census age is rendered because the snapshot is a 60s
|
|
3235
|
+
sample and a dead collector emits nothing.
|
|
3236
|
+
|
|
3141
3237
|
## Sidebar surfaces
|
|
3142
3238
|
|
|
3143
3239
|
The sidebar is the entire left column of the admin UI. Its full layout,
|
|
@@ -3973,7 +4069,7 @@ This tool is read-only and available to both public and admin agents.
|
|
|
3973
4069
|
|
|
3974
4070
|
### When conversations are created
|
|
3975
4071
|
|
|
3976
|
-
`:Conversation` nodes on webchat (admin login, "New conversation" in the burger, a new public visitor) are created lazily. Opening the chat or logging in does not write anything to the graph — Maxy only records the conversation once the user sends a second message. This keeps `conversation-search` and the Conversations modal free of one-turn abandoned threads. WhatsApp and Telegram take the opposite posture: every inbound — DM or group, allowed or activation-off, agent-invoked or gated — MERGEs the `:Conversation` and writes a forensic `:Message:WhatsAppMessage` row before any access-control decision. The graph is the durable record of every message the device received, not just the ones the agent replied to. See `.docs/web-chat.md` "Deferred conversation persistence"
|
|
4072
|
+
`:Conversation` nodes on webchat (admin login, "New conversation" in the burger, a new public visitor) are created lazily. Opening the chat or logging in does not write anything to the graph — Maxy only records the conversation once the user sends a second message. This keeps `conversation-search` and the Conversations modal free of one-turn abandoned threads. WhatsApp and Telegram take the opposite posture: every inbound — DM or group, allowed or activation-off, agent-invoked or gated — MERGEs the `:Conversation` and writes a forensic `:Message:WhatsAppMessage` row before any access-control decision. The graph is the durable record of every message the device received, not just the ones the agent replied to. That forensic row is addressed by cacheKey (`default:<phone>`) on the socket-owning account and deliberately has no session behind it. A WhatsApp sender therefore carries a **second** `:Conversation`: the anchored row written at spawn on the account the session actually runs under, keyed by the session's own deterministic id, which is the row every `MATCH (c:Conversation {sessionId: $SESSION_ID})` resolves. Two rows, two jobs, not duplicates. See `.docs/web-chat.md` "Deferred conversation persistence", `.docs/whatsapp.md` "Session continuity", and `.docs/session-conversation-identity.md` for the per-channel identity contract.
|
|
3977
4073
|
|
|
3978
4074
|
Each row in the Conversations modal exposes a `View logs` row-action that opens a popover with three links — **Stream**, **Errors**, **SSE** — each of which targets `/api/admin/logs?type={stream|error|sse}&sessionId={full-id}` in a new tab. The row's 8-char id chip is click-to-copy; hover reveals the full `sessionId` as a tooltip. See `.docs/web-chat.md` "In-chat retrieval" for the route contract and `console.debug` observability.
|
|
3979
4075
|
|