iranti 0.3.40 → 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/dist/scripts/iranti-cli.js +100 -4
- package/dist/scripts/iranti-mcp.js +9 -5
- package/dist/scripts/setup.js +2 -1
- package/dist/src/api/middleware/auth.d.ts +2 -0
- package/dist/src/api/middleware/auth.d.ts.map +1 -1
- package/dist/src/api/middleware/auth.js +2 -0
- package/dist/src/api/middleware/auth.js.map +1 -1
- package/dist/src/api/routes/batch.js +2 -1
- package/dist/src/api/routes/batch.js.map +1 -1
- package/dist/src/api/routes/consumerMcp.d.ts +25 -0
- package/dist/src/api/routes/consumerMcp.d.ts.map +1 -0
- package/dist/src/api/routes/consumerMcp.js +197 -0
- package/dist/src/api/routes/consumerMcp.js.map +1 -0
- package/dist/src/api/routes/feedback.d.ts +13 -0
- package/dist/src/api/routes/feedback.d.ts.map +1 -0
- package/dist/src/api/routes/feedback.js +111 -0
- package/dist/src/api/routes/feedback.js.map +1 -0
- package/dist/src/api/routes/knowledge.d.ts.map +1 -1
- package/dist/src/api/routes/knowledge.js +9 -5
- package/dist/src/api/routes/knowledge.js.map +1 -1
- package/dist/src/api/routes/memory.d.ts.map +1 -1
- package/dist/src/api/routes/memory.js +2 -1
- package/dist/src/api/routes/memory.js.map +1 -1
- package/dist/src/api/routes/tokens.d.ts +18 -0
- package/dist/src/api/routes/tokens.d.ts.map +1 -0
- package/dist/src/api/routes/tokens.js +89 -0
- package/dist/src/api/routes/tokens.js.map +1 -0
- package/dist/src/api/server.js +24 -1
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/attendant/AttendantInstance.d.ts +19 -0
- package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
- package/dist/src/attendant/AttendantInstance.js +243 -4
- package/dist/src/attendant/AttendantInstance.js.map +1 -1
- package/dist/src/generated/prisma/browser.d.ts +15 -0
- package/dist/src/generated/prisma/browser.d.ts.map +1 -1
- package/dist/src/generated/prisma/client.d.ts +17 -2
- package/dist/src/generated/prisma/client.d.ts.map +1 -1
- package/dist/src/generated/prisma/client.js +2 -2
- package/dist/src/generated/prisma/commonInputTypes.d.ts +363 -243
- package/dist/src/generated/prisma/commonInputTypes.d.ts.map +1 -1
- package/dist/src/generated/prisma/enums.d.ts +24 -0
- package/dist/src/generated/prisma/enums.d.ts.map +1 -1
- package/dist/src/generated/prisma/enums.js +22 -1
- package/dist/src/generated/prisma/enums.js.map +1 -1
- package/dist/src/generated/prisma/internal/class.d.ts +40 -7
- package/dist/src/generated/prisma/internal/class.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/class.js +4 -4
- package/dist/src/generated/prisma/internal/class.js.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespace.d.ts +304 -14
- package/dist/src/generated/prisma/internal/prismaNamespace.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespace.js +45 -7
- package/dist/src/generated/prisma/internal/prismaNamespace.js.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts +46 -5
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js +45 -7
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/src/generated/prisma/models/Archive.d.ts +0 -10
- package/dist/src/generated/prisma/models/Archive.d.ts.map +1 -1
- package/dist/src/generated/prisma/models/Feedback.d.ts +1328 -0
- package/dist/src/generated/prisma/models/Feedback.d.ts.map +1 -0
- package/dist/src/generated/prisma/models/Feedback.js +3 -0
- package/dist/src/generated/prisma/models/Feedback.js.map +1 -0
- package/dist/src/generated/prisma/models/KnowledgeEntry.d.ts +349 -17
- package/dist/src/generated/prisma/models/KnowledgeEntry.d.ts.map +1 -1
- package/dist/src/generated/prisma/models/Token.d.ts +1329 -0
- package/dist/src/generated/prisma/models/Token.d.ts.map +1 -0
- package/dist/src/generated/prisma/models/Token.js +3 -0
- package/dist/src/generated/prisma/models/Token.js.map +1 -0
- package/dist/src/generated/prisma/models/User.d.ts +1545 -0
- package/dist/src/generated/prisma/models/User.d.ts.map +1 -0
- package/dist/src/generated/prisma/models/User.js +3 -0
- package/dist/src/generated/prisma/models/User.js.map +1 -0
- package/dist/src/generated/prisma/models.d.ts +3 -0
- package/dist/src/generated/prisma/models.d.ts.map +1 -1
- package/dist/src/lib/cliHelpCatalog.d.ts.map +1 -1
- package/dist/src/lib/cliHelpCatalog.js +6 -0
- package/dist/src/lib/cliHelpCatalog.js.map +1 -1
- package/dist/src/lib/cliHelpRenderer.d.ts +1 -0
- package/dist/src/lib/cliHelpRenderer.d.ts.map +1 -1
- package/dist/src/lib/cliHelpRenderer.js +4 -0
- package/dist/src/lib/cliHelpRenderer.js.map +1 -1
- package/dist/src/lib/feedbackCollector.d.ts.map +1 -1
- package/dist/src/lib/feedbackCollector.js +48 -1
- package/dist/src/lib/feedbackCollector.js.map +1 -1
- package/dist/src/librarian/source-reliability.d.ts.map +1 -1
- package/dist/src/librarian/source-reliability.js +4 -2
- package/dist/src/librarian/source-reliability.js.map +1 -1
- package/dist/src/library/agent-registry.d.ts.map +1 -1
- package/dist/src/library/agent-registry.js +12 -6
- package/dist/src/library/agent-registry.js.map +1 -1
- package/dist/src/library/queries.d.ts.map +1 -1
- package/dist/src/library/queries.js +4 -2
- package/dist/src/library/queries.js.map +1 -1
- package/dist/src/sdk/index.d.ts +1 -0
- package/dist/src/sdk/index.d.ts.map +1 -1
- package/dist/src/sdk/index.js +1 -1
- package/dist/src/sdk/index.js.map +1 -1
- package/dist/src/security/apiKeys.d.ts +2 -0
- package/dist/src/security/apiKeys.d.ts.map +1 -1
- package/dist/src/security/apiKeys.js +8 -4
- package/dist/src/security/apiKeys.js.map +1 -1
- package/dist/src/security/consumerTokens.d.ts +52 -0
- package/dist/src/security/consumerTokens.d.ts.map +1 -0
- package/dist/src/security/consumerTokens.js +98 -0
- package/dist/src/security/consumerTokens.js.map +1 -0
- package/package.json +1 -1
- package/prisma/migrations/20260414191958_add_multi_tenant_identity/migration.sql +106 -0
- package/prisma/migrations/20260415030000_add_feedback_table/migration.sql +35 -0
- package/prisma/schema.prisma +84 -2
|
@@ -2329,20 +2329,23 @@ try {
|
|
|
2329
2329
|
const pendingEdits = debt.pendingEdits || 0;
|
|
2330
2330
|
const lastEditAt = debt.lastEditAt || null;
|
|
2331
2331
|
|
|
2332
|
-
|
|
2332
|
+
// Block only after this many unique file edits are pending.
|
|
2333
|
+
const WRITE_DEBT_BLOCK_THRESHOLD = 5;
|
|
2334
|
+
|
|
2335
|
+
if (pendingEdits < WRITE_DEBT_BLOCK_THRESHOLD) {
|
|
2333
2336
|
process.exit(0);
|
|
2334
2337
|
}
|
|
2335
2338
|
|
|
2336
2339
|
const output = JSON.stringify({
|
|
2337
2340
|
hookEventName: 'PreToolUse',
|
|
2338
2341
|
permissionDecision: 'deny',
|
|
2339
|
-
permissionDecisionReason: \`Iranti write-guard: \${pendingEdits} file edit(s)
|
|
2342
|
+
permissionDecisionReason: \`Iranti write-guard: \${pendingEdits} file edit(s) pending iranti_write (threshold: \${WRITE_DEBT_BLOCK_THRESHOLD}). Call iranti_write for pending edits before making new changes.\`,
|
|
2340
2343
|
additionalContext: [
|
|
2341
2344
|
'IRANTI WRITE-GUARD BLOCKED THIS EDIT.',
|
|
2342
2345
|
\`You have \${pendingEdits} pending file edit(s) that have not been written to Iranti shared memory.\`,
|
|
2343
|
-
|
|
2346
|
+
\`Before making any more edits, call iranti_write for pending edits to bring debt below \${WRITE_DEBT_BLOCK_THRESHOLD}.\`,
|
|
2344
2347
|
'Include: entity (project/[id]/file/[filename]), absolutePath, lines changed, what changed and why.',
|
|
2345
|
-
'After writing
|
|
2348
|
+
'After writing pending edits below the threshold, this guard will allow new edits.',
|
|
2346
2349
|
].join('\\n'),
|
|
2347
2350
|
});
|
|
2348
2351
|
|
|
@@ -8591,6 +8594,9 @@ function printProviderKeyHelp() {
|
|
|
8591
8594
|
function printFeedbackHelp() {
|
|
8592
8595
|
(0, cliHelpRenderer_1.printFeedbackHelp)({ sectionTitle, commandText });
|
|
8593
8596
|
}
|
|
8597
|
+
function printUiHelp() {
|
|
8598
|
+
(0, cliHelpRenderer_1.printUiHelp)({ sectionTitle, commandText });
|
|
8599
|
+
}
|
|
8594
8600
|
function printMcpHelp() {
|
|
8595
8601
|
console.log([
|
|
8596
8602
|
'MCP server and maintenance commands.',
|
|
@@ -9009,6 +9015,88 @@ async function deleteRuleCommand(args) {
|
|
|
9009
9015
|
await (0, client_1.disconnectDb)().catch(() => undefined);
|
|
9010
9016
|
}
|
|
9011
9017
|
}
|
|
9018
|
+
// ── UI (control plane launcher) ──────────────────────────────────────────────
|
|
9019
|
+
function openBrowserUrl(url) {
|
|
9020
|
+
try {
|
|
9021
|
+
let cmd;
|
|
9022
|
+
let cmdArgs;
|
|
9023
|
+
if (process.platform === 'win32') {
|
|
9024
|
+
cmd = 'cmd';
|
|
9025
|
+
cmdArgs = ['/c', 'start', '', url];
|
|
9026
|
+
}
|
|
9027
|
+
else if (process.platform === 'darwin') {
|
|
9028
|
+
cmd = 'open';
|
|
9029
|
+
cmdArgs = [url];
|
|
9030
|
+
}
|
|
9031
|
+
else {
|
|
9032
|
+
cmd = 'xdg-open';
|
|
9033
|
+
cmdArgs = [url];
|
|
9034
|
+
}
|
|
9035
|
+
(0, child_process_1.spawn)(cmd, cmdArgs, { stdio: 'ignore', detached: true }).unref();
|
|
9036
|
+
}
|
|
9037
|
+
catch {
|
|
9038
|
+
// Browser open is best-effort; non-fatal
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
async function uiCommand(args) {
|
|
9042
|
+
// Resolve DATABASE_URL from project binding or instance env
|
|
9043
|
+
const instanceName = getFlag(args, 'instance');
|
|
9044
|
+
if (instanceName) {
|
|
9045
|
+
const scope = normalizeScope(getFlag(args, 'scope'));
|
|
9046
|
+
const root = resolveInstallRoot(args, scope);
|
|
9047
|
+
const loaded = await loadInstanceEnv(root, instanceName);
|
|
9048
|
+
applyEnvMap(loaded.env);
|
|
9049
|
+
}
|
|
9050
|
+
else {
|
|
9051
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
9052
|
+
const explicitProjectEnv = getFlag(args, 'project-env');
|
|
9053
|
+
(0, runtimeEnv_1.loadRuntimeEnv)({
|
|
9054
|
+
cwd,
|
|
9055
|
+
projectEnvFile: explicitProjectEnv ? path_1.default.resolve(explicitProjectEnv) : undefined,
|
|
9056
|
+
});
|
|
9057
|
+
}
|
|
9058
|
+
const databaseUrl = process.env.DATABASE_URL?.trim();
|
|
9059
|
+
if (!databaseUrl) {
|
|
9060
|
+
throw cliError('IRANTI_DATABASE_URL_MISSING', 'DATABASE_URL is required. Run from a bound project, pass --instance <name>, or set DATABASE_URL.', ['Run `iranti project init . --instance <name>` to bind this project.']);
|
|
9061
|
+
}
|
|
9062
|
+
const noOpen = hasFlag(args, 'no-open');
|
|
9063
|
+
const port = getFlag(args, 'port') ?? '7500';
|
|
9064
|
+
const url = `http://localhost:${port}`;
|
|
9065
|
+
// npx handles both cases: uses the global install if available, downloads otherwise
|
|
9066
|
+
const npxExe = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
9067
|
+
console.log(`${infoLabel()} Starting Iranti control plane at ${url} …`);
|
|
9068
|
+
if (!noOpen) {
|
|
9069
|
+
// Give the server a moment to bind before opening the browser
|
|
9070
|
+
setTimeout(() => { openBrowserUrl(url); }, 2500);
|
|
9071
|
+
}
|
|
9072
|
+
await new Promise((resolve, reject) => {
|
|
9073
|
+
const child = (0, child_process_1.spawn)(npxExe, ['--yes', 'iranti-control-plane'], {
|
|
9074
|
+
stdio: 'inherit',
|
|
9075
|
+
env: {
|
|
9076
|
+
...process.env,
|
|
9077
|
+
DATABASE_URL: databaseUrl,
|
|
9078
|
+
PORT: port,
|
|
9079
|
+
},
|
|
9080
|
+
});
|
|
9081
|
+
const onSigint = () => { child.kill('SIGINT'); };
|
|
9082
|
+
process.once('SIGINT', onSigint);
|
|
9083
|
+
child.on('error', (err) => {
|
|
9084
|
+
process.off('SIGINT', onSigint);
|
|
9085
|
+
reject(cliError('IRANTI_CP_SPAWN_FAILED', `Failed to start iranti-control-plane: ${err.message}`, ['Ensure npx is available on PATH (it comes with npm).']));
|
|
9086
|
+
});
|
|
9087
|
+
child.on('exit', (code, signal) => {
|
|
9088
|
+
process.off('SIGINT', onSigint);
|
|
9089
|
+
if (signal === 'SIGINT' || signal === 'SIGTERM') {
|
|
9090
|
+
resolve();
|
|
9091
|
+
return;
|
|
9092
|
+
}
|
|
9093
|
+
if ((code ?? 0) !== 0) {
|
|
9094
|
+
process.exit(code ?? 1);
|
|
9095
|
+
}
|
|
9096
|
+
resolve();
|
|
9097
|
+
});
|
|
9098
|
+
});
|
|
9099
|
+
}
|
|
9012
9100
|
// ── Export / Import / Snapshot commands ─────────────────────────────────────
|
|
9013
9101
|
/** Marker file written at the end of every successful export (enables --since last). */
|
|
9014
9102
|
const EXPORT_MARKER_FILE = '.iranti-export-marker';
|
|
@@ -10147,6 +10235,14 @@ async function main() {
|
|
|
10147
10235
|
}
|
|
10148
10236
|
throw new Error(`Unknown integrate target '${args.subcommand ?? ''}'. Use 'claude', 'codex', or 'copilot'.`);
|
|
10149
10237
|
}
|
|
10238
|
+
if (args.command === 'ui') {
|
|
10239
|
+
if (hasFlag(args, 'help')) {
|
|
10240
|
+
printUiHelp();
|
|
10241
|
+
return;
|
|
10242
|
+
}
|
|
10243
|
+
await uiCommand(args);
|
|
10244
|
+
return;
|
|
10245
|
+
}
|
|
10150
10246
|
throw cliError('IRANTI_UNKNOWN_COMMAND', `Unknown command '${args.command}'. Run: iranti help`, ['Use `iranti help` to see the current command surface.'], { command: args.command });
|
|
10151
10247
|
}
|
|
10152
10248
|
main().then(async () => {
|
|
@@ -89,6 +89,10 @@ const WATCHER_EXCLUDE_DIRS = new Set([
|
|
|
89
89
|
'__pycache__', '.cache', '.iranti',
|
|
90
90
|
]);
|
|
91
91
|
const WRITE_DEBT_FILENAME = '.iranti-write-debt';
|
|
92
|
+
// Block attend only after this many unique file edits are pending — avoids
|
|
93
|
+
// false-positive blocks on single-file changes while still enforcing logging
|
|
94
|
+
// discipline when a meaningful batch of edits has accumulated.
|
|
95
|
+
const WRITE_DEBT_BLOCK_THRESHOLD = 5;
|
|
92
96
|
let _activeWatcher = null;
|
|
93
97
|
let _watchedCwd = null;
|
|
94
98
|
let _watchDebounceTimer = null;
|
|
@@ -453,7 +457,7 @@ function startFileWatcher(cwd) {
|
|
|
453
457
|
}
|
|
454
458
|
}
|
|
455
459
|
/**
|
|
456
|
-
* Read .iranti-write-debt and return an isError gate result when debt
|
|
460
|
+
* Read .iranti-write-debt and return an isError gate result when debt >= WRITE_DEBT_BLOCK_THRESHOLD.
|
|
457
461
|
* Returns null when attend should proceed normally.
|
|
458
462
|
*/
|
|
459
463
|
function checkWriteDebtForAttend(cwd) {
|
|
@@ -463,7 +467,7 @@ function checkWriteDebtForAttend(cwd) {
|
|
|
463
467
|
return null;
|
|
464
468
|
const debt = JSON.parse(node_fs_1.default.readFileSync(debtFile, 'utf8'));
|
|
465
469
|
const pendingEdits = debt.pendingEdits || 0;
|
|
466
|
-
if (pendingEdits <
|
|
470
|
+
if (pendingEdits < WRITE_DEBT_BLOCK_THRESHOLD)
|
|
467
471
|
return null;
|
|
468
472
|
const edits = debt.edits || [];
|
|
469
473
|
const fileList = edits.length > 0
|
|
@@ -473,12 +477,12 @@ function checkWriteDebtForAttend(cwd) {
|
|
|
473
477
|
content: [{
|
|
474
478
|
type: 'text',
|
|
475
479
|
text: [
|
|
476
|
-
`WRITE_GUARD_BLOCKED: ${pendingEdits} file edit(s) pending iranti_write.`,
|
|
480
|
+
`WRITE_GUARD_BLOCKED: ${pendingEdits} file edit(s) pending iranti_write (threshold: ${WRITE_DEBT_BLOCK_THRESHOLD}).`,
|
|
477
481
|
`Changed files (most recent ${Math.min(pendingEdits, 10)}):`,
|
|
478
482
|
fileList,
|
|
479
483
|
'',
|
|
480
484
|
`Required: call iranti_write for each changed file before iranti_attend can proceed.`,
|
|
481
|
-
`After writing
|
|
485
|
+
`After writing pending edits below the threshold, re-call iranti_attend to get your memory brief.`,
|
|
482
486
|
].join('\n'),
|
|
483
487
|
}],
|
|
484
488
|
isError: true,
|
|
@@ -801,7 +805,7 @@ async function main() {
|
|
|
801
805
|
// DB startup is deferred to first tool call via dbStartup() — see above.
|
|
802
806
|
const server = new mcp_js_1.McpServer({
|
|
803
807
|
name: 'iranti-mcp',
|
|
804
|
-
version: '0.3.
|
|
808
|
+
version: '0.3.41',
|
|
805
809
|
});
|
|
806
810
|
server.registerTool('iranti_handshake', {
|
|
807
811
|
description: `Initialize or refresh an agent's working-memory brief for the current task.
|
package/dist/scripts/setup.js
CHANGED
|
@@ -64,7 +64,8 @@ async function isSeeded() {
|
|
|
64
64
|
try {
|
|
65
65
|
const entry = await (0, client_1.getDb)().knowledgeEntry.findUnique({
|
|
66
66
|
where: {
|
|
67
|
-
|
|
67
|
+
userId_entityType_entityId_key: {
|
|
68
|
+
userId: 1,
|
|
68
69
|
entityType: 'system',
|
|
69
70
|
entityId: 'library',
|
|
70
71
|
key: 'initialization_log',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/api/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/api/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,OAAO,CAAC;QACd,UAAU,OAAO;YACb,UAAU,CAAC,EAAE,iBAAiB,CAAC;SAClC;KACJ;CACJ;AAmBD,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBjG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/api/middleware/auth.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/api/middleware/auth.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AAuCH,oCAmBC;AAvDD,oDAAwD;AAmBxD,SAAS,aAAa,CAAC,GAAY;IAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACzE,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/D,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACpE,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC9E,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAc,EAAC,WAAW,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,oDAAoD,EAAE,CAAC,CAAC;QACvH,OAAO;IACX,CAAC;IAED,GAAG,CAAC,UAAU,GAAG;QACb,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,UAAU;QAC/B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;QAChC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;QAChC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC;QAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,SAAS;KAC7C,CAAC;IAEF,IAAI,EAAE,CAAC;AACX,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../../src/api/routes/batch.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAEH,qCAAoD;AACpD,iDAA6C;AAEhC,QAAA,WAAW,GAAW,IAAA,gBAAM,GAAE,CAAC;AAE5C;;GAEG;AACH,mBAAW,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC1D,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,IAAqD,CAAC;QAE5E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,EAAE,GAAG,IAAA,cAAK,GAAE,CAAC;QAEnB,6CAA6C;QAC7C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACrB,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEhC,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;gBACxC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACxD,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC;oBAC7C,KAAK,EAAE;wBACL,
|
|
1
|
+
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../../src/api/routes/batch.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAEH,qCAAoD;AACpD,iDAA6C;AAEhC,QAAA,WAAW,GAAW,IAAA,gBAAM,GAAE,CAAC;AAE5C;;GAEG;AACH,mBAAW,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC1D,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,IAAqD,CAAC;QAE5E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,EAAE,GAAG,IAAA,cAAK,GAAE,CAAC;QAEnB,6CAA6C;QAC7C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACrB,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEhC,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;gBACxC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACxD,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC;oBAC7C,KAAK,EAAE;wBACL,8BAA8B,EAAE;4BAC9B,MAAM,EAAE,CAAC;4BACT,UAAU;4BACV,QAAQ;4BACR,GAAG,EAAE,EAAE,CAAC,GAAG;yBACZ;qBACF;iBACF,CAAC,CAAC;gBAEH,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;gBACxD,CAAC;gBACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;oBACpB,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;gBACxD,CAAC;gBAED,OAAO;oBACL,MAAM,EAAE,EAAE,CAAC,MAAM;oBACjB,GAAG,EAAE,EAAE,CAAC,GAAG;oBACX,GAAG,EAAE,IAAI;oBACT,KAAK,EAAE,GAAG,CAAC,QAAQ;oBACnB,OAAO,EAAE,GAAG,CAAC,YAAY;oBACzB,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACxD,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAC/F,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer MCP route — `/mcp/:token`
|
|
3
|
+
*
|
|
4
|
+
* Serves a simplified, user-scoped Model Context Protocol tool surface for
|
|
5
|
+
* Claude.ai, ChatGPT, and other MCP-compatible AI frontends.
|
|
6
|
+
*
|
|
7
|
+
* Authentication: the raw token is extracted from the URL path, hashed with
|
|
8
|
+
* SHA256+pepper, and looked up in the `tokens` table. A missing, revoked, or
|
|
9
|
+
* wrong-scope token returns 401 before any MCP handshake begins.
|
|
10
|
+
*
|
|
11
|
+
* Tool surface (scope mcp_consumer_t0):
|
|
12
|
+
* - iranti_remember — store a personal memory
|
|
13
|
+
* - iranti_recall — retrieve a personal memory
|
|
14
|
+
* - iranti_forget — delete a personal memory
|
|
15
|
+
*
|
|
16
|
+
* Transport: MCP Streamable HTTP (stateless — one transport per request).
|
|
17
|
+
* Supports both POST (tool calls) and GET (SSE event stream) on the same path,
|
|
18
|
+
* as required by the MCP spec.
|
|
19
|
+
*
|
|
20
|
+
* All reads and writes are scoped to the `userId` resolved from the token, so
|
|
21
|
+
* no cross-user data leakage is possible at the query layer.
|
|
22
|
+
*/
|
|
23
|
+
import { Router } from 'express';
|
|
24
|
+
export declare function consumerMcpRoutes(): Router;
|
|
25
|
+
//# sourceMappingURL=consumerMcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumerMcp.d.ts","sourceRoot":"","sources":["../../../../src/api/routes/consumerMcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAQpD,wBAAgB,iBAAiB,IAAI,MAAM,CA0K1C"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Consumer MCP route — `/mcp/:token`
|
|
4
|
+
*
|
|
5
|
+
* Serves a simplified, user-scoped Model Context Protocol tool surface for
|
|
6
|
+
* Claude.ai, ChatGPT, and other MCP-compatible AI frontends.
|
|
7
|
+
*
|
|
8
|
+
* Authentication: the raw token is extracted from the URL path, hashed with
|
|
9
|
+
* SHA256+pepper, and looked up in the `tokens` table. A missing, revoked, or
|
|
10
|
+
* wrong-scope token returns 401 before any MCP handshake begins.
|
|
11
|
+
*
|
|
12
|
+
* Tool surface (scope mcp_consumer_t0):
|
|
13
|
+
* - iranti_remember — store a personal memory
|
|
14
|
+
* - iranti_recall — retrieve a personal memory
|
|
15
|
+
* - iranti_forget — delete a personal memory
|
|
16
|
+
*
|
|
17
|
+
* Transport: MCP Streamable HTTP (stateless — one transport per request).
|
|
18
|
+
* Supports both POST (tool calls) and GET (SSE event stream) on the same path,
|
|
19
|
+
* as required by the MCP spec.
|
|
20
|
+
*
|
|
21
|
+
* All reads and writes are scoped to the `userId` resolved from the token, so
|
|
22
|
+
* no cross-user data leakage is possible at the query layer.
|
|
23
|
+
*/
|
|
24
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(o, k2, desc);
|
|
31
|
+
}) : (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
o[k2] = m[k];
|
|
34
|
+
}));
|
|
35
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
36
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
37
|
+
}) : function(o, v) {
|
|
38
|
+
o["default"] = v;
|
|
39
|
+
});
|
|
40
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
41
|
+
var ownKeys = function(o) {
|
|
42
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
43
|
+
var ar = [];
|
|
44
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
45
|
+
return ar;
|
|
46
|
+
};
|
|
47
|
+
return ownKeys(o);
|
|
48
|
+
};
|
|
49
|
+
return function (mod) {
|
|
50
|
+
if (mod && mod.__esModule) return mod;
|
|
51
|
+
var result = {};
|
|
52
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53
|
+
__setModuleDefault(result, mod);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
})();
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.consumerMcpRoutes = consumerMcpRoutes;
|
|
59
|
+
const express_1 = require("express");
|
|
60
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
61
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
62
|
+
const z = __importStar(require("zod/v4"));
|
|
63
|
+
const client_1 = require("../../library/client");
|
|
64
|
+
const apiKeys_1 = require("../../security/apiKeys");
|
|
65
|
+
function consumerMcpRoutes() {
|
|
66
|
+
const router = (0, express_1.Router)();
|
|
67
|
+
// Handle both GET (SSE) and POST (tool calls) on the same path
|
|
68
|
+
router.all('/:token', async (req, res) => {
|
|
69
|
+
const rawToken = Array.isArray(req.params['token']) ? req.params['token'][0] : req.params['token'];
|
|
70
|
+
if (!rawToken) {
|
|
71
|
+
res.status(401).json({ error: 'Missing token' });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const db = (0, client_1.getDb)();
|
|
75
|
+
// ── Token authentication ──────────────────────────────────────────────────
|
|
76
|
+
const tokenHash = (0, apiKeys_1.hashApiKeySecret)(rawToken);
|
|
77
|
+
const tokenRecord = await db.token.findUnique({ where: { tokenHash } });
|
|
78
|
+
if (!tokenRecord || tokenRecord.revokedAt !== null) {
|
|
79
|
+
res.status(401).json({ error: 'Invalid or revoked token' });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Consumer endpoint only serves mcp_consumer_* scopes
|
|
83
|
+
if (!tokenRecord.scope.startsWith('mcp_consumer')) {
|
|
84
|
+
res.status(403).json({ error: 'Token scope does not permit MCP consumer access' });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const userId = tokenRecord.userId;
|
|
88
|
+
// Fire-and-forget lastUsedAt update (non-blocking)
|
|
89
|
+
db.token.update({ where: { tokenHash }, data: { lastUsedAt: new Date() } }).catch(() => { });
|
|
90
|
+
// ── MCP server setup (stateless — one per request) ────────────────────────
|
|
91
|
+
const mcpServer = new mcp_js_1.McpServer({
|
|
92
|
+
name: 'iranti',
|
|
93
|
+
version: '1.0.0',
|
|
94
|
+
});
|
|
95
|
+
// iranti_remember — store a personal memory
|
|
96
|
+
mcpServer.tool('iranti_remember', 'Store a personal memory in your Iranti knowledge base.', {
|
|
97
|
+
entity: z.string().describe('Entity identifier. Use "person/me" for personal facts.'),
|
|
98
|
+
key: z.string().describe('Fact key — a stable identifier for this memory (e.g. "dietary_preference")'),
|
|
99
|
+
value: z.string().describe('The fact value to remember'),
|
|
100
|
+
summary: z.string().optional().describe('Short human-readable summary (auto-derived from value if omitted)'),
|
|
101
|
+
}, async ({ entity, key, value, summary }) => {
|
|
102
|
+
const [entityType, ...rest] = entity.split('/');
|
|
103
|
+
const entityId = rest.join('/') || 'me';
|
|
104
|
+
const valueSummary = summary ?? value.slice(0, 120);
|
|
105
|
+
const valueRaw = { text: value };
|
|
106
|
+
await db.knowledgeEntry.upsert({
|
|
107
|
+
where: {
|
|
108
|
+
userId_entityType_entityId_key: { userId, entityType, entityId, key },
|
|
109
|
+
},
|
|
110
|
+
update: {
|
|
111
|
+
valueRaw,
|
|
112
|
+
valueSummary,
|
|
113
|
+
source: `mcp_consumer`,
|
|
114
|
+
updatedAt: new Date(),
|
|
115
|
+
lastAccessedAt: new Date(),
|
|
116
|
+
},
|
|
117
|
+
create: {
|
|
118
|
+
userId,
|
|
119
|
+
entityType,
|
|
120
|
+
entityId,
|
|
121
|
+
key,
|
|
122
|
+
valueRaw,
|
|
123
|
+
valueSummary,
|
|
124
|
+
confidence: 80,
|
|
125
|
+
source: `mcp_consumer`,
|
|
126
|
+
createdBy: `user/${userId}`,
|
|
127
|
+
surface: tokenRecord.surface,
|
|
128
|
+
conflictLog: [],
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
content: [{ type: 'text', text: `Remembered: ${entity}/${key} = "${valueSummary}"` }],
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
// iranti_recall — retrieve a personal memory
|
|
136
|
+
mcpServer.tool('iranti_recall', 'Retrieve a personal memory from your Iranti knowledge base.', {
|
|
137
|
+
entity: z.string().describe('Entity identifier (e.g. "person/me")'),
|
|
138
|
+
key: z.string().describe('Fact key to retrieve'),
|
|
139
|
+
}, async ({ entity, key }) => {
|
|
140
|
+
const [entityType, ...rest] = entity.split('/');
|
|
141
|
+
const entityId = rest.join('/') || 'me';
|
|
142
|
+
const entry = await db.knowledgeEntry.findUnique({
|
|
143
|
+
where: {
|
|
144
|
+
userId_entityType_entityId_key: { userId, entityType, entityId, key },
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
if (!entry) {
|
|
148
|
+
return {
|
|
149
|
+
content: [{ type: 'text', text: `No memory found for ${entity}/${key}` }],
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// Update access timestamp
|
|
153
|
+
db.knowledgeEntry.update({
|
|
154
|
+
where: { userId_entityType_entityId_key: { userId, entityType, entityId, key } },
|
|
155
|
+
data: { lastAccessedAt: new Date() },
|
|
156
|
+
}).catch(() => { });
|
|
157
|
+
const valueText = typeof entry.valueRaw === 'string'
|
|
158
|
+
? entry.valueRaw
|
|
159
|
+
: entry.valueRaw?.text ?? JSON.stringify(entry.valueRaw);
|
|
160
|
+
return {
|
|
161
|
+
content: [{ type: 'text', text: `${entry.valueSummary}\n\n${valueText}` }],
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
// iranti_forget — delete a personal memory
|
|
165
|
+
mcpServer.tool('iranti_forget', 'Delete a personal memory from your Iranti knowledge base.', {
|
|
166
|
+
entity: z.string().describe('Entity identifier (e.g. "person/me")'),
|
|
167
|
+
key: z.string().describe('Fact key to forget'),
|
|
168
|
+
}, async ({ entity, key }) => {
|
|
169
|
+
const [entityType, ...rest] = entity.split('/');
|
|
170
|
+
const entityId = rest.join('/') || 'me';
|
|
171
|
+
const deleted = await db.knowledgeEntry.deleteMany({
|
|
172
|
+
where: { userId, entityType, entityId, key },
|
|
173
|
+
});
|
|
174
|
+
if (deleted.count === 0) {
|
|
175
|
+
return {
|
|
176
|
+
content: [{ type: 'text', text: `No memory found for ${entity}/${key} — nothing to forget.` }],
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
content: [{ type: 'text', text: `Forgotten: ${entity}/${key}` }],
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
// ── Stateless transport (one per request) ─────────────────────────────────
|
|
184
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
185
|
+
sessionIdGenerator: undefined, // stateless mode
|
|
186
|
+
});
|
|
187
|
+
try {
|
|
188
|
+
await mcpServer.connect(transport);
|
|
189
|
+
await transport.handleRequest(req, res, req.body);
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
await mcpServer.close();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return router;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=consumerMcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumerMcp.js","sourceRoot":"","sources":["../../../../src/api/routes/consumerMcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedback REST route for iranti (`/feedback`).
|
|
3
|
+
*
|
|
4
|
+
* Receives satisfaction signals submitted by the `iranti feedback` CLI command.
|
|
5
|
+
* Unauthenticated — CLI users do not hold API keys. Rate-limited by IP to
|
|
6
|
+
* discourage abuse. Idempotent on `feedbackId` (client UUID) via upsert, so
|
|
7
|
+
* the CLI offline-retry queue can safely replay submissions.
|
|
8
|
+
*
|
|
9
|
+
* POST /feedback — accept and persist a FeedbackPayload
|
|
10
|
+
*/
|
|
11
|
+
import { Router } from 'express';
|
|
12
|
+
export declare const feedbackRouter: Router;
|
|
13
|
+
//# sourceMappingURL=feedback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../../../src/api/routes/feedback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAIpD,eAAO,MAAM,cAAc,EAAE,MAAiB,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Feedback REST route for iranti (`/feedback`).
|
|
4
|
+
*
|
|
5
|
+
* Receives satisfaction signals submitted by the `iranti feedback` CLI command.
|
|
6
|
+
* Unauthenticated — CLI users do not hold API keys. Rate-limited by IP to
|
|
7
|
+
* discourage abuse. Idempotent on `feedbackId` (client UUID) via upsert, so
|
|
8
|
+
* the CLI offline-retry queue can safely replay submissions.
|
|
9
|
+
*
|
|
10
|
+
* POST /feedback — accept and persist a FeedbackPayload
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.feedbackRouter = void 0;
|
|
14
|
+
const express_1 = require("express");
|
|
15
|
+
const client_1 = require("../../library/client");
|
|
16
|
+
exports.feedbackRouter = (0, express_1.Router)();
|
|
17
|
+
// ── Validation helpers ────────────────────────────────────────────────────────
|
|
18
|
+
const VALID_TYPES = new Set(['bug', 'praise', 'suggestion', 'general']);
|
|
19
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20
|
+
function isValidUuid(v) {
|
|
21
|
+
return typeof v === 'string' && UUID_RE.test(v);
|
|
22
|
+
}
|
|
23
|
+
function isValidRating(v) {
|
|
24
|
+
return typeof v === 'number' && Number.isInteger(v) && v >= 1 && v <= 5;
|
|
25
|
+
}
|
|
26
|
+
function isValidType(v) {
|
|
27
|
+
return typeof v === 'string' && VALID_TYPES.has(v);
|
|
28
|
+
}
|
|
29
|
+
function isNonEmptyString(v) {
|
|
30
|
+
return typeof v === 'string' && v.trim().length > 0;
|
|
31
|
+
}
|
|
32
|
+
function isValidIsoDate(v) {
|
|
33
|
+
if (typeof v !== 'string')
|
|
34
|
+
return false;
|
|
35
|
+
const d = new Date(v);
|
|
36
|
+
return !isNaN(d.getTime());
|
|
37
|
+
}
|
|
38
|
+
// ── POST /feedback ────────────────────────────────────────────────────────────
|
|
39
|
+
exports.feedbackRouter.post('/', async (req, res) => {
|
|
40
|
+
const body = req.body ?? {};
|
|
41
|
+
// Required field validation
|
|
42
|
+
if (!isValidUuid(body.feedbackId)) {
|
|
43
|
+
return res.status(400).json({ error: 'feedbackId must be a valid UUID.' });
|
|
44
|
+
}
|
|
45
|
+
if (!isValidRating(body.rating)) {
|
|
46
|
+
return res.status(400).json({ error: 'rating must be an integer 1–5.' });
|
|
47
|
+
}
|
|
48
|
+
if (!isValidType(body.type)) {
|
|
49
|
+
return res.status(400).json({ error: 'type must be one of: bug, praise, suggestion, general.' });
|
|
50
|
+
}
|
|
51
|
+
if (!isNonEmptyString(body.version)) {
|
|
52
|
+
return res.status(400).json({ error: 'version is required.' });
|
|
53
|
+
}
|
|
54
|
+
if (!isNonEmptyString(body.instanceId)) {
|
|
55
|
+
return res.status(400).json({ error: 'instanceId is required.' });
|
|
56
|
+
}
|
|
57
|
+
if (!isValidIsoDate(body.submittedAt)) {
|
|
58
|
+
return res.status(400).json({ error: 'submittedAt must be a valid ISO 8601 date string.' });
|
|
59
|
+
}
|
|
60
|
+
// Optional field normalisation
|
|
61
|
+
const comment = typeof body.comment === 'string' && body.comment.trim().length > 0
|
|
62
|
+
? body.comment.trim().slice(0, 2000) // cap at 2000 chars
|
|
63
|
+
: null;
|
|
64
|
+
const os = isNonEmptyString(body.os) ? String(body.os).slice(0, 64) : 'unknown';
|
|
65
|
+
const arch = isNonEmptyString(body.arch) ? String(body.arch).slice(0, 32) : 'unknown';
|
|
66
|
+
const nodeVersion = isNonEmptyString(body.nodeVersion) ? String(body.nodeVersion).slice(0, 32) : 'unknown';
|
|
67
|
+
const sessionCount = typeof body.sessionCount === 'number' && Number.isFinite(body.sessionCount)
|
|
68
|
+
? Math.max(0, Math.floor(body.sessionCount))
|
|
69
|
+
: null;
|
|
70
|
+
const factCount = typeof body.factCount === 'number' && Number.isFinite(body.factCount)
|
|
71
|
+
? Math.max(0, Math.floor(body.factCount))
|
|
72
|
+
: null;
|
|
73
|
+
const milestoneContext = typeof body.milestoneContext === 'string' && body.milestoneContext.trim().length > 0
|
|
74
|
+
? body.milestoneContext.trim().slice(0, 256)
|
|
75
|
+
: null;
|
|
76
|
+
try {
|
|
77
|
+
const db = (0, client_1.getDb)();
|
|
78
|
+
// Upsert on feedbackId — safe for the CLI offline-retry queue.
|
|
79
|
+
// On conflict, update mutable fields only (comment, receivedAt) so
|
|
80
|
+
// repeated drain attempts don't corrupt the original submission data.
|
|
81
|
+
await db.feedback.upsert({
|
|
82
|
+
where: { feedbackId: body.feedbackId },
|
|
83
|
+
create: {
|
|
84
|
+
feedbackId: body.feedbackId,
|
|
85
|
+
rating: body.rating,
|
|
86
|
+
comment,
|
|
87
|
+
type: body.type,
|
|
88
|
+
version: String(body.version).slice(0, 32),
|
|
89
|
+
os,
|
|
90
|
+
arch,
|
|
91
|
+
nodeVersion,
|
|
92
|
+
sessionCount,
|
|
93
|
+
factCount,
|
|
94
|
+
instanceId: String(body.instanceId).slice(0, 64),
|
|
95
|
+
milestoneContext,
|
|
96
|
+
submittedAt: new Date(body.submittedAt),
|
|
97
|
+
},
|
|
98
|
+
update: {
|
|
99
|
+
// Allow comment update in case first attempt sent null
|
|
100
|
+
comment,
|
|
101
|
+
receivedAt: new Date(),
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
res.status(200).json({ ok: true });
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.error('[feedback] insert error:', err);
|
|
108
|
+
res.status(500).json({ error: 'Failed to record feedback.' });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../../../src/api/routes/feedback.ts"],"names":[],"mappings":"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"}
|