@arcfold/dsh 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +8 -2
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/cordis.patch.yml +138 -0
- package/package.json +70 -4
- package/patches/deepseek-0.2.2-rc.1-transport.json +65 -0
- package/patches/deepseek-0.2.2-rc.1-transport.patch +61 -0
- package/presets/arcfold.patch.yml +110 -0
- package/runtime/README.md +19 -0
- package/runtime/bootstrap.json +15 -0
- package/runtime/desktop-python.tar.gz +0 -0
- package/runtime/host/package.json +11 -0
- package/runtime/host/pnpm-workspace.yaml +9 -0
- package/runtime/initial-policy.json +94 -0
- package/runtime/profile/pnpm-workspace.yaml +7 -0
- package/scripts/exact-package-patch.mjs +106 -0
- package/scripts/patch-deepseek-transport.mjs +14 -0
- package/src/agent.mjs +56 -0
- package/src/browse-scope.mjs +14 -0
- package/src/budget.mjs +369 -0
- package/src/business.mjs +334 -0
- package/src/context-material.mjs +119 -0
- package/src/deepseek-budget-plugin.mjs +58 -0
- package/src/deepseek-provider.mjs +57 -0
- package/src/deepseek-receipt.mjs +97 -0
- package/src/deepseek-transport.mjs +97 -0
- package/src/desktop/adapter.mjs +16 -0
- package/src/desktop/bootstrap.mjs +84 -0
- package/src/desktop/configuration.mjs +117 -0
- package/src/desktop/provider.mjs +46 -0
- package/src/desktop/python-runtime.mjs +105 -0
- package/src/desktop/setup-service.mjs +81 -0
- package/src/desktop/vendor/LICENSE.deepseek +21 -0
- package/src/desktop/vendor/NOTICE.md +5 -0
- package/src/desktop/vendor/deepseek-0.2.2-rc.1.mjs +2919 -0
- package/src/evidence-ownership.mjs +51 -0
- package/src/evidence.mjs +35 -0
- package/src/goal-context.mjs +52 -0
- package/src/goal-execution-tool.mjs +74 -0
- package/src/goal-execution.mjs +333 -0
- package/src/goal-tool.mjs +56 -0
- package/src/goal-work-control.mjs +63 -0
- package/src/goal-work.mjs +257 -0
- package/src/goals.mjs +578 -0
- package/src/importer.mjs +298 -0
- package/src/index.mjs +53 -0
- package/src/learning-contracts.mjs +220 -0
- package/src/learning-defaults.mjs +98 -0
- package/src/learning-goals.mjs +165 -0
- package/src/learning-plugin.mjs +28 -0
- package/src/learning-runner.mjs +275 -0
- package/src/learning.mjs +534 -0
- package/src/legacy-export.mjs +332 -0
- package/src/legacy-import-source.mjs +356 -0
- package/src/metered-provider-host.mjs +101 -0
- package/src/metered-transport.mjs +435 -0
- package/src/method-context.mjs +57 -0
- package/src/method-lifecycle.mjs +34 -0
- package/src/method-tool.mjs +61 -0
- package/src/methods.mjs +425 -0
- package/src/model-selection.mjs +41 -0
- package/src/native-context-call.mjs +88 -0
- package/src/native-continuation.mjs +217 -0
- package/src/native-request-authority.mjs +90 -0
- package/src/openai-models.mjs +4 -0
- package/src/openai-receipt.mjs +98 -0
- package/src/openai-transport.mjs +167 -0
- package/src/openai-usage.mjs +194 -0
- package/src/opportunities.mjs +295 -0
- package/src/preparation-artifacts.mjs +213 -0
- package/src/preparation-plugin.mjs +290 -0
- package/src/runtime-command.mjs +264 -0
- package/src/runtime-config.mjs +417 -0
- package/src/runtime-guard.mjs +284 -0
- package/src/runtime-host.mjs +212 -0
- package/src/runtime-init.mjs +278 -0
- package/src/runtime-installation.mjs +518 -0
- package/src/runtime-lifecycle.mjs +227 -0
- package/src/runtime-model-settings.mjs +111 -0
- package/src/runtime-readiness.mjs +285 -0
- package/src/runtime-workspace.mjs +18 -0
- package/src/session-bridge.mjs +365 -0
- package/src/store.mjs +394 -0
- package/src/tree/LICENSE +21 -0
- package/src/tree/attribution.mjs +120 -0
- package/src/tree/clusters.mjs +61 -0
- package/src/tree/consolidation.mjs +103 -0
- package/src/tree/context.mjs +211 -0
- package/src/tree/contracts.mjs +142 -0
- package/src/tree/experience.mjs +140 -0
- package/src/tree/experiment-budget.mjs +84 -0
- package/src/tree/hooks.mjs +254 -0
- package/src/tree/host-context.mjs +107 -0
- package/src/tree/host-process.mjs +288 -0
- package/src/tree/host.mjs +37 -0
- package/src/tree/improvement.mjs +106 -0
- package/src/tree/items.mjs +294 -0
- package/src/tree/jobs.mjs +184 -0
- package/src/tree/learning.mjs +202 -0
- package/src/tree/metrics.mjs +203 -0
- package/src/tree/model-owner.mjs +254 -0
- package/src/tree/observations.mjs +73 -0
- package/src/tree/prompts.mjs +500 -0
- package/src/tree/reports.mjs +67 -0
- package/src/tree/repository.mjs +236 -0
- package/src/tree/runtime.mjs +745 -0
- package/src/tree/script-writer.mjs +149 -0
- package/src/tree/scripts.mjs +208 -0
- package/src/tree/signals.mjs +118 -0
- package/src/tree/snapshots.mjs +379 -0
- package/src/tree/token-counter.mjs +75 -0
- package/src/tree/token-counter.py +37 -0
- package/src/tree/tokenizer-resources/LICENSE +21 -0
- package/src/tree/tokenizer-resources/README.md +31 -0
- package/src/tree/tokenizer-resources/deepseek_recipe-0.2.0-cp310-abi3-macosx_11_0_arm64.whl +0 -0
- package/src/tree/tokenizer-resources/manifest.json +61 -0
- package/src/tree/tokenizer-resources/native.pyi +1042 -0
- package/src/tree/tokenizer-resources/tokenizer-NOTICE.md +26 -0
- package/src/tree/tokenizer-resources/tokenizer-v4-NOTICE.md +27 -0
- package/src/tree/tokenizer-resources/tokenizer-v4.json +267359 -0
- package/src/tree/tokenizer-resources/tokenizer.json +267359 -0
- package/src/tree/tools.mjs +99 -0
- package/src/tree/tree.mjs +202 -0
- package/src/tree/ui.mjs +285 -0
- package/src/tree/verification.mjs +143 -0
- package/src/understandings.mjs +309 -0
- package/src/web-budget-recovery.mjs +181 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { randomUUID, createHash } from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { dirname, join, sep } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
7
|
+
import { BudgetLedger, webBudgetIdentity } from './budget.mjs';
|
|
8
|
+
import { OpenAIUsageLedger } from './openai-usage.mjs';
|
|
9
|
+
import { canonicalJson } from './store.mjs';
|
|
10
|
+
import { readInstallation } from './runtime-installation.mjs';
|
|
11
|
+
import { acquireRuntimeLease } from './runtime-lifecycle.mjs';
|
|
12
|
+
import { ownEvidenceDirectory, assertEvidenceOwnership } from './evidence-ownership.mjs';
|
|
13
|
+
import { openOwnedWebBudget } from './web-budget-recovery.mjs';
|
|
14
|
+
import { canonicalRuntimePath, createInitialRuntimeConfig } from './runtime-config.mjs';
|
|
15
|
+
|
|
16
|
+
const SCHEMA = 'arcfold-initialization-v1';
|
|
17
|
+
const sha = value => createHash('sha256').update(value).digest('hex');
|
|
18
|
+
const within = (parent, child) => child === parent || child.startsWith(parent + sep);
|
|
19
|
+
const disjoint = (a, b) => !within(a, b) && !within(b, a);
|
|
20
|
+
const present = path => { try { fs.lstatSync(path); return true; } catch (e) { if (e.code === 'ENOENT') return false; throw e; } };
|
|
21
|
+
function syncDirectory(path) { const fd = fs.openSync(path, 'r'); try { fs.fsyncSync(fd); } finally { fs.closeSync(fd); } }
|
|
22
|
+
function privateFile(path, links = [1]) {
|
|
23
|
+
const stat = fs.lstatSync(path);
|
|
24
|
+
assert.ok(stat.isFile() && stat.uid === process.getuid() && !(stat.mode & 0o077) && links.includes(stat.nlink),
|
|
25
|
+
'Initialization files must be private regular files with their explained link count');
|
|
26
|
+
return stat;
|
|
27
|
+
}
|
|
28
|
+
function signature(path, links = [1]) {
|
|
29
|
+
const st = privateFile(path, links), bytes = fs.readFileSync(path);
|
|
30
|
+
return { dev: st.dev, ino: st.ino, bytes: bytes.length, sha256: sha(bytes) };
|
|
31
|
+
}
|
|
32
|
+
function json(path) { privateFile(path, [1, 2]); return JSON.parse(fs.readFileSync(path, 'utf8')); }
|
|
33
|
+
function writeNew(path, value) {
|
|
34
|
+
const body = typeof value === 'string' ? value : JSON.stringify(value, null, 2) + '\n';
|
|
35
|
+
const temporary = join(dirname(path), '.init-write-' + randomUUID());
|
|
36
|
+
const fd = fs.openSync(temporary, 'wx', 0o600);
|
|
37
|
+
try { fs.writeFileSync(fd, body); fs.fsyncSync(fd); } finally { fs.closeSync(fd); }
|
|
38
|
+
// No rename-overwrite: every fixed receipt is published exactly once.
|
|
39
|
+
fs.linkSync(temporary, path); syncDirectory(dirname(path));
|
|
40
|
+
fs.unlinkSync(temporary); syncDirectory(dirname(path));
|
|
41
|
+
}
|
|
42
|
+
function authority(initId, provider, authorizedAt) {
|
|
43
|
+
return { authorizationRef: 'arcfold-init:' + initId + ':' + provider, authorizedAt,
|
|
44
|
+
authorizationEvidence: 'Explicit public init --web-unlimited confirmation for this independent installation; ' +
|
|
45
|
+
(provider === 'openai' ? 'OpenAI token-only accounting.' : 'DeepSeek web accounting without a local spending cap.') };
|
|
46
|
+
}
|
|
47
|
+
function expectedAuthority(provider, authorization) {
|
|
48
|
+
return provider === 'deepseek-official' ? webBudgetIdentity(authorization) : {
|
|
49
|
+
id: 'openai-web-' + sha(authorization.authorizationRef),
|
|
50
|
+
specification: { scope: 'web-openai', provider: 'openai', accounting: 'tokens_only', ...authorization },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function ledgerSnapshot(path, provider, authorization) {
|
|
54
|
+
const db = new DatabaseSync(path, { readOnly: true });
|
|
55
|
+
try {
|
|
56
|
+
assert.deepEqual(db.prepare('PRAGMA integrity_check').all().map(r => r.integrity_check), ['ok']);
|
|
57
|
+
const records = db.prepare('SELECT * FROM records ORDER BY kind,id').all().map(r => ({ ...r }));
|
|
58
|
+
const meta = db.prepare('SELECT * FROM store_meta ORDER BY key').all().map(r => ({ ...r }));
|
|
59
|
+
const expected = expectedAuthority(provider, authorization), kind = provider === 'openai' ? 'openai_authorizations' : 'budget_authorizations';
|
|
60
|
+
assert.equal(records.length, 1, 'A fresh ledger may contain only its initial authorization');
|
|
61
|
+
assert.equal(records[0].kind, kind); assert.equal(records[0].id, expected.id);
|
|
62
|
+
assert.equal(records[0].revision, 1);
|
|
63
|
+
const body = JSON.parse(records[0].body);
|
|
64
|
+
assert.deepEqual(body.specification, expected.specification); assert.equal(body.createdSequence, 1); assert.equal(body.updatedSequence, 1);
|
|
65
|
+
assert.equal(meta.find(r => r.key === 'schema_version')?.value, '2');
|
|
66
|
+
assert.equal(meta.find(r => r.key === 'mutation_sequence')?.value, '1');
|
|
67
|
+
if (provider !== 'openai') {
|
|
68
|
+
assert.equal(db.prepare('PRAGMA application_id').get().application_id, 0x41574631);
|
|
69
|
+
assert.equal(db.prepare('SELECT count(*) AS n FROM budget_requests').get().n, 0);
|
|
70
|
+
assert.deepEqual(JSON.parse(meta.find(r => r.key === 'web_budget_mode').value).authorization, expected);
|
|
71
|
+
} else assert.equal(db.prepare('PRAGMA application_id').get().application_id, 0);
|
|
72
|
+
return { schema: db.prepare('SELECT type,name,tbl_name,sql FROM sqlite_schema ORDER BY type,name').all().map(r => ({ ...r })),
|
|
73
|
+
records, meta, authorizationId: expected.id };
|
|
74
|
+
} finally { db.close(); }
|
|
75
|
+
}
|
|
76
|
+
function noSidecars(path) {
|
|
77
|
+
for (const suffix of ['-wal', '-shm', '-journal'])
|
|
78
|
+
assert.ok(!present(path + suffix), 'A newly published ledger cannot depend on unpublished sidecars');
|
|
79
|
+
}
|
|
80
|
+
function createStagedLedger(path, provider, authorization) {
|
|
81
|
+
assert.ok(!present(path), 'A new attempt never reuses a failed stage');
|
|
82
|
+
const ledger = provider === 'openai'
|
|
83
|
+
? new OpenAIUsageLedger(path, { create: true, webAuthorization: authorization })
|
|
84
|
+
: new BudgetLedger(path, { mode: 'web-only', scope: 'web-unlimited', create: true, webAuthorization: authorization });
|
|
85
|
+
try {
|
|
86
|
+
// Only a brand-new, privately owned database is changed to a self-contained
|
|
87
|
+
// rollback file. Running-ledger recovery keeps its separate existing policy.
|
|
88
|
+
if (provider === 'openai') {
|
|
89
|
+
assert.equal(ledger.db.prepare('PRAGMA wal_checkpoint(TRUNCATE)').get().busy, 0);
|
|
90
|
+
assert.equal(ledger.db.prepare('PRAGMA journal_mode=DELETE').get().journal_mode, 'delete');
|
|
91
|
+
}
|
|
92
|
+
} finally { ledger.close(); }
|
|
93
|
+
noSidecars(path); const snapshot = ledgerSnapshot(path, provider, authorization);
|
|
94
|
+
const copy = path + '.standalone-check';
|
|
95
|
+
fs.copyFileSync(path, copy, fs.constants.COPYFILE_EXCL); fs.chmodSync(copy, 0o600);
|
|
96
|
+
assert.deepEqual(ledgerSnapshot(copy, provider, authorization), snapshot, 'Main file alone must contain the whole initialized ledger');
|
|
97
|
+
const fd = fs.openSync(path, 'r'); try { fs.fsyncSync(fd); } finally { fs.closeSync(fd); }
|
|
98
|
+
syncDirectory(dirname(path)); return snapshot;
|
|
99
|
+
}
|
|
100
|
+
function loadIntent(path, { plan, name, target, attempts }) {
|
|
101
|
+
const intent = json(path);
|
|
102
|
+
assert.equal(intent.schema, 'arcfold-init-publication-v1'); assert.equal(intent.initId, plan.initId);
|
|
103
|
+
assert.equal(intent.name, name); assert.equal(intent.target, target);
|
|
104
|
+
assert.match(intent.attempt, /^[0-9a-f-]{36}$/);
|
|
105
|
+
assert.equal(intent.staged, join(attempts, intent.attempt, name));
|
|
106
|
+
assert.equal(canonicalRuntimePath(intent.staged), intent.staged, 'Staging path cannot be an alias');
|
|
107
|
+
return intent;
|
|
108
|
+
}
|
|
109
|
+
/** Fixed three-file publication, not a general transaction/recovery engine. */
|
|
110
|
+
function publish(intent, intentPath, owner, artifactDirectory, validate) {
|
|
111
|
+
assertEvidenceOwnership(owner, artifactDirectory);
|
|
112
|
+
for (const path of [intent.staged, intent.target])
|
|
113
|
+
assert.equal(canonicalRuntimePath(path), path, 'Publication paths cannot be aliases');
|
|
114
|
+
const staged = present(intent.staged), target = present(intent.target);
|
|
115
|
+
if (target) {
|
|
116
|
+
assert.deepEqual(signature(intent.target, staged ? [2] : [1]), intent.file, 'Published file does not match its exact prior intent');
|
|
117
|
+
if (staged) assert.deepEqual(signature(intent.staged, [2]), intent.file, 'Unexplained staging link');
|
|
118
|
+
} else {
|
|
119
|
+
assert.ok(staged, 'The unpublished stage is missing');
|
|
120
|
+
assert.deepEqual(signature(intent.staged), intent.file, 'The staged file changed');
|
|
121
|
+
}
|
|
122
|
+
validate(target ? intent.target : intent.staged);
|
|
123
|
+
if (!target) { fs.linkSync(intent.staged, intent.target); syncDirectory(dirname(intent.target)); }
|
|
124
|
+
if (present(intent.staged)) {
|
|
125
|
+
assert.deepEqual(signature(intent.staged, [2]), intent.file);
|
|
126
|
+
assert.deepEqual(signature(intent.target, [2]), intent.file);
|
|
127
|
+
fs.unlinkSync(intent.staged); syncDirectory(dirname(intent.staged));
|
|
128
|
+
}
|
|
129
|
+
assert.deepEqual(signature(intent.target), intent.file);
|
|
130
|
+
const completed = intentPath + '.completed';
|
|
131
|
+
if (present(completed)) assert.deepEqual(json(completed), { initId: intent.initId, intentHash: sha(canonicalJson(intent)) });
|
|
132
|
+
else writeNew(completed, { initId: intent.initId, intentHash: sha(canonicalJson(intent)) });
|
|
133
|
+
}
|
|
134
|
+
function configIntent(path, plan, input) {
|
|
135
|
+
const intent = json(path);
|
|
136
|
+
assert.equal(intent.schema, 'arcfold-init-publication-v1');
|
|
137
|
+
assert.equal(intent.initId, plan.initId); assert.equal(intent.target, input.configPath);
|
|
138
|
+
assert.equal(intent.name, 'config'); assert.match(intent.attempt, /^[0-9a-f-]{36}$/);
|
|
139
|
+
assert.equal(intent.staged, join(dirname(input.configPath), '.arcfold-init-' + plan.initId + '-' + intent.attempt));
|
|
140
|
+
return intent;
|
|
141
|
+
}
|
|
142
|
+
function emptyFirstUse(dataRoot, runtimeDirectory, artifactDirectory, receipts) {
|
|
143
|
+
for (const name of fs.readdirSync(dataRoot))
|
|
144
|
+
assert.ok(['runtime', 'requests'].includes(name), 'An existing data directory cannot be claimed by first init');
|
|
145
|
+
for (const name of fs.readdirSync(runtimeDirectory))
|
|
146
|
+
assert.ok(name === 'owner.lock' || name === 'initialization', 'Existing runtime records cannot be claimed by first init');
|
|
147
|
+
for (const name of fs.readdirSync(artifactDirectory))
|
|
148
|
+
assert.equal(name, 'owner.lock', 'Existing request evidence or ledger cannot be claimed by first init');
|
|
149
|
+
for (const name of fs.readdirSync(receipts))
|
|
150
|
+
assert.match(name, /^\.init-write-[0-9a-f-]{36}$/, 'Unexplained initialization evidence');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Only called after full installation verification, from that actual installed core. */
|
|
154
|
+
export async function initializeRuntimeDeployment(options) {
|
|
155
|
+
assert.ok(options && typeof options === 'object' && !Array.isArray(options));
|
|
156
|
+
assert.ok(Object.keys(options).every(k => ['installationFile','configPath','dataRoot','workspace','port',
|
|
157
|
+
'webUnlimited','main','learn','network','credentialRefs'].includes(k)), 'Unsupported init options');
|
|
158
|
+
assert.equal(options.webUnlimited, true, 'Explicit --web-unlimited confirmation is required');
|
|
159
|
+
const installation = readInstallation(options.installationFile);
|
|
160
|
+
assert.deepEqual(Object.keys(installation.providers ?? {}).sort(), ['deepseek-official', 'openai'], 'First use requires both actual provider proofs');
|
|
161
|
+
assert.ok(installation.modelSelection, 'First use requires the actual native model-selection proof');
|
|
162
|
+
assert.equal(fileURLToPath(import.meta.url), join(installation.coreRoot, 'src/runtime-init.mjs'), 'Initialization must run in the verified installed core');
|
|
163
|
+
const policyPath = join(installation.coreRoot, 'runtime/initial-policy.json'), policy = JSON.parse(fs.readFileSync(policyPath, 'utf8'));
|
|
164
|
+
const input = { installationFile: installation.installationFile, installationHash: sha(fs.readFileSync(installation.installationFile)),
|
|
165
|
+
policyHash: sha(fs.readFileSync(policyPath)), configPath: canonicalRuntimePath(options.configPath),
|
|
166
|
+
dataRoot: canonicalRuntimePath(options.dataRoot), workspace: canonicalRuntimePath(options.workspace),
|
|
167
|
+
port: options.port ?? 4381, main: options.main ?? policy.initialMain, learn: options.learn ?? options.main ?? policy.initialMain,
|
|
168
|
+
network: options.network ?? { mode: 'direct' }, credentialRefs: options.credentialRefs ??
|
|
169
|
+
{ 'deepseek-official': 'ARCFOLD_DEEPSEEK_API_KEY', openai: 'ARCFOLD_OPENAI_API_KEY' } };
|
|
170
|
+
assert.ok(fs.lstatSync(input.workspace).isDirectory(), 'The workspace must already exist');
|
|
171
|
+
assert.ok(disjoint(input.dataRoot, installation.installationDir) && disjoint(input.workspace, installation.installationDir) &&
|
|
172
|
+
disjoint(input.dataRoot, input.workspace), 'Keep user data, workspace and installed code separate');
|
|
173
|
+
const runtimeDirectory = join(input.dataRoot, 'runtime'), artifactDirectory = join(input.dataRoot, 'requests');
|
|
174
|
+
for (const path of [runtimeDirectory, artifactDirectory, join(runtimeDirectory, 'initialization')])
|
|
175
|
+
assert.equal(canonicalRuntimePath(path), path, 'Initialization subdirectories cannot be aliases');
|
|
176
|
+
assert.ok(!within(input.workspace, input.configPath) && !within(installation.installationDir, input.configPath) &&
|
|
177
|
+
!within(runtimeDirectory, input.configPath) && !within(artifactDirectory, input.configPath), 'Config cannot replace runtime, workspace or installed files');
|
|
178
|
+
// Validate all choices before creating a data directory or taking a write lock.
|
|
179
|
+
createInitialRuntimeConfig({ ...input, policy, webAuthorizations: {
|
|
180
|
+
'deepseek-official': authority('validation', 'deepseek-official', '2026-11-07T00:00:00.000Z'),
|
|
181
|
+
openai: authority('validation', 'openai', '2026-11-07T00:00:00.000Z'),
|
|
182
|
+
} });
|
|
183
|
+
const runtimeOwner = await acquireRuntimeLease(runtimeDirectory); let owner;
|
|
184
|
+
try {
|
|
185
|
+
owner = await ownEvidenceDirectory(artifactDirectory);
|
|
186
|
+
const receipts = join(runtimeDirectory, 'initialization'); fs.mkdirSync(receipts, { recursive: true, mode: 0o700 });
|
|
187
|
+
syncDirectory(input.dataRoot); syncDirectory(runtimeDirectory); syncDirectory(artifactDirectory);
|
|
188
|
+
const planPath = join(receipts, 'identity.json');
|
|
189
|
+
let plan;
|
|
190
|
+
if (present(planPath)) {
|
|
191
|
+
plan = json(planPath); assert.equal(plan.schema, SCHEMA);
|
|
192
|
+
assert.deepEqual(plan.input, input, 'Retry requires the exact original initialization input');
|
|
193
|
+
assert.match(plan.initId, /^[0-9a-f-]{36}$/);
|
|
194
|
+
for (const provider of ['deepseek-official', 'openai'])
|
|
195
|
+
assert.deepEqual(plan.authorizations[provider], authority(plan.initId, provider, plan.authorizedAt));
|
|
196
|
+
} else {
|
|
197
|
+
assert.ok(!present(input.configPath), 'First init cannot replace an existing configuration');
|
|
198
|
+
emptyFirstUse(input.dataRoot, runtimeDirectory, artifactDirectory, receipts);
|
|
199
|
+
const initId = randomUUID(), authorizedAt = new Date().toISOString();
|
|
200
|
+
plan = { schema: SCHEMA, initId, input, authorizedAt, authorizations: Object.fromEntries(
|
|
201
|
+
['deepseek-official', 'openai'].map(provider => [provider, authority(initId, provider, authorizedAt)])) };
|
|
202
|
+
writeNew(planPath, plan);
|
|
203
|
+
}
|
|
204
|
+
const config = createInitialRuntimeConfig({ ...input, policy, webAuthorizations: plan.authorizations });
|
|
205
|
+
const configBody = JSON.stringify(config, null, 2) + '\n', completionPath = join(receipts, 'completed.json');
|
|
206
|
+
const attempts = join(artifactDirectory, 'initialization', plan.initId);
|
|
207
|
+
assert.equal(canonicalRuntimePath(attempts), attempts, 'Staging ancestry must stay inside the owned requests directory');
|
|
208
|
+
const result = created => ({ configPath: input.configPath, initId: plan.initId, created,
|
|
209
|
+
initialization: 'completed', runtimeChecked: false, mode: 'configuration-only',
|
|
210
|
+
ledgerPaths: Object.fromEntries(Object.entries(config.transport.routes).map(([p,r]) => [p,r.ledgerPath])) });
|
|
211
|
+
if (present(input.configPath)) {
|
|
212
|
+
// Config publication is the completion boundary. The ledger may already
|
|
213
|
+
// have legitimate requests, so verify ownership, not its initial contents.
|
|
214
|
+
for (const [provider, route] of Object.entries(config.transport.routes)) {
|
|
215
|
+
const name = provider === 'openai' ? 'openai-web.sqlite' : 'deepseek-web.sqlite';
|
|
216
|
+
const intentPath = join(receipts, name + '.intent.json');
|
|
217
|
+
const intent = loadIntent(intentPath, { plan, name, target: route.ledgerPath, attempts });
|
|
218
|
+
assert.equal(intent.authorizationId, expectedAuthority(provider, plan.authorizations[provider]).id);
|
|
219
|
+
assert.deepEqual(json(intentPath + '.completed'), { initId: plan.initId, intentHash: sha(canonicalJson(intent)) });
|
|
220
|
+
assert.ok(!present(intent.staged), 'Ledger publication was not completed before config');
|
|
221
|
+
const current = privateFile(route.ledgerPath);
|
|
222
|
+
assert.deepEqual({ dev: current.dev, ino: current.ino }, { dev: intent.file.dev, ino: intent.file.ino },
|
|
223
|
+
'A completed initialization cannot claim a replacement ledger');
|
|
224
|
+
}
|
|
225
|
+
const path = join(receipts, 'config.intent.json'), intent = configIntent(path, plan, input);
|
|
226
|
+
publish(intent, path, owner, artifactDirectory, file => assert.equal(fs.readFileSync(file, 'utf8'), configBody));
|
|
227
|
+
const completed = { initId: plan.initId, configHash: sha(configBody) };
|
|
228
|
+
if (present(completionPath)) assert.deepEqual(json(completionPath), completed);
|
|
229
|
+
else writeNew(completionPath, completed);
|
|
230
|
+
// No SQLite constructor/recovery or authorization write after publication.
|
|
231
|
+
return result(false);
|
|
232
|
+
}
|
|
233
|
+
assert.ok(!present(completionPath), 'The completed configuration is missing');
|
|
234
|
+
fs.mkdirSync(attempts, { recursive: true, mode: 0o700 });
|
|
235
|
+
syncDirectory(artifactDirectory); syncDirectory(dirname(attempts)); syncDirectory(attempts);
|
|
236
|
+
const attempt = randomUUID(), stage = join(attempts, attempt); fs.mkdirSync(stage, { mode: 0o700 }); syncDirectory(attempts);
|
|
237
|
+
for (const provider of ['deepseek-official', 'openai']) {
|
|
238
|
+
const name = provider === 'openai' ? 'openai-web.sqlite' : 'deepseek-web.sqlite';
|
|
239
|
+
const target = config.transport.routes[provider].ledgerPath, intentPath = join(receipts, name + '.intent.json');
|
|
240
|
+
let intent;
|
|
241
|
+
if (present(intentPath)) intent = loadIntent(intentPath, { plan, name, target, attempts });
|
|
242
|
+
else {
|
|
243
|
+
assert.ok(!present(target), 'Canonical ledger has no initialization publication intent');
|
|
244
|
+
for (const suffix of ['-wal','-shm','-journal']) assert.ok(!present(target + suffix), 'Unexplained canonical ledger sidecar');
|
|
245
|
+
const staged = join(stage, name), snapshot = createStagedLedger(staged, provider, plan.authorizations[provider]);
|
|
246
|
+
intent = { schema: 'arcfold-init-publication-v1', initId: plan.initId, attempt, name, target, staged,
|
|
247
|
+
file: signature(staged), snapshotHash: sha(canonicalJson(snapshot)), authorizationId: snapshot.authorizationId };
|
|
248
|
+
writeNew(intentPath, intent);
|
|
249
|
+
}
|
|
250
|
+
publish(intent, intentPath, owner, artifactDirectory, path => {
|
|
251
|
+
noSidecars(path);
|
|
252
|
+
const snapshot = ledgerSnapshot(path, provider, plan.authorizations[provider]);
|
|
253
|
+
assert.equal(snapshot.authorizationId, intent.authorizationId); assert.equal(sha(canonicalJson(snapshot)), intent.snapshotHash);
|
|
254
|
+
});
|
|
255
|
+
if (provider === 'deepseek-official') {
|
|
256
|
+
const { ledger } = openOwnedWebBudget({ artifactDirectory, ledgerPath: target, webAuthorization: plan.authorizations[provider], owner });
|
|
257
|
+
ledger.close();
|
|
258
|
+
}
|
|
259
|
+
assert.deepEqual(signature(target), intent.file, 'Validation must not rewrite the initialized ledger');
|
|
260
|
+
}
|
|
261
|
+
fs.mkdirSync(dirname(input.configPath), { recursive: true, mode: 0o700 });
|
|
262
|
+
// Config staging is on its destination filesystem, even when dataRoot is elsewhere.
|
|
263
|
+
const intentPath = join(receipts, 'config.intent.json'); let intent;
|
|
264
|
+
if (present(intentPath)) {
|
|
265
|
+
intent = configIntent(intentPath, plan, input);
|
|
266
|
+
} else {
|
|
267
|
+
assert.ok(!present(input.configPath), 'Existing config has no publication intent');
|
|
268
|
+
const staged = join(dirname(input.configPath), '.arcfold-init-' + plan.initId + '-' + attempt);
|
|
269
|
+
writeNew(staged, configBody);
|
|
270
|
+
intent = { schema: 'arcfold-init-publication-v1', initId: plan.initId, attempt, name: 'config',
|
|
271
|
+
target: input.configPath, staged, file: signature(staged) };
|
|
272
|
+
writeNew(intentPath, intent);
|
|
273
|
+
}
|
|
274
|
+
publish(intent, intentPath, owner, artifactDirectory, path => assert.equal(fs.readFileSync(path, 'utf8'), configBody));
|
|
275
|
+
writeNew(completionPath, { initId: plan.initId, configHash: sha(configBody) });
|
|
276
|
+
return result(true);
|
|
277
|
+
} finally { try { await owner?.close(); } finally { await runtimeOwner.close(); } }
|
|
278
|
+
}
|