@idleware/ringi 0.5.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/package.json +1 -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/{heartbeat → core/agents/heartbeat}/index.d.ts +2 -4
- package/target/dts/{app/heartbeat.d.ts → core/agents/heartbeat/pulse.d.ts} +5 -6
- 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} +48 -18
- 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 -34
- 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 +7 -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} +4 -77
- 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/{heartbeat → core/agents/heartbeat}/index.js +14 -12
- package/target/esm/{app/heartbeat.js → core/agents/heartbeat/pulse.js} +31 -55
- 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 -10
- 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/heartbeat/platform.d.ts +0 -15
- package/target/dts/heartbeat/tools.d.ts +0 -11
- 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 -92
- package/target/dts/store/git/remote.d.ts +0 -95
- 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 -181
- package/target/esm/app/session.js +0 -99
- package/target/esm/cli/context.js +0 -8
- package/target/esm/cli/operator.js +0 -185
- 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/heartbeat/platform.js +0 -83
- package/target/esm/heartbeat/tools.js +0 -68
- 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 -719
- package/target/esm/store/git/remote.js +0 -928
- 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
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// plan: one loop's turns: what arrived, grouped and reserved; planning and dispatch take locks in the order grant,
|
|
2
|
+
// reader, sessions.
|
|
3
|
+
import { locked } from '../../hub/ports/index.js';
|
|
4
|
+
import { link } from '../../hub/protocol/index.js';
|
|
5
|
+
import { loadRoomUnlocked, loadState, readerLock, saveState } from '../../hub/history/index.js';
|
|
6
|
+
import { reserveGroups } from './budgets.js';
|
|
7
|
+
import { collectMessages, groupMessages } from './messages.js';
|
|
8
|
+
import { answerWatchPings } from './pings.js';
|
|
9
|
+
const planUnlocked = (c, R) => {
|
|
10
|
+
const { logs, st } = loadRoomUnlocked(R, c.me);
|
|
11
|
+
if (st.inflight) {
|
|
12
|
+
st.seen = st.inflight.seen;
|
|
13
|
+
st.inflight = undefined;
|
|
14
|
+
saveState(R, c.me, st);
|
|
15
|
+
}
|
|
16
|
+
const all = link(logs), heartbeatSeen = answerWatchPings(c, R, logs, st);
|
|
17
|
+
const { retry, cursors, go } = collectMessages(c, R, logs, st, all);
|
|
18
|
+
const p = reserveGroups(c, R, all, groupMessages(R, all, go), st);
|
|
19
|
+
if (p.lost)
|
|
20
|
+
return { runs: [], hold: true, lost: true };
|
|
21
|
+
const pending = [...new Set([...retry.map(m => m.id), ...p.runs.flatMap(r => r.msgs.map(m => m.id))])];
|
|
22
|
+
saveState(R, c.me, {
|
|
23
|
+
...loadState(R, c.me), heartbeatSeen, exhausted: p.exhausted, pending, runs: p.ownRuns,
|
|
24
|
+
...(p.hold ? {} : { watched: cursors })
|
|
25
|
+
});
|
|
26
|
+
return { runs: p.runs, hold: p.hold, lost: false };
|
|
27
|
+
};
|
|
28
|
+
export const planTurns = (c, R) => locked(`grant-${R.hub.name}`, () => readerLock(R, c.me, () => planUnlocked(c, R)));
|
|
29
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// poll: each loop renews the watcher's seat and finds its room still there, the same, with its agent a member.
|
|
2
|
+
import { locked } from '../../hub/ports/index.js';
|
|
3
|
+
import { openHub, openRoom, start } from '../../hub/rooms/index.js';
|
|
4
|
+
import { stamp } from '../../../lib/index.js';
|
|
5
|
+
import { dropSession, readSession, saveSession } from '../sessions/index.js';
|
|
6
|
+
const refreshSeat = (c) => locked('sessions', () => {
|
|
7
|
+
const cur = readSession(c.handle);
|
|
8
|
+
if (cur?.state === 'active')
|
|
9
|
+
saveSession({ ...cur, lastSeen: stamp(), pid: process.pid });
|
|
10
|
+
return cur;
|
|
11
|
+
});
|
|
12
|
+
const currentRoom = (c) => {
|
|
13
|
+
const H = openHub(c.H0.name, { refresh: true }), R = openRoom(H, c.R0.name, { quiet: true });
|
|
14
|
+
if (!R || R.genesis !== c.R0.genesis) {
|
|
15
|
+
locked('sessions', () => { if (readSession(c.handle)?.genesis === c.R0.genesis)
|
|
16
|
+
dropSession(c.handle); });
|
|
17
|
+
c.log(`watch: ${c.R0.name} is gone, recreated or archived; ${c.me} left it`);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (!R.members[c.me]) {
|
|
21
|
+
c.log(`watch: ${c.me} was removed from ${c.R0.name}; stopping`);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return R;
|
|
25
|
+
};
|
|
26
|
+
const quorum = (c, R) => {
|
|
27
|
+
const st = start(R);
|
|
28
|
+
if (st.started)
|
|
29
|
+
return { done: false, R };
|
|
30
|
+
if (c.w.once)
|
|
31
|
+
c.log(`watch: ${c.R0.name} waits for a quorum of ${st.quorum} agents and has ${st.agents}; nothing to do yet`);
|
|
32
|
+
return { done: !!c.w.once };
|
|
33
|
+
};
|
|
34
|
+
export const pollWatcher = (c) => {
|
|
35
|
+
const s = refreshSeat(c);
|
|
36
|
+
if (!s) {
|
|
37
|
+
c.log(`watch: the seat of ${c.me} was released or taken over; stopping`);
|
|
38
|
+
return { done: true };
|
|
39
|
+
}
|
|
40
|
+
if (s.state === 'stopped') {
|
|
41
|
+
if (c.w.once)
|
|
42
|
+
c.log('watch: stopped by the operator');
|
|
43
|
+
return { done: !!c.w.once };
|
|
44
|
+
}
|
|
45
|
+
const R = currentRoom(c);
|
|
46
|
+
return R ? quorum(c, R) : { done: true };
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=poll.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// results: a turn's end: its usage receipt settled, and its messages delivered or kept for a retry.
|
|
2
|
+
import { OPERATOR, append } from '../../hub/rooms/index.js';
|
|
3
|
+
import { note } from '../../../lib/index.js';
|
|
4
|
+
import { compose } from '../../hub/protocol/index.js';
|
|
5
|
+
import { loadState, readerLock, saveState } from '../../hub/history/index.js';
|
|
6
|
+
import { dispatch } from './dispatch.js';
|
|
7
|
+
const settle = (c, R, run, result) => append(R, c.me, compose(`usage: settle a run of ${c.me}${result.why ? ` (${result.why})` : ''}`, [['To', OPERATOR], ['Kind', 'usage'], ['Grant', run.grant], ['Usage', 'settle'], ['Run', run.run], ['Seconds', String(result.seconds)], ['Exit', String(result.exit)]]));
|
|
8
|
+
const delivered = (c, R, run, r) => readerLock(R, c.me, () => {
|
|
9
|
+
const st = loadState(R, c.me), ids = new Set(run.msgs.map(m => m.id));
|
|
10
|
+
const success = r.code === 0 || r.timedOut;
|
|
11
|
+
saveState(R, c.me, {
|
|
12
|
+
...st, inflight: undefined, ...(success
|
|
13
|
+
? { pending: (st.pending ?? []).filter(id => !ids.has(id)) }
|
|
14
|
+
: { seen: st.inflight?.seen ?? st.seen })
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
const ended = (c, R, run, r) => {
|
|
18
|
+
note(`watch: exit ${r.code ?? r.signal}${r.timedOut ? ' (stopped at the grant\'s run-seconds)' : ''} after ${r.seconds}s`);
|
|
19
|
+
if (run.run)
|
|
20
|
+
settle(c, R, run, { seconds: r.seconds, exit: r.code ?? 128 });
|
|
21
|
+
delivered(c, R, run, r);
|
|
22
|
+
};
|
|
23
|
+
export const runTurns = async (c, R, runs) => {
|
|
24
|
+
let exitCode = 0;
|
|
25
|
+
for (const run of runs) {
|
|
26
|
+
const next = dispatch(c, R, run);
|
|
27
|
+
if (next.why) {
|
|
28
|
+
note(`watch: not starting the next turn: ${next.why}`);
|
|
29
|
+
if (run.run)
|
|
30
|
+
settle(c, R, run, { seconds: 0, exit: 125, why: `not started: ${next.why}` });
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const r = await next.done;
|
|
34
|
+
ended(c, R, run, r);
|
|
35
|
+
if (r.code !== 0 || r.timedOut)
|
|
36
|
+
exitCode ||= r.code || 128;
|
|
37
|
+
}
|
|
38
|
+
return exitCode;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=results.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// seat: the watcher takes its agent's seat, from a dead watcher or by an explicit handoff from the agent's own chat.
|
|
2
|
+
import { locked } from '../../hub/ports/index.js';
|
|
3
|
+
import { config, openHub, openRoom } from '../../hub/rooms/index.js';
|
|
4
|
+
import { fail, stamp } from '../../../lib/index.js';
|
|
5
|
+
import { dropSession, liveness, parseSelector, pidAlive, saveSession, seatHolder, whoAmI } from '../sessions/index.js';
|
|
6
|
+
import { validateWatch } from './limits.js';
|
|
7
|
+
const handoff = (c, holder) => {
|
|
8
|
+
const own = c.w.handoff && holder?.product !== 'watch' && holder?.handle === whoAmI().handle;
|
|
9
|
+
if (c.w.handoff && !own)
|
|
10
|
+
fail('watch --handoff needs the invoking chat to own this seat');
|
|
11
|
+
if (own && holder.state === 'stopped')
|
|
12
|
+
fail('this chat is stopped; continue it before a handoff');
|
|
13
|
+
const live = holder && (holder.product !== 'watch' || (holder.pid && pidAlive(holder.pid)));
|
|
14
|
+
if (holder && !own && live)
|
|
15
|
+
fail(`${c.R0.name}/${c.me} is held by session ${holder.handle} (${liveness(holder)}); one seat per agent. Its chat may use watch --handoff`);
|
|
16
|
+
return !!own;
|
|
17
|
+
};
|
|
18
|
+
const claim = (c) => locked('sessions', () => {
|
|
19
|
+
const { w, H0, R0, me, handle } = c;
|
|
20
|
+
const holder = seatHolder(H0.name, R0.genesis, me, handle), handed = handoff(c, holder);
|
|
21
|
+
if (holder)
|
|
22
|
+
dropSession(holder.handle);
|
|
23
|
+
saveSession({
|
|
24
|
+
handle, product: 'watch', hub: H0.name, room: R0.name, genesis: R0.genesis, agent: me, scope: w.scope ?? holder?.scope ?? null,
|
|
25
|
+
state: holder?.state === 'stopped' ? 'stopped' : 'active', since: stamp(), lastSeen: stamp(), pid: process.pid,
|
|
26
|
+
takenFrom: handed ? holder.handle : holder?.takenFrom
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
export const createWatcher = (w, log) => {
|
|
30
|
+
validateWatch(w);
|
|
31
|
+
const sel = parseSelector(w.seat), H0 = openHub(sel.hub ?? w.hub ?? config().hub), R0 = openRoom(H0, sel.room), me = sel.agent;
|
|
32
|
+
if (R0.archived)
|
|
33
|
+
fail(`${R0.name} is archived`);
|
|
34
|
+
if (!R0.members[me])
|
|
35
|
+
fail(`${me} is not a member of ${R0.name}; the operator adds it with a join, or watch another agent`);
|
|
36
|
+
const raw = `watch-${H0.name}-${R0.genesis.slice(0, 8)}-${me}-${process.pid}`, handle = `env:${raw}`;
|
|
37
|
+
const c = {
|
|
38
|
+
w, H0, R0, me, raw, handle, cmd: w.exec, log, interval: (w.interval ?? 5) * 1000,
|
|
39
|
+
allow: w.from ? new Set(w.from) : null, maxHop: w.maxHop ?? 8, maxRuns: w.maxRuns ?? 10, span: w.window ?? 86400, runSeq: 0
|
|
40
|
+
};
|
|
41
|
+
claim(c);
|
|
42
|
+
return c;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=seat.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// The capabilities this build enforces: `<name>/<major>` → the module whose folds apply it. A new major is a new module
|
|
2
2
|
// registered beside the old one. A hub contract selects at most one major of each name; a room applies what its
|
|
3
3
|
// contract base selects (docs/ARCHITECTURE.md, Evolution).
|
|
4
|
-
import * as decisions from './decisions.js';
|
|
5
|
-
import * as profiles from './
|
|
4
|
+
import * as decisions from './decisions/index.js';
|
|
5
|
+
import * as profiles from './work/index.js';
|
|
6
6
|
export const CAPABILITIES = { [decisions.CAPABILITY]: decisions, [profiles.PROFILES_CAPABILITY]: profiles };
|
|
7
7
|
// Why a contract's capability list cannot be enforced by this build, or nothing.
|
|
8
8
|
export const unenforceable = (ids) => {
|
|
@@ -13,4 +13,4 @@ export const unenforceable = (ids) => {
|
|
|
13
13
|
const unknown = ids.filter(id => !CAPABILITIES[id]);
|
|
14
14
|
return unknown.length ? `requires ${unknown.join(', ')}` : null;
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=
|
|
16
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// budget: what a decision grants (a budget), until when a proposal waits (its due time), and who may decide it.
|
|
2
|
+
import { fail } from '../../../lib/index.js';
|
|
3
|
+
export const ROOT = 'operator';
|
|
4
|
+
const BUDGET_KEYS = ['runs', 'run-seconds', 'concurrency'];
|
|
5
|
+
export const ids = (v) => v === null ? [] : [...new Set(v.split(',').map(x => x.trim()).filter(Boolean))];
|
|
6
|
+
const PART = /^([a-z][a-z-]*)=(\d{1,9})$/;
|
|
7
|
+
// `runs=5, run-seconds=600, concurrency=1`; undefined if malformed. `runs` is required: a budget without a run count
|
|
8
|
+
// bounds nothing; a zero run time or concurrency would disable the bound it names.
|
|
9
|
+
export const parseBudget = (s) => {
|
|
10
|
+
if (s === null || s === undefined)
|
|
11
|
+
return null;
|
|
12
|
+
const b = {};
|
|
13
|
+
for (const part of String(s).split(',').map(x => x.trim()).filter(Boolean)) {
|
|
14
|
+
const m = PART.exec(part);
|
|
15
|
+
if (!m || !BUDGET_KEYS.includes(m[1]) || m[1] in b)
|
|
16
|
+
return undefined;
|
|
17
|
+
b[m[1]] = Number(m[2]);
|
|
18
|
+
}
|
|
19
|
+
return bounded(b) ? { 'run-seconds': 1800, concurrency: 1, ...b } : undefined;
|
|
20
|
+
};
|
|
21
|
+
const bounded = (b) => 'runs' in b && b['run-seconds'] !== 0 && b.concurrency !== 0;
|
|
22
|
+
export const budgetText = (b) => BUDGET_KEYS.map(k => `${k}=${b[k]}`).join(', ');
|
|
23
|
+
const UNIT = { m: 60e3, h: 3600e3, d: 86400e3 };
|
|
24
|
+
// Relative (`90m`, `2h`, `3d`) or an ISO 8601 time → ISO UTC to the second.
|
|
25
|
+
export const parseDue = (s) => {
|
|
26
|
+
const rel = /^(\d{1,6})([mhd])$/.exec(s);
|
|
27
|
+
const t = rel ? Date.now() + Number(rel[1]) * UNIT[rel[2]] : Date.parse(s);
|
|
28
|
+
if (!Number.isFinite(t))
|
|
29
|
+
fail(`--due takes 90m, 2h, 3d or an ISO time, not ${s}`);
|
|
30
|
+
return new Date(t).toISOString().slice(0, 19) + 'Z';
|
|
31
|
+
};
|
|
32
|
+
const within = (cap, budget) => BUDGET_KEYS.every(k => Number.isFinite(cap[k]) && budget[k] <= cap[k]);
|
|
33
|
+
// The root always may; anyone else only within the authority table, and never on their own proposal.
|
|
34
|
+
export const mayDecide = (authority, decider, proposer, budget) => {
|
|
35
|
+
if (decider === ROOT)
|
|
36
|
+
return true;
|
|
37
|
+
const cap = decider === proposer ? undefined : authority?.decide?.[decider];
|
|
38
|
+
return !!cap && (!budget || within(cap, budget));
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// check: the extension's trailers are part of a record's validity; a malformed decision record routes nowhere.
|
|
2
|
+
import { ID_RE, one } from '../protocol/index.js';
|
|
3
|
+
import { ids, parseBudget } from './budget.js';
|
|
4
|
+
export const STAMPS = ['approve', 'object', 'abstain'];
|
|
5
|
+
export const DECISIONS = ['approved', 'rejected', 'revoked'];
|
|
6
|
+
const SINGLE = ['decider', 'reviewers', 'due', 'budget', 'supersedes', 'stamp', 'decision', 'control', 'grant', 'usage', 'run', 'seconds', 'exit'];
|
|
7
|
+
const RUN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
8
|
+
// A trailer absent, or a message id.
|
|
9
|
+
const refOk = (m, k, isRef) => one(m, k) === null || isRef(one(m, k));
|
|
10
|
+
const answers = (m, values, k) => !!m.re && values.includes(one(m, k) ?? '');
|
|
11
|
+
const receipt = (m, isRef) => isRef(one(m, 'grant') ?? '') && ['reserve', 'settle'].includes(one(m, 'usage') ?? '') && RUN.test(one(m, 'run') ?? '');
|
|
12
|
+
const dueOk = (v) => v === null || Number.isFinite(Date.parse(v));
|
|
13
|
+
// What each kind of record must carry, as (wrong, why) in the order the reasons are reported.
|
|
14
|
+
const BY_KIND = {
|
|
15
|
+
proposal: (m, isRef) => [
|
|
16
|
+
[() => !ID_RE.test(one(m, 'decider') ?? ''), 'proposal without a valid Decider'],
|
|
17
|
+
[() => !ids(one(m, 'reviewers')).every(x => ID_RE.test(x)), 'malformed Reviewers'],
|
|
18
|
+
[() => !dueOk(one(m, 'due')), 'malformed Due'],
|
|
19
|
+
[() => !refOk(m, 'supersedes', isRef), 'malformed Supersedes'],
|
|
20
|
+
],
|
|
21
|
+
stamp: m => [[() => !answers(m, STAMPS, 'stamp'), 'stamp without Re or a valid Stamp']],
|
|
22
|
+
decision: m => [[() => !answers(m, DECISIONS, 'decision'), 'decision without Re or a valid Decision']],
|
|
23
|
+
usage: (m, isRef) => [
|
|
24
|
+
[() => !receipt(m, isRef), 'malformed usage receipt'],
|
|
25
|
+
[() => one(m, 'usage') === 'settle' && !/^\d{1,9}$/.test(one(m, 'seconds') ?? ''), 'usage settle without Seconds'],
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
// Why a record is malformed for this extension, or null.
|
|
29
|
+
export const check = (m, isRef) => {
|
|
30
|
+
if (m.bad)
|
|
31
|
+
return null;
|
|
32
|
+
const twice = SINGLE.find(k => (m.trailers[k]?.length ?? 0) > 1);
|
|
33
|
+
if (twice)
|
|
34
|
+
return `duplicate ${twice}`;
|
|
35
|
+
const rules = [
|
|
36
|
+
[() => !refOk(m, 'grant', isRef), 'malformed Grant'],
|
|
37
|
+
[() => !refOk(m, 'control', isRef), 'malformed Control'],
|
|
38
|
+
[() => one(m, 'budget') !== null && !parseBudget(one(m, 'budget')), 'malformed Budget'],
|
|
39
|
+
...BY_KIND[m.kind ?? '']?.(m, isRef) ?? [],
|
|
40
|
+
];
|
|
41
|
+
return rules.find(([wrong]) => wrong())?.[1] ?? null;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// decide: the extension for decisions and budgets (capability `decisions/1`, docs/spec/decisions-1.md). A proposal circulates
|
|
2
|
+
// to named reviewers, who stamp it; only the named decider, holding authority from the hub's contract, decides. An
|
|
3
|
+
// approval that carries a budget is a grant; work spends against it, and the runner that starts model runs writes
|
|
4
|
+
// the usage receipts. Everything here is a pure fold over messages; nothing trusts a model's own report.
|
|
5
|
+
export const CAPABILITY = 'decisions/1';
|
|
6
|
+
export * from './budget.js';
|
|
7
|
+
export * from './check.js';
|
|
8
|
+
export * from './proposal.js';
|
|
9
|
+
export * from './usage.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// proposal: one proposal folded over the messages that answer it, in thread order: its stamps, its decision, a
|
|
2
|
+
// revocation, a superseding revision; and the grant an approval with a budget makes.
|
|
3
|
+
import { one, ordered } from '../protocol/index.js';
|
|
4
|
+
import { ROOT, ids, mayDecide, parseBudget } from './budget.js';
|
|
5
|
+
const byOwner = (m, p) => m.from === p.from || m.from === ROOT;
|
|
6
|
+
// A revision supersedes only when its author is the proposer or the root.
|
|
7
|
+
const revises = (m, p) => m.kind === 'proposal' && one(m, 'supersedes') === p.id && byOwner(m, p);
|
|
8
|
+
const answers = (m, p) => m.reId === p.id && (m.kind === 'stamp' || m.kind === 'decision');
|
|
9
|
+
const among = (all, keep) => ordered([...all.values()].filter(m => !m.bad && keep(m)));
|
|
10
|
+
// A decision names the room's control commit it was made under (`Control`); its authority is the table in effect
|
|
11
|
+
// there. A commit that does not exist yet cannot be named, so a later contract never promotes or demotes a decision.
|
|
12
|
+
const authorized = (c, m) => {
|
|
13
|
+
if (m.from === ROOT)
|
|
14
|
+
return true;
|
|
15
|
+
const table = c.authorityAt(one(m, 'control'));
|
|
16
|
+
return !!table && mayDecide(table, c.decider, c.p.from, c.budget);
|
|
17
|
+
};
|
|
18
|
+
const decides = (c, m) => one(m, 'decision') !== 'revoked' && m.from === c.decider && authorized(c, m);
|
|
19
|
+
const revokes = (c, m) => one(m, 'decision') === 'revoked' && (m.from === c.decider || m.from === ROOT);
|
|
20
|
+
const approved = (f) => f.decision?.decision === 'approved';
|
|
21
|
+
// One answer applied: a reviewer's latest stamp counts (its position relative to the decision is only a same-second
|
|
22
|
+
// tie); the first decision of the decider with authority; then the first revocation of an approval.
|
|
23
|
+
const take = (c, f, m) => {
|
|
24
|
+
if (m.kind === 'stamp' && c.reviewers.includes(m.from))
|
|
25
|
+
f.stamps[m.from] = { stamp: one(m, 'stamp'), id: m.id, reason: m.subject };
|
|
26
|
+
if (m.kind !== 'decision')
|
|
27
|
+
return;
|
|
28
|
+
if (!f.decision && decides(c, m))
|
|
29
|
+
f.decision = { decision: one(m, 'decision'), id: m.id, by: m.from, time: m.time };
|
|
30
|
+
else if (approved(f) && !f.revoked && revokes(c, m))
|
|
31
|
+
f.revoked = { id: m.id, by: m.from, time: m.time };
|
|
32
|
+
};
|
|
33
|
+
// The answers in thread order; one after the superseding revision no longer applies to this revision, except a
|
|
34
|
+
// revocation of an earlier approval.
|
|
35
|
+
const fold = (c, list, superseded) => {
|
|
36
|
+
const f = { stamps: {}, decision: null, revoked: null };
|
|
37
|
+
for (const m of ordered([...list, ...(superseded ? [superseded] : [])])) {
|
|
38
|
+
if (m === superseded)
|
|
39
|
+
break;
|
|
40
|
+
take(c, f, m);
|
|
41
|
+
}
|
|
42
|
+
const late = superseded && approved(f) && !f.revoked ? list.find(m => revokes(c, m)) : undefined;
|
|
43
|
+
if (late)
|
|
44
|
+
f.revoked = { id: late.id, by: late.from, time: late.time };
|
|
45
|
+
return f;
|
|
46
|
+
};
|
|
47
|
+
const stateOf = (f, superseded, due, now) => {
|
|
48
|
+
if (f.revoked)
|
|
49
|
+
return 'revoked';
|
|
50
|
+
if (f.decision)
|
|
51
|
+
return f.decision.decision;
|
|
52
|
+
if (superseded)
|
|
53
|
+
return 'superseded';
|
|
54
|
+
return due && now > due ? 'overdue' : 'open';
|
|
55
|
+
};
|
|
56
|
+
export const proposalOf = (all, p, authorityAt, now = Date.now() / 1000) => {
|
|
57
|
+
const c = { p, decider: one(p, 'decider'), reviewers: ids(one(p, 'reviewers')), budget: parseBudget(one(p, 'budget')) ?? null, authorityAt };
|
|
58
|
+
const due = one(p, 'due') ? Date.parse(one(p, 'due')) / 1000 : null;
|
|
59
|
+
const superseded = among(all, m => revises(m, p))[0] ?? null;
|
|
60
|
+
const f = fold(c, among(all, m => answers(m, p)), superseded);
|
|
61
|
+
const grant = approved(f) && c.budget ? { id: f.decision.id, budget: c.budget, proposal: p, revoked: !!f.revoked } : null;
|
|
62
|
+
return { proposal: p, decider: c.decider, reviewers: c.reviewers, budget: c.budget, due, ...f,
|
|
63
|
+
missing: c.reviewers.filter(r => !f.stamps[r]), superseded, state: stateOf(f, superseded, due, now), grant };
|
|
64
|
+
};
|
|
65
|
+
export const proposals = (all, authorityAt) => [...all.values()].filter(m => !m.bad && m.kind === 'proposal').map(p => proposalOf(all, p, authorityAt));
|
|
66
|
+
const decision = (d) => !!d && !d.bad && d.kind === 'decision';
|
|
67
|
+
export const grantOf = (all, authorityAt, id) => {
|
|
68
|
+
const d = all.get(id);
|
|
69
|
+
const p = decision(d) && d.reId ? all.get(d.reId) : undefined;
|
|
70
|
+
const g = p ? proposalOf(all, p, authorityAt).grant : null;
|
|
71
|
+
return g?.id === id ? g : null;
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=proposal.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// usage: what a grant's runs spent, from the usage receipts the runners write.
|
|
2
|
+
import { one, ordered } from '../protocol/index.js';
|
|
3
|
+
import { grantOf } from './proposal.js';
|
|
4
|
+
// The receipts a grant's ledger counts, in thread order: every reservation, and for each run (its runner and Run id)
|
|
5
|
+
// the first settlement after its reservation, as the first decision counts. A settlement of no reserved run counts
|
|
6
|
+
// nothing.
|
|
7
|
+
const ledger = (all, grant) => {
|
|
8
|
+
const reserves = [], settled = new Map(), reserved = new Set();
|
|
9
|
+
for (const m of ordered([...all.values()].filter(m => !m.bad && m.kind === 'usage' && one(m, 'grant') === grant.id))) {
|
|
10
|
+
const run = `${m.from}/${one(m, 'run')}`;
|
|
11
|
+
if (one(m, 'usage') === 'reserve') {
|
|
12
|
+
reserves.push(m);
|
|
13
|
+
reserved.add(run);
|
|
14
|
+
}
|
|
15
|
+
else if (reserved.has(run) && !settled.has(run))
|
|
16
|
+
settled.set(run, m);
|
|
17
|
+
}
|
|
18
|
+
return { reserves, settled };
|
|
19
|
+
};
|
|
20
|
+
// Whether a receipt counts: its Grant names a grant, and that grant's ledger holds it.
|
|
21
|
+
export const counted = (all, authorityAt, m) => {
|
|
22
|
+
const g = !m.bad && m.kind === 'usage' ? grantOf(all, authorityAt, one(m, 'grant') ?? '') : null;
|
|
23
|
+
if (!g)
|
|
24
|
+
return false;
|
|
25
|
+
const { reserves, settled } = ledger(all, g);
|
|
26
|
+
return reserves.includes(m) || [...settled.values()].includes(m);
|
|
27
|
+
};
|
|
28
|
+
// Usage from the runners' receipts: every reservation is a run, settled or not; an unsettled one is open while its
|
|
29
|
+
// run could still be going, and uncertain after that.
|
|
30
|
+
export const usageOf = (all, grant, now = Date.now() / 1000) => {
|
|
31
|
+
const { reserves, settled } = ledger(all, grant);
|
|
32
|
+
let seconds = 0;
|
|
33
|
+
for (const m of settled.values())
|
|
34
|
+
seconds += Number(one(m, 'seconds'));
|
|
35
|
+
const unsettled = reserves.filter(m => !settled.has(`${m.from}/${one(m, 'run')}`));
|
|
36
|
+
const open = unsettled.filter(m => now - m.time <= grant.budget['run-seconds'] + 60);
|
|
37
|
+
return { runs: reserves.length, open: open.length, uncertain: unsettled.length - open.length, seconds, left: Math.max(0, grant.budget.runs - reserves.length) };
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1,90 @@
|
|
|
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 * as Signals from '../signals/index.js';
|
|
4
|
+
import { hubPorts, locked } from '../ports/index.js';
|
|
5
|
+
import { toMessage } from '../rooms/index.js';
|
|
6
|
+
import { fail, note, short } from '../../../lib/index.js';
|
|
7
|
+
import { link } from '../protocol/index.js';
|
|
8
|
+
// What one reader accepted of one room: a record of the machine's state.
|
|
9
|
+
const readerKey = (R, reader) => ['readers', R.hub.name, R.genesis, reader];
|
|
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) => hubPorts().state.read(readerKey(R, reader), {});
|
|
12
|
+
export const saveState = (R, reader, st) => hubPorts().state.write(readerKey(R, reader), st);
|
|
13
|
+
// The control history must extend what this reader accepted; a rewritten one delivers nothing.
|
|
14
|
+
const acceptControl = (R, st) => {
|
|
15
|
+
if (st.control && !R.hub.store.extends(st.control, R.head)) {
|
|
16
|
+
fail(`ALARM room ${R.name}: its control history was rewritten (accepted ${short(st.control)}, now ${short(R.head)}). Nothing is delivered; the operator decides`);
|
|
17
|
+
}
|
|
18
|
+
st.control = R.head;
|
|
19
|
+
};
|
|
20
|
+
// Why a log's current head cannot be accepted after `acc`, if it cannot.
|
|
21
|
+
const logProblem = (R, id, acc, cur) => {
|
|
22
|
+
const store = R.hub.store;
|
|
23
|
+
if (!cur)
|
|
24
|
+
return `log ${id} was deleted after ${short(acc)}`;
|
|
25
|
+
if (acc && !store.extends(acc, cur))
|
|
26
|
+
return `log ${id} was rewritten: ${short(cur)} does not extend the accepted ${short(acc)}`;
|
|
27
|
+
if (!store.extends(R.genesis, cur))
|
|
28
|
+
return `log ${id} does not descend from the room's genesis`;
|
|
29
|
+
const why = store.verifyLog(R.s, id, cur);
|
|
30
|
+
return why && `log ${id}: ${why}`;
|
|
31
|
+
};
|
|
32
|
+
// Every log that still extends its accepted head, pinned at its new head; the others become alarms.
|
|
33
|
+
const acceptLogs = (R, reader, st, alarms) => {
|
|
34
|
+
const store = R.hub.store, heads = st.heads ??= {};
|
|
35
|
+
const logs = new Map();
|
|
36
|
+
for (const id of new Set([...store.logIds(R.s), ...Object.keys(heads)])) {
|
|
37
|
+
const cur = store.logHead(R.s, id), acc = heads[id];
|
|
38
|
+
const why = logProblem(R, id, acc, cur);
|
|
39
|
+
if (why) {
|
|
40
|
+
alarms.push(why);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (acc !== cur) {
|
|
44
|
+
heads[id] = cur;
|
|
45
|
+
store.pin(R.s, reader, id, cur);
|
|
46
|
+
}
|
|
47
|
+
logs.set(id, store.messages(R.s, id, cur).map((x, seq) => toMessage(R, id, x, seq)));
|
|
48
|
+
}
|
|
49
|
+
return logs;
|
|
50
|
+
};
|
|
51
|
+
// The signals that agree with their messages are pinned; the rest become alarms.
|
|
52
|
+
const acceptSignals = (R, logs, st, alarms) => {
|
|
53
|
+
const records = R.hub.store.signals(R.s);
|
|
54
|
+
const checked = Signals.check(R, link(logs), records);
|
|
55
|
+
const signalPins = Signals.pins(records, checked, st.signals);
|
|
56
|
+
st.signals = signalPins.accepted;
|
|
57
|
+
alarms.push(...signalPins.alarms, ...checked.filter(x => !x.ok).map(x => `signal ${x.ref}: ${x.why}`));
|
|
58
|
+
};
|
|
59
|
+
// What follows from an alarm, by what it is about.
|
|
60
|
+
const remedy = (R, alarm) => {
|
|
61
|
+
if (alarm.startsWith('signal '))
|
|
62
|
+
return 'the messages stay the truth; the author restores a missing signal with ringi agent signals --repair';
|
|
63
|
+
if (alarm.startsWith('commit '))
|
|
64
|
+
return 'it is skipped; the room reads on without it';
|
|
65
|
+
return `it is quarantined and withheld. Restore it, or the operator runs ringi forget ${R.name}/<log>`;
|
|
66
|
+
};
|
|
67
|
+
// Every log must keep extending what this reader accepted, and the store must verify it (a signed store: every entry
|
|
68
|
+
// signed by the key the room admitted). A log that lost, rewrote or forked accepted history, or fails verification,
|
|
69
|
+
// is quarantined: withheld, its accepted head pinned as evidence. Only `ringi forget` by the operator accepts a new
|
|
70
|
+
// baseline. Each alarm is told once.
|
|
71
|
+
export const loadRoomUnlocked = (R, reader) => {
|
|
72
|
+
const st = loadState(R, reader);
|
|
73
|
+
acceptControl(R, st);
|
|
74
|
+
const alarms = [...R.hub.store.alarms?.(R.s) ?? []];
|
|
75
|
+
const logs = acceptLogs(R, reader, st, alarms);
|
|
76
|
+
acceptSignals(R, logs, st, alarms);
|
|
77
|
+
const reported = new Set(st.alarms ?? []);
|
|
78
|
+
for (const a of alarms)
|
|
79
|
+
if (!reported.has(a))
|
|
80
|
+
note(`ALARM ${a}; ${remedy(R, a)}`);
|
|
81
|
+
st.alarms = alarms;
|
|
82
|
+
saveState(R, reader, st);
|
|
83
|
+
return { logs, st };
|
|
84
|
+
};
|
|
85
|
+
export const loadRoom = (R, reader) => readerLock(R, reader, () => loadRoomUnlocked(R, reader));
|
|
86
|
+
export const linked = (R, reader) => {
|
|
87
|
+
const { logs } = loadRoom(R, reader);
|
|
88
|
+
return { logs, all: link(logs) };
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// ports (hub): what the hub needs from the world it runs in — this build, the machine's state, the store types — and
|
|
2
|
+
// where an implementation plugs in. Code asks `hubPorts()` and never imports an adapter; composition/ wires them in
|
|
3
|
+
// when a program starts. The agents' own ports are apart (core/agents/ports).
|
|
4
|
+
import { fail } from '../../../lib/fail.js';
|
|
5
|
+
let wired = null;
|
|
6
|
+
export const wireHub = (p) => { wired = p; };
|
|
7
|
+
export const hubPorts = () => wired ?? fail('ringi is not wired: a program starts it through composition/');
|
|
8
|
+
// Exclusive across the processes of this machine (LocalState.locked).
|
|
9
|
+
export const locked = (name, fn) => hubPorts().state.locked(name, fn);
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// state: what ringi keeps on this machine — the operator's terminal context, what each reader accepted, the sessions,
|
|
2
|
+
// a hub's descriptor and its store's own files — as a port. A record is named by a key path; the adapter decides where
|
|
3
|
+
// it lives (adapters/state-fs: $RINGI_HOME). Reading fails closed: an unreadable record is an error, never a fresh start.
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// store: the port every storage type implements, each an adapter (adapters/transport-<type>: git, kafka and temporal
|
|
2
|
+
// planned) that composition/ registers. Rooms, accepted history, profiles, decisions and signals use only this
|
|
3
|
+
// interface; git is the first implementation, and a hub's descriptor names which one it uses (`store.type`). A store
|
|
4
|
+
// keeps the shared contract (versioned files the participants agree on: contract.json, authority.json, profiles), the
|
|
5
|
+
// rooms (a control record with versioned files, members and roster, and one append-only log per member) and signals
|
|
6
|
+
// (named markers on log entries); the port is split by what each part does (Log, Attachments, …).
|
|
7
|
+
// Revisions are opaque, store-assigned ids. A store says whether one revision extends another; ringi builds the
|
|
8
|
+
// trust rules on that (core/hub/history).
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// files: the paths a message may attach (core-1 §4).
|
|
2
|
-
import { fail } from '
|
|
2
|
+
import { fail } from '../../../lib/index.js';
|
|
3
3
|
export const CC_RE = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/;
|
|
4
|
-
|
|
4
|
+
// A path component that is empty, a directory alias or git's own, too long, or holds control characters.
|
|
5
|
+
const RESERVED_COMPONENTS = new Set(['', '.', '..', '.git']);
|
|
6
|
+
const COMPONENT_BAD = (c) => RESERVED_COMPONENTS.has(c) || Buffer.byteLength(c) > 255 || CC_RE.test(c) || /[\n\t]/.test(c);
|
|
5
7
|
export const checkPath = (p) => {
|
|
6
8
|
if (p.startsWith('/') || p.split('/').some(COMPONENT_BAD))
|
|
7
9
|
fail(`bad file path ${p}`);
|
|
@@ -0,0 +1,9 @@
|
|
|
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: the text (text.ts), threads and order (threads.ts), inboxes and
|
|
3
|
+
// waking (reading.ts). What a task is, which states it has and who may move it, is a profile, not part of the protocol.
|
|
4
|
+
export * from './model.js';
|
|
5
|
+
export * from './text.js';
|
|
6
|
+
export * from './threads.js';
|
|
7
|
+
export * from './order.js';
|
|
8
|
+
export * from './reading.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// model: what the protocol is made of — ids, trailers, messages — with no behaviour (docs/spec/core-1.md).
|
|
2
|
+
export const ID_RE = /^(?=.{1,64}$)[a-z0-9]+(?:[._-][a-z0-9]+)*(?<!\.lock)$/;
|
|
3
|
+
// An agent's id has no dot: it starts the name of its signals, `<agent>.<signal>.<message12>`.
|
|
4
|
+
export const AGENT_RE = /^(?=.{1,64}$)[a-z0-9]+(?:[_-][a-z0-9]+)*$/;
|
|
5
|
+
export const TOKEN_RE = /^[a-z][a-z0-9-]*$/;
|
|
6
|
+
export const HOP_RE = /^(?:0|[1-9]\d{0,5})$/;
|
|
7
|
+
export const TRAILER_RE = /^([A-Za-z][A-Za-z0-9-]*):[ \t]*(.*)$/;
|
|
8
|
+
export const TEXT_MAX = 64 * 1024;
|
|
9
|
+
// Trailers the protocol itself interprets; any other trailer belongs to an extension or a profile.
|
|
10
|
+
export const KNOWN = new Set(['to', 're', 'kind', 'state', 'hop', 'assign', 'roles']);
|
|
11
|
+
export const HEARTBEATS = new Set(['ping', 'pong']);
|
|
12
|
+
// Kinds that are bookkeeping, never delivered to an inbox: heartbeats, usage receipts, cards, room records.
|
|
13
|
+
export const HIDDEN = new Set(['ping', 'pong', 'usage', 'card', 'room']);
|
|
14
|
+
export const one = (m, k) => m.trailers[k]?.[0] ?? null;
|
|
15
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// order: the order of messages (core-1 §5).
|
|
2
|
+
// The order's edges: each log in sequence, and each answer after what it answers.
|
|
3
|
+
const graph = (list) => {
|
|
4
|
+
const byId = new Map(list.map(m => [m.id, m]));
|
|
5
|
+
const next = new Map(list.map(m => [m.id, []]));
|
|
6
|
+
const indeg = new Map(list.map(m => [m.id, 0]));
|
|
7
|
+
const edge = (a, b) => {
|
|
8
|
+
next.get(a.id).push(b);
|
|
9
|
+
indeg.set(b.id, indeg.get(b.id) + 1);
|
|
10
|
+
};
|
|
11
|
+
const last = new Map();
|
|
12
|
+
for (const m of [...list].sort((a, b) => a.seq - b.seq)) {
|
|
13
|
+
if (last.has(m.from))
|
|
14
|
+
edge(last.get(m.from), m);
|
|
15
|
+
last.set(m.from, m);
|
|
16
|
+
if (m.reId && byId.has(m.reId))
|
|
17
|
+
edge(byId.get(m.reId), m);
|
|
18
|
+
}
|
|
19
|
+
return { next, indeg };
|
|
20
|
+
};
|
|
21
|
+
const earliest = (a, b) => a.time - b.time || (a.id < b.id ? -1 : 1);
|
|
22
|
+
// Kahn's order: the answered message before the answer, earlier before later within one log; among the ready ones,
|
|
23
|
+
// the smallest (time, id) goes first.
|
|
24
|
+
export const ordered = (list) => {
|
|
25
|
+
const { next, indeg } = graph(list);
|
|
26
|
+
const ready = list.filter(m => !indeg.get(m.id));
|
|
27
|
+
const res = [];
|
|
28
|
+
while (ready.length) {
|
|
29
|
+
const m = ready.sort(earliest).shift();
|
|
30
|
+
res.push(m);
|
|
31
|
+
for (const n of next.get(m.id)) {
|
|
32
|
+
indeg.set(n.id, indeg.get(n.id) - 1);
|
|
33
|
+
if (!indeg.get(n.id))
|
|
34
|
+
ready.push(n);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=order.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// reading: what is delivered to whom (core-1 §6) and what wakes it (§7).
|
|
2
|
+
import { ordered } from './order.js';
|
|
3
|
+
const addressed = (m, id) => m.to.includes(id) || m.to.includes('*');
|
|
4
|
+
const hiddenKind = (m, hidden) => !!m.kind && hidden.has(m.kind);
|
|
5
|
+
// Delivered: well-formed, not a hidden kind, addressed to `id` by name or `*`.
|
|
6
|
+
export const visible = (m, id, hidden) => !m.invalid && !m.bad && !hiddenKind(m, hidden) && addressed(m, id);
|
|
7
|
+
// Wakes: only a direct address. Broadcasts are read when the agent is awake for another reason.
|
|
8
|
+
export const wakes = (m, id, hidden) => visible(m, id, hidden) && m.to.includes(id);
|
|
9
|
+
const after = (msgs, cursor) => msgs.slice(msgs.findIndex(m => m.id === cursor) + 1);
|
|
10
|
+
const others = (logs, id) => [...logs].filter(([log]) => log !== id);
|
|
11
|
+
// Each log's cursor moves past what was shown and what is not for `id`, up to the first message held back.
|
|
12
|
+
const advance = (logs, id, cursors, seen, hidden) => {
|
|
13
|
+
const next = { ...cursors };
|
|
14
|
+
for (const [log, msgs] of others(logs, id)) {
|
|
15
|
+
for (const m of after(msgs, cursors[log])) {
|
|
16
|
+
if (visible(m, id, hidden) && !seen.has(m.id))
|
|
17
|
+
break;
|
|
18
|
+
next[log] = m.id;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return next;
|
|
22
|
+
};
|
|
23
|
+
// Messages for `id` after the per-log cursors; cursors advance only past what was shown.
|
|
24
|
+
export const unread = (logs, id, cursors, limit = Infinity, hidden) => {
|
|
25
|
+
const queue = ordered(others(logs, id).flatMap(([log, msgs]) => after(msgs, cursors[log]).filter(m => visible(m, id, hidden))));
|
|
26
|
+
const shown = queue.slice(0, limit);
|
|
27
|
+
return { msgs: shown, rest: queue.length - shown.length, cursors: advance(logs, id, cursors, new Set(shown.map(m => m.id)), hidden) };
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=reading.js.map
|