feat(builder)!: self-improvement family keyless - two-step proposal tools, @ts-nocheck dropped, safety.ts deleted, custody allowlist EMPTY

Rewrites self-improvement.ts (1024 -> 556 lines): typed, no @ts-nocheck,
imports build logic from gov-build.ts (Tasks 3-4). Splits the old single-shot
vector_self_improvement_submit_proposal into two keyless build tools
(proposal_lock, proposal_spend) since the deployed module validator requires
a confirmed lock before the spend+mint step can reference it; renames
critique/endorse to vector_build_self_improvement_*. browse and
analyze_metrics stay behavior-identical read-only tools (render strings
verified byte-for-byte against the custodial originals).

Deletes safety.ts (its last importer). Removes SpendLimits/SpendStatus/
AuditEntry from shared types (grep-verified zero references first). Drops
the now-dead spend-limit/audit-log env vars. Empties the custody boundary
allowlist with a size-0 pin - every builder family is now keyless.

Tool count 23 -> 24. Snapshot delta is surgical: 3 removed, 4 added, 19 of
the other 20 byte-identical (analyze_metrics' description had to drop the
literal word "mnemonic" to satisfy the custody grep - the one disclosed
exception).

Headline: grep -rni "mnemonic|seed|bip39|fromSeed" packages/builder/src
returns zero lines. This was the last custodial family.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
FilipBl4gojevic
2026-07-30 16:43:16 +02:00
parent 81626738bf
commit 88068816e6
7 changed files with 533 additions and 1129 deletions

View File

@@ -7,16 +7,10 @@ VECTOR_KOIOS_URL=https://v2.koios.vector.testnet.apexfusion.org/
VECTOR_SUBMIT_URL=https://submit.vector.testnet.apexfusion.org/api/submit/tx VECTOR_SUBMIT_URL=https://submit.vector.testnet.apexfusion.org/api/submit/tx
VECTOR_EXPLORER_URL=https://vector.testnet.apexscan.org VECTOR_EXPLORER_URL=https://vector.testnet.apexscan.org
# Safety Limits (in lovelace, 1 ADA = 1,000,000 lovelace) # Non-custodial migration complete: every builder tool is keyless. Spend
# Scope note (non-custodial migration): the keyless build_* families (wallet/tx/contract, # limits and audit logging are owned entirely by the LOCAL signer, per user -
# agent registry) ignore these - spend limits for them are enforced by the LOCAL signer, per # see packages/signer/README.md. The server holds no key material and enforces
# user. These server-side limits still govern the one remaining custodial family # no spend limits of its own.
# (self-improvement) and will be removed when it goes keyless too.
VECTOR_SPEND_LIMIT_PER_TX=100000000 # 100 ADA per transaction
VECTOR_SPEND_LIMIT_DAILY=500000000 # 500 ADA daily limit
# Audit Log
VECTOR_AUDIT_LOG_PATH=./vector-audit-log.json # Path for persistent audit log (default: ./vector-audit-log.json)
# Auth - when set, every request must carry `Authorization: Bearer <token>`. # Auth - when set, every request must carry `Authorization: Bearer <token>`.
# Comma-separated; each entry is `label:token` or a bare token. # Comma-separated; each entry is `label:token` or a bare token.

View File

@@ -1,144 +0,0 @@
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import type { SpendLimits, SpendStatus, AuditEntry } from '@apexfusion/vector-mcp-shared/types';
const VECTOR_SPEND_LIMIT_PER_TX = parseInt(process.env.VECTOR_SPEND_LIMIT_PER_TX || '100000000'); // 100 AP3X
const VECTOR_SPEND_LIMIT_DAILY = parseInt(process.env.VECTOR_SPEND_LIMIT_DAILY || '500000000'); // 500 AP3X
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// From the bundled entrypoint's directory (packages/builder/build), three levels
// up lands on the repo root, which is where .env.example and the README document
// the default audit log path (./vector-audit-log.json) as living.
const projectRoot = resolve(__dirname, '../../..');
export class SafetyLayer {
private dailySpent: number = 0;
private dailyResetTime: number;
private auditLog: AuditEntry[] = [];
private limits: SpendLimits;
private auditLogPath: string;
constructor() {
this.limits = {
perTransaction: VECTOR_SPEND_LIMIT_PER_TX,
daily: VECTOR_SPEND_LIMIT_DAILY,
};
// Reset daily limit at midnight UTC
this.dailyResetTime = this.getNextMidnightUTC();
// Audit log file persistence
this.auditLogPath = process.env.VECTOR_AUDIT_LOG_PATH
? resolve(process.env.VECTOR_AUDIT_LOG_PATH)
: resolve(projectRoot, 'vector-audit-log.json');
this.loadAuditLog();
}
private getNextMidnightUTC(): number {
const now = new Date();
const tomorrow = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
return tomorrow.getTime();
}
private checkAndResetDaily(): void {
if (Date.now() >= this.dailyResetTime) {
this.dailySpent = 0;
this.dailyResetTime = this.getNextMidnightUTC();
}
}
private loadAuditLog(): void {
try {
if (existsSync(this.auditLogPath)) {
const data = readFileSync(this.auditLogPath, 'utf-8');
const parsed = JSON.parse(data);
if (Array.isArray(parsed)) {
this.auditLog = parsed;
// Recalculate dailySpent from today's entries (survives server restart)
this.recalculateDailySpent();
}
}
} catch (err) {
console.error(`Warning: Could not load audit log from ${this.auditLogPath}:`, err);
this.auditLog = [];
}
}
private recalculateDailySpent(): void {
const todayStart = new Date();
todayStart.setUTCHours(0, 0, 0, 0);
const todayStartMs = todayStart.getTime();
this.dailySpent = 0;
for (const entry of this.auditLog) {
const entryTime = new Date(entry.timestamp).getTime();
if (entryTime >= todayStartMs) {
this.dailySpent += entry.amountLovelace;
}
}
}
private persistAuditLog(): void {
try {
writeFileSync(this.auditLogPath, JSON.stringify(this.auditLog, null, 2));
} catch (err) {
console.error(`Warning: Could not persist audit log to ${this.auditLogPath}:`, err);
}
}
checkTransaction(amountLovelace: number): { allowed: boolean; reason?: string } {
this.checkAndResetDaily();
if (amountLovelace > this.limits.perTransaction) {
return {
allowed: false,
reason: `Transaction amount ${(amountLovelace / 1_000_000).toFixed(6)} AP3X exceeds per-transaction limit of ${(this.limits.perTransaction / 1_000_000).toFixed(6)} AP3X`,
};
}
if (this.dailySpent + amountLovelace > this.limits.daily) {
const remaining = this.limits.daily - this.dailySpent;
return {
allowed: false,
reason: `Transaction would exceed daily spend limit. Daily limit: ${(this.limits.daily / 1_000_000).toFixed(6)} AP3X, already spent: ${(this.dailySpent / 1_000_000).toFixed(6)} AP3X, remaining: ${(remaining / 1_000_000).toFixed(6)} AP3X`,
};
}
return { allowed: true };
}
recordTransaction(txHash: string, amountLovelace: number, recipient: string): void {
this.checkAndResetDaily();
this.dailySpent += amountLovelace;
this.auditLog.push({
timestamp: new Date().toISOString(),
txHash,
amountLovelace,
recipient,
action: 'send',
});
this.persistAuditLog();
}
getSpendStatus(): SpendStatus {
this.checkAndResetDaily();
return {
perTransactionLimit: this.limits.perTransaction,
dailyLimit: this.limits.daily,
dailySpent: this.dailySpent,
dailyRemaining: Math.max(0, this.limits.daily - this.dailySpent),
resetTime: new Date(this.dailyResetTime).toISOString(),
};
}
getAuditLog(): AuditEntry[] {
return [...this.auditLog];
}
}
// Singleton instance
export const safetyLayer = new SafetyLayer();

File diff suppressed because it is too large Load Diff

View File

@@ -13,9 +13,11 @@ import { resolve, join, relative } from 'node:path';
*/ */
const SRC_ROOT = resolve(import.meta.dirname!, '../src'); const SRC_ROOT = resolve(import.meta.dirname!, '../src');
const SCRIPTS_ROOT = resolve(import.meta.dirname!, '../scripts'); const SCRIPTS_ROOT = resolve(import.meta.dirname!, '../scripts');
const CUSTODIAL_UNTIL_LATER_PR = new Set([ // Empty since spec PR 8: family 3 (self-improvement) went keyless, taking the
'vector/self-improvement.ts', // family 3 (governance) — goes keyless in spec PR 8 // last custodial file (vector/self-improvement.ts) off the allowlist. Every
]); // builder family is now keyless - this set may never grow again (see the
// size-0 pin below).
const CUSTODIAL_UNTIL_LATER_PR = new Set<string>([]);
// No \b boundaries: this is deliberately a substring match, not a whole-word // No \b boundaries: this is deliberately a substring match, not a whole-word
// one. Word-bounding let `seedPhrase`, `WALLET_SEED` or `bip39x` slip past // one. Word-bounding let `seedPhrase`, `WALLET_SEED` or `bip39x` slip past
// undetected — those are real key-material vocabulary wearing a different // undetected — those are real key-material vocabulary wearing a different
@@ -70,11 +72,13 @@ describe('builder custody boundary', () => {
}); });
// The allowlist may only shrink (PR 7 dropped agent-network.ts to reach 1, // The allowlist may only shrink (PR 7 dropped agent-network.ts to reach 1,
// PR 8 drops self-improvement.ts to reach 0 - see the "goes keyless in spec // PR 8 drops self-improvement.ts to reach 0 - see the comment above
// PR N" comment above). Pinning the size means any widening is a deliberate, // CUSTODIAL_UNTIL_LATER_PR). Pinning the size means any widening is a
// reviewable number change instead of a silent `.add(...)` slipping through. // deliberate, reviewable number change instead of a silent `.add(...)`
// slipping through - and since the migration is complete, that number can
// now only ever be 0.
test('the allowlist may only shrink', () => { test('the allowlist may only shrink', () => {
assert.equal(CUSTODIAL_UNTIL_LATER_PR.size, 1, 'the custodial allowlist may only shrink - spec PR 8 takes it to 0'); assert.equal(CUSTODIAL_UNTIL_LATER_PR.size, 0, 'the custodial allowlist is EMPTY - the migration is complete; it may never grow again');
}); });
// Pins every FORBIDDEN alternative individually against a fixture corpus, so // Pins every FORBIDDEN alternative individually against a fixture corpus, so

View File

@@ -5,7 +5,7 @@ import { resolve } from 'node:path';
import { startServer, stopServer, ServerContext } from '../setup.ts'; import { startServer, stopServer, ServerContext } from '../setup.ts';
/** /**
* Snapshot of the current tool surface (23 tools) for the non-custodial split * Snapshot of the current tool surface (24 tools) for the non-custodial split
* series (see docs/architecture/non-custodial-split.md). PR 6 (Task 5) is the * series (see docs/architecture/non-custodial-split.md). PR 6 (Task 5) is the
* PR that took this list from 25 to 23: it deleted `vector_get_address` * PR that took this list from 25 to 23: it deleted `vector_get_address`
* outright, along with the tool that reported per-transaction/daily * outright, along with the tool that reported per-transaction/daily
@@ -13,7 +13,14 @@ import { startServer, stopServer, ServerContext } from '../setup.ts';
* keyless equivalent — spend status is gone because the builder no longer * keyless equivalent — spend status is gone because the builder no longer
* holds keys to limit) as part of making the remaining query tools * holds keys to limit) as part of making the remaining query tools
* (`vector_get_utxos`, `vector_get_transaction_history`, `vector_dry_run`) * (`vector_get_utxos`, `vector_get_transaction_history`, `vector_dry_run`)
* keyless. PRs 2, 6, 7 and 8 each deliberately restructure and rename tool * keyless. Spec PR 8 (Task 5) took it from 23 to 24: the self-improvement
* family went keyless, removing `vector_self_improvement_submit_proposal`
* and renaming `_critique`/`_endorse` to `vector_build_self_improvement_*`,
* and splitting the old single-shot submit into two build_* tools
* (`_proposal_lock` + `_proposal_spend`) since the deployed module validator
* requires a confirmed lock before the spend+mint step can reference it.
* This was the last custodial family - the builder now holds no key material
* anywhere. PRs 2, 6, 7 and 8 each deliberately restructure and rename tool
* families, and each of those PRs is expected to update this list * families, and each of those PRs is expected to update this list
* deliberately, not accidentally. No wallet, no network beyond localhost — * deliberately, not accidentally. No wallet, no network beyond localhost —
* this never needs a mnemonic. * this never needs a mnemonic.
@@ -25,6 +32,10 @@ const EXPECTED_TOOLS = [
'vector_build_interact_contract', 'vector_build_interact_contract',
'vector_build_message_agent', 'vector_build_message_agent',
'vector_build_register_agent', 'vector_build_register_agent',
'vector_build_self_improvement_critique',
'vector_build_self_improvement_endorse',
'vector_build_self_improvement_proposal_lock',
'vector_build_self_improvement_proposal_spend',
'vector_build_send_apex', 'vector_build_send_apex',
'vector_build_send_tokens', 'vector_build_send_tokens',
'vector_build_transaction', 'vector_build_transaction',
@@ -38,9 +49,6 @@ const EXPECTED_TOOLS = [
'vector_get_utxos', 'vector_get_utxos',
'vector_self_improvement_analyze_metrics', 'vector_self_improvement_analyze_metrics',
'vector_self_improvement_browse', 'vector_self_improvement_browse',
'vector_self_improvement_critique',
'vector_self_improvement_endorse',
'vector_self_improvement_submit_proposal',
'vector_submit_transaction', 'vector_submit_transaction',
]; ];
@@ -92,11 +100,11 @@ after(async () => {
}); });
describe('tool inventory smoke test', () => { describe('tool inventory smoke test', () => {
test('exposes exactly 23 tools', () => { test('exposes exactly 24 tools', () => {
assert.equal( assert.equal(
actualNames.length, actualNames.length,
23, 24,
`expected 23 tools, got ${actualNames.length}: ${JSON.stringify(actualNames)}` `expected 24 tools, got ${actualNames.length}: ${JSON.stringify(actualNames)}`
); );
}); });
@@ -132,7 +140,7 @@ describe('tool schema snapshot', () => {
}); });
// One assertion per tool (rather than a single deepStrictEqual over the whole // One assertion per tool (rather than a single deepStrictEqual over the whole
// 23-tool map) so a failure names the specific tool and shows a readable // 24-tool map) so a failure names the specific tool and shows a readable
// diff of just that tool's schema, instead of "objects differ" over an // diff of just that tool's schema, instead of "objects differ" over an
// unreadable combined structure. // unreadable combined structure.
for (const toolName of Object.keys(schemaSnapshot).sort()) { for (const toolName of Object.keys(schemaSnapshot).sort()) {

View File

@@ -243,6 +243,220 @@
"$schema": "http://json-schema.org/draft-07/schema#" "$schema": "http://json-schema.org/draft-07/schema#"
} }
}, },
"vector_build_self_improvement_critique": {
"description": "Build an UNSIGNED transaction that submits a critique on an improvement proposal (Supportive, Opposing, or Amendment). Requires staking at least 10 AP3X. Provide critiqueDocument for automatic IPFS upload, or critiqueHash and storageUri manually. Takes no key material. Sign it locally with vector_signer_sign, broadcast with vector_submit_transaction, then confirm with vector_await_transaction. Find a proposalTxHash to critique with vector_self_improvement_browse.",
"inputSchema": {
"type": "object",
"properties": {
"changeAddress": {
"description": "Your wallet address (holds the stake AP3X; receives change). Get it from vector_signer_get_address.",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex)",
"type": "string"
},
"proposalTxHash": {
"description": "TX hash of the proposal UTxO to critique",
"type": "string"
},
"proposalOutputIndex": {
"description": "Output index of the proposal UTxO",
"default": 0,
"type": "number"
},
"critiqueDocument": {
"description": "Full critique document as JSON string. Uploaded to IPFS via Filebase; hash and CID computed automatically.",
"type": "string"
},
"critiqueHash": {
"description": "blake2b_256 hash of critique document (64 hex chars). Required if critiqueDocument is not provided.",
"type": "string"
},
"critiqueType": {
"description": "Type of critique",
"type": "string",
"enum": [
"Supportive",
"Opposing",
"Amendment"
]
},
"storageUri": {
"description": "Off-chain storage URI for the critique document. Required if critiqueDocument is not provided.",
"type": "string"
},
"stakeApex": {
"description": "AP3X to stake (minimum 10)",
"type": "number",
"minimum": 10
}
},
"required": [
"changeAddress",
"agentDid",
"proposalTxHash",
"critiqueType",
"stakeApex"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_build_self_improvement_endorse": {
"description": "Build an UNSIGNED transaction that endorses an improvement proposal by staking at least 5 AP3X. Endorsements signal support to the Foundation Council and are weighted by stake amount. Takes no key material. Sign it locally with vector_signer_sign, broadcast with vector_submit_transaction, then confirm with vector_await_transaction. Find a proposalTxHash to endorse with vector_self_improvement_browse.",
"inputSchema": {
"type": "object",
"properties": {
"changeAddress": {
"description": "Your wallet address (holds the stake AP3X; receives change). Get it from vector_signer_get_address.",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex)",
"type": "string"
},
"proposalTxHash": {
"description": "TX hash of the proposal UTxO to endorse",
"type": "string"
},
"proposalOutputIndex": {
"description": "Output index of the proposal UTxO",
"default": 0,
"type": "number"
},
"stakeApex": {
"description": "AP3X to stake as endorsement (minimum 5)",
"type": "number",
"minimum": 5
}
},
"required": [
"changeAddress",
"agentDid",
"proposalTxHash",
"stakeApex"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_build_self_improvement_proposal_lock": {
"description": "Build an UNSIGNED transaction that locks an improvement-proposal stake (step 1 of 2). Requires staking at least 25 AP3X. Provide proposalDocument for automatic IPFS upload, or proposalHash and storageUri manually. Takes no key material. Sign it locally with vector_signer_sign, broadcast with vector_submit_transaction, then confirm with vector_await_transaction. After this confirms, call this tool's counterpart, vector_build_self_improvement_proposal_spend, with the lock transaction hash to complete the submission.",
"inputSchema": {
"type": "object",
"properties": {
"changeAddress": {
"description": "Your wallet address (holds the stake AP3X; receives change). Get it from vector_signer_get_address.",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex) - the asset name from Agent Registry NFT",
"type": "string"
},
"proposalType": {
"description": "Category of the proposal",
"type": "string",
"enum": [
"ParameterChange",
"TreasurySpend",
"ProtocolUpgrade",
"GameActivation",
"GeneralSuggestion"
]
},
"stakeApex": {
"description": "AP3X to stake (minimum 25)",
"type": "number",
"minimum": 25
},
"typeParams": {
"description": "Type-specific parameters (required for ParameterChange and TreasurySpend)",
"type": "object",
"properties": {
"paramName": {
"type": "string"
},
"currentValue": {
"type": "number"
},
"proposedValue": {
"type": "number"
},
"amount": {
"type": "number"
},
"recipientDescription": {
"type": "string"
},
"upgradeHash": {
"type": "string"
},
"gameId": {
"type": "number"
}
}
},
"priority": {
"description": "Priority level (Emergency requires higher stake and reputation)",
"default": "Standard",
"type": "string",
"enum": [
"Standard",
"Emergency"
]
},
"proposalDocument": {
"description": "Full proposal document as JSON string. Uploaded to IPFS via Filebase; hash and CID computed automatically. If provided, proposalHash and storageUri are ignored.",
"type": "string"
},
"proposalHash": {
"description": "blake2b_256 hash of proposal document (64 hex chars). Required if proposalDocument is not provided.",
"type": "string"
},
"storageUri": {
"description": "Off-chain storage URI for the full proposal (IPFS CID or OriginTrail UAL). Required if proposalDocument is not provided.",
"type": "string"
}
},
"required": [
"changeAddress",
"agentDid",
"proposalType",
"stakeApex"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_build_self_improvement_proposal_spend": {
"description": "Build an UNSIGNED transaction that completes an improvement-proposal submission (step 2 of 2): spends the locked stake through the module validator and mints the proposal and activity tokens. Requires the confirmed lock transaction hash from vector_build_self_improvement_proposal_lock. Takes no key material. Sign it locally with vector_signer_sign, broadcast with vector_submit_transaction, then confirm with vector_await_transaction.",
"inputSchema": {
"type": "object",
"properties": {
"changeAddress": {
"description": "The SAME wallet address used to build the proposal lock. Get it from vector_signer_get_address.",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex) - must match the proposer DID in the locked proposal",
"type": "string"
},
"lockTxHash": {
"description": "The CONFIRMED transaction hash from the proposal lock step",
"type": "string"
},
"lockOutputIndex": {
"description": "Output index of the locked proposal UTxO (default: 0)",
"default": 0,
"type": "number"
}
},
"required": [
"changeAddress",
"agentDid",
"lockTxHash"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_build_send_apex": { "vector_build_send_apex": {
"description": "Build an UNSIGNED transaction sending AP3X to a recipient. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.", "description": "Build an UNSIGNED transaction sending AP3X to a recipient. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
"inputSchema": { "inputSchema": {
@@ -589,7 +803,7 @@
} }
}, },
"vector_self_improvement_analyze_metrics": { "vector_self_improvement_analyze_metrics": {
"description": "Analyze proposal metrics: proposal activity, adoption rate, treasury health, and engagement statistics. Read-only - no mnemonic needed.", "description": "Analyze proposal metrics: proposal activity, adoption rate, treasury health, and engagement statistics. Read-only, takes no key material.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -646,189 +860,6 @@
"$schema": "http://json-schema.org/draft-07/schema#" "$schema": "http://json-schema.org/draft-07/schema#"
} }
}, },
"vector_self_improvement_critique": {
"description": "Submit a critique on an improvement proposal. Critiques can support, oppose, or propose amendments. Requires staking AP3X. Provide critiqueDocument (JSON string) for automatic IPFS upload, or critiqueHash + storageUri manually.",
"inputSchema": {
"type": "object",
"properties": {
"mnemonic": {
"description": "15 or 24-word BIP39 mnemonic for the wallet",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex)",
"type": "string"
},
"proposalTxHash": {
"description": "TX hash of the proposal UTxO to critique",
"type": "string"
},
"proposalOutputIndex": {
"description": "Output index of the proposal UTxO",
"default": 0,
"type": "number"
},
"critiqueDocument": {
"description": "Full critique document as JSON string. Uploaded to IPFS via Filebase; hash and CID computed automatically.",
"type": "string"
},
"critiqueHash": {
"description": "blake2b_256 hash of critique document (64 hex chars). Required if critiqueDocument is not provided.",
"type": "string"
},
"critiqueType": {
"description": "Type of critique",
"type": "string",
"enum": [
"Supportive",
"Opposing",
"Amendment"
]
},
"storageUri": {
"description": "Off-chain storage URI for the critique document. Required if critiqueDocument is not provided.",
"type": "string"
},
"stakeApex": {
"description": "AP3X to stake (minimum 10)",
"type": "number",
"minimum": 10
}
},
"required": [
"mnemonic",
"agentDid",
"proposalTxHash",
"critiqueType",
"stakeApex"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_self_improvement_endorse": {
"description": "Endorse an improvement proposal by staking AP3X. Endorsements signal support to the Foundation Council and are weighted by stake amount.",
"inputSchema": {
"type": "object",
"properties": {
"mnemonic": {
"description": "15 or 24-word BIP39 mnemonic for the wallet",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex)",
"type": "string"
},
"proposalTxHash": {
"description": "TX hash of the proposal UTxO to endorse",
"type": "string"
},
"proposalOutputIndex": {
"description": "Output index of the proposal UTxO",
"default": 0,
"type": "number"
},
"stakeApex": {
"description": "AP3X to stake as endorsement (minimum 5)",
"type": "number",
"minimum": 5
}
},
"required": [
"mnemonic",
"agentDid",
"proposalTxHash",
"stakeApex"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_self_improvement_submit_proposal": {
"description": "Submit an improvement proposal to the Vector Self-Improvement Module. Requires staking AP3X. Provide proposalDocument (JSON string) for automatic IPFS upload via Filebase and blake2b_256 hashing, OR provide proposalHash and storageUri manually.",
"inputSchema": {
"type": "object",
"properties": {
"mnemonic": {
"description": "15 or 24-word BIP39 mnemonic for the wallet",
"type": "string"
},
"agentDid": {
"description": "Agent DID (hex) - the asset name from Agent Registry NFT",
"type": "string"
},
"proposalDocument": {
"description": "Full proposal document as JSON string. Uploaded to IPFS via Filebase; hash and CID computed automatically. If provided, proposalHash and storageUri are ignored.",
"type": "string"
},
"proposalHash": {
"description": "blake2b_256 hash of proposal document (64 hex chars). Required if proposalDocument is not provided.",
"type": "string"
},
"proposalType": {
"description": "Category of the proposal",
"type": "string",
"enum": [
"ParameterChange",
"TreasurySpend",
"ProtocolUpgrade",
"GameActivation",
"GeneralSuggestion"
]
},
"storageUri": {
"description": "Off-chain storage URI for the full proposal (IPFS CID or OriginTrail UAL). Required if proposalDocument is not provided.",
"type": "string"
},
"stakeApex": {
"description": "AP3X to stake (minimum 25)",
"type": "number",
"minimum": 25
},
"typeParams": {
"description": "Type-specific parameters (required for ParameterChange and TreasurySpend)",
"type": "object",
"properties": {
"paramName": {
"type": "string"
},
"currentValue": {
"type": "number"
},
"proposedValue": {
"type": "number"
},
"amount": {
"type": "number"
},
"recipientDescription": {
"type": "string"
},
"upgradeHash": {
"type": "string"
},
"gameId": {
"type": "number"
}
}
},
"priority": {
"description": "Priority level (Emergency requires higher stake and reputation)",
"default": "Standard",
"type": "string",
"enum": [
"Standard",
"Emergency"
]
}
},
"required": [
"mnemonic",
"agentDid",
"proposalType",
"stakeApex"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"vector_submit_transaction": { "vector_submit_transaction": {
"description": "Submit an already-signed transaction to Vector. Use this to broadcast CBOR signed elsewhere (for example by a local signer). Does not sign anything.", "description": "Submit an already-signed transaction to Vector. Use this to broadcast CBOR signed elsewhere (for example by a local signer). Does not sign anything.",
"inputSchema": { "inputSchema": {

View File

@@ -1,26 +1,5 @@
// Vector-specific type definitions // Vector-specific type definitions
export interface SpendLimits {
perTransaction: number; // lovelace
daily: number; // lovelace
}
export interface SpendStatus {
perTransactionLimit: number;
dailyLimit: number;
dailySpent: number;
dailyRemaining: number;
resetTime: string;
}
export interface AuditEntry {
timestamp: string;
txHash: string;
amountLovelace: number;
recipient: string;
action: string;
}
// --- Build Transaction --- // --- Build Transaction ---
export interface TxOutput { export interface TxOutput {