@astrosheep/square 0.3.105 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activity-feed.js +1 -1
- package/dist/artifact-store.d.ts +41 -0
- package/dist/artifact-store.js +272 -0
- package/dist/artifact.d.ts +8 -12
- package/dist/artifact.js +66 -343
- package/dist/attention-presentation.d.ts +33 -7
- package/dist/attention-presentation.js +33 -69
- package/dist/boundary-presentation.d.ts +0 -2
- package/dist/boundary-presentation.js +17 -22
- package/dist/catch-decisions.d.ts +2 -2
- package/dist/catch-decisions.js +14 -4
- package/dist/catch-selection.d.ts +8 -0
- package/dist/catch-selection.js +5 -0
- package/dist/channel-artifact.d.ts +10 -0
- package/dist/channel-artifact.js +55 -0
- package/dist/channel-delivery.d.ts +11 -0
- package/dist/channel-delivery.js +51 -0
- package/dist/channel-domain.d.ts +3 -0
- package/dist/channel-domain.js +83 -0
- package/dist/channel-facade.d.ts +76 -0
- package/dist/channel-facade.js +1 -0
- package/dist/channel-internal.d.ts +126 -0
- package/dist/channel-internal.js +440 -0
- package/dist/channel-metadata.d.ts +11 -0
- package/dist/channel-metadata.js +1 -0
- package/dist/channel-ports.d.ts +241 -0
- package/dist/channel-ports.js +1 -0
- package/dist/channel-presentation.d.ts +17 -0
- package/dist/channel-presentation.js +22 -0
- package/dist/channel-sqlite-schema.d.ts +13 -0
- package/dist/channel-sqlite-schema.js +81 -0
- package/dist/channel-transport.d.ts +62 -0
- package/dist/channel-transport.js +1 -0
- package/dist/channel-values.d.ts +27 -0
- package/dist/channel-values.js +90 -0
- package/dist/channel.d.ts +31 -21
- package/dist/channel.js +42 -74
- package/dist/claude-delivery-status.js +1 -1
- package/dist/claude-delivery.d.ts +2 -5
- package/dist/claude-delivery.js +56 -103
- package/dist/claude-mod.js +4 -4
- package/dist/claude-transport.d.ts +5 -0
- package/dist/claude-transport.js +58 -0
- package/dist/cli/context.d.ts +2 -2
- package/dist/cli/context.js +0 -1
- package/dist/cli/maintenance-commands.d.ts +0 -4
- package/dist/cli/maintenance-commands.js +2 -29
- package/dist/cli/program.js +1 -1
- package/dist/cli/registry.js +1 -2
- package/dist/codex-address.d.ts +1 -1
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +1 -3
- package/dist/decisions.js +3 -3
- package/dist/delivery-deferral.d.ts +9 -18
- package/dist/delivery-deferral.js +4 -4
- package/dist/delivery-health.d.ts +4 -4
- package/dist/delivery-health.js +11 -11
- package/dist/delivery-operations.d.ts +15 -2
- package/dist/delivery-operations.js +60 -30
- package/dist/delivery.d.ts +44 -33
- package/dist/delivery.js +49 -75
- package/dist/help.js +1 -6
- package/dist/http-delivery.d.ts +2 -2
- package/dist/http-delivery.js +2 -4
- package/dist/inbox.d.ts +10 -18
- package/dist/inbox.js +44 -53
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.js +40 -70
- package/dist/message.d.ts +7 -0
- package/dist/message.js +23 -0
- package/dist/model.d.ts +41 -77
- package/dist/model.js +7 -139
- package/dist/neutral.d.ts +72 -0
- package/dist/neutral.js +27 -0
- package/dist/notifications.d.ts +2 -8
- package/dist/notifications.js +15 -50
- package/dist/operation-presentation.d.ts +1 -2
- package/dist/operation-presentation.js +1 -7
- package/dist/owner.d.ts +2 -2
- package/dist/owner.js +1 -1
- package/dist/paseo-delivery.d.ts +1 -1
- package/dist/paseo-delivery.js +2 -4
- package/dist/paseo-timeline.js +1 -0
- package/dist/plugins/opencode/delivery.js +27 -42
- package/dist/ports.d.ts +46 -168
- package/dist/presentation-operations.d.ts +1 -14
- package/dist/presentation-operations.js +16 -16
- package/dist/presentation.d.ts +5 -5
- package/dist/presentation.js +1 -0
- package/dist/runtime.js +2 -2
- package/dist/search.js +1 -1
- package/dist/sqlite-channel.d.ts +15 -0
- package/dist/sqlite-channel.js +600 -0
- package/dist/sqlite-framing.d.ts +8 -0
- package/dist/sqlite-framing.js +31 -0
- package/dist/sqlite-square.d.ts +12 -13
- package/dist/sqlite-square.js +192 -248
- package/dist/sqlite-values.d.ts +21 -0
- package/dist/sqlite-values.js +78 -0
- package/dist/square-api.d.ts +1 -1
- package/dist/square-api.js +1 -1
- package/dist/square-core.d.ts +1 -1
- package/dist/square-domain.d.ts +21 -7
- package/dist/square-domain.js +93 -94
- package/dist/square-facade.d.ts +12 -66
- package/dist/square-index.d.ts +1 -1
- package/dist/square-index.js +1 -1
- package/dist/square-location.d.ts +6 -1
- package/dist/square-location.js +1 -1
- package/dist/square-receive.d.ts +2 -3
- package/dist/square-sqlite.d.ts +45 -44
- package/dist/square-sqlite.js +308 -764
- package/dist/square-tools.d.ts +8 -0
- package/dist/square-tools.js +39 -0
- package/dist/views.d.ts +6 -6
- package/dist/views.js +15 -9
- package/dist/wake-preview.d.ts +7 -0
- package/dist/wake-preview.js +15 -0
- package/dist/wake-sink.d.ts +2 -2
- package/dist/wake-sink.js +1 -1
- package/dist/wake-transports.d.ts +7 -0
- package/dist/wake-transports.js +42 -0
- package/guides/claude-native.md +13 -10
- package/guides/codex-delivery.md +3 -1
- package/guides/participant-ownership.md +1 -1
- package/guides/row-runtime-delivery-evidence.md +2 -0
- package/guides/row-storage-design.md +19 -44
- package/guides/square-api.md +137 -60
- package/package.json +3 -3
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/types.d.ts +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +28 -41
- package/plugins/pi/square-pi.js +28 -51
- package/dist/square-legacy-framing.d.ts +0 -11
- package/dist/square-legacy-framing.js +0 -64
- package/dist/square-migration-host-ledger.d.ts +0 -26
- package/dist/square-migration-host-ledger.js +0 -169
- package/dist/square-migration.d.ts +0 -30
- package/dist/square-migration.js +0 -599
- package/guides/migration.md +0 -156
package/dist/channel.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { WakeAddress } from './channel-values.js';
|
|
2
|
+
import type { Owner, OperationControl } from './neutral.js';
|
|
3
|
+
import type { HarnessSessionChannel } from './participant-identity.js';
|
|
4
|
+
import type { WakeTransportPort } from './channel-transport.js';
|
|
5
|
+
import type { MetadataMatch, DeliveryDeferral } from './channel-metadata.js';
|
|
6
|
+
import type { MessageId } from './message.js';
|
|
7
|
+
import type { AckResult, ChannelEndpointHold, ChannelEndpointSummary, ChannelHistoryQuery, ChannelHistoryResult, ChannelPendingOptions, ChannelPendingResult, ChannelReceiveResult, ChannelSendInput, ChannelSendResult } from './channel-facade.js';
|
|
4
8
|
export { harnessOwner, decodeHarnessOwner, localUserOwner } from './owner.js';
|
|
5
|
-
export type {
|
|
6
|
-
export type {
|
|
9
|
+
export type { MessageMetadata, WakeAddress } from './channel-values.js';
|
|
10
|
+
export type { MessageId } from './message.js';
|
|
11
|
+
export type { MessageCursor, MessageQuery, MessageSearch, ChannelTruncate, ChannelSendInput, ChannelSendResult, ChannelMessage, ChannelPendingOptions, ChannelPendingResult, ChannelReceiveResult, ChannelHistoryQuery, ChannelHistoryResult, AckResult, ChannelEndpointSummary, ChannelEndpointHold } from './channel-facade.js';
|
|
12
|
+
export type { MetadataMatch, DeliveryDeferral } from './channel-metadata.js';
|
|
13
|
+
export type { Owner, OperationControl } from './neutral.js';
|
|
14
|
+
export type { WakeTransportPort } from './channel-transport.js';
|
|
15
|
+
export type { HarnessSessionChannel } from './participant-identity.js';
|
|
7
16
|
export interface ResolvedHarnessSession {
|
|
8
17
|
readonly channel: HarnessSessionChannel;
|
|
9
18
|
readonly sessionId: string;
|
|
@@ -18,7 +27,6 @@ export interface ChannelOpenInput {
|
|
|
18
27
|
readonly env?: NodeJS.ProcessEnv;
|
|
19
28
|
readonly clock?: () => number;
|
|
20
29
|
readonly wakeTransport?: WakeTransportPort | false;
|
|
21
|
-
readonly resources?: SquareResourceOwner;
|
|
22
30
|
}
|
|
23
31
|
export interface ChannelCreateInput extends ChannelOpenInput {
|
|
24
32
|
readonly force?: boolean;
|
|
@@ -30,16 +38,16 @@ type EndpointOptions = {
|
|
|
30
38
|
};
|
|
31
39
|
type EndpointIdentity = {
|
|
32
40
|
readonly owner: Owner;
|
|
33
|
-
readonly generation:
|
|
41
|
+
readonly generation: string;
|
|
34
42
|
};
|
|
35
|
-
/** A
|
|
43
|
+
/** A trusted handle to one independent message channel. */
|
|
36
44
|
export declare class Channel {
|
|
37
|
-
private
|
|
45
|
+
#private;
|
|
38
46
|
private constructor();
|
|
39
|
-
get location(): string;
|
|
40
47
|
static open(input: ChannelOpenInput, control?: OperationControl): Promise<Channel>;
|
|
41
48
|
static create(input: ChannelCreateInput, control?: OperationControl): Promise<Channel>;
|
|
42
|
-
static inMemory(input?: Omit<ChannelCreateInput, 'path' | '
|
|
49
|
+
static inMemory(input?: Omit<ChannelCreateInput, 'path' | 'force'>): Channel;
|
|
50
|
+
get location(): string;
|
|
43
51
|
attach(name: string, options: EndpointOptions & {
|
|
44
52
|
readonly takeover?: boolean;
|
|
45
53
|
}, control?: OperationControl): Promise<ChannelEndpoint>;
|
|
@@ -47,23 +55,24 @@ export declare class Channel {
|
|
|
47
55
|
endpoint(name: string, options: {
|
|
48
56
|
readonly owner: Owner;
|
|
49
57
|
}): Promise<ChannelEndpoint>;
|
|
50
|
-
endpointsOf(owner: Owner): Promise<readonly
|
|
58
|
+
endpointsOf(owner: Owner): Promise<readonly ChannelEndpointHold[]>;
|
|
59
|
+
listEndpoints(control?: OperationControl): Promise<readonly ChannelEndpointSummary[]>;
|
|
51
60
|
detach(name: string, identity: EndpointIdentity): Promise<true | null>;
|
|
61
|
+
cancelDeliveries(name: string, identity: EndpointIdentity, control?: OperationControl): Promise<boolean>;
|
|
52
62
|
remove(name: string, identity: EndpointIdentity): Promise<boolean>;
|
|
53
|
-
cancelDeliveries(name: string, identity: EndpointIdentity): Promise<boolean>;
|
|
54
63
|
send(input: ChannelSendInput, control?: OperationControl): Promise<ChannelSendResult>;
|
|
64
|
+
history(query?: ChannelHistoryQuery, control?: OperationControl): Promise<ChannelHistoryResult>;
|
|
55
65
|
close(): Promise<void>;
|
|
56
66
|
}
|
|
57
|
-
/**
|
|
67
|
+
/** Fenced to one attached endpoint generation. */
|
|
58
68
|
export declare class ChannelEndpoint {
|
|
59
|
-
private
|
|
60
|
-
private
|
|
61
|
-
constructor(channel: Channel, participant: Participant);
|
|
69
|
+
#private;
|
|
70
|
+
private constructor();
|
|
62
71
|
get name(): string;
|
|
63
|
-
get generation():
|
|
64
|
-
pending(options?:
|
|
65
|
-
ack(ids: readonly
|
|
66
|
-
|
|
72
|
+
get generation(): string;
|
|
73
|
+
pending(options?: ChannelPendingOptions, control?: OperationControl): Promise<ChannelPendingResult>;
|
|
74
|
+
ack(ids: readonly MessageId[], control?: OperationControl): Promise<AckResult>;
|
|
75
|
+
receive(options?: ChannelPendingOptions, control?: OperationControl): Promise<ChannelReceiveResult>;
|
|
67
76
|
deferDelivery(input: Readonly<{
|
|
68
77
|
match: MetadataMatch;
|
|
69
78
|
durationMs: number;
|
|
@@ -71,4 +80,5 @@ export declare class ChannelEndpoint {
|
|
|
71
80
|
renewDeliveryDeferral(id: string, durationMs: number, control?: OperationControl): Promise<DeliveryDeferral | null>;
|
|
72
81
|
releaseDeliveryDeferral(id: string, control?: OperationControl): Promise<boolean>;
|
|
73
82
|
send(input: Omit<ChannelSendInput, 'from'>, control?: OperationControl): Promise<ChannelSendResult>;
|
|
83
|
+
leave(control?: OperationControl): Promise<void>;
|
|
74
84
|
}
|
package/dist/channel.js
CHANGED
|
@@ -1,92 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SquareError } from './model.js';
|
|
3
|
-
import { harnessOwner } from './owner.js';
|
|
4
|
-
import { harnessSessionSources } from './participant-identity.js';
|
|
5
|
-
import { Square } from './square-api.js';
|
|
6
|
-
import { squareLocation } from './square-location.js';
|
|
1
|
+
import { Channel as ChannelCore, resolveHarnessSession as resolveSession } from './channel-internal.js';
|
|
7
2
|
export { harnessOwner, decodeHarnessOwner, localUserOwner } from './owner.js';
|
|
8
3
|
export function resolveHarnessSession(env = process.env) {
|
|
9
|
-
|
|
10
|
-
const sessionId = env[variable]?.trim();
|
|
11
|
-
if (!sessionId)
|
|
12
|
-
continue;
|
|
13
|
-
const agentId = channel === 'claude-code' && env.CLAUDE_CODE_CHILD_SESSION?.trim() === '1'
|
|
14
|
-
? env.CLAUDE_CODE_AGENT_ID?.trim() || undefined : undefined;
|
|
15
|
-
const wakeAddress = channel === 'codex' ? codexWakeAddress(sessionId, env)
|
|
16
|
-
: channel === 'paseo' ? { kind: 'paseo', address: { agentId: sessionId } } : undefined;
|
|
17
|
-
return { channel, sessionId, ...(agentId === undefined ? {} : { agentId }),
|
|
18
|
-
owner: harnessOwner({ channel, session: sessionId, ...(agentId === undefined ? {} : { agent: agentId }) }),
|
|
19
|
-
...(wakeAddress === undefined ? {} : { wakeAddress }) };
|
|
20
|
-
}
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
function explicitLocation(input) {
|
|
24
|
-
if (typeof input?.path !== 'string' || input.path.trim() === '')
|
|
25
|
-
throw new SquareError('invalid_args', 'Channel path is required.');
|
|
26
|
-
return squareLocation(input);
|
|
4
|
+
return resolveSession(env);
|
|
27
5
|
}
|
|
28
|
-
|
|
6
|
+
const endpointKey = Symbol('ChannelEndpoint');
|
|
7
|
+
let wrapEndpoint;
|
|
8
|
+
/** A trusted handle to one independent message channel. */
|
|
29
9
|
export class Channel {
|
|
30
|
-
|
|
31
|
-
constructor(
|
|
32
|
-
this.square = square;
|
|
33
|
-
}
|
|
34
|
-
get location() { return this.square.location; }
|
|
10
|
+
#core;
|
|
11
|
+
constructor(core) { this.#core = core; }
|
|
35
12
|
static async open(input, control) {
|
|
36
|
-
|
|
37
|
-
return new Channel(await Square.at({ ...input, path }, control));
|
|
13
|
+
return new Channel(await ChannelCore.open(input, control));
|
|
38
14
|
}
|
|
39
15
|
static async create(input, control) {
|
|
40
|
-
|
|
41
|
-
return new Channel(await Square.build({ ...input, path, hardCap: null, markdown: input.description ?? '# Channel\n' }, control));
|
|
16
|
+
return new Channel(await ChannelCore.create(input, control));
|
|
42
17
|
}
|
|
43
18
|
static inMemory(input = {}) {
|
|
44
|
-
return new Channel(
|
|
19
|
+
return new Channel(ChannelCore.inMemory(input));
|
|
45
20
|
}
|
|
21
|
+
get location() { return this.#core.location; }
|
|
46
22
|
async attach(name, options, control) {
|
|
47
|
-
return
|
|
23
|
+
return wrapEndpoint(await this.#core.attach(name, options, control));
|
|
48
24
|
}
|
|
49
25
|
async reattach(name, options, control) {
|
|
50
|
-
const
|
|
51
|
-
return
|
|
26
|
+
const endpoint = await this.#core.reattach(name, options, control);
|
|
27
|
+
return endpoint === null ? null : wrapEndpoint(endpoint);
|
|
52
28
|
}
|
|
53
29
|
async endpoint(name, options) {
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
endpointsOf(owner) { return this.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
cancelDeliveries(name, identity) { return this.
|
|
60
|
-
|
|
61
|
-
|
|
30
|
+
return wrapEndpoint(await this.#core.endpoint(name, options));
|
|
31
|
+
}
|
|
32
|
+
endpointsOf(owner) { return this.#core.endpointsOf(owner); }
|
|
33
|
+
listEndpoints(control) { return this.#core.listEndpoints(control); }
|
|
34
|
+
detach(name, identity) { return this.#core.detach(name, identity); }
|
|
35
|
+
cancelDeliveries(name, identity, control) { return this.#core.cancelDeliveries(name, identity, control); }
|
|
36
|
+
remove(name, identity) { return this.#core.remove(name, identity); }
|
|
37
|
+
send(input, control) { return this.#core.send(input, control); }
|
|
38
|
+
history(query, control) { return this.#core.history(query, control); }
|
|
39
|
+
close() { return this.#core.close(); }
|
|
62
40
|
}
|
|
63
|
-
/**
|
|
41
|
+
/** Fenced to one attached endpoint generation. */
|
|
64
42
|
export class ChannelEndpoint {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
renewDeliveryDeferral(id, durationMs, control) {
|
|
84
|
-
return this.participant.renewDeliveryDeferral(id, durationMs, control);
|
|
85
|
-
}
|
|
86
|
-
releaseDeliveryDeferral(id, control) {
|
|
87
|
-
return this.participant.releaseDeliveryDeferral(id, control);
|
|
88
|
-
}
|
|
89
|
-
send(input, control) {
|
|
90
|
-
return this.channel.send({ ...input, from: this.name }, control);
|
|
91
|
-
}
|
|
43
|
+
#core;
|
|
44
|
+
constructor(core, key) {
|
|
45
|
+
if (key !== endpointKey)
|
|
46
|
+
throw new TypeError('Channel endpoints are obtained from a Channel.');
|
|
47
|
+
this.#core = core;
|
|
48
|
+
}
|
|
49
|
+
static { wrapEndpoint = core => new ChannelEndpoint(core, endpointKey); }
|
|
50
|
+
get name() { return this.#core.name; }
|
|
51
|
+
get generation() { return this.#core.generation; }
|
|
52
|
+
pending(options, control) { return this.#core.pending(options, control); }
|
|
53
|
+
ack(ids, control) { return this.#core.ack(ids, control); }
|
|
54
|
+
receive(options, control) { return this.#core.receive(options, control); }
|
|
55
|
+
deferDelivery(input, control) { return this.#core.deferDelivery(input, control); }
|
|
56
|
+
renewDeliveryDeferral(id, durationMs, control) { return this.#core.renewDeliveryDeferral(id, durationMs, control); }
|
|
57
|
+
releaseDeliveryDeferral(id, control) { return this.#core.releaseDeliveryDeferral(id, control); }
|
|
58
|
+
send(input, control) { return this.#core.send(input, control); }
|
|
59
|
+
leave(control) { return this.#core.leave(control); }
|
|
92
60
|
}
|
|
@@ -33,7 +33,7 @@ export async function recordClaudeDeliveryStatus(input, env = process.env) {
|
|
|
33
33
|
continue;
|
|
34
34
|
const { seat, evidence } = match[0];
|
|
35
35
|
const ref = { participant: seat.participant, owner: seat.owner, generation: seat.generation };
|
|
36
|
-
return (await artifact.transactAs({ kind: 'participant', seat: ref }, (facts) => facts.observeNativeDelivery({ seat: ref, claimToken: evidence.claimToken, observation: {
|
|
36
|
+
return (await artifact.transactAs({ kind: 'participant', seat: ref }, (facts) => facts.channel.observeNativeDelivery({ seat: ref, claimToken: evidence.claimToken, observation: {
|
|
37
37
|
eventId: input.eventId, messageId: input.messageId, state: input.state,
|
|
38
38
|
...(input.reason === undefined ? {} : { reason: input.reason }), observedAt: input.observedAt,
|
|
39
39
|
} }))).value;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function nativeTokens(text: string): string[];
|
|
3
|
-
export declare function nativePayload(token: string, preview: string): string;
|
|
4
|
-
export declare function createClaudeWakeTransport(env?: NodeJS.ProcessEnv): WakeTransportPort;
|
|
1
|
+
export { createClaudeWakeTransport, nativeTokens, nativePayload } from './claude-transport.js';
|
|
5
2
|
/** Recognize the whole frame first; one inactive token vetoes it before any evidence/receipt write. */
|
|
6
3
|
export declare function observeClaudeDelivery(sessionId: string, text: string, operation: 'guard' | 'admitted' | 'stored', env?: NodeJS.ProcessEnv): Promise<{
|
|
7
4
|
recognized: boolean;
|
|
@@ -11,5 +8,5 @@ export type ClaudeBinding = {
|
|
|
11
8
|
readonly location: string;
|
|
12
9
|
readonly participant: string;
|
|
13
10
|
readonly session: string;
|
|
14
|
-
readonly generation?:
|
|
11
|
+
readonly generation?: string;
|
|
15
12
|
};
|
package/dist/claude-delivery.js
CHANGED
|
@@ -1,87 +1,11 @@
|
|
|
1
|
-
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { createHash, randomUUID } from 'node:crypto';
|
|
3
1
|
import { createArtifactPort } from './artifact.js';
|
|
4
2
|
import { presentPending } from './presentation-operations.js';
|
|
5
|
-
import {
|
|
6
|
-
import { parseActivityId } from './square-core.js';
|
|
3
|
+
import { nativePendingHead } from './delivery.js';
|
|
7
4
|
import { decodeHarnessOwner } from './owner.js';
|
|
8
5
|
import { indexedSquareEntries } from './square-index.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export function nativeTokens(text) { return [...text.matchAll(marker)].map((match) => match[1]); }
|
|
13
|
-
export function nativePayload(token, preview) { return `[square-inbox:${token}]\n${preview}\n[/square-inbox:${token}]`; }
|
|
14
|
-
function nativeSupported(route) { return route.address.loaded === 'true' && !!route.address.endpoint; }
|
|
15
|
-
function hashPayload(payload) { return createHash('sha256').update(payload).digest('hex'); }
|
|
16
|
-
function previewFacts(facts, request) {
|
|
17
|
-
const index = parseActivityId(request.activity);
|
|
18
|
-
if (index === undefined || request.route.kind !== 'claude-native' || request.route.address.endpoint === undefined)
|
|
19
|
-
return undefined;
|
|
20
|
-
return nativePendingPreview(facts, { location: request.location, routeKind: 'claude-native', generation: request.seat.generation,
|
|
21
|
-
address: request.route.address,
|
|
22
|
-
participant: request.participant, actIndex: index, now: Date.now() });
|
|
23
|
-
}
|
|
24
|
-
async function preview(artifact, request) {
|
|
25
|
-
return (await artifact.read((facts) => previewFacts(facts, request))).value;
|
|
26
|
-
}
|
|
27
|
-
async function writeClaudeWake(sessionId, endpoint, messageId, payload, timeoutMs, signal) {
|
|
28
|
-
const result = await writeClaudeNative({ sessionId, endpoint, messageId }, payload, { deadline: Date.now() + timeoutMs, signal });
|
|
29
|
-
if (result.outcome === 'unavailable')
|
|
30
|
-
return { outcome: 'failed', signature: 'claude_endpoint_unavailable', message: result.message };
|
|
31
|
-
return { outcome: 'unknown', signature: 'native_admission_unconfirmed', message: result.outcome === 'written' ? 'Claude accepted the local write; native admission is unconfirmed.' : result.message };
|
|
32
|
-
}
|
|
33
|
-
export function createClaudeWakeTransport(env = process.env) {
|
|
34
|
-
return {
|
|
35
|
-
async probe(route) {
|
|
36
|
-
if (!nativeSupported(route))
|
|
37
|
-
return { outcome: 'not-capable', diagnostic: 'Claude native inbox unavailable: a loaded interactive Square mod is required.' };
|
|
38
|
-
try {
|
|
39
|
-
return (await stat(route.address.endpoint)).isSocket() || { outcome: 'not-capable', diagnostic: 'Claude native inbox endpoint is not a socket.' };
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return { outcome: 'not-capable', diagnostic: 'Claude native inbox endpoint unavailable.' };
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
attempt: (request, timeoutMs, beforeSend) => dispatchClaude(request, timeoutMs, beforeSend, env),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
async function dispatchClaude(request, timeoutMs, beforeSend, env = process.env) {
|
|
49
|
-
void env;
|
|
50
|
-
const signal = AbortSignal.timeout(timeoutMs);
|
|
51
|
-
if (!nativeSupported(request.route) || request.artifact === undefined || request.claimToken === undefined)
|
|
52
|
-
return { outcome: 'not-capable', diagnostic: 'Claude native delivery needs a current artifact claim and loaded inbox.' };
|
|
53
|
-
if (signal.aborted || !await beforeSend())
|
|
54
|
-
return { outcome: 'unknown', signature: 'native_send_suppressed' };
|
|
55
|
-
const prepared = await preview(request.artifact, request);
|
|
56
|
-
if (prepared === undefined)
|
|
57
|
-
return { outcome: 'not-capable', diagnostic: 'Claude activity is no longer current.' };
|
|
58
|
-
const messageId = randomUUID();
|
|
59
|
-
const payload = nativePayload(request.claimToken, prepared.payload);
|
|
60
|
-
const correlation = { harness: 'claude', token: request.claimToken, messageId, payloadHash: hashPayload(payload) };
|
|
61
|
-
if (!await request.artifact.prepareDelivery({ seat: request.seat, claimToken: request.claimToken, correlation }))
|
|
62
|
-
return { outcome: 'not-capable', diagnostic: 'Claude delivery claim is no longer current.' };
|
|
63
|
-
const fresh = await preview(request.artifact, request);
|
|
64
|
-
if (fresh === undefined || nativePayload(request.claimToken, fresh.payload) !== payload)
|
|
65
|
-
return { outcome: 'not-capable', diagnostic: 'Claude activity changed before native write.' };
|
|
66
|
-
if (signal.aborted || !await beforeSend())
|
|
67
|
-
return { outcome: 'not-capable', diagnostic: 'Claude activity was consumed before native write.' };
|
|
68
|
-
const sessionId = request.route.address.sessionId;
|
|
69
|
-
if (sessionId === undefined)
|
|
70
|
-
return { outcome: 'not-capable', diagnostic: 'Claude native route has no session address.' };
|
|
71
|
-
return writeClaudeWake(sessionId, request.route.address.endpoint, messageId, payload, timeoutMs, signal);
|
|
72
|
-
}
|
|
73
|
-
function currentPayload(facts, request) {
|
|
74
|
-
const seat = facts.seat(request.participant), evidence = facts.deliveryByToken(request.claimToken);
|
|
75
|
-
if (seat === undefined || seat.attachment !== 'attached' || evidence === undefined || seat.generation !== evidence.generation
|
|
76
|
-
|| seat.generation !== request.seat.generation || seat.owner !== request.seat.owner
|
|
77
|
-
|| evidence.activity !== request.activity || !['dispatching', 'unknown', 'accepted'].includes(evidence.outcome))
|
|
78
|
-
return undefined;
|
|
79
|
-
const native = previewFacts(facts, request);
|
|
80
|
-
if (native === undefined)
|
|
81
|
-
return undefined;
|
|
82
|
-
const payload = nativePayload(request.claimToken, native.payload);
|
|
83
|
-
return evidence.correlation?.payloadHash === hashPayload(payload) ? payload : undefined;
|
|
84
|
-
}
|
|
6
|
+
import { parseMessageId } from './message.js';
|
|
7
|
+
export { createClaudeWakeTransport, nativeTokens, nativePayload } from './claude-transport.js';
|
|
8
|
+
import { nativeTokens, hashPayload } from './claude-transport.js';
|
|
85
9
|
async function rowsForSession(sessionId, env, tokens) {
|
|
86
10
|
const rows = [];
|
|
87
11
|
const candidates = (await indexedSquareEntries({}, env)).filter(entry => {
|
|
@@ -97,16 +21,9 @@ async function rowsForSession(sessionId, env, tokens) {
|
|
|
97
21
|
if (evidence?.kind !== 'wake' || evidence.correlation?.harness !== 'claude' || evidence.correlation.token !== token
|
|
98
22
|
|| evidence.route?.kind !== 'claude-native' || evidence.route.address.sessionId !== sessionId)
|
|
99
23
|
return [];
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (seat === undefined || item?.kind !== 'say')
|
|
104
|
-
return [row];
|
|
105
|
-
const route = { location, participant: seat.participant,
|
|
106
|
-
...evidence.route, updatedAt: evidence.at };
|
|
107
|
-
const request = { location, participant: seat.participant, activity: evidence.activity,
|
|
108
|
-
actor: item.actor, seat: asSeatRef(seat), claimToken: token, attemptN: evidence.attemptN, route, artifact };
|
|
109
|
-
return [{ ...row, request, payload: currentPayload(facts, request) }];
|
|
24
|
+
const seat = facts.seat(evidence.participant);
|
|
25
|
+
return [{ artifact, evidence, location, index: parseMessageId(evidence.message),
|
|
26
|
+
...(seat === undefined ? {} : { seat: { participant: evidence.participant, owner: seat.owner, generation: evidence.generation } }) }];
|
|
110
27
|
}));
|
|
111
28
|
rows.push(...found.value);
|
|
112
29
|
if (found.value.length === 0)
|
|
@@ -118,6 +35,28 @@ async function rowsForSession(sessionId, env, tokens) {
|
|
|
118
35
|
}
|
|
119
36
|
return rows;
|
|
120
37
|
}
|
|
38
|
+
/** The token, participant, activity and captured generation must still be the exact wake. */
|
|
39
|
+
function sameCapturedEvidence(facts, row) {
|
|
40
|
+
const token = row.evidence.claimToken;
|
|
41
|
+
const evidence = token === undefined ? undefined : facts.deliveryByToken(token);
|
|
42
|
+
return token !== undefined && evidence !== undefined && row.seat !== undefined && row.seat.participant === row.evidence.participant
|
|
43
|
+
&& row.seat.generation === row.evidence.generation && evidence.kind === 'wake' && evidence.claimToken === token
|
|
44
|
+
&& evidence.participant === row.evidence.participant && evidence.message === row.evidence.message
|
|
45
|
+
&& evidence.generation === row.evidence.generation
|
|
46
|
+
&& evidence.correlation?.harness === 'claude' && evidence.correlation.token === token
|
|
47
|
+
&& evidence.correlation.payloadHash === row.evidence.correlation?.payloadHash
|
|
48
|
+
&& ['dispatching', 'unknown', 'accepted'].includes(evidence.outcome);
|
|
49
|
+
}
|
|
50
|
+
function capturedInput(row, now) {
|
|
51
|
+
if (row.seat === undefined || row.index === undefined || row.evidence.route === undefined)
|
|
52
|
+
return undefined;
|
|
53
|
+
return { location: row.location, participant: row.evidence.participant, generation: row.seat.generation,
|
|
54
|
+
owner: row.seat.owner, index: row.index, route: row.evidence.route, now };
|
|
55
|
+
}
|
|
56
|
+
function currentRow(facts, row, now) {
|
|
57
|
+
const input = capturedInput(row, now);
|
|
58
|
+
return input !== undefined && sameCapturedEvidence(facts, row) && nativePendingHead(facts, input) !== undefined;
|
|
59
|
+
}
|
|
121
60
|
/** Recognize the whole frame first; one inactive token vetoes it before any evidence/receipt write. */
|
|
122
61
|
export async function observeClaudeDelivery(sessionId, text, operation, env = process.env) {
|
|
123
62
|
const tokens = nativeTokens(text);
|
|
@@ -127,25 +66,39 @@ export async function observeClaudeDelivery(sessionId, text, operation, env = pr
|
|
|
127
66
|
const recognized = rows.length > 0;
|
|
128
67
|
const frames = [...text.matchAll(/(?:^|\n)(\[square-inbox:([a-zA-Z0-9-]+)\]\n[\s\S]*?\n\[\/square-inbox:\2\])(?=\n|$)/g)];
|
|
129
68
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
69
|
+
// Every recognized token is vetted before any row can write: actual bytes against the
|
|
70
|
+
// stored correlation hash, then independent current eligibility.
|
|
71
|
+
const contentCurrent = rows.every(row => {
|
|
72
|
+
const token = row.evidence.claimToken, hash = row.evidence.correlation?.payloadHash;
|
|
73
|
+
if (token === undefined || hash === undefined || row.seat === undefined || row.index === undefined
|
|
74
|
+
|| !['dispatching', 'unknown', 'accepted'].includes(row.evidence.outcome))
|
|
75
|
+
return false;
|
|
76
|
+
const matching = frames.filter(frame => frame[2] === token);
|
|
77
|
+
return matching.length === tokens.filter(candidate => candidate === token).length
|
|
78
|
+
&& matching.every(frame => hashPayload(frame[1]) === hash);
|
|
79
|
+
});
|
|
80
|
+
if (!recognized || !contentCurrent)
|
|
135
81
|
return { recognized, current: false };
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
for (const row of rows) {
|
|
84
|
+
if (!(await row.artifact.read(facts => currentRow(facts, row, now))).value)
|
|
85
|
+
return { recognized, current: false };
|
|
86
|
+
}
|
|
136
87
|
for (const row of rows) {
|
|
137
88
|
if (operation === 'guard')
|
|
138
89
|
continue;
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
90
|
+
const seat = row.seat;
|
|
91
|
+
const current = (facts) => currentRow(facts, row, Date.now());
|
|
92
|
+
const admitted = await row.artifact.transactAs({ kind: 'participant', seat }, facts => current(facts) && facts.channel.completeDelivery({ seat, message: row.evidence.message,
|
|
93
|
+
claimToken: row.evidence.claimToken, outcome: 'accepted', at: Date.now() })).catch(() => ({ value: false }));
|
|
142
94
|
if (!admitted.value)
|
|
143
95
|
return { recognized, current: false };
|
|
144
|
-
if (operation === 'stored')
|
|
145
|
-
await presentPending({ artifact: row.artifact, location:
|
|
146
|
-
//
|
|
147
|
-
participant:
|
|
148
|
-
|
|
96
|
+
if (operation === 'stored') {
|
|
97
|
+
await presentPending({ artifact: row.artifact, location: row.location,
|
|
98
|
+
// Persisted coverage decides consumption; the current renderer never guesses.
|
|
99
|
+
participant: row.evidence.participant, message: row.evidence.message, seat, observationOf: row.evidence.claimToken,
|
|
100
|
+
markSeen: row.evidence.coverage !== 'clipped', sink: { present() { } }, current });
|
|
101
|
+
}
|
|
149
102
|
}
|
|
150
103
|
return { recognized, current: true };
|
|
151
104
|
}
|
package/dist/claude-mod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { operationEnv } from './participant-identity.js';
|
|
2
|
-
import { createArtifactPort } from './artifact.js';
|
|
2
|
+
import { channelArtifact, createArtifactPort } from './artifact.js';
|
|
3
3
|
import { recordClaudeDeliveryStatus } from './claude-delivery-status.js';
|
|
4
4
|
import { Square } from './square-api.js';
|
|
5
5
|
import { observeClaudeDelivery } from './claude-delivery.js';
|
|
@@ -104,9 +104,9 @@ export async function runClaudeMod(inputText, env = process.env) {
|
|
|
104
104
|
let beforeIndex;
|
|
105
105
|
for (;;) {
|
|
106
106
|
const page = facts.activityHeads({ beforeIndex }, { edge: 'newest', limit: 100 });
|
|
107
|
-
const last =
|
|
107
|
+
const last = page.items.find((activity) => activity.at <= cutoff && activity.messageIndex !== undefined);
|
|
108
108
|
if (last !== undefined)
|
|
109
|
-
return last.
|
|
109
|
+
return last.messageIndex;
|
|
110
110
|
if (!page.hasMore)
|
|
111
111
|
return -1;
|
|
112
112
|
beforeIndex = page.items[0].index;
|
|
@@ -148,7 +148,7 @@ export async function runClaudeMod(inputText, env = process.env) {
|
|
|
148
148
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
149
149
|
let indices;
|
|
150
150
|
try {
|
|
151
|
-
indices = await sweepPending({ artifact, location, now: Date.now(), graceMs: 0, limit: 8 });
|
|
151
|
+
indices = await sweepPending({ artifact: channelArtifact(artifact), location, now: Date.now(), graceMs: 0, limit: 8 });
|
|
152
152
|
}
|
|
153
153
|
catch (error) {
|
|
154
154
|
if (error instanceof InternalSquareError && error.code === 'not_found')
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { WakeTransportPort } from './channel-transport.js';
|
|
2
|
+
export declare function nativeTokens(text: string): string[];
|
|
3
|
+
export declare function nativePayload(token: string, preview: string): string;
|
|
4
|
+
export declare function hashPayload(payload: string): string;
|
|
5
|
+
export declare function createClaudeWakeTransport(env?: NodeJS.ProcessEnv): WakeTransportPort;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { writeClaudeNative } from './packages/agent-delivery/src/claude-native.js';
|
|
4
|
+
const marker = /(?:^|\n)\[square-inbox:([a-zA-Z0-9-]+)\](?:\n|$)/g;
|
|
5
|
+
export function nativeTokens(text) { return [...text.matchAll(marker)].map((match) => match[1]); }
|
|
6
|
+
export function nativePayload(token, preview) { return `[square-inbox:${token}]\n${preview}\n[/square-inbox:${token}]`; }
|
|
7
|
+
function nativeSupported(route) { return route.address.loaded === 'true' && !!route.address.endpoint; }
|
|
8
|
+
export function hashPayload(payload) { return createHash('sha256').update(payload).digest('hex'); }
|
|
9
|
+
async function preview(request) {
|
|
10
|
+
return request.presentation;
|
|
11
|
+
}
|
|
12
|
+
async function writeClaudeWake(sessionId, endpoint, messageId, payload, timeoutMs, signal) {
|
|
13
|
+
const result = await writeClaudeNative({ sessionId, endpoint, messageId }, payload, { deadline: Date.now() + timeoutMs, signal });
|
|
14
|
+
if (result.outcome === 'unavailable')
|
|
15
|
+
return { outcome: 'failed', signature: 'claude_endpoint_unavailable', message: result.message };
|
|
16
|
+
return { outcome: 'unknown', signature: 'native_admission_unconfirmed', message: result.outcome === 'written' ? 'Claude accepted the local write; native admission is unconfirmed.' : result.message };
|
|
17
|
+
}
|
|
18
|
+
export function createClaudeWakeTransport(env = process.env) {
|
|
19
|
+
return {
|
|
20
|
+
async probe(route) {
|
|
21
|
+
if (!nativeSupported(route))
|
|
22
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native inbox unavailable: a loaded interactive Square mod is required.' };
|
|
23
|
+
try {
|
|
24
|
+
return (await stat(route.address.endpoint)).isSocket() || { outcome: 'not-capable', diagnostic: 'Claude native inbox endpoint is not a socket.' };
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native inbox endpoint unavailable.' };
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
attempt: (request, timeoutMs, beforeSend) => dispatchClaude(request, timeoutMs, beforeSend, env),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async function dispatchClaude(request, timeoutMs, beforeSend, env = process.env) {
|
|
34
|
+
void env;
|
|
35
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
36
|
+
if (!nativeSupported(request.route) || request.claimToken === undefined)
|
|
37
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native delivery needs a current artifact claim and loaded inbox.' };
|
|
38
|
+
if (signal.aborted || !await beforeSend())
|
|
39
|
+
return { outcome: 'unknown', signature: 'native_send_suppressed' };
|
|
40
|
+
const prepared = await preview(request);
|
|
41
|
+
if (prepared === undefined)
|
|
42
|
+
return { outcome: 'not-capable', diagnostic: 'Claude activity is no longer current.' };
|
|
43
|
+
const messageId = randomUUID();
|
|
44
|
+
const payload = nativePayload(request.claimToken, prepared.payload);
|
|
45
|
+
const correlation = { harness: 'claude', token: request.claimToken, messageId, payloadHash: hashPayload(payload) };
|
|
46
|
+
if (!await request.channel.prepare({ correlation, coverage: prepared.coverage,
|
|
47
|
+
...(prepared.description === undefined ? {} : { description: prepared.description }) }))
|
|
48
|
+
return { outcome: 'not-capable', diagnostic: 'Claude delivery claim is no longer current.' };
|
|
49
|
+
const fresh = await preview(request);
|
|
50
|
+
if (fresh === undefined || nativePayload(request.claimToken, fresh.payload) !== payload)
|
|
51
|
+
return { outcome: 'not-capable', diagnostic: 'Claude activity changed before native write.' };
|
|
52
|
+
if (signal.aborted || !await beforeSend())
|
|
53
|
+
return { outcome: 'not-capable', diagnostic: 'Claude activity was consumed before native write.' };
|
|
54
|
+
const sessionId = request.route.address.sessionId;
|
|
55
|
+
if (sessionId === undefined)
|
|
56
|
+
return { outcome: 'not-capable', diagnostic: 'Claude native route has no session address.' };
|
|
57
|
+
return writeClaudeWake(sessionId, request.route.address.endpoint, messageId, payload, timeoutMs, signal);
|
|
58
|
+
}
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Owner } from '../square-api.js';
|
|
2
|
-
import { type HardCap } from '../model.js';
|
|
2
|
+
import { type HardCap, type WakeAddress } from '../model.js';
|
|
3
3
|
import { Square } from '../square-api.js';
|
|
4
4
|
import type { OperationControl } from '../square-facade.js';
|
|
5
5
|
export interface CommandContext {
|
|
@@ -46,7 +46,7 @@ export declare function squareInput(context: CommandContext): {
|
|
|
46
46
|
};
|
|
47
47
|
export declare function commandIdentity(env: NodeJS.ProcessEnv, explicit?: Owner): {
|
|
48
48
|
owner: Owner;
|
|
49
|
-
wakeAddress?:
|
|
49
|
+
wakeAddress?: WakeAddress;
|
|
50
50
|
};
|
|
51
51
|
/** Adapter lifetime only; each callback uses the actual public resource API. */
|
|
52
52
|
export declare function withSquare<T>(context: CommandContext, run: (square: Square) => Promise<T>, control?: OperationControl): Promise<T>;
|
package/dist/cli/context.js
CHANGED
|
@@ -3,9 +3,5 @@ interface DoctorResult {
|
|
|
3
3
|
output: string;
|
|
4
4
|
exitCode?: number;
|
|
5
5
|
}
|
|
6
|
-
interface MigrateResult {
|
|
7
|
-
output: string;
|
|
8
|
-
}
|
|
9
|
-
export declare const migrateCommand: CommandSpec<undefined, MigrateResult>;
|
|
10
6
|
export declare const doctorCommand: CommandSpec<undefined, DoctorResult>;
|
|
11
7
|
export {};
|
|
@@ -1,30 +1,6 @@
|
|
|
1
|
-
import { diagnoseSquare
|
|
2
|
-
import {
|
|
1
|
+
import { diagnoseSquare } from '../square-api.js';
|
|
2
|
+
import { renderDoctorClean, renderDoctorUnfixable, withPathOutput } from '../presentation.js';
|
|
3
3
|
import { requireSquarePath, squareInput, usage } from './context.js';
|
|
4
|
-
export const migrateCommand = {
|
|
5
|
-
parse(argv, context) {
|
|
6
|
-
if (argv.length > 0)
|
|
7
|
-
usage(context.command);
|
|
8
|
-
return undefined;
|
|
9
|
-
},
|
|
10
|
-
async execute(_intent, context) {
|
|
11
|
-
const squarePath = requireSquarePath(context);
|
|
12
|
-
const outcome = await migrateSquare(squareInput(context));
|
|
13
|
-
const body = outcome.status === 'migrated'
|
|
14
|
-
? [
|
|
15
|
-
'✓ migrated to current row storage',
|
|
16
|
-
...(outcome.counts === undefined ? [] : [
|
|
17
|
-
` · ${outcome.counts.activities} activities · ${outcome.counts.receipts} receipts · ${outcome.counts.leases} leases · ${outcome.counts.routes} routes`,
|
|
18
|
-
` · ${outcome.counts.recoveredSeats} recovered seats · ${outcome.counts.unownedStanding} unowned standing · ${outcome.counts.sharedBodySeats} shared-body seats · ${outcome.counts.skippedEvidence} skipped evidence`,
|
|
19
|
-
]),
|
|
20
|
-
].join('\n')
|
|
21
|
-
: '· already current format — nothing changed';
|
|
22
|
-
return { output: withPathOutput(squarePath, body, { participantCount: outcome.standing }) };
|
|
23
|
-
},
|
|
24
|
-
present(result) {
|
|
25
|
-
process.stdout.write(result.output);
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
4
|
export const doctorCommand = {
|
|
29
5
|
parse(argv, context) {
|
|
30
6
|
if (argv.length > 0)
|
|
@@ -34,9 +10,6 @@ export const doctorCommand = {
|
|
|
34
10
|
async execute(_intent, context) {
|
|
35
11
|
const squarePath = requireSquarePath(context);
|
|
36
12
|
const diagnosis = await diagnoseSquare(squareInput(context));
|
|
37
|
-
if (diagnosis.migrationRequired !== undefined) {
|
|
38
|
-
return { output: withPathOutput(squarePath, `${diagnosis.migrationRequired}\n${commandPrefix(squarePath)} migrate\n`), exitCode: 2 };
|
|
39
|
-
}
|
|
40
13
|
if (diagnosis.unfixable !== undefined || diagnosis.standingCount === undefined) {
|
|
41
14
|
return {
|
|
42
15
|
output: withPathOutput(squarePath, renderDoctorUnfixable(diagnosis.unfixable ?? 'the artifact could not be decoded')),
|