@idleware/ringi 0.6.1 → 0.7.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.
Files changed (152) hide show
  1. package/README.md +7 -18
  2. package/package.json +1 -1
  3. package/src/main/resources/profiles/a2a-1.json +0 -4
  4. package/src/main/resources/skill/ringi/SKILL.md +2 -18
  5. package/target/dts/adapters/host-posix/index.d.ts +2 -2
  6. package/target/dts/adapters/transport-git/branches.d.ts +2 -3
  7. package/target/dts/adapters/transport-git/index.d.ts +0 -1
  8. package/target/dts/adapters/transport-git/remote/types.d.ts +0 -1
  9. package/target/dts/adapters/transport-git/repo.d.ts +0 -1
  10. package/target/dts/clients/cli/agent/index.d.ts +0 -2
  11. package/target/dts/clients/cli/shared/index.d.ts +0 -1
  12. package/target/dts/core/agents/heartbeat/index.d.ts +2 -5
  13. package/target/dts/core/agents/heartbeat/pulse.d.ts +1 -3
  14. package/target/dts/core/agents/overview.d.ts +1 -5
  15. package/target/dts/core/agents/ports/host.d.ts +5 -37
  16. package/target/dts/core/agents/sessions/agent.d.ts +0 -17
  17. package/target/dts/core/agents/sessions/index.d.ts +0 -1
  18. package/target/dts/core/hub/history/index.d.ts +1 -11
  19. package/target/dts/core/hub/ports/store.d.ts +1 -5
  20. package/target/dts/core/hub/protocol/model.d.ts +0 -1
  21. package/target/dts/core/hub/protocol/reading.d.ts +0 -1
  22. package/target/dts/core/hub/rooms/index.d.ts +0 -4
  23. package/target/dts/core/hub/rooms/messages.d.ts +0 -1
  24. package/target/dts/core/hub/rooms/rooms.d.ts +1 -1
  25. package/target/dts/core/hub/signals/model.d.ts +0 -2
  26. package/target/dts/core/hub/usecases/hubs.d.ts +0 -1
  27. package/target/dts/core/hub/usecases/room.d.ts +0 -1
  28. package/target/dts/core/hub/usecases/rooms.d.ts +1 -5
  29. package/target/dts/core/hub/usecases/send.d.ts +0 -1
  30. package/target/dts/core/hub/usecases/view.d.ts +0 -22
  31. package/target/dts/core/hub/work/index.d.ts +0 -1
  32. package/target/dts/index.d.ts +0 -1
  33. package/target/esm/adapters/host-posix/index.js +30 -32
  34. package/target/esm/adapters/transport-git/branches.js +13 -20
  35. package/target/esm/adapters/transport-git/index.js +1 -6
  36. package/target/esm/adapters/transport-git/marks.js +1 -1
  37. package/target/esm/adapters/transport-git/remote/admit.js +0 -2
  38. package/target/esm/adapters/transport-git/remote/heartbeat-push.js +1 -1
  39. package/target/esm/adapters/transport-git/remote/main.js +1 -4
  40. package/target/esm/adapters/transport-git/repo.js +0 -1
  41. package/target/esm/clients/cli/agent/index.js +4 -10
  42. package/target/esm/clients/cli/arg-parse.js +1 -1
  43. package/target/esm/clients/cli/commands.js +6 -7
  44. package/target/esm/clients/cli/help.js +6 -13
  45. package/target/esm/clients/cli/operator/heartbeat-format.js +1 -1
  46. package/target/esm/clients/cli/operator/hub-commands.js +1 -1
  47. package/target/esm/clients/cli/operator/index.js +1 -1
  48. package/target/esm/clients/cli/operator/room.js +46 -7
  49. package/target/esm/clients/cli/operator/where-format.js +1 -3
  50. package/target/esm/clients/cli/shared/index.js +1 -2
  51. package/target/esm/clients/cli/shared/messages.js +1 -1
  52. package/target/esm/clients/cli/shared/profile.js +2 -2
  53. package/target/esm/clients/cli/shared/work.js +1 -1
  54. package/target/esm/composition/index.js +1 -3
  55. package/target/esm/core/agents/heartbeat/index.js +16 -23
  56. package/target/esm/core/agents/heartbeat/pulse.js +18 -33
  57. package/target/esm/core/agents/heartbeat/tools.js +1 -2
  58. package/target/esm/core/agents/overview.js +5 -6
  59. package/target/esm/core/agents/ports/host.js +2 -2
  60. package/target/esm/core/agents/sessions/agent.js +3 -23
  61. package/target/esm/core/agents/sessions/binding.js +5 -7
  62. package/target/esm/core/agents/sessions/index.js +3 -7
  63. package/target/esm/core/agents/sessions/join.js +1 -5
  64. package/target/esm/core/agents/sessions/resume.js +3 -4
  65. package/target/esm/core/agents/sessions/wait.js +10 -31
  66. package/target/esm/core/hub/capabilities.js +4 -2
  67. package/target/esm/core/hub/history/index.js +3 -1
  68. package/target/esm/core/hub/ports/store.js +3 -3
  69. package/target/esm/core/hub/protocol/index.js +3 -3
  70. package/target/esm/core/hub/protocol/model.js +2 -3
  71. package/target/esm/core/hub/protocol/reading.js +1 -3
  72. package/target/esm/core/hub/rooms/compat.js +1 -2
  73. package/target/esm/core/hub/rooms/hubs.js +2 -5
  74. package/target/esm/core/hub/rooms/index.js +3 -3
  75. package/target/esm/core/hub/rooms/messages.js +5 -10
  76. package/target/esm/core/hub/rooms/rooms.js +9 -38
  77. package/target/esm/core/hub/signals/effective.js +1 -21
  78. package/target/esm/core/hub/signals/index.js +2 -2
  79. package/target/esm/core/hub/signals/pins.js +1 -1
  80. package/target/esm/core/hub/usecases/hubs.js +0 -3
  81. package/target/esm/core/hub/usecases/room.js +2 -3
  82. package/target/esm/core/hub/usecases/rooms.js +4 -17
  83. package/target/esm/core/hub/usecases/roster.js +1 -1
  84. package/target/esm/core/hub/usecases/send.js +2 -12
  85. package/target/esm/core/hub/usecases/view.js +2 -6
  86. package/target/esm/core/hub/work/task.js +4 -11
  87. package/target/esm/index.js +1 -2
  88. package/target/esm/lib/json.js +1 -1
  89. package/target/dts/adapters/host-posix/group-state.d.ts +0 -7
  90. package/target/dts/adapters/host-posix/groups.d.ts +0 -1
  91. package/target/dts/adapters/host-posix/launch.d.ts +0 -7
  92. package/target/dts/adapters/host-posix/probes.d.ts +0 -5
  93. package/target/dts/adapters/host-posix/stats.d.ts +0 -9
  94. package/target/dts/adapters/transport-kafka/index.d.ts +0 -2
  95. package/target/dts/adapters/transport-temporal/index.d.ts +0 -2
  96. package/target/dts/clients/cli/operator/room-lifecycle.d.ts +0 -5
  97. package/target/dts/clients/cli/operator/room-list.d.ts +0 -5
  98. package/target/dts/clients/cli/operator/room-members.d.ts +0 -4
  99. package/target/dts/clients/cli/operator/watch.d.ts +0 -2
  100. package/target/dts/clients/cli/shared/budget.d.ts +0 -7
  101. package/target/dts/core/agents/turns/budgets.d.ts +0 -5
  102. package/target/dts/core/agents/turns/dispatch.d.ts +0 -9
  103. package/target/dts/core/agents/turns/exhaustion.d.ts +0 -11
  104. package/target/dts/core/agents/turns/grants.d.ts +0 -4
  105. package/target/dts/core/agents/turns/index.d.ts +0 -4
  106. package/target/dts/core/agents/turns/limits.d.ts +0 -2
  107. package/target/dts/core/agents/turns/messages.d.ts +0 -10
  108. package/target/dts/core/agents/turns/pings.d.ts +0 -5
  109. package/target/dts/core/agents/turns/plan.d.ts +0 -3
  110. package/target/dts/core/agents/turns/poll.d.ts +0 -8
  111. package/target/dts/core/agents/turns/results.d.ts +0 -3
  112. package/target/dts/core/agents/turns/seat.d.ts +0 -2
  113. package/target/dts/core/agents/turns/types.d.ts +0 -59
  114. package/target/dts/core/hub/decisions/budget.d.ts +0 -15
  115. package/target/dts/core/hub/decisions/check.d.ts +0 -6
  116. package/target/dts/core/hub/decisions/index.d.ts +0 -5
  117. package/target/dts/core/hub/decisions/proposal.d.ts +0 -38
  118. package/target/dts/core/hub/decisions/usage.d.ts +0 -12
  119. package/target/dts/core/hub/usecases/budget.d.ts +0 -23
  120. package/target/dts/core/hub/usecases/propose.d.ts +0 -17
  121. package/target/esm/adapters/host-posix/group-state.js +0 -24
  122. package/target/esm/adapters/host-posix/groups.js +0 -43
  123. package/target/esm/adapters/host-posix/launch.js +0 -80
  124. package/target/esm/adapters/host-posix/probes.js +0 -66
  125. package/target/esm/adapters/host-posix/stats.js +0 -27
  126. package/target/esm/adapters/transport-kafka/index.js +0 -4
  127. package/target/esm/adapters/transport-temporal/index.js +0 -4
  128. package/target/esm/clients/cli/operator/room-lifecycle.js +0 -23
  129. package/target/esm/clients/cli/operator/room-list.js +0 -27
  130. package/target/esm/clients/cli/operator/room-members.js +0 -15
  131. package/target/esm/clients/cli/operator/watch.js +0 -15
  132. package/target/esm/clients/cli/shared/budget.js +0 -50
  133. package/target/esm/core/agents/turns/budgets.js +0 -48
  134. package/target/esm/core/agents/turns/dispatch.js +0 -40
  135. package/target/esm/core/agents/turns/exhaustion.js +0 -16
  136. package/target/esm/core/agents/turns/grants.js +0 -36
  137. package/target/esm/core/agents/turns/index.js +0 -33
  138. package/target/esm/core/agents/turns/limits.js +0 -11
  139. package/target/esm/core/agents/turns/messages.js +0 -32
  140. package/target/esm/core/agents/turns/pings.js +0 -30
  141. package/target/esm/core/agents/turns/plan.js +0 -29
  142. package/target/esm/core/agents/turns/poll.js +0 -48
  143. package/target/esm/core/agents/turns/results.js +0 -40
  144. package/target/esm/core/agents/turns/seat.js +0 -44
  145. package/target/esm/core/agents/turns/types.js +0 -3
  146. package/target/esm/core/hub/decisions/budget.js +0 -40
  147. package/target/esm/core/hub/decisions/check.js +0 -43
  148. package/target/esm/core/hub/decisions/index.js +0 -10
  149. package/target/esm/core/hub/decisions/proposal.js +0 -73
  150. package/target/esm/core/hub/decisions/usage.js +0 -39
  151. package/target/esm/core/hub/usecases/budget.js +0 -78
  152. package/target/esm/core/hub/usecases/propose.js +0 -39
@@ -1,12 +0,0 @@
1
- import type { All, Message } from '../protocol/index.ts';
2
- import type { AuthorityAt } from './budget.ts';
3
- import type { Grant } from './proposal.ts';
4
- export type Usage = {
5
- runs: number;
6
- open: number;
7
- uncertain: number;
8
- seconds: number;
9
- left: number;
10
- };
11
- export declare const counted: (all: All, authorityAt: AuthorityAt, m: Message) => boolean;
12
- export declare const usageOf: (all: All, grant: Grant, now?: number) => Usage;
@@ -1,23 +0,0 @@
1
- import * as D from '../decisions/index.ts';
2
- import type { Message } from '../protocol/index.ts';
3
- import type { Actor } from './actor.ts';
4
- import type { GrantView, ProposalView } from './view.ts';
5
- export declare const stamp: ({ R, me }: Actor, ref: string, s: string, text: string) => {
6
- proposal: Message;
7
- id: string;
8
- };
9
- export declare const decide: ({ R, me }: Actor, ref: string, d: string, text: string) => {
10
- proposal: Message;
11
- id: string;
12
- budget: D.Budget | null;
13
- };
14
- export declare const proposals: ({ R, me }: Actor, { all: everything }?: {
15
- all?: boolean;
16
- }) => {
17
- proposals: D.Proposal[];
18
- views: ProposalView[];
19
- };
20
- export declare const grants: ({ R, me }: Actor) => GrantView[];
21
- export { propose } from './propose.ts';
22
- export type { ProposeInput } from './propose.ts';
23
- export { DECISIONS, STAMPS, budgetText } from '../decisions/index.ts';
@@ -1,17 +0,0 @@
1
- import * as D from '../decisions/index.ts';
2
- import type { Entry } from '../protocol/files.ts';
3
- import type { Actor } from './actor.ts';
4
- export type ProposeInput = {
5
- text: string;
6
- decider: string;
7
- reviewers?: string[];
8
- budget?: string;
9
- due?: string;
10
- supersedes?: string;
11
- files?: Entry[];
12
- };
13
- export declare const propose: ({ R, me }: Actor, x: ProposeInput) => {
14
- id: string;
15
- to: string[];
16
- budget: D.Budget | null;
17
- };
@@ -1,24 +0,0 @@
1
- // group-state: process-group membership and whether its observed members have finished; only Z is a zombie.
2
- export const procMember = (text) => {
3
- const close = text.lastIndexOf(')');
4
- if (!/^\d+ \(/.test(text) || close < 0)
5
- return null;
6
- const fields = text.slice(close + 1).trim().split(/\s+/);
7
- const group = Number(fields[2]), state = fields[0];
8
- return /^[A-Za-z]$/.test(state) && Number.isSafeInteger(group) && group >= 0 ? { group, state } : null;
9
- };
10
- export const psMember = (text) => {
11
- const match = /^\s*(\d+)\s+([A-Za-z][^\s]*)\s*$/.exec(text);
12
- if (!match)
13
- return null;
14
- const group = Number(match[1]);
15
- return Number.isSafeInteger(group) ? { group, state: match[2][0] } : null;
16
- };
17
- // No matching row, or an unreadable row that might belong to this group, cannot prove it is quiescent.
18
- export const groupRunning = (group, members) => {
19
- const own = members.filter(m => m?.group === group);
20
- if (own.some(m => m.state !== 'Z'))
21
- return true;
22
- return own.length && members.every(m => m !== null) ? false : null;
23
- };
24
- //# sourceMappingURL=group-state.js.map
@@ -1,43 +0,0 @@
1
- // groups: a turn's POSIX group is settled once every observed member is a zombie; failed probes stay conservative.
2
- import fs from 'node:fs';
3
- import { spawnSync } from 'node:child_process';
4
- import { groupRunning, procMember, psMember } from './group-state.js';
5
- const exists = (group) => {
6
- try {
7
- process.kill(-group, 0);
8
- return true;
9
- }
10
- catch (e) {
11
- return e.code !== 'ESRCH';
12
- }
13
- };
14
- const procMembers = () => {
15
- try {
16
- return fs.readdirSync('/proc').filter(p => /^\d+$/.test(p)).flatMap(pid => {
17
- try {
18
- return [procMember(fs.readFileSync(`/proc/${pid}/stat`, 'utf8'))];
19
- }
20
- catch (e) {
21
- return e.code === 'ENOENT' || e.code === 'ESRCH' ? [] : [null];
22
- }
23
- });
24
- }
25
- catch {
26
- return null;
27
- }
28
- };
29
- const psMembers = () => {
30
- const result = spawnSync('ps', ['-A', '-o', 'pgid=,stat='], { encoding: 'utf8', timeout: 1000 });
31
- return result.status === 0 ? result.stdout.split('\n').filter(line => line.trim()).map(psMember) : null;
32
- };
33
- export const groupAlive = (group) => {
34
- if (!exists(group))
35
- return false;
36
- const proc = process.platform === 'linux' ? procMembers() : null;
37
- const known = proc && groupRunning(group, proc);
38
- if (known !== null)
39
- return known;
40
- const rows = psMembers(), observed = rows && groupRunning(group, rows);
41
- return observed ?? exists(group);
42
- };
43
- //# sourceMappingURL=groups.js.map
@@ -1,80 +0,0 @@
1
- // host-posix launch: an isolated shell turn settles its group before its result, as the watcher did before this
2
- // adapter. Detached argv launches leave the caller's event loop. Only this module knows POSIX group signals.
3
- import { spawn } from 'node:child_process';
4
- import { sleep } from '../../lib/index.js';
5
- import { groupAlive } from './groups.js';
6
- const GRACE = 5000;
7
- const signalGroup = (pid, sig) => {
8
- if (pid)
9
- try {
10
- process.kill(-pid, sig);
11
- }
12
- catch { }
13
- };
14
- const detachedSettlement = async (pid) => {
15
- while (pid && groupAlive(pid))
16
- await new Promise(resolve => { setTimeout(resolve, 50).unref(); });
17
- };
18
- const settle = async (pid) => {
19
- if (!pid)
20
- return;
21
- signalGroup(pid, 'SIGTERM');
22
- const until = Date.now() + GRACE;
23
- while (groupAlive(pid) && Date.now() < until)
24
- await sleep(50);
25
- if (groupAlive(pid))
26
- signalGroup(pid, 'SIGKILL');
27
- while (groupAlive(pid))
28
- await sleep(50);
29
- };
30
- const detached = (r, clock) => {
31
- const at = clock.wall(), child = spawn(r.file, [...r.args], { stdio: 'ignore', env: r.env, detached: true });
32
- let finished = false;
33
- const done = new Promise((resolve, reject) => {
34
- child.once('error', e => { finished = true; reject(e); });
35
- child.once('exit', (code, signal) => {
36
- void detachedSettlement(child.pid).then(() => {
37
- finished = true;
38
- resolve({ code, signal, timedOut: false, seconds: Math.round((clock.wall() - at) / 1000) });
39
- }, reject);
40
- });
41
- });
42
- child.unref();
43
- // Fire-and-forget launches still handle spawn failures without an unhandled rejection.
44
- void done.catch(() => { });
45
- return { done, stop: () => { if (!finished)
46
- signalGroup(child.pid, 'SIGTERM'); } };
47
- };
48
- const shell = (r, clock) => {
49
- const at = clock.wall(), child = spawn('sh', ['-c', r.shell], { stdio: 'inherit', env: r.env, detached: true });
50
- let timedOut = false, finished = false;
51
- const stop = () => { if (!finished)
52
- signalGroup(child.pid, 'SIGTERM'); };
53
- const done = new Promise((resolve, reject) => {
54
- let hard;
55
- const timer = r.timeout ? setTimeout(() => {
56
- timedOut = true;
57
- signalGroup(child.pid, 'SIGTERM');
58
- hard = setTimeout(() => signalGroup(child.pid, 'SIGKILL'), GRACE);
59
- }, r.timeout * 1000) : undefined;
60
- const cleanup = () => {
61
- clearTimeout(timer);
62
- clearTimeout(hard);
63
- process.removeListener('SIGINT', stop);
64
- process.removeListener('SIGTERM', stop);
65
- };
66
- process.once('SIGINT', stop);
67
- process.once('SIGTERM', stop);
68
- child.once('error', e => { finished = true; cleanup(); reject(e); });
69
- child.once('exit', (code, signal) => {
70
- cleanup();
71
- void settle(child.pid).then(() => {
72
- finished = true;
73
- resolve({ code, signal, timedOut, seconds: Math.round((clock.wall() - at) / 1000) });
74
- }, reject);
75
- });
76
- });
77
- return { done, stop };
78
- };
79
- export const launch = (request, clock) => 'shell' in request ? shell(request, clock) : detached(request, clock);
80
- //# sourceMappingURL=launch.js.map
@@ -1,66 +0,0 @@
1
- // host-posix probes: process existence, ancestry and CPU samples on macOS/Linux. Unavailable CPU probes stay null.
2
- import { spawnSync } from 'node:child_process';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { procStat, seconds } from './stats.js';
6
- export const supported = process.platform === 'darwin' || process.platform === 'linux';
7
- export const alive = (pid) => {
8
- try {
9
- process.kill(pid, 0);
10
- return true;
11
- }
12
- catch (e) {
13
- return e.code === 'EPERM';
14
- }
15
- };
16
- const proc = () => {
17
- let pids;
18
- try {
19
- pids = fs.readdirSync('/proc').filter(d => /^\d+$/.test(d));
20
- }
21
- catch {
22
- return null;
23
- }
24
- const rows = new Map();
25
- for (const pid of pids) {
26
- try {
27
- const row = procStat(fs.readFileSync(`/proc/${pid}/stat`, 'utf8'));
28
- if (row)
29
- rows.set(Number(pid), row);
30
- }
31
- catch { /* the process ended meanwhile */ }
32
- }
33
- return rows.size ? rows : null;
34
- };
35
- export const snapshot = () => {
36
- if (!supported)
37
- return null;
38
- if (process.platform === 'linux') {
39
- const rows = proc();
40
- if (rows)
41
- return rows;
42
- }
43
- const r = spawnSync('ps', ['-A', '-o', 'pid=,ppid=,time='], { encoding: 'utf8', timeout: 10000 });
44
- if (r.status !== 0)
45
- return null;
46
- const rows = new Map();
47
- for (const line of r.stdout.split('\n')) {
48
- const [pid, ppid, time] = line.trim().split(/\s+/);
49
- if (pid && time)
50
- rows.set(Number(pid), { ppid: Number(ppid), cpu: seconds(time) });
51
- }
52
- return rows;
53
- };
54
- export const ancestors = (first) => {
55
- const result = [];
56
- for (let pid = first, i = 0; i < 12 && pid > 1; i++) {
57
- const r = spawnSync('ps', ['-o', 'ppid=,comm=', '-p', String(pid)], { encoding: 'utf8' });
58
- const m = r.status === 0 ? /^\s*(\d+)\s+(.*)$/.exec(String(r.stdout ?? '').trim()) : null;
59
- if (!m)
60
- break;
61
- result.push({ pid, name: path.basename(m[2].trim()).toLowerCase() });
62
- pid = Number(m[1]);
63
- }
64
- return result;
65
- };
66
- //# sourceMappingURL=probes.js.map
@@ -1,27 +0,0 @@
1
- // host-posix stats: parsing and folding of process CPU samples; no probes, files or platform selection.
2
- // Cumulative CPU time: [DD-][HH:]MM:SS[.ss].
3
- export const seconds = (time) => {
4
- const [days, rest] = time.includes('-') ? [Number(time.split('-')[0]), time.split('-')[1]] : [0, time];
5
- return days * 86400 + rest.split(':').reduce((acc, part) => acc * 60 + Number(part), 0);
6
- };
7
- // A parenthesized command may itself contain spaces or parentheses; fields follow its last closing parenthesis.
8
- export const procStat = (line) => {
9
- const f = line.slice(line.lastIndexOf(')') + 2).split(' ');
10
- const ppid = Number(f[1]), cpu = (Number(f[11]) + Number(f[12])) / 100;
11
- return Number.isFinite(ppid) && Number.isFinite(cpu) ? { ppid, cpu } : null;
12
- };
13
- export const treeCpu = (pid, rows) => {
14
- if (!rows?.has(pid))
15
- return null;
16
- const children = new Map();
17
- for (const [p, { ppid }] of rows)
18
- children.set(ppid, [...children.get(ppid) ?? [], p]);
19
- let sum = 0;
20
- for (const stack = [pid]; stack.length;) {
21
- const p = stack.pop();
22
- sum += rows.get(p)?.cpu ?? 0;
23
- stack.push(...children.get(p) ?? []);
24
- }
25
- return sum;
26
- };
27
- //# sourceMappingURL=stats.js.map
@@ -1,4 +0,0 @@
1
- import { fail } from '../../lib/index.js';
2
- const planned = (d) => fail(`hub ${d.name}: the kafka store is planned and not implemented in this ringi`);
3
- export const kafka = { layout: 'kafka/1', open: (_at, d) => planned(d), create: (_at, d) => planned(d) };
4
- //# sourceMappingURL=index.js.map
@@ -1,4 +0,0 @@
1
- import { fail } from '../../lib/index.js';
2
- const planned = (d) => fail(`hub ${d.name}: the temporal store is planned and not implemented in this ringi`);
3
- export const temporal = { layout: 'temporal/1', open: (_at, d) => planned(d), create: (_at, d) => planned(d) };
4
- //# sourceMappingURL=index.js.map
@@ -1,23 +0,0 @@
1
- // room-lifecycle: `ringi room archive | delete | rebase-contract`.
2
- import * as Rooms from '../../../core/hub/usecases/rooms.js';
3
- import { fail, short } from '../../../lib/index.js';
4
- import { flag, opt, out } from '../args.js';
5
- export const archiveRoom = (H, arg, o) => {
6
- // Without an id, the room of the current context.
7
- const R = Rooms.roomIn(H, arg ?? opt(o, 'room'));
8
- const name = Rooms.archive(H, R);
9
- return out(`archived ${R.name} as ${name}: read-only, wakes nobody; its sessions end. Read it with --room ${name}`);
10
- };
11
- export const deleteRoom = (H, arg, o) => {
12
- const R = Rooms.roomIn(H, arg ?? opt(o, 'room'));
13
- if (!flag(o, 'yes'))
14
- fail(`deleting ${R.name} in hub ${H.name} erases it and everything kept for it, for good. Run again with --yes, or archive it instead`);
15
- Rooms.erase(H, R);
16
- return out(`deleted room ${R.name}: its branch, signals, pins, evidence and readers' state. Sessions bound to it leave it on their next turn`);
17
- };
18
- export const rebaseRoomContract = (H, arg, o) => {
19
- const R = Rooms.roomIn(H, arg ?? fail('usage: ringi room rebase-contract <id>'));
20
- Rooms.rebase(H, R);
21
- return out(`room ${R.name} now follows the hub contract at ${short(H.main)} (${H.contract.version})`);
22
- };
23
- //# sourceMappingURL=room-lifecycle.js.map
@@ -1,27 +0,0 @@
1
- // room-list: `ringi room list | create | switch`.
2
- import { roomsActive } from '../../../core/agents/overview.js';
3
- import * as Rooms from '../../../core/hub/usecases/rooms.js';
4
- import { fail, short } from '../../../lib/index.js';
5
- import { flag, opt, out } from '../args.js';
6
- export const listRoom = (H, arg, o) => {
7
- const rs = roomsActive(H, { archived: flag(o, 'archived') });
8
- for (const r of rs.filter(r => !r.archived))
9
- out(`${r.current ? '*' : ' '} ${r.name.padEnd(16)} ${r.members} member(s), ${r.active} active session(s), profile ${r.profile} genesis ${short(r.genesis)}`);
10
- for (const r of rs.filter(r => r.archived))
11
- out(` ${r.name.padEnd(16)} archived, read-only`);
12
- if (!rs.length && !flag(o, 'archived'))
13
- out(`no rooms in hub ${H.name}: ringi room create <id>`);
14
- return;
15
- };
16
- export const createRoom = (H, arg, o) => {
17
- const quorum = opt(o, 'quorum');
18
- const r = Rooms.create(H, arg ?? '', { profile: opt(o, 'profile'), quorum: quorum === undefined ? undefined : Number(quorum) });
19
- if (quorum !== undefined)
20
- return out(`created room ${arg} in hub ${H.name} with profile ${r.profile}; it is the current room. Its work starts by itself at a quorum of ${quorum} agent(s): in each chat that should take part, say "join ${arg} as <id>"`);
21
- return out(`created room ${arg} in hub ${H.name} with profile ${r.profile}; it is the current room. In each chat that should take part, say: "join ${arg} as <id>; <what to accept>"`);
22
- };
23
- export const switchRoom = (H, arg, o) => {
24
- const R = Rooms.use(H, arg ?? fail('usage: ringi room switch <id>'));
25
- return out(`current room: ${H.name}/${R.name}; agents keep their own rooms`);
26
- };
27
- //# sourceMappingURL=room-list.js.map
@@ -1,15 +0,0 @@
1
- // room-members: `ringi room admit | remove`.
2
- import * as Rooms from '../../../core/hub/usecases/rooms.js';
3
- import { fail } from '../../../lib/index.js';
4
- import { opt, out } from '../args.js';
5
- export const admitRoom = (H, arg, o) => {
6
- const R = Rooms.roomIn(H, opt(o, 'room'));
7
- Rooms.admit(H, R, arg ?? fail('usage: ringi room admit <agent> <public key|file>'), o._[2] ?? fail('usage: ringi room admit <agent> <public key|file>'));
8
- return out(`admitted ${arg} to ${H.name}/${R.name}: its signed messages are accepted from now on; it can join`);
9
- };
10
- export const removeRoom = (H, arg, o) => {
11
- const R = Rooms.roomIn(H, opt(o, 'room'));
12
- Rooms.remove(H, R, arg ?? fail('usage: ringi room remove <agent>'));
13
- return out(`removed ${arg} from ${R.name}: it can no longer write or be woken there; returning needs a fresh join`);
14
- };
15
- //# sourceMappingURL=room-members.js.map
@@ -1,15 +0,0 @@
1
- // watch: the headless watcher the operator starts for an agent's seat (`ringi watch <room>/<agent> --exec …`).
2
- import { watch } from '../../../core/agents/sessions/agent.js';
3
- import { fail, words } from '../../../lib/index.js';
4
- import { flag, opt, out } from '../args.js';
5
- const numberOption = (o, k) => opt(o, k) === undefined ? undefined : Number(opt(o, k));
6
- export const watchCommand = async (o) => {
7
- process.exitCode = await watch({
8
- seat: o._[0] ?? fail('usage: ringi watch <room>/<agent> --exec <cmd> [--scope <text>] [--once] [--require-grant] …'),
9
- exec: opt(o, 'exec') ?? fail('--exec <cmd> is required: the command that starts a headless turn'),
10
- hub: opt(o, 'hub'), scope: opt(o, 'scope'), once: flag(o, 'once'), requireGrant: flag(o, 'require-grant'), handoff: flag(o, 'handoff'),
11
- interval: numberOption(o, 'interval'), from: opt(o, 'from') ? words(opt(o, 'from')) : undefined, maxHop: numberOption(o, 'max-hop'),
12
- maxRuns: numberOption(o, 'max-runs'), window: numberOption(o, 'window')
13
- }, out);
14
- };
15
- //# sourceMappingURL=watch.js.map
@@ -1,50 +0,0 @@
1
- // budget: `propose`, `stamp`, `decide`, `proposals`, `grants`.
2
- import * as Budget from '../../../core/hub/usecases/budget.js';
3
- import { fail, short, words } from '../../../lib/index.js';
4
- import { attachments, dump, flag, list, opt, out, textOf } from '../args.js';
5
- // --- decisions and budgets ---
6
- export const propose = (a, o) => {
7
- const decider = opt(o, 'decider') ?? fail('--decider <id> is required: who decides (operator, or someone with authority in the hub contract)');
8
- const r = Budget.propose(a, {
9
- text: textOf(o), decider, reviewers: words(opt(o, 'reviewers')), budget: opt(o, 'budget'), due: opt(o, 'due'),
10
- supersedes: opt(o, 'supersedes'), files: list(o, 'attach').flatMap(attachments)
11
- });
12
- out(`proposed ${short(r.id)} to ${r.to.join(', ') || 'the room'}; decider ${decider}${r.budget ? `, budget ${Budget.budgetText(r.budget)}` : ''}`);
13
- };
14
- export const stamp_ = (a, o) => {
15
- const s = o._[1] ?? '';
16
- if (!Budget.STAMPS.includes(s))
17
- fail(`usage: stamp <proposal> ${Budget.STAMPS.join('|')} -m <reason>`);
18
- const r = Budget.stamp(a, o._[0] ?? fail('name the proposal'), s, textOf(o));
19
- out(`stamped ${short(r.proposal.id)} ${s}: ${short(r.id)}`);
20
- };
21
- export const decide = (a, o) => {
22
- const d = o._[1] ?? '';
23
- if (!Budget.DECISIONS.includes(d))
24
- fail(`usage: decide <proposal> ${Budget.DECISIONS.join('|')} -m <reason>`);
25
- const r = Budget.decide(a, o._[0] ?? fail('name the proposal'), d, textOf(o));
26
- out(`${d} ${short(r.proposal.id)}: ${short(r.id)}${r.budget ? `; grant ${short(r.id)} with ${Budget.budgetText(r.budget)}. Work spends it with --grant ${short(r.id)}` : ''}`);
27
- };
28
- export const proposals = (a, o) => {
29
- const { proposals: ps, views } = Budget.proposals(a, { all: flag(o, 'all') });
30
- if (flag(o, 'json'))
31
- return dump(views);
32
- if (!ps.length)
33
- return out(flag(o, 'all') ? 'no proposals' : 'no open proposals (proposals --all for everything)');
34
- for (const x of ps) {
35
- const st = x.reviewers.map(r => `${r}:${x.stamps[r]?.stamp ?? '-'}`).join(' ');
36
- out(`${short(x.proposal.id)} ${x.state.padEnd(10)} ${x.proposal.from} → ${x.decider}${x.budget ? ` [${Budget.budgetText(x.budget)}]` : ''}${st ? ` ${st}` : ''} ${x.proposal.subject}`);
37
- }
38
- };
39
- export const grants = (a, o) => {
40
- const gs = Budget.grants(a);
41
- if (flag(o, 'json'))
42
- return dump(gs);
43
- if (!gs.length)
44
- return out('no grants');
45
- for (const g of gs) {
46
- const u = g.usage;
47
- out(`${short(g.grant)} ${g.revoked ? 'revoked ' : u.left ? 'active ' : 'spent '} runs ${u.runs}/${g.budget.runs}, open ${u.open}${u.uncertain ? `, uncertain ${u.uncertain}` : ''}, ${u.seconds}s used, ≤${g.budget['run-seconds']}s a run, concurrency ${g.budget.concurrency} ${g.subject}`);
48
- }
49
- };
50
- //# sourceMappingURL=budget.js.map
@@ -1,48 +0,0 @@
1
- // budgets: which groups of messages may start a turn now: within a grant's budget, or within the watcher's own run
2
- // limit when no grant covers them.
3
- import { note, short } from '../../../lib/index.js';
4
- import { reportExhausted } from './exhaustion.js';
5
- import { reserveGrant } from './grants.js';
6
- const ownRun = (c, grp, p, now) => {
7
- if (c.w.requireGrant) {
8
- for (const m of grp.msgs)
9
- note(`watch: ${short(m.id)} is outside any grant; --require-grant: not starting a turn`);
10
- return;
11
- }
12
- if (p.ownRuns.length >= c.maxRuns) {
13
- p.hold = true;
14
- note(`watch: own run budget spent (${c.maxRuns} per ${c.span}s); ${grp.msgs.length} message(s) wait`);
15
- return;
16
- }
17
- p.ownRuns = [...p.ownRuns, now];
18
- p.runs.push({ ...grp, timeout: null });
19
- };
20
- const grantedRun = ({ c, R, all, grp, r, p }) => {
21
- if (r.wait) {
22
- p.hold = true;
23
- note(`watch: ${r.why}; waiting`);
24
- return;
25
- }
26
- if (r.why) {
27
- note(`watch: ${r.why}`);
28
- reportExhausted({ c, R, all, grp, r, p });
29
- return;
30
- }
31
- p.runs.push({ ...grp, run: r.run, timeout: r.gr.budget['run-seconds'] });
32
- };
33
- export const reserveGroups = (c, R, all, groups, st) => {
34
- const now = Date.now() / 1000;
35
- const p = { runs: [], hold: false, lost: false, ownRuns: (st.runs ?? []).filter(t => t > now - c.span), exhausted: { ...st.exhausted } };
36
- for (const grp of groups.values()) {
37
- if (!grp.grant) {
38
- ownRun(c, grp, p, now);
39
- continue;
40
- }
41
- const r = reserveGrant(c, R, all, grp);
42
- if (r.lost)
43
- return { ...p, runs: [], hold: true, lost: true };
44
- grantedRun({ c, R, all, grp, r, p });
45
- }
46
- return p;
47
- };
48
- //# sourceMappingURL=budgets.js.map
@@ -1,40 +0,0 @@
1
- // dispatch: a planned turn is started through the process host, still holding the seat and a valid grant.
2
- import * as D from '../../hub/decisions/index.js';
3
- import { hubPorts, locked } from '../../hub/ports/index.js';
4
- import { fail, note, short } from '../../../lib/index.js';
5
- import { link } from '../../hub/protocol/index.js';
6
- import { loadRoomUnlocked, loadState, readerLock, saveState } from '../../hub/history/index.js';
7
- import { readSession } from '../sessions/index.js';
8
- import { agentPorts } from '../ports/index.js';
9
- const grantProblem = (c, R, run) => {
10
- if (!run.grant)
11
- return undefined;
12
- const { logs } = readerLock(R, c.me, () => loadRoomUnlocked(R, c.me));
13
- const gr = D.grantOf(link(logs), R.authorityAt, run.grant);
14
- return !gr ? 'its grant is no longer valid' : gr.revoked ? 'its grant was revoked' : undefined;
15
- };
16
- const spawnTurn = (c, run) => locked('sessions', () => {
17
- const cur = readSession(c.handle);
18
- if (!cur || cur.pid !== process.pid)
19
- return { why: 'the seat was taken over' };
20
- if (cur.state !== 'active')
21
- return { why: 'the watcher was stopped' };
22
- note(`watch: ${run.msgs.length} new${run.grant ? ` under grant ${short(run.grant)}` : ''}: ${c.cmd}`);
23
- return {
24
- done: agentPorts().host.awaitQuiescence(agentPorts().host.start({ shell: c.cmd, timeout: run.timeout, env: {
25
- ...process.env, RINGI_HOME: hubPorts().state.root, RINGI_SESSION: c.raw,
26
- RINGI_MSGS: run.msgs.map(m => m.id).join('\n'), RINGI_GRANT: run.grant ?? ''
27
- } })).then(result => result ?? fail('the process host did not settle the turn'))
28
- };
29
- });
30
- export const dispatch = (c, R, run) => locked(`grant-${R.hub.name}`, () => {
31
- const why = grantProblem(c, R, run);
32
- if (why)
33
- return { why };
34
- readerLock(R, c.me, () => {
35
- const st = loadState(R, c.me);
36
- saveState(R, c.me, { ...st, inflight: { seen: st.seen ?? {} } });
37
- });
38
- return spawnTurn(c, run);
39
- });
40
- //# sourceMappingURL=dispatch.js.map
@@ -1,16 +0,0 @@
1
- // exhaustion: a piece of work whose grant is spent or revoked waits for a new grant, said once in its thread.
2
- import { isOpen, taskOf } from '../../hub/work/index.js';
3
- import { OPERATOR, append } from '../../hub/rooms/index.js';
4
- import { compose } from '../../hub/protocol/index.js';
5
- export const reportExhausted = ({ c, R, all, grp, r, p }) => {
6
- const key = `${grp.task?.id}/${grp.grant}`;
7
- if (!r.exhausted || !grp.task || p.exhausted[key])
8
- return;
9
- p.exhausted[key] = true;
10
- const t = taskOf(all, grp.task, R.profile), last = grp.msgs.at(-1);
11
- if (isOpen(t, R.profile))
12
- append(R, c.me, compose(`${r.why}; waiting for a new grant`, [
13
- ['To', [...new Set([t.requester, OPERATOR])].join(', ')], ['Re', last.id], ['State', R.profile.waiting], ['Hop', String(last.hopEff + 1)]
14
- ]));
15
- };
16
- //# sourceMappingURL=exhaustion.js.map
@@ -1,36 +0,0 @@
1
- // grants: a run reserved under a grant: approved, not revoked, not spent, within its concurrency.
2
- import * as D from '../../hub/decisions/index.js';
3
- import { OPERATOR, append } from '../../hub/rooms/index.js';
4
- import { short } from '../../../lib/index.js';
5
- import { compose } from '../../hub/protocol/index.js';
6
- import { readSession } from '../sessions/index.js';
7
- const grantStatus = (gr) => {
8
- if (gr.revoked)
9
- return { why: `grant ${short(gr.id)} was revoked`, exhausted: true, gr };
10
- return { gr };
11
- };
12
- const remaining = (all, gr) => {
13
- const u = D.usageOf(all, gr);
14
- if (u.left <= 0)
15
- return { why: `grant ${short(gr.id)} is spent: ${u.runs}/${gr.budget.runs} runs`, exhausted: true, gr };
16
- if (u.open >= gr.budget.concurrency)
17
- return { why: `grant ${short(gr.id)} has ${u.open} run(s) open, concurrency ${gr.budget.concurrency}`, wait: true };
18
- return { gr };
19
- };
20
- export const reserveGrant = (c, R, all, grp) => {
21
- if (readSession(c.handle)?.pid !== process.pid)
22
- return { why: 'this watcher no longer holds the seat', lost: true };
23
- const gr = D.grantOf(all, R.authorityAt, grp.grant);
24
- if (!gr)
25
- return { why: `grant ${short(grp.grant)} is not an approved decision with a budget` };
26
- const status = grantStatus(gr);
27
- if (status.why)
28
- return status;
29
- const balance = remaining(all, gr);
30
- if (balance.why)
31
- return balance;
32
- const run = `${c.raw}.${process.pid}.${Date.now().toString(36)}.${c.runSeq++}`;
33
- append(R, c.me, compose(`usage: reserve a run of ${c.me}`, [['To', OPERATOR], ['Kind', 'usage'], ['Grant', gr.id], ['Usage', 'reserve'], ['Run', run]]));
34
- return { gr, run };
35
- };
36
- //# sourceMappingURL=grants.js.map
@@ -1,33 +0,0 @@
1
- // turns: the headless watcher: it holds one agent's seat, wakes a command for what arrives, and charges only its own
2
- // reservations and receipts.
3
- import { note, sleep } from '../../../lib/index.js';
4
- import { planTurns } from './plan.js';
5
- import { pollWatcher } from './poll.js';
6
- import { runTurns } from './results.js';
7
- import { createWatcher } from './seat.js';
8
- export const watch = async (w, log = note) => {
9
- const c = createWatcher(w, log);
10
- for (;;) {
11
- const done = await watchTick(c);
12
- if (done !== undefined)
13
- return done;
14
- await sleep(c.interval);
15
- }
16
- };
17
- const watchTick = async (c) => {
18
- const poll = pollWatcher(c);
19
- if (poll.done)
20
- return 0;
21
- if (poll.R) {
22
- const plan = planTurns(c, poll.R);
23
- if (plan.lost) {
24
- c.log(`watch: the seat of ${c.me} was taken over; stopping`);
25
- return 0;
26
- }
27
- const exitCode = await runTurns(c, poll.R, plan.runs);
28
- if (c.w.once)
29
- return exitCode || (plan.hold ? 4 : 0);
30
- }
31
- return undefined;
32
- };
33
- //# sourceMappingURL=index.js.map
@@ -1,11 +0,0 @@
1
- // limits: the watcher's options checked before it starts.
2
- import { fail } from '../../../lib/index.js';
3
- export const validateWatch = (w) => {
4
- for (const [name, value] of [['interval', w.interval], ['window', w.window]])
5
- if (value !== undefined && (!Number.isFinite(value) || value <= 0))
6
- fail(`watch ${name} must be positive seconds`);
7
- for (const [name, value] of [['max-runs', w.maxRuns], ['max-hop', w.maxHop]])
8
- if (value !== undefined && (!Number.isSafeInteger(value) || value < 0))
9
- fail(`watch ${name} must be a nonnegative integer`);
10
- };
11
- //# sourceMappingURL=limits.js.map