@astrosheep/square 0.3.58 → 0.3.62
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 +1 -1
- package/claude-plugin/skills/square/SKILL.md +5 -7
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity.d.ts +6 -2
- package/dist/activity.js +170 -133
- package/dist/artifact.d.ts +4 -0
- package/dist/artifact.js +43 -14
- package/dist/attention-presentation.d.ts +1 -0
- package/dist/attention-presentation.js +21 -19
- package/dist/automatic-session.js +16 -26
- package/dist/boundary-presentation.d.ts +1 -2
- package/dist/boundary-presentation.js +4 -19
- package/dist/catch-decisions.js +1 -1
- package/dist/cli/context.d.ts +2 -0
- package/dist/cli/context.js +17 -33
- package/dist/cli/harness-command.js +1 -1
- package/dist/cli/mcp-server-command.d.ts +2 -0
- package/dist/cli/mcp-server-command.js +13 -0
- package/dist/cli/observation-commands.js +132 -64
- package/dist/cli/program.js +36 -9
- package/dist/cli/registry.js +2 -0
- package/dist/cli/square-commands.d.ts +1 -1
- package/dist/cli/square-commands.js +103 -133
- package/dist/decisions.d.ts +4 -0
- package/dist/decisions.js +82 -34
- package/dist/delivery-operations.d.ts +1 -2
- package/dist/delivery-operations.js +1 -4
- package/dist/file-changes.d.ts +12 -0
- package/dist/file-changes.js +235 -0
- package/dist/help.js +4 -8
- package/dist/host-ledger-file-adapter.d.ts +15 -13
- package/dist/host-ledger-file-adapter.js +131 -79
- package/dist/host-ledger-root.d.ts +2 -0
- package/dist/host-ledger-root.js +9 -0
- package/dist/host-ledger.d.ts +4 -24
- package/dist/inbox.d.ts +10 -5
- package/dist/inbox.js +152 -67
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/list.js +12 -9
- package/dist/mcp.d.ts +7 -0
- package/dist/mcp.js +122 -0
- package/dist/mention-parse.d.ts +8 -0
- package/dist/mention-parse.js +107 -0
- package/dist/model.d.ts +5 -0
- package/dist/model.js +4 -1
- package/dist/notifications.d.ts +1 -0
- package/dist/notifications.js +25 -20
- package/dist/participant-host.js +2 -2
- package/dist/ports.d.ts +2 -9
- package/dist/presentation.d.ts +19 -1
- package/dist/presentation.js +111 -73
- package/dist/presented.js +2 -1
- package/dist/registry.d.ts +8 -4
- package/dist/registry.js +43 -76
- package/dist/routes.d.ts +19 -2
- package/dist/routes.js +48 -5
- package/dist/runtime.d.ts +10 -0
- package/dist/runtime.js +39 -0
- package/dist/square-actions.d.ts +26 -13
- package/dist/square-actions.js +203 -87
- package/dist/square-application.d.ts +58 -0
- package/dist/square-application.js +183 -0
- package/dist/square-facade.d.ts +24 -9
- package/dist/square-file-adapter.d.ts +5 -12
- package/dist/square-file-adapter.js +12 -64
- package/dist/square-projections.d.ts +3 -2
- package/dist/square-projections.js +12 -3
- package/dist/square-storage.js +27 -34
- package/dist/square-wiring.d.ts +12 -7
- package/dist/square-wiring.js +36 -32
- package/dist/state-cell.d.ts +1 -1
- package/dist/stream.js +31 -27
- package/dist/tty-style.d.ts +7 -0
- package/dist/tty-style.js +13 -0
- package/dist/views.d.ts +3 -3
- package/dist/views.js +10 -9
- package/dist/wake-attempts.js +2 -1
- package/dist/wake-evidence.js +2 -8
- package/dist/wakes.d.ts +1 -0
- package/dist/wakes.js +5 -5
- package/dist/watch.d.ts +6 -1
- package/dist/watch.js +43 -28
- package/extensions/square-pi.js +107 -109
- package/guides/application-boundary.md +32 -0
- package/guides/change-waits.md +28 -0
- package/guides/host-ledger.md +9 -0
- package/guides/mcp.md +9 -0
- package/guides/operation-cancellation.md +17 -0
- package/package.json +10 -4
- package/skills/square/SKILL.md +5 -7
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { hostLedgerRoot } from './host-ledger-root.js';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { openSquare } from './square-file-adapter.js';
|
|
4
5
|
import { closeOpenSquare } from './open-square.js';
|
|
@@ -9,7 +10,7 @@ import { SquareError } from './model.js';
|
|
|
9
10
|
import { createHostLedgerPort } from './host-ledger-file-adapter.js';
|
|
10
11
|
import { projectSessionBindings } from './square-projections.js';
|
|
11
12
|
import { claimSessionParticipant, readParticipantOwner, releaseSessionParticipant } from './registry.js';
|
|
12
|
-
import { publishWakeRoute,
|
|
13
|
+
import { publishWakeRoute, resolvePrimaryWakeRoute, defaultWakeRouteCapabilities } from './routes.js';
|
|
13
14
|
export { automaticParticipant } from './participant-identity.js';
|
|
14
15
|
const providerEnv = {
|
|
15
16
|
codex: 'CODEX_THREAD_ID',
|
|
@@ -29,10 +30,9 @@ function operationEnv(provider, sessionId, env) {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
function hostLedgerForEnv(env) {
|
|
32
|
-
const root =
|
|
33
|
+
const root = hostLedgerRoot(env);
|
|
33
34
|
return createHostLedgerPort({
|
|
34
|
-
|
|
35
|
-
localPath: env.SQUARE_HOST_LEDGER_LOCAL ?? root,
|
|
35
|
+
rootPath: root,
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
export function publicSquarePath(cwd) {
|
|
@@ -64,17 +64,17 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
64
64
|
let bindings;
|
|
65
65
|
let entry;
|
|
66
66
|
try {
|
|
67
|
-
bindings = await hostLedger.listPresence({ location: squarePath, participant: name
|
|
67
|
+
bindings = await hostLedger.listPresence({ location: squarePath, participant: name });
|
|
68
68
|
entry = await entryPresentation(reader, name);
|
|
69
69
|
}
|
|
70
70
|
finally {
|
|
71
71
|
await closeOpenSquare(reader);
|
|
72
72
|
}
|
|
73
73
|
if (bindings.some((binding) => binding.session !== sessionId)) {
|
|
74
|
-
throw new SquareError('already_joined',
|
|
74
|
+
throw new SquareError('already_joined', `✕ ${name} already stands here — another session holds the name`);
|
|
75
75
|
}
|
|
76
76
|
if (entry.joined && !bindings.some((binding) => binding.session === sessionId)) {
|
|
77
|
-
throw new SquareError('already_joined',
|
|
77
|
+
throw new SquareError('already_joined', `✕ ${name} already stands here — another session holds the name`);
|
|
78
78
|
}
|
|
79
79
|
const scopedEnv = operationEnv(provider, sessionId, env);
|
|
80
80
|
const claim = await claimSessionParticipant(squarePath, name, scopedEnv);
|
|
@@ -103,8 +103,7 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
103
103
|
channel: provider === 'claude' ? 'claude-code' : provider,
|
|
104
104
|
updatedAt: Date.now(),
|
|
105
105
|
...(claim?.epoch === undefined || claim.epoch <= 0 ? {} : { epoch: claim.epoch }),
|
|
106
|
-
}
|
|
107
|
-
await square.reconcileBinding();
|
|
106
|
+
});
|
|
108
107
|
return undefined;
|
|
109
108
|
}
|
|
110
109
|
catch (error) {
|
|
@@ -127,7 +126,6 @@ export async function automaticSessionEnd(provider, sessionId, cwd, env = proces
|
|
|
127
126
|
hostLedger,
|
|
128
127
|
sessionId,
|
|
129
128
|
location: probe.location,
|
|
130
|
-
scopes: ['user', 'local'],
|
|
131
129
|
}))[0];
|
|
132
130
|
const expectedEpoch = binding === undefined
|
|
133
131
|
? undefined
|
|
@@ -135,22 +133,14 @@ export async function automaticSessionEnd(provider, sessionId, cwd, env = proces
|
|
|
135
133
|
await closeOpenSquare(probe);
|
|
136
134
|
const square = await Square.at({ path: squarePath, hostLedger, env: scopedEnv });
|
|
137
135
|
try {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
const cleanup = await openSquare(squarePath);
|
|
148
|
-
try {
|
|
149
|
-
await retireWakeRoutesForSessionFromArtifact(cleanup.artifact, { location: squarePath, sessionId });
|
|
150
|
-
}
|
|
151
|
-
finally {
|
|
152
|
-
await closeOpenSquare(cleanup);
|
|
153
|
-
}
|
|
136
|
+
// The ended owner's done, routes, and presence settle inside the ownership claim
|
|
137
|
+
// lock. A same-session rejoin or takeover that lands afterwards claims only after
|
|
138
|
+
// that cleanup, so this call never performs post-return ledger or route cleanup that
|
|
139
|
+
// could remove the replacement owner's fresh rows.
|
|
140
|
+
if (binding === undefined)
|
|
141
|
+
await square.retireEndedSessionRoutes(sessionId);
|
|
142
|
+
else
|
|
143
|
+
await square.endOwnedSession(binding.participant, sessionId, expectedEpoch);
|
|
154
144
|
}
|
|
155
145
|
finally {
|
|
156
146
|
await square.close();
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { InboxMembership } from './model.js';
|
|
2
|
-
|
|
3
|
-
export declare function pendingAtBoundary(inbox: InboxMembership[]): InboxMembership[];
|
|
2
|
+
export { pendingAtBoundary } from './square-projections.js';
|
|
4
3
|
export declare function renderPendingAtBoundary(inbox: InboxMembership[]): string;
|
|
5
4
|
/** Serialize a boundary across hook processes so one stale inbox cannot render twice. */
|
|
6
5
|
export declare function presentPendingAtBoundary<T>(sessionId: string, present: (context: string) => T | Promise<T>, lookup?: (sessionId: string, env?: NodeJS.ProcessEnv, signal?: AbortSignal) => Promise<InboxMembership[]> | InboxMembership[], env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<T | undefined>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { hostLedgerRoot } from './host-ledger-root.js';
|
|
1
2
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { leaseOwnsNotification } from './delivery.js';
|
|
5
4
|
import { withFileLock } from './file-lock.js';
|
|
6
5
|
import { openSquare } from './square-file-adapter.js';
|
|
7
6
|
import { closeOpenSquare } from './open-square.js';
|
|
8
7
|
import { presentPending } from './presentation-operations.js';
|
|
9
8
|
import { hostLedgerForEnv, sessionInbox } from './inbox.js';
|
|
10
9
|
import { attentionBodyIsClipped, renderAttentionPreview } from './attention-presentation.js';
|
|
11
|
-
import { presentationSuppressesWake, projectPresentationEvidence } from './square-projections.js';
|
|
10
|
+
import { pendingAtBoundary, presentationSuppressesWake, projectPresentationEvidence } from './square-projections.js';
|
|
11
|
+
export { pendingAtBoundary } from './square-projections.js';
|
|
12
12
|
import { formatActivityId } from './square-core.js';
|
|
13
13
|
const CONTEXT_MAX = 1200;
|
|
14
14
|
const presentationLocks = new Map();
|
|
@@ -38,20 +38,6 @@ async function awaitWithSignal(promise, signal) {
|
|
|
38
38
|
function pendingCount(inbox) {
|
|
39
39
|
return inbox.reduce((total, membership) => total + membership.notifications.length, 0);
|
|
40
40
|
}
|
|
41
|
-
/** A fresh blocking catch owns only the notifications admitted by its filter. */
|
|
42
|
-
export function pendingAtBoundary(inbox) {
|
|
43
|
-
return inbox
|
|
44
|
-
.map((membership) => {
|
|
45
|
-
const lease = membership.catchLease;
|
|
46
|
-
if (lease === undefined)
|
|
47
|
-
return membership;
|
|
48
|
-
return {
|
|
49
|
-
...membership,
|
|
50
|
-
notifications: membership.notifications.filter((notification) => !leaseOwnsNotification(lease, { ...notification, recipient: membership.name })),
|
|
51
|
-
};
|
|
52
|
-
})
|
|
53
|
-
.filter((membership) => membership.notifications.length > 0);
|
|
54
|
-
}
|
|
55
41
|
export function renderPendingAtBoundary(inbox) {
|
|
56
42
|
return renderBoundary(inbox).context;
|
|
57
43
|
}
|
|
@@ -165,8 +151,7 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
165
151
|
}
|
|
166
152
|
/** Serialize a boundary across hook processes so one stale inbox cannot render twice. */
|
|
167
153
|
export async function presentPendingAtBoundary(sessionId, present, lookup = sessionInbox, env = process.env, signal) {
|
|
168
|
-
const ledgerRoot = env
|
|
169
|
-
?? (env.SQUARE_REGISTRY === undefined ? path.join(os.homedir(), '.square', 'host-ledger') : path.dirname(env.SQUARE_REGISTRY));
|
|
154
|
+
const ledgerRoot = hostLedgerRoot(env);
|
|
170
155
|
const ownerKey = createHash('sha256').update(sessionId).digest('hex');
|
|
171
156
|
return withFileLock(path.join(ledgerRoot, `presentation-boundary-${ownerKey}.lock`), { retryMs: 10, signal }, () => presentPendingAtBoundaryUnlocked(sessionId, present, lookup, env, signal));
|
|
172
157
|
}
|
package/dist/catch-decisions.js
CHANGED
|
@@ -17,7 +17,7 @@ function resolveCatchName(state, requestedName) {
|
|
|
17
17
|
validateName(requestedName);
|
|
18
18
|
const known = resolveRosterName(state, requestedName);
|
|
19
19
|
if (known === undefined) {
|
|
20
|
-
throw new SquareError('invalid_args',
|
|
20
|
+
throw new SquareError('invalid_args', `✕ ${participantIdentity(requestedName)} has never stepped into this square`);
|
|
21
21
|
}
|
|
22
22
|
return known;
|
|
23
23
|
}
|
package/dist/cli/context.d.ts
CHANGED
package/dist/cli/context.js
CHANGED
|
@@ -35,66 +35,66 @@ export function usage(command) {
|
|
|
35
35
|
export function requireValue(args, index, flag) {
|
|
36
36
|
const value = args[index + 1];
|
|
37
37
|
if (value === undefined || value.startsWith('--'))
|
|
38
|
-
fail(
|
|
38
|
+
fail(`✕ missing value for ${flag}`);
|
|
39
39
|
return value;
|
|
40
40
|
}
|
|
41
41
|
export function parseDurationMs(value, flag) {
|
|
42
42
|
const match = value.match(/^([1-9]\d*)(ms|s|m|h)$/);
|
|
43
43
|
if (!match)
|
|
44
|
-
fail(
|
|
44
|
+
fail(`✕ invalid ${flag}: expected a positive duration with unit ms, s, m, or h (for example 500ms, 30s, 3m, 1h)`);
|
|
45
45
|
const amount = Number.parseInt(match[1], 10);
|
|
46
46
|
const multiplier = { ms: 1, s: 1000, m: 60000, h: 3600000 };
|
|
47
47
|
const milliseconds = amount * multiplier[match[2]];
|
|
48
48
|
if (!Number.isSafeInteger(milliseconds))
|
|
49
|
-
fail(
|
|
49
|
+
fail(`✕ invalid ${flag}: duration is too large`);
|
|
50
50
|
return milliseconds;
|
|
51
51
|
}
|
|
52
52
|
export function parsePositiveInteger(value, flag) {
|
|
53
53
|
if (!/^[1-9]\d*$/.test(value))
|
|
54
|
-
fail(
|
|
54
|
+
fail(`✕ invalid ${flag}: expected a positive integer`);
|
|
55
55
|
const parsed = Number(value);
|
|
56
56
|
if (!Number.isSafeInteger(parsed))
|
|
57
|
-
fail(
|
|
57
|
+
fail(`✕ invalid ${flag}: value is too large`);
|
|
58
58
|
return parsed;
|
|
59
59
|
}
|
|
60
60
|
export function parseBoundedLimit(value, flag, max, retry) {
|
|
61
61
|
if (value === undefined || value.startsWith('--') || !/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(Number(value))) {
|
|
62
|
-
fail(`✕ ${flag} needs a positive integer\n
|
|
62
|
+
fail(`✕ ${flag} needs a positive integer\n${retry}`);
|
|
63
63
|
}
|
|
64
64
|
const parsed = Number(value);
|
|
65
65
|
if (parsed > max)
|
|
66
|
-
fail(`✕ ${flag} is capped at ${max}\n
|
|
66
|
+
fail(`✕ ${flag} is capped at ${max}\n${retry}`);
|
|
67
67
|
return parsed;
|
|
68
68
|
}
|
|
69
69
|
export function parseNonNegativeInteger(value, flag) {
|
|
70
70
|
if (!/^\d+$/.test(value))
|
|
71
|
-
fail(
|
|
71
|
+
fail(`✕ invalid ${flag}: expected a non-negative integer`);
|
|
72
72
|
const parsed = Number(value);
|
|
73
73
|
if (!Number.isSafeInteger(parsed))
|
|
74
|
-
fail(
|
|
74
|
+
fail(`✕ invalid ${flag}: value is too large`);
|
|
75
75
|
return parsed;
|
|
76
76
|
}
|
|
77
77
|
export function parseHardCap(value) {
|
|
78
78
|
if (value === 'unlimited')
|
|
79
79
|
return null;
|
|
80
80
|
if (!/^[1-9]\d*$/.test(value))
|
|
81
|
-
fail('
|
|
81
|
+
fail('✕ invalid build option: --cap must be a positive integer or unlimited');
|
|
82
82
|
const parsed = Number(value);
|
|
83
83
|
if (!Number.isSafeInteger(parsed))
|
|
84
|
-
fail('
|
|
84
|
+
fail('✕ invalid build option: --cap must be a positive integer or unlimited');
|
|
85
85
|
return parsed;
|
|
86
86
|
}
|
|
87
87
|
export function parseNameList(value, flag) {
|
|
88
88
|
const names = parseParticipantList(value);
|
|
89
89
|
if (names.length === 0)
|
|
90
|
-
fail(
|
|
90
|
+
fail(`✕ invalid ${flag}: expected at least one participant name`);
|
|
91
91
|
for (const name of names)
|
|
92
92
|
validateName(name);
|
|
93
93
|
return names;
|
|
94
94
|
}
|
|
95
95
|
export function requireParticipant(name) {
|
|
96
96
|
if (!name)
|
|
97
|
-
fail('
|
|
97
|
+
fail('✕ missing required option: --as <name>');
|
|
98
98
|
validateName(name);
|
|
99
99
|
return name;
|
|
100
100
|
}
|
|
@@ -113,6 +113,7 @@ const LOCATION_REQUIRED_COMMANDS = new Set([
|
|
|
113
113
|
'history',
|
|
114
114
|
'status',
|
|
115
115
|
'participants',
|
|
116
|
+
'mcp-server',
|
|
116
117
|
'doctor',
|
|
117
118
|
]);
|
|
118
119
|
function configuredLocation() {
|
|
@@ -126,22 +127,10 @@ function configuredName() {
|
|
|
126
127
|
validateName(value);
|
|
127
128
|
return value;
|
|
128
129
|
}
|
|
129
|
-
function withoutAsCommand(rawArgs) {
|
|
130
|
-
const args = [];
|
|
131
|
-
for (let index = 0; index < rawArgs.length; index++) {
|
|
132
|
-
if (rawArgs[index] === '--as') {
|
|
133
|
-
index += 1;
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
args.push(rawArgs[index]);
|
|
137
|
-
}
|
|
138
|
-
return `square ${args.map((arg) => /^[A-Za-z0-9_./:=@+,-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, "'\\''")}'`).join(' ')}`;
|
|
139
|
-
}
|
|
140
130
|
export async function parseGlobalArgs(rawArgs) {
|
|
141
131
|
const args = [...rawArgs];
|
|
142
132
|
let requestedPath;
|
|
143
133
|
let name;
|
|
144
|
-
let hasExplicitName = false;
|
|
145
134
|
for (let index = 0; index < args.length; index++) {
|
|
146
135
|
if (args[index] === '--location') {
|
|
147
136
|
requestedPath = requireValue(args, index, args[index]);
|
|
@@ -150,15 +139,11 @@ export async function parseGlobalArgs(rawArgs) {
|
|
|
150
139
|
}
|
|
151
140
|
else if (args[index] === '--as') {
|
|
152
141
|
name = requireValue(args, index, args[index]);
|
|
153
|
-
hasExplicitName = true;
|
|
154
142
|
args.splice(index, 2);
|
|
155
143
|
index -= 1;
|
|
156
144
|
}
|
|
157
145
|
}
|
|
158
146
|
const command = args[0];
|
|
159
|
-
if (command === 'history' && hasExplicitName) {
|
|
160
|
-
fail(`✕ history is an archive and does not use --as\n» ${withoutAsCommand(rawArgs)}`);
|
|
161
|
-
}
|
|
162
147
|
if (name === undefined)
|
|
163
148
|
name = configuredName();
|
|
164
149
|
if (name !== undefined)
|
|
@@ -166,7 +151,7 @@ export async function parseGlobalArgs(rawArgs) {
|
|
|
166
151
|
const explicitSquarePath = requestedPath !== undefined;
|
|
167
152
|
const configured = configuredLocation();
|
|
168
153
|
if (command !== undefined && !['--help', '-h'].includes(command) && locationIsRequired(command) && requestedPath === undefined && configured === undefined) {
|
|
169
|
-
fail(`✕ ${command} needs a square location\
|
|
154
|
+
fail(`✕ ${command} needs a square location\nsquare ls`);
|
|
170
155
|
}
|
|
171
156
|
const squarePath = requestedPath ?? configured;
|
|
172
157
|
if (name === undefined && squarePath !== undefined && command !== undefined && locationIsRequired(command)) {
|
|
@@ -174,7 +159,6 @@ export async function parseGlobalArgs(rawArgs) {
|
|
|
174
159
|
hostLedger: createHostLedgerPort(),
|
|
175
160
|
location: squarePath,
|
|
176
161
|
sessionId,
|
|
177
|
-
scopes: ['user', 'local'],
|
|
178
162
|
})))).flat();
|
|
179
163
|
const names = new Set(bindings.map((binding) => binding.participant));
|
|
180
164
|
name = names.size === 1 ? [...names][0] : undefined;
|
|
@@ -185,10 +169,10 @@ export function locationIsRequired(command) {
|
|
|
185
169
|
return LOCATION_REQUIRED_COMMANDS.has(command);
|
|
186
170
|
}
|
|
187
171
|
export function defaultContext(command, squarePath, name) {
|
|
188
|
-
return { command, squarePath, name, homeDir: os.homedir() };
|
|
172
|
+
return { command, cwd: process.cwd(), env: { ...process.env }, squarePath, name, homeDir: os.homedir() };
|
|
189
173
|
}
|
|
190
174
|
export function requireSquarePath(context) {
|
|
191
175
|
if (context.squarePath === undefined)
|
|
192
|
-
fail(`✕ ${context.command} needs a square location\
|
|
176
|
+
fail(`✕ ${context.command} needs a square location\nsquare ls`);
|
|
193
177
|
return context.squarePath;
|
|
194
178
|
}
|
|
@@ -102,7 +102,7 @@ export function formatHarnessResult(result) {
|
|
|
102
102
|
return `${[...result.notes, ...result.lines, ...result.failures].join('\n')}\n`;
|
|
103
103
|
}
|
|
104
104
|
export function runHarnessCommand(argv, squarePath) {
|
|
105
|
-
const context = { homeDir: os.homedir(), ...(squarePath === undefined ? {} : { squarePath }), command: 'harness' };
|
|
105
|
+
const context = { cwd: process.cwd(), env: { ...process.env }, homeDir: os.homedir(), ...(squarePath === undefined ? {} : { squarePath }), command: 'harness' };
|
|
106
106
|
const intent = harnessCommand.parse(argv, context);
|
|
107
107
|
return Promise.resolve(harnessCommand.execute(intent, context)).then(formatHarnessResult);
|
|
108
108
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { fail } from './context.js';
|
|
2
|
+
export const mcpServerCommand = {
|
|
3
|
+
parse(argv) {
|
|
4
|
+
if (argv.length > 0)
|
|
5
|
+
fail('Usage: square [--location <square>] [--as <name>] mcp-server');
|
|
6
|
+
return undefined;
|
|
7
|
+
},
|
|
8
|
+
async execute(_intent, context) {
|
|
9
|
+
const { runSquareMcpStdio } = await import('../mcp.js');
|
|
10
|
+
await runSquareMcpStdio({ cwd: context.cwd, env: context.env, squarePath: context.squarePath, participant: context.name });
|
|
11
|
+
},
|
|
12
|
+
present() { },
|
|
13
|
+
};
|