@astrosheep/square 0.3.106 → 0.4.1
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 +6 -12
- package/dist/artifact.js +43 -344
- package/dist/attention-presentation.d.ts +13 -7
- package/dist/attention-presentation.js +29 -68
- package/dist/boundary-presentation.d.ts +3 -16
- package/dist/boundary-presentation.js +29 -109
- package/dist/card-presentation.d.ts +1 -0
- package/dist/card-presentation.js +2 -0
- package/dist/catch-decisions.d.ts +2 -2
- package/dist/catch-decisions.js +7 -3
- package/dist/catch-selection.d.ts +8 -0
- package/dist/catch-selection.js +5 -0
- package/dist/claude-delivery.d.ts +14 -12
- package/dist/claude-delivery.js +42 -142
- package/dist/claude-mcp-context.js +2 -2
- package/dist/claude-mod.js +28 -140
- package/dist/claude-transport.d.ts +5 -0
- package/dist/claude-transport.js +34 -0
- package/dist/cli/context.d.ts +2 -2
- package/dist/cli/context.js +7 -10
- package/dist/cli/maintenance-commands.d.ts +0 -4
- package/dist/cli/maintenance-commands.js +2 -29
- package/dist/cli/observation-commands.d.ts +2 -0
- package/dist/cli/observation-commands.js +12 -2
- package/dist/cli/program.js +1 -1
- package/dist/cli/registry.js +4 -3
- package/dist/codex-address.d.ts +2 -2
- package/dist/codex-boundary-state.d.ts +1 -5
- package/dist/codex-boundary-state.js +0 -4
- package/dist/codex-hook.d.ts +7 -10
- package/dist/codex-hook.js +69 -33
- package/dist/codex-queue.d.ts +10 -11
- package/dist/codex-queue.js +32 -34
- package/dist/codex-watch.d.ts +2 -0
- package/dist/codex-watch.js +100 -0
- package/dist/decisions.js +3 -3
- package/dist/delivery-deferral.d.ts +1 -19
- package/dist/delivery-deferral.js +1 -29
- package/dist/delivery-frame.d.ts +7 -0
- package/dist/delivery-frame.js +11 -0
- package/dist/delivery-ledger-sqlite.d.ts +97 -0
- package/dist/delivery-ledger-sqlite.js +496 -0
- package/dist/delivery-ledger.d.ts +196 -0
- package/dist/delivery-ledger.js +268 -0
- package/dist/delivery-lifetime.d.ts +6 -0
- package/dist/delivery-lifetime.js +45 -0
- package/dist/harness-links.js +61 -7
- package/dist/harness.js +12 -17
- package/dist/help.js +3 -6
- package/dist/http-delivery.d.ts +5 -9
- package/dist/http-delivery.js +20 -79
- package/dist/inbox.d.ts +6 -57
- package/dist/inbox.js +24 -380
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -2
- 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 +15 -91
- package/dist/model.js +2 -140
- package/dist/neutral.d.ts +72 -0
- package/dist/neutral.js +27 -0
- package/dist/notifications.d.ts +24 -26
- package/dist/notifications.js +39 -143
- package/dist/operation-control.d.ts +4 -0
- package/dist/operation-control.js +20 -0
- 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/packages/agent-delivery/src/claude-native.d.ts +2 -0
- package/dist/packages/agent-delivery/src/claude-native.js +5 -0
- package/dist/packages/agent-delivery/src/codex-boundary.d.ts +11 -6
- package/dist/packages/agent-delivery/src/codex-boundary.js +31 -40
- package/dist/packages/agent-delivery/src/codex-hook.d.ts +17 -12
- package/dist/packages/agent-delivery/src/codex-hook.js +26 -39
- package/dist/packages/agent-delivery/src/codex.d.ts +3 -0
- package/dist/packages/agent-delivery/src/codex.js +41 -4
- package/dist/packages/agent-delivery/src/index.d.ts +3 -1
- package/dist/packages/agent-delivery/src/index.js +1 -1
- package/dist/packages/agent-delivery/src/paseo.js +11 -2
- package/dist/packages/agent-delivery/src/types.d.ts +1 -0
- package/dist/paseo-delivery.d.ts +5 -5
- package/dist/paseo-delivery.js +19 -99
- package/dist/paseo.d.ts +1 -1
- package/dist/paseo.js +1 -1
- package/dist/plugins/opencode/index.d.ts +5 -3
- package/dist/plugins/opencode/index.js +99 -21
- package/dist/plugins/opencode-shared/delivery.d.ts +23 -0
- package/dist/plugins/opencode-shared/delivery.js +109 -0
- package/dist/plugins/opencode-v1/index.d.ts +28 -0
- package/dist/plugins/opencode-v1/index.js +41 -0
- package/dist/plugins/opencode-v1/runtime.d.ts +56 -0
- package/dist/plugins/opencode-v1/runtime.js +152 -0
- package/dist/plugins/opencode-v1/transport.d.ts +13 -0
- package/dist/plugins/opencode-v1/transport.js +50 -0
- package/dist/plugins/paseo/shared/card-presentation.d.ts +10 -0
- package/dist/plugins/paseo/shared/card-presentation.js +7 -0
- package/dist/ports.d.ts +33 -214
- 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/session-lifecycle.d.ts +8 -7
- package/dist/session-lifecycle.js +40 -42
- package/dist/sqlite-framing.d.ts +8 -0
- package/dist/sqlite-framing.js +31 -0
- package/dist/sqlite-square.d.ts +16 -26
- package/dist/sqlite-square.js +199 -262
- 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 +5 -8
- package/dist/square-core.d.ts +0 -1
- package/dist/square-domain.d.ts +12 -10
- package/dist/square-domain.js +105 -223
- package/dist/square-facade.d.ts +25 -76
- package/dist/square-location.d.ts +6 -1
- package/dist/square-location.js +1 -1
- package/dist/square-post.d.ts +53 -0
- package/dist/square-post.js +4 -0
- package/dist/square-posting.d.ts +13 -0
- package/dist/square-posting.js +174 -0
- package/dist/square-producer-sqlite.d.ts +11 -0
- package/dist/square-producer-sqlite.js +210 -0
- package/dist/square-receive.d.ts +2 -3
- package/dist/square-sqlite.d.ts +33 -42
- package/dist/square-sqlite.js +236 -768
- package/dist/square-tools.d.ts +8 -0
- package/dist/square-tools.js +39 -0
- package/dist/square-values.d.ts +27 -0
- package/dist/square-values.js +90 -0
- package/dist/views.d.ts +6 -6
- package/dist/views.js +14 -9
- package/dist/wake-sink.d.ts +4 -11
- package/dist/wake-sink.js +8 -32
- package/dist/wake-transports.d.ts +4 -0
- package/dist/wake-transports.js +11 -0
- package/examples/symmetric-domains.mjs +29 -249
- package/guides/change-waits.md +13 -53
- package/guides/claude-native.md +19 -172
- package/guides/codex-delivery.md +55 -78
- package/guides/delivery-primitives.md +48 -207
- package/guides/operation-cancellation.md +2 -5
- package/guides/participant-ownership.md +25 -89
- package/guides/pi-native-delivery.md +19 -56
- package/guides/pi-tools.md +6 -8
- package/guides/row-runtime-delivery-evidence.md +2 -0
- package/guides/row-storage-design.md +19 -44
- package/guides/square-api.md +113 -538
- package/package.json +8 -8
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/hooks.json +1 -1
- package/plugins/claude/{hooks/register.js → mods/square.js} +4 -7
- package/plugins/claude/types.d.ts +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/hooks/hooks.json +11 -23
- package/plugins/opencode/index.ts +91 -23
- package/plugins/opencode-shared/delivery.ts +91 -0
- package/plugins/opencode-v1/index.ts +36 -0
- package/plugins/opencode-v1/runtime.ts +134 -0
- package/plugins/opencode-v1/transport.ts +41 -0
- package/plugins/paseo/OVERVIEW.md +5 -5
- package/plugins/paseo/README.md +7 -6
- package/plugins/paseo/client/markdown.tsx +5 -5
- package/plugins/paseo/client/square-message.tsx +28 -24
- package/plugins/paseo/client/transform.ts +8 -5
- package/plugins/paseo/shared/card-presentation.ts +16 -0
- package/plugins/paseo/shared/message.ts +6 -11
- package/plugins/pi/square-pi.js +167 -451
- package/dist/channel.d.ts +0 -74
- package/dist/channel.js +0 -92
- package/dist/claude-delivery-status.d.ts +0 -13
- package/dist/claude-delivery-status.js +0 -46
- package/dist/cmd/notify-once.d.ts +0 -2
- package/dist/cmd/notify-once.js +0 -29
- package/dist/delivery-attempts.d.ts +0 -52
- package/dist/delivery-attempts.js +0 -73
- package/dist/delivery-effects.d.ts +0 -139
- package/dist/delivery-effects.js +0 -163
- package/dist/delivery-health.d.ts +0 -51
- package/dist/delivery-health.js +0 -173
- package/dist/delivery-operations.d.ts +0 -9
- package/dist/delivery-operations.js +0 -168
- package/dist/delivery-primitives.d.ts +0 -5
- package/dist/delivery-primitives.js +0 -3
- package/dist/delivery.d.ts +0 -45
- package/dist/delivery.js +0 -106
- package/dist/plugins/opencode/delivery.d.ts +0 -19
- package/dist/plugins/opencode/delivery.js +0 -238
- package/dist/presentation-operations.d.ts +0 -18
- package/dist/presentation-operations.js +0 -86
- package/dist/square-index.d.ts +0 -16
- package/dist/square-index.js +0 -106
- 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/plugins/opencode/delivery.ts +0 -211
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
export const FORMAT4_ADDED_OBJECTS = new Set([
|
|
2
|
-
'seats', 'seat_body', 'delivery_evidence', 'delivery_claim_token', 'delivery_activity', 'delivery_cancellations',
|
|
3
|
-
]);
|
|
4
|
-
export const FORMAT4_REPLACED_OBJECTS = new Set(['routes', 'route_participant', 'route_session']);
|
|
5
|
-
const LEGACY_ROUTES_SQL = `CREATE TABLE routes (
|
|
6
|
-
position INTEGER PRIMARY KEY CHECK (position >= 0),
|
|
7
|
-
participant_key_json TEXT COLLATE BINARY NOT NULL,
|
|
8
|
-
session_json TEXT COLLATE BINARY NOT NULL,
|
|
9
|
-
kind TEXT NOT NULL CHECK (kind IN ('opencode-server','codex-queue','claude-native','paseo')),
|
|
10
|
-
updated_at REAL NOT NULL,
|
|
11
|
-
payload_json TEXT NOT NULL CHECK (json_valid(payload_json))
|
|
12
|
-
);
|
|
13
|
-
CREATE INDEX route_participant ON routes(participant_key_json, position);
|
|
14
|
-
CREATE INDEX route_session ON routes(session_json, position);`;
|
|
15
|
-
function normalizedSql(sql) {
|
|
16
|
-
return sql.trim().replace(/;$/, '').replace(/\s+/g, ' ').replace(/\s*([(),=])\s*/g, '$1');
|
|
17
|
-
}
|
|
18
|
-
/** Historical activity framing only; no runtime activity decoder accepts these kinds. */
|
|
19
|
-
export function legacyActivitySchema(currentSchemaSql) {
|
|
20
|
-
return currentSchemaSql
|
|
21
|
-
.replace("kind IN ('join','done','say','read','listen','ignore','unlisten')", "kind IN ('join','done','say','hold','resume','read','listen','ignore','unlisten')")
|
|
22
|
-
.replace(' actor_json TEXT COLLATE BINARY NOT NULL,', ' actor_json TEXT COLLATE BINARY,')
|
|
23
|
-
.replace(' actor_key_json TEXT COLLATE BINARY NOT NULL,', ' actor_key_json TEXT COLLATE BINARY,')
|
|
24
|
-
.replace(" CHECK (kind = 'say' OR (reach IS NULL AND reply_index IS NULL))", " CHECK ((actor_json IS NULL) = (actor_key_json IS NULL)),\n CHECK (kind IN ('hold','resume') OR actor_json IS NOT NULL),\n CHECK (kind = 'say' OR (reach IS NULL AND reply_index IS NULL))");
|
|
25
|
-
}
|
|
26
|
-
function legacyRowSchema(currentSchemaSql, version) {
|
|
27
|
-
const statements = currentSchemaSql.split(';').map((statement) => statement.trim()).filter(Boolean)
|
|
28
|
-
.filter((statement) => {
|
|
29
|
-
const match = /^(?:CREATE (?:UNIQUE )?TABLE|CREATE (?:UNIQUE )?INDEX)\s+([a-z_]+)/i.exec(statement);
|
|
30
|
-
return match === null || !FORMAT4_ADDED_OBJECTS.has(match[1]) && !FORMAT4_REPLACED_OBJECTS.has(match[1]);
|
|
31
|
-
});
|
|
32
|
-
const legacyStatements = statements.join(';\n')
|
|
33
|
-
.replace(' delivery_revision INTEGER NOT NULL CHECK (delivery_revision BETWEEN 0 AND 9007199254740991),\n', '')
|
|
34
|
-
.replace(' generation_json TEXT NOT NULL DEFAULT \'""\',\n', '');
|
|
35
|
-
const allStatements = [...legacyStatements.split(';').map((statement) => statement.trim()).filter(Boolean),
|
|
36
|
-
...LEGACY_ROUTES_SQL.split(';').map((statement) => statement.trim()).filter(Boolean)];
|
|
37
|
-
let schema = allStatements.join(';\n');
|
|
38
|
-
if (version === 2) {
|
|
39
|
-
schema = schema.replace("kind IN ('join','done','say','hold','resume','read','listen','ignore','unlisten')", "kind IN ('join','done','say','hold','resume','read','listen','ignore')");
|
|
40
|
-
}
|
|
41
|
-
return schema.split(';').map((statement) => normalizedSql(statement)).filter(Boolean).sort();
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Read-only recognition of the exact row framing accepted by explicit migration.
|
|
45
|
-
* It inspects identity, owned schema and journal mode only; it never reads row
|
|
46
|
-
* contents (including legacy routes), changes pragmas, or performs DDL.
|
|
47
|
-
*/
|
|
48
|
-
export function legacyRowFramingIssue(database, applicationId, version, location, currentSchemaSql) {
|
|
49
|
-
const identity = database.prepare('SELECT application_id, user_version FROM pragma_application_id, pragma_user_version').get();
|
|
50
|
-
if (identity.application_id !== applicationId)
|
|
51
|
-
return 'unrelated SQLite database.';
|
|
52
|
-
if (identity.user_version !== version)
|
|
53
|
-
return 'unsupported SQLite format version.';
|
|
54
|
-
const actual = database.prepare("SELECT sql FROM sqlite_schema WHERE name NOT GLOB 'sqlite_*' AND sql IS NOT NULL").all()
|
|
55
|
-
.map((row) => typeof row.sql === 'string' ? normalizedSql(row.sql) : '')
|
|
56
|
-
.sort();
|
|
57
|
-
const expected = legacyRowSchema(currentSchemaSql, version);
|
|
58
|
-
if (actual.length !== expected.length || actual.some((sql, index) => sql !== expected[index]))
|
|
59
|
-
return 'unsupported row schema.';
|
|
60
|
-
const journalMode = database.prepare('PRAGMA journal_mode').get().journal_mode;
|
|
61
|
-
if (journalMode !== (location === ':memory:' ? 'memory' : 'delete'))
|
|
62
|
-
return 'unsupported journal mode.';
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { type HarnessCoordinate } from './owner.js';
|
|
2
|
-
/** Offline conversion input only; never a runtime ownership or evidence reader. */
|
|
3
|
-
export interface LegacyOwner {
|
|
4
|
-
readonly participant: string;
|
|
5
|
-
readonly coordinate: HarnessCoordinate;
|
|
6
|
-
}
|
|
7
|
-
export interface LegacyHostData {
|
|
8
|
-
readonly owners: readonly LegacyOwner[];
|
|
9
|
-
readonly evidence: readonly LegacyDeliveryEvidence[];
|
|
10
|
-
}
|
|
11
|
-
export interface LegacyDeliveryEvidence {
|
|
12
|
-
readonly v: 1;
|
|
13
|
-
readonly location: string;
|
|
14
|
-
readonly participant: string;
|
|
15
|
-
readonly session: string;
|
|
16
|
-
readonly activity: string;
|
|
17
|
-
readonly kind: 'wake' | 'presentation' | 'lifecycle';
|
|
18
|
-
readonly outcome: string;
|
|
19
|
-
readonly at?: number;
|
|
20
|
-
readonly expiresAt?: number;
|
|
21
|
-
readonly attemptN?: number;
|
|
22
|
-
readonly claimToken?: string;
|
|
23
|
-
readonly [key: string]: unknown;
|
|
24
|
-
}
|
|
25
|
-
/** One frozen snapshot, latest owners only; no age, expiry, or ownership history inference. */
|
|
26
|
-
export declare function readLegacyHostData(location: string, env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<LegacyHostData>;
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { pathToFileURL } from 'node:url';
|
|
6
|
-
import { canonicalPath } from './canonical-path.js';
|
|
7
|
-
import { inSqliteTransaction } from './sqlite-transaction.js';
|
|
8
|
-
import { harnessOwner } from './owner.js';
|
|
9
|
-
import { nameKey } from './model.js';
|
|
10
|
-
const LEDGER_FILENAME = 'host-ledger.sqlite';
|
|
11
|
-
const LEDGER_APPLICATION_ID = 0x5351484c;
|
|
12
|
-
const LEDGER_VERSION = 2;
|
|
13
|
-
const tableSchema = {
|
|
14
|
-
host_meta: 'CREATE TABLE host_meta (id INTEGER PRIMARY KEY CHECK(id=1), presence_revision INTEGER NOT NULL, evidence_revision INTEGER NOT NULL)',
|
|
15
|
-
host_presence: 'CREATE TABLE host_presence (seq INTEGER PRIMARY KEY AUTOINCREMENT, location_key TEXT NOT NULL, participant_key TEXT NOT NULL, session_key TEXT NOT NULL, channel_key TEXT NOT NULL, effective_at REAL NOT NULL, row_json TEXT NOT NULL)',
|
|
16
|
-
host_evidence: 'CREATE TABLE host_evidence (seq INTEGER PRIMARY KEY AUTOINCREMENT, location_key TEXT NOT NULL, participant_key TEXT NOT NULL, session_key TEXT NOT NULL, activity_key TEXT NOT NULL, kind TEXT NOT NULL, outcome TEXT NOT NULL, claim_token_key TEXT, effective_at REAL NOT NULL, row_json TEXT NOT NULL)',
|
|
17
|
-
host_native_tokens: "CREATE TABLE host_native_tokens (harness TEXT NOT NULL CHECK(harness='claude'), session_key TEXT NOT NULL, token_key TEXT NOT NULL, PRIMARY KEY(harness,session_key,token_key)) WITHOUT ROWID",
|
|
18
|
-
};
|
|
19
|
-
const indexes = {
|
|
20
|
-
host_presence_identity: ['host_presence', 'location_key', 'participant_key', 'seq'],
|
|
21
|
-
host_presence_session: ['host_presence', 'session_key', 'seq'],
|
|
22
|
-
host_presence_time: ['host_presence', 'effective_at'],
|
|
23
|
-
host_evidence_attention: ['host_evidence', 'location_key', 'participant_key', 'activity_key', 'kind', 'session_key', 'seq'],
|
|
24
|
-
host_evidence_kind_session: ['host_evidence', 'kind', 'session_key', 'seq'],
|
|
25
|
-
host_evidence_session: ['host_evidence', 'session_key', 'seq'],
|
|
26
|
-
host_evidence_token: ['host_evidence', 'location_key', 'participant_key', 'activity_key', 'session_key', 'claim_token_key', 'seq'],
|
|
27
|
-
host_evidence_outcome_time: ['host_evidence', 'outcome', 'effective_at'],
|
|
28
|
-
host_evidence_time: ['host_evidence', 'effective_at'],
|
|
29
|
-
host_evidence_native_token: ['host_evidence', 'session_key', 'claim_token_key', 'seq'],
|
|
30
|
-
};
|
|
31
|
-
const LEGACY_FILES = ['presence.ndjsonl', 'evidence.ndjsonl'];
|
|
32
|
-
function indexSql(name, fields) {
|
|
33
|
-
return `CREATE INDEX ${name} ON ${fields[0]} (${fields.slice(1).join(',')})`;
|
|
34
|
-
}
|
|
35
|
-
function normalizedSql(sql) {
|
|
36
|
-
return sql.replace(/\s+/g, '').replace(/;$/, '');
|
|
37
|
-
}
|
|
38
|
-
function recordKey(value) { return JSON.stringify(value); }
|
|
39
|
-
function validateLedger(database) {
|
|
40
|
-
const application = database.prepare('PRAGMA application_id').get().application_id;
|
|
41
|
-
const version = database.prepare('PRAGMA user_version').get().user_version;
|
|
42
|
-
if (application !== LEDGER_APPLICATION_ID || version !== LEDGER_VERSION)
|
|
43
|
-
throw invalid('unsupported format.');
|
|
44
|
-
if (database.prepare('PRAGMA journal_mode').get().journal_mode !== 'delete')
|
|
45
|
-
throw invalid('unsupported journal mode.');
|
|
46
|
-
const expected = new Map([
|
|
47
|
-
...Object.entries(tableSchema),
|
|
48
|
-
...Object.entries(indexes).map(([name, fields]) => [name, indexSql(name, fields)]),
|
|
49
|
-
]);
|
|
50
|
-
const schema = database.prepare("SELECT name,sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%'").all();
|
|
51
|
-
if (schema.length !== expected.size || schema.some((row) => typeof row.name !== 'string' || typeof row.sql !== 'string'
|
|
52
|
-
|| !expected.has(row.name) || normalizedSql(row.sql) !== normalizedSql(expected.get(row.name))))
|
|
53
|
-
throw invalid('schema or indexes are malformed.');
|
|
54
|
-
const meta = database.prepare('SELECT id,presence_revision,evidence_revision FROM host_meta').all();
|
|
55
|
-
if (meta.length !== 1 || meta[0].id !== 1 || ![meta[0].presence_revision, meta[0].evidence_revision].every((value) => Number.isSafeInteger(value) && value >= 0))
|
|
56
|
-
throw invalid('revision header is malformed.');
|
|
57
|
-
const integrity = database.prepare('PRAGMA integrity_check').all();
|
|
58
|
-
if (integrity.length !== 1 || integrity[0].integrity_check !== 'ok')
|
|
59
|
-
throw invalid('integrity check failed.');
|
|
60
|
-
// Token-only tombstones have no artifact coordinate. Never guess or discard replay protection.
|
|
61
|
-
if (database.prepare('SELECT 1 FROM host_native_tokens LIMIT 1').get() !== undefined)
|
|
62
|
-
throw invalid('native token tombstones cannot be mapped safely; preserve replay protection and resolve the ledger offline.');
|
|
63
|
-
}
|
|
64
|
-
function ledgerRoot(env) {
|
|
65
|
-
return path.resolve(env.SQUARE_HOST_LEDGER_ROOT
|
|
66
|
-
?? (env.SQUARE_REGISTRY === undefined ? path.join(env.HOME ?? os.homedir(), '.square', 'host-ledger') : path.dirname(env.SQUARE_REGISTRY)));
|
|
67
|
-
}
|
|
68
|
-
function invalid(detail) {
|
|
69
|
-
return new Error(`Invalid legacy host ledger: ${detail}`);
|
|
70
|
-
}
|
|
71
|
-
function finite(value) {
|
|
72
|
-
return typeof value === 'number' && Number.isFinite(value);
|
|
73
|
-
}
|
|
74
|
-
function decodeEvidence(value) {
|
|
75
|
-
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
76
|
-
throw invalid('evidence record is not an object.');
|
|
77
|
-
const row = value;
|
|
78
|
-
if (row.v !== 1 || typeof row.location !== 'string' || typeof row.participant !== 'string' || typeof row.session !== 'string'
|
|
79
|
-
|| typeof row.activity !== 'string' || !['wake', 'presentation', 'lifecycle'].includes(row.kind)
|
|
80
|
-
|| typeof row.outcome !== 'string')
|
|
81
|
-
throw invalid('evidence record fields are malformed.');
|
|
82
|
-
if (row.at !== undefined && !finite(row.at))
|
|
83
|
-
throw invalid('evidence time is malformed.');
|
|
84
|
-
if (row.expiresAt !== undefined && !finite(row.expiresAt))
|
|
85
|
-
throw invalid('evidence expiry is malformed.');
|
|
86
|
-
if (row.attemptN !== undefined && (!Number.isSafeInteger(row.attemptN) || row.attemptN < 0))
|
|
87
|
-
throw invalid('evidence attempt is malformed.');
|
|
88
|
-
if (row.claimToken !== undefined && (typeof row.claimToken !== 'string' || row.claimToken.length === 0))
|
|
89
|
-
throw invalid('evidence claim token is malformed.');
|
|
90
|
-
return row;
|
|
91
|
-
}
|
|
92
|
-
function record(row) {
|
|
93
|
-
if (!Number.isSafeInteger(row.seq) || row.seq < 1 || typeof row.row_json !== 'string')
|
|
94
|
-
throw invalid('row framing is malformed.');
|
|
95
|
-
let value;
|
|
96
|
-
try {
|
|
97
|
-
value = JSON.parse(row.row_json);
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
throw invalid('record JSON is malformed.');
|
|
101
|
-
}
|
|
102
|
-
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
103
|
-
throw invalid('record is not an object.');
|
|
104
|
-
return value;
|
|
105
|
-
}
|
|
106
|
-
function projections(row, expected) {
|
|
107
|
-
if (Object.entries(expected).some(([key, value]) => row[key] !== value))
|
|
108
|
-
throw invalid('record projections are malformed.');
|
|
109
|
-
}
|
|
110
|
-
/** One frozen snapshot, latest owners only; no age, expiry, or ownership history inference. */
|
|
111
|
-
export async function readLegacyHostData(location, env = process.env, signal) {
|
|
112
|
-
if (signal?.aborted)
|
|
113
|
-
throw signal.reason;
|
|
114
|
-
const root = ledgerRoot(env);
|
|
115
|
-
const file = path.join(root, LEDGER_FILENAME);
|
|
116
|
-
try {
|
|
117
|
-
await fs.promises.stat(file);
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
if (error.code !== 'ENOENT')
|
|
121
|
-
throw error;
|
|
122
|
-
for (const legacy of LEGACY_FILES) {
|
|
123
|
-
try {
|
|
124
|
-
await fs.promises.stat(path.join(root, legacy));
|
|
125
|
-
throw invalid('legacy line sources require separate host-ledger migration.');
|
|
126
|
-
}
|
|
127
|
-
catch (nested) {
|
|
128
|
-
if (nested.code !== 'ENOENT')
|
|
129
|
-
throw nested;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return { owners: [], evidence: [] };
|
|
133
|
-
}
|
|
134
|
-
const uri = pathToFileURL(file);
|
|
135
|
-
uri.searchParams.set('mode', 'ro');
|
|
136
|
-
const database = new DatabaseSync(uri.href);
|
|
137
|
-
try {
|
|
138
|
-
const canonical = await canonicalPath(location);
|
|
139
|
-
return await inSqliteTransaction(database, false, () => validateLedger(database), () => {
|
|
140
|
-
const owners = database.prepare(`SELECT * FROM (
|
|
141
|
-
SELECT *,row_number() OVER (PARTITION BY participant_key ORDER BY effective_at DESC,seq DESC) AS ordinal
|
|
142
|
-
FROM host_presence WHERE location_key=?) WHERE ordinal=1`).all(recordKey(canonical)).map(row => {
|
|
143
|
-
const value = record(row);
|
|
144
|
-
const at = value.at ?? value.updatedAt;
|
|
145
|
-
if (value.v !== 1 || value.location !== canonical || typeof value.participant !== 'string'
|
|
146
|
-
|| !finite(at))
|
|
147
|
-
throw invalid('owner fields are malformed.');
|
|
148
|
-
const coordinate = { channel: value.channel, session: value.session, ...(value.agent === undefined ? {} : { agent: value.agent }) };
|
|
149
|
-
harnessOwner(coordinate);
|
|
150
|
-
projections(row, { location_key: recordKey(canonical), participant_key: recordKey(nameKey(value.participant)),
|
|
151
|
-
channel_key: recordKey(coordinate.channel), session_key: recordKey(coordinate.session), effective_at: at });
|
|
152
|
-
return { participant: value.participant, coordinate };
|
|
153
|
-
});
|
|
154
|
-
const evidence = database.prepare("SELECT * FROM host_evidence WHERE location_key=? AND kind IN ('wake','presentation') ORDER BY seq").all(recordKey(canonical)).map(row => {
|
|
155
|
-
const value = decodeEvidence(record(row));
|
|
156
|
-
if (value.location !== canonical || !finite(value.at))
|
|
157
|
-
throw invalid('evidence fields are malformed.');
|
|
158
|
-
projections(row, { location_key: recordKey(canonical), participant_key: recordKey(nameKey(value.participant)), session_key: recordKey(value.session),
|
|
159
|
-
activity_key: recordKey(value.activity), kind: value.kind, outcome: value.outcome,
|
|
160
|
-
claim_token_key: value.claimToken === undefined ? null : recordKey(value.claimToken), effective_at: value.at });
|
|
161
|
-
return value;
|
|
162
|
-
});
|
|
163
|
-
return { owners, evidence };
|
|
164
|
-
}, signal);
|
|
165
|
-
}
|
|
166
|
-
finally {
|
|
167
|
-
database.close();
|
|
168
|
-
}
|
|
169
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { type SquareState } from './square-sqlite.js';
|
|
2
|
-
/** Validate persisted v1 JSON; row codecs share activity and lease acceptance. */
|
|
3
|
-
export declare function validateSquareState(value: unknown): SquareState;
|
|
4
|
-
export interface MigrationCounts {
|
|
5
|
-
readonly activities: number;
|
|
6
|
-
readonly receipts: number;
|
|
7
|
-
readonly leases: number;
|
|
8
|
-
readonly routes: number;
|
|
9
|
-
readonly recoveredSeats: number;
|
|
10
|
-
readonly unownedStanding: number;
|
|
11
|
-
readonly sharedBodySeats: number;
|
|
12
|
-
readonly skippedEvidence: number;
|
|
13
|
-
}
|
|
14
|
-
export interface MigrationOutcome {
|
|
15
|
-
readonly status: 'migrated' | 'already-current';
|
|
16
|
-
/** Participants standing after the conversion, for the CLI header. */
|
|
17
|
-
readonly standing: number;
|
|
18
|
-
readonly counts?: MigrationCounts;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Explicit conversion of the supported legacy formats. Row-backed versions 2 and 3 are
|
|
22
|
-
* preflighted read-only, then receive ownership/evidence and deferral storage in one
|
|
23
|
-
* format-8 transaction. Formats 4/5 gain attachment; format 4 also gains empty deferrals.
|
|
24
|
-
* All legacy seats are encoded as opaque owners, preserving format-6 attachment.
|
|
25
|
-
* Every source drops obsolete activities and their identity references, clears dangling
|
|
26
|
-
* replies and rebuilds derived indices; surviving ids and allocation watermarks remain stable.
|
|
27
|
-
* Legacy delivery evidence is copied from HostLedger only when its owner/session mapping is
|
|
28
|
-
* unique; no source record is retired. Version 1 is not a supported source for this format transition.
|
|
29
|
-
*/
|
|
30
|
-
export declare function migrateSquareFile(location: string, signal?: AbortSignal, env?: NodeJS.ProcessEnv): Promise<MigrationOutcome>;
|