@astrosheep/square 0.3.70 → 0.3.71
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.d.ts +4 -5
- package/dist/activity-feed.js +14 -10
- package/dist/artifact.d.ts +26 -33
- package/dist/artifact.js +346 -317
- package/dist/attention-presentation.js +2 -9
- package/dist/automatic-session.js +6 -6
- package/dist/boundary-presentation.js +3 -3
- package/dist/catch-decisions.d.ts +19 -12
- package/dist/catch-decisions.js +32 -68
- package/dist/claude-delivery.js +7 -7
- package/dist/claude-mod.js +18 -7
- package/dist/cli/catch-presentation.d.ts +7 -0
- package/dist/cli/catch-presentation.js +55 -0
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +5 -23
- package/dist/cli/express-presentation.d.ts +10 -0
- package/dist/cli/express-presentation.js +196 -0
- package/dist/cli/maintenance-commands.d.ts +4 -0
- package/dist/cli/maintenance-commands.js +29 -6
- package/dist/cli/observation-commands.d.ts +7 -5
- package/dist/cli/observation-commands.js +275 -262
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +43 -56
- package/dist/cli/registry.js +2 -1
- package/dist/cli/square-commands.d.ts +3 -9
- package/dist/cli/square-commands.js +134 -255
- package/dist/codex-queue.js +4 -1
- package/dist/decisions.d.ts +26 -74
- package/dist/decisions.js +190 -335
- package/dist/delivery-health.js +13 -22
- package/dist/delivery-operations.d.ts +0 -11
- package/dist/delivery-operations.js +44 -33
- package/dist/delivery.d.ts +33 -32
- package/dist/delivery.js +70 -81
- package/dist/help.js +6 -1
- package/dist/inbox.d.ts +27 -0
- package/dist/inbox.js +55 -18
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -1
- package/dist/list.d.ts +7 -1
- package/dist/list.js +49 -122
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +7 -37
- package/dist/model.d.ts +4 -44
- package/dist/model.js +1 -3
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +13 -7
- package/dist/open-square.d.ts +16 -2
- package/dist/open-square.js +40 -1
- package/dist/perception-projection.d.ts +6 -15
- package/dist/perception-projection.js +6 -26
- package/dist/plugins/opencode/delivery.js +9 -9
- package/dist/plugins/opencode/index.js +3 -3
- package/dist/ports.d.ts +156 -11
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +35 -44
- package/dist/presentation.d.ts +12 -19
- package/dist/presentation.js +33 -54
- package/dist/routes.d.ts +7 -14
- package/dist/routes.js +33 -62
- package/dist/runtime.d.ts +12 -39
- package/dist/runtime.js +33 -164
- package/dist/square-actions.d.ts +11 -21
- package/dist/square-actions.js +171 -271
- package/dist/square-application.d.ts +31 -55
- package/dist/square-application.js +637 -141
- package/dist/square-core.d.ts +3 -94
- package/dist/square-core.js +8 -353
- package/dist/square-domain.d.ts +24 -0
- package/dist/square-domain.js +77 -0
- package/dist/square-facade.d.ts +360 -9
- package/dist/square-migration.d.ts +24 -0
- package/dist/square-migration.js +211 -0
- package/dist/square-projections.d.ts +2 -42
- package/dist/square-projections.js +1 -37
- package/dist/square-sqlite.d.ts +59 -0
- package/dist/square-sqlite.js +702 -0
- package/dist/stream.d.ts +3 -10
- package/dist/stream.js +81 -52
- package/dist/views.d.ts +27 -95
- package/dist/views.js +217 -87
- package/dist/wake-eligibility.d.ts +15 -5
- package/dist/wake-eligibility.js +32 -16
- package/dist/wakes.d.ts +3 -3
- package/dist/wakes.js +31 -27
- package/guides/application-facade-delivery-evidence.md +200 -0
- package/guides/application-facade-design.md +95 -0
- package/guides/change-waits.md +4 -4
- package/guides/migration.md +77 -0
- package/guides/primitive-catch-consolidation.md +85 -0
- package/guides/primitive-history-consolidation.md +76 -0
- package/guides/primitive-status-consolidation.md +87 -0
- package/guides/primitive-storage-consolidation.md +128 -0
- package/guides/row-runtime-delivery-evidence.md +160 -0
- package/guides/row-storage-design.md +567 -0
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +11 -11
- package/plugins/opencode/index.ts +3 -3
- package/plugins/paseo/client/square-message.tsx +70 -52
- package/plugins/paseo/shared/message.ts +15 -0
- package/plugins/pi/square-pi.js +3 -0
- package/dist/activity.d.ts +0 -14
- package/dist/activity.js +0 -248
- package/dist/square-file-adapter.d.ts +0 -26
- package/dist/square-file-adapter.js +0 -85
- package/dist/square-state.d.ts +0 -6
- package/dist/square-state.js +0 -138
- package/dist/square-storage.d.ts +0 -14
- package/dist/square-storage.js +0 -188
- package/dist/square-wiring.d.ts +0 -33
- package/dist/square-wiring.js +0 -109
- package/dist/watch.d.ts +0 -8
- package/dist/watch.js +0 -252
package/dist/cli/program.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Parse global flags, select an executable adapter, and leave
|
|
1
|
+
/** Parse global flags, select an executable adapter, and leave operations to the application. */
|
|
2
2
|
export declare function runCli(rawArgs?: string[]): Promise<void>;
|
package/dist/cli/program.js
CHANGED
|
@@ -1,58 +1,46 @@
|
|
|
1
1
|
import { helpRequest } from '../help.js';
|
|
2
2
|
import { isSquareError } from '../model.js';
|
|
3
|
-
import { commandPrefix, formatRefusal, joinRecoveryCommand, participantsRecoveryCommand, takeoverRecoveryLines } from '../presentation.js';
|
|
4
|
-
import {
|
|
5
|
-
import { openSquare } from '../square-file-adapter.js';
|
|
6
|
-
import { closeOpenSquare } from '../open-square.js';
|
|
7
|
-
import { defaultContext, parseGlobalArgs } from './context.js';
|
|
3
|
+
import { commandPrefix, formatRefusal, refusalText, joinRecoveryCommand, participantIdentity, participantsRecoveryCommand, takeoverRecoveryLines, } from '../presentation.js';
|
|
4
|
+
import { applicationFor, defaultContext, parseGlobalArgs } from './context.js';
|
|
8
5
|
import { executeRegisteredCommand, findCommand } from './registry.js';
|
|
9
|
-
async function handleSquareError(error,
|
|
10
|
-
if (isSquareError(error))
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
else if (squarePath !== undefined && error.facts?.reason === 'not_standing') {
|
|
23
|
-
existing.push(participantsRecoveryCommand(squarePath));
|
|
24
|
-
}
|
|
25
|
-
else if (squarePath !== undefined && error.facts?.reason === 'not_addressed' && typeof error.facts.activityId === 'string') {
|
|
26
|
-
// An anchor only works for an activity the artifact actually holds.
|
|
27
|
-
existing.push(error.facts.activityExists === true
|
|
28
|
-
? `${commandPrefix(squarePath)} history --at ${error.facts.activityId} -C 2`
|
|
29
|
-
: `${commandPrefix(squarePath)} history --limit 10`);
|
|
30
|
-
}
|
|
31
|
-
if (squarePath === undefined) {
|
|
32
|
-
process.stderr.write(`${existing.join('\n')}\n`);
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
let participantCount;
|
|
36
|
-
try {
|
|
37
|
-
const square = await openSquare(squarePath, { clock: nowMs });
|
|
38
|
-
try {
|
|
39
|
-
participantCount = inSquareCount((await square.artifact.read()).state);
|
|
40
|
-
}
|
|
41
|
-
finally {
|
|
42
|
-
await closeOpenSquare(square);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch { /* the header count is best effort */ }
|
|
46
|
-
process.stderr.write(formatRefusal(squarePath, existing, participantCount === undefined ? {} : { participantCount }));
|
|
47
|
-
}
|
|
48
|
-
process.exit(error.code === 'not_found' ? 1 : 2);
|
|
6
|
+
async function handleSquareError(error, context) {
|
|
7
|
+
if (!isSquareError(error))
|
|
8
|
+
throw error;
|
|
9
|
+
const detail = error.operation;
|
|
10
|
+
const squarePath = context?.squarePath;
|
|
11
|
+
const recovery = context === undefined || squarePath === undefined ? undefined
|
|
12
|
+
: await applicationFor({ ...context, name: detail?.participant ?? context.name }).recovery().catch(() => undefined);
|
|
13
|
+
const name = detail?.participant ?? recovery?.data.participant ?? context?.name;
|
|
14
|
+
const existing = [refusalText(error)];
|
|
15
|
+
if (squarePath !== undefined && name !== undefined && error.code === 'already_joined') {
|
|
16
|
+
existing.splice(0, 1, `✕ ${participantIdentity(name)} shoos you out of the square`, ` · ${participantIdentity(name)} already stands here — another session holds the name`);
|
|
17
|
+
existing.push(...takeoverRecoveryLines(squarePath, name));
|
|
49
18
|
}
|
|
50
|
-
|
|
19
|
+
else if (squarePath !== undefined && error.facts?.reason === 'never_joined') {
|
|
20
|
+
existing.push(detail?.subject !== 'filter' && name !== undefined
|
|
21
|
+
? joinRecoveryCommand(squarePath, name) : participantsRecoveryCommand(squarePath));
|
|
22
|
+
}
|
|
23
|
+
else if (squarePath !== undefined && error.facts?.reason === 'not_standing') {
|
|
24
|
+
existing.push(participantsRecoveryCommand(squarePath));
|
|
25
|
+
}
|
|
26
|
+
else if (squarePath !== undefined && error.facts?.reason === 'not_addressed' && typeof error.facts.activityId === 'string') {
|
|
27
|
+
existing.push(error.facts.activityExists === true
|
|
28
|
+
? `${commandPrefix(squarePath)} history --at ${error.facts.activityId} -C 2`
|
|
29
|
+
: `${commandPrefix(squarePath)} history --limit 10`);
|
|
30
|
+
}
|
|
31
|
+
if (error.facts?.reason === 'invalid_done_body')
|
|
32
|
+
existing.push('square done --help');
|
|
33
|
+
if (squarePath === undefined)
|
|
34
|
+
process.stderr.write(`${existing.join('\n')}\n`);
|
|
35
|
+
else
|
|
36
|
+
process.stderr.write(formatRefusal(squarePath, existing, {
|
|
37
|
+
participantCount: recovery?.data.standingCount, held: recovery?.data.held,
|
|
38
|
+
}));
|
|
39
|
+
process.exit(error.code === 'not_found' ? 1 : 2);
|
|
51
40
|
}
|
|
52
|
-
/** Parse global flags, select an executable adapter, and leave
|
|
41
|
+
/** Parse global flags, select an executable adapter, and leave operations to the application. */
|
|
53
42
|
export async function runCli(rawArgs = process.argv.slice(2)) {
|
|
54
|
-
let
|
|
55
|
-
let requestedName;
|
|
43
|
+
let context;
|
|
56
44
|
try {
|
|
57
45
|
const requestedHelp = helpRequest(rawArgs);
|
|
58
46
|
if (requestedHelp !== undefined) {
|
|
@@ -60,20 +48,19 @@ export async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
60
48
|
return;
|
|
61
49
|
}
|
|
62
50
|
const parsed = await parseGlobalArgs(rawArgs);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
await executeRegisteredCommand('help', [],
|
|
51
|
+
const command = parsed.args[0];
|
|
52
|
+
context = defaultContext(command ?? 'help', parsed.squarePath, parsed.name);
|
|
53
|
+
if (command === undefined || command === '--help' || command === '-h') {
|
|
54
|
+
await executeRegisteredCommand('help', [], context);
|
|
67
55
|
return;
|
|
68
56
|
}
|
|
69
|
-
const command = parsed.args[0];
|
|
70
57
|
if (findCommand(command) === undefined) {
|
|
71
58
|
process.stderr.write(`unknown command: ${command}\nrun 'square' for usage\n`);
|
|
72
59
|
process.exit(2);
|
|
73
60
|
}
|
|
74
|
-
await executeRegisteredCommand(command, parsed.args.slice(1),
|
|
61
|
+
await executeRegisteredCommand(command, parsed.args.slice(1), context);
|
|
75
62
|
}
|
|
76
63
|
catch (error) {
|
|
77
|
-
await handleSquareError(error,
|
|
64
|
+
await handleSquareError(error, context);
|
|
78
65
|
}
|
|
79
66
|
}
|
package/dist/cli/registry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildCommand, doneCommand, expressCommand, holdCommand, ignoreCommand, joinCommand, listenCommand, listeningCommand, resumeCommand } from './square-commands.js';
|
|
2
|
-
import { doctorCommand } from './maintenance-commands.js';
|
|
2
|
+
import { doctorCommand, migrateCommand } from './maintenance-commands.js';
|
|
3
3
|
import { harnessCommand, installCommand, uninstallCommand } from './harness-command.js';
|
|
4
4
|
import { helpCommand, versionCommand } from './meta-commands.js';
|
|
5
5
|
import { mcpServerCommand } from './mcp-server-command.js';
|
|
@@ -25,6 +25,7 @@ export const commandRegistry = [
|
|
|
25
25
|
{ names: ['uninstall'], spec: uninstallCommand },
|
|
26
26
|
{ names: ['harness'], spec: harnessCommand },
|
|
27
27
|
{ names: ['doctor'], spec: doctorCommand },
|
|
28
|
+
{ names: ['migrate'], spec: migrateCommand },
|
|
28
29
|
{ names: ['history'], spec: historyCommand },
|
|
29
30
|
{ names: ['status'], spec: statusCommand },
|
|
30
31
|
{ names: ['participants'], spec: participantsCommand },
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { type BuildOptions, type HardCap
|
|
1
|
+
import { type BuildOptions, type HardCap } from '../model.js';
|
|
2
|
+
import type { Reach } from '../square-facade.js';
|
|
2
3
|
import { type CommandSpec } from './context.js';
|
|
3
4
|
interface BuildIntent {
|
|
4
5
|
options: BuildOptions & {
|
|
5
6
|
hardCap: HardCap;
|
|
6
7
|
};
|
|
7
|
-
snippet: string;
|
|
8
8
|
}
|
|
9
9
|
interface JoinIntent {
|
|
10
|
-
name: string;
|
|
11
10
|
lastN: number;
|
|
12
11
|
kick: boolean;
|
|
13
12
|
}
|
|
14
13
|
interface ActivityIntent {
|
|
15
|
-
name: string;
|
|
16
14
|
activity: string;
|
|
17
15
|
force: boolean;
|
|
18
16
|
noWait: boolean;
|
|
@@ -22,11 +20,9 @@ interface ActivityIntent {
|
|
|
22
20
|
reply?: string;
|
|
23
21
|
}
|
|
24
22
|
interface BodyIntent {
|
|
25
|
-
name: string;
|
|
26
23
|
body?: string;
|
|
27
24
|
}
|
|
28
25
|
interface ListenerIntent {
|
|
29
|
-
name: string;
|
|
30
26
|
target?: string;
|
|
31
27
|
}
|
|
32
28
|
export declare const buildCommand: CommandSpec<BuildIntent, string>;
|
|
@@ -37,7 +33,5 @@ export declare const ignoreCommand: CommandSpec<ListenerIntent, string>;
|
|
|
37
33
|
export declare const listeningCommand: CommandSpec<ListenerIntent, string>;
|
|
38
34
|
export declare const doneCommand: CommandSpec<BodyIntent, string>;
|
|
39
35
|
export declare const holdCommand: CommandSpec<BodyIntent, string>;
|
|
40
|
-
export declare const resumeCommand: CommandSpec<
|
|
41
|
-
name: string;
|
|
42
|
-
}, string>;
|
|
36
|
+
export declare const resumeCommand: CommandSpec<Record<string, never>, string>;
|
|
43
37
|
export {};
|
|
@@ -1,149 +1,98 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { formatHardCap, sameName, } from '../model.js';
|
|
5
|
-
import { formatRefusal, participantCommandPrefix, participantIdentity, takeoverRecoveryLines, renderRoomChangeText, renderAmbientEvent, withPathOutput, } from '../presentation.js';
|
|
6
|
-
import { hostLedgerForEnv, hasAutomaticDeliveryIdentity, } from '../registry.js';
|
|
7
|
-
import { actId, nowMs } from '../runtime.js';
|
|
8
|
-
import { createSquare, openSquare } from '../square-file-adapter.js';
|
|
9
|
-
import { closeOpenSquare } from '../open-square.js';
|
|
10
|
-
import { Square } from '../square-wiring.js';
|
|
11
|
-
import { createSquareApplication } from '../square-application.js';
|
|
12
|
-
import { entryPresentation, eventPresentation } from '../views.js';
|
|
13
|
-
import { createDefaultWakeTransport } from '../notifications.js';
|
|
1
|
+
import { formatHardCap } from '../model.js';
|
|
2
|
+
import { commandPrefix, participantCommandPrefix, participantIdentity, renderRoomChangeText, renderAmbientEvent, withPathOutput, } from '../presentation.js';
|
|
3
|
+
import { formatActivityId } from '../square-application.js';
|
|
14
4
|
import { style } from '../tty-style.js';
|
|
15
|
-
import {
|
|
5
|
+
import { executeExpression } from './express-presentation.js';
|
|
6
|
+
import { applicationFor, fail, parseBoundedLimit, parseHardCap, parsePositiveInteger, readStdin, requireSquarePath, requireValue, resolveBody, usage, } from './context.js';
|
|
16
7
|
const JOIN_DEFAULT_LAST = 10;
|
|
17
8
|
const JOIN_MAX_LAST = 100;
|
|
18
|
-
function parseBuild(argv) {
|
|
19
|
-
const options = { force: false, hardCap: null };
|
|
20
|
-
for (let index = 0; index < argv.length; index++) {
|
|
21
|
-
const flag = argv[index];
|
|
22
|
-
switch (flag) {
|
|
23
|
-
case '--cap':
|
|
24
|
-
options.hardCap = parseHardCap(requireValue(argv, index, flag));
|
|
25
|
-
index += 1;
|
|
26
|
-
break;
|
|
27
|
-
case '--template':
|
|
28
|
-
options.template = requireValue(argv, index, flag);
|
|
29
|
-
index += 1;
|
|
30
|
-
break;
|
|
31
|
-
case '--throttle':
|
|
32
|
-
case '--throttle-per-minute':
|
|
33
|
-
options.throttlePerMinute = parsePositiveInteger(requireValue(argv, index, flag), flag);
|
|
34
|
-
index += 1;
|
|
35
|
-
break;
|
|
36
|
-
case '--force':
|
|
37
|
-
case '-f':
|
|
38
|
-
options.force = true;
|
|
39
|
-
break;
|
|
40
|
-
default:
|
|
41
|
-
fail(`Unknown build option: ${flag}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (options.template !== undefined && !/^[a-zA-Z0-9-]+$/.test(options.template)) {
|
|
45
|
-
fail('Invalid template name: only letters, digits, and hyphens allowed.');
|
|
46
|
-
}
|
|
47
|
-
if (options.throttlePerMinute !== undefined && options.throttlePerMinute <= 0) {
|
|
48
|
-
fail('Invalid build option: --throttle must be a positive integer.');
|
|
49
|
-
}
|
|
50
|
-
return { options, snippet: '' };
|
|
51
|
-
}
|
|
52
9
|
export const buildCommand = {
|
|
53
|
-
parse
|
|
10
|
+
parse(argv) {
|
|
11
|
+
const options = { force: false, hardCap: null };
|
|
12
|
+
for (let index = 0; index < argv.length; index++) {
|
|
13
|
+
const flag = argv[index];
|
|
14
|
+
switch (flag) {
|
|
15
|
+
case '--cap':
|
|
16
|
+
options.hardCap = parseHardCap(requireValue(argv, index, flag));
|
|
17
|
+
index += 1;
|
|
18
|
+
break;
|
|
19
|
+
case '--template':
|
|
20
|
+
options.template = requireValue(argv, index, flag);
|
|
21
|
+
index += 1;
|
|
22
|
+
break;
|
|
23
|
+
case '--throttle':
|
|
24
|
+
case '--throttle-per-minute':
|
|
25
|
+
options.throttlePerMinute = parsePositiveInteger(requireValue(argv, index, flag), flag);
|
|
26
|
+
index += 1;
|
|
27
|
+
break;
|
|
28
|
+
case '--force':
|
|
29
|
+
case '-f':
|
|
30
|
+
options.force = true;
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
fail(`Unknown build option: ${flag}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (options.template !== undefined && !/^[a-zA-Z0-9-]+$/.test(options.template)) {
|
|
37
|
+
fail('Invalid template name: only letters, digits, and hyphens allowed.');
|
|
38
|
+
}
|
|
39
|
+
return { options };
|
|
40
|
+
},
|
|
54
41
|
async execute(intent, context) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
if (snippet.trim() === '')
|
|
42
|
+
const markdown = await readStdin();
|
|
43
|
+
if (markdown.trim() === '')
|
|
58
44
|
fail('Missing Markdown body snippet on stdin.');
|
|
59
|
-
await
|
|
60
|
-
const cap =
|
|
61
|
-
const throttle =
|
|
62
|
-
return withPathOutput(
|
|
45
|
+
const { data, projection } = await applicationFor(context).build({ ...intent.options, markdown });
|
|
46
|
+
const cap = data.hardCap === null ? 'unlimited' : formatHardCap(data.hardCap);
|
|
47
|
+
const throttle = data.throttlePerMinute === undefined ? [] : [` · throttle ${data.throttlePerMinute}/min`];
|
|
48
|
+
return withPathOutput(data.location, ['· the square stands ready', ` · cap ${cap}`, ...throttle].join('\n'), {
|
|
49
|
+
participantCount: projection.standingCount, held: projection.held,
|
|
50
|
+
});
|
|
63
51
|
},
|
|
64
52
|
present: (result) => process.stdout.write(result),
|
|
65
53
|
};
|
|
66
|
-
function parseJoin(argv, context) {
|
|
67
|
-
const name = requireParticipant(context.name);
|
|
68
|
-
const squarePath = requireSquarePath(context);
|
|
69
|
-
let lastN = JOIN_DEFAULT_LAST;
|
|
70
|
-
let kick = false;
|
|
71
|
-
for (let index = 0; index < argv.length; index++) {
|
|
72
|
-
if (argv[index] === '--last') {
|
|
73
|
-
lastN = parseBoundedLimit(argv[index + 1], '--last', JOIN_MAX_LAST, `${participantCommandPrefix(squarePath, name)} join --last ${JOIN_MAX_LAST}`);
|
|
74
|
-
index += 1;
|
|
75
|
-
}
|
|
76
|
-
else if (argv[index] === '--kick') {
|
|
77
|
-
kick = true;
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
usage(context.command);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return { name, lastN, kick };
|
|
84
|
-
}
|
|
85
54
|
export const joinCommand = {
|
|
86
|
-
parse
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const application = createSquareApplication({ cwd: context.cwd, env: context.env, squarePath, participant: intent.name, clock: nowMs, hostLedger, wakeTransport: await createDefaultWakeTransport(hostLedger, nowMs) });
|
|
94
|
-
let joinedName;
|
|
95
|
-
let joinKind;
|
|
96
|
-
try {
|
|
97
|
-
const result = await application.join({ takeover: intent.kick });
|
|
98
|
-
joinedName = result.participant;
|
|
99
|
-
joinKind = result.kind;
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
if (error instanceof Error && 'code' in error && error.code === 'already_joined') {
|
|
103
|
-
process.stderr.write(formatRefusal(squarePath, [
|
|
104
|
-
`✕ ${participantIdentity(intent.name)} shoos you out of the square`,
|
|
105
|
-
' · a same-named participant stands here — the name is taken',
|
|
106
|
-
...takeoverRecoveryLines(squarePath, intent.name),
|
|
107
|
-
], { participantCount: before.participantCount }));
|
|
108
|
-
process.exit(2);
|
|
55
|
+
parse(argv, context) {
|
|
56
|
+
let lastN = JOIN_DEFAULT_LAST;
|
|
57
|
+
let kick = false;
|
|
58
|
+
for (let index = 0; index < argv.length; index++) {
|
|
59
|
+
if (argv[index] === '--last') {
|
|
60
|
+
lastN = parseBoundedLimit(argv[index + 1], '--last', JOIN_MAX_LAST, `${context.name === undefined ? commandPrefix(requireSquarePath(context)) : participantCommandPrefix(requireSquarePath(context), context.name)} join --last ${JOIN_MAX_LAST}`);
|
|
61
|
+
index += 1;
|
|
109
62
|
}
|
|
110
|
-
|
|
63
|
+
else if (argv[index] === '--kick')
|
|
64
|
+
kick = true;
|
|
65
|
+
else
|
|
66
|
+
usage(context.command);
|
|
111
67
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
68
|
+
return { lastN, kick };
|
|
69
|
+
},
|
|
70
|
+
async execute(intent, context) {
|
|
71
|
+
const { data, projection: after } = await applicationFor(context).join({ takeover: intent.kick, last: intent.lastN });
|
|
72
|
+
const name = data.participant;
|
|
73
|
+
const activities = after.recentActivities.map((event) => renderAmbientEvent(event, name, {
|
|
74
|
+
now: after.now, preview: 200,
|
|
118
75
|
actNumber: event.kind === 'say' ? after.sayNumbers[event.index] : undefined,
|
|
119
|
-
|
|
76
|
+
perception: after.perceptions[event.index],
|
|
120
77
|
})).filter(Boolean).join('\n\n');
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// The long scene belongs to a name's first join here; a return reads its own line.
|
|
134
|
-
const joinedBefore = after.state.acts.filter((act) => act.kind === 'join' && sameName(act.actor, joinedName)).length > 1;
|
|
135
|
-
const rejoinScene = '*the flagstones are where you left them. so is your shadow.*';
|
|
136
|
-
const entryScene = joinKind !== 'joined' ? '' : joinedBefore ? rejoinScene : scene;
|
|
137
|
-
const output = [
|
|
138
|
-
entryLine,
|
|
139
|
-
'',
|
|
78
|
+
const fallback = after.automaticDeliveryAvailable ? [] : [
|
|
79
|
+
'', `${participantCommandPrefix(after.location, name)} catch --idle 30m`,
|
|
80
|
+
' the square has no way to call you — keep this catch open and stay within earshot',
|
|
81
|
+
];
|
|
82
|
+
const entryLine = data.kind === 'joined' ? '● you stepped into the square'
|
|
83
|
+
: data.kind === 'reconnected' ? '● you are already in the square'
|
|
84
|
+
: `✓ you banished the original ${participantIdentity(name)} — the name is yours`;
|
|
85
|
+
const isRejoin = data.kind !== 'joined';
|
|
86
|
+
const entryScene = isRejoin ? '' : after.joinedBefore
|
|
87
|
+
? '*the flagstones are where you left them. so is your shadow.*' : after.scene;
|
|
88
|
+
return withPathOutput(after.location, [
|
|
89
|
+
entryLine, '',
|
|
140
90
|
"· carved into the fountain's edge: every word here lands on a real ear — speak when someone needs it.",
|
|
141
|
-
...(
|
|
142
|
-
...(isRejoin ||
|
|
91
|
+
...(entryScene === '' ? [] : ['', entryScene]),
|
|
92
|
+
...(isRejoin || after.joinContext === '' ? [] : ['', style('dim', 'context'), after.joinContext]),
|
|
143
93
|
...(isRejoin || activities === '' ? [] : ['', style('dim', 'recent activity'), activities]),
|
|
144
94
|
...fallback,
|
|
145
|
-
].join('\n');
|
|
146
|
-
return withPathOutput(squarePath, output, { participantCount: after.participantCount });
|
|
95
|
+
].join('\n'), { participantCount: after.standingCount, held: after.held });
|
|
147
96
|
},
|
|
148
97
|
present: (result) => process.stdout.write(result),
|
|
149
98
|
};
|
|
@@ -184,31 +133,20 @@ function parseActivity(argv, context) {
|
|
|
184
133
|
if (noMention && mentions.length > 0)
|
|
185
134
|
fail('✕ --no-mention cannot be combined with --mention\nsquare express --help');
|
|
186
135
|
if (bodyArgs.length !== 1) {
|
|
187
|
-
if (bodyArgs.length === 0)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
fail("express requires a body argument (a quoted string or '-' with piped stdin)");
|
|
136
|
+
if (bodyArgs.length === 0 && !process.stdin.isTTY)
|
|
137
|
+
bodyArgs.push('-');
|
|
138
|
+
else
|
|
139
|
+
fail("express requires a body argument (a quoted string or '-' with piped stdin)");
|
|
192
140
|
}
|
|
193
|
-
return {
|
|
141
|
+
return { activity: bodyArgs[0], force, noWait, noMention, mentions, reach, reply };
|
|
194
142
|
}
|
|
195
143
|
export const expressCommand = {
|
|
196
144
|
parse: parseActivity,
|
|
197
145
|
async execute(intent, context) {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
await cmdActivity(squarePath, intent.name, body, (value) => value, {
|
|
204
|
-
force: intent.force,
|
|
205
|
-
noWait: intent.noWait,
|
|
206
|
-
noMention: intent.noMention,
|
|
207
|
-
mentions: intent.mentions,
|
|
208
|
-
reach: intent.reach,
|
|
209
|
-
reply: intent.reply,
|
|
210
|
-
cwd: context.cwd,
|
|
211
|
-
env: context.env,
|
|
146
|
+
const rawInput = await resolveBody(intent.activity);
|
|
147
|
+
await executeExpression(applicationFor(context), requireSquarePath(context), context.name, rawInput, {
|
|
148
|
+
force: intent.force, noWait: intent.noWait, noMention: intent.noMention,
|
|
149
|
+
mentions: intent.mentions, reach: intent.reach, reply: intent.reply,
|
|
212
150
|
});
|
|
213
151
|
},
|
|
214
152
|
present: () => { },
|
|
@@ -216,117 +154,63 @@ export const expressCommand = {
|
|
|
216
154
|
function parseListener(argv, context, targetRequired) {
|
|
217
155
|
if (targetRequired ? argv.length !== 1 : argv.length !== 0)
|
|
218
156
|
usage(context.command);
|
|
219
|
-
return
|
|
157
|
+
return targetRequired ? { target: argv[0] } : {};
|
|
220
158
|
}
|
|
221
|
-
function
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
159
|
+
function listenerCommand(verb) {
|
|
160
|
+
return {
|
|
161
|
+
parse(argv, context) { return parseListener(argv, context, true); },
|
|
162
|
+
async execute(intent, context) {
|
|
163
|
+
const { data, projection } = await applicationFor(context)[verb](intent.target);
|
|
164
|
+
const actor = participantIdentity(projection.participant);
|
|
165
|
+
const target = participantIdentity(projection.target);
|
|
166
|
+
const action = data.activity !== null
|
|
167
|
+
? verb === 'listen' ? `${actor} turns an ear toward ${target}` : `${actor} turns away from ${target}`
|
|
168
|
+
: verb === 'listen' ? `${actor} already turns an ear toward ${target}` : `${actor} is not turned toward ${target}`;
|
|
169
|
+
return withPathOutput(projection.location, `${data.activity === null ? '○' : '·'} ${action}`, {
|
|
170
|
+
participantCount: projection.standingCount, held: projection.held,
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
present: (result) => process.stdout.write(result),
|
|
174
|
+
};
|
|
232
175
|
}
|
|
233
|
-
export const listenCommand =
|
|
234
|
-
|
|
235
|
-
async execute(intent, context) {
|
|
236
|
-
const squarePath = requireSquarePath(context);
|
|
237
|
-
const square = await Square.at({ path: squarePath, clock: nowMs });
|
|
238
|
-
try {
|
|
239
|
-
const result = await createSquareApplication({ cwd: context.cwd, env: context.env, squarePath, participant: intent.name, clock: nowMs }).listen(intent.target);
|
|
240
|
-
const participantCount = (await square.snapshot()).participants.filter((item) => item.state === 'joined').length;
|
|
241
|
-
return listenerPresentation(squarePath, intent.name, intent.target, 'listen', result.activity, participantCount);
|
|
242
|
-
}
|
|
243
|
-
finally {
|
|
244
|
-
await square.close();
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
present: (result) => process.stdout.write(result),
|
|
248
|
-
};
|
|
249
|
-
export const ignoreCommand = {
|
|
250
|
-
parse(argv, context) { return parseListener(argv, context, true); },
|
|
251
|
-
async execute(intent, context) {
|
|
252
|
-
const squarePath = requireSquarePath(context);
|
|
253
|
-
const square = await Square.at({ path: squarePath, clock: nowMs });
|
|
254
|
-
try {
|
|
255
|
-
const result = await createSquareApplication({ cwd: context.cwd, env: context.env, squarePath, participant: intent.name, clock: nowMs }).ignore(intent.target);
|
|
256
|
-
const participantCount = (await square.snapshot()).participants.filter((item) => item.state === 'joined').length;
|
|
257
|
-
return listenerPresentation(squarePath, intent.name, intent.target, 'ignore', result.activity, participantCount);
|
|
258
|
-
}
|
|
259
|
-
finally {
|
|
260
|
-
await square.close();
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
present: (result) => process.stdout.write(result),
|
|
264
|
-
};
|
|
176
|
+
export const listenCommand = listenerCommand('listen');
|
|
177
|
+
export const ignoreCommand = listenerCommand('ignore');
|
|
265
178
|
export const listeningCommand = {
|
|
266
179
|
parse(argv, context) { return parseListener(argv, context, false); },
|
|
267
|
-
async execute(
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const participantCount = (await square.snapshot()).participants.filter((item) => item.state === 'joined').length;
|
|
274
|
-
const body = targets.length === 0
|
|
275
|
-
? `○ ${participantIdentity(participant.name)} is not turned toward anyone`
|
|
276
|
-
: ['listening', ...targets.map((target) => ` · ${participantIdentity(target)}`)].join('\n');
|
|
277
|
-
return withPathOutput(squarePath, body, { participantCount });
|
|
278
|
-
}
|
|
279
|
-
finally {
|
|
280
|
-
await square.close();
|
|
281
|
-
}
|
|
180
|
+
async execute(_intent, context) {
|
|
181
|
+
const { data, projection } = await applicationFor(context).listening();
|
|
182
|
+
const body = data.listening.length === 0
|
|
183
|
+
? `○ ${participantIdentity(projection.participant)} is not turned toward anyone`
|
|
184
|
+
: ['listening', ...data.listening.map((target) => ` · ${participantIdentity(target)}`)].join('\n');
|
|
185
|
+
return withPathOutput(projection.location, body, { participantCount: projection.standingCount, held: projection.held });
|
|
282
186
|
},
|
|
283
187
|
present: (result) => process.stdout.write(result),
|
|
284
188
|
};
|
|
285
|
-
function validateDoneInput(body) {
|
|
286
|
-
try {
|
|
287
|
-
validateDoneBody(body);
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
fail(`${error instanceof Error ? error.message : String(error)}\nsquare done --help`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
function parseDone(argv, context) {
|
|
294
|
-
if (argv.length > 1)
|
|
295
|
-
usage(context.command);
|
|
296
|
-
if (argv[0] !== '-')
|
|
297
|
-
validateDoneInput(argv[0]);
|
|
298
|
-
return { name: requireParticipant(context.name), body: argv.length === 1 ? argv[0] : undefined };
|
|
299
|
-
}
|
|
300
189
|
export const doneCommand = {
|
|
301
|
-
parse
|
|
190
|
+
parse(argv, context) {
|
|
191
|
+
if (argv.length > 1)
|
|
192
|
+
usage(context.command);
|
|
193
|
+
return { body: argv[0] };
|
|
194
|
+
},
|
|
302
195
|
async execute(intent, context) {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const presentation = await openSquare(squarePath, { clock: nowMs, env: context.env, hostLedger: hostLedgerForEnv(context.env) });
|
|
310
|
-
const participantCount = (await entryPresentation(presentation, name).finally(() => closeOpenSquare(presentation))).participantCount;
|
|
311
|
-
return withPathOutput(squarePath, `○ you stepped out — your footsteps fade · ${result.activity.id}`, { participantCount });
|
|
196
|
+
const body = intent.body === '-' || ((intent.body === undefined || intent.body === '') && !process.stdin.isTTY)
|
|
197
|
+
? await readStdin() : intent.body;
|
|
198
|
+
const { data, projection } = await applicationFor(context).done(body);
|
|
199
|
+
return withPathOutput(projection.location, `○ you stepped out — your footsteps fade · ${data.activity.id}`, {
|
|
200
|
+
participantCount: projection.standingCount, held: projection.held,
|
|
201
|
+
});
|
|
312
202
|
},
|
|
313
203
|
present: (result) => process.stdout.write(result),
|
|
314
204
|
};
|
|
315
|
-
function parseHold(argv, context) {
|
|
316
|
-
if (argv.length > 1)
|
|
317
|
-
usage(context.command);
|
|
318
|
-
return { name: requireParticipant(context.name), body: argv[0] };
|
|
319
|
-
}
|
|
320
205
|
export const holdCommand = {
|
|
321
|
-
parse
|
|
206
|
+
parse(argv, context) {
|
|
207
|
+
if (argv.length > 1)
|
|
208
|
+
usage(context.command);
|
|
209
|
+
return { body: argv[0] };
|
|
210
|
+
},
|
|
322
211
|
async execute(intent, context) {
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
const result = await application.hold((await resolveBody(intent.body ?? '')).replace(/\r\n/g, '\n').trim());
|
|
326
|
-
const presentationSquare = await openSquare(squarePath, { clock: nowMs, env: context.env, hostLedger: hostLedgerForEnv(context.env) });
|
|
327
|
-
const presentation = await eventPresentation(presentationSquare, result.activity.id);
|
|
328
|
-
await closeOpenSquare(presentationSquare);
|
|
329
|
-
return withPathOutput(squarePath, `· ${renderRoomChangeText(presentation.activity)} · ${actId(presentation.activity.index)} · just now`, { participantCount: presentation.participantCount, held: true });
|
|
212
|
+
const { projection } = await applicationFor(context).hold((await resolveBody(intent.body ?? '')).replace(/\r\n/g, '\n').trim());
|
|
213
|
+
return withPathOutput(projection.location, `· ${renderRoomChangeText(projection.activity)} · ${formatActivityId(projection.activity.index)} · just now`, { participantCount: projection.standingCount, held: projection.held });
|
|
330
214
|
},
|
|
331
215
|
present: (result) => process.stdout.write(result),
|
|
332
216
|
};
|
|
@@ -334,16 +218,11 @@ export const resumeCommand = {
|
|
|
334
218
|
parse(argv, context) {
|
|
335
219
|
if (argv.length !== 0)
|
|
336
220
|
usage(context.command);
|
|
337
|
-
return {
|
|
221
|
+
return {};
|
|
338
222
|
},
|
|
339
|
-
async execute(
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const result = await application.resume();
|
|
343
|
-
const presentationSquare = await openSquare(squarePath, { clock: nowMs, env: context.env, hostLedger: hostLedgerForEnv(context.env) });
|
|
344
|
-
const presentation = await eventPresentation(presentationSquare, result.activity.id);
|
|
345
|
-
await closeOpenSquare(presentationSquare);
|
|
346
|
-
return withPathOutput(squarePath, `✓ ${renderRoomChangeText(presentation.activity)} · ${actId(presentation.activity.index)} · just now`, { participantCount: presentation.participantCount });
|
|
223
|
+
async execute(_intent, context) {
|
|
224
|
+
const { projection } = await applicationFor(context).resume();
|
|
225
|
+
return withPathOutput(projection.location, `✓ ${renderRoomChangeText(projection.activity)} · ${formatActivityId(projection.activity.index)} · just now`, { participantCount: projection.standingCount, held: projection.held });
|
|
347
226
|
},
|
|
348
227
|
present: (result) => process.stdout.write(result),
|
|
349
228
|
};
|