@jinn-network/client 0.1.2-canary.d6e72dfd → 0.1.2
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/CHANGELOG.md +2 -0
- package/README.md +3 -0
- package/dist/adapters/adapter.d.ts +7 -0
- package/dist/adapters/mech/adapter.d.ts +4 -0
- package/dist/adapters/mech/adapter.js +140 -19
- package/dist/adapters/mech/adapter.js.map +1 -1
- package/dist/adapters/mech/contracts.d.ts +17 -1
- package/dist/adapters/mech/contracts.js +55 -1
- package/dist/adapters/mech/contracts.js.map +1 -1
- package/dist/adapters/mech/ipfs.d.ts +30 -5
- package/dist/adapters/mech/ipfs.js +162 -17
- package/dist/adapters/mech/ipfs.js.map +1 -1
- package/dist/adapters/mech/safe.js +8 -6
- package/dist/adapters/mech/safe.js.map +1 -1
- package/dist/adapters/mech/types.d.ts +2 -0
- package/dist/adapters/mech/types.js.map +1 -1
- package/dist/api/balance-build.js +3 -3
- package/dist/api/balance-build.js.map +1 -1
- package/dist/api/fleet-build.js +35 -40
- package/dist/api/fleet-build.js.map +1 -1
- package/dist/api/gather-status.d.ts +5 -0
- package/dist/api/gather-status.js +158 -7
- package/dist/api/gather-status.js.map +1 -1
- package/dist/api/history-build.d.ts +5 -1
- package/dist/api/history-build.js +51 -26
- package/dist/api/history-build.js.map +1 -1
- package/dist/api/portfolio-v0-build.d.ts +3 -1
- package/dist/api/portfolio-v0-build.js +12 -10
- package/dist/api/portfolio-v0-build.js.map +1 -1
- package/dist/api/rewards-build.js +29 -13
- package/dist/api/rewards-build.js.map +1 -1
- package/dist/api/status-build.d.ts +32 -6
- package/dist/api/status-build.js +2 -1
- package/dist/api/status-build.js.map +1 -1
- package/dist/api/status-rollup-build.d.ts +2 -0
- package/dist/api/status-rollup-build.js +30 -3
- package/dist/api/status-rollup-build.js.map +1 -1
- package/dist/build-meta.json +1 -1
- package/dist/cli/commands/auth.js +27 -5
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/balance.js +8 -1
- package/dist/cli/commands/balance.js.map +1 -1
- package/dist/cli/commands/bootstrap.js +22 -0
- package/dist/cli/commands/bootstrap.js.map +1 -1
- package/dist/cli/commands/doctor.js +33 -3
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/fleet.js +10 -1
- package/dist/cli/commands/fleet.js.map +1 -1
- package/dist/cli/commands/history.js +25 -6
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/logs.js +35 -11
- package/dist/cli/commands/logs.js.map +1 -1
- package/dist/cli/commands/quickstart.js +39 -1
- package/dist/cli/commands/quickstart.js.map +1 -1
- package/dist/cli/commands/run.js +38 -0
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/status.js +11 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/submit-intent.js +62 -99
- package/dist/cli/commands/submit-intent.js.map +1 -1
- package/dist/cli/intent-registry-access.d.ts +3 -5
- package/dist/cli/intent-registry-access.js +12 -34
- package/dist/cli/intent-registry-access.js.map +1 -1
- package/dist/cli/introspection-context.js +11 -8
- package/dist/cli/introspection-context.js.map +1 -1
- package/dist/config.d.ts +28 -1
- package/dist/config.js +29 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon/balance-topup-loop.js +32 -4
- package/dist/daemon/balance-topup-loop.js.map +1 -1
- package/dist/daemon/creator.d.ts +6 -9
- package/dist/daemon/creator.js +45 -51
- package/dist/daemon/creator.js.map +1 -1
- package/dist/daemon/daemon.d.ts +9 -20
- package/dist/daemon/daemon.js +34 -27
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/delivery-watcher.d.ts +3 -1
- package/dist/daemon/delivery-watcher.js +19 -1
- package/dist/daemon/delivery-watcher.js.map +1 -1
- package/dist/daemon/reward-claim-loop.js +38 -1
- package/dist/daemon/reward-claim-loop.js.map +1 -1
- package/dist/dashboard/index.html +71 -496
- package/dist/discovery/registry.d.ts +54 -0
- package/dist/discovery/registry.js +73 -0
- package/dist/discovery/registry.js.map +1 -1
- package/dist/earning/bootstrap.js +8 -38
- package/dist/earning/bootstrap.js.map +1 -1
- package/dist/earning/stolas-claim.d.ts +6 -0
- package/dist/earning/stolas-claim.js +7 -0
- package/dist/earning/stolas-claim.js.map +1 -1
- package/dist/intents/kinds/constants.d.ts +5 -0
- package/dist/intents/kinds/constants.js +6 -0
- package/dist/intents/kinds/constants.js.map +1 -0
- package/dist/intents/kinds/index.d.ts +28 -0
- package/dist/intents/kinds/index.js +50 -0
- package/dist/intents/kinds/index.js.map +1 -0
- package/dist/intents/kinds/portfolio-v0.d.ts +2 -0
- package/dist/intents/kinds/portfolio-v0.js +13 -0
- package/dist/intents/kinds/portfolio-v0.js.map +1 -0
- package/dist/intents/kinds/prediction-apy-v0.d.ts +3 -0
- package/dist/intents/kinds/prediction-apy-v0.js +21 -0
- package/dist/intents/kinds/prediction-apy-v0.js.map +1 -0
- package/dist/intents/kinds/prediction-v0.d.ts +3 -0
- package/dist/intents/kinds/prediction-v0.js +32 -0
- package/dist/intents/kinds/prediction-v0.js.map +1 -0
- package/dist/intents/kinds/spec-kind.d.ts +38 -0
- package/dist/intents/kinds/spec-kind.js +6 -0
- package/dist/intents/kinds/spec-kind.js.map +1 -0
- package/dist/intents/posting-service.d.ts +26 -0
- package/dist/intents/posting-service.js +218 -0
- package/dist/intents/posting-service.js.map +1 -0
- package/dist/intents/prediction-apy-v0-auto.js +1 -1
- package/dist/intents/prediction-apy-v0-auto.js.map +1 -1
- package/dist/intents/prediction-v0-template.d.ts +8 -3
- package/dist/intents/prediction-v0-template.js +21 -1
- package/dist/intents/prediction-v0-template.js.map +1 -1
- package/dist/intents/sources.d.ts +39 -0
- package/dist/intents/sources.js +42 -0
- package/dist/intents/sources.js.map +1 -0
- package/dist/main.js +89 -65
- package/dist/main.js.map +1 -1
- package/dist/mcp/server.js +8 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/observability/emit-event.d.ts +12 -0
- package/dist/observability/emit-event.js +27 -0
- package/dist/observability/emit-event.js.map +1 -0
- package/dist/preflight/api-port.d.ts +13 -0
- package/dist/preflight/api-port.js +32 -0
- package/dist/preflight/api-port.js.map +1 -0
- package/dist/preflight/rpc-network.d.ts +44 -0
- package/dist/preflight/rpc-network.js +121 -0
- package/dist/preflight/rpc-network.js.map +1 -0
- package/dist/restorer/engine/engine.d.ts +10 -0
- package/dist/restorer/engine/engine.js +60 -44
- package/dist/restorer/engine/engine.js.map +1 -1
- package/dist/restorer/impls/claude-mcp-hyperliquid/index.d.ts +7 -4
- package/dist/restorer/impls/claude-mcp-hyperliquid/index.js +12 -1
- package/dist/restorer/impls/claude-mcp-hyperliquid/index.js.map +1 -1
- package/dist/restorer/impls/claude-mcp-prediction/index.d.ts +2 -1
- package/dist/restorer/impls/claude-mcp-prediction/index.js +9 -0
- package/dist/restorer/impls/claude-mcp-prediction/index.js.map +1 -1
- package/dist/restorer/impls/claude-mcp-prediction/types.d.ts +2 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/index.d.ts +34 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/index.js +233 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/index.js.map +1 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/mcp-tools.d.ts +18 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/mcp-tools.js +136 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/mcp-tools.js.map +1 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/prompt.d.ts +7 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/prompt.js +46 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/prompt.js.map +1 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/session-orchestrator.d.ts +27 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/session-orchestrator.js +128 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/session-orchestrator.js.map +1 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/types.d.ts +64 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/types.js +6 -0
- package/dist/restorer/impls/claude-mcp-prediction-apy/types.js.map +1 -0
- package/dist/restorer/impls/evaluation-context.d.ts +16 -0
- package/dist/restorer/impls/evaluation-context.js +18 -0
- package/dist/restorer/impls/evaluation-context.js.map +1 -0
- package/dist/restorer/impls/index.d.ts +46 -0
- package/dist/restorer/impls/index.js +88 -0
- package/dist/restorer/impls/index.js.map +1 -0
- package/dist/restorer/impls/legacy-claude/index.d.ts +8 -1
- package/dist/restorer/impls/legacy-claude/index.js +79 -10
- package/dist/restorer/impls/legacy-claude/index.js.map +1 -1
- package/dist/restorer/impls/portfolio-v0-evaluator/index.d.ts +2 -1
- package/dist/restorer/impls/portfolio-v0-evaluator/index.js +9 -0
- package/dist/restorer/impls/portfolio-v0-evaluator/index.js.map +1 -1
- package/dist/restorer/impls/portfolio-v0-evaluator/types.d.ts +2 -0
- package/dist/restorer/impls/prediction-apy-v0-baseline/index.d.ts +1 -0
- package/dist/restorer/impls/prediction-apy-v0-baseline/index.js +12 -3
- package/dist/restorer/impls/prediction-apy-v0-baseline/index.js.map +1 -1
- package/dist/restorer/impls/prediction-apy-v0-evaluator/canonical-metrics.d.ts +4 -0
- package/dist/restorer/impls/prediction-apy-v0-evaluator/canonical-metrics.js +4 -0
- package/dist/restorer/impls/prediction-apy-v0-evaluator/canonical-metrics.js.map +1 -1
- package/dist/restorer/impls/prediction-apy-v0-evaluator/index.d.ts +6 -3
- package/dist/restorer/impls/prediction-apy-v0-evaluator/index.js +55 -33
- package/dist/restorer/impls/prediction-apy-v0-evaluator/index.js.map +1 -1
- package/dist/restorer/impls/prediction-apy-v0-evaluator/parse-submission.d.ts +7 -0
- package/dist/restorer/impls/prediction-apy-v0-evaluator/parse-submission.js +29 -0
- package/dist/restorer/impls/prediction-apy-v0-evaluator/parse-submission.js.map +1 -0
- package/dist/restorer/impls/prediction-apy-v0-evaluator/types.d.ts +1 -1
- package/dist/restorer/impls/prediction-v0-baseline/index.d.ts +2 -0
- package/dist/restorer/impls/prediction-v0-baseline/index.js +6 -0
- package/dist/restorer/impls/prediction-v0-baseline/index.js.map +1 -1
- package/dist/restorer/impls/prediction-v0-evaluator/checks/integrity.d.ts +6 -0
- package/dist/restorer/impls/prediction-v0-evaluator/checks/integrity.js +19 -1
- package/dist/restorer/impls/prediction-v0-evaluator/checks/integrity.js.map +1 -1
- package/dist/restorer/impls/prediction-v0-evaluator/index.d.ts +6 -3
- package/dist/restorer/impls/prediction-v0-evaluator/index.js +30 -4
- package/dist/restorer/impls/prediction-v0-evaluator/index.js.map +1 -1
- package/dist/restorer/impls/prediction-v0-evaluator/types.d.ts +1 -1
- package/dist/restorer/types.d.ts +17 -0
- package/dist/restorer/types.js +22 -1
- package/dist/restorer/types.js.map +1 -1
- package/dist/rpc-error-context.d.ts +10 -0
- package/dist/rpc-error-context.js +26 -0
- package/dist/rpc-error-context.js.map +1 -0
- package/dist/store/store.d.ts +98 -0
- package/dist/store/store.js +331 -4
- package/dist/store/store.js.map +1 -1
- package/dist/trajectory/schema.d.ts +510 -0
- package/dist/trajectory/schema.js +74 -0
- package/dist/trajectory/schema.js.map +1 -0
- package/dist/types/prediction-apy.d.ts +21 -10
- package/dist/types/prediction-apy.js +17 -5
- package/dist/types/prediction-apy.js.map +1 -1
- package/dist/types/prediction.d.ts +11 -10
- package/dist/types/prediction.js +3 -2
- package/dist/types/prediction.js.map +1 -1
- package/dist/venues/aave-v3/client.d.ts +6 -2
- package/dist/venues/aave-v3/client.js +14 -5
- package/dist/venues/aave-v3/client.js.map +1 -1
- package/package.json +4 -3
- package/dist/daemon/restorer.d.ts +0 -19
- package/dist/daemon/restorer.js +0 -82
- package/dist/daemon/restorer.js.map +0 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claude-mcp-prediction-apy — RestorerImpl for prediction.apy.v0 that spawns a
|
|
3
|
+
* single Claude Code session with read_aave_reserve + submit_apy_prediction.
|
|
4
|
+
*
|
|
5
|
+
* Opt-in via config.restorers.byKind['prediction.apy.v0']; baseline remains default.
|
|
6
|
+
* Isolation gate: test/restorer/impls/claude-mcp-prediction-apy/isolation.test.ts
|
|
7
|
+
*/
|
|
8
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync, chmodSync } from 'node:fs';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { createPublicClient, http } from 'viem';
|
|
12
|
+
import { base, baseSepolia, mainnet } from 'viem/chains';
|
|
13
|
+
import { REQUIRES_LIVE_DAEMON_READINESS } from '../../types.js';
|
|
14
|
+
import { PredictionApyV0IntentSchema } from '../../../types/prediction-apy.js';
|
|
15
|
+
import { buildSessionPrompt } from './prompt.js';
|
|
16
|
+
import { spawnSession } from './session-orchestrator.js';
|
|
17
|
+
function chainForVenue(venue) {
|
|
18
|
+
if (venue === 'aave-v3-base-sepolia')
|
|
19
|
+
return { chain: baseSepolia, chainId: 84532 };
|
|
20
|
+
if (venue === 'aave-v3-mainnet')
|
|
21
|
+
return { chain: mainnet, chainId: 1 };
|
|
22
|
+
return { chain: base, chainId: 8453 };
|
|
23
|
+
}
|
|
24
|
+
export class ClaudeMcpPredictionApyImpl {
|
|
25
|
+
config;
|
|
26
|
+
name = 'claude-mcp-prediction-apy';
|
|
27
|
+
version = '1.0.0';
|
|
28
|
+
constructor(config = {}) {
|
|
29
|
+
this.config = config;
|
|
30
|
+
}
|
|
31
|
+
supports(ctx) {
|
|
32
|
+
return ctx.kind === 'prediction.apy.v0' && ctx.type !== 'evaluation';
|
|
33
|
+
}
|
|
34
|
+
async isReady() {
|
|
35
|
+
if (this.config.stub)
|
|
36
|
+
return { ...REQUIRES_LIVE_DAEMON_READINESS };
|
|
37
|
+
return { ready: true };
|
|
38
|
+
}
|
|
39
|
+
enableMetadata() {
|
|
40
|
+
return {
|
|
41
|
+
description: 'prediction.apy.v0 — Claude + MCP reads Aave reserve APY and submits predicted bps.',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async onEnable(_args) {
|
|
45
|
+
return { status: 'ready' };
|
|
46
|
+
}
|
|
47
|
+
async canAttempt(intent) {
|
|
48
|
+
const parsed = PredictionApyV0IntentSchema.safeParse(intent);
|
|
49
|
+
if (!parsed.success)
|
|
50
|
+
return { ok: false, reason: `Invalid prediction.apy.v0 intent: ${parsed.error.message}` };
|
|
51
|
+
if (Date.now() > parsed.data.window.endTs)
|
|
52
|
+
return { ok: false, reason: 'window already closed' };
|
|
53
|
+
return { ok: true };
|
|
54
|
+
}
|
|
55
|
+
async run(ctx) {
|
|
56
|
+
if (this.config.stub) {
|
|
57
|
+
throw new Error('claude-mcp-prediction-apy: stub registry cannot run (requires live daemon)');
|
|
58
|
+
}
|
|
59
|
+
const { intent, workingDir, log } = ctx;
|
|
60
|
+
const parsed = PredictionApyV0IntentSchema.parse(intent);
|
|
61
|
+
const testDeps = this.config._testDeps;
|
|
62
|
+
const submissionState = {
|
|
63
|
+
predictedBps: null,
|
|
64
|
+
rationale: null,
|
|
65
|
+
submittedAt: null,
|
|
66
|
+
};
|
|
67
|
+
const signalSubmit = (predictedBps, rationale) => {
|
|
68
|
+
submissionState.predictedBps = predictedBps;
|
|
69
|
+
submissionState.rationale = rationale;
|
|
70
|
+
submissionState.submittedAt = Date.now();
|
|
71
|
+
};
|
|
72
|
+
const sessionId = `apy-pred-${Date.now()}`;
|
|
73
|
+
const prompt = buildSessionPrompt(parsed, sessionId);
|
|
74
|
+
if (testDeps?.runSession) {
|
|
75
|
+
const session = await testDeps.runSession({
|
|
76
|
+
sessionId,
|
|
77
|
+
prompt,
|
|
78
|
+
mcpConfigPath: '<test>',
|
|
79
|
+
workingDir,
|
|
80
|
+
implStateDir: ctx.implStateDir,
|
|
81
|
+
timeoutMs: this.config.sessionMaxMs ?? 180_000,
|
|
82
|
+
signalSubmit,
|
|
83
|
+
});
|
|
84
|
+
return this._finalize(parsed, sessionId, session.transcriptPath, submissionState, session.startedAt, session.endedAt);
|
|
85
|
+
}
|
|
86
|
+
const { venue, pool, reserve, reserveSymbol } = parsed.spec.oracle;
|
|
87
|
+
const { chain, chainId } = chainForVenue(venue);
|
|
88
|
+
const rpcUrl = this.config.archiveRpcUrl ?? this.config.rpcUrl ?? this._defaultRpcUrl(venue);
|
|
89
|
+
const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
|
|
90
|
+
const actual = await publicClient.getChainId();
|
|
91
|
+
if (actual !== chainId) {
|
|
92
|
+
throw new Error(`oracle venue mismatch: ${venue} expects chain ${chainId}, got ${actual}`);
|
|
93
|
+
}
|
|
94
|
+
const mcpDir = join(workingDir, 'mcp');
|
|
95
|
+
mkdirSync(mcpDir, { recursive: true });
|
|
96
|
+
const submissionLogPath = join(mcpDir, 'submissions.jsonl');
|
|
97
|
+
writeFileSync(submissionLogPath, '', { encoding: 'utf-8', mode: 0o600 });
|
|
98
|
+
chmodSync(submissionLogPath, 0o600);
|
|
99
|
+
const wrapperPath = join(mcpDir, 'apy-prediction-server.mjs');
|
|
100
|
+
const wrapperConfigPath = join(mcpDir, 'apy-prediction-server-config.json');
|
|
101
|
+
const wrapperConfig = {
|
|
102
|
+
venue,
|
|
103
|
+
pool,
|
|
104
|
+
reserve,
|
|
105
|
+
reserveSymbol,
|
|
106
|
+
rpcUrl,
|
|
107
|
+
submissionLogPath,
|
|
108
|
+
};
|
|
109
|
+
writeFileSync(wrapperConfigPath, JSON.stringify(wrapperConfig), { encoding: 'utf-8', mode: 0o600 });
|
|
110
|
+
chmodSync(wrapperConfigPath, 0o600);
|
|
111
|
+
_writeApyPredictionMcpServerScript(wrapperPath);
|
|
112
|
+
const mcpConfigPath = join(mcpDir, 'mcp-config.json');
|
|
113
|
+
writeFileSync(mcpConfigPath, JSON.stringify({
|
|
114
|
+
mcpServers: {
|
|
115
|
+
'jinn-apy-prediction': {
|
|
116
|
+
command: process.execPath,
|
|
117
|
+
args: [wrapperPath, wrapperConfigPath],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
}, null, 2));
|
|
121
|
+
const isSubmitted = () => {
|
|
122
|
+
try {
|
|
123
|
+
const contents = readFileSync(submissionLogPath, 'utf-8');
|
|
124
|
+
const lastLine = contents.trim().split('\n').pop() ?? '';
|
|
125
|
+
if (!lastLine)
|
|
126
|
+
return false;
|
|
127
|
+
const record = JSON.parse(lastLine);
|
|
128
|
+
if (record && typeof record.predictedBps === 'string' && typeof record.rationale === 'string') {
|
|
129
|
+
signalSubmit(record.predictedBps, record.rationale);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
};
|
|
138
|
+
log({ level: 'info', msg: 'claude-mcp-prediction-apy: spawning session', data: { sessionId } });
|
|
139
|
+
const session = await spawnSession(sessionId, prompt, {
|
|
140
|
+
claudePath: this.config.claudePath ?? 'claude',
|
|
141
|
+
...(this.config.claudeModel ? { claudeModel: this.config.claudeModel } : {}),
|
|
142
|
+
mcpConfigPath,
|
|
143
|
+
workingDir,
|
|
144
|
+
abort: ctx.abort,
|
|
145
|
+
log,
|
|
146
|
+
isSubmitted,
|
|
147
|
+
...(this.config.sessionMaxMs !== undefined ? { sessionMaxMs: this.config.sessionMaxMs } : {}),
|
|
148
|
+
});
|
|
149
|
+
if (!submissionState.predictedBps)
|
|
150
|
+
isSubmitted();
|
|
151
|
+
return this._finalize(parsed, sessionId, session.transcriptPath, submissionState, session.startedAt, session.endedAt);
|
|
152
|
+
}
|
|
153
|
+
_finalize(intent, sessionId, transcriptPath, submission, startedAt, endedAt) {
|
|
154
|
+
if (!submission.predictedBps || !submission.rationale) {
|
|
155
|
+
throw new Error(`claude-mcp-prediction-apy: session ${sessionId} ended without a valid submit_apy_prediction call`);
|
|
156
|
+
}
|
|
157
|
+
const submittedAt = submission.submittedAt ?? Date.now();
|
|
158
|
+
const modelId = `claude-mcp-prediction-apy.${this.config.claudeModel ?? 'default'}.v1`;
|
|
159
|
+
const predictionPath = join(dirname(transcriptPath), '..', '..', 'prediction-apy.json');
|
|
160
|
+
writeFileSync(predictionPath, JSON.stringify({
|
|
161
|
+
predictedBps: submission.predictedBps,
|
|
162
|
+
submittedAt,
|
|
163
|
+
modelId,
|
|
164
|
+
rationale: submission.rationale,
|
|
165
|
+
}, null, 2), { encoding: 'utf-8' });
|
|
166
|
+
const { venue, pool, reserve, reserveSymbol } = intent.spec.oracle;
|
|
167
|
+
return {
|
|
168
|
+
venueRef: { name: 'aave-v3' },
|
|
169
|
+
gating: {
|
|
170
|
+
predictedBps: submission.predictedBps,
|
|
171
|
+
submittedAt: String(submittedAt),
|
|
172
|
+
modelId,
|
|
173
|
+
},
|
|
174
|
+
informational: {
|
|
175
|
+
rationale: submission.rationale,
|
|
176
|
+
sessionId,
|
|
177
|
+
transcriptPath,
|
|
178
|
+
venue,
|
|
179
|
+
pool,
|
|
180
|
+
reserve,
|
|
181
|
+
reserveSymbol,
|
|
182
|
+
sessionDurationMs: endedAt - startedAt,
|
|
183
|
+
},
|
|
184
|
+
artifacts: [
|
|
185
|
+
{ path: 'prediction-apy.json', role: 'prediction_submission' },
|
|
186
|
+
{
|
|
187
|
+
path: transcriptPath,
|
|
188
|
+
role: 'session_transcript',
|
|
189
|
+
metadata: { sessionId, startedAt, endedAt },
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
_defaultRpcUrl(venue) {
|
|
195
|
+
if (venue === 'aave-v3-base-sepolia')
|
|
196
|
+
return 'https://sepolia.base.org';
|
|
197
|
+
if (venue === 'aave-v3-base')
|
|
198
|
+
return 'https://mainnet.base.org';
|
|
199
|
+
return 'https://eth.llamarpc.com';
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export function _writeApyPredictionMcpServerScript(outPath) {
|
|
203
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
204
|
+
let mcpToolsPath = join(dirname(__filename), 'mcp-tools.js');
|
|
205
|
+
if (!existsSync(mcpToolsPath) && __filename.includes(`${'/'}src${'/'}`)) {
|
|
206
|
+
mcpToolsPath = __filename
|
|
207
|
+
.replace(`${'/'}src${'/'}`, `${'/'}dist${'/'}`)
|
|
208
|
+
.replace(/index\.(ts|js)$/, 'mcp-tools.js');
|
|
209
|
+
}
|
|
210
|
+
if (!existsSync(mcpToolsPath)) {
|
|
211
|
+
throw new Error(`E_DAEMON_MUST_RUN_FROM_DIST: ${mcpToolsPath} does not exist. ` +
|
|
212
|
+
`The claude-mcp-prediction-apy wrapper subprocess loads this compiled artifact. ` +
|
|
213
|
+
`Run \`yarn build\` before starting the daemon or isolation test.`);
|
|
214
|
+
}
|
|
215
|
+
const script = `#!/usr/bin/env node
|
|
216
|
+
// Auto-generated jinn-apy-prediction MCP wrapper — do not edit.
|
|
217
|
+
import { readFileSync } from 'node:fs';
|
|
218
|
+
import { startMcpServer } from ${JSON.stringify(mcpToolsPath)};
|
|
219
|
+
|
|
220
|
+
const configPath = process.argv[2];
|
|
221
|
+
if (!configPath) {
|
|
222
|
+
process.stderr.write('Usage: apy-prediction-server.mjs <config-file-path>\\n');
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
227
|
+
await startMcpServer(config);
|
|
228
|
+
`.trim();
|
|
229
|
+
writeFileSync(outPath, script, { encoding: 'utf-8', mode: 0o600 });
|
|
230
|
+
chmodSync(outPath, 0o600);
|
|
231
|
+
}
|
|
232
|
+
export default ClaudeMcpPredictionApyImpl;
|
|
233
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/restorer/impls/claude-mcp-prediction-apy/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool definitions for claude-mcp-prediction-apy.
|
|
3
|
+
*
|
|
4
|
+
* Two tools:
|
|
5
|
+
* - read_aave_reserve: read-only Aave v3 Pool.getReserveData; APY bps from liquidity rate.
|
|
6
|
+
* - submit_apy_prediction: terminal tool; records predicted bps + rationale.
|
|
7
|
+
*/
|
|
8
|
+
import type { ApyPredictionToolDefinition, ApyPredictionToolDeps, AaveV3Venue } from './types.js';
|
|
9
|
+
export declare function buildApyPredictionTools(deps: ApyPredictionToolDeps): ApyPredictionToolDefinition[];
|
|
10
|
+
export interface McpServerConfig {
|
|
11
|
+
venue: AaveV3Venue;
|
|
12
|
+
pool: `0x${string}`;
|
|
13
|
+
reserve: `0x${string}`;
|
|
14
|
+
reserveSymbol: string;
|
|
15
|
+
rpcUrl: string;
|
|
16
|
+
submissionLogPath: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function startMcpServer(config: McpServerConfig): Promise<void>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool definitions for claude-mcp-prediction-apy.
|
|
3
|
+
*
|
|
4
|
+
* Two tools:
|
|
5
|
+
* - read_aave_reserve: read-only Aave v3 Pool.getReserveData; APY bps from liquidity rate.
|
|
6
|
+
* - submit_apy_prediction: terminal tool; records predicted bps + rationale.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { createPublicClient, http } from 'viem';
|
|
10
|
+
import { base, baseSepolia, mainnet } from 'viem/chains';
|
|
11
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
|
+
import { AAVE_POOL_ABI, liquidityRateRayToApyBps, } from '../../../venues/aave-v3/client.js';
|
|
14
|
+
function ok(data) {
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function toolErr(code, message) {
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: 'text', text: JSON.stringify({ error: true, code, message }) }],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const ReadAaveReserveSchema = z.object({});
|
|
25
|
+
const SubmitApyPredictionSchema = z.object({
|
|
26
|
+
predictedBps: z
|
|
27
|
+
.number()
|
|
28
|
+
.int('predictedBps must be an integer')
|
|
29
|
+
.min(0, 'predictedBps must be ≥ 0')
|
|
30
|
+
.max(1_000_000, 'predictedBps must be ≤ 1_000_000'),
|
|
31
|
+
rationale: z
|
|
32
|
+
.string()
|
|
33
|
+
.min(1, 'rationale must not be empty')
|
|
34
|
+
.max(2000, 'rationale must be ≤ 2000 characters'),
|
|
35
|
+
});
|
|
36
|
+
export function buildApyPredictionTools(deps) {
|
|
37
|
+
const { pool, reserve, reserveSymbol, venue, publicClient, onSubmit } = deps;
|
|
38
|
+
const readAaveReserve = {
|
|
39
|
+
name: 'read_aave_reserve',
|
|
40
|
+
description: 'Read the current Aave v3 reserve supply APY (basis points) for the pool/reserve in this intent. Returns the converted APY from currentLiquidityRate plus block metadata.',
|
|
41
|
+
schema: ReadAaveReserveSchema,
|
|
42
|
+
handler: async () => {
|
|
43
|
+
try {
|
|
44
|
+
const reserveData = await publicClient.readContract({
|
|
45
|
+
address: pool,
|
|
46
|
+
abi: AAVE_POOL_ABI,
|
|
47
|
+
functionName: 'getReserveData',
|
|
48
|
+
args: [reserve],
|
|
49
|
+
});
|
|
50
|
+
const currentLiquidityRateRay = reserveData[2];
|
|
51
|
+
const lastUpdateTimestamp = reserveData[6];
|
|
52
|
+
const apyBps = liquidityRateRayToApyBps(currentLiquidityRateRay);
|
|
53
|
+
const block = await publicClient.getBlock({ blockTag: 'latest' });
|
|
54
|
+
const chainId = await publicClient.getChainId();
|
|
55
|
+
return ok({
|
|
56
|
+
apyBps,
|
|
57
|
+
liquidityRateRay: String(currentLiquidityRateRay),
|
|
58
|
+
lastUpdateTimestamp: Number(lastUpdateTimestamp),
|
|
59
|
+
pool,
|
|
60
|
+
reserve,
|
|
61
|
+
reserveSymbol,
|
|
62
|
+
venue,
|
|
63
|
+
chainId,
|
|
64
|
+
blockNumber: String(block.number),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return toolErr('AAVE_READ_FAILED', err instanceof Error ? err.message : String(err));
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const submitApyPrediction = {
|
|
73
|
+
name: 'submit_apy_prediction',
|
|
74
|
+
description: 'Submit your final APY prediction in basis points (integer). `predictedBps` is the supply APY you predict for the TWA window ending at resolveTs. `rationale` is a brief explanation. Calling this ends the session; do not call any other tool after it.',
|
|
75
|
+
schema: SubmitApyPredictionSchema,
|
|
76
|
+
handler: async (rawArgs) => {
|
|
77
|
+
const parsed = SubmitApyPredictionSchema.safeParse(rawArgs);
|
|
78
|
+
if (!parsed.success) {
|
|
79
|
+
return toolErr('INVALID_ARGS', parsed.error.issues.map((i) => i.message).join('; '));
|
|
80
|
+
}
|
|
81
|
+
const { predictedBps, rationale } = parsed.data;
|
|
82
|
+
const predictedBpsStr = String(predictedBps);
|
|
83
|
+
onSubmit({ predictedBps: predictedBpsStr, rationale });
|
|
84
|
+
return ok({
|
|
85
|
+
accepted: true,
|
|
86
|
+
predictedBps: predictedBpsStr,
|
|
87
|
+
note: 'Prediction recorded. The session will terminate shortly after this response reaches Claude.',
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
return [readAaveReserve, submitApyPrediction];
|
|
92
|
+
}
|
|
93
|
+
function chainForVenue(venue) {
|
|
94
|
+
if (venue === 'aave-v3-base-sepolia')
|
|
95
|
+
return { chain: baseSepolia, chainId: 84532 };
|
|
96
|
+
if (venue === 'aave-v3-mainnet')
|
|
97
|
+
return { chain: mainnet, chainId: 1 };
|
|
98
|
+
return { chain: base, chainId: 8453 };
|
|
99
|
+
}
|
|
100
|
+
export async function startMcpServer(config) {
|
|
101
|
+
const { chain } = chainForVenue(config.venue);
|
|
102
|
+
const publicClient = createPublicClient({
|
|
103
|
+
chain,
|
|
104
|
+
transport: http(config.rpcUrl),
|
|
105
|
+
});
|
|
106
|
+
const { appendFileSync } = await import('node:fs');
|
|
107
|
+
const onSubmit = (submission) => {
|
|
108
|
+
appendFileSync(config.submissionLogPath, JSON.stringify({
|
|
109
|
+
ts: Date.now(),
|
|
110
|
+
predictedBps: submission.predictedBps,
|
|
111
|
+
rationale: submission.rationale,
|
|
112
|
+
}) + '\n', { encoding: 'utf-8' });
|
|
113
|
+
};
|
|
114
|
+
const tools = buildApyPredictionTools({
|
|
115
|
+
pool: config.pool,
|
|
116
|
+
reserve: config.reserve,
|
|
117
|
+
reserveSymbol: config.reserveSymbol,
|
|
118
|
+
venue: config.venue,
|
|
119
|
+
publicClient,
|
|
120
|
+
onSubmit,
|
|
121
|
+
});
|
|
122
|
+
const server = new McpServer({ name: 'jinn-apy-prediction', version: '1.0.0' });
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
124
|
+
const registerTool = server.tool.bind(server);
|
|
125
|
+
for (const tool of tools) {
|
|
126
|
+
const shape = tool.schema.shape ?? {};
|
|
127
|
+
registerTool(tool.name, tool.description, shape, async (args) => tool.handler(args));
|
|
128
|
+
}
|
|
129
|
+
const transport = new StdioServerTransport();
|
|
130
|
+
await server.connect(transport);
|
|
131
|
+
await new Promise((resolve) => {
|
|
132
|
+
process.stdin.on('close', resolve);
|
|
133
|
+
process.stdin.on('end', resolve);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=mcp-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../../../src/restorer/impls/claude-mcp-prediction-apy/mcp-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt template for claude-mcp-prediction-apy sessions.
|
|
3
|
+
*
|
|
4
|
+
* Kept intentionally static (no branching) so tests can snapshot deterministically.
|
|
5
|
+
*/
|
|
6
|
+
import type { PredictionApyV0Intent } from '../../../types/prediction-apy.js';
|
|
7
|
+
export declare function buildSessionPrompt(intent: PredictionApyV0Intent, sessionId: string): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt template for claude-mcp-prediction-apy sessions.
|
|
3
|
+
*
|
|
4
|
+
* Kept intentionally static (no branching) so tests can snapshot deterministically.
|
|
5
|
+
*/
|
|
6
|
+
export function buildSessionPrompt(intent, sessionId) {
|
|
7
|
+
const { oracle, metric, question } = intent.spec;
|
|
8
|
+
const { window } = intent;
|
|
9
|
+
return [
|
|
10
|
+
`Session: ${sessionId}`,
|
|
11
|
+
'',
|
|
12
|
+
'You are evaluating a Jinn prediction.apy.v0 intent. Predict the time-weighted-average (TWA) supply APY for the reserve, expressed as an integer in basis points (bps), and submit it via submit_apy_prediction.',
|
|
13
|
+
'',
|
|
14
|
+
'Ground truth (for scoring) is computed at resolution as follows:',
|
|
15
|
+
' - Take sampleCount evenly spaced timestamps in [resolveTs - twaWindowSeconds, resolveTs].',
|
|
16
|
+
' - At each timestamp, read Aave Pool.getReserveData(reserve).currentLiquidityRate (ray).',
|
|
17
|
+
' - Convert each sample to supply APY and take the arithmetic mean; round to integer bps.',
|
|
18
|
+
'',
|
|
19
|
+
`Reserve: ${oracle.reserveSymbol} (${oracle.reserve})`,
|
|
20
|
+
`Pool: ${oracle.pool}`,
|
|
21
|
+
`Venue: ${oracle.venue}`,
|
|
22
|
+
`TWA window: ${metric.twaWindowSeconds}s with ${metric.sampleCount} samples`,
|
|
23
|
+
`Tolerance: ±${metric.toleranceBps} bps (for scoring)`,
|
|
24
|
+
'',
|
|
25
|
+
`Intent window: [${new Date(window.startTs).toISOString()}, ${new Date(window.endTs).toISOString()}]`,
|
|
26
|
+
`Resolve at: ${new Date(question.resolveTs).toISOString()}`,
|
|
27
|
+
'',
|
|
28
|
+
'You have exactly two tools:',
|
|
29
|
+
'',
|
|
30
|
+
' 1. read_aave_reserve — returns the current on-chain supply APY in bps from the reserve (spot, not the full TWA). Call this once.',
|
|
31
|
+
' 2. submit_apy_prediction — submit your final predicted bps (non-negative integer) with a brief rationale.',
|
|
32
|
+
' Calling this ends the session. Do not call any other tool afterward.',
|
|
33
|
+
'',
|
|
34
|
+
'Approach:',
|
|
35
|
+
' 1. Call read_aave_reserve to see the current supply APY in bps.',
|
|
36
|
+
' 2. Reason briefly about what TWA APY at resolveTs might be given the spot reading and time to resolution.',
|
|
37
|
+
' 3. Call submit_apy_prediction with your integer predictedBps and a concise rationale.',
|
|
38
|
+
'',
|
|
39
|
+
'Guidelines:',
|
|
40
|
+
' - predictedBps must be a whole number (basis points). Example: 350 means 3.50% APY.',
|
|
41
|
+
' - Do not call submit_apy_prediction before calling read_aave_reserve.',
|
|
42
|
+
' - The rationale should reference the apyBps you read.',
|
|
43
|
+
' - Keep the rationale under 2000 characters.',
|
|
44
|
+
].join('\n');
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../../src/restorer/impls/claude-mcp-prediction-apy/prompt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,UAAU,kBAAkB,CAAC,MAA6B,EAAE,SAAiB;IACjF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IACjD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAE1B,OAAO;QACL,YAAY,SAAS,EAAE;QACvB,EAAE;QACF,iNAAiN;QACjN,EAAE;QACF,kEAAkE;QAClE,6FAA6F;QAC7F,2FAA2F;QAC3F,2FAA2F;QAC3F,EAAE;QACF,mBAAmB,MAAM,CAAC,aAAa,KAAK,MAAM,CAAC,OAAO,GAAG;QAC7D,mBAAmB,MAAM,CAAC,IAAI,EAAE;QAChC,mBAAmB,MAAM,CAAC,KAAK,EAAE;QACjC,mBAAmB,MAAM,CAAC,gBAAgB,UAAU,MAAM,CAAC,WAAW,UAAU;QAChF,oBAAoB,MAAM,CAAC,YAAY,oBAAoB;QAC3D,EAAE;QACF,oBAAoB,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,GAAG;QACtG,mBAAmB,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;QAC/D,EAAE;QACF,6BAA6B;QAC7B,EAAE;QACF,oIAAoI;QACpI,6GAA6G;QAC7G,kGAAkG;QAClG,EAAE;QACF,WAAW;QACX,mEAAmE;QACnE,6GAA6G;QAC7G,yFAAyF;QACzF,EAAE;QACF,aAAa;QACb,uFAAuF;QACvF,yEAAyE;QACzE,yDAAyD;QACzD,+CAA+C;KAChD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session orchestrator for claude-mcp-prediction-apy.
|
|
3
|
+
*
|
|
4
|
+
* Single-session. Spawns Claude once with the APY prediction MCP + prompt,
|
|
5
|
+
* polls for submit_apy_prediction, then terminates after a short grace period.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from 'node:child_process';
|
|
8
|
+
import type { SessionResult } from './types.js';
|
|
9
|
+
export interface OrchestratorDeps {
|
|
10
|
+
claudePath: string;
|
|
11
|
+
claudeModel?: string;
|
|
12
|
+
mcpConfigPath: string;
|
|
13
|
+
workingDir: string;
|
|
14
|
+
abort: AbortSignal;
|
|
15
|
+
log: (event: {
|
|
16
|
+
level: 'info' | 'warn' | 'error';
|
|
17
|
+
msg: string;
|
|
18
|
+
data?: unknown;
|
|
19
|
+
}) => void;
|
|
20
|
+
/** Poll callback — returns true once submit_apy_prediction has been invoked. */
|
|
21
|
+
isSubmitted: () => boolean;
|
|
22
|
+
sessionMaxMs?: number;
|
|
23
|
+
pollIntervalMs?: number;
|
|
24
|
+
submissionGraceMs?: number;
|
|
25
|
+
_spawnFn?: typeof spawn;
|
|
26
|
+
}
|
|
27
|
+
export declare function spawnSession(sessionId: string, prompt: string, deps: OrchestratorDeps): Promise<SessionResult>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session orchestrator for claude-mcp-prediction-apy.
|
|
3
|
+
*
|
|
4
|
+
* Single-session. Spawns Claude once with the APY prediction MCP + prompt,
|
|
5
|
+
* polls for submit_apy_prediction, then terminates after a short grace period.
|
|
6
|
+
*/
|
|
7
|
+
import { appendFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
const DEFAULT_SESSION_MAX_MS = 180_000;
|
|
11
|
+
const DEFAULT_POLL_INTERVAL_MS = 500;
|
|
12
|
+
const DEFAULT_SUBMISSION_GRACE_MS = 2_000;
|
|
13
|
+
export async function spawnSession(sessionId, prompt, deps) {
|
|
14
|
+
const sessionMaxMs = deps.sessionMaxMs ?? DEFAULT_SESSION_MAX_MS;
|
|
15
|
+
const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
16
|
+
const submissionGraceMs = deps.submissionGraceMs ?? DEFAULT_SUBMISSION_GRACE_MS;
|
|
17
|
+
const sessionDir = join(deps.workingDir, 'sessions', sessionId);
|
|
18
|
+
mkdirSync(sessionDir, { recursive: true });
|
|
19
|
+
const transcriptPath = join(sessionDir, 'transcript.txt');
|
|
20
|
+
const startedAt = Date.now();
|
|
21
|
+
writeFileSync(transcriptPath, `=== Session ${sessionId} started at ${new Date(startedAt).toISOString()} ===\n\n`);
|
|
22
|
+
const args = [
|
|
23
|
+
'-p', prompt,
|
|
24
|
+
'--mcp-config', deps.mcpConfigPath,
|
|
25
|
+
'--strict-mcp-config',
|
|
26
|
+
'--allowedTools', 'mcp__jinn-apy-prediction__*',
|
|
27
|
+
];
|
|
28
|
+
if (deps.claudeModel)
|
|
29
|
+
args.push('--model', deps.claudeModel);
|
|
30
|
+
const agentEnv = {};
|
|
31
|
+
for (const key of [
|
|
32
|
+
'PATH', 'HOME', 'USER', 'SHELL', 'LANG', 'TERM', 'TMPDIR',
|
|
33
|
+
'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'XDG_CACHE_HOME',
|
|
34
|
+
'NODE_PATH', 'NODE_OPTIONS', 'NPM_CONFIG_PREFIX',
|
|
35
|
+
'CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_API_KEY',
|
|
36
|
+
]) {
|
|
37
|
+
if (process.env[key])
|
|
38
|
+
agentEnv[key] = process.env[key];
|
|
39
|
+
}
|
|
40
|
+
deps.log({ level: 'info', msg: `apy-prediction-session: spawning ${sessionId}`, data: { claudePath: deps.claudePath } });
|
|
41
|
+
const spawnFn = deps._spawnFn ?? spawn;
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const child = spawnFn(deps.claudePath, args, {
|
|
44
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
45
|
+
env: agentEnv,
|
|
46
|
+
});
|
|
47
|
+
let stdout = '';
|
|
48
|
+
let aborted = false;
|
|
49
|
+
let terminatedEarly = false;
|
|
50
|
+
child.stdout?.on('data', (d) => {
|
|
51
|
+
const chunk = d.toString();
|
|
52
|
+
stdout += chunk;
|
|
53
|
+
appendFileSync(transcriptPath, chunk);
|
|
54
|
+
});
|
|
55
|
+
child.stderr?.on('data', (d) => {
|
|
56
|
+
appendFileSync(transcriptPath, `[stderr] ${d.toString()}`);
|
|
57
|
+
});
|
|
58
|
+
const sessionTimeout = setTimeout(() => {
|
|
59
|
+
if (!child.killed) {
|
|
60
|
+
deps.log({ level: 'warn', msg: `apy-prediction-session: ${sessionId} reached sessionMaxMs; killing`, data: { sessionMaxMs } });
|
|
61
|
+
child.kill('SIGTERM');
|
|
62
|
+
}
|
|
63
|
+
}, sessionMaxMs);
|
|
64
|
+
let graceTimer = null;
|
|
65
|
+
const pollTimer = setInterval(() => {
|
|
66
|
+
if (graceTimer || child.killed)
|
|
67
|
+
return;
|
|
68
|
+
if (deps.isSubmitted()) {
|
|
69
|
+
deps.log({ level: 'info', msg: `apy-prediction-session: ${sessionId} submit_apy_prediction invoked; scheduling graceful termination` });
|
|
70
|
+
terminatedEarly = true;
|
|
71
|
+
graceTimer = setTimeout(() => {
|
|
72
|
+
if (!child.killed)
|
|
73
|
+
child.kill('SIGTERM');
|
|
74
|
+
}, submissionGraceMs);
|
|
75
|
+
}
|
|
76
|
+
}, pollIntervalMs);
|
|
77
|
+
const onAbort = () => {
|
|
78
|
+
if (aborted)
|
|
79
|
+
return;
|
|
80
|
+
aborted = true;
|
|
81
|
+
deps.log({ level: 'info', msg: `apy-prediction-session: ${sessionId} window abort; killing` });
|
|
82
|
+
child.kill('SIGTERM');
|
|
83
|
+
};
|
|
84
|
+
deps.abort.addEventListener('abort', onAbort);
|
|
85
|
+
const cleanup = () => {
|
|
86
|
+
clearTimeout(sessionTimeout);
|
|
87
|
+
if (graceTimer)
|
|
88
|
+
clearTimeout(graceTimer);
|
|
89
|
+
clearInterval(pollTimer);
|
|
90
|
+
deps.abort.removeEventListener('abort', onAbort);
|
|
91
|
+
};
|
|
92
|
+
child.on('exit', (code, signal) => {
|
|
93
|
+
cleanup();
|
|
94
|
+
const endedAt = Date.now();
|
|
95
|
+
appendFileSync(transcriptPath, `\n\n=== Session ended at ${new Date(endedAt).toISOString()} (code=${code} signal=${signal} submitted=${deps.isSubmitted()} terminatedEarly=${terminatedEarly} aborted=${aborted}) ===\n`);
|
|
96
|
+
deps.log({
|
|
97
|
+
level: 'info',
|
|
98
|
+
msg: `apy-prediction-session: ${sessionId} exited`,
|
|
99
|
+
data: { code, signal, durationMs: endedAt - startedAt, submitted: deps.isSubmitted(), aborted },
|
|
100
|
+
});
|
|
101
|
+
resolve({
|
|
102
|
+
sessionId,
|
|
103
|
+
startedAt,
|
|
104
|
+
endedAt,
|
|
105
|
+
transcriptPath,
|
|
106
|
+
submitted: deps.isSubmitted(),
|
|
107
|
+
stdout,
|
|
108
|
+
aborted: aborted || deps.abort.aborted,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
child.on('error', (err) => {
|
|
112
|
+
cleanup();
|
|
113
|
+
const endedAt = Date.now();
|
|
114
|
+
appendFileSync(transcriptPath, `\n\n=== Session spawn error: ${err.message} ===\n`);
|
|
115
|
+
deps.log({ level: 'error', msg: `apy-prediction-session: ${sessionId} spawn error`, data: { err: err.message } });
|
|
116
|
+
resolve({
|
|
117
|
+
sessionId,
|
|
118
|
+
startedAt,
|
|
119
|
+
endedAt,
|
|
120
|
+
transcriptPath,
|
|
121
|
+
submitted: deps.isSubmitted(),
|
|
122
|
+
stdout,
|
|
123
|
+
aborted: deps.abort.aborted,
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=session-orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-orchestrator.js","sourceRoot":"","sources":["../../../../src/restorer/impls/claude-mcp-prediction-apy/session-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAkB9D,MAAM,sBAAsB,GAAG,OAAO,CAAC;AACvC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AACrC,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB,EAAE,MAAc,EAAE,IAAsB;IAC1F,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,sBAAsB,CAAC;IACjE,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,wBAAwB,CAAC;IACvE,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,2BAA2B,CAAC;IAEhF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IAChE,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,aAAa,CACX,cAAc,EACd,eAAe,SAAS,eAAe,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,UAAU,CACnF,CAAC;IAEF,MAAM,IAAI,GAAG;QACX,IAAI,EAAE,MAAM;QACZ,cAAc,EAAE,IAAI,CAAC,aAAa;QAClC,qBAAqB;QACrB,gBAAgB,EAAE,6BAA6B;KAChD,CAAC;IACF,IAAI,IAAI,CAAC,WAAW;QAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAE7D,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,GAAG,IAAI;QAChB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ;QACzD,iBAAiB,EAAE,eAAe,EAAE,gBAAgB;QACpD,WAAW,EAAE,cAAc,EAAE,mBAAmB;QAChD,yBAAyB,EAAE,mBAAmB;KAC/C,EAAE,CAAC;QACF,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,oCAAoC,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAEzH,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;IAEvC,OAAO,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,EAAE;QAC5C,MAAM,KAAK,GAAiB,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE;YACzD,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,EAAE,QAAQ;SACd,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,eAAe,GAAG,KAAK,CAAC;QAE5B,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC;YAChB,cAAc,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;YACrC,cAAc,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YACrC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBAClB,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,2BAA2B,SAAS,gCAAgC,EAAE,IAAI,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;gBAC/H,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;QACH,CAAC,EAAE,YAAY,CAAC,CAAC;QAEjB,IAAI,UAAU,GAA0B,IAAI,CAAC;QAC7C,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,IAAI,UAAU,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YACvC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,2BAA2B,SAAS,iEAAiE,EAAE,CAAC,CAAC;gBACxI,eAAe,GAAG,IAAI,CAAC;gBACvB,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM;wBAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC3C,CAAC,EAAE,iBAAiB,CAAC,CAAC;YACxB,CAAC;QACH,CAAC,EAAE,cAAc,CAAC,CAAC;QAEnB,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,2BAA2B,SAAS,wBAAwB,EAAE,CAAC,CAAC;YAC/F,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAE9C,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,cAAc,CAAC,CAAC;YAC7B,IAAI,UAAU;gBAAE,YAAY,CAAC,UAAU,CAAC,CAAC;YACzC,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAChC,OAAO,EAAE,CAAC;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,cAAc,CACZ,cAAc,EACd,4BAA4B,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,UAAU,IAAI,WAAW,MAAM,cAAc,IAAI,CAAC,WAAW,EAAE,oBAAoB,eAAe,YAAY,OAAO,SAAS,CAC1L,CAAC;YACF,IAAI,CAAC,GAAG,CAAC;gBACP,KAAK,EAAE,MAAM;gBACb,GAAG,EAAE,2BAA2B,SAAS,SAAS;gBAClD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE;aAChG,CAAC,CAAC;YACH,OAAO,CAAC;gBACN,SAAS;gBACT,SAAS;gBACT,OAAO;gBACP,cAAc;gBACd,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE;gBAC7B,MAAM;gBACN,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO;aACvC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,OAAO,EAAE,CAAC;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,cAAc,CAAC,cAAc,EAAE,gCAAgC,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC;YACpF,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,2BAA2B,SAAS,cAAc,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAClH,OAAO,CAAC;gBACN,SAAS;gBACT,SAAS;gBACT,OAAO;gBACP,cAAc;gBACd,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE;gBAC7B,MAAM;gBACN,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;aAC5B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|