@astrosheep/square 0.3.63 → 0.3.65
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/claude-plugin/.claude-plugin/plugin.json +3 -2
- package/claude-plugin/hooks/hooks.json +1 -22
- package/claude-plugin/hooks/register.js +119 -0
- package/claude-plugin/types.d.ts +7 -0
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity-feed.d.ts +1 -10
- package/dist/activity-feed.js +1 -27
- package/dist/activity.js +57 -25
- package/dist/artifact.d.ts +1 -1
- package/dist/artifact.js +24 -25
- package/dist/attention-presentation.js +1 -0
- package/dist/automatic-session.d.ts +3 -1
- package/dist/automatic-session.js +21 -34
- package/dist/boundary-presentation.js +4 -13
- package/dist/canonical-path.d.ts +11 -0
- package/dist/canonical-path.js +47 -0
- package/dist/catch-decisions.js +14 -10
- package/dist/catch-selection.d.ts +6 -0
- package/dist/catch-selection.js +14 -0
- package/dist/claude-delivery.d.ts +11 -0
- package/dist/claude-delivery.js +145 -0
- package/dist/claude-mod.d.ts +8 -0
- package/dist/claude-mod.js +164 -0
- package/dist/cli/context.d.ts +0 -1
- package/dist/cli/context.js +9 -21
- package/dist/cli/harness-command.d.ts +0 -1
- package/dist/cli/harness-command.js +0 -6
- package/dist/cli/observation-commands.d.ts +1 -1
- package/dist/cli/observation-commands.js +31 -58
- package/dist/cli/program.js +20 -18
- package/dist/cli/registry.js +2 -2
- package/dist/cli/square-commands.js +10 -6
- package/dist/codex-boundary-state.d.ts +2 -2
- package/dist/codex-boundary-state.js +4 -4
- package/dist/codex-hook.js +12 -15
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +7 -5
- package/dist/decisions.d.ts +2 -6
- package/dist/decisions.js +16 -17
- package/dist/delivery-health.d.ts +1 -2
- package/dist/delivery-health.js +4 -5
- package/dist/delivery-operations.d.ts +2 -5
- package/dist/delivery-operations.js +77 -214
- package/dist/delivery.d.ts +25 -47
- package/dist/delivery.js +14 -46
- package/dist/diagnostic-redaction.js +7 -9
- package/dist/file-changes.d.ts +0 -1
- package/dist/file-changes.js +2 -19
- package/dist/harness-claude.js +8 -6
- package/dist/harness-codex.d.ts +0 -2
- package/dist/harness-codex.js +0 -2
- package/dist/harness-links.js +13 -17
- package/dist/harness.js +3 -7
- package/dist/help.js +4 -3
- package/dist/host-ledger-file-adapter.d.ts +17 -8
- package/dist/host-ledger-file-adapter.js +164 -80
- package/dist/host-ledger.d.ts +55 -50
- package/dist/inbox.d.ts +0 -3
- package/dist/inbox.js +88 -50
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list.js +1 -4
- package/dist/mcp.js +24 -41
- package/dist/mention-parse.js +3 -9
- package/dist/model.d.ts +11 -2
- package/dist/model.js +1 -1
- package/dist/notifications.d.ts +3 -16
- package/dist/notifications.js +41 -122
- package/dist/opencode-delivery.d.ts +14 -0
- package/dist/opencode-delivery.js +171 -0
- package/dist/opencode.d.ts +39 -18
- package/dist/opencode.js +145 -40
- package/dist/packages/agent-delivery/src/claude-auth.d.ts +13 -0
- package/dist/packages/agent-delivery/src/claude-auth.js +75 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +28 -0
- package/dist/packages/agent-delivery/src/claude-native.js +68 -0
- package/dist/packages/agent-delivery/src/claude.d.ts +14 -0
- package/dist/packages/agent-delivery/src/claude.js +66 -0
- package/dist/packages/agent-delivery/src/deadline.d.ts +11 -0
- package/dist/packages/agent-delivery/src/deadline.js +41 -0
- package/dist/packages/agent-delivery/src/errors.d.ts +16 -0
- package/dist/packages/agent-delivery/src/errors.js +41 -0
- package/dist/packages/agent-delivery/src/guards.d.ts +6 -0
- package/dist/packages/agent-delivery/src/guards.js +6 -0
- package/dist/packages/agent-delivery/src/index.d.ts +83 -0
- package/dist/packages/agent-delivery/src/index.js +110 -0
- package/dist/packages/agent-delivery/src/local-endpoint.d.ts +26 -0
- package/dist/packages/agent-delivery/src/local-endpoint.js +114 -0
- package/dist/packages/agent-delivery/src/opencode-native.d.ts +33 -0
- package/dist/packages/agent-delivery/src/opencode-native.js +75 -0
- package/dist/packages/agent-delivery/src/opencode.d.ts +14 -0
- package/dist/packages/agent-delivery/src/opencode.js +127 -0
- package/dist/packages/agent-delivery/src/paseo-native.d.ts +58 -0
- package/dist/packages/agent-delivery/src/paseo-native.js +122 -0
- package/dist/packages/agent-delivery/src/paseo.d.ts +19 -0
- package/dist/packages/agent-delivery/src/paseo.js +106 -0
- package/dist/packages/agent-delivery/src/pi-client.d.ts +10 -0
- package/dist/packages/agent-delivery/src/pi-client.js +106 -0
- package/dist/packages/agent-delivery/src/pi-protocol.d.ts +15 -0
- package/dist/packages/agent-delivery/src/pi-protocol.js +50 -0
- package/dist/packages/agent-delivery/src/pi-send.d.ts +23 -0
- package/dist/packages/agent-delivery/src/pi-send.js +4 -0
- package/dist/packages/agent-delivery/src/pi.d.ts +25 -0
- package/dist/packages/agent-delivery/src/pi.js +209 -0
- package/dist/packages/agent-delivery/src/types.d.ts +120 -0
- package/dist/participant-host.js +12 -13
- package/dist/participant-identity.d.ts +21 -0
- package/dist/participant-identity.js +32 -11
- package/dist/paseo-delivery.d.ts +2 -2
- package/dist/paseo-delivery.js +35 -27
- package/dist/paseo-timeline.js +25 -21
- package/dist/paseo.d.ts +2 -2
- package/dist/paseo.js +1 -2
- package/dist/ports.d.ts +7 -20
- package/dist/presentation-operations.js +16 -4
- package/dist/presentation.d.ts +19 -10
- package/dist/presentation.js +99 -177
- package/dist/registry.d.ts +15 -66
- package/dist/registry.js +45 -123
- package/dist/routes.d.ts +1 -28
- package/dist/routes.js +22 -104
- package/dist/runtime.d.ts +3 -9
- package/dist/runtime.js +14 -67
- package/dist/search.d.ts +0 -2
- package/dist/search.js +3 -10
- package/dist/square-actions.js +48 -72
- package/dist/square-application.js +32 -30
- package/dist/square-core.d.ts +3 -0
- package/dist/square-core.js +22 -5
- package/dist/square-facade.d.ts +2 -0
- package/dist/square-file-adapter.d.ts +2 -1
- package/dist/square-file-adapter.js +6 -9
- package/dist/square-projections.d.ts +40 -45
- package/dist/square-projections.js +60 -74
- package/dist/square-state.js +1 -4
- package/dist/square-storage.d.ts +5 -8
- package/dist/square-storage.js +13 -36
- package/dist/square-wiring.d.ts +2 -7
- package/dist/square-wiring.js +6 -24
- package/dist/stream.js +4 -6
- package/dist/time.js +2 -7
- package/dist/views.d.ts +6 -18
- package/dist/views.js +14 -21
- package/dist/wake-attempts.d.ts +2 -56
- package/dist/wake-attempts.js +15 -110
- package/dist/wake-eligibility.d.ts +43 -0
- package/dist/wake-eligibility.js +106 -0
- package/dist/wake-evidence.d.ts +32 -9
- package/dist/wake-evidence.js +29 -24
- package/dist/wake-sink.d.ts +13 -9
- package/dist/wake-sink.js +35 -54
- package/dist/watch.js +13 -21
- package/extensions/square-pi.js +27 -13
- package/guides/change-waits.md +1 -1
- package/guides/claude-native.md +101 -0
- package/guides/host-ledger.md +3 -1
- package/guides/participant.md +14 -7
- package/guides/pi-native-delivery.md +49 -0
- package/package.json +4 -3
- package/dist/claude-hook.d.ts +0 -10
- package/dist/claude-hook.js +0 -60
- package/dist/paseo-connection.d.ts +0 -15
- package/dist/paseo-connection.js +0 -141
- package/dist/presence.d.ts +0 -2
- package/dist/presence.js +0 -24
- package/dist/presented.d.ts +0 -2
- package/dist/presented.js +0 -10
- package/dist/state-cell.d.ts +0 -14
- package/dist/wake-port.d.ts +0 -23
- package/dist/wake-port.js +0 -27
- /package/dist/{state-cell.js → packages/agent-delivery/src/types.js} +0 -0
|
@@ -5,11 +5,11 @@ import { withFileLock } from './file-lock.js';
|
|
|
5
5
|
import { openSquare } from './square-file-adapter.js';
|
|
6
6
|
import { closeOpenSquare } from './open-square.js';
|
|
7
7
|
import { presentPending } from './presentation-operations.js';
|
|
8
|
-
import { hostLedgerForEnv
|
|
8
|
+
import { hostLedgerForEnv } from './registry.js';
|
|
9
|
+
import { sessionInbox } from './inbox.js';
|
|
9
10
|
import { attentionBodyIsClipped, renderAttentionPreview } from './attention-presentation.js';
|
|
10
|
-
import {
|
|
11
|
+
import { projectBoundaryEligibility } from './square-projections.js';
|
|
11
12
|
export { pendingAtBoundary } from './square-projections.js';
|
|
12
|
-
import { formatActivityId } from './square-core.js';
|
|
13
13
|
const CONTEXT_MAX = 1200;
|
|
14
14
|
const presentationLocks = new Map();
|
|
15
15
|
/** One settled promise loses to an abort so an in-process presentation wait stays bounded too. */
|
|
@@ -35,9 +35,6 @@ async function awaitWithSignal(promise, signal) {
|
|
|
35
35
|
signal.removeEventListener('abort', onAbort);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
function pendingCount(inbox) {
|
|
39
|
-
return inbox.reduce((total, membership) => total + membership.notifications.length, 0);
|
|
40
|
-
}
|
|
41
38
|
export function renderPendingAtBoundary(inbox) {
|
|
42
39
|
return renderBoundary(inbox).context;
|
|
43
40
|
}
|
|
@@ -84,13 +81,7 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
84
81
|
if (signal?.aborted)
|
|
85
82
|
return undefined;
|
|
86
83
|
const hostLedger = hostLedgerForEnv(env);
|
|
87
|
-
const pending =
|
|
88
|
-
for (const membership of pendingAtBoundary(inbox)) {
|
|
89
|
-
const evidence = await projectPresentationEvidence({ hostLedger, location: membership.squarePath, participant: membership.name, sessionId });
|
|
90
|
-
const notifications = membership.notifications.filter((notification) => !presentationSuppressesWake(evidence.filter((row) => row.activity === formatActivityId(notification.actIndex))));
|
|
91
|
-
if (notifications.length > 0)
|
|
92
|
-
pending.push({ ...membership, notifications });
|
|
93
|
-
}
|
|
84
|
+
const pending = await projectBoundaryEligibility({ hostLedger, sessionId, inbox });
|
|
94
85
|
if (pending.length === 0 || signal?.aborted)
|
|
95
86
|
return undefined;
|
|
96
87
|
const delivered = renderBoundary(pending);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one canonicalizer for square locations.
|
|
3
|
+
*
|
|
4
|
+
* Resolve, then realpath the nearest existing ancestor and rejoin the non-existing
|
|
5
|
+
* suffix: a square that does not exist yet under a symlinked directory still lands
|
|
6
|
+
* on the same identity as the directory it will appear in. Any other read error
|
|
7
|
+
* keeps the plain resolution.
|
|
8
|
+
*/
|
|
9
|
+
export declare function canonicalPath(value: string): Promise<string>;
|
|
10
|
+
/** The synchronous face of {@link canonicalPath}, using the native realpath. */
|
|
11
|
+
export declare function canonicalPathSync(value: string): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* The one canonicalizer for square locations.
|
|
5
|
+
*
|
|
6
|
+
* Resolve, then realpath the nearest existing ancestor and rejoin the non-existing
|
|
7
|
+
* suffix: a square that does not exist yet under a symlinked directory still lands
|
|
8
|
+
* on the same identity as the directory it will appear in. Any other read error
|
|
9
|
+
* keeps the plain resolution.
|
|
10
|
+
*/
|
|
11
|
+
export async function canonicalPath(value) {
|
|
12
|
+
let current = path.resolve(value);
|
|
13
|
+
const suffix = [];
|
|
14
|
+
for (;;) {
|
|
15
|
+
try {
|
|
16
|
+
return path.join(await fs.promises.realpath(current), ...suffix.reverse());
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error.code !== 'ENOENT')
|
|
20
|
+
return path.resolve(value);
|
|
21
|
+
const parent = path.dirname(current);
|
|
22
|
+
if (parent === current)
|
|
23
|
+
return path.resolve(value);
|
|
24
|
+
suffix.push(path.basename(current));
|
|
25
|
+
current = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** The synchronous face of {@link canonicalPath}, using the native realpath. */
|
|
30
|
+
export function canonicalPathSync(value) {
|
|
31
|
+
let current = path.resolve(value);
|
|
32
|
+
const suffix = [];
|
|
33
|
+
for (;;) {
|
|
34
|
+
try {
|
|
35
|
+
return path.join(fs.realpathSync.native(current), ...suffix.reverse());
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.code !== 'ENOENT')
|
|
39
|
+
return path.resolve(value);
|
|
40
|
+
const parent = path.dirname(current);
|
|
41
|
+
if (parent === current)
|
|
42
|
+
return path.resolve(value);
|
|
43
|
+
suffix.push(path.basename(current));
|
|
44
|
+
current = parent;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
package/dist/catch-decisions.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { audienceOf, formatActivityId, parseActivityId } from './square-core.js';
|
|
1
|
+
import { activityAuthors, audienceOf, formatActivityId, parseActivityId } from './square-core.js';
|
|
2
2
|
import { derivePerceptionProjection } from './perception-projection.js';
|
|
3
|
-
import {
|
|
3
|
+
import { recordObservation } from './runtime.js';
|
|
4
|
+
import { matchesCatchSelection } from './catch-selection.js';
|
|
4
5
|
import { participantIdentity } from './participant-identity.js';
|
|
5
|
-
import { SquareError,
|
|
6
|
+
import { SquareError, validateName } from './model.js';
|
|
6
7
|
import { resolveRosterName } from './runtime.js';
|
|
7
8
|
export const CATCH_DEFAULT_LIMIT = 10;
|
|
8
9
|
export const CATCH_MAX_LIMIT = 100;
|
|
@@ -17,7 +18,7 @@ function resolveCatchName(state, requestedName) {
|
|
|
17
18
|
validateName(requestedName);
|
|
18
19
|
const known = resolveRosterName(state, requestedName);
|
|
19
20
|
if (known === undefined) {
|
|
20
|
-
throw new SquareError('invalid_args', `✕ ${participantIdentity(requestedName)} has never stepped into this square
|
|
21
|
+
throw new SquareError('invalid_args', `✕ ${participantIdentity(requestedName)} has never stepped into this square`, { reason: 'never_joined' });
|
|
21
22
|
}
|
|
22
23
|
return known;
|
|
23
24
|
}
|
|
@@ -35,7 +36,11 @@ export function decideCatch(state, requestedName, options, at, project = deriveP
|
|
|
35
36
|
throw new SquareError('invalid_args', 'Invalid catch id: expected an activity id like act/12.');
|
|
36
37
|
const activity = state.acts.find((item) => item.index === index);
|
|
37
38
|
if (activity === undefined || activity.kind !== 'say' || !delivery.directedTo(activity, viewer)) {
|
|
38
|
-
throw new SquareError('invalid_args',
|
|
39
|
+
throw new SquareError('invalid_args', `✕ ${formatActivityId(index)} isn't addressed to you`, {
|
|
40
|
+
reason: 'not_addressed',
|
|
41
|
+
activityId: formatActivityId(index),
|
|
42
|
+
activityExists: activity !== undefined,
|
|
43
|
+
});
|
|
39
44
|
}
|
|
40
45
|
const perception = delivery.perceive(activity, viewer);
|
|
41
46
|
const changed = recordObservation(state, viewer, index, 'seen', at);
|
|
@@ -49,17 +54,16 @@ export function decideCatch(state, requestedName, options, at, project = deriveP
|
|
|
49
54
|
remaining: state.acts.filter((item) => item.kind === 'say' && delivery.directedTo(item, viewer) && !delivery.isSeen(viewer, item.index)).length,
|
|
50
55
|
};
|
|
51
56
|
}
|
|
52
|
-
const
|
|
53
|
-
const
|
|
57
|
+
const filter = { participants: options.from, mention: options.mention === true ? viewer : undefined };
|
|
58
|
+
const authors = activityAuthors(state.acts);
|
|
54
59
|
const delivered = [];
|
|
55
60
|
const perceptions = new Map();
|
|
56
61
|
const matching = [];
|
|
57
62
|
for (const activity of state.acts) {
|
|
58
63
|
if (activity.kind !== 'say' || !delivery.directedTo(activity, viewer))
|
|
59
64
|
continue;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (mentionOnly && audienceOf(activity).kind !== 'bell' && !matchesMentionTarget(activity, viewer))
|
|
65
|
+
const replyAuthor = activity.reply === undefined ? undefined : authors.get(activity.reply);
|
|
66
|
+
if (!matchesCatchSelection(activity.actor, audienceOf(activity), filter, replyAuthor))
|
|
63
67
|
continue;
|
|
64
68
|
if (delivery.isSeen(viewer, activity.index))
|
|
65
69
|
continue;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Audience } from './square-core.js';
|
|
2
|
+
/** Pure filter over settled audience facts; unread/directed eligibility and paging belong to callers. */
|
|
3
|
+
export declare function matchesCatchSelection(actor: string, audience: Audience, filter: {
|
|
4
|
+
readonly participants?: readonly string[];
|
|
5
|
+
readonly mention?: string;
|
|
6
|
+
}, replyAuthor?: string): boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { sameName } from './model.js';
|
|
2
|
+
import { audienceIncludes } from './square-core.js';
|
|
3
|
+
/** Pure filter over settled audience facts; unread/directed eligibility and paging belong to callers. */
|
|
4
|
+
export function matchesCatchSelection(actor, audience, filter, replyAuthor) {
|
|
5
|
+
if (filter.participants !== undefined && !filter.participants.some((participant) => sameName(participant, actor))) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (filter.mention === undefined)
|
|
9
|
+
return true;
|
|
10
|
+
// A reply is directed attention in its own right: the viewer is reached as the
|
|
11
|
+
// author of the activity they answered, exactly like a mention.
|
|
12
|
+
return audienceIncludes(audience, filter.mention)
|
|
13
|
+
|| (replyAuthor !== undefined && sameName(replyAuthor, filter.mention));
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HostLedgerPort, PresenceRecord } from './host-ledger.js';
|
|
2
|
+
import type { WakeTransportPort } from './ports.js';
|
|
3
|
+
export declare function nativeTokens(text: string): string[];
|
|
4
|
+
export declare function nativePayload(token: string, preview: string): string;
|
|
5
|
+
export declare function createClaudeWakeTransport(hostLedger: HostLedgerPort, env?: NodeJS.ProcessEnv): WakeTransportPort;
|
|
6
|
+
/** Authority comes only from bound memberships and the existing attempt ledger. */
|
|
7
|
+
export declare function observeClaudeDelivery(sessionId: string, text: string, operation: 'guard' | 'admitted' | 'stored', env?: NodeJS.ProcessEnv): Promise<{
|
|
8
|
+
recognized: boolean;
|
|
9
|
+
current: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
export type ClaudeBinding = Pick<PresenceRecord, 'location' | 'participant' | 'session' | 'epoch'>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { openSquare } from './square-file-adapter.js';
|
|
3
|
+
import { closeOpenSquare } from './open-square.js';
|
|
4
|
+
import { hostLedgerForEnv } from './registry.js';
|
|
5
|
+
import { nativePendingPreview, projectPresentationEvidence, presentationSuppressesWake } from './square-projections.js';
|
|
6
|
+
import { presentPending } from './presentation-operations.js';
|
|
7
|
+
import { canonicalPath } from './canonical-path.js';
|
|
8
|
+
import { parseActivityId } from './square-core.js';
|
|
9
|
+
import { DeliveryError, connect } from './packages/agent-delivery/src/index.js';
|
|
10
|
+
const marker = /(?:^|\n)\[square-inbox:([a-zA-Z0-9-]+)\](?:\n|$)/g;
|
|
11
|
+
export function nativeTokens(text) { return [...text.matchAll(marker)].map((match) => match[1]); }
|
|
12
|
+
export function nativePayload(token, preview) { return `[square-inbox:${token}]\n${preview}\n[/square-inbox:${token}]`; }
|
|
13
|
+
function nativeSupported(route) { return route.address.version === '2.1.295' && route.address.loaded === 'true' && !!route.address.endpoint; }
|
|
14
|
+
/**
|
|
15
|
+
* The shared entry owns platform policy, token resolution and frame shape; Square
|
|
16
|
+
* owns the payload, the correlation and the evidence. A local write is never proof
|
|
17
|
+
* of native admission.
|
|
18
|
+
*/
|
|
19
|
+
async function writeClaudeWake(sessionId, endpoint, payload, timeoutMs, signal) {
|
|
20
|
+
try {
|
|
21
|
+
const agent = await connect({ harness: 'claude', sessionId, endpoint, timeoutMs });
|
|
22
|
+
await agent.steer(payload, { signal });
|
|
23
|
+
return { outcome: 'unknown', signature: 'native_admission_unconfirmed', message: 'Claude accepted the local write; native admission is unconfirmed.' };
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof DeliveryError && !error.maybeDelivered) {
|
|
27
|
+
return { outcome: 'failed', unavailable: true, retainRoute: true, signature: 'claude_endpoint_unavailable', message: error.message };
|
|
28
|
+
}
|
|
29
|
+
return { outcome: 'unknown', signature: 'native_admission_unconfirmed', message: error instanceof Error ? error.message : String(error) };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function createClaudeWakeTransport(hostLedger, env = process.env) {
|
|
33
|
+
return {
|
|
34
|
+
async probe(route) {
|
|
35
|
+
if (!nativeSupported(route))
|
|
36
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native inbox unavailable: Claude 2.1.295 with a loaded interactive Square mod required.' };
|
|
37
|
+
try {
|
|
38
|
+
return (await stat(route.address.endpoint)).isSocket() || { outcome: 'not-capable', diagnostic: 'Claude native inbox endpoint is not a socket.' };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native inbox endpoint unavailable.' };
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
attempt: (request, timeoutMs, beforeSend) => dispatchClaude(request, hostLedger, timeoutMs, beforeSend, env),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function currentDelivery(row, hostLedger) {
|
|
48
|
+
if (row.nativeDelivery?.harness !== 'claude')
|
|
49
|
+
return undefined;
|
|
50
|
+
const native = row.nativeDelivery;
|
|
51
|
+
const owner = (await hostLedger.listPresence({ location: row.location, participant: row.participant })).find((binding) => binding.session === row.session && binding.epoch === native.epoch);
|
|
52
|
+
const index = parseActivityId(row.activity);
|
|
53
|
+
if (!owner || index === undefined || !row.claimToken)
|
|
54
|
+
return undefined;
|
|
55
|
+
const square = await openSquare(owner.location, { hostLedger });
|
|
56
|
+
try {
|
|
57
|
+
const state = (await square.artifact.read()).state;
|
|
58
|
+
const preview = nativePendingPreview(state, { location: row.location, routeKind: 'claude-native', sessionId: row.session, participant: row.participant, actIndex: index, epoch: native.epoch, address: { endpoint: native.endpoint }, cancelledThrough: owner.cancelledThrough, now: Date.now() });
|
|
59
|
+
if (!preview || nativePayload(row.claimToken, preview.payload) !== native.payload)
|
|
60
|
+
return undefined;
|
|
61
|
+
return { cancelledThrough: owner.cancelledThrough, clipped: preview.clipped };
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
await closeOpenSquare(square);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Square owns rendering, correlation and evidence; socket transport owns none of them. */
|
|
68
|
+
async function dispatchClaude(request, hostLedger, timeoutMs, beforeSend, env = process.env) {
|
|
69
|
+
request = { ...request, location: await canonicalPath(request.location) };
|
|
70
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
71
|
+
if (!nativeSupported(request.route))
|
|
72
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native inbox requires Claude 2.1.295 and a loaded interactive Square mod.' };
|
|
73
|
+
return hostLedger.withClaimLock(async () => {
|
|
74
|
+
if (signal.aborted)
|
|
75
|
+
return { outcome: 'not-capable', diagnostic: 'Native dispatch deadline elapsed before send.' };
|
|
76
|
+
if (!request.claimToken || !await (beforeSend?.() ?? Promise.resolve(true)))
|
|
77
|
+
return { outcome: 'unknown', signature: 'native_send_suppressed' };
|
|
78
|
+
const owner = (await hostLedger.listPresence({ location: request.location, participant: request.participant })).find((binding) => binding.session === request.route.sessionId && binding.epoch === request.route.epoch);
|
|
79
|
+
if (!owner)
|
|
80
|
+
return { outcome: 'not-capable', diagnostic: 'Claude binding changed.' };
|
|
81
|
+
const square = await openSquare(request.location, { hostLedger });
|
|
82
|
+
let payload;
|
|
83
|
+
try {
|
|
84
|
+
const index = parseActivityId(request.activity);
|
|
85
|
+
const preview = index === undefined ? undefined : nativePendingPreview((await square.artifact.read()).state, { location: request.location, routeKind: 'claude-native', sessionId: request.route.sessionId, participant: request.participant, actIndex: index, epoch: request.route.epoch, address: { endpoint: request.route.address.endpoint }, cancelledThrough: owner.cancelledThrough, now: Date.now() });
|
|
86
|
+
if (!preview)
|
|
87
|
+
return { outcome: 'not-capable', diagnostic: 'Catch or consumption owns this activity.' };
|
|
88
|
+
payload = nativePayload(request.claimToken, preview.payload);
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
await closeOpenSquare(square);
|
|
92
|
+
}
|
|
93
|
+
if (!await (beforeSend?.() ?? Promise.resolve(true)))
|
|
94
|
+
return { outcome: 'not-capable', diagnostic: 'Native activity was consumed before send.' };
|
|
95
|
+
const native = { harness: 'claude', payload, epoch: owner.epoch ?? 0, endpoint: request.route.address.endpoint };
|
|
96
|
+
const row = { location: request.location, participant: request.participant, session: request.route.sessionId, activity: request.activity, kind: 'wake', outcome: 'dispatching', routeKind: 'claude-native', attemptN: request.attemptN, claimToken: request.claimToken, nativeDelivery: native };
|
|
97
|
+
if (!await currentDelivery(row, hostLedger) || !await hostLedger.prepareNativeWake(row))
|
|
98
|
+
return { outcome: 'not-capable', diagnostic: 'Native delivery is no longer current.' };
|
|
99
|
+
if (!await (beforeSend?.() ?? Promise.resolve(true)) || !await currentDelivery(row, hostLedger))
|
|
100
|
+
return { outcome: 'not-capable', diagnostic: 'Catch, cancellation or consumption won before native write.' };
|
|
101
|
+
return writeClaudeWake(row.session, native.endpoint, payload, timeoutMs, signal);
|
|
102
|
+
}, signal);
|
|
103
|
+
}
|
|
104
|
+
/** Authority comes only from bound memberships and the existing attempt ledger. */
|
|
105
|
+
export async function observeClaudeDelivery(sessionId, text, operation, env = process.env) {
|
|
106
|
+
const ledger = hostLedgerForEnv(env);
|
|
107
|
+
return ledger.withClaimLock(async () => {
|
|
108
|
+
const tokens = nativeTokens(text);
|
|
109
|
+
const rows = (await ledger.listEvidence({ kind: 'wake', session: sessionId })).filter((row) => row.nativeDelivery?.harness === 'claude' && row.claimToken && tokens.includes(row.claimToken) && ['dispatching', 'unknown', 'accepted'].includes(row.outcome));
|
|
110
|
+
let current = false;
|
|
111
|
+
for (const row of rows) {
|
|
112
|
+
if (row.nativeDelivery?.harness !== 'claude')
|
|
113
|
+
continue;
|
|
114
|
+
const native = row.nativeDelivery;
|
|
115
|
+
const pending = await currentDelivery(row, ledger).catch(() => undefined);
|
|
116
|
+
if (!pending || !text.includes(native.payload))
|
|
117
|
+
continue;
|
|
118
|
+
current = true;
|
|
119
|
+
if (operation === 'admitted') {
|
|
120
|
+
if (text === native.payload)
|
|
121
|
+
await ledger.confirmWakeAdmission({ ...row, claimToken: row.claimToken });
|
|
122
|
+
}
|
|
123
|
+
if (operation === 'stored') {
|
|
124
|
+
await ledger.confirmWakeAdmission({ ...row, claimToken: row.claimToken });
|
|
125
|
+
const prior = await projectPresentationEvidence({ hostLedger: ledger, location: row.location, participant: row.participant, sessionId, activity: row.activity });
|
|
126
|
+
if (presentationSuppressesWake(prior))
|
|
127
|
+
continue;
|
|
128
|
+
const square = await openSquare(row.location, { hostLedger: ledger, env });
|
|
129
|
+
try {
|
|
130
|
+
await presentPending({ artifact: square.artifact, hostLedger: ledger, location: row.location, participant: row.participant, session: sessionId, activity: row.activity, sink: { present() { } }, markSeen: !pending.clipped, current: (state) => {
|
|
131
|
+
const index = parseActivityId(row.activity);
|
|
132
|
+
if (index === undefined)
|
|
133
|
+
return false;
|
|
134
|
+
const preview = nativePendingPreview(state, { location: row.location, routeKind: 'claude-native', sessionId: row.session, participant: row.participant, actIndex: index, epoch: native.epoch, address: { endpoint: native.endpoint }, cancelledThrough: pending.cancelledThrough, now: Date.now() });
|
|
135
|
+
return preview !== undefined && nativePayload(row.claimToken, preview.payload) === native.payload;
|
|
136
|
+
} });
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
await closeOpenSquare(square);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { recognized: rows.length > 0, current };
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ClaudeCoordinate {
|
|
2
|
+
readonly sessionId: string;
|
|
3
|
+
readonly cwd: string;
|
|
4
|
+
readonly version: string;
|
|
5
|
+
readonly endpoint?: string;
|
|
6
|
+
}
|
|
7
|
+
/** JSON stdin bridge. Identity is explicit per operation; process.env is never rewritten. */
|
|
8
|
+
export declare function runClaudeMod(inputText: string, env?: NodeJS.ProcessEnv): Promise<string>;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { automaticSessionStart, operationEnv } from './automatic-session.js';
|
|
2
|
+
import { claimSessionParticipant, hostLedgerForEnv } from './registry.js';
|
|
3
|
+
import { openSquare } from './square-file-adapter.js';
|
|
4
|
+
import { closeOpenSquare } from './open-square.js';
|
|
5
|
+
import { publishWakeRoute, retireWakeRouteFromArtifact } from './routes.js';
|
|
6
|
+
import { Square } from './square-wiring.js';
|
|
7
|
+
import { observeClaudeDelivery } from './claude-delivery.js';
|
|
8
|
+
import { processActNotificationsOnce } from './notifications.js';
|
|
9
|
+
import { sweepPending } from './delivery-operations.js';
|
|
10
|
+
/** JSON stdin bridge. Identity is explicit per operation; process.env is never rewritten. */
|
|
11
|
+
export async function runClaudeMod(inputText, env = process.env) {
|
|
12
|
+
if (inputText.length > 512_000)
|
|
13
|
+
throw new Error('Claude bridge input exceeds its bound.');
|
|
14
|
+
const input = JSON.parse(inputText);
|
|
15
|
+
if (!input || typeof input.sessionId !== 'string' || !input.sessionId || typeof input.cwd !== 'string')
|
|
16
|
+
throw new Error('Claude bridge coordinate missing.');
|
|
17
|
+
const scoped = operationEnv('claude', input.sessionId, env);
|
|
18
|
+
const ledger = hostLedgerForEnv(env);
|
|
19
|
+
const signal = AbortSignal.timeout(2500);
|
|
20
|
+
const supported = process.platform === 'darwin' && input.version === '2.1.295' && typeof input.endpoint === 'string' && input.endpoint.startsWith('/');
|
|
21
|
+
if (input.operation === 'end') {
|
|
22
|
+
const retired = [];
|
|
23
|
+
const captured = [...input.bindings ?? []];
|
|
24
|
+
// Discover committed late joins at the pinned end boundary, never later owners.
|
|
25
|
+
if (input.endedAt !== undefined)
|
|
26
|
+
for (const row of await ledger.listPresence({ session: input.sessionId })) {
|
|
27
|
+
if (row.channel === 'claude-code' && (row.updatedAt ?? Infinity) <= input.endedAt && !captured.some((binding) => binding.location === row.location && binding.participant === row.participant))
|
|
28
|
+
captured.push(row);
|
|
29
|
+
}
|
|
30
|
+
for (const binding of captured) {
|
|
31
|
+
if (binding.session !== input.sessionId || !Number.isSafeInteger(binding.epoch))
|
|
32
|
+
continue;
|
|
33
|
+
const square = await Square.at({ path: binding.location, hostLedger: ledger, env: scoped });
|
|
34
|
+
try {
|
|
35
|
+
const ended = await square.endOwnedSession(binding.participant, input.sessionId, binding.epoch);
|
|
36
|
+
if (ended?.activity) {
|
|
37
|
+
retired.push(binding);
|
|
38
|
+
const row = { location: binding.location, participant: binding.participant, session: input.sessionId, activity: ended.activity.id, kind: 'lifecycle', bindingEpoch: binding.epoch, outcome: 'retired' };
|
|
39
|
+
const claim = await ledger.claimEvidence({ ...row, leaseMs: 1000 });
|
|
40
|
+
if (claim.status === 'acquired')
|
|
41
|
+
await ledger.appendEvidence({ ...row, claimToken: claim.claimToken });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await square.close();
|
|
46
|
+
}
|
|
47
|
+
if (signal.aborted)
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
return `${JSON.stringify({ retired })}\n`;
|
|
51
|
+
}
|
|
52
|
+
const recovery = new Set();
|
|
53
|
+
const cancelledBindings = [...input.cancelledBindings ?? []];
|
|
54
|
+
if (input.operation === 'start') {
|
|
55
|
+
// Host state survives reload, not conversation replacement. Resume authority is
|
|
56
|
+
// the existing lifecycle ledger plus the exact ended activity, never peer text.
|
|
57
|
+
if (input.resume)
|
|
58
|
+
for (const row of await ledger.listEvidence({ kind: 'lifecycle', session: input.sessionId })) {
|
|
59
|
+
if (signal.aborted || row.outcome !== 'retired' || !Number.isSafeInteger(row.bindingEpoch))
|
|
60
|
+
continue;
|
|
61
|
+
const probe = await openSquare(row.location, { hostLedger: ledger, env: scoped, signal });
|
|
62
|
+
let eligible = false;
|
|
63
|
+
try {
|
|
64
|
+
const state = (await probe.artifact.read(signal)).state;
|
|
65
|
+
const last = state.acts.findLast((activity) => activity.actor === row.participant && ['join', 'done', 'kick'].includes(activity.kind));
|
|
66
|
+
eligible = last?.kind === 'done' && `act/${last.index}` === row.activity;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await closeOpenSquare(probe);
|
|
70
|
+
}
|
|
71
|
+
if (!eligible)
|
|
72
|
+
continue;
|
|
73
|
+
const claimed = await ledger.claimPresence({ location: row.location, participant: row.participant, session: input.sessionId, channel: 'claude-code', epoch: row.bindingEpoch + 1, updatedAt: Date.now() }, signal);
|
|
74
|
+
if (claimed.status !== 'acquired')
|
|
75
|
+
continue;
|
|
76
|
+
const square = await Square.at({ path: row.location, hostLedger: ledger, env: scoped });
|
|
77
|
+
try {
|
|
78
|
+
await square.join(row.participant);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
await ledger.removePresenceIfUnchanged(claimed.record);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await square.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
await automaticSessionStart('claude', input.sessionId, input.cwd, env);
|
|
88
|
+
}
|
|
89
|
+
if (input.operation === 'start' || input.operation === 'reconcile' || input.operation === 'cancel' || input.cancelAt !== undefined) {
|
|
90
|
+
const memberships = await ledger.listPresence({ session: input.sessionId });
|
|
91
|
+
for (const binding of memberships) {
|
|
92
|
+
if (binding.channel !== 'claude-code' || signal.aborted)
|
|
93
|
+
continue;
|
|
94
|
+
const expected = input.bindings?.find((row) => row.location === binding.location && row.participant === binding.participant && row.session === input.sessionId);
|
|
95
|
+
const cancelled = input.cancelledBindings?.find((row) => row.location === binding.location && row.participant === binding.participant && row.session === input.sessionId)
|
|
96
|
+
?? (input.operation === 'cancel' ? expected : undefined);
|
|
97
|
+
const lateCancelledJoin = input.operation === 'cancel' && input.cancelAt !== undefined && (binding.updatedAt ?? Infinity) <= input.cancelAt && expected === undefined;
|
|
98
|
+
if (lateCancelledJoin)
|
|
99
|
+
cancelledBindings.push(binding);
|
|
100
|
+
if (input.operation !== 'start' && input.operation !== 'reconcile' && !lateCancelledJoin && (!expected || expected.epoch !== binding.epoch))
|
|
101
|
+
continue;
|
|
102
|
+
const claim = await claimSessionParticipant(binding.location, binding.participant, ledger, scoped, signal);
|
|
103
|
+
if (!claim || claim.epoch !== (binding.epoch ?? 0))
|
|
104
|
+
continue;
|
|
105
|
+
await ledger.withClaimLock(async () => {
|
|
106
|
+
const current = (await ledger.listPresence({ location: binding.location, participant: binding.participant })).find((row) => row.session === input.sessionId && (row.epoch ?? 0) === claim.epoch);
|
|
107
|
+
if (!current)
|
|
108
|
+
return;
|
|
109
|
+
const epoch = claim.epoch || 1;
|
|
110
|
+
if (current.epoch !== epoch)
|
|
111
|
+
await ledger.ensurePresence({ ...current, epoch });
|
|
112
|
+
const square = await openSquare(binding.location, { hostLedger: ledger, env: scoped, signal });
|
|
113
|
+
try {
|
|
114
|
+
const state = (await square.artifact.read(signal)).state;
|
|
115
|
+
const existing = state.routes?.find((route) => route.participant === binding.participant && route.sessionId === input.sessionId && route.kind === 'claude-native' && route.epoch === epoch);
|
|
116
|
+
if (!supported) {
|
|
117
|
+
if (existing)
|
|
118
|
+
await retireWakeRouteFromArtifact(square.artifact, existing, { expectedEpoch: epoch });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const cutoff = cancelled?.epoch === epoch || (lateCancelledJoin && current.epoch === binding.epoch && (current.updatedAt ?? Infinity) <= input.cancelAt) ? input.cancelAt : undefined;
|
|
122
|
+
if (cutoff !== undefined) {
|
|
123
|
+
const through = state.acts.filter((activity) => activity.at <= cutoff).reduce((highest, activity) => Math.max(highest, activity.index), -1);
|
|
124
|
+
await ledger.suppressPresence({ ...current, epoch }, through);
|
|
125
|
+
}
|
|
126
|
+
if (!existing || existing.address.endpoint !== input.endpoint)
|
|
127
|
+
recovery.add(binding.location);
|
|
128
|
+
await publishWakeRoute(square.artifact, { location: binding.location, participant: binding.participant, sessionId: input.sessionId, channel: 'claude-code', kind: 'claude-native', epoch, address: { sessionId: input.sessionId, endpoint: input.endpoint, version: input.version, platform: 'darwin', loaded: 'true' } }, { requireCurrentSession: true });
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
await closeOpenSquare(square);
|
|
132
|
+
}
|
|
133
|
+
}, signal);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (input.operation === 'start' || input.operation === 'reconcile' || input.operation === 'cancel') {
|
|
137
|
+
const bindings = (await ledger.listPresence({ session: input.sessionId })).filter((row) => row.channel === 'claude-code').map(({ location, participant, session, epoch }) => ({ location, participant, session, epoch }));
|
|
138
|
+
// One startup recovery pass for known unsent work. Unknown/admitted sends never replay.
|
|
139
|
+
if (supported && input.operation !== 'cancel')
|
|
140
|
+
for (const binding of bindings) {
|
|
141
|
+
if (signal.aborted)
|
|
142
|
+
break;
|
|
143
|
+
if (input.operation !== 'start' && !recovery.has(binding.location))
|
|
144
|
+
continue;
|
|
145
|
+
const square = await openSquare(binding.location, { hostLedger: ledger, env, signal });
|
|
146
|
+
let indices;
|
|
147
|
+
try {
|
|
148
|
+
indices = await sweepPending({ artifact: square.artifact, hostLedger: ledger, location: binding.location, now: Date.now(), graceMs: 0, limit: 8 });
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
await closeOpenSquare(square);
|
|
152
|
+
}
|
|
153
|
+
for (const index of indices) {
|
|
154
|
+
if (signal.aborted)
|
|
155
|
+
break;
|
|
156
|
+
await processActNotificationsOnce(binding.location, index, { env: { ...env, SQUARE_NOTIFY_DELIVERY_WAIT_MS: '200' } });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return `${JSON.stringify({ available: supported, diagnostic: supported ? undefined : 'Native inbox unavailable: requires macOS Claude 2.1.295, an interactive loaded mod and its real endpoint.', bindings, cancelledBindings })}\n`;
|
|
160
|
+
}
|
|
161
|
+
if (!['guard', 'admitted', 'stored'].includes(input.operation) || typeof input.text !== 'string')
|
|
162
|
+
throw new Error('Unknown Claude bridge operation.');
|
|
163
|
+
return `${JSON.stringify(await observeClaudeDelivery(input.sessionId, input.text, input.operation, env))}\n`;
|
|
164
|
+
}
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ export interface CommandSpec<Intent = unknown, Result = void> {
|
|
|
14
14
|
}
|
|
15
15
|
export declare function readStdin(): Promise<string>;
|
|
16
16
|
export declare function resolveBody(arg: string): Promise<string>;
|
|
17
|
-
export declare function readPipedBodyFallback(): Promise<string | undefined>;
|
|
18
17
|
export declare function fail(message: string, exitCode?: number): never;
|
|
19
18
|
export declare function usage(command: string): never;
|
|
20
19
|
export declare function requireValue(args: string[], index: number, flag: string): string;
|
package/dist/cli/context.js
CHANGED
|
@@ -2,7 +2,8 @@ import os from 'node:os';
|
|
|
2
2
|
import { commandUsageHint } from '../help.js';
|
|
3
3
|
import { parseParticipantList, validateName } from '../model.js';
|
|
4
4
|
import { createHostLedgerPort } from '../host-ledger-file-adapter.js';
|
|
5
|
-
import { projectSessionBindings
|
|
5
|
+
import { projectSessionBindings } from '../square-projections.js';
|
|
6
|
+
import { sessionIdsFromEnvironment } from '../participant-identity.js';
|
|
6
7
|
export async function readStdin() {
|
|
7
8
|
try {
|
|
8
9
|
let content = '';
|
|
@@ -17,12 +18,6 @@ export async function readStdin() {
|
|
|
17
18
|
export async function resolveBody(arg) {
|
|
18
19
|
return arg === '-' ? readStdin() : arg;
|
|
19
20
|
}
|
|
20
|
-
export async function readPipedBodyFallback() {
|
|
21
|
-
if (process.stdin.isTTY)
|
|
22
|
-
return undefined;
|
|
23
|
-
const content = await readStdin();
|
|
24
|
-
return content.trim() === '' ? undefined : content;
|
|
25
|
-
}
|
|
26
21
|
export function fail(message, exitCode = 2) {
|
|
27
22
|
process.stderr.write(`${message}\n`);
|
|
28
23
|
process.exit(exitCode);
|
|
@@ -116,17 +111,6 @@ const LOCATION_REQUIRED_COMMANDS = new Set([
|
|
|
116
111
|
'mcp-server',
|
|
117
112
|
'doctor',
|
|
118
113
|
]);
|
|
119
|
-
function configuredLocation() {
|
|
120
|
-
const value = process.env.SQUARE_LOCATION?.trim();
|
|
121
|
-
return value === '' ? undefined : value;
|
|
122
|
-
}
|
|
123
|
-
function configuredName() {
|
|
124
|
-
const value = process.env.SQUARE_PARTICIPANT_NAME?.trim();
|
|
125
|
-
if (!value)
|
|
126
|
-
return undefined;
|
|
127
|
-
validateName(value);
|
|
128
|
-
return value;
|
|
129
|
-
}
|
|
130
114
|
export async function parseGlobalArgs(rawArgs) {
|
|
131
115
|
const args = [...rawArgs];
|
|
132
116
|
let requestedPath;
|
|
@@ -144,12 +128,16 @@ export async function parseGlobalArgs(rawArgs) {
|
|
|
144
128
|
}
|
|
145
129
|
}
|
|
146
130
|
const command = args[0];
|
|
147
|
-
if (name === undefined)
|
|
148
|
-
|
|
131
|
+
if (name === undefined) {
|
|
132
|
+
const configured = process.env.SQUARE_PARTICIPANT_NAME?.trim();
|
|
133
|
+
if (configured)
|
|
134
|
+
name = configured;
|
|
135
|
+
}
|
|
149
136
|
if (name !== undefined)
|
|
150
137
|
validateName(name);
|
|
151
138
|
const explicitSquarePath = requestedPath !== undefined;
|
|
152
|
-
const
|
|
139
|
+
const configuredLocation = process.env.SQUARE_LOCATION?.trim();
|
|
140
|
+
const configured = configuredLocation === '' ? undefined : configuredLocation;
|
|
153
141
|
if (command !== undefined && !['--help', '-h'].includes(command) && locationIsRequired(command) && requestedPath === undefined && configured === undefined) {
|
|
154
142
|
fail(`✕ ${command} needs a square location\nsquare ls`);
|
|
155
143
|
}
|
|
@@ -24,5 +24,4 @@ export declare const installCommand: CommandSpec<ParsedInstallCommand, HarnessCo
|
|
|
24
24
|
export declare const uninstallCommand: CommandSpec<ParsedInstallCommand, HarnessCommandResult>;
|
|
25
25
|
export declare const harnessCommand: CommandSpec<ParsedHarnessCommand, HarnessCommandResult>;
|
|
26
26
|
export declare function formatHarnessResult(result: HarnessCommandResult): string;
|
|
27
|
-
export declare function runHarnessCommand(argv: string[], squarePath?: string): Promise<string>;
|
|
28
27
|
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
1
|
import { executeHarnessTarget, harnessTargets, } from '../harness.js';
|
|
3
2
|
function installTargets(intent, action) {
|
|
4
3
|
const available = harnessTargets().filter((target) => target.capabilities.includes(action));
|
|
@@ -101,8 +100,3 @@ export const harnessCommand = {
|
|
|
101
100
|
export function formatHarnessResult(result) {
|
|
102
101
|
return `${[...result.notes, ...result.lines, ...result.failures].join('\n')}\n`;
|
|
103
102
|
}
|
|
104
|
-
export function runHarnessCommand(argv, squarePath) {
|
|
105
|
-
const context = { cwd: process.cwd(), env: { ...process.env }, homeDir: os.homedir(), ...(squarePath === undefined ? {} : { squarePath }), command: 'harness' };
|
|
106
|
-
const intent = harnessCommand.parse(argv, context);
|
|
107
|
-
return Promise.resolve(harnessCommand.execute(intent, context)).then(formatHarnessResult);
|
|
108
|
-
}
|
|
@@ -25,6 +25,6 @@ interface InboxIntent {
|
|
|
25
25
|
limit: number;
|
|
26
26
|
}
|
|
27
27
|
export declare const inboxCommand: CommandSpec<InboxIntent, string>;
|
|
28
|
-
export declare const
|
|
28
|
+
export declare const claudeModCommand: CommandSpec<undefined, string>;
|
|
29
29
|
export declare const codexHookCommand: CommandSpec<undefined, string>;
|
|
30
30
|
export {};
|