@astrosheep/square 0.3.86 → 0.3.88
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/artifact.d.ts +6 -1
- package/dist/artifact.js +79 -10
- package/dist/boundary-presentation.d.ts +5 -4
- package/dist/boundary-presentation.js +21 -25
- package/dist/catch-decisions.js +2 -1
- package/dist/claude-delivery-status.d.ts +8 -2
- package/dist/claude-delivery-status.js +26 -10
- package/dist/claude-delivery.d.ts +8 -4
- package/dist/claude-delivery.js +114 -104
- package/dist/claude-mcp-context.js +2 -2
- package/dist/claude-mod.js +119 -105
- package/dist/cli/context.d.ts +3 -1
- package/dist/cli/context.js +25 -1
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +14 -10
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.js +1 -0
- package/dist/cli/registry.js +0 -2
- package/dist/cli/square-commands.d.ts +4 -2
- package/dist/cli/square-commands.js +21 -6
- package/dist/codex-hook.d.ts +3 -3
- package/dist/codex-hook.js +4 -4
- package/dist/codex-queue.d.ts +5 -6
- package/dist/codex-queue.js +9 -5
- package/dist/decisions.d.ts +3 -2
- package/dist/decisions.js +18 -6
- package/dist/delivery-health.d.ts +32 -2
- package/dist/delivery-health.js +108 -45
- package/dist/delivery-operations.d.ts +1 -2
- package/dist/delivery-operations.js +155 -196
- package/dist/delivery.d.ts +14 -23
- package/dist/delivery.js +48 -18
- package/dist/file-lock.d.ts +8 -1
- package/dist/file-lock.js +2 -0
- package/dist/help.js +8 -11
- package/dist/inbox.d.ts +35 -9
- package/dist/inbox.js +228 -144
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -3
- package/dist/list.js +9 -4
- package/dist/mcp.js +12 -1
- package/dist/model.d.ts +39 -5
- package/dist/model.js +84 -0
- package/dist/notifications.d.ts +8 -6
- package/dist/notifications.js +56 -143
- package/dist/operation-presentation.js +7 -4
- package/dist/participant-identity.d.ts +0 -3
- package/dist/participant-identity.js +0 -31
- package/dist/paseo-delivery.d.ts +5 -6
- package/dist/paseo-delivery.js +13 -8
- package/dist/paseo.d.ts +1 -1
- package/dist/paseo.js +1 -1
- package/dist/plugins/opencode/delivery.d.ts +8 -3
- package/dist/plugins/opencode/delivery.js +187 -132
- package/dist/plugins/opencode/index.js +12 -38
- package/dist/ports.d.ts +112 -40
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +51 -35
- package/dist/presentation.js +8 -3
- package/dist/seats.d.ts +7 -0
- package/dist/seats.js +27 -0
- package/dist/session-lifecycle.d.ts +2 -2
- package/dist/session-lifecycle.js +10 -12
- package/dist/sqlite-square.d.ts +20 -9
- package/dist/sqlite-square.js +476 -341
- package/dist/square-api.d.ts +1 -0
- package/dist/square-api.js +3 -4
- package/dist/square-core.d.ts +3 -2
- package/dist/square-domain.d.ts +12 -5
- package/dist/square-domain.js +163 -7
- package/dist/square-facade.d.ts +16 -10
- package/dist/square-index.d.ts +24 -0
- package/dist/square-index.js +131 -0
- package/dist/square-legacy-framing.d.ts +9 -0
- package/dist/square-legacy-framing.js +56 -0
- package/dist/square-migration-host-ledger.d.ts +26 -0
- package/dist/square-migration-host-ledger.js +168 -0
- package/dist/square-migration.d.ts +5 -5
- package/dist/square-migration.js +373 -71
- package/dist/square-sqlite.d.ts +9 -9
- package/dist/square-sqlite.js +329 -79
- package/dist/square-stdio.d.ts +1 -1
- package/dist/square-stdio.js +12 -7
- package/dist/square-tools.d.ts +1 -1
- package/dist/square-tools.js +80 -27
- package/dist/stdio-server.js +4 -2
- package/dist/stream.d.ts +3 -2
- package/dist/stream.js +9 -10
- package/dist/views.d.ts +9 -14
- package/dist/views.js +52 -70
- package/dist/wakes.d.ts +6 -5
- package/dist/wakes.js +20 -17
- package/guides/application-facade-delivery-evidence.md +1 -1
- package/guides/claude-native.md +9 -9
- package/guides/mcp.md +2 -2
- package/guides/migration.md +107 -67
- package/guides/pi-tools.md +1 -1
- package/guides/row-storage-design.md +1 -1
- package/guides/square-api.md +61 -28
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/register.js +1 -1
- package/plugins/claude/skills/square/SKILL.md +4 -4
- package/plugins/claude/types.d.ts +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +170 -118
- package/plugins/opencode/index.ts +12 -30
- package/plugins/pi/square-pi.js +56 -18
- package/skills/square/SKILL.md +4 -4
- package/dist/cli/ledger-command.d.ts +0 -12
- package/dist/cli/ledger-command.js +0 -72
- package/dist/host-ledger-file-adapter.d.ts +0 -47
- package/dist/host-ledger-file-adapter.js +0 -384
- package/dist/host-ledger-migration.d.ts +0 -27
- package/dist/host-ledger-migration.js +0 -264
- package/dist/host-ledger-root.d.ts +0 -2
- package/dist/host-ledger-root.js +0 -9
- package/dist/host-ledger-sqlite.d.ts +0 -65
- package/dist/host-ledger-sqlite.js +0 -368
- package/dist/host-ledger.d.ts +0 -195
- package/dist/host-ledger.js +0 -1
- package/dist/ledger-maintenance.d.ts +0 -30
- package/dist/ledger-maintenance.js +0 -110
- package/dist/open-square.d.ts +0 -38
- package/dist/open-square.js +0 -81
- package/dist/participant-host.d.ts +0 -23
- package/dist/participant-host.js +0 -92
- package/dist/registry.d.ts +0 -55
- package/dist/registry.js +0 -123
- package/dist/routes.d.ts +0 -39
- package/dist/routes.js +0 -99
- package/dist/square-actions.d.ts +0 -56
- package/dist/square-actions.js +0 -353
- package/dist/square-projections.d.ts +0 -31
- package/dist/square-projections.js +0 -64
- package/dist/wake-attempts.d.ts +0 -10
- package/dist/wake-attempts.js +0 -39
- package/dist/wake-eligibility.d.ts +0 -53
- package/dist/wake-eligibility.js +0 -123
- package/dist/wake-evidence.d.ts +0 -33
- package/dist/wake-evidence.js +0 -32
- package/guides/host-ledger.md +0 -58
- package/guides/indexed-host-ledger-performance.md +0 -39
|
@@ -0,0 +1,168 @@
|
|
|
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 { nameKey, validateBody } from './model.js';
|
|
9
|
+
const LEDGER_FILENAME = 'host-ledger.sqlite';
|
|
10
|
+
const LEDGER_APPLICATION_ID = 0x5351484c;
|
|
11
|
+
const LEDGER_VERSION = 2;
|
|
12
|
+
const tableSchema = {
|
|
13
|
+
host_meta: 'CREATE TABLE host_meta (id INTEGER PRIMARY KEY CHECK(id=1), presence_revision INTEGER NOT NULL, evidence_revision INTEGER NOT NULL)',
|
|
14
|
+
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)',
|
|
15
|
+
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)',
|
|
16
|
+
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",
|
|
17
|
+
};
|
|
18
|
+
const indexes = {
|
|
19
|
+
host_presence_identity: ['host_presence', 'location_key', 'participant_key', 'seq'],
|
|
20
|
+
host_presence_session: ['host_presence', 'session_key', 'seq'],
|
|
21
|
+
host_presence_time: ['host_presence', 'effective_at'],
|
|
22
|
+
host_evidence_attention: ['host_evidence', 'location_key', 'participant_key', 'activity_key', 'kind', 'session_key', 'seq'],
|
|
23
|
+
host_evidence_kind_session: ['host_evidence', 'kind', 'session_key', 'seq'],
|
|
24
|
+
host_evidence_session: ['host_evidence', 'session_key', 'seq'],
|
|
25
|
+
host_evidence_token: ['host_evidence', 'location_key', 'participant_key', 'activity_key', 'session_key', 'claim_token_key', 'seq'],
|
|
26
|
+
host_evidence_outcome_time: ['host_evidence', 'outcome', 'effective_at'],
|
|
27
|
+
host_evidence_time: ['host_evidence', 'effective_at'],
|
|
28
|
+
host_evidence_native_token: ['host_evidence', 'session_key', 'claim_token_key', 'seq'],
|
|
29
|
+
};
|
|
30
|
+
const LEGACY_FILES = ['presence.ndjsonl', 'evidence.ndjsonl'];
|
|
31
|
+
function indexSql(name, fields) {
|
|
32
|
+
return `CREATE INDEX ${name} ON ${fields[0]} (${fields.slice(1).join(',')})`;
|
|
33
|
+
}
|
|
34
|
+
function normalizedSql(sql) {
|
|
35
|
+
return sql.replace(/\s+/g, '').replace(/;$/, '');
|
|
36
|
+
}
|
|
37
|
+
function recordKey(value) { return JSON.stringify(value); }
|
|
38
|
+
function validateLedger(database) {
|
|
39
|
+
const application = database.prepare('PRAGMA application_id').get().application_id;
|
|
40
|
+
const version = database.prepare('PRAGMA user_version').get().user_version;
|
|
41
|
+
if (application !== LEDGER_APPLICATION_ID || version !== LEDGER_VERSION)
|
|
42
|
+
throw invalid('unsupported format.');
|
|
43
|
+
if (database.prepare('PRAGMA journal_mode').get().journal_mode !== 'delete')
|
|
44
|
+
throw invalid('unsupported journal mode.');
|
|
45
|
+
const expected = new Map([
|
|
46
|
+
...Object.entries(tableSchema),
|
|
47
|
+
...Object.entries(indexes).map(([name, fields]) => [name, indexSql(name, fields)]),
|
|
48
|
+
]);
|
|
49
|
+
const schema = database.prepare("SELECT name,sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%'").all();
|
|
50
|
+
if (schema.length !== expected.size || schema.some((row) => typeof row.name !== 'string' || typeof row.sql !== 'string'
|
|
51
|
+
|| !expected.has(row.name) || normalizedSql(row.sql) !== normalizedSql(expected.get(row.name))))
|
|
52
|
+
throw invalid('schema or indexes are malformed.');
|
|
53
|
+
const meta = database.prepare('SELECT id,presence_revision,evidence_revision FROM host_meta').all();
|
|
54
|
+
if (meta.length !== 1 || meta[0].id !== 1 || ![meta[0].presence_revision, meta[0].evidence_revision].every((value) => Number.isSafeInteger(value) && value >= 0))
|
|
55
|
+
throw invalid('revision header is malformed.');
|
|
56
|
+
const integrity = database.prepare('PRAGMA integrity_check').all();
|
|
57
|
+
if (integrity.length !== 1 || integrity[0].integrity_check !== 'ok')
|
|
58
|
+
throw invalid('integrity check failed.');
|
|
59
|
+
// Token-only tombstones have no artifact coordinate. Never guess or discard replay protection.
|
|
60
|
+
if (database.prepare('SELECT 1 FROM host_native_tokens LIMIT 1').get() !== undefined)
|
|
61
|
+
throw invalid('native token tombstones cannot be mapped safely; preserve replay protection and resolve the ledger offline.');
|
|
62
|
+
}
|
|
63
|
+
function ledgerRoot(env) {
|
|
64
|
+
return path.resolve(env.SQUARE_HOST_LEDGER_ROOT
|
|
65
|
+
?? (env.SQUARE_REGISTRY === undefined ? path.join(env.HOME ?? os.homedir(), '.square', 'host-ledger') : path.dirname(env.SQUARE_REGISTRY)));
|
|
66
|
+
}
|
|
67
|
+
function invalid(detail) {
|
|
68
|
+
return new Error(`Invalid legacy host ledger: ${detail}`);
|
|
69
|
+
}
|
|
70
|
+
function finite(value) {
|
|
71
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
72
|
+
}
|
|
73
|
+
function decodeEvidence(value) {
|
|
74
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
75
|
+
throw invalid('evidence record is not an object.');
|
|
76
|
+
const row = value;
|
|
77
|
+
if (row.v !== 1 || typeof row.location !== 'string' || typeof row.participant !== 'string' || typeof row.session !== 'string'
|
|
78
|
+
|| typeof row.activity !== 'string' || !['wake', 'presentation', 'lifecycle'].includes(row.kind)
|
|
79
|
+
|| typeof row.outcome !== 'string')
|
|
80
|
+
throw invalid('evidence record fields are malformed.');
|
|
81
|
+
if (row.at !== undefined && !finite(row.at))
|
|
82
|
+
throw invalid('evidence time is malformed.');
|
|
83
|
+
if (row.expiresAt !== undefined && !finite(row.expiresAt))
|
|
84
|
+
throw invalid('evidence expiry is malformed.');
|
|
85
|
+
if (row.attemptN !== undefined && (!Number.isSafeInteger(row.attemptN) || row.attemptN < 0))
|
|
86
|
+
throw invalid('evidence attempt is malformed.');
|
|
87
|
+
if (row.claimToken !== undefined && (typeof row.claimToken !== 'string' || row.claimToken.length === 0))
|
|
88
|
+
throw invalid('evidence claim token is malformed.');
|
|
89
|
+
return row;
|
|
90
|
+
}
|
|
91
|
+
function record(row) {
|
|
92
|
+
if (!Number.isSafeInteger(row.seq) || row.seq < 1 || typeof row.row_json !== 'string')
|
|
93
|
+
throw invalid('row framing is malformed.');
|
|
94
|
+
let value;
|
|
95
|
+
try {
|
|
96
|
+
value = JSON.parse(row.row_json);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw invalid('record JSON is malformed.');
|
|
100
|
+
}
|
|
101
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
102
|
+
throw invalid('record is not an object.');
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
function projections(row, expected) {
|
|
106
|
+
if (Object.entries(expected).some(([key, value]) => row[key] !== value))
|
|
107
|
+
throw invalid('record projections are malformed.');
|
|
108
|
+
}
|
|
109
|
+
/** One frozen snapshot, latest owners only; no age, expiry, or ownership history inference. */
|
|
110
|
+
export async function readLegacyHostData(location, env = process.env, signal) {
|
|
111
|
+
if (signal?.aborted)
|
|
112
|
+
throw signal.reason;
|
|
113
|
+
const root = ledgerRoot(env);
|
|
114
|
+
const file = path.join(root, LEDGER_FILENAME);
|
|
115
|
+
try {
|
|
116
|
+
await fs.promises.stat(file);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (error.code !== 'ENOENT')
|
|
120
|
+
throw error;
|
|
121
|
+
for (const legacy of LEGACY_FILES) {
|
|
122
|
+
try {
|
|
123
|
+
await fs.promises.stat(path.join(root, legacy));
|
|
124
|
+
throw invalid('legacy line sources require separate host-ledger migration.');
|
|
125
|
+
}
|
|
126
|
+
catch (nested) {
|
|
127
|
+
if (nested.code !== 'ENOENT')
|
|
128
|
+
throw nested;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { owners: [], evidence: [] };
|
|
132
|
+
}
|
|
133
|
+
const uri = pathToFileURL(file);
|
|
134
|
+
uri.searchParams.set('mode', 'ro');
|
|
135
|
+
const database = new DatabaseSync(uri.href);
|
|
136
|
+
try {
|
|
137
|
+
const canonical = await canonicalPath(location);
|
|
138
|
+
return await inSqliteTransaction(database, false, () => validateLedger(database), () => {
|
|
139
|
+
const owners = database.prepare(`SELECT * FROM (
|
|
140
|
+
SELECT *,row_number() OVER (PARTITION BY participant_key ORDER BY effective_at DESC,seq DESC) AS ordinal
|
|
141
|
+
FROM host_presence WHERE location_key=?) WHERE ordinal=1`).all(recordKey(canonical)).map(row => {
|
|
142
|
+
const value = record(row);
|
|
143
|
+
const at = value.at ?? value.updatedAt;
|
|
144
|
+
if (value.v !== 1 || value.location !== canonical || typeof value.participant !== 'string'
|
|
145
|
+
|| !finite(at))
|
|
146
|
+
throw invalid('owner fields are malformed.');
|
|
147
|
+
const body = { channel: value.channel, session: value.session, ...(value.agent === undefined ? {} : { agent: value.agent }) };
|
|
148
|
+
validateBody(body);
|
|
149
|
+
projections(row, { location_key: recordKey(canonical), participant_key: recordKey(nameKey(value.participant)),
|
|
150
|
+
channel_key: recordKey(body.channel), session_key: recordKey(body.session), effective_at: at });
|
|
151
|
+
return { participant: value.participant, body };
|
|
152
|
+
});
|
|
153
|
+
const evidence = database.prepare("SELECT * FROM host_evidence WHERE location_key=? AND kind IN ('wake','presentation') ORDER BY seq").all(recordKey(canonical)).map(row => {
|
|
154
|
+
const value = decodeEvidence(record(row));
|
|
155
|
+
if (value.location !== canonical || !finite(value.at))
|
|
156
|
+
throw invalid('evidence fields are malformed.');
|
|
157
|
+
projections(row, { location_key: recordKey(canonical), participant_key: recordKey(nameKey(value.participant)), session_key: recordKey(value.session),
|
|
158
|
+
activity_key: recordKey(value.activity), kind: value.kind, outcome: value.outcome,
|
|
159
|
+
claim_token_key: value.claimToken === undefined ? null : recordKey(value.claimToken), effective_at: value.at });
|
|
160
|
+
return value;
|
|
161
|
+
});
|
|
162
|
+
return { owners, evidence };
|
|
163
|
+
}, signal);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
database.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -14,9 +14,9 @@ export interface MigrationOutcome {
|
|
|
14
14
|
readonly counts?: MigrationCounts;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Explicit
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* Explicit conversion of the supported legacy formats. Row-backed versions 2 and 3 are
|
|
18
|
+
* preflighted read-only, then receive the format-4 ownership/evidence rows in one transaction.
|
|
19
|
+
* Legacy delivery evidence is copied from HostLedger only when its owner/session mapping is
|
|
20
|
+
* unique; no source record is retired. Version 1 is not a supported source for this format transition.
|
|
21
21
|
*/
|
|
22
|
-
export declare function migrateSquareFile(location: string, signal?: AbortSignal): Promise<MigrationOutcome>;
|
|
22
|
+
export declare function migrateSquareFile(location: string, signal?: AbortSignal, env?: NodeJS.ProcessEnv): Promise<MigrationOutcome>;
|