@astrosheep/square 0.3.11 → 0.3.13

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 (127) hide show
  1. package/codex-plugin/.codex-plugin/plugin.json +1 -1
  2. package/codex-plugin/hooks/hooks.json +9 -0
  3. package/dist/activity-feed.d.ts +14 -0
  4. package/dist/activity-feed.js +5 -5
  5. package/dist/activity.d.ts +9 -0
  6. package/dist/activity.js +112 -96
  7. package/dist/artifact.d.ts +20 -0
  8. package/dist/artifact.js +317 -648
  9. package/dist/automatic-session.d.ts +5 -0
  10. package/dist/automatic-session.js +86 -0
  11. package/dist/boundary-presentation.d.ts +5 -0
  12. package/dist/boundary-presentation.js +6 -5
  13. package/dist/claude-hook.d.ts +9 -0
  14. package/dist/claude-hook.js +35 -3
  15. package/dist/cli/context.d.ts +35 -0
  16. package/dist/cli/context.js +26 -31
  17. package/dist/cli/harness-command.d.ts +28 -0
  18. package/dist/cli/harness-command.js +30 -15
  19. package/dist/cli/maintenance-commands.d.ts +7 -0
  20. package/dist/cli/maintenance-commands.js +12 -69
  21. package/dist/cli/meta-commands.d.ts +5 -0
  22. package/dist/cli/observation-commands.d.ts +20 -0
  23. package/dist/cli/observation-commands.js +159 -139
  24. package/dist/cli/program.d.ts +2 -0
  25. package/dist/cli/program.js +3 -12
  26. package/dist/cli/registry.d.ts +9 -0
  27. package/dist/cli/registry.js +2 -4
  28. package/dist/cli/square-commands.d.ts +34 -0
  29. package/dist/cli/square-commands.js +90 -84
  30. package/dist/cmd/notify-once.d.ts +2 -0
  31. package/dist/codex-hook.d.ts +10 -0
  32. package/dist/codex-hook.js +35 -3
  33. package/dist/decisions.d.ts +92 -0
  34. package/dist/decisions.js +93 -81
  35. package/dist/delivery-health.d.ts +21 -0
  36. package/dist/delivery-health.js +41 -34
  37. package/dist/delivery.d.ts +81 -0
  38. package/dist/delivery.js +71 -69
  39. package/dist/file-lock.d.ts +6 -0
  40. package/dist/harness-claude.d.ts +19 -0
  41. package/dist/harness-claude.js +8 -3
  42. package/dist/harness-codex.d.ts +29 -0
  43. package/dist/harness-codex.js +2 -2
  44. package/dist/harness-links.d.ts +17 -0
  45. package/dist/harness-links.js +2 -2
  46. package/dist/harness-pi.d.ts +11 -0
  47. package/dist/harness-pi.js +2 -2
  48. package/dist/harness-stage.d.ts +6 -0
  49. package/dist/harness.d.ts +20 -0
  50. package/dist/harness.js +5 -3
  51. package/dist/help.d.ts +6 -0
  52. package/dist/help.js +12 -13
  53. package/dist/identity.d.ts +13 -0
  54. package/dist/inbox.d.ts +2 -0
  55. package/dist/inbox.js +15 -19
  56. package/dist/index.d.ts +13 -0
  57. package/dist/index.js +31 -67
  58. package/dist/landing.d.ts +10 -0
  59. package/dist/landing.js +95 -0
  60. package/dist/list.d.ts +1 -0
  61. package/dist/list.js +39 -61
  62. package/dist/model.d.ts +147 -0
  63. package/dist/model.js +12 -8
  64. package/dist/notifications.d.ts +30 -0
  65. package/dist/notifications.js +83 -91
  66. package/dist/open-square.d.ts +11 -0
  67. package/dist/open-square.js +4 -0
  68. package/dist/participant-identity.d.ts +1 -0
  69. package/dist/participant-identity.js +3 -0
  70. package/dist/paseo-connection.d.ts +15 -0
  71. package/dist/paseo-delivery.d.ts +14 -0
  72. package/dist/paseo-state.d.ts +11 -0
  73. package/dist/paseo-timeline.d.ts +16 -0
  74. package/dist/presence.d.ts +3 -0
  75. package/dist/presence.js +42 -0
  76. package/dist/presentation.d.ts +91 -0
  77. package/dist/presentation.js +52 -63
  78. package/dist/presented.d.ts +11 -0
  79. package/dist/registry.d.ts +58 -0
  80. package/dist/registry.js +36 -3
  81. package/dist/routes.d.ts +42 -0
  82. package/dist/runtime.d.ts +45 -0
  83. package/dist/runtime.js +48 -55
  84. package/dist/search.d.ts +11 -0
  85. package/dist/square-core.d.ts +111 -0
  86. package/dist/square-core.js +63 -9
  87. package/dist/square-facade.d.ts +86 -0
  88. package/dist/square-facade.js +1 -0
  89. package/dist/square-file-adapter.d.ts +18 -0
  90. package/dist/square-file-adapter.js +70 -0
  91. package/dist/square-storage.d.ts +20 -0
  92. package/dist/square-storage.js +171 -0
  93. package/dist/square-wiring.d.ts +19 -0
  94. package/dist/square-wiring.js +70 -0
  95. package/dist/square.d.ts +2 -0
  96. package/dist/state-cell.d.ts +14 -0
  97. package/dist/state-cell.js +1 -0
  98. package/dist/stream.d.ts +3 -0
  99. package/dist/stream.js +19 -23
  100. package/dist/time.d.ts +6 -0
  101. package/dist/views.d.ts +95 -0
  102. package/dist/views.js +81 -0
  103. package/dist/wake-attempts.d.ts +39 -0
  104. package/dist/wake-attempts.js +8 -4
  105. package/dist/wake-evidence.d.ts +12 -0
  106. package/dist/wake-evidence.js +7 -10
  107. package/dist/wake-port.d.ts +20 -0
  108. package/dist/wake-sink.d.ts +12 -0
  109. package/dist/wakes.d.ts +40 -0
  110. package/dist/wakes.js +62 -0
  111. package/dist/watch.d.ts +2 -0
  112. package/dist/watch.js +89 -210
  113. package/extensions/square-opencode.js +27 -1
  114. package/extensions/square-pi.js +13 -0
  115. package/guides/participant.md +7 -174
  116. package/package.json +5 -4
  117. package/skills/brainstorm/SKILL.md +30 -30
  118. package/skills/square/.claude-plugin/plugin.json +1 -1
  119. package/skills/square/SKILL.md +56 -29
  120. package/skills/square/hooks/hooks.json +9 -0
  121. package/skills/square-feedback/SKILL.md +9 -9
  122. package/dist/compact.js +0 -26
  123. package/dist/doctor.js +0 -36
  124. package/dist/square-application.js +0 -262
  125. package/template.md +0 -4
  126. package/templates/architect.md +0 -4
  127. package/templates/brainstorm.md +0 -4
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "square",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "description": "Shared Square activity with reliable participant attention at Codex boundaries.",
5
5
  "author": {
6
6
  "name": "Square"
@@ -1,5 +1,14 @@
1
1
  {
2
2
  "hooks": {
3
+ "SessionStart": [
4
+ { "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5 }] }
5
+ ],
6
+ "SessionResume": [
7
+ { "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5 }] }
8
+ ],
9
+ "SessionEnd": [
10
+ { "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5 }] }
11
+ ],
3
12
  "PostToolUse": [
4
13
  {
5
14
  "hooks": [
@@ -0,0 +1,14 @@
1
+ import { type StoredAct, type SquareState, type PublicAct, type RoomChangeAct } from './model.js';
2
+ export interface ActivityFeedFilter {
3
+ participants?: string[];
4
+ mention?: string;
5
+ }
6
+ export declare function actDelta(acts: StoredAct[], cursor: number): StoredAct[];
7
+ /** Public cursor changes plus directed receipts that remain pending behind it. */
8
+ export declare function deliveryDelta(squareState: SquareState, name: string): StoredAct[];
9
+ export declare function peerRoomChanges(delta: StoredAct[], name: string): RoomChangeAct[];
10
+ export declare function peerPublicActs(delta: StoredAct[], name: string): PublicAct[];
11
+ export declare function matchesFeedFilter(act: StoredAct, filter: ActivityFeedFilter): boolean;
12
+ export declare function filteredPeerActivities(delta: StoredAct[], name: string, filter: ActivityFeedFilter): PublicAct[];
13
+ export declare function filteredRoomChanges(delta: StoredAct[], name: string, filter: ActivityFeedFilter): RoomChangeAct[];
14
+ export declare function ackPeerDelta(squareState: SquareState, name: string, delta: StoredAct[], at?: number): boolean;
@@ -5,10 +5,10 @@ export function actDelta(acts, cursor) {
5
5
  return acts.filter((act) => act.index > cursor);
6
6
  }
7
7
  /** Public cursor changes plus directed receipts that remain pending behind it. */
8
- export function deliveryDelta(doc, name) {
9
- const items = actDelta(doc.acts, readCursor(doc, name));
8
+ export function deliveryDelta(squareState, name) {
9
+ const items = actDelta(squareState.acts, readCursor(squareState, name));
10
10
  const seen = new Set(items.map((act) => act.index));
11
- for (const notification of deriveDeliveryModel(doc).pendingFor(name)) {
11
+ for (const notification of deriveDeliveryModel(squareState).pendingFor(name)) {
12
12
  if (!seen.has(notification.item.index))
13
13
  items.push(notification.item);
14
14
  }
@@ -39,6 +39,6 @@ export function filteredRoomChanges(delta, name, filter) {
39
39
  return [];
40
40
  return peerRoomChanges(delta, name).filter((act) => matchesParticipants(act, filter.participants));
41
41
  }
42
- export function ackPeerDelta(doc, name, delta) {
43
- return advanceCursor(doc, name, latestActIndex([...peerPublicActs(delta, name), ...peerRoomChanges(delta, name)]));
42
+ export function ackPeerDelta(squareState, name, delta, at) {
43
+ return advanceCursor(squareState, name, latestActIndex([...peerPublicActs(delta, name), ...peerRoomChanges(delta, name)]), at);
44
44
  }
@@ -0,0 +1,9 @@
1
+ export interface ActivityOptions {
2
+ force?: boolean;
3
+ forceCommand: string;
4
+ noWait?: boolean;
5
+ reach?: import('./model.js').Reach;
6
+ reply?: number;
7
+ }
8
+ export declare function saveActivityDraft(squarePath: string, name: string, body: string): string;
9
+ export declare function cmdActivity(squarePath: string, name: string, activity: string, resolveBody: (arg: string) => string, opts: ActivityOptions): Promise<void>;
package/dist/activity.js CHANGED
@@ -2,13 +2,15 @@ import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { setTimeout as sleep } from 'node:timers/promises';
5
- import { loadSquare } from './artifact.js';
6
- import { SquareError, validateName } from './model.js';
5
+ import { SquareError, isSquareError, validateName } from './model.js';
7
6
  import { expressHintLine, renderActivityBlocked, renderActivityLimit, renderExpressNoWait, renderExpressWaiting, renderPendingFeed, withPathOutput, } from './presentation.js';
8
- import { currentHold, inSquareCount, nowMs, SLEEP_MS, resolveRosterName } from './runtime.js';
9
- import { resolveKnownName } from './decisions.js';
10
- import { dispatchActNotifications } from './notifications.js';
11
- import { execute } from './square-application.js';
7
+ import { nowMs, SLEEP_MS } from './runtime.js';
8
+ import { wakeNotifierForSquare } from './notifications.js';
9
+ import { openSquare } from './square-file-adapter.js';
10
+ import { closeOpenSquare } from './open-square.js';
11
+ import { Square } from './square-wiring.js';
12
+ import { activityPresentation, resolveParticipant } from './views.js';
13
+ import { formatActivityId } from './square-core.js';
12
14
  import { formatTimestamp } from './time.js';
13
15
  function draftDirFor(squarePath) {
14
16
  return path.join(path.dirname(squarePath), 'drafts');
@@ -40,118 +42,132 @@ export function saveActivityDraft(squarePath, name, body) {
40
42
  export async function cmdActivity(squarePath, name, activity, resolveBody, opts) {
41
43
  validateName(name);
42
44
  const rawInput = String(resolveBody(activity)).replace(/\r\n/g, '\n');
43
- let doc;
45
+ const reader = await openSquare(squarePath, { clock: nowMs });
46
+ let knownName;
44
47
  try {
45
- doc = loadSquare(squarePath);
48
+ knownName = (await resolveParticipant(reader, name)).name;
46
49
  }
47
50
  catch (err) {
48
- if (err instanceof SquareError) {
51
+ await closeOpenSquare(reader);
52
+ if (isSquareError(err)) {
53
+ if (err.code === 'unknown_participant' || err.code === 'invalid_args') {
54
+ const draftPath = saveActivityDraft(squarePath, name, rawInput);
55
+ process.stderr.write(err.message + '\n');
56
+ process.stderr.write(`draft kept: ${draftPath}\n`);
57
+ process.exit(2);
58
+ }
49
59
  process.stderr.write(err.message + '\n');
50
60
  process.exit(err.code === 'not_found' ? 1 : 2);
51
61
  }
52
62
  throw err;
53
63
  }
54
- const knownName = resolveRosterName(doc, name);
55
- if (knownName === undefined) {
56
- const draftPath = saveActivityDraft(squarePath, name, rawInput);
57
- const expected = doc.acts.filter((act) => act.kind === 'join').map((act) => act.actor);
58
- process.stderr.write(`Unknown participant "${name}". Expected one of: ${expected.join(', ')}.\n`);
59
- process.stderr.write(`draft kept: ${draftPath}\n`);
60
- process.exit(2);
61
- }
64
+ await closeOpenSquare(reader);
62
65
  const body = rawInput.trim();
63
66
  const force = opts.force ?? false;
64
67
  const noWait = opts.noWait ?? false;
65
- const reach = opts.reach === undefined
66
- ? undefined
67
- : opts.reach === 'bell'
68
- ? 'bell'
69
- : { beside: resolveKnownName(doc, opts.reach.beside) };
68
+ const reach = opts.reach === 'bell' ? 'bell' : undefined;
70
69
  let announcedWait;
71
- while (true) {
72
- const committed = await execute(squarePath, {
73
- type: 'say',
74
- name,
75
- body,
76
- force,
77
- now: nowMs(),
78
- ...(reach === undefined ? {} : { reach }),
79
- ...(opts.reply === undefined ? {} : { reply: opts.reply }),
80
- });
81
- const decision = committed.result;
82
- const freshDoc = loadSquare(squarePath);
83
- const headerCount = inSquareCount(freshDoc);
84
- const held = currentHold(freshDoc.acts).active;
85
- switch (decision.type) {
86
- case 'sent': {
87
- const sayAct = committed.acts.find((act) => act.kind === 'say');
88
- if (sayAct !== undefined)
89
- await dispatchActNotifications(squarePath, sayAct);
90
- const hasPending = decision.pendingPublic.length > 0 || decision.pendingRoomChanges.length > 0;
91
- const pending = hasPending ? `\n\n${renderPendingFeed(freshDoc.acts, decision.pendingPublic, decision.pendingRoomChanges)}` : '';
92
- const hint = expressHintLine(decision.ownActCount);
93
- const withHint = hint ? `${decision.confirmation}\n${hint}` : decision.confirmation;
70
+ const square = await Square.at({ path: squarePath, clock: nowMs, notifier: wakeNotifierForSquare(squarePath) });
71
+ try {
72
+ const participant = await square.join(name);
73
+ while (true) {
74
+ const beforeSquare = await openSquare(squarePath, { clock: nowMs });
75
+ const before = await activityPresentation(beforeSquare, knownName).finally(() => closeOpenSquare(beforeSquare));
76
+ const pendingPublic = before.pendingPublic;
77
+ const pendingRoomChanges = before.pendingRoomChanges;
78
+ try {
79
+ await participant.express(body, {
80
+ force,
81
+ ...(reach === undefined ? {} : { reach }),
82
+ ...(opts.reply === undefined ? {} : { reply: formatActivityId(opts.reply) }),
83
+ });
84
+ const freshSquare = await openSquare(squarePath, { clock: nowMs });
85
+ const fresh = await activityPresentation(freshSquare, knownName).finally(() => closeOpenSquare(freshSquare));
86
+ const headerCount = fresh.participantCount;
87
+ const held = fresh.held;
88
+ const ownActCount = fresh.ownActivityCount;
89
+ const hasPending = pendingPublic.length > 0 || pendingRoomChanges.length > 0;
90
+ const pending = hasPending ? `\n\n${renderPendingFeed([...fresh.activities], [...pendingPublic], [...pendingRoomChanges], knownName)}` : '';
91
+ const hint = expressHintLine(ownActCount);
92
+ const confirmation = `● heads turn your way — #${ownActCount}`;
93
+ const withHint = hint ? `${confirmation}\n${hint}` : confirmation;
94
94
  process.stdout.write(withPathOutput(squarePath, withHint + pending, { participantCount: headerCount, held }));
95
95
  return;
96
96
  }
97
- case 'blocked': {
98
- const draftPath = saveActivityDraft(squarePath, name, rawInput);
99
- process.stdout.write(renderActivityBlocked({
100
- squarePath,
101
- name: knownName,
102
- forceCommand: opts.forceCommand,
103
- activitySummaries: decision.activitySummaries,
104
- unreadRoomChanges: decision.unreadRoomChanges,
105
- draftPath,
106
- participantCount: headerCount,
107
- held,
108
- }));
109
- process.exit(1);
110
- break;
111
- }
112
- case 'capped': {
113
- process.stdout.write(renderActivityLimit({
114
- squarePath,
115
- name: knownName,
116
- count: decision.count,
117
- hardCap: decision.hardCap,
118
- draftPath: saveActivityDraft(squarePath, name, rawInput),
119
- participantCount: headerCount,
120
- held,
121
- }));
122
- process.exit(1);
123
- break;
124
- }
125
- case 'throttled': {
126
- if (noWait) {
97
+ catch (error) {
98
+ if (!(error instanceof SquareError))
99
+ throw error;
100
+ const freshSquare = await openSquare(squarePath, { clock: nowMs });
101
+ const fresh = await activityPresentation(freshSquare, knownName).finally(() => closeOpenSquare(freshSquare));
102
+ const headerCount = fresh.participantCount;
103
+ const held = fresh.held;
104
+ if (error.code === 'behind') {
127
105
  const draftPath = saveActivityDraft(squarePath, name, rawInput);
128
- process.stdout.write(renderExpressNoWait({ squarePath, name: knownName, reason: 'throttled', delayMs: decision.delayMs, draftPath, participantCount: headerCount, held }));
106
+ process.stdout.write(renderActivityBlocked({
107
+ squarePath,
108
+ name: knownName,
109
+ forceCommand: opts.forceCommand,
110
+ activitySummaries: [],
111
+ unreadRoomChanges: [...pendingRoomChanges],
112
+ draftPath,
113
+ participantCount: headerCount,
114
+ held,
115
+ }));
129
116
  process.exit(1);
117
+ return;
130
118
  }
131
- if (announcedWait !== 'throttled') {
132
- process.stdout.write(renderExpressWaiting({ reason: 'throttled', delayMs: decision.delayMs }) + '\n');
133
- announcedWait = 'throttled';
134
- }
135
- await sleep(decision.delayMs);
136
- break;
137
- }
138
- case 'held': {
139
- if (noWait) {
140
- const draftPath = saveActivityDraft(squarePath, name, rawInput);
141
- process.stdout.write(renderExpressNoWait({ squarePath, name: knownName, reason: 'held', holdReason: decision.reason, draftPath, participantCount: headerCount, held }));
119
+ if (error.code === 'capped') {
120
+ process.stdout.write(renderActivityLimit({
121
+ squarePath,
122
+ name: knownName,
123
+ count: fresh.ownActivityCount,
124
+ ...(fresh.hardCap === null ? {} : { hardCap: fresh.hardCap }),
125
+ draftPath: saveActivityDraft(squarePath, name, rawInput),
126
+ participantCount: headerCount,
127
+ held,
128
+ }));
142
129
  process.exit(1);
130
+ return;
143
131
  }
144
- if (announcedWait !== 'held') {
145
- process.stdout.write(renderExpressWaiting({ reason: 'held' }) + '\n');
146
- announcedWait = 'held';
132
+ if (error.code === 'throttled') {
133
+ const delayMs = error.facts?.retryAfterMs ?? SLEEP_MS;
134
+ if (noWait) {
135
+ const draftPath = saveActivityDraft(squarePath, name, rawInput);
136
+ process.stdout.write(renderExpressNoWait({ squarePath, name: knownName, reason: 'throttled', delayMs, draftPath, participantCount: headerCount, held }));
137
+ process.exit(1);
138
+ }
139
+ if (announcedWait !== 'throttled') {
140
+ process.stdout.write(renderExpressWaiting({ reason: 'throttled', delayMs }) + '\n');
141
+ announcedWait = 'throttled';
142
+ }
143
+ await sleep(delayMs);
144
+ continue;
147
145
  }
148
- await sleep(SLEEP_MS);
149
- break;
150
- }
151
- case 'bell_quota': {
152
- process.stdout.write(withPathOutput(squarePath, [`✕ the bell stays quiet for now`, ` · you can ring it again at ${formatTimestamp(decision.nextAt)}`].join('\n'), { participantCount: headerCount, held }));
153
- process.exit(1);
146
+ if (error.code === 'held') {
147
+ const holdReason = fresh.holdReason;
148
+ if (noWait) {
149
+ const draftPath = saveActivityDraft(squarePath, name, rawInput);
150
+ process.stdout.write(renderExpressNoWait({ squarePath, name: knownName, reason: 'held', holdReason, draftPath, participantCount: headerCount, held }));
151
+ process.exit(1);
152
+ }
153
+ if (announcedWait !== 'held') {
154
+ process.stdout.write(renderExpressWaiting({ reason: 'held' }) + '\n');
155
+ announcedWait = 'held';
156
+ }
157
+ await sleep(SLEEP_MS);
158
+ continue;
159
+ }
160
+ if (error.code === 'bell_quota') {
161
+ const nextAt = nowMs() + (error.facts?.retryAfterMs ?? 1);
162
+ process.stdout.write(withPathOutput(squarePath, [`✕ the bell stays quiet for now`, ` · you can ring it again at ${formatTimestamp(nextAt)}`].join('\n'), { participantCount: headerCount, held }));
163
+ process.exit(1);
164
+ return;
165
+ }
166
+ throw error;
154
167
  }
155
168
  }
156
169
  }
170
+ finally {
171
+ await square.close();
172
+ }
157
173
  }
@@ -0,0 +1,20 @@
1
+ import { type BuildOptions, type HardCap, type SquareState, type SquareRuntimeState } from './model.js';
2
+ export interface DoctorProblem {
3
+ kind: string;
4
+ message: string;
5
+ }
6
+ export interface DiagnoseResult {
7
+ unfixable?: string;
8
+ problems: DoctorProblem[];
9
+ state?: SquareState;
10
+ }
11
+ export declare function emptyRuntimeState(nextActIndex?: number): SquareRuntimeState;
12
+ export declare function createSquareState(options: BuildOptions & {
13
+ hardCap: HardCap;
14
+ }, snippet: string): SquareState;
15
+ export declare function encodeSquare(squareState: SquareState): Buffer;
16
+ export declare function decodeSquare(bytes: Buffer): SquareState;
17
+ export declare function writeSquareFile(squarePath: string, squareState: SquareState): void;
18
+ export declare function loadSquare(squarePath: string): SquareState;
19
+ export declare function probeSquare(squarePath: string): SquareState | undefined;
20
+ export declare function diagnoseSquareFile(squarePath: string): DiagnoseResult;