@idleware/ringi 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +5 -1
- package/target/dts/adapters/fs/index.d.ts +2 -0
- package/target/dts/adapters/fs/lock.d.ts +1 -0
- package/target/dts/adapters/fs/write.d.ts +5 -0
- package/target/dts/adapters/host-posix/group-state.d.ts +7 -0
- package/target/dts/adapters/host-posix/groups.d.ts +1 -0
- package/target/dts/adapters/host-posix/index.d.ts +2 -0
- package/target/dts/adapters/host-posix/launch.d.ts +7 -0
- package/target/dts/adapters/host-posix/probes.d.ts +5 -0
- package/target/dts/adapters/host-posix/stats.d.ts +9 -0
- package/target/dts/adapters/keys-file/index.d.ts +2 -0
- package/target/dts/adapters/state-fs/index.d.ts +5 -0
- package/target/dts/adapters/tool-claude/index.d.ts +2 -0
- package/target/dts/adapters/tool-codex/index.d.ts +2 -0
- package/target/dts/adapters/tool-cursor/index.d.ts +2 -0
- package/target/dts/adapters/tool-traces/index.d.ts +3 -0
- package/target/dts/adapters/transport-git/branches.d.ts +43 -0
- package/target/dts/adapters/transport-git/files.d.ts +2 -0
- package/target/dts/adapters/transport-git/index.d.ts +32 -0
- package/target/dts/adapters/transport-git/marks.d.ts +20 -0
- package/target/dts/adapters/transport-git/remote/admit.d.ts +7 -0
- package/target/dts/adapters/transport-git/remote/alarms.d.ts +3 -0
- package/target/dts/adapters/transport-git/remote/bootstrap.d.ts +7 -0
- package/target/dts/adapters/transport-git/remote/branch-commit.d.ts +3 -0
- package/target/dts/adapters/transport-git/remote/branch-control.d.ts +15 -0
- package/target/dts/adapters/transport-git/remote/branch-scan.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/branch.d.ts +5 -0
- package/target/dts/adapters/transport-git/remote/cache.d.ts +3 -0
- package/target/dts/adapters/transport-git/remote/commits.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/forget.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/git.d.ts +26 -0
- package/target/dts/adapters/transport-git/remote/heartbeat-facts.d.ts +1 -0
- package/target/dts/adapters/transport-git/remote/heartbeat-name.d.ts +6 -0
- package/target/dts/adapters/transport-git/remote/heartbeat-object.d.ts +10 -0
- package/target/dts/adapters/transport-git/remote/heartbeat-push.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/heartbeat.d.ts +7 -0
- package/target/dts/adapters/transport-git/remote/keys.d.ts +13 -0
- package/target/dts/adapters/transport-git/remote/main.d.ts +11 -0
- package/target/dts/adapters/transport-git/remote/process.d.ts +20 -0
- package/target/dts/adapters/transport-git/remote/push-retry.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/push-validate.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/push.d.ts +16 -0
- package/target/dts/adapters/transport-git/remote/roster.d.ts +7 -0
- package/target/dts/adapters/transport-git/remote/signals.d.ts +15 -0
- package/target/dts/adapters/transport-git/remote/signature.d.ts +5 -0
- package/target/dts/adapters/transport-git/remote/sync-heartbeat.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/sync-rooms.d.ts +6 -0
- package/target/dts/adapters/transport-git/remote/sync-tags.d.ts +8 -0
- package/target/dts/adapters/transport-git/remote/sync.d.ts +2 -0
- package/target/dts/adapters/transport-git/remote/types.d.ts +64 -0
- package/target/dts/adapters/transport-git/remote.d.ts +17 -0
- package/target/dts/adapters/transport-git/repo.d.ts +31 -0
- package/target/dts/adapters/transport-git/run.d.ts +21 -0
- package/target/dts/adapters/transport-git/signing.d.ts +4 -0
- package/target/dts/adapters/transport-git/tags.d.ts +15 -0
- package/target/dts/adapters/transport-git/transport.d.ts +7 -0
- package/target/dts/adapters/transport-kafka/index.d.ts +2 -0
- package/target/dts/adapters/transport-temporal/index.d.ts +2 -0
- package/target/dts/cli.d.ts +2 -1
- package/target/dts/{cli/agent.d.ts → clients/cli/agent/index.d.ts} +3 -3
- package/target/dts/{cli → clients/cli/agent}/session.d.ts +2 -2
- package/target/dts/clients/cli/arg-parse.d.ts +2 -0
- package/target/dts/{cli → clients/cli}/args.d.ts +2 -2
- package/target/dts/clients/cli/commands.d.ts +2 -0
- package/target/dts/clients/cli/context.d.ts +4 -0
- package/target/dts/{cli/index.d.ts → clients/cli/help.d.ts} +1 -3
- package/target/dts/clients/cli/index.d.ts +4 -0
- package/target/dts/clients/cli/operator/heartbeat-format.d.ts +5 -0
- package/target/dts/clients/cli/operator/heartbeat.d.ts +3 -0
- package/target/dts/clients/cli/operator/hub-commands.d.ts +6 -0
- package/target/dts/clients/cli/operator/hub.d.ts +2 -0
- package/target/dts/clients/cli/operator/index.d.ts +5 -0
- package/target/dts/clients/cli/operator/room-lifecycle.d.ts +5 -0
- package/target/dts/clients/cli/operator/room-list.d.ts +5 -0
- package/target/dts/clients/cli/operator/room-members.d.ts +4 -0
- package/target/dts/clients/cli/operator/room.d.ts +2 -0
- package/target/dts/clients/cli/operator/sessions.d.ts +5 -0
- package/target/dts/clients/cli/operator/watch.d.ts +2 -0
- package/target/dts/clients/cli/operator/where-format.d.ts +7 -0
- package/target/dts/clients/cli/operator/where.d.ts +2 -0
- package/target/dts/clients/cli/shared/budget.d.ts +7 -0
- package/target/dts/clients/cli/shared/files.d.ts +4 -0
- package/target/dts/clients/cli/shared/index.d.ts +7 -0
- package/target/dts/clients/cli/shared/messages.d.ts +7 -0
- package/target/dts/clients/cli/shared/profile.d.ts +4 -0
- package/target/dts/clients/cli/shared/session.d.ts +6 -0
- package/target/dts/clients/cli/shared/signals.d.ts +3 -0
- package/target/dts/clients/cli/shared/work.d.ts +6 -0
- package/target/dts/clients/cli/skill/index.d.ts +3 -0
- package/target/dts/{cli/skill.d.ts → clients/cli/skill/targets.d.ts} +1 -2
- package/target/dts/composition/index.d.ts +2 -0
- package/target/dts/core/agents/heartbeat/index.d.ts +33 -0
- package/target/dts/core/agents/heartbeat/pulse.d.ts +32 -0
- package/target/dts/core/agents/heartbeat/singleton.d.ts +3 -0
- package/target/dts/core/agents/heartbeat/tools.d.ts +6 -0
- package/target/dts/{app → core/agents}/overview.d.ts +12 -6
- package/target/dts/core/agents/ports/host.d.ts +47 -0
- package/target/dts/core/agents/ports/index.d.ts +9 -0
- package/target/dts/core/agents/ports/tools.d.ts +18 -0
- package/target/dts/core/agents/sessions/agent.d.ts +70 -0
- package/target/dts/core/agents/sessions/binding.d.ts +9 -0
- package/target/dts/core/agents/sessions/context.d.ts +8 -0
- package/target/dts/{runtime/session.d.ts → core/agents/sessions/index.d.ts} +2 -9
- package/target/dts/core/agents/sessions/join.d.ts +20 -0
- package/target/dts/core/agents/sessions/resume.d.ts +2 -0
- package/target/dts/core/agents/sessions/session.d.ts +46 -0
- package/target/dts/core/agents/sessions/wait.d.ts +38 -0
- package/target/dts/core/agents/turns/budgets.d.ts +5 -0
- package/target/dts/core/agents/turns/dispatch.d.ts +9 -0
- package/target/dts/core/agents/turns/exhaustion.d.ts +11 -0
- package/target/dts/core/agents/turns/grants.d.ts +4 -0
- package/target/dts/core/agents/turns/index.d.ts +4 -0
- package/target/dts/core/agents/turns/limits.d.ts +2 -0
- package/target/dts/core/agents/turns/messages.d.ts +10 -0
- package/target/dts/core/agents/turns/pings.d.ts +5 -0
- package/target/dts/core/agents/turns/plan.d.ts +3 -0
- package/target/dts/core/agents/turns/poll.d.ts +8 -0
- package/target/dts/core/agents/turns/results.d.ts +3 -0
- package/target/dts/core/agents/turns/seat.d.ts +2 -0
- package/target/dts/core/agents/turns/types.d.ts +59 -0
- package/target/dts/core/hub/decisions/budget.d.ts +15 -0
- package/target/dts/core/hub/decisions/check.d.ts +6 -0
- package/target/dts/core/hub/decisions/index.d.ts +5 -0
- package/target/dts/core/hub/decisions/proposal.d.ts +38 -0
- package/target/dts/core/hub/decisions/usage.d.ts +12 -0
- package/target/dts/{runtime/reader.d.ts → core/hub/history/index.d.ts} +12 -6
- package/target/dts/core/hub/ports/index.d.ts +16 -0
- package/target/dts/core/hub/ports/state.d.ts +12 -0
- package/target/dts/{store/index.d.ts → core/hub/ports/store.d.ts} +58 -17
- package/target/dts/core/hub/protocol/index.d.ts +5 -0
- package/target/dts/{protocol/index.d.ts → core/hub/protocol/model.d.ts} +0 -25
- package/target/dts/core/hub/protocol/order.d.ts +2 -0
- package/target/dts/core/hub/protocol/reading.d.ts +8 -0
- package/target/dts/core/hub/protocol/text.d.ts +11 -0
- package/target/dts/core/hub/protocol/threads.d.ts +5 -0
- package/target/dts/core/hub/rooms/compat.d.ts +5 -0
- package/target/dts/core/hub/rooms/hubs.d.ts +14 -0
- package/target/dts/core/hub/rooms/index.d.ts +53 -0
- package/target/dts/core/hub/rooms/messages.d.ts +8 -0
- package/target/dts/core/hub/rooms/rooms.d.ts +10 -0
- package/target/dts/core/hub/signals/check.d.ts +3 -0
- package/target/dts/core/hub/signals/effective.d.ts +3 -0
- package/target/dts/core/hub/signals/index.d.ts +5 -0
- package/target/dts/core/hub/signals/marks.d.ts +4 -0
- package/target/dts/core/hub/signals/model.d.ts +28 -0
- package/target/dts/core/hub/signals/pins.d.ts +5 -0
- package/target/dts/{hub/signals.d.ts → core/hub/signals/write.d.ts} +1 -1
- package/target/dts/core/hub/usecases/actor.d.ts +6 -0
- package/target/dts/{app → core/hub/usecases}/budget.d.ts +5 -18
- package/target/dts/core/hub/usecases/config.d.ts +6 -0
- package/target/dts/{app → core/hub/usecases}/context.d.ts +3 -8
- package/target/dts/{app → core/hub/usecases}/hubs.d.ts +1 -1
- package/target/dts/core/hub/usecases/propose.d.ts +17 -0
- package/target/dts/{app → core/hub/usecases}/room.d.ts +8 -33
- package/target/dts/{app → core/hub/usecases}/rooms.d.ts +2 -6
- package/target/dts/core/hub/usecases/roster.d.ts +5 -0
- package/target/dts/core/hub/usecases/send.d.ts +21 -0
- package/target/dts/core/hub/usecases/staging.d.ts +8 -0
- package/target/dts/{app → core/hub/usecases}/view.d.ts +4 -4
- package/target/dts/{domain/profiles.d.ts → core/hub/work/index.d.ts} +3 -7
- package/target/dts/core/hub/work/parse.d.ts +2 -0
- package/target/dts/core/hub/work/task.d.ts +6 -0
- package/target/dts/core/signing/index.d.ts +35 -0
- package/target/dts/index.d.ts +8 -8
- package/target/dts/lib/fail.d.ts +8 -0
- package/target/dts/lib/index.d.ts +3 -11
- package/target/dts/lib/json.d.ts +1 -0
- package/target/esm/adapters/fs/index.js +5 -0
- package/target/esm/adapters/fs/lock.js +83 -0
- package/target/esm/adapters/fs/write.js +25 -0
- package/target/esm/adapters/host-posix/group-state.js +24 -0
- package/target/esm/adapters/host-posix/groups.js +43 -0
- package/target/esm/adapters/host-posix/index.js +35 -0
- package/target/esm/adapters/host-posix/launch.js +80 -0
- package/target/esm/adapters/host-posix/probes.js +66 -0
- package/target/esm/adapters/host-posix/stats.js +27 -0
- package/target/esm/adapters/keys-file/index.js +68 -0
- package/target/esm/adapters/state-fs/index.js +79 -0
- package/target/esm/adapters/tool-claude/index.js +32 -0
- package/target/esm/adapters/tool-codex/index.js +38 -0
- package/target/esm/adapters/tool-cursor/index.js +8 -0
- package/target/esm/adapters/tool-traces/index.js +18 -0
- package/target/esm/adapters/transport-git/branches.js +155 -0
- package/target/esm/adapters/transport-git/files.js +48 -0
- package/target/esm/adapters/transport-git/index.js +128 -0
- package/target/esm/adapters/transport-git/marks.js +88 -0
- package/target/esm/adapters/transport-git/remote/admit.js +71 -0
- package/target/esm/adapters/transport-git/remote/alarms.js +30 -0
- package/target/esm/adapters/transport-git/remote/bootstrap.js +47 -0
- package/target/esm/adapters/transport-git/remote/branch-commit.js +36 -0
- package/target/esm/adapters/transport-git/remote/branch-control.js +37 -0
- package/target/esm/adapters/transport-git/remote/branch-scan.js +28 -0
- package/target/esm/adapters/transport-git/remote/branch.js +37 -0
- package/target/esm/adapters/transport-git/remote/cache.js +23 -0
- package/target/esm/adapters/transport-git/remote/commits.js +25 -0
- package/target/esm/adapters/transport-git/remote/forget.js +35 -0
- package/target/esm/adapters/transport-git/remote/git.js +58 -0
- package/target/esm/adapters/transport-git/remote/heartbeat-facts.js +35 -0
- package/target/esm/adapters/transport-git/remote/heartbeat-name.js +19 -0
- package/target/esm/adapters/transport-git/remote/heartbeat-object.js +40 -0
- package/target/esm/adapters/transport-git/remote/heartbeat-push.js +44 -0
- package/target/esm/adapters/transport-git/remote/heartbeat.js +44 -0
- package/target/esm/adapters/transport-git/remote/keys.js +75 -0
- package/target/esm/adapters/transport-git/remote/main.js +41 -0
- package/target/esm/adapters/transport-git/remote/process.js +37 -0
- package/target/esm/adapters/transport-git/remote/push-retry.js +46 -0
- package/target/esm/adapters/transport-git/remote/push-validate.js +39 -0
- package/target/esm/adapters/transport-git/remote/push.js +62 -0
- package/target/esm/adapters/transport-git/remote/roster.js +48 -0
- package/target/esm/adapters/transport-git/remote/signals.js +63 -0
- package/target/esm/adapters/transport-git/remote/signature.js +56 -0
- package/target/esm/adapters/transport-git/remote/sync-heartbeat.js +26 -0
- package/target/esm/adapters/transport-git/remote/sync-rooms.js +38 -0
- package/target/esm/adapters/transport-git/remote/sync-tags.js +48 -0
- package/target/esm/adapters/transport-git/remote/sync.js +38 -0
- package/target/esm/adapters/transport-git/remote/types.js +10 -0
- package/target/esm/adapters/transport-git/remote.js +17 -0
- package/target/esm/adapters/transport-git/repo.js +115 -0
- package/target/esm/adapters/transport-git/run.js +57 -0
- package/target/esm/adapters/transport-git/signing.js +44 -0
- package/target/esm/adapters/transport-git/tags.js +21 -0
- package/target/esm/adapters/transport-git/transport.js +29 -0
- package/target/esm/adapters/transport-kafka/index.js +4 -0
- package/target/esm/adapters/transport-temporal/index.js +4 -0
- package/target/esm/cli.js +5 -4
- package/target/esm/{cli/agent.js → clients/cli/agent/index.js} +8 -7
- package/target/esm/{cli → clients/cli/agent}/session.js +13 -7
- package/target/esm/clients/cli/arg-parse.js +41 -0
- package/target/esm/{cli → clients/cli}/args.js +3 -36
- package/target/esm/clients/cli/commands.js +45 -0
- package/target/esm/clients/cli/context.js +6 -0
- package/target/esm/{cli/index.js → clients/cli/help.js} +6 -73
- package/target/esm/clients/cli/index.js +27 -0
- package/target/esm/clients/cli/operator/heartbeat-format.js +8 -0
- package/target/esm/clients/cli/operator/heartbeat.js +35 -0
- package/target/esm/clients/cli/operator/hub-commands.js +37 -0
- package/target/esm/clients/cli/operator/hub.js +10 -0
- package/target/esm/clients/cli/operator/index.js +8 -0
- package/target/esm/clients/cli/operator/room-lifecycle.js +23 -0
- package/target/esm/clients/cli/operator/room-list.js +27 -0
- package/target/esm/clients/cli/operator/room-members.js +15 -0
- package/target/esm/clients/cli/operator/room.js +15 -0
- package/target/esm/clients/cli/operator/sessions.js +32 -0
- package/target/esm/clients/cli/operator/watch.js +15 -0
- package/target/esm/clients/cli/operator/where-format.js +24 -0
- package/target/esm/clients/cli/operator/where.js +32 -0
- package/target/esm/clients/cli/shared/budget.js +50 -0
- package/target/esm/clients/cli/shared/files.js +26 -0
- package/target/esm/clients/cli/shared/index.js +10 -0
- package/target/esm/clients/cli/shared/messages.js +41 -0
- package/target/esm/clients/cli/shared/profile.js +17 -0
- package/target/esm/clients/cli/shared/session.js +8 -0
- package/target/esm/clients/cli/shared/signals.js +21 -0
- package/target/esm/clients/cli/shared/work.js +26 -0
- package/target/esm/clients/cli/skill/index.js +40 -0
- package/target/esm/clients/cli/skill/targets.js +20 -0
- package/target/esm/composition/index.js +34 -0
- package/target/esm/core/agents/heartbeat/index.js +43 -0
- package/target/esm/core/agents/heartbeat/pulse.js +86 -0
- package/target/esm/core/agents/heartbeat/singleton.js +38 -0
- package/target/esm/core/agents/heartbeat/tools.js +24 -0
- package/target/esm/{app → core/agents}/overview.js +15 -9
- package/target/esm/core/agents/ports/host.js +4 -0
- package/target/esm/core/agents/ports/index.js +7 -0
- package/target/esm/core/agents/ports/tools.js +5 -0
- package/target/esm/{app → core/agents/sessions}/agent.js +11 -43
- package/target/esm/core/agents/sessions/binding.js +43 -0
- package/target/esm/core/agents/sessions/context.js +11 -0
- package/target/esm/core/agents/sessions/index.js +59 -0
- package/target/esm/core/agents/sessions/join.js +55 -0
- package/target/esm/core/agents/sessions/resume.js +54 -0
- package/target/esm/core/agents/sessions/session.js +28 -0
- package/target/esm/core/agents/sessions/wait.js +47 -0
- package/target/esm/core/agents/turns/budgets.js +48 -0
- package/target/esm/core/agents/turns/dispatch.js +40 -0
- package/target/esm/core/agents/turns/exhaustion.js +16 -0
- package/target/esm/core/agents/turns/grants.js +36 -0
- package/target/esm/core/agents/turns/index.js +33 -0
- package/target/esm/core/agents/turns/limits.js +11 -0
- package/target/esm/core/agents/turns/messages.js +32 -0
- package/target/esm/core/agents/turns/pings.js +30 -0
- package/target/esm/core/agents/turns/plan.js +29 -0
- package/target/esm/core/agents/turns/poll.js +48 -0
- package/target/esm/core/agents/turns/results.js +40 -0
- package/target/esm/core/agents/turns/seat.js +44 -0
- package/target/esm/core/agents/turns/types.js +3 -0
- package/target/esm/{domain/index.js → core/hub/capabilities.js} +3 -3
- package/target/esm/core/hub/decisions/budget.js +40 -0
- package/target/esm/core/hub/decisions/check.js +43 -0
- package/target/esm/core/hub/decisions/index.js +10 -0
- package/target/esm/core/hub/decisions/proposal.js +73 -0
- package/target/esm/core/hub/decisions/usage.js +39 -0
- package/target/esm/core/hub/history/index.js +90 -0
- package/target/esm/core/hub/ports/index.js +10 -0
- package/target/esm/core/hub/ports/state.js +5 -0
- package/target/esm/core/hub/ports/store.js +10 -0
- package/target/esm/{protocol → core/hub/protocol}/files.js +4 -2
- package/target/esm/core/hub/protocol/index.js +9 -0
- package/target/esm/core/hub/protocol/model.js +15 -0
- package/target/esm/core/hub/protocol/order.js +39 -0
- package/target/esm/core/hub/protocol/reading.js +29 -0
- package/target/esm/core/hub/protocol/text.js +95 -0
- package/target/esm/core/hub/protocol/threads.js +52 -0
- package/target/esm/core/hub/rooms/compat.js +42 -0
- package/target/esm/core/hub/rooms/hubs.js +92 -0
- package/target/esm/core/hub/rooms/index.js +23 -0
- package/target/esm/core/hub/rooms/messages.js +47 -0
- package/target/esm/core/hub/rooms/rooms.js +84 -0
- package/target/esm/core/hub/signals/check.js +33 -0
- package/target/esm/core/hub/signals/effective.js +31 -0
- package/target/esm/core/hub/signals/index.js +23 -0
- package/target/esm/core/hub/signals/marks.js +30 -0
- package/target/esm/core/hub/signals/model.js +5 -0
- package/target/esm/core/hub/signals/pins.js +21 -0
- package/target/esm/{hub/signals.js → core/hub/signals/write.js} +4 -4
- package/target/esm/core/hub/usecases/actor.js +3 -0
- package/target/esm/core/hub/usecases/budget.js +78 -0
- package/target/esm/core/hub/usecases/config.js +5 -0
- package/target/esm/core/hub/usecases/context.js +13 -0
- package/target/esm/core/hub/usecases/hubs.js +95 -0
- package/target/esm/core/hub/usecases/propose.js +39 -0
- package/target/esm/core/hub/usecases/room.js +82 -0
- package/target/esm/{app → core/hub/usecases}/rooms.js +11 -63
- package/target/esm/core/hub/usecases/roster.js +47 -0
- package/target/esm/core/hub/usecases/send.js +78 -0
- package/target/esm/core/hub/usecases/staging.js +60 -0
- package/target/esm/{app → core/hub/usecases}/view.js +33 -33
- package/target/esm/core/hub/work/index.js +13 -0
- package/target/esm/core/hub/work/parse.js +37 -0
- package/target/esm/core/hub/work/task.js +68 -0
- package/target/esm/core/signing/index.js +4 -0
- package/target/esm/index.js +7 -6
- package/target/esm/lib/fail.js +18 -0
- package/target/esm/lib/index.js +20 -195
- package/target/esm/lib/json.js +81 -0
- package/target/dts/app/agent.d.ts +0 -109
- package/target/dts/app/session.d.ts +0 -65
- package/target/dts/cli/context.d.ts +0 -6
- package/target/dts/cli/operator.d.ts +0 -8
- package/target/dts/cli/shared.d.ts +0 -27
- package/target/dts/domain/decisions.d.ts +0 -65
- package/target/dts/domain/signals.d.ts +0 -37
- package/target/dts/home/index.d.ts +0 -21
- package/target/dts/hub/index.d.ts +0 -72
- package/target/dts/runtime/watch.d.ts +0 -17
- package/target/dts/store/git/index.d.ts +0 -79
- package/target/dts/store/git/remote.d.ts +0 -86
- package/target/dts/store/kafka/index.d.ts +0 -2
- package/target/dts/store/temporal/index.d.ts +0 -2
- package/target/esm/app/budget.js +0 -95
- package/target/esm/app/context.js +0 -16
- package/target/esm/app/hubs.js +0 -76
- package/target/esm/app/room.js +0 -163
- package/target/esm/app/session.js +0 -99
- package/target/esm/cli/context.js +0 -8
- package/target/esm/cli/operator.js +0 -157
- package/target/esm/cli/shared.js +0 -159
- package/target/esm/cli/skill.js +0 -54
- package/target/esm/domain/decisions.js +0 -178
- package/target/esm/domain/profiles.js +0 -96
- package/target/esm/domain/signals.js +0 -134
- package/target/esm/home/index.js +0 -88
- package/target/esm/hub/index.js +0 -224
- package/target/esm/protocol/index.js +0 -219
- package/target/esm/runtime/reader.js +0 -65
- package/target/esm/runtime/session.js +0 -116
- package/target/esm/runtime/watch.js +0 -321
- package/target/esm/store/git/index.js +0 -644
- package/target/esm/store/git/remote.js +0 -758
- package/target/esm/store/index.js +0 -15
- package/target/esm/store/kafka/index.js +0 -3
- package/target/esm/store/temporal/index.js +0 -3
- /package/target/dts/{domain/index.d.ts → core/hub/capabilities.d.ts} +0 -0
- /package/target/dts/{protocol → core/hub/protocol}/files.d.ts +0 -0
package/target/esm/home/index.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// home: where ringi keeps its state on this machine. $RINGI_HOME holds hubs (each a descriptor and a store),
|
|
2
|
-
// reader state, session records and locks. Reading state fails closed; a write the sandbox denies fails with one
|
|
3
|
-
// fixed instruction.
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import os from 'node:os';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import { spawnSync } from 'node:child_process';
|
|
8
|
-
import { fileURLToPath } from 'node:url';
|
|
9
|
-
import { errno, fail, guardWrite, locked as lockFile, mkdirIn, note, writeJsonAtomic } from '../lib/index.js';
|
|
10
|
-
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
// This file sits in src/main/ts/home (source) or target/esm/home (build): three levels below the package root.
|
|
12
|
-
export const ROOT = path.resolve(HERE, '..', '..', '..');
|
|
13
|
-
export const RESOURCES = path.join(ROOT, 'src', 'main', 'resources');
|
|
14
|
-
export const VERSION = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version;
|
|
15
|
-
export const HOME = path.resolve(process.env.RINGI_HOME || path.join(os.homedir(), '.ringi'));
|
|
16
|
-
export const HOME_VERSION = 3;
|
|
17
|
-
export const OPERATOR = 'operator';
|
|
18
|
-
// --- writing safely ---
|
|
19
|
-
export const guard = (fn) => guardWrite(HOME, fn);
|
|
20
|
-
export const mkdir = (d) => mkdirIn(HOME, d);
|
|
21
|
-
export const writeJson = (f, v) => guard(() => {
|
|
22
|
-
mkdir(path.dirname(f));
|
|
23
|
-
writeJsonAtomic(f, v);
|
|
24
|
-
});
|
|
25
|
-
// State fails closed: unreadable JSON is an error, never a silent fresh start.
|
|
26
|
-
export const readJson = (f, dflt) => {
|
|
27
|
-
let raw;
|
|
28
|
-
try {
|
|
29
|
-
raw = fs.readFileSync(f, 'utf8');
|
|
30
|
-
}
|
|
31
|
-
catch (e) {
|
|
32
|
-
if (errno(e) === 'ENOENT')
|
|
33
|
-
return dflt;
|
|
34
|
-
throw e;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
return JSON.parse(raw);
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
return fail(`${f} is not valid JSON (${e.message}); refusing to continue with lost state`);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
// --- the home ---
|
|
44
|
-
export const hubsDir = () => path.join(HOME, 'hub');
|
|
45
|
-
export const hubHome = (name) => path.join(hubsDir(), name);
|
|
46
|
-
// The home is created on first use; anything else at that path is refused. A home of the previous layout (each hub a
|
|
47
|
-
// bare repository `hub/<name>.git` with its settings in git config) is moved into descriptor and store.
|
|
48
|
-
export const ensureHome = () => {
|
|
49
|
-
const marker = path.join(HOME, 'home.json');
|
|
50
|
-
if (fs.existsSync(marker)) {
|
|
51
|
-
const h = readJson(marker, {});
|
|
52
|
-
if (h.version === 2)
|
|
53
|
-
return migrate2(marker);
|
|
54
|
-
if (h.version !== HOME_VERSION)
|
|
55
|
-
fail(`${HOME} is a ringi home of version ${h.version}; this ringi ${VERSION} needs version ${HOME_VERSION}`);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
if (fs.existsSync(HOME) && fs.readdirSync(HOME).length)
|
|
59
|
-
fail(`${HOME} exists and is not a ringi home (no home.json); move it away or set RINGI_HOME`);
|
|
60
|
-
mkdir(HOME);
|
|
61
|
-
writeJson(marker, { version: HOME_VERSION });
|
|
62
|
-
};
|
|
63
|
-
const migrate2 = (marker) => {
|
|
64
|
-
for (const f of fs.existsSync(hubsDir()) ? fs.readdirSync(hubsDir()).filter(f => f.endsWith('.git')) : []) {
|
|
65
|
-
const name = f.slice(0, -4);
|
|
66
|
-
const old = path.join(hubsDir(), f);
|
|
67
|
-
const cfg = (k) => String(spawnSync('git', ['--git-dir', old, 'config', '--get', k], { encoding: 'utf8' }).stdout ?? '').trim();
|
|
68
|
-
const signed = cfg('ringi.type') === 'remote';
|
|
69
|
-
const descriptor = { schema: 'ringi-hub/2', name, trust: signed ? 'signed' : 'asserted',
|
|
70
|
-
...(signed ? { root: cfg('ringi.rootKey') || undefined, genesis: cfg('ringi.genesis') || undefined } : {}),
|
|
71
|
-
store: { type: 'git', path: 'store', ...(cfg('remote.origin.url') ? { remote: cfg('remote.origin.url') } : {}) } };
|
|
72
|
-
mkdir(path.join(hubHome(name), 'store'));
|
|
73
|
-
guard(() => fs.renameSync(old, path.join(hubHome(name), 'store', '.git')));
|
|
74
|
-
writeJson(path.join(hubHome(name), 'hub.json'), descriptor);
|
|
75
|
-
note(`moved hub ${name} to ${hubHome(name)} (descriptor hub.json, store/.git)`);
|
|
76
|
-
}
|
|
77
|
-
writeJson(marker, { version: HOME_VERSION });
|
|
78
|
-
};
|
|
79
|
-
export const locked = (name, fn) => {
|
|
80
|
-
ensureHome();
|
|
81
|
-
const dir = path.join(HOME, 'locks');
|
|
82
|
-
mkdir(dir);
|
|
83
|
-
return guard(() => lockFile(path.join(dir, `${name}.lock`), fn));
|
|
84
|
-
};
|
|
85
|
-
export const configFile = () => path.join(HOME, 'config.json');
|
|
86
|
-
export const config = () => ({ hub: 'local', room: null, ...readJson(configFile(), {}) });
|
|
87
|
-
export const setConfig = (patch) => writeJson(configFile(), { ...config(), ...patch });
|
|
88
|
-
//# sourceMappingURL=index.js.map
|
package/target/esm/hub/index.js
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
// hub: hubs and rooms on top of any store. A hub is a directory with a descriptor (hub.json: which store, where,
|
|
2
|
-
// what this machine pins) beside its store. Its shared contract lives in the store (contract.json, authority.json,
|
|
3
|
-
// profiles/*.json). This file reads contracts, opens rooms with their profile and authority, and decides what a reader
|
|
4
|
-
// accepts: only history that extends what it accepted before, from members the store verifies (docs/spec/hub-1.md, Trust).
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import * as D from '../domain/decisions.js';
|
|
8
|
-
import { CAPABILITIES, unenforceable } from '../domain/index.js';
|
|
9
|
-
import { GitStore } from '../store/git/index.js';
|
|
10
|
-
import { HOME, OPERATOR, RESOURCES, VERSION, ensureHome, hubHome, hubsDir, locked, mkdir, writeJson } from '../home/index.js';
|
|
11
|
-
import { DEFAULT_PROFILE, PROFILES_CAPABILITY, parseProfile } from '../domain/profiles.js';
|
|
12
|
-
import { HIDDEN, compose, decodeText, link, parse } from '../protocol/index.js';
|
|
13
|
-
import { emit } from './signals.js';
|
|
14
|
-
import { STORES } from '../store/index.js';
|
|
15
|
-
import { fail, short, strictJson } from '../lib/index.js';
|
|
16
|
-
export const HUB_MAJOR = 1;
|
|
17
|
-
export const CAPS = new Set(Object.keys(CAPABILITIES));
|
|
18
|
-
export const RESERVED_ROOMS = new Set(['main', 'archive']);
|
|
19
|
-
// Whether the room's work has started: it has the quorum of agents its genesis asked for (`Quorum`), or asked for none.
|
|
20
|
-
export const start = (R) => {
|
|
21
|
-
const agents = Object.values(R.members).filter(m => m.role !== 'root').length;
|
|
22
|
-
return { quorum: R.quorum, agents, started: R.quorum === null || agents >= R.quorum };
|
|
23
|
-
};
|
|
24
|
-
// --- hubs ---
|
|
25
|
-
export const hubNames = () => {
|
|
26
|
-
try {
|
|
27
|
-
return fs.readdirSync(hubsDir()).filter(n => fs.existsSync(path.join(hubsDir(), n, 'hub.json'))).sort();
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
const HUB_MD = `# ringi hub
|
|
34
|
-
|
|
35
|
-
The shared contract of a ringi hub (docs/spec/hub-1.md): contract.json (schema, version, protocol, trust, capabilities, the
|
|
36
|
-
default profile), authority.json (who may decide what, up to which budget; the root, \`operator\`, always may) and
|
|
37
|
-
profiles/ (what a piece of work is in a room: its states, and who may move it). Use \`ringi\`; never edit by hand.
|
|
38
|
-
`;
|
|
39
|
-
const readProfileResource = (name) => fs.readFileSync(path.join(RESOURCES, 'profiles', `${name}.json`), 'utf8');
|
|
40
|
-
// A new hub: local (asserted senders), or signed, with the operator's root key generated on this machine and pinned.
|
|
41
|
-
export const createHub = (name, { signed = false, url } = {}) => {
|
|
42
|
-
ensureHome();
|
|
43
|
-
const dir = hubHome(name);
|
|
44
|
-
if (fs.existsSync(dir))
|
|
45
|
-
fail(`hub ${name} exists`);
|
|
46
|
-
if (url && !signed)
|
|
47
|
-
fail('--url publishes a hub; only a --signed hub may be published');
|
|
48
|
-
const d = { schema: 'ringi-hub/2', name, trust: signed ? 'signed' : 'asserted', store: { type: 'git', path: 'store', ...(url ? { remote: url } : {}) } };
|
|
49
|
-
try {
|
|
50
|
-
mkdir(dir);
|
|
51
|
-
if (signed)
|
|
52
|
-
d.root = GitStore.rootFor(dir, d, HOME);
|
|
53
|
-
const contract = { schema: 'ringi-hub', version: '1.1', protocol: 1, trust: d.trust, capabilities: [D.CAPABILITY, PROFILES_CAPABILITY], profile: DEFAULT_PROFILE, ...(d.root ? { root: d.root } : {}) };
|
|
54
|
-
const store = GitStore.create(dir, d, HOME, {
|
|
55
|
-
'contract.json': JSON.stringify(contract, null, 2) + '\n',
|
|
56
|
-
'authority.json': JSON.stringify({ decide: {} }, null, 2) + '\n',
|
|
57
|
-
'HUB.md': HUB_MD,
|
|
58
|
-
[`profiles/${DEFAULT_PROFILE}.json`]: readProfileResource(DEFAULT_PROFILE),
|
|
59
|
-
}, compose(`hub ${name}`, [['To', '*'], ['Kind', 'hub']]));
|
|
60
|
-
if (signed)
|
|
61
|
-
d.genesis = store.contractHead();
|
|
62
|
-
writeJson(path.join(dir, 'hub.json'), d);
|
|
63
|
-
}
|
|
64
|
-
catch (e) {
|
|
65
|
-
if (!fs.existsSync(path.join(dir, 'hub.json')))
|
|
66
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
67
|
-
throw e;
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
export const readDescriptor = (name) => {
|
|
71
|
-
const f = path.join(hubHome(name), 'hub.json');
|
|
72
|
-
if (!fs.existsSync(f))
|
|
73
|
-
fail(`no hub ${name}; hubs: ${hubNames().join(', ') || 'none'}`);
|
|
74
|
-
const d = strictJson(fs.readFileSync(f, 'utf8'), f);
|
|
75
|
-
if (d.schema !== 'ringi-hub/2' || d.name !== name || !['signed', 'asserted'].includes(d.trust) || !d.store?.type || !d.store.path)
|
|
76
|
-
fail(`${f} is not a ringi hub descriptor this ringi ${VERSION} reads`);
|
|
77
|
-
return d;
|
|
78
|
-
};
|
|
79
|
-
// The contract a tool must understand before it touches a hub or a room: known schema, major and capabilities.
|
|
80
|
-
export const contractAt = (store, name, rev) => {
|
|
81
|
-
const text = store.contractFile(rev, 'contract.json') ?? store.contractFile(rev, 'hub.json') ?? fail(`hub ${name} has no contract at ${short(rev)}`);
|
|
82
|
-
const c = strictJson(text, `hub ${name}: contract`);
|
|
83
|
-
if (c.schema !== 'ringi-hub')
|
|
84
|
-
fail(`hub ${name} declares schema ${String(c.schema)}, not ringi-hub`);
|
|
85
|
-
const major = Number(String(c.version).split('.')[0]);
|
|
86
|
-
if (major !== HUB_MAJOR)
|
|
87
|
-
fail(`hub ${name} follows contract version ${c.version}; this ringi ${VERSION} supports ${HUB_MAJOR}.x. Upgrade ringi`);
|
|
88
|
-
const why = unenforceable(c.capabilities ?? []);
|
|
89
|
-
if (why)
|
|
90
|
-
fail(`hub ${name} ${why}, which this ringi ${VERSION} cannot enforce. Upgrade ringi`);
|
|
91
|
-
const a = store.contractFile(rev, 'authority.json');
|
|
92
|
-
return { ...c, authority: a === null ? {} : strictJson(a, `hub ${name}: authority.json at ${short(rev)}`) };
|
|
93
|
-
};
|
|
94
|
-
// A hub is opened once per process; its store syncs then (a signed store fetches and verifies), and again on refresh.
|
|
95
|
-
const opened = new Map();
|
|
96
|
-
export const openHub = (name, { refresh = false } = {}) => {
|
|
97
|
-
ensureHome();
|
|
98
|
-
if (!/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(name))
|
|
99
|
-
fail(`bad hub name ${name}`);
|
|
100
|
-
if (opened.has(name) && !refresh)
|
|
101
|
-
return opened.get(name);
|
|
102
|
-
if (name === 'local' && !fs.existsSync(path.join(hubHome(name), 'hub.json')))
|
|
103
|
-
createHub('local');
|
|
104
|
-
const d = readDescriptor(name);
|
|
105
|
-
const factory = STORES[d.store.type] ?? fail(`hub ${name} uses a ${d.store.type} store; this ringi ${VERSION} knows ${Object.keys(STORES).join(', ')}`);
|
|
106
|
-
const store = factory(hubHome(name), d, HOME);
|
|
107
|
-
store.sync();
|
|
108
|
-
const main = store.contractHead();
|
|
109
|
-
const H = { name, dir: hubHome(name), d, store, main, contract: contractAt(store, name, main), signed: d.trust === 'signed' };
|
|
110
|
-
opened.set(name, H);
|
|
111
|
-
return H;
|
|
112
|
-
};
|
|
113
|
-
// --- rooms ---
|
|
114
|
-
export const roomNames = (H, archived = false) => H.store.roomNames(archived);
|
|
115
|
-
export const openRoom = (H, name, { quiet = false } = {}) => {
|
|
116
|
-
if (!name)
|
|
117
|
-
return fail('no room: the operator creates one with ringi room create <id>, or picks one with ringi room switch <id>');
|
|
118
|
-
const s = H.store.room(name);
|
|
119
|
-
if (!s) {
|
|
120
|
-
if (quiet)
|
|
121
|
-
return null;
|
|
122
|
-
const gone = roomNames(H, true).find(a => a.startsWith(`${name}@`));
|
|
123
|
-
return fail(gone ? `room ${name} is archived as ${gone}; read it with --room ${gone}` : `no room ${name} in hub ${H.name}; rooms: ${roomNames(H).join(', ') || 'none'}`);
|
|
124
|
-
}
|
|
125
|
-
// The genesis names its room, in the root's hand: a history offered under another name is not that room.
|
|
126
|
-
const named = s.archived ? name.slice(0, name.lastIndexOf('@')) : name;
|
|
127
|
-
const subject = s.control[0]?.rev === s.genesis ? s.control[0].text.split('\n')[0] : '(none)';
|
|
128
|
-
if (subject !== `room ${named}` || (s.archived && name !== `${named}@${s.genesis.slice(0, 8)}`))
|
|
129
|
-
fail(`room ${name}: its genesis is "${subject}"; refusing a room's history under another name`);
|
|
130
|
-
// The contract in effect at each control entry: the hub contract the room was created on, then each `Contract:`
|
|
131
|
-
// the operator moved it to. A decision names the control entry it was made under (decide.ts).
|
|
132
|
-
const atControl = new Map();
|
|
133
|
-
let current = s.base;
|
|
134
|
-
for (const rec of s.control) {
|
|
135
|
-
const m = /^Contract: ([0-9a-f]{40,64})$/m.exec(rec.text);
|
|
136
|
-
if (m)
|
|
137
|
-
current = m[1];
|
|
138
|
-
atControl.set(rec.rev, current);
|
|
139
|
-
}
|
|
140
|
-
const contract = current === H.main ? H.contract : contractAt(H.store, H.name, current);
|
|
141
|
-
const tables = new Map();
|
|
142
|
-
const authorityAt = (control) => {
|
|
143
|
-
const rev = control ? atControl.get(control) : undefined;
|
|
144
|
-
if (!rev)
|
|
145
|
-
return null;
|
|
146
|
-
if (!tables.has(rev))
|
|
147
|
-
tables.set(rev, contractAt(H.store, H.name, rev).authority);
|
|
148
|
-
return tables.get(rev);
|
|
149
|
-
};
|
|
150
|
-
// The room's profile is fixed when the room is made: its content is copied into the genesis control entry, so no
|
|
151
|
-
// later change of the hub's profiles or contract reinterprets the room's history. Rooms made before this carry
|
|
152
|
-
// none and use the default profile of the contract they were created on.
|
|
153
|
-
const baseProfile = contractAt(H.store, H.name, s.base).profile ?? DEFAULT_PROFILE;
|
|
154
|
-
const profileText = H.store.controlFile(s, 'profile.json', s.genesis)
|
|
155
|
-
?? H.store.contractFile(s.base, `profiles/${baseProfile}.json`)
|
|
156
|
-
?? (baseProfile === DEFAULT_PROFILE ? readProfileResource(DEFAULT_PROFILE) : fail(`room ${name}: unknown profile ${baseProfile}`));
|
|
157
|
-
const roster = H.store.roster(s);
|
|
158
|
-
const members = roster?.members ?? strictJson(H.store.controlFile(s, 'members.json') ?? '{}', `room ${name}: members.json`);
|
|
159
|
-
// The root's control records set the quorum; the latest one counts.
|
|
160
|
-
let quorum = null;
|
|
161
|
-
for (const rec of s.control) {
|
|
162
|
-
const m = /^Quorum: ([1-9][0-9]?)$/m.exec(rec.text);
|
|
163
|
-
if (m)
|
|
164
|
-
quorum = Number(m[1]);
|
|
165
|
-
}
|
|
166
|
-
return { hub: H, s, name, archived: s.archived, head: s.head, genesis: s.genesis, contractRev: current, contract, authorityAt,
|
|
167
|
-
profile: parseProfile(profileText, `room ${name}: profile`), members, quorum };
|
|
168
|
-
};
|
|
169
|
-
export const room = (H, name) => openRoom(H, name);
|
|
170
|
-
export const ROOM_MD = (name) => `# room ${name}\n\nA ringi room: members.json lists who takes part; profile.json is what a piece of work is here, fixed when the room was made.\n`;
|
|
171
|
-
export const profileText = (H, name) => H.store.contractFile(H.main, `profiles/${name}.json`) ?? (name === DEFAULT_PROFILE ? readProfileResource(DEFAULT_PROFILE) : null);
|
|
172
|
-
// A control change under the hub lock. In a signed room membership changes only through `room admit`.
|
|
173
|
-
export const controlChange = (R, who, subject, mutate, extra = []) => locked(`hub-${R.hub.name}`, () => {
|
|
174
|
-
const s = R.hub.store.room(R.name) ?? fail(`room ${R.name} is gone`);
|
|
175
|
-
const members = strictJson(R.hub.store.controlFile(s, 'members.json') ?? '{}', `room ${R.name}: members.json`);
|
|
176
|
-
const before = JSON.stringify(members);
|
|
177
|
-
mutate(members);
|
|
178
|
-
if (R.hub.signed && JSON.stringify(members) !== before)
|
|
179
|
-
fail('in a signed room, membership changes only by ringi room admit');
|
|
180
|
-
R.head = R.hub.store.updateControl(s, who, compose(subject, [['To', '*'], ['Kind', 'room'], ...extra]), { 'members.json': JSON.stringify(members, null, 2) + '\n' });
|
|
181
|
-
R.members = members;
|
|
182
|
-
});
|
|
183
|
-
// --- messages and what a reader accepts ---
|
|
184
|
-
export const toMessage = (R, from, x, seq) => {
|
|
185
|
-
const trust = R.hub.signed ? 'verified' : 'asserted';
|
|
186
|
-
const files = x.files.map(f => ({ path: f.path, size: null }));
|
|
187
|
-
const base = { id: x.id, from, trust, time: x.time, seq, files, refused: x.refused, reId: null, hopEff: 0 };
|
|
188
|
-
const d = decodeText(x.text);
|
|
189
|
-
if (d.invalid !== undefined) {
|
|
190
|
-
return { ...base, invalid: d.invalid, subject: '', body: '', to: [], re: null, kind: null, state: null, assign: null, roles: null, hop: 0, bad: d.invalid, trailers: {} };
|
|
191
|
-
}
|
|
192
|
-
const p = parse(d.text, s => R.hub.store.isRef(s));
|
|
193
|
-
// An extension's trailers and the room profile's states are part of a message's validity.
|
|
194
|
-
const ext = D.check(p, s => R.hub.store.isRef(s));
|
|
195
|
-
const state = !p.bad && p.state && !R.profile.states.includes(p.state) ? `State ${p.state} is not in profile ${R.profile.name}` : null;
|
|
196
|
-
return { ...base, invalid: null, ...p, bad: p.bad ?? ext ?? state };
|
|
197
|
-
};
|
|
198
|
-
// The room as stored, read without a reader's lock or state: for an author working out the signals of its own message
|
|
199
|
-
// (append runs inside reader locks too). Readers check signals themselves.
|
|
200
|
-
export const asStored = (R) => {
|
|
201
|
-
const s = R.hub.store.room(R.name) ?? R.s;
|
|
202
|
-
return link(new Map(R.hub.store.logIds(s).map(id => [id, R.hub.store.messages(s, id, R.hub.store.logHead(s, id)).map((x, seq) => toMessage(R, id, x, seq))])));
|
|
203
|
-
};
|
|
204
|
-
const CARRIES = (p, R) => !p.bad && (p.kind === R.profile.opens || !!p.assign || !!p.state || ['proposal', 'stamp', 'decision', 'usage'].includes(p.kind ?? ''));
|
|
205
|
-
// A message on the author's log, and the signals it made (signals.ts).
|
|
206
|
-
export const append = (R, who, text, entries = []) => {
|
|
207
|
-
const id = R.hub.store.append(R.s, who, text, entries);
|
|
208
|
-
if (CARRIES(parse(text, s => R.hub.store.isRef(s)), R)) {
|
|
209
|
-
const all = asStored(R);
|
|
210
|
-
const m = all.get(id);
|
|
211
|
-
if (m)
|
|
212
|
-
emit(R, who, all, m);
|
|
213
|
-
}
|
|
214
|
-
return id;
|
|
215
|
-
};
|
|
216
|
-
export const withSizes = (R, m) => {
|
|
217
|
-
if (!m.files.length)
|
|
218
|
-
return [];
|
|
219
|
-
const sizes = R.hub.store.sizes(m.id, m.files.map(f => f.path));
|
|
220
|
-
return m.files.map(f => ({ ...f, size: sizes.get(f.path) ?? null }));
|
|
221
|
-
};
|
|
222
|
-
export const pongText = (me, m, what) => compose(`pong: ${me} ${what}`, [['To', m.from], ['Re', m.id], ['Kind', 'pong'], ['Hop', String(m.hopEff + 1)]]);
|
|
223
|
-
export { OPERATOR, HIDDEN };
|
|
224
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
// protocol: the message protocol, docs/spec/core-1.md (§3, §5–§7), independent of storage and of any task model. A store
|
|
2
|
-
// turns its records into messages and hands them here: text, threads, inboxes and waking live in this file. What a
|
|
3
|
-
// task is, which states it has and who may move it, is a profile (profile.ts), not part of the protocol.
|
|
4
|
-
import { CC_RE } from './files.js';
|
|
5
|
-
import { fail } from '../lib/index.js';
|
|
6
|
-
export const ID_RE = /^(?=.{1,64}$)[a-z0-9]+(?:[._-][a-z0-9]+)*(?<!\.lock)$/;
|
|
7
|
-
// An agent's id has no dot: it starts the name of its signals, `<agent>.<signal>.<message12>`.
|
|
8
|
-
export const AGENT_RE = /^(?=.{1,64}$)[a-z0-9]+(?:[_-][a-z0-9]+)*$/;
|
|
9
|
-
export const TOKEN_RE = /^[a-z][a-z0-9-]*$/;
|
|
10
|
-
export const HOP_RE = /^(?:0|[1-9]\d{0,5})$/;
|
|
11
|
-
export const TRAILER_RE = /^([A-Za-z][A-Za-z0-9-]*):[ \t]*(.*)$/;
|
|
12
|
-
export const TEXT_MAX = 64 * 1024;
|
|
13
|
-
// Trailers the protocol itself interprets; any other trailer belongs to an extension or a profile.
|
|
14
|
-
export const KNOWN = new Set(['to', 're', 'kind', 'state', 'hop', 'assign', 'roles']);
|
|
15
|
-
export const HEARTBEATS = new Set(['ping', 'pong']);
|
|
16
|
-
// Kinds that are bookkeeping, never delivered to an inbox: heartbeats, usage receipts, cards, room records.
|
|
17
|
-
export const HIDDEN = new Set(['ping', 'pong', 'usage', 'card', 'room']);
|
|
18
|
-
export const one = (m, k) => m.trailers[k]?.[0] ?? null;
|
|
19
|
-
// --- text (§3) ---
|
|
20
|
-
const utf8 = new TextDecoder('utf-8', { fatal: true });
|
|
21
|
-
// Invalid text is dangerous bytes: readers treat the message as absent.
|
|
22
|
-
export const decodeText = (buf) => {
|
|
23
|
-
let s;
|
|
24
|
-
try {
|
|
25
|
-
s = utf8.decode(buf);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return { invalid: 'not valid UTF-8' };
|
|
29
|
-
}
|
|
30
|
-
s = s.replace(/\r\n/g, '\n');
|
|
31
|
-
if (/\r/.test(s))
|
|
32
|
-
return { invalid: 'a CR not followed by LF' };
|
|
33
|
-
if (CC_RE.test(s))
|
|
34
|
-
return { invalid: 'control characters in the text' };
|
|
35
|
-
return { text: s };
|
|
36
|
-
};
|
|
37
|
-
// Parses well-formed and malformed text alike; `bad` names why a message routes nowhere. `isRef` is the store's
|
|
38
|
-
// grammar for message ids in `Re`.
|
|
39
|
-
export const parse = (raw, isRef) => {
|
|
40
|
-
const text = raw.replace(/\r\n/g, '\n').trimEnd();
|
|
41
|
-
const cut = text.lastIndexOf('\n\n');
|
|
42
|
-
const tail = cut < 0 ? [] : text.slice(cut + 2).split('\n');
|
|
43
|
-
const has = tail.length > 0 && tail.every(l => TRAILER_RE.test(l));
|
|
44
|
-
const trailers = {};
|
|
45
|
-
if (has) {
|
|
46
|
-
for (const l of tail) {
|
|
47
|
-
const [, k, v] = TRAILER_RE.exec(l);
|
|
48
|
-
const key = k.toLowerCase();
|
|
49
|
-
trailers[key] = [...(trailers[key] ?? []), v.trim()];
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
const head = has ? text.slice(0, cut) : text;
|
|
53
|
-
const nl = head.indexOf('\n');
|
|
54
|
-
const subject = (nl < 0 ? head : head.slice(0, nl)).trim();
|
|
55
|
-
const bad = [...KNOWN].filter(k => (trailers[k]?.length ?? 0) > 1).map(k => `duplicate ${k}`);
|
|
56
|
-
const get = (k) => trailers[k]?.[0] ?? null;
|
|
57
|
-
const ids = (v) => v === null ? null : [...new Set(v.split(',').map(x => x.trim()))];
|
|
58
|
-
const to = get('to') === '*' ? ['*'] : ids(get('to'));
|
|
59
|
-
const assign = ids(get('assign'));
|
|
60
|
-
// Roles: `<id>=<label>, …`; the label `none` clears one.
|
|
61
|
-
const pairs = get('roles') === null ? null : get('roles').split(',').map(x => x.trim().split('=').map(y => y.trim()));
|
|
62
|
-
if (pairs && !pairs.every(p => p.length === 2 && ID_RE.test(p[0]) && TOKEN_RE.test(p[1])))
|
|
63
|
-
bad.push('malformed Roles');
|
|
64
|
-
if (!subject)
|
|
65
|
-
bad.push('empty subject');
|
|
66
|
-
if (Buffer.byteLength(raw) > TEXT_MAX)
|
|
67
|
-
bad.push('text over 64 KiB');
|
|
68
|
-
if (!has)
|
|
69
|
-
bad.push('no trailer block');
|
|
70
|
-
else if (!to)
|
|
71
|
-
bad.push('no To');
|
|
72
|
-
else if (to[0] !== '*' && !to.every(x => ID_RE.test(x)))
|
|
73
|
-
bad.push('malformed To');
|
|
74
|
-
if (assign && !assign.every(x => ID_RE.test(x)))
|
|
75
|
-
bad.push('malformed Assign');
|
|
76
|
-
if (get('re') !== null && !isRef(get('re')))
|
|
77
|
-
bad.push('malformed Re');
|
|
78
|
-
if (get('hop') !== null && !HOP_RE.test(get('hop')))
|
|
79
|
-
bad.push('malformed Hop');
|
|
80
|
-
// A state is a token; whether the room's profile knows it is the store's check.
|
|
81
|
-
if (get('state') !== null && !TOKEN_RE.test(get('state')))
|
|
82
|
-
bad.push('malformed State');
|
|
83
|
-
if (get('kind') !== null && !TOKEN_RE.test(get('kind')))
|
|
84
|
-
bad.push('malformed Kind');
|
|
85
|
-
const ok = !bad.length;
|
|
86
|
-
return {
|
|
87
|
-
subject,
|
|
88
|
-
body: nl < 0 ? '' : head.slice(nl + 1).replace(/^\n+/, '').trimEnd(),
|
|
89
|
-
// A malformed message is read as if it had no trailers.
|
|
90
|
-
to: ok ? to : [],
|
|
91
|
-
assign: ok ? assign : null,
|
|
92
|
-
roles: ok && pairs ? Object.fromEntries(pairs) : null,
|
|
93
|
-
re: ok ? get('re') : null,
|
|
94
|
-
kind: ok ? get('kind') : null,
|
|
95
|
-
state: ok ? get('state') : null,
|
|
96
|
-
hop: ok && get('hop') !== null ? Number(get('hop')) : 0,
|
|
97
|
-
bad: bad.join(', ') || null,
|
|
98
|
-
trailers,
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
|
-
export const compose = (text, trailers) => `${text}\n\n${trailers.filter(([, v]) => v).map(([k, v]) => `${k}: ${v}`).join('\n')}\n`;
|
|
102
|
-
// A client refuses to write what readers would drop or ignore (§3).
|
|
103
|
-
export const checkOutgoing = (text, isRef) => {
|
|
104
|
-
const d = decodeText(Buffer.from(text));
|
|
105
|
-
if (d.invalid !== undefined)
|
|
106
|
-
fail(`refusing to send: ${d.invalid}`);
|
|
107
|
-
const m = parse(d.text, isRef);
|
|
108
|
-
if (m.bad)
|
|
109
|
-
fail(`refusing to send a malformed message: ${m.bad}`);
|
|
110
|
-
return m;
|
|
111
|
-
};
|
|
112
|
-
// --- threads (§5) ---
|
|
113
|
-
// Resolves Re and computes effective hops. Invalid messages are absent: a Re naming one does not resolve.
|
|
114
|
-
export const link = (logs) => {
|
|
115
|
-
const all = new Map();
|
|
116
|
-
for (const msgs of logs.values())
|
|
117
|
-
for (const m of msgs)
|
|
118
|
-
if (!m.invalid)
|
|
119
|
-
all.set(m.id, m);
|
|
120
|
-
for (const m of all.values())
|
|
121
|
-
m.reId = m.re && all.has(m.re) ? m.re : null;
|
|
122
|
-
const eff = new Map();
|
|
123
|
-
for (const m of all.values()) {
|
|
124
|
-
const chain = [];
|
|
125
|
-
for (let x = m; x && !eff.has(x.id) && chain.length < 100000; x = x.reId ? all.get(x.reId) : undefined)
|
|
126
|
-
chain.push(x);
|
|
127
|
-
for (let i = chain.length - 1; i >= 0; i--) {
|
|
128
|
-
const c = chain[i];
|
|
129
|
-
eff.set(c.id, Math.max(c.hop, c.reId ? eff.get(c.reId) + 1 : c.re ? 1 : 0));
|
|
130
|
-
}
|
|
131
|
-
m.hopEff = eff.get(m.id);
|
|
132
|
-
}
|
|
133
|
-
return all;
|
|
134
|
-
};
|
|
135
|
-
// Kahn's order: the answered message before the answer, earlier before later within one log; among the ready ones,
|
|
136
|
-
// the smallest (time, id) goes first.
|
|
137
|
-
export const ordered = (list) => {
|
|
138
|
-
const byId = new Map(list.map(m => [m.id, m]));
|
|
139
|
-
const next = new Map(list.map(m => [m.id, []]));
|
|
140
|
-
const indeg = new Map(list.map(m => [m.id, 0]));
|
|
141
|
-
const edge = (a, b) => {
|
|
142
|
-
next.get(a.id).push(b);
|
|
143
|
-
indeg.set(b.id, indeg.get(b.id) + 1);
|
|
144
|
-
};
|
|
145
|
-
const last = new Map();
|
|
146
|
-
for (const m of [...list].sort((a, b) => a.seq - b.seq)) {
|
|
147
|
-
if (last.has(m.from))
|
|
148
|
-
edge(last.get(m.from), m);
|
|
149
|
-
last.set(m.from, m);
|
|
150
|
-
if (m.reId && byId.has(m.reId))
|
|
151
|
-
edge(byId.get(m.reId), m);
|
|
152
|
-
}
|
|
153
|
-
const ready = list.filter(m => !indeg.get(m.id));
|
|
154
|
-
const res = [];
|
|
155
|
-
while (ready.length) {
|
|
156
|
-
ready.sort((a, b) => a.time - b.time || (a.id < b.id ? -1 : 1));
|
|
157
|
-
const m = ready.shift();
|
|
158
|
-
res.push(m);
|
|
159
|
-
for (const n of next.get(m.id)) {
|
|
160
|
-
indeg.set(n.id, indeg.get(n.id) - 1);
|
|
161
|
-
if (!indeg.get(n.id))
|
|
162
|
-
ready.push(n);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return res;
|
|
166
|
-
};
|
|
167
|
-
export const chainHas = (all, m, top) => {
|
|
168
|
-
for (let x = m, i = 0; x && i < 10000; x = x.reId ? all.get(x.reId) : undefined, i++)
|
|
169
|
-
if (x === top)
|
|
170
|
-
return true;
|
|
171
|
-
return false;
|
|
172
|
-
};
|
|
173
|
-
export const rootOf = (all, m) => {
|
|
174
|
-
let x = m;
|
|
175
|
-
for (let i = 0; x.reId && all.has(x.reId) && i < 10000; i++)
|
|
176
|
-
x = all.get(x.reId);
|
|
177
|
-
return x;
|
|
178
|
-
};
|
|
179
|
-
export const under = (all, top) => ordered([...all.values()].filter(m => chainHas(all, m, top)));
|
|
180
|
-
export const lookup = (all, ref) => {
|
|
181
|
-
const key = String(ref ?? '').toLowerCase();
|
|
182
|
-
if (all.has(key))
|
|
183
|
-
return all.get(key);
|
|
184
|
-
const hits = key.length >= 4 ? [...all.keys()].filter(k => k.startsWith(key)) : [];
|
|
185
|
-
if (hits.length === 1)
|
|
186
|
-
return all.get(hits[0]);
|
|
187
|
-
return fail(hits.length ? `ambiguous message id ${ref}` : `unknown message ${ref}`);
|
|
188
|
-
};
|
|
189
|
-
// --- reading (§6) and waking (§7) ---
|
|
190
|
-
// Delivered: well-formed, not a hidden kind, addressed to `id` by name or `*`.
|
|
191
|
-
export const visible = (m, id, hidden) => !m.invalid && !m.bad && !(m.kind && hidden.has(m.kind)) && (m.to.includes(id) || m.to.includes('*'));
|
|
192
|
-
// Wakes: only a direct address. Broadcasts are read when the agent is awake for another reason.
|
|
193
|
-
export const wakes = (m, id, hidden) => visible(m, id, hidden) && m.to.includes(id);
|
|
194
|
-
// Messages for `id` after the per-log cursors; cursors advance only past what was shown.
|
|
195
|
-
export const unread = (logs, id, cursors, limit = Infinity, hidden) => {
|
|
196
|
-
const fresh = [];
|
|
197
|
-
for (const [log, msgs] of logs) {
|
|
198
|
-
if (log === id)
|
|
199
|
-
continue;
|
|
200
|
-
const at = msgs.findIndex(m => m.id === cursors[log]);
|
|
201
|
-
fresh.push(...msgs.slice(at + 1).filter(m => visible(m, id, hidden)));
|
|
202
|
-
}
|
|
203
|
-
const queue = ordered(fresh);
|
|
204
|
-
const shown = queue.slice(0, limit);
|
|
205
|
-
const seen = new Set(shown.map(m => m.id));
|
|
206
|
-
const next = { ...cursors };
|
|
207
|
-
for (const [log, msgs] of logs) {
|
|
208
|
-
if (log === id)
|
|
209
|
-
continue;
|
|
210
|
-
const at = msgs.findIndex(m => m.id === cursors[log]);
|
|
211
|
-
for (const m of msgs.slice(at + 1)) {
|
|
212
|
-
if (visible(m, id, hidden) && !seen.has(m.id))
|
|
213
|
-
break;
|
|
214
|
-
next[log] = m.id;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return { msgs: shown, rest: queue.length - shown.length, cursors: next };
|
|
218
|
-
};
|
|
219
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// reader: what one reader on this machine accepted of a room: heads, signals, cursors, alarms. Only history that
|
|
2
|
-
// extends what it accepted before, verified by the store, is delivered (docs/spec/hub-1.md, Trust).
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import * as Signals from '../domain/signals.js';
|
|
5
|
-
import { HOME, locked, readJson, writeJson } from '../home/index.js';
|
|
6
|
-
import { toMessage } from '../hub/index.js';
|
|
7
|
-
import { fail, note, short } from '../lib/index.js';
|
|
8
|
-
import { link } from '../protocol/index.js';
|
|
9
|
-
export const readerFile = (R, reader) => path.join(HOME, 'readers', R.hub.name, R.genesis, `${reader}.json`);
|
|
10
|
-
export const readerLock = (R, reader, fn) => locked(`reader-${R.hub.name}-${R.genesis.slice(0, 12)}-${reader}`, fn);
|
|
11
|
-
export const loadState = (R, reader) => readJson(readerFile(R, reader), {});
|
|
12
|
-
export const saveState = (R, reader, st) => writeJson(readerFile(R, reader), st);
|
|
13
|
-
// Every log must keep extending what this reader accepted, and the store must verify it (a signed store: every entry
|
|
14
|
-
// signed by the key the room admitted). A log that lost, rewrote or forked accepted history, or fails verification,
|
|
15
|
-
// is quarantined: withheld, its accepted head pinned as evidence. Only `ringi forget` by the operator accepts a new
|
|
16
|
-
// baseline.
|
|
17
|
-
export const loadRoomUnlocked = (R, reader) => {
|
|
18
|
-
const st = loadState(R, reader);
|
|
19
|
-
const store = R.hub.store;
|
|
20
|
-
if (st.control && !store.extends(st.control, R.head)) {
|
|
21
|
-
fail(`ALARM room ${R.name}: its control history was rewritten (accepted ${short(st.control)}, now ${short(R.head)}). Nothing is delivered; the operator decides`);
|
|
22
|
-
}
|
|
23
|
-
st.control = R.head;
|
|
24
|
-
st.heads ??= {};
|
|
25
|
-
const alarms = [...store.alarms?.(R.s) ?? []];
|
|
26
|
-
const logs = new Map();
|
|
27
|
-
for (const id of new Set([...store.logIds(R.s), ...Object.keys(st.heads)])) {
|
|
28
|
-
const cur = store.logHead(R.s, id);
|
|
29
|
-
const acc = st.heads[id];
|
|
30
|
-
const why = !cur ? `log ${id} was deleted after ${short(acc)}`
|
|
31
|
-
: acc && !store.extends(acc, cur) ? `log ${id} was rewritten: ${short(cur)} does not extend the accepted ${short(acc)}`
|
|
32
|
-
: !store.extends(R.genesis, cur) ? `log ${id} does not descend from the room's genesis`
|
|
33
|
-
: store.verifyLog(R.s, id, cur);
|
|
34
|
-
if (why) {
|
|
35
|
-
alarms.push(why.startsWith('log ') ? why : `log ${id}: ${why}`);
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (acc !== cur) {
|
|
39
|
-
st.heads[id] = cur;
|
|
40
|
-
store.pin(R.s, reader, id, cur);
|
|
41
|
-
}
|
|
42
|
-
logs.set(id, store.messages(R.s, id, cur).map((x, seq) => toMessage(R, id, x, seq)));
|
|
43
|
-
}
|
|
44
|
-
const records = store.signals(R.s);
|
|
45
|
-
const checked = Signals.check(R, link(logs), records);
|
|
46
|
-
const signalPins = Signals.pins(records, checked, st.signals);
|
|
47
|
-
st.signals = signalPins.accepted;
|
|
48
|
-
alarms.push(...signalPins.alarms, ...checked.filter(x => !x.ok).map(x => `signal ${x.ref}: ${x.why}`));
|
|
49
|
-
const reported = new Set(st.alarms ?? []);
|
|
50
|
-
for (const a of alarms)
|
|
51
|
-
if (!reported.has(a))
|
|
52
|
-
note(`ALARM ${a}; ${a.startsWith('signal ')
|
|
53
|
-
? 'the messages stay the truth; the author restores a missing signal with ringi agent signals --repair'
|
|
54
|
-
: a.startsWith('commit ') ? 'it is skipped; the room reads on without it'
|
|
55
|
-
: `it is quarantined and withheld. Restore it, or the operator runs ringi forget ${R.name}/<log>`}`);
|
|
56
|
-
st.alarms = alarms;
|
|
57
|
-
saveState(R, reader, st);
|
|
58
|
-
return { logs, st };
|
|
59
|
-
};
|
|
60
|
-
export const loadRoom = (R, reader) => readerLock(R, reader, () => loadRoomUnlocked(R, reader));
|
|
61
|
-
export const linked = (R, reader) => {
|
|
62
|
-
const { logs } = loadRoom(R, reader);
|
|
63
|
-
return { logs, all: link(logs) };
|
|
64
|
-
};
|
|
65
|
-
//# sourceMappingURL=reader.js.map
|