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.
Files changed (109) hide show
  1. package/dist/scripts/iranti-cli.js +100 -4
  2. package/dist/scripts/iranti-mcp.js +9 -5
  3. package/dist/scripts/setup.js +2 -1
  4. package/dist/src/api/middleware/auth.d.ts +2 -0
  5. package/dist/src/api/middleware/auth.d.ts.map +1 -1
  6. package/dist/src/api/middleware/auth.js +2 -0
  7. package/dist/src/api/middleware/auth.js.map +1 -1
  8. package/dist/src/api/routes/batch.js +2 -1
  9. package/dist/src/api/routes/batch.js.map +1 -1
  10. package/dist/src/api/routes/consumerMcp.d.ts +25 -0
  11. package/dist/src/api/routes/consumerMcp.d.ts.map +1 -0
  12. package/dist/src/api/routes/consumerMcp.js +197 -0
  13. package/dist/src/api/routes/consumerMcp.js.map +1 -0
  14. package/dist/src/api/routes/feedback.d.ts +13 -0
  15. package/dist/src/api/routes/feedback.d.ts.map +1 -0
  16. package/dist/src/api/routes/feedback.js +111 -0
  17. package/dist/src/api/routes/feedback.js.map +1 -0
  18. package/dist/src/api/routes/knowledge.d.ts.map +1 -1
  19. package/dist/src/api/routes/knowledge.js +9 -5
  20. package/dist/src/api/routes/knowledge.js.map +1 -1
  21. package/dist/src/api/routes/memory.d.ts.map +1 -1
  22. package/dist/src/api/routes/memory.js +2 -1
  23. package/dist/src/api/routes/memory.js.map +1 -1
  24. package/dist/src/api/routes/tokens.d.ts +18 -0
  25. package/dist/src/api/routes/tokens.d.ts.map +1 -0
  26. package/dist/src/api/routes/tokens.js +89 -0
  27. package/dist/src/api/routes/tokens.js.map +1 -0
  28. package/dist/src/api/server.js +24 -1
  29. package/dist/src/api/server.js.map +1 -1
  30. package/dist/src/attendant/AttendantInstance.d.ts +19 -0
  31. package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
  32. package/dist/src/attendant/AttendantInstance.js +243 -4
  33. package/dist/src/attendant/AttendantInstance.js.map +1 -1
  34. package/dist/src/generated/prisma/browser.d.ts +15 -0
  35. package/dist/src/generated/prisma/browser.d.ts.map +1 -1
  36. package/dist/src/generated/prisma/client.d.ts +17 -2
  37. package/dist/src/generated/prisma/client.d.ts.map +1 -1
  38. package/dist/src/generated/prisma/client.js +2 -2
  39. package/dist/src/generated/prisma/commonInputTypes.d.ts +363 -243
  40. package/dist/src/generated/prisma/commonInputTypes.d.ts.map +1 -1
  41. package/dist/src/generated/prisma/enums.d.ts +24 -0
  42. package/dist/src/generated/prisma/enums.d.ts.map +1 -1
  43. package/dist/src/generated/prisma/enums.js +22 -1
  44. package/dist/src/generated/prisma/enums.js.map +1 -1
  45. package/dist/src/generated/prisma/internal/class.d.ts +40 -7
  46. package/dist/src/generated/prisma/internal/class.d.ts.map +1 -1
  47. package/dist/src/generated/prisma/internal/class.js +4 -4
  48. package/dist/src/generated/prisma/internal/class.js.map +1 -1
  49. package/dist/src/generated/prisma/internal/prismaNamespace.d.ts +304 -14
  50. package/dist/src/generated/prisma/internal/prismaNamespace.d.ts.map +1 -1
  51. package/dist/src/generated/prisma/internal/prismaNamespace.js +45 -7
  52. package/dist/src/generated/prisma/internal/prismaNamespace.js.map +1 -1
  53. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts +46 -5
  54. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -1
  55. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js +45 -7
  56. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -1
  57. package/dist/src/generated/prisma/models/Archive.d.ts +0 -10
  58. package/dist/src/generated/prisma/models/Archive.d.ts.map +1 -1
  59. package/dist/src/generated/prisma/models/Feedback.d.ts +1328 -0
  60. package/dist/src/generated/prisma/models/Feedback.d.ts.map +1 -0
  61. package/dist/src/generated/prisma/models/Feedback.js +3 -0
  62. package/dist/src/generated/prisma/models/Feedback.js.map +1 -0
  63. package/dist/src/generated/prisma/models/KnowledgeEntry.d.ts +349 -17
  64. package/dist/src/generated/prisma/models/KnowledgeEntry.d.ts.map +1 -1
  65. package/dist/src/generated/prisma/models/Token.d.ts +1329 -0
  66. package/dist/src/generated/prisma/models/Token.d.ts.map +1 -0
  67. package/dist/src/generated/prisma/models/Token.js +3 -0
  68. package/dist/src/generated/prisma/models/Token.js.map +1 -0
  69. package/dist/src/generated/prisma/models/User.d.ts +1545 -0
  70. package/dist/src/generated/prisma/models/User.d.ts.map +1 -0
  71. package/dist/src/generated/prisma/models/User.js +3 -0
  72. package/dist/src/generated/prisma/models/User.js.map +1 -0
  73. package/dist/src/generated/prisma/models.d.ts +3 -0
  74. package/dist/src/generated/prisma/models.d.ts.map +1 -1
  75. package/dist/src/lib/cliHelpCatalog.d.ts.map +1 -1
  76. package/dist/src/lib/cliHelpCatalog.js +6 -0
  77. package/dist/src/lib/cliHelpCatalog.js.map +1 -1
  78. package/dist/src/lib/cliHelpRenderer.d.ts +1 -0
  79. package/dist/src/lib/cliHelpRenderer.d.ts.map +1 -1
  80. package/dist/src/lib/cliHelpRenderer.js +4 -0
  81. package/dist/src/lib/cliHelpRenderer.js.map +1 -1
  82. package/dist/src/lib/feedbackCollector.d.ts.map +1 -1
  83. package/dist/src/lib/feedbackCollector.js +48 -1
  84. package/dist/src/lib/feedbackCollector.js.map +1 -1
  85. package/dist/src/librarian/source-reliability.d.ts.map +1 -1
  86. package/dist/src/librarian/source-reliability.js +4 -2
  87. package/dist/src/librarian/source-reliability.js.map +1 -1
  88. package/dist/src/library/agent-registry.d.ts.map +1 -1
  89. package/dist/src/library/agent-registry.js +12 -6
  90. package/dist/src/library/agent-registry.js.map +1 -1
  91. package/dist/src/library/queries.d.ts.map +1 -1
  92. package/dist/src/library/queries.js +4 -2
  93. package/dist/src/library/queries.js.map +1 -1
  94. package/dist/src/sdk/index.d.ts +1 -0
  95. package/dist/src/sdk/index.d.ts.map +1 -1
  96. package/dist/src/sdk/index.js +1 -1
  97. package/dist/src/sdk/index.js.map +1 -1
  98. package/dist/src/security/apiKeys.d.ts +2 -0
  99. package/dist/src/security/apiKeys.d.ts.map +1 -1
  100. package/dist/src/security/apiKeys.js +8 -4
  101. package/dist/src/security/apiKeys.js.map +1 -1
  102. package/dist/src/security/consumerTokens.d.ts +52 -0
  103. package/dist/src/security/consumerTokens.d.ts.map +1 -0
  104. package/dist/src/security/consumerTokens.js +98 -0
  105. package/dist/src/security/consumerTokens.js.map +1 -0
  106. package/package.json +1 -1
  107. package/prisma/migrations/20260414191958_add_multi_tenant_identity/migration.sql +106 -0
  108. package/prisma/migrations/20260415030000_add_feedback_table/migration.sql +35 -0
  109. 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
- if (pendingEdits < 1) {
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) since last iranti_write (last edit: \${lastEditAt || 'unknown'}). Call iranti_write for each pending edit before making new changes.\`,
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
- 'Before making any more edits, you MUST call iranti_write for each pending edit.',
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 all pending edits, this guard will allow new edits.',
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 > 0.
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 < 1)
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 all pending edits, re-call iranti_attend to get your memory brief.`,
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.40',
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.
@@ -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
- entityType_entityId_key: {
67
+ userId_entityType_entityId_key: {
68
+ userId: 1,
68
69
  entityType: 'system',
69
70
  entityId: 'library',
70
71
  key: 'initialization_log',
@@ -19,6 +19,8 @@ export interface IrantiAuthContext {
19
19
  keyId: string;
20
20
  owner: string;
21
21
  scopes: string[];
22
+ userId: number;
23
+ tokenScope: string;
22
24
  }
23
25
  declare global {
24
26
  namespace Express {
@@ -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;CACpB;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,CAiBjG"}
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"}
@@ -45,6 +45,8 @@ async function authenticate(req, res, next) {
45
45
  keyId: result.keyId ?? 'unknown',
46
46
  owner: result.owner ?? 'unknown',
47
47
  scopes: result.scopes ?? ['*'],
48
+ userId: result.userId ?? 1,
49
+ tokenScope: result.tokenScope ?? 'dev_cli',
48
50
  };
49
51
  next();
50
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/api/middleware/auth.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AAqCH,oCAiBC;AAnDD,oDAAwD;AAiBxD,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;KACjC,CAAC;IAEF,IAAI,EAAE,CAAC;AACX,CAAC"}
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"}
@@ -39,7 +39,8 @@ exports.batchRouter.post("/", async (req, res) => {
39
39
  try {
40
40
  const row = await db.knowledgeEntry.findUnique({
41
41
  where: {
42
- entityType_entityId_key: {
42
+ userId_entityType_entityId_key: {
43
+ userId: 1,
43
44
  entityType,
44
45
  entityId,
45
46
  key: it.key,
@@ -1 +1 @@
1
- {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../../src/api/routes/batch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../../src/api/routes/batch.ts"],"names":[],"mappings":"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"}
@@ -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":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUH,8CA0KC;AAlLD,qCAAoD;AACpD,oEAAoE;AACpE,0FAAmG;AACnG,0CAA4B;AAC5B,iDAA6C;AAC7C,oDAA0D;AAG1D,SAAgB,iBAAiB;IAC/B,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;IAExB,+DAA+D;IAC/D,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAiB,EAAE;QACzE,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,MAAM,EAAE,GAAG,IAAA,cAAK,GAAE,CAAC;QAEnB,6EAA6E;QAC7E,MAAM,SAAS,GAAG,IAAA,0BAAgB,EAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAExE,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YACnD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QAED,sDAAsD;QACtD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YAClD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iDAAiD,EAAE,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;QAElC,mDAAmD;QACnD,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE5F,6EAA6E;QAC7E,MAAM,SAAS,GAAG,IAAI,kBAAS,CAAC;YAC9B,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC;QAEH,4CAA4C;QAC5C,SAAS,CAAC,IAAI,CACZ,iBAAiB,EACjB,wDAAwD,EACxD;YACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;YACrF,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;YACtG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;YACxD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;SAC7G,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;YACxC,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;YAExC,MAAM,YAAY,GAAG,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACpD,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,KAAK,EAAkC,CAAC;YAEjE,MAAM,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC;gBAC7B,KAAK,EAAE;oBACL,8BAA8B,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE;iBACtE;gBACD,MAAM,EAAE;oBACN,QAAQ;oBACR,YAAY;oBACZ,MAAM,EAAE,cAAc;oBACtB,SAAS,EAAE,IAAI,IAAI,EAAE;oBACrB,cAAc,EAAE,IAAI,IAAI,EAAE;iBAC3B;gBACD,MAAM,EAAE;oBACN,MAAM;oBACN,UAAU;oBACV,QAAQ;oBACR,GAAG;oBACH,QAAQ;oBACR,YAAY;oBACZ,UAAU,EAAE,EAAE;oBACd,MAAM,EAAE,cAAc;oBACtB,SAAS,EAAE,QAAQ,MAAM,EAAE;oBAC3B,OAAO,EAAE,WAAW,CAAC,OAAO;oBAC5B,WAAW,EAAE,EAAE;iBAChB;aACF,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,eAAe,MAAM,IAAI,GAAG,OAAO,YAAY,GAAG,EAAE,CAAC;aAC/F,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,6CAA6C;QAC7C,SAAS,CAAC,IAAI,CACZ,eAAe,EACf,6DAA6D,EAC7D;YACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACnE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;SACjD,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE;YACxB,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;YAExC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC;gBAC/C,KAAK,EAAE;oBACL,8BAA8B,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE;iBACtE;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,uBAAuB,MAAM,IAAI,GAAG,EAAE,EAAE,CAAC;iBACnF,CAAC;YACJ,CAAC;YAED,0BAA0B;YAC1B,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC;gBACvB,KAAK,EAAE,EAAE,8BAA8B,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE;gBAChF,IAAI,EAAE,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,EAAE;aACrC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAEnB,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;gBAClD,CAAC,CAAC,KAAK,CAAC,QAAQ;gBAChB,CAAC,CAAE,KAAK,CAAC,QAA8B,EAAE,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAElF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,YAAY,OAAO,SAAS,EAAE,EAAE,CAAC;aACpF,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,2CAA2C;QAC3C,SAAS,CAAC,IAAI,CACZ,eAAe,EACf,2DAA2D,EAC3D;YACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACnE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;SAC/C,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE;YACxB,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;YAExC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC;gBACjD,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE;aAC7C,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,uBAAuB,MAAM,IAAI,GAAG,uBAAuB,EAAE,CAAC;iBACxG,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,MAAM,IAAI,GAAG,EAAE,EAAE,CAAC;aAC1E,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,6EAA6E;QAC7E,MAAM,SAAS,GAAG,IAAI,iDAA6B,CAAC;YAClD,kBAAkB,EAAE,SAAS,EAAE,iBAAiB;SACjD,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACpD,CAAC;gBAAS,CAAC;YACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -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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"}