-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpangolin.config.mjs
More file actions
101 lines (89 loc) · 4.13 KB
/
Copy pathpangolin.config.mjs
File metadata and controls
101 lines (89 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// pangolin.config.mjs — operator config for the handoff-dag example.
//
// Exports:
// default / client — wired PangolinClient (namespace 'handoff-dag')
// orch — OrchContext: { transport, storage, anchor, verifySignature, runService }
//
// IMPORT-SAFE: no throw at load when the Claude credential (ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN) is absent.
// The live-run guard (exit 1 on missing key) lives in src/index.ts, not here.
import { mkdtemp } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { PangolinClient, NoopCredentialProvider, StdoutResultSink } from '@quarry-systems/pangolin-client';
import { claudeAuthSecrets } from '@quarry-systems/pangolin-core';
import { LocalStorageProvider } from '@quarry-systems/pangolin-storage-local';
import { LocalDockerProvider } from '@quarry-systems/pangolin-providers-local-docker';
import { LocalSecretStore } from '@quarry-systems/pangolin-secret-store';
import {
PangolinOrchestrator,
SqliteRunStateStore,
ManualTrigger,
DispatchExecutor,
AuditLog,
LocalAnchor,
createLocalSigner,
verifyEd25519,
MailboxSubmissionTransport,
LocalDirMailbox,
serve,
} from '@quarry-systems/pangolin-orchestrator';
// ---------------------------------------------------------------------------
// Path setup — rootDir/secretDir/mailboxDir use stable per-host paths so
// containers can bind-mount them across CLI invocations (intentional; matches
// offload-fanout template). dbPath is PID-qualified to avoid SQLITE_BUSY
// when multiple CLI invocations run concurrently (each gets its own DB file).
// ---------------------------------------------------------------------------
const rootDir = join(tmpdir(), 'pangolin-handoff-storage');
const secretDir = join(tmpdir(), 'pangolin-handoff-secrets');
const mailboxDir = join(tmpdir(), 'pangolin-handoff-mailbox');
const dbPath = join(tmpdir(), `pangolin-handoff-${process.pid}.db`);
const workerImage = 'ghcr.io/quarrysystems/pangolin-worker:latest';
// ---------------------------------------------------------------------------
// PangolinClient — lazy: no Docker/network until dispatch fires.
// ---------------------------------------------------------------------------
export const client = new PangolinClient({
namespace: 'handoff-dag',
compute: { 'local-docker': new LocalDockerProvider({ allowUnpinnedImage: true }) },
storage: new LocalStorageProvider({ rootDir }),
secretStores: { local: new LocalSecretStore({ dir: secretDir }) },
credentials: { none: new NoopCredentialProvider() },
targets: { local: { compute: 'local-docker', credentials: 'none', secretStore: 'local' } },
resultSink: new StdoutResultSink(),
});
export default client;
// ---------------------------------------------------------------------------
// Audit + orchestrator setup (IMPORT-SAFE: constructors are lazy / in-memory).
// ---------------------------------------------------------------------------
const store = new SqliteRunStateStore(dbPath);
// Defensive: release the SQLite handle on process exit so the OS-level file lock
// is always freed even if the caller forgets to call store.close() explicitly.
process.on('exit', () => { try { store.close(); } catch {} });
const signer = createLocalSigner();
const anchor = new LocalAnchor(store);
const auditLog = new AuditLog({ store, signer, anchor });
const orchestrator = new PangolinOrchestrator({
store,
executors: {
dispatch: new DispatchExecutor({
client,
target: 'local',
workerImage,
secrets: claudeAuthSecrets().secrets,
}),
},
triggers: { manual: new ManualTrigger() },
queues: { default: { concurrency: 2 } },
auditLog,
});
/** Verify an ed25519 signature produced by our local signer. */
const verifySignature = (root, sig) => verifyEd25519(root, sig, signer.publicKey);
const transport = new MailboxSubmissionTransport(new LocalDirMailbox(mailboxDir));
/** Start the serve loop; returns a Promise that resolves when signal fires. */
const runService = (signal) => serve({ orchestrator, transport, signal });
export const orch = {
transport,
storage: client.storage,
anchor,
verifySignature,
runService,
};