@astrosheep/square 0.3.77 → 0.3.79

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 (76) hide show
  1. package/dist/attention-presentation.d.ts +3 -1
  2. package/dist/attention-presentation.js +45 -13
  3. package/dist/automatic-session.js +1 -1
  4. package/dist/boundary-presentation.js +4 -6
  5. package/dist/claude-mod.js +1 -1
  6. package/dist/cli/catch-presentation.d.ts +2 -2
  7. package/dist/cli/catch-presentation.js +3 -3
  8. package/dist/cli/context.d.ts +11 -1
  9. package/dist/cli/context.js +14 -3
  10. package/dist/cli/express-presentation.d.ts +6 -5
  11. package/dist/cli/express-presentation.js +35 -30
  12. package/dist/cli/maintenance-commands.js +8 -8
  13. package/dist/cli/mcp-server-command.js +1 -1
  14. package/dist/cli/observation-commands.d.ts +4 -4
  15. package/dist/cli/observation-commands.js +20 -16
  16. package/dist/cli/program.d.ts +1 -1
  17. package/dist/cli/program.js +13 -7
  18. package/dist/cli/square-commands.js +35 -23
  19. package/dist/decisions.d.ts +9 -4
  20. package/dist/decisions.js +17 -8
  21. package/dist/delivery.d.ts +1 -1
  22. package/dist/help.js +15 -2
  23. package/dist/host-ledger-migration.js +2 -6
  24. package/dist/host-ledger-sqlite.js +2 -2
  25. package/dist/inbox.js +3 -3
  26. package/dist/index.d.ts +1 -2
  27. package/dist/index.js +1 -2
  28. package/dist/ledger-maintenance.d.ts +1 -1
  29. package/dist/ledger-maintenance.js +1 -1
  30. package/dist/list.d.ts +3 -3
  31. package/dist/list.js +1 -1
  32. package/dist/mcp.d.ts +2 -2
  33. package/dist/mcp.js +12 -7
  34. package/dist/mention-parse.d.ts +2 -8
  35. package/dist/mention-parse.js +6 -9
  36. package/dist/model.d.ts +5 -1
  37. package/dist/notifications.js +24 -8
  38. package/dist/participant-host.js +5 -0
  39. package/dist/plugins/opencode/index.js +1 -1
  40. package/dist/square-actions.d.ts +22 -9
  41. package/dist/square-actions.js +27 -19
  42. package/dist/square-api.d.ts +43 -0
  43. package/dist/square-api.js +471 -0
  44. package/dist/square-facade.d.ts +124 -203
  45. package/dist/square-sqlite.d.ts +2 -8
  46. package/dist/square-sqlite.js +3 -11
  47. package/dist/square-tools.d.ts +4 -3
  48. package/dist/square-tools.js +22 -16
  49. package/dist/stream.d.ts +2 -2
  50. package/dist/views.d.ts +16 -12
  51. package/dist/views.js +13 -27
  52. package/guides/application-demand-optimization.md +5 -0
  53. package/guides/application-facade-delivery-evidence.md +6 -1
  54. package/guides/claude-native.md +3 -1
  55. package/guides/mcp-connection-lifetime.md +2 -2
  56. package/guides/mcp.md +1 -1
  57. package/guides/migration.md +2 -1
  58. package/guides/operation-cancellation.md +2 -0
  59. package/guides/primitive-catch-consolidation.md +5 -0
  60. package/guides/primitive-history-consolidation.md +5 -0
  61. package/guides/primitive-status-consolidation.md +5 -0
  62. package/guides/primitive-storage-consolidation.md +5 -0
  63. package/guides/row-storage-design.md +2 -2
  64. package/guides/square-api.md +107 -0
  65. package/package.json +1 -1
  66. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  67. package/plugins/claude/skills/square/SKILL.md +3 -3
  68. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  69. package/plugins/opencode/index.ts +1 -1
  70. package/plugins/paseo/client/markdown.tsx +16 -6
  71. package/plugins/pi/square-pi.js +70 -30
  72. package/skills/square/SKILL.md +3 -3
  73. package/dist/square-application.d.ts +0 -38
  74. package/dist/square-application.js +0 -683
  75. package/guides/application-boundary.md +0 -32
  76. package/guides/application-facade-design.md +0 -98
@@ -1,14 +1,15 @@
1
1
  import path from 'node:path';
2
- import { Text } from '@earendil-works/pi-tui';
2
+ import { Container, Markdown, Spacer, Text } from '@earendil-works/pi-tui';
3
3
  import { z } from 'zod/v4';
4
4
 
5
- import { createSquareApplication } from '../../dist/square-application.js';
5
+ import { Square } from '../../dist/square-api.js';
6
6
  import { SQUARE_TOOLS, SQUARE_TOOL_INSTRUCTIONS, squareToolFailure } from '../../dist/square-tools.js';
7
7
 
8
8
  import { presentPendingAtBoundary, renderPendingAtBoundary } from '../../dist/boundary-presentation.js';
9
9
  import { automaticSessionEnd, automaticSessionStart, operationEnv } from '../../dist/automatic-session.js';
10
10
  import { sessionInbox, observeSessionPending } from '../../dist/inbox.js';
11
11
  import { previewAttentionBody, renderAttentionDescription, renderAttentionFull } from '../../dist/attention-presentation.js';
12
+ import { formatActivityId } from '../../dist/square-core.js';
12
13
  import { createPiReceiver, sendPiMessage } from '../../dist/packages/agent-delivery/src/pi.js';
13
14
 
14
15
  class PiDeliveryDroppedError extends Error {
@@ -36,15 +37,17 @@ function framePiMessage(content) {
36
37
  return `\n${content.replace(/^\n+/, '').replace(/\n+$/, '')}\n`;
37
38
  }
38
39
 
39
- /** Renderer-only summary and full text; Pi never sends `details` to the model. */
40
+ /** Renderer-only card facts for Pi and Paseo; Pi never sends `details` to the model. */
40
41
  export function pendingCardDetails(pending) {
41
42
  const items = pending.flatMap((membership) => membership.notifications.map((note) => ({
42
43
  square: path.basename(membership.squarePath, '.square'),
43
44
  actor: note.actor,
44
45
  recipient: membership.name,
45
46
  route: note.route,
47
+ act: formatActivityId(note.actIndex),
46
48
  preview: previewAttentionBody(note.body),
47
- description: renderAttentionDescription({ actor: note.actor, recipient: membership.name, route: note.route }),
49
+ description: renderAttentionDescription({ actor: note.actor, route: note.route }),
50
+ body: note.body,
48
51
  })));
49
52
  if (items.length === 0) return undefined;
50
53
  const fullText = pending.flatMap((membership) => membership.notifications.map((note) => renderAttentionFull({
@@ -73,31 +76,67 @@ function fitColumns(text, columns) {
73
76
  return `${out}…`;
74
77
  }
75
78
 
79
+ const fg = (theme, color, text) => theme.fg?.(color, text) ?? text;
80
+ const style = (theme, name) => (text) => theme[name]?.(text) ?? text;
81
+
82
+ function markdownTheme(theme) {
83
+ const color = (name) => (text) => fg(theme, name, text);
84
+ return {
85
+ heading: color('mdHeading'), link: color('mdLink'), linkUrl: color('mdLinkUrl'), code: color('mdCode'),
86
+ codeBlock: color('mdCodeBlock'), codeBlockBorder: color('mdCodeBlockBorder'), quote: color('mdQuote'),
87
+ quoteBorder: color('mdQuoteBorder'), hr: color('mdHr'), listBullet: color('mdListBullet'),
88
+ bold: style(theme, 'bold'), italic: style(theme, 'italic'), underline: style(theme, 'underline'),
89
+ strikethrough: style(theme, 'strikethrough'),
90
+ };
91
+ }
92
+
93
+ /** One styled line that never exceeds the width; truncated lines stay unstyled so escapes are never cut. */
94
+ function fitLine(parts, width) {
95
+ const plain = parts.map(([text]) => text).join('');
96
+ return widthOf(plain) <= width ? parts.map(([text, paint]) => paint(text)).join('') : fitColumns(plain, width);
97
+ }
98
+
76
99
  /**
77
- * Collapsed: one line naming who reached you and where. Expanded: the complete
78
- * notification text from renderer details, wrapped by Pi's terminal component.
100
+ * Collapsed: who reached you and where, then the first line of what they said.
101
+ * Expanded: each activity as a heading line and its Markdown body; the model's
102
+ * framing and continuation hints are not for human eyes.
79
103
  */
80
104
  export function renderSquareCard(message, { expanded, outputPad = 1 }, theme) {
81
- if (expanded) {
82
- return typeof message.details?.fullText === 'string'
83
- ? new Text(message.details.fullText, outputPad, 0)
84
- : undefined;
85
- }
86
105
  const items = message.details?.items;
87
- if (!Array.isArray(items) || items.length === 0) return undefined;
88
- const [first] = items;
89
- const tail = ` · ${first.square}${items.length > 1 ? ` +${items.length - 1}` : ''}`;
90
- return {
91
- invalidate() {},
92
- render(width) {
93
- const room = Math.max(1, width - outputPad * 2 - 2);
94
- // Style only an untruncated line, so escape codes never count toward or get cut by the width.
95
- const line = widthOf(first.description + tail) <= room
96
- ? `${first.description}${theme.fg('dim', tail)}`
97
- : fitColumns(first.description + tail, room);
98
- return [`${' '.repeat(outputPad)}${theme.fg('customMessageLabel', '■')} ${line}`];
99
- },
100
- };
106
+ if (!Array.isArray(items) || items.length === 0 || items.some((item) => typeof item.body !== 'string')) return undefined;
107
+ const pad = ' '.repeat(outputPad);
108
+ const dim = (text) => fg(theme, 'dim', text);
109
+ if (!expanded) {
110
+ const [first] = items;
111
+ const more = items.length > 1 ? ` +${items.length - 1}` : '';
112
+ // A glance, not a render: drop the commonest inline markers so the line reads as speech.
113
+ const opening = (first.body.split('\n').find((line) => line.trim() !== '') ?? '')
114
+ .trim().replace(/^(#{1,6}|>|[-*+])\s+/, '').replace(/\*\*|__|`/g, '');
115
+ return {
116
+ invalidate() {},
117
+ render(width) {
118
+ const room = Math.max(1, width - outputPad * 2 - 2);
119
+ return [
120
+ `${pad}${fg(theme, 'customMessageLabel', '■')} ${fitLine([[first.description, (t) => t], [` · ${first.square} · ${first.recipient}${more}`, dim]], room)}`,
121
+ ...(opening ? [`${pad} ${fitLine([[opening, dim]], room)}`] : []),
122
+ ];
123
+ },
124
+ };
125
+ }
126
+ const card = new Container();
127
+ for (const [index, item] of items.entries()) {
128
+ if (index > 0) card.addChild(new Spacer(1));
129
+ card.addChild({
130
+ invalidate() {},
131
+ render(width) {
132
+ const room = Math.max(1, width - outputPad * 2 - 2);
133
+ return [`${pad}${fg(theme, 'customMessageLabel', '●')} ${fitLine([[item.description, (t) => t], [` ${item.square} · ${item.recipient} · ${item.act}`, dim]], room)}`];
134
+ },
135
+ });
136
+ card.addChild(new Spacer(1));
137
+ card.addChild(new Markdown(item.body, outputPad + 2, 0, markdownTheme(theme)));
138
+ }
139
+ return card;
101
140
  }
102
141
 
103
142
  export default function squarePiExtension(pi) {
@@ -112,14 +151,15 @@ export default function squarePiExtension(pi) {
112
151
  namespace: { name: 'square', description: 'Participate in a shared public square.', instructions: SQUARE_TOOL_INSTRUCTIONS },
113
152
  async execute(_id, args, signal, _onUpdate, ctx) {
114
153
  try {
115
- const app = createSquareApplication({
154
+ const square = await Square.at({
116
155
  cwd: ctx.cwd,
117
156
  env: operationEnv('pi', ctx.sessionManager.getSessionId(), process.env),
118
- squarePath: args.location,
157
+ path: args.location,
119
158
  participant: args.as,
120
- }, { presentation: false });
121
- // Without a resource owner the facade closes each call's connection, including on cancellation.
122
- const { data } = await tool.run(app, args, { signal });
159
+ }, { signal });
160
+ let data;
161
+ try { data = await tool.run(square, args, { signal }); }
162
+ finally { await square.close(); }
123
163
  return { content: [{ type: 'text', text: JSON.stringify(data) }], details: data, structuredContent: data };
124
164
  } catch (error) {
125
165
  const data = { error: squareToolFailure(error, signal) };
@@ -37,9 +37,9 @@ I disagree — the cache is the wrong layer for this.
37
37
 
38
38
  **Reach.** Every activity chooses who it is meant for:
39
39
 
40
- - **Mention** participants to address them. An `@name` in the body that matches a standing participant counts too; code spans, emails, and URLs never do. Mentioned participants hear the full body; everyone else sees you walk over to them.
41
- - **Reply** to an activity to reach its author the same way.
42
- - **Ring the bell** only when every participant needs it.
40
+ - **Mention** participants to address them. An `@name` in the body that matches a standing participant counts too; code spans, emails, and URLs never do. Unmatched names stay literal, with a notice to you. Mentioned participants hear the full body; everyone else sees you walk over to them.
41
+ - **Reply** to an activity to also reach its author, regardless of the other reach you choose.
42
+ - **Ring the bell** only when every participant needs it. Body `@names` stay literal; explicit mentions cannot combine with a bell.
43
43
  - **Land it bare** when it is meant for no one in particular. Only participants listening to you receive it.
44
44
 
45
45
  Addressing is not a secrecy boundary. Everything stays readable through `history`.
@@ -1,38 +0,0 @@
1
- import type { Activity, ExpressResult, HistoryQuery, OperationControl, Participant, ParticipantStatus, SquareApplication, SquareApplicationContext, SquareAtInput, SquareBuildInput, SquareSnapshot } from './square-facade.js';
2
- export type * from './square-facade.js';
3
- export { createSquareResourceOwner } from './open-square.js';
4
- export { formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
5
- export { CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT } from './catch-decisions.js';
6
- export { HELD_WAIT_BUDGET_MS } from './runtime.js';
7
- export { HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT } from './views.js';
8
- export { DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT } from './list.js';
9
- /** Supported SDK resource. It owns one open artifact; application operations use
10
- * the same owner functions directly, not an application -> SDK -> application chain. */
11
- export declare class Square {
12
- readonly location: string;
13
- private readonly square;
14
- private readonly transport;
15
- private constructor();
16
- static at(input: SquareAtInput, control?: OperationControl): Promise<Square>;
17
- static build(input: SquareBuildInput): Promise<Square>;
18
- static inMemory(input: Omit<SquareBuildInput, 'path'>): Square;
19
- private handle;
20
- join(name: string, control?: OperationControl): Promise<Participant>;
21
- takeover(name: string, control?: OperationControl): Promise<Participant>;
22
- doneOwnedSession(name: string, body: string, expectedEpoch: number, control?: OperationControl): Promise<ExpressResult>;
23
- implicitJoin(name: string, control?: OperationControl): Promise<{
24
- readonly state: 'joined' | 'active' | 'done';
25
- readonly participant?: Participant;
26
- }>;
27
- participants(): Promise<ParticipantStatus[]>;
28
- snapshot(control?: OperationControl): Promise<SquareSnapshot>;
29
- history(query?: HistoryQuery, control?: OperationControl): Promise<Activity[]>;
30
- recognize(env: NodeJS.ProcessEnv): Promise<Participant | null>;
31
- close(): Promise<void>;
32
- endOwnedSession(name: string, sessionId: string, expectedEpoch?: number): Promise<ExpressResult | null>;
33
- retireEndedSessionRoutes(sessionId: string): Promise<void>;
34
- }
35
- export declare function createSquareApplication(context: SquareApplicationContext): SquareApplication;
36
- export declare function createSquareApplication(context: SquareApplicationContext, demand: {
37
- readonly presentation: false;
38
- }): SquareApplication<false>;