@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.
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/hooks/hooks.json +9 -0
- package/dist/activity-feed.d.ts +14 -0
- package/dist/activity-feed.js +5 -5
- package/dist/activity.d.ts +9 -0
- package/dist/activity.js +112 -96
- package/dist/artifact.d.ts +20 -0
- package/dist/artifact.js +317 -648
- package/dist/automatic-session.d.ts +5 -0
- package/dist/automatic-session.js +86 -0
- package/dist/boundary-presentation.d.ts +5 -0
- package/dist/boundary-presentation.js +6 -5
- package/dist/claude-hook.d.ts +9 -0
- package/dist/claude-hook.js +35 -3
- package/dist/cli/context.d.ts +35 -0
- package/dist/cli/context.js +26 -31
- package/dist/cli/harness-command.d.ts +28 -0
- package/dist/cli/harness-command.js +30 -15
- package/dist/cli/maintenance-commands.d.ts +7 -0
- package/dist/cli/maintenance-commands.js +12 -69
- package/dist/cli/meta-commands.d.ts +5 -0
- package/dist/cli/observation-commands.d.ts +20 -0
- package/dist/cli/observation-commands.js +159 -139
- package/dist/cli/program.d.ts +2 -0
- package/dist/cli/program.js +3 -12
- package/dist/cli/registry.d.ts +9 -0
- package/dist/cli/registry.js +2 -4
- package/dist/cli/square-commands.d.ts +34 -0
- package/dist/cli/square-commands.js +90 -84
- package/dist/cmd/notify-once.d.ts +2 -0
- package/dist/codex-hook.d.ts +10 -0
- package/dist/codex-hook.js +35 -3
- package/dist/decisions.d.ts +92 -0
- package/dist/decisions.js +93 -81
- package/dist/delivery-health.d.ts +21 -0
- package/dist/delivery-health.js +41 -34
- package/dist/delivery.d.ts +81 -0
- package/dist/delivery.js +71 -69
- package/dist/file-lock.d.ts +6 -0
- package/dist/harness-claude.d.ts +19 -0
- package/dist/harness-claude.js +8 -3
- package/dist/harness-codex.d.ts +29 -0
- package/dist/harness-codex.js +2 -2
- package/dist/harness-links.d.ts +17 -0
- package/dist/harness-links.js +2 -2
- package/dist/harness-pi.d.ts +11 -0
- package/dist/harness-pi.js +2 -2
- package/dist/harness-stage.d.ts +6 -0
- package/dist/harness.d.ts +20 -0
- package/dist/harness.js +5 -3
- package/dist/help.d.ts +6 -0
- package/dist/help.js +12 -13
- package/dist/identity.d.ts +13 -0
- package/dist/inbox.d.ts +2 -0
- package/dist/inbox.js +15 -19
- package/dist/index.d.ts +13 -0
- package/dist/index.js +31 -67
- package/dist/landing.d.ts +10 -0
- package/dist/landing.js +95 -0
- package/dist/list.d.ts +1 -0
- package/dist/list.js +39 -61
- package/dist/model.d.ts +147 -0
- package/dist/model.js +12 -8
- package/dist/notifications.d.ts +30 -0
- package/dist/notifications.js +83 -91
- package/dist/open-square.d.ts +11 -0
- package/dist/open-square.js +4 -0
- package/dist/participant-identity.d.ts +1 -0
- package/dist/participant-identity.js +3 -0
- package/dist/paseo-connection.d.ts +15 -0
- package/dist/paseo-delivery.d.ts +14 -0
- package/dist/paseo-state.d.ts +11 -0
- package/dist/paseo-timeline.d.ts +16 -0
- package/dist/presence.d.ts +3 -0
- package/dist/presence.js +42 -0
- package/dist/presentation.d.ts +91 -0
- package/dist/presentation.js +52 -63
- package/dist/presented.d.ts +11 -0
- package/dist/registry.d.ts +58 -0
- package/dist/registry.js +36 -3
- package/dist/routes.d.ts +42 -0
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.js +48 -55
- package/dist/search.d.ts +11 -0
- package/dist/square-core.d.ts +111 -0
- package/dist/square-core.js +63 -9
- package/dist/square-facade.d.ts +86 -0
- package/dist/square-facade.js +1 -0
- package/dist/square-file-adapter.d.ts +18 -0
- package/dist/square-file-adapter.js +70 -0
- package/dist/square-storage.d.ts +20 -0
- package/dist/square-storage.js +171 -0
- package/dist/square-wiring.d.ts +19 -0
- package/dist/square-wiring.js +70 -0
- package/dist/square.d.ts +2 -0
- package/dist/state-cell.d.ts +14 -0
- package/dist/state-cell.js +1 -0
- package/dist/stream.d.ts +3 -0
- package/dist/stream.js +19 -23
- package/dist/time.d.ts +6 -0
- package/dist/views.d.ts +95 -0
- package/dist/views.js +81 -0
- package/dist/wake-attempts.d.ts +39 -0
- package/dist/wake-attempts.js +8 -4
- package/dist/wake-evidence.d.ts +12 -0
- package/dist/wake-evidence.js +7 -10
- package/dist/wake-port.d.ts +20 -0
- package/dist/wake-sink.d.ts +12 -0
- package/dist/wakes.d.ts +40 -0
- package/dist/wakes.js +62 -0
- package/dist/watch.d.ts +2 -0
- package/dist/watch.js +89 -210
- package/extensions/square-opencode.js +27 -1
- package/extensions/square-pi.js +13 -0
- package/guides/participant.md +7 -174
- package/package.json +5 -4
- package/skills/brainstorm/SKILL.md +30 -30
- package/skills/square/.claude-plugin/plugin.json +1 -1
- package/skills/square/SKILL.md +56 -29
- package/skills/square/hooks/hooks.json +9 -0
- package/skills/square-feedback/SKILL.md +9 -9
- package/dist/compact.js +0 -26
- package/dist/doctor.js +0 -36
- package/dist/square-application.js +0 -262
- package/template.md +0 -4
- package/templates/architect.md +0 -4
- package/templates/brainstorm.md +0 -4
package/dist/delivery.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { SquareError, findParticipantName, sameName, } from './model.js';
|
|
3
|
+
import { canonicalSquarePath, localParticipantName } from './registry.js';
|
|
4
|
+
import { audienceOf, formatActivityId, resolveAudience } from './square-core.js';
|
|
5
|
+
import { actId, isCurrentlyJoined, lastJoinIndex, matchesMentionTarget, resolveRosterName, rosterNames } from './runtime.js';
|
|
3
6
|
export function notificationMessageId(squarePath, actIndex) {
|
|
4
|
-
return `square:${squarePath}
|
|
7
|
+
return `square:${squarePath}#${formatActivityId(actIndex)}`;
|
|
5
8
|
}
|
|
6
|
-
|
|
7
|
-
return
|
|
8
|
-
}
|
|
9
|
-
function canonicalRecipient(doc, name) {
|
|
10
|
-
return resolveRosterName(doc, name) ?? name;
|
|
9
|
+
function canonicalRecipient(squareState, name) {
|
|
10
|
+
return resolveRosterName(squareState, name) ?? name;
|
|
11
11
|
}
|
|
12
12
|
/** Delivery receipts are the only durable acknowledgement of directed attention. */
|
|
13
|
-
export function deliveryReceipt(
|
|
14
|
-
return deliveryReceiptFromRuntime(
|
|
13
|
+
export function deliveryReceipt(squareState, name, actOrIndex) {
|
|
14
|
+
return deliveryReceiptFromRuntime(squareState.runtime, canonicalRecipient(squareState, name), actOrIndex);
|
|
15
15
|
}
|
|
16
16
|
export function deliveryReceiptFromRuntime(runtime, recipient, actOrIndex) {
|
|
17
17
|
return runtime.deliveryReceipts[recipient]?.[actId(actOrIndex)];
|
|
18
18
|
}
|
|
19
|
-
export function isDeliveryDelivered(
|
|
20
|
-
return deliveryReceipt(
|
|
19
|
+
export function isDeliveryDelivered(squareState, name, actOrIndex) {
|
|
20
|
+
return deliveryReceipt(squareState, name, actOrIndex)?.status === 'delivered';
|
|
21
21
|
}
|
|
22
|
-
export function recordDeliveredDelivery(
|
|
23
|
-
return recordDeliveredRuntime(
|
|
22
|
+
export function recordDeliveredDelivery(squareState, name, actOrIndex, receipt) {
|
|
23
|
+
return recordDeliveredRuntime(squareState.runtime, canonicalRecipient(squareState, name), actOrIndex, receipt);
|
|
24
24
|
}
|
|
25
25
|
export function recordDeliveredRuntime(runtime, recipient, actOrIndex, receipt) {
|
|
26
26
|
const id = actId(actOrIndex);
|
|
@@ -29,47 +29,23 @@ export function recordDeliveredRuntime(runtime, recipient, actOrIndex, receipt)
|
|
|
29
29
|
(runtime.deliveryReceipts[recipient] ??= {})[id] = { status: 'delivered', ...receipt };
|
|
30
30
|
return true;
|
|
31
31
|
}
|
|
32
|
-
export function markDeliveredDelivery(
|
|
33
|
-
return recordDeliveredDelivery(
|
|
34
|
-
}
|
|
35
|
-
function uniqueKnownMentions(body, roster) {
|
|
36
|
-
const recipients = [];
|
|
37
|
-
for (const mention of extractMentions(body)) {
|
|
38
|
-
const known = findParticipantName(roster, mention);
|
|
39
|
-
if (known !== undefined && !recipients.some((recipient) => sameName(recipient, known))) {
|
|
40
|
-
recipients.push(known);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return recipients;
|
|
32
|
+
export function markDeliveredDelivery(squareState, name, actOrIndex, at = Date.now()) {
|
|
33
|
+
return recordDeliveredDelivery(squareState, name, actOrIndex, { at });
|
|
44
34
|
}
|
|
45
35
|
/**
|
|
46
|
-
* Derive delivery behavior once from the
|
|
36
|
+
* Derive delivery behavior once from the decoded Square state.
|
|
47
37
|
* All consumers share these targets instead of reinterpreting artifact text or cursor state.
|
|
48
38
|
*/
|
|
49
|
-
export function deriveDeliveryModel(
|
|
50
|
-
const roster = rosterNames(
|
|
39
|
+
export function deriveDeliveryModel(squareState) {
|
|
40
|
+
const roster = rosterNames(squareState).filter((name) => isCurrentlyJoined(squareState.acts, name));
|
|
51
41
|
let pendingByRecipient;
|
|
52
42
|
function plan(item) {
|
|
53
43
|
if (item.kind !== 'say')
|
|
54
44
|
return [];
|
|
55
45
|
const sayItem = item;
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.filter((recipient) => !sameName(recipient, actor))
|
|
60
|
-
.map((recipient) => ({ item: sayItem, recipient, route: 'bell' }));
|
|
61
|
-
}
|
|
62
|
-
if (sayItem.reach !== undefined) {
|
|
63
|
-
const recipient = findParticipantName(roster, sayItem.reach.beside);
|
|
64
|
-
return recipient === undefined || sameName(recipient, actor)
|
|
65
|
-
? []
|
|
66
|
-
: [{ item: sayItem, recipient, route: 'beside' }];
|
|
67
|
-
}
|
|
68
|
-
const mentions = uniqueKnownMentions(sayItem.body, roster).filter((recipient) => !sameName(recipient, actor));
|
|
69
|
-
const recipients = mentions.length > 0
|
|
70
|
-
? mentions
|
|
71
|
-
: roster.filter((recipient) => !sameName(recipient, actor));
|
|
72
|
-
const route = mentions.length > 0 ? 'mention' : 'broadcast';
|
|
46
|
+
const audience = audienceOf(sayItem);
|
|
47
|
+
const recipients = resolveAudience(audience, roster).filter((recipient) => !sameName(recipient, sayItem.actor));
|
|
48
|
+
const route = audience.kind === 'bell' ? 'bell' : 'mention';
|
|
73
49
|
return recipients.map((recipient) => ({ item: sayItem, recipient, route }));
|
|
74
50
|
}
|
|
75
51
|
function pendingFor(requestedRecipient) {
|
|
@@ -78,23 +54,20 @@ export function deriveDeliveryModel(doc) {
|
|
|
78
54
|
return [];
|
|
79
55
|
if (pendingByRecipient === undefined) {
|
|
80
56
|
pendingByRecipient = new Map(roster.map((name) => [name, []]));
|
|
81
|
-
const joinedAfter = new Map(roster.map((name) => [name, lastJoinIndex(
|
|
82
|
-
for (const act of
|
|
57
|
+
const joinedAfter = new Map(roster.map((name) => [name, lastJoinIndex(squareState.acts, name)]));
|
|
58
|
+
for (const act of squareState.acts) {
|
|
83
59
|
if (act.kind !== 'say')
|
|
84
60
|
continue;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (act.reach === undefined && extractMentions(act.body).length === 0)
|
|
61
|
+
const audience = audienceOf(act);
|
|
62
|
+
if (audience.kind === 'mentions' && audience.names.length === 0)
|
|
88
63
|
continue;
|
|
89
64
|
for (const planned of plan(act)) {
|
|
90
|
-
if (planned.route === 'broadcast')
|
|
91
|
-
continue;
|
|
92
65
|
const joinedAt = joinedAfter.get(planned.recipient);
|
|
93
66
|
if (joinedAt === undefined || act.index <= joinedAt)
|
|
94
67
|
continue;
|
|
95
|
-
if (isDeliveryDelivered(
|
|
68
|
+
if (isDeliveryDelivered(squareState, planned.recipient, act.index))
|
|
96
69
|
continue;
|
|
97
|
-
pendingByRecipient.get(planned.recipient)?.push(
|
|
70
|
+
pendingByRecipient.get(planned.recipient)?.push(planned);
|
|
98
71
|
}
|
|
99
72
|
}
|
|
100
73
|
}
|
|
@@ -102,23 +75,23 @@ export function deriveDeliveryModel(doc) {
|
|
|
102
75
|
}
|
|
103
76
|
return { plan, pendingFor };
|
|
104
77
|
}
|
|
105
|
-
export function planActNotifications(
|
|
106
|
-
return deriveDeliveryModel(
|
|
78
|
+
export function planActNotifications(squareState, item) {
|
|
79
|
+
return deriveDeliveryModel(squareState).plan(item);
|
|
107
80
|
}
|
|
108
81
|
/** Mark only the directed notifications selected by the canonical pending projection. */
|
|
109
|
-
export function markDeliveredNotifications(
|
|
82
|
+
export function markDeliveredNotifications(squareState, recipient, delivered, at = Date.now()) {
|
|
110
83
|
const deliveredIndexes = new Set(delivered.map((item) => item.index));
|
|
111
84
|
let changed = false;
|
|
112
|
-
for (const notification of deriveDeliveryModel(
|
|
85
|
+
for (const notification of deriveDeliveryModel(squareState).pendingFor(recipient)) {
|
|
113
86
|
if (!deliveredIndexes.has(notification.item.index))
|
|
114
87
|
continue;
|
|
115
|
-
changed = recordDeliveredDelivery(
|
|
88
|
+
changed = recordDeliveredDelivery(squareState, notification.recipient, notification.item.index, { at }) || changed;
|
|
116
89
|
}
|
|
117
90
|
return changed;
|
|
118
91
|
}
|
|
119
92
|
/** Canonical say-activity filter shared by catch selection and hook ownership. */
|
|
120
93
|
export function matchesCatchFilter(activity, filter) {
|
|
121
|
-
if (activity.
|
|
94
|
+
if (audienceOf(activity).kind === 'bell')
|
|
122
95
|
return true;
|
|
123
96
|
if (filter.participants !== undefined &&
|
|
124
97
|
!filter.participants.some((participant) => sameName(participant, activity.actor))) {
|
|
@@ -128,16 +101,45 @@ export function matchesCatchFilter(activity, filter) {
|
|
|
128
101
|
}
|
|
129
102
|
/** True only when the live catch's own filters would deliver this notification. */
|
|
130
103
|
export function leaseOwnsNotification(lease, notification) {
|
|
131
|
-
const recipient = notification.recipient;
|
|
132
|
-
if (notification.route === 'beside' && recipient === undefined)
|
|
133
|
-
return false;
|
|
134
104
|
return matchesCatchFilter({
|
|
135
105
|
actor: notification.actor,
|
|
136
106
|
body: notification.body,
|
|
137
|
-
|
|
138
|
-
? 'bell'
|
|
139
|
-
: notification.route === 'beside'
|
|
140
|
-
? { beside: recipient }
|
|
141
|
-
: undefined,
|
|
107
|
+
...(notification.route === 'bell' ? { reach: 'bell' } : {}),
|
|
142
108
|
}, lease.filter ?? {});
|
|
143
109
|
}
|
|
110
|
+
const SQUARE_ROUTE_KEYS = ['name', 'squarePath', 'v'];
|
|
111
|
+
function publicSquareFromCwd(cwd) {
|
|
112
|
+
return path.resolve(cwd, '.square', 'PUBLIC.square');
|
|
113
|
+
}
|
|
114
|
+
export function parseSquareRoute(value) {
|
|
115
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
116
|
+
throw new SquareError('invalid_args', 'Malformed Square route');
|
|
117
|
+
}
|
|
118
|
+
const record = value;
|
|
119
|
+
const keys = Object.keys(record).sort();
|
|
120
|
+
if (keys.length !== SQUARE_ROUTE_KEYS.length || keys.some((key, index) => key !== SQUARE_ROUTE_KEYS[index])) {
|
|
121
|
+
throw new SquareError('invalid_args', 'Malformed Square route');
|
|
122
|
+
}
|
|
123
|
+
if (record.v !== 1 ||
|
|
124
|
+
typeof record.squarePath !== 'string' || record.squarePath === '' ||
|
|
125
|
+
typeof record.name !== 'string' || record.name === '') {
|
|
126
|
+
throw new SquareError('invalid_args', 'Malformed Square route');
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
v: 1,
|
|
130
|
+
squarePath: record.squarePath,
|
|
131
|
+
name: record.name,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export function captureRoute(input) {
|
|
135
|
+
const env = input.env ?? process.env;
|
|
136
|
+
const squarePath = canonicalSquarePath(publicSquareFromCwd(input.cwd));
|
|
137
|
+
const name = localParticipantName(squarePath, env);
|
|
138
|
+
if (name === undefined)
|
|
139
|
+
return null;
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
v: 1,
|
|
142
|
+
squarePath,
|
|
143
|
+
name,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface FileLockOptions {
|
|
2
|
+
retryMs: number;
|
|
3
|
+
staleMs: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function withFileLockSync<T>(lockPath: string, options: FileLockOptions, fn: () => T): T;
|
|
6
|
+
export declare function withFileLock<T>(lockPath: string, options: FileLockOptions, fn: () => T | Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const CLAUDE_PLUGIN_ID: "square@astrosheep";
|
|
2
|
+
export declare const CLAUDE_MARKETPLACE_NAME: "astrosheep";
|
|
3
|
+
export interface ClaudeCommandResult {
|
|
4
|
+
status: number;
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
}
|
|
8
|
+
export type ClaudeCommandRunner = (homeDir: string, args: string[]) => ClaudeCommandResult;
|
|
9
|
+
export interface ClaudeInstallResult {
|
|
10
|
+
marketplaceRoot: string;
|
|
11
|
+
pluginRoot: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function claudeMarketplaceRoot(homeDir: string): string;
|
|
14
|
+
export declare function installClaudePlugin(homeDir: string, run?: ClaudeCommandRunner): Promise<ClaudeInstallResult>;
|
|
15
|
+
export declare function uninstallClaudePlugin(homeDir: string, run?: ClaudeCommandRunner): Promise<{
|
|
16
|
+
paths: string[];
|
|
17
|
+
notes: string[];
|
|
18
|
+
}>;
|
|
19
|
+
export declare function doctorClaudePlugin(homeDir: string, run?: ClaudeCommandRunner): Promise<string[]>;
|
package/dist/harness-claude.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import crossSpawn from 'cross-spawn';
|
|
5
5
|
import { SQUARE_IDENTITY } from './identity.js';
|
|
6
6
|
import { stageReplacement } from './harness-stage.js';
|
|
7
7
|
export const CLAUDE_PLUGIN_ID = SQUARE_IDENTITY.pluginId;
|
|
@@ -10,11 +10,16 @@ export function claudeMarketplaceRoot(homeDir) {
|
|
|
10
10
|
return path.join(homeDir, '.square', 'claude', 'marketplaces', CLAUDE_MARKETPLACE_NAME);
|
|
11
11
|
}
|
|
12
12
|
function runClaude(homeDir, args) {
|
|
13
|
-
const
|
|
13
|
+
const command = process.env.SQUARE_CLAUDE_BIN || 'claude';
|
|
14
|
+
const result = crossSpawn.sync(command, args, {
|
|
14
15
|
encoding: 'utf8', env: { ...process.env, HOME: homeDir, CLAUDE_CONFIG_DIR: path.join(homeDir, '.claude') }, timeout: 30_000,
|
|
15
16
|
});
|
|
16
|
-
if (result.error)
|
|
17
|
+
if (result.error) {
|
|
18
|
+
if (result.error.code === 'ENOENT') {
|
|
19
|
+
throw new Error(`Claude CLI not found: ${command}. Install Claude Code or set SQUARE_CLAUDE_BIN to its executable path.`);
|
|
20
|
+
}
|
|
17
21
|
throw result.error;
|
|
22
|
+
}
|
|
18
23
|
return { status: result.status ?? 1, stdout: result.stdout || '', stderr: result.stderr || '' };
|
|
19
24
|
}
|
|
20
25
|
function requireSuccess(result, operation, allowMissing = false) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const CODEX_HOOK_COMMAND: "square codex-hook";
|
|
2
|
+
export declare const SQUARE_CODEX_MARKER: "square-codex-hook";
|
|
3
|
+
export declare const CODEX_PLUGIN_ID: "square@astrosheep";
|
|
4
|
+
export declare const CODEX_MARKETPLACE_NAME: "astrosheep";
|
|
5
|
+
export interface CodexCommandResult {
|
|
6
|
+
status: number;
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
}
|
|
10
|
+
export type CodexCommandRunner = (homeDir: string, args: string[], codexHomeDir?: string) => CodexCommandResult;
|
|
11
|
+
export interface CodexInstallResult {
|
|
12
|
+
configPath: string;
|
|
13
|
+
marketplaceRoot: string;
|
|
14
|
+
pluginRoot: string;
|
|
15
|
+
installedPath?: string;
|
|
16
|
+
notes: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function codexMarketplaceRoot(homeDir: string): string;
|
|
19
|
+
export declare function codexPluginRoot(homeDir: string, marketplaceRoot?: string): string;
|
|
20
|
+
export declare function codexPluginHooksPath(homeDir: string, marketplaceRoot?: string): string;
|
|
21
|
+
export declare function codexHomeHooksPath(homeDir: string, codexHomeDir?: string): string;
|
|
22
|
+
export declare function codexConfigPath(homeDir: string, codexHomeDir?: string): string;
|
|
23
|
+
export declare function upsertTomlSectionKey(text: string, section: string, key: string, value: string): string;
|
|
24
|
+
export declare function installCodexPlugin(homeDir: string, run?: CodexCommandRunner, codexHomeDir?: string): Promise<CodexInstallResult>;
|
|
25
|
+
export declare function uninstallCodexPlugin(homeDir: string, run?: CodexCommandRunner, codexHomeDir?: string): Promise<{
|
|
26
|
+
paths: string[];
|
|
27
|
+
notes: string[];
|
|
28
|
+
}>;
|
|
29
|
+
export declare function doctorCodexPlugin(homeDir: string, run?: CodexCommandRunner, codexHomeDir?: string): Promise<string[]>;
|
package/dist/harness-codex.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import crossSpawn from 'cross-spawn';
|
|
5
5
|
import { SQUARE_IDENTITY } from './identity.js';
|
|
6
6
|
import { stageReplacement } from './harness-stage.js';
|
|
7
7
|
export const CODEX_HOOK_COMMAND = SQUARE_IDENTITY.hookCommand;
|
|
@@ -46,7 +46,7 @@ function codexHome(homeDir, codexHomeDir) {
|
|
|
46
46
|
export function codexHomeHooksPath(homeDir, codexHomeDir) { return path.join(codexHome(homeDir, codexHomeDir), 'hooks.json'); }
|
|
47
47
|
export function codexConfigPath(homeDir, codexHomeDir) { return path.join(codexHome(homeDir, codexHomeDir), 'config.toml'); }
|
|
48
48
|
function runCodex(homeDir, args, codexHomeDir) {
|
|
49
|
-
const result =
|
|
49
|
+
const result = crossSpawn.sync(process.env.SQUARE_CODEX_BIN || 'codex', args, {
|
|
50
50
|
encoding: 'utf8', env: { ...process.env, HOME: homeDir, CODEX_HOME: codexHome(homeDir, codexHomeDir) }, timeout: 30_000,
|
|
51
51
|
});
|
|
52
52
|
if (result.error)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface HarnessLink {
|
|
2
|
+
source: string;
|
|
3
|
+
target: string;
|
|
4
|
+
kind?: 'skill' | 'extension';
|
|
5
|
+
}
|
|
6
|
+
export declare function installHarnessLinks(links: HarnessLink[], force?: boolean): string[];
|
|
7
|
+
export declare function uninstallHarnessLinks(links: HarnessLink[]): string[];
|
|
8
|
+
export declare function doctorHarnessLinks(links: HarnessLink[]): string[];
|
|
9
|
+
export type OpenCodeCommandRunner = (homeDir: string, args: string[]) => {
|
|
10
|
+
status: number;
|
|
11
|
+
stdout: string;
|
|
12
|
+
stderr: string;
|
|
13
|
+
};
|
|
14
|
+
/** Verify that OpenCode accepts its resolved runtime configuration after links are installed. */
|
|
15
|
+
export declare function verifyOpenCodeRuntime(homeDir: string, run?: OpenCodeCommandRunner): string;
|
|
16
|
+
export declare function skillLinks(homeDir?: string, parents?: Array<'.claude' | '.agents'>): HarnessLink[];
|
|
17
|
+
export declare function opencodeExtensionLink(homeDir?: string): HarnessLink;
|
package/dist/harness-links.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { spawnSync } from 'node:child_process';
|
|
5
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
+
import crossSpawn from 'cross-spawn';
|
|
6
6
|
function packageRoot() {
|
|
7
7
|
// Emitted modules live in dist; package assets are one level above them.
|
|
8
8
|
return fileURLToPath(new URL('../', import.meta.url));
|
|
@@ -74,7 +74,7 @@ export function doctorHarnessLinks(links) {
|
|
|
74
74
|
: `○ Square ${link.kind ?? 'link'} missing ${link.target}`);
|
|
75
75
|
}
|
|
76
76
|
function runOpenCode(homeDir, args) {
|
|
77
|
-
const result =
|
|
77
|
+
const result = crossSpawn.sync(process.env.SQUARE_OPENCODE_BIN || 'opencode', args, {
|
|
78
78
|
encoding: 'utf8',
|
|
79
79
|
env: { ...process.env, HOME: homeDir, XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME ?? path.join(homeDir, '.config') },
|
|
80
80
|
timeout: 30_000,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface PiCommandResult {
|
|
2
|
+
status: number;
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
}
|
|
6
|
+
export type PiCommandRunner = (homeDir: string, args: string[]) => PiCommandResult;
|
|
7
|
+
export declare function piPackageSource(): string;
|
|
8
|
+
export declare function piPackageRoot(homeDir: string): string;
|
|
9
|
+
export declare function installPiPackage(homeDir: string, run?: PiCommandRunner): string[];
|
|
10
|
+
export declare function uninstallPiPackage(homeDir: string, run?: PiCommandRunner): string[];
|
|
11
|
+
export declare function doctorPiPackage(homeDir: string, run?: PiCommandRunner): string[];
|
package/dist/harness-pi.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import
|
|
3
|
+
import crossSpawn from 'cross-spawn';
|
|
4
4
|
import { SQUARE_IDENTITY } from './identity.js';
|
|
5
5
|
export function piPackageSource() {
|
|
6
6
|
return `npm:${SQUARE_IDENTITY.packageName}@${SQUARE_IDENTITY.packageVersion}`;
|
|
@@ -9,7 +9,7 @@ export function piPackageRoot(homeDir) {
|
|
|
9
9
|
return path.join(homeDir, '.pi', 'agent', 'npm', 'node_modules', ...SQUARE_IDENTITY.packageName.split('/'));
|
|
10
10
|
}
|
|
11
11
|
function runPi(homeDir, args) {
|
|
12
|
-
const result =
|
|
12
|
+
const result = crossSpawn.sync(process.env.SQUARE_PI_BIN || 'pi', args, {
|
|
13
13
|
encoding: 'utf8',
|
|
14
14
|
env: { ...process.env, HOME: homeDir },
|
|
15
15
|
timeout: 30_000,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface StagedReplacement {
|
|
2
|
+
rollback(): void;
|
|
3
|
+
finalize(): void;
|
|
4
|
+
}
|
|
5
|
+
/** Replace a file or directory while retaining the previous value for rollback. */
|
|
6
|
+
export declare function stageReplacement(root: string, populate: (stage: string) => void): StagedReplacement;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type HarnessTargetName = 'claude' | 'codex' | 'opencode' | 'pi' | 'delivery';
|
|
2
|
+
export type HarnessAction = 'install' | 'uninstall' | 'doctor';
|
|
3
|
+
export interface HarnessTargetContext {
|
|
4
|
+
homeDir: string;
|
|
5
|
+
squarePath?: string;
|
|
6
|
+
force: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface HarnessTargetResult {
|
|
9
|
+
lines: string[];
|
|
10
|
+
notes: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface HarnessTarget {
|
|
13
|
+
name: HarnessTargetName;
|
|
14
|
+
capabilities: readonly HarnessAction[];
|
|
15
|
+
install?(context: HarnessTargetContext): Promise<HarnessTargetResult> | HarnessTargetResult;
|
|
16
|
+
uninstall?(context: HarnessTargetContext): Promise<HarnessTargetResult> | HarnessTargetResult;
|
|
17
|
+
doctor?(context: HarnessTargetContext): Promise<HarnessTargetResult> | HarnessTargetResult;
|
|
18
|
+
}
|
|
19
|
+
export declare function harnessTargets(): readonly HarnessTarget[];
|
|
20
|
+
export declare function executeHarnessTarget(targetName: string, action: HarnessAction, context: HarnessTargetContext): Promise<HarnessTargetResult>;
|
package/dist/harness.js
CHANGED
|
@@ -79,9 +79,11 @@ const TARGETS = [
|
|
|
79
79
|
{
|
|
80
80
|
name: 'delivery',
|
|
81
81
|
capabilities: ['doctor'],
|
|
82
|
-
doctor
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
async doctor({ squarePath }) {
|
|
83
|
+
return result(readableSquarePath(squarePath)
|
|
84
|
+
? await doctorDeliveryHealth(squarePath, wakeGraceMs())
|
|
85
|
+
: ['○ delivery health skipped (no readable square path)']);
|
|
86
|
+
},
|
|
85
87
|
},
|
|
86
88
|
];
|
|
87
89
|
export function harnessTargets() {
|
package/dist/help.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function renderGlobalHelp(): string;
|
|
2
|
+
export declare function renderSubcommandHelp(command: string): string | undefined;
|
|
3
|
+
export declare function helpRequest(rawArgs: string[]): {
|
|
4
|
+
command?: string;
|
|
5
|
+
} | undefined;
|
|
6
|
+
export declare function commandUsageHint(command: string | undefined): string;
|
package/dist/help.js
CHANGED
|
@@ -16,9 +16,9 @@ const COMMANDS = [
|
|
|
16
16
|
details: ['Options:', ' --last <N> Show the last N public activities (default 10).', ' --all Show the complete history.'],
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
|
-
names: ['express'], usage: '--as <name> express [-f|--force] [--no-wait] [--
|
|
19
|
+
names: ['express'], usage: '--as <name> express [-f|--force] [--no-wait] [--bell] [--reply <activity-id>] <activity | ->', usesSquare: true, group: 'participant',
|
|
20
20
|
summary: 'Speak, gesture, or do both.',
|
|
21
|
-
details: ['Options:', ' -f, --force Express without first catching unread activity.', ' --no-wait If held or throttled, save a draft and return.', ' --
|
|
21
|
+
details: ['Reach:', ' @name Address someone in the square. They hear the body; everyone else sees you walk over.', " --bell Call every participant's attention to this activity without a mention.", '', 'Options:', ' -f, --force Express without first catching unread activity.', ' --no-wait If held or throttled, save a draft and return.', ' --reply <activity-id> Mark this activity as a reply to an earlier activity (for example act/12).'],
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
names: ['catch'], usage: '--as <name> catch (--now | --idle <duration>) [--from <names>] [--mention [name]] [--replace]', usesSquare: true, group: 'participant',
|
|
@@ -39,10 +39,9 @@ const COMMANDS = [
|
|
|
39
39
|
{ names: ['claude-hook', 'codex-hook'], usage: '{command}', summary: 'Present pending attention at one native agent boundary.', hiddenFromIndex: true },
|
|
40
40
|
{
|
|
41
41
|
names: ['history'], usage: '[--as <name>] history [filters] [output]', usesSquare: true, group: 'participant',
|
|
42
|
-
summary: 'Read or search
|
|
43
|
-
details: ['Filters:', ' --from <names> Match activities from participants.', ' --since <time>, --until <time> Match a time window.', ' --grep <regex> | --fixed <s> Search ids,
|
|
42
|
+
summary: 'Read or search the archive without changing what you have caught.',
|
|
43
|
+
details: ['Filters:', ' --from <names> Match activities from participants.', ' --since <time>, --until <time> Match a time window.', ' --grep <regex> | --fixed <s> Search activity ids, participants, and original bodies.', ' --mention <name> Match mentions.', ' --pending Match attention waiting for --as <name>.', ' --at <ids> Center on comma-separated activity ids; may repeat.', ' -B, -A, -C <N> Set non-negative context around every --at coordinate.', ' --after <id> Match activities after an id.', '', 'Results:', ' --limit <N> | --all Bound the newest matches (default 10).', ' --order <asc|desc> Set display order (default oldest first).', '', 'Output:', ' --full --json --format <fields>', ' Without --as, the default view shows complete activity bodies.'],
|
|
44
44
|
},
|
|
45
|
-
{ names: ['warmup'], usage: 'warmup', usesSquare: true, group: 'host', summary: 'Print the complete embedded participant warmup.' },
|
|
46
45
|
{ names: ['status'], usage: '[--as <name>] status', usesSquare: true, group: 'participant', summary: 'Show who is present and what happened most recently.' },
|
|
47
46
|
{ names: ['participants'], usage: 'participants', usesSquare: true, group: 'host', summary: 'Show the full participant roster and current states.' },
|
|
48
47
|
{ names: ['hold'], usage: '--as <name> hold [reason | -]', usesSquare: true, group: 'participant', summary: 'Raise a hand and pause participant activity.' },
|
|
@@ -62,11 +61,9 @@ const COMMANDS = [
|
|
|
62
61
|
summary: 'Diagnose installed agent-host support.',
|
|
63
62
|
details: ['Targets:', ' claude, codex, opencode, pi Diagnose one installed adapter.', ' delivery Diagnose delivery for the selected square.'],
|
|
64
63
|
},
|
|
65
|
-
{ names: ['compact'], usage: 'compact [--keep N]', usesSquare: true, group: 'host', summary: 'Move older activity out of the working artifact while keeping the latest N.' },
|
|
66
64
|
{
|
|
67
|
-
names: ['doctor'], usage: 'doctor
|
|
68
|
-
summary: '
|
|
69
|
-
details: ['Options:', ' --fix Repair recoverable artifact problems.'],
|
|
65
|
+
names: ['doctor'], usage: 'doctor', usesSquare: true, group: 'maintenance',
|
|
66
|
+
summary: 'Validate binary artifact integrity.',
|
|
70
67
|
},
|
|
71
68
|
];
|
|
72
69
|
function definitionFor(command) {
|
|
@@ -78,8 +75,8 @@ function isHelpFlag(value) {
|
|
|
78
75
|
export function renderGlobalHelp() {
|
|
79
76
|
const groups = [
|
|
80
77
|
{ key: 'participant', title: 'In the square:', order: ['join', 'express', 'catch', 'history', 'status', 'hold', 'resume', 'done'] },
|
|
81
|
-
{ key: 'host', title: 'Prepare and manage:', order: ['build', 'list', 'participants'
|
|
82
|
-
{ key: 'maintenance', title: 'Setup
|
|
78
|
+
{ key: 'host', title: 'Prepare and manage:', order: ['build', 'list', 'participants'] },
|
|
79
|
+
{ key: 'maintenance', title: 'Setup:', order: ['install', 'uninstall', 'doctor'] },
|
|
83
80
|
];
|
|
84
81
|
const commandLines = groups.flatMap(({ key, title, order }) => [
|
|
85
82
|
title,
|
|
@@ -90,7 +87,9 @@ export function renderGlobalHelp() {
|
|
|
90
87
|
'',
|
|
91
88
|
]);
|
|
92
89
|
return [
|
|
93
|
-
'Usage: square [--location <
|
|
90
|
+
'Usage: square [--location <square>] [--as <name>] <command> [args...]',
|
|
91
|
+
'Environment: SQUARE_LOCATION sets the CLI location; SQUARE_PARTICIPANT_NAME sets the participant name.',
|
|
92
|
+
'CLI flags override environment values. Automatic provider sessions use only .square/PUBLIC.square.',
|
|
94
93
|
'',
|
|
95
94
|
...commandLines,
|
|
96
95
|
"Run 'square <command> --help' for command options.",
|
|
@@ -104,7 +103,7 @@ export function renderSubcommandHelp(command) {
|
|
|
104
103
|
const aliases = definition.names.filter((name) => name !== command);
|
|
105
104
|
const usage = definition.usage.replace('{command}', command);
|
|
106
105
|
return [
|
|
107
|
-
`Usage: square ${definition.usesSquare ? '[--location <
|
|
106
|
+
`Usage: square ${definition.usesSquare ? '[--location <square>] ' : ''}${usage}`,
|
|
108
107
|
...(aliases.length > 0 ? [`Aliases: ${aliases.join(', ')}`] : []),
|
|
109
108
|
'',
|
|
110
109
|
definition.summary,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const SQUARE_IDENTITY: Readonly<{
|
|
2
|
+
publisher: "astrosheep";
|
|
3
|
+
packageName: "@astrosheep/square";
|
|
4
|
+
packageVersion: string;
|
|
5
|
+
productName: "Square";
|
|
6
|
+
pluginName: "square";
|
|
7
|
+
marketplaceName: "astrosheep";
|
|
8
|
+
cliName: "square";
|
|
9
|
+
pluginId: "square@astrosheep";
|
|
10
|
+
hookCommand: "square codex-hook";
|
|
11
|
+
hookMarker: "square-codex-hook";
|
|
12
|
+
clientName: "astrosheep_square";
|
|
13
|
+
}>;
|
package/dist/inbox.d.ts
ADDED
package/dist/inbox.js
CHANGED
|
@@ -1,34 +1,30 @@
|
|
|
1
|
-
import { loadSquare } from './artifact.js';
|
|
2
|
-
import { deriveDeliveryModel } from './delivery.js';
|
|
3
1
|
import { lookupSessionBindings } from './registry.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
2
|
+
import { openSquare } from './square-file-adapter.js';
|
|
3
|
+
import { closeOpenSquare } from './open-square.js';
|
|
4
|
+
import { inboxProjection } from './views.js';
|
|
5
|
+
export async function sessionInbox(sessionId) {
|
|
6
6
|
const inbox = [];
|
|
7
7
|
for (const binding of lookupSessionBindings(sessionId)) {
|
|
8
|
+
let square;
|
|
8
9
|
try {
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
10
|
+
square = await openSquare(binding.squarePath);
|
|
11
|
+
const projection = await inboxProjection(square, binding.name, binding.ownerId);
|
|
12
|
+
if (!projection.joined)
|
|
12
13
|
continue;
|
|
13
|
-
const notifications = deriveDeliveryModel(doc).pendingFor(name).map(({ item, route }) => ({
|
|
14
|
-
actIndex: item.index,
|
|
15
|
-
actor: item.actor,
|
|
16
|
-
at: item.at,
|
|
17
|
-
route,
|
|
18
|
-
body: item.body,
|
|
19
|
-
}));
|
|
20
|
-
const lease = freshWatchLease(doc, name);
|
|
21
|
-
const catchLease = lease?.ownerId === binding.ownerId ? lease : undefined;
|
|
22
14
|
inbox.push({
|
|
23
|
-
name,
|
|
15
|
+
name: projection.name,
|
|
24
16
|
squarePath: binding.squarePath,
|
|
25
|
-
notifications,
|
|
26
|
-
...(catchLease !== undefined ? { catchLease } : {}),
|
|
17
|
+
notifications: [...projection.notifications],
|
|
18
|
+
...(projection.catchLease !== undefined ? { catchLease: projection.catchLease } : {}),
|
|
27
19
|
});
|
|
28
20
|
}
|
|
29
21
|
catch {
|
|
30
22
|
// A stale discovery-cache row only disables delivery for that membership.
|
|
31
23
|
}
|
|
24
|
+
finally {
|
|
25
|
+
if (square !== undefined)
|
|
26
|
+
await closeOpenSquare(square);
|
|
27
|
+
}
|
|
32
28
|
}
|
|
33
29
|
return inbox;
|
|
34
30
|
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type SquareRoute } from './delivery.js';
|
|
2
|
+
import type { ExpressResult } from './square-facade.js';
|
|
3
|
+
export { Square } from './square-wiring.js';
|
|
4
|
+
export { SquareError } from './model.js';
|
|
5
|
+
export { captureRoute } from './delivery.js';
|
|
6
|
+
export type { SquareRoute } from './delivery.js';
|
|
7
|
+
export type { ActivityId } from './square-core.js';
|
|
8
|
+
export type { Activity, CatchOptions, CatchResult, ExpressOptions, ExpressResult, HistoryQuery, OpenOptions, Participant, ParticipantStatus, PerceivedActivity, SquareAtInput, SquareBuildInput, SquareSnapshot, SquareSource, WakeNotifier, } from './square-facade.js';
|
|
9
|
+
export interface RouteExpressOptions {
|
|
10
|
+
readonly as: string;
|
|
11
|
+
readonly body: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function express(route: SquareRoute, options: RouteExpressOptions): Promise<ExpressResult>;
|