mcp-scraper 0.28.3 → 0.29.1

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/README.md CHANGED
@@ -88,7 +88,7 @@ Build the branded one-click bundle:
88
88
  npm run build:mcpb
89
89
  ```
90
90
 
91
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.28.3`, SHA-256 `81df6a65eec545f0b7f45e63d7ddd4214b96c551a55cc3341402eadd1c4ad038`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
91
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.29.1`, SHA-256 `837b6d05ce5bd0d7f104616d4781c3b33216bd4901887995e62a8e456c2b8804`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
92
92
 
93
93
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
94
94
 
@@ -29723,7 +29723,7 @@ var PACKAGE_VERSION;
29723
29723
  var init_version = __esm({
29724
29724
  "src/version.ts"() {
29725
29725
  "use strict";
29726
- PACKAGE_VERSION = "0.28.3";
29726
+ PACKAGE_VERSION = "0.29.1";
29727
29727
  }
29728
29728
  });
29729
29729
 
@@ -29845,12 +29845,14 @@ Multi-step orchestrations \u2014 prefer these over hand-chaining primitives when
29845
29845
 
29846
29846
  ## Memory
29847
29847
  mcp-scraper also exposes persistent per-user memory tools (notes, facts, vaults,
29848
- scheduled actions, tables, channels) backed by memory.mcpscraper.dev. Every account starts with 14
29848
+ scheduled actions, tables, channels) backed by memory.mcpscraper.dev. Every account starts with 15
29849
29849
  vaults \u2014 call **list-vaults** to see what exists before creating anything new. Pick the vault whose job
29850
29850
  matches the content: **Ideas** (unvalidated concepts), **Knowledge** (distilled lessons/how-tos),
29851
29851
  **Library** (raw source material \u2014 articles, transcripts), **People** (one durable note per person/org),
29852
- **Communications** (individual conversation records), **Calendar** (time-anchored entries), **Tasks**
29853
- (action items with a status), **Projects** (durable named initiatives), **Issues** (something broken),
29852
+ **Deals** (commercial opportunities tied to a known person or organization), **Communications** (individual
29853
+ conversation records and drafts), **Calendar** (time-anchored entries), **Tasks** (independent Inbox action items
29854
+ that may link to a known Project), **Projects** (only codebases, known client projects, personal projects, or ongoing siloed
29855
+ workstreams), **Issues** (something broken),
29854
29856
  **Improvement Log** (receipts of changes made and whether they worked), **Experiments** (hypothesis +
29855
29857
  measured result), **Sprint** (current cycle's scope), **Inspiration** (other people's work worth
29856
29858
  studying), **Skills** (reusable skill packages; each requires \`scripts/\` and at least one of
@@ -29864,6 +29866,19 @@ deliberate edits and migrations. Use
29864
29866
  they'll filter/sort by exact value. **memory-search** is meaning-based over full content (embeds, slower);
29865
29867
  **memory-list** filters one vault by kind/tags (fast, exact).
29866
29868
 
29869
+ For People, Deals, Projects, Tasks, and Communications, use the returned contract rather than guessing:
29870
+ People only holds a real person or organization hub. Its contact card uses \`phone\`, \`text_phone\`, and
29871
+ \`email\` for Call/Text/Email; \`memories\` for durable person context; and linked Deals, Projects,
29872
+ Communications, and Calendar records for the other sections. Deals need a known party; Projects need
29873
+ \`project_kind\`; Tasks can be independent Inbox todos or link a verified \`project_ref\` and matching
29874
+ project name; and email drafts awaiting human review need \`direction:"draft"\` with
29875
+ \`approval_state:"pending"\`. Link a known person, project, deal, or communication only when verified.
29876
+ When the user asks to add Gmail or Google Calendar evidence from a connected account, first resolve the
29877
+ existing People hub. Persist Gmail as one linked **Communications** email and Calendar as one linked
29878
+ **Calendar** event, each with the provider's stable reference and \`person_refs\`; do not create a person
29879
+ from a subject line, infer attendees, or silently bulk-import a mailbox/calendar. If a relationship is requested but not clear, ask the user rather than inventing one. Overview is the review queue: editing leaves a draft pending, and
29880
+ approval or denial records a state only\u2014it does not send email.
29881
+
29867
29882
  Treat every memory create or update as a graph operation. **prepare-memory-write** supplies the initial
29868
29883
  shortlist; use **memory-search** when it is weak or the topic is broad, and **memory-get** to read the best
29869
29884
  candidates in full. Add only links supported by the notes: same-
@@ -32316,7 +32331,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
32316
32331
  }, async (input) => buildMetaAdCreativeMediaResult(executor, input));
32317
32332
  server.registerTool("import_service_connection_to_memory", {
32318
32333
  title: "Import Connected Service Snapshot to Memory",
32319
- description: "Run exactly one bounded, approved read on a tenant-owned connected service and upsert the redacted result into an existing ordinary Memory vault at a server-generated stable path. The saved document is embedded for RAG and marked as untrusted provider data, never instructions. This is a one-result snapshot: it does not paginate, bulk-import an account, continuously sync changes, propagate deletions, or create normalized tables. Use list_service_connections first and supply an exact current readTools entry; action and admin tools are rejected.",
32334
+ description: "Run exactly one bounded, approved read on a tenant-owned connected service and upsert the redacted result into an existing ordinary Memory vault at a server-generated stable path. The saved document is embedded for RAG and marked as untrusted provider data, never instructions. This is a one-result snapshot: it does not paginate, bulk-import an account, continuously sync changes, propagate deletions, or create normalized tables. It is not a People contact-card activity importer: when the user asks to add verified Gmail or Calendar activity to a person, resolve the People hub and create a linked Communications or Calendar record with stable provider references instead. Use list_service_connections first and supply an exact current readTools entry; action and admin tools are rejected.",
32320
32335
  inputSchema: ImportServiceConnectionToMemoryInputSchema,
32321
32336
  outputSchema: recordOutputSchema("import_service_connection_to_memory", ImportServiceConnectionToMemoryOutputSchema),
32322
32337
  annotations: { title: "Import Connected Service Snapshot to Memory", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }
@@ -34939,7 +34954,7 @@ var init_memory_tool_schemas = __esm({
34939
34954
  MemoryCaptureSchema = {
34940
34955
  id: "memory-capture",
34941
34956
  upstreamName: "memoryCaptureTool",
34942
- description: "Strict normal-create path for durable memory. Before capture, list the complete tag vocabulary, call prepare-memory-write, run hybrid memory-search for related notes, and read the strongest link candidates. This tool refuses incomplete notes, writes through memory-put, registers canonical tags, and verifies persisted content and props. Reserve memory-put for low-level migrations or deliberate edits.",
34957
+ description: "Strict normal-create path for durable memory. Before capture, list the complete tag vocabulary, call prepare-memory-write, run hybrid memory-search for related notes, and read the strongest link candidates. This tool refuses incomplete notes and invalid relationship-domain writes: projects need a project kind, tasks can be independent Inbox todos or link a verified project, deals need a known party, and draft emails need a pending approval state. It writes through memory-put, registers canonical tags, and verifies persisted content and props. Reserve memory-put for low-level migrations or deliberate edits.",
34943
34958
  input: {
34944
34959
  vault: import_zod37.z.string(),
34945
34960
  folder: import_zod37.z.string().optional(),
@@ -34997,7 +35012,7 @@ var init_memory_tool_schemas = __esm({
34997
35012
  PrepareMemoryWriteSchema = {
34998
35013
  id: "prepare-memory-write",
34999
35014
  upstreamName: "prepareMemoryWriteTool",
35000
- description: "Mandatory planning pass for a normal new memory. First inspect the complete tag vocabulary with list-memory-tags; then this pass routes the note, returns the live template and natural vault relationships, resolves proposed tags, and shortlists interlinks. Use hybrid memory-search (3 focused queries, 50 fused candidates, bounded graph expansion, rerank to 30 by default) and read strong related notes before capture. This is an explicit AI workflow directive, not a claim of persisted call-order enforcement.",
35015
+ description: "Mandatory planning pass for a normal new memory. First inspect the complete tag vocabulary with list-memory-tags; then this pass routes the note, returns the live template and natural vault relationships, resolves proposed tags, and shortlists interlinks. For People, Deals, Projects, Tasks, and Communications, it also returns relationship and approval guidance: a Task may be an independent Inbox todo, so search existing records only before adding a requested project or party link and never invent one. Use hybrid memory-search (3 focused queries, 50 fused candidates, bounded graph expansion, rerank to 30 by default) and read strong related notes before capture. This is an explicit AI workflow directive, not a claim of persisted call-order enforcement.",
35001
35016
  input: {
35002
35017
  title: import_zod37.z.string().min(1),
35003
35018
  content: import_zod37.z.string().min(1),
@@ -35704,10 +35719,10 @@ var init_memory_tool_schemas = __esm({
35704
35719
  PutSchema = {
35705
35720
  id: "memory-put",
35706
35721
  upstreamName: "putTool",
35707
- description: "Create or edit one note at a path in a memory vault; content is persisted and indexed for search. For row-shaped datasets you'll filter/sort by exact value, use table-create/table-insert-rows/table-query instead. Ordinary vaults are indexed and shareable \u2014 never store real secrets there; use a secure vault (create-secure-vault) instead, which is never indexed or shareable and is encrypted at rest. Requires write scope.",
35722
+ description: "Create or deliberately edit one note at a path in a memory vault; content is persisted and indexed for search. For normal new People, Deals, Projects, Tasks, or Communications records, use prepare-memory-write then memory-capture: People must be real people or organizations, Deals need a known party, Projects need a supported kind, Tasks may be independent Inbox todos or use a verified Project link when requested, and draft emails need pending approval. For row-shaped datasets you'll filter/sort by exact value, use table-create/table-insert-rows/table-query instead. Ordinary vaults are indexed and shareable \u2014 never store real secrets there; use a secure vault (create-secure-vault) instead, which is never indexed or shareable and is encrypted at rest. Requires write scope.",
35708
35723
  input: {
35709
35724
  vault: import_zod37.z.string().optional().describe(
35710
- "Vault to write to. Optional; defaults to the session active vault, then the first vault the caller is entitled to. On a default-provisioned account, pick the vault whose job matches the content (see the server instructions for the full 13-vault guide) rather than defaulting blindly \u2014 e.g. a lesson learned goes in Knowledge, the raw source it came from goes in Library, a broken feature goes in Issues, a named real-world initiative goes in Projects."
35725
+ "Vault to write to. Optional; defaults to the session active vault, then the first vault the caller is entitled to. On a default-provisioned account, pick the vault whose job matches the content (see the server instructions for the full 15-vault guide) rather than defaulting blindly \u2014 e.g. a lesson learned goes in Knowledge, the raw source it came from goes in Library, a broken feature goes in Issues, a named real-world initiative goes in Projects. Do not use this low-level tool to create ordinary People, Deals, Projects, Tasks, or Communications records: first use prepare-memory-write then memory-capture so relationships and approval state are validated."
35711
35726
  ),
35712
35727
  path: import_zod37.z.string().optional().describe("Vault-relative note path to create or overwrite, e.g. projects/q3-plan. Writing an existing path replaces it. Required unless shareId is given."),
35713
35728
  shareId: import_zod37.z.string().optional().describe("Edit a note someone individually shared with you and you accepted (accept-share), by its shareId, instead of vault+path. Requires the share to grant edit permission, and baseRevision is mandatory (get the current revision first) since you are editing alongside the owner and possibly others."),
@@ -36494,9 +36509,9 @@ var init_memory_tool_schemas = __esm({
36494
36509
  GetVaultContractSchema = {
36495
36510
  id: "get-vault-contract",
36496
36511
  upstreamName: "getVaultContractTool",
36497
- description: "Read the machine-enforced purpose, template, statuses, types, natural neighbor vaults, and typed relationship guidance for one of the 13 governed Obsidian-style vaults. Call before composing a note when the correct shape is uncertain.",
36512
+ description: "Read the machine-enforced purpose, template, statuses, types, natural neighbor vaults, and typed relationship guidance for one of the 15 governed Obsidian-style vaults. Call before composing a note when the correct shape is uncertain.",
36498
36513
  input: {
36499
- vault: import_zod37.z.string().describe("One governed vault: Ideas, Inspiration, Knowledge, Library, People, Communications, Calendar, Tasks, Projects, Issues, Improvement Log, Experiments, or Sprint.")
36514
+ vault: import_zod37.z.string().describe("One governed vault: Ideas, Inspiration, Knowledge, Library, People, Deals, Communications, Calendar, Tasks, Projects, Issues, Improvement Log, Experiments, Sprint, or Skills.")
36500
36515
  },
36501
36516
  output: {
36502
36517
  ok: import_zod37.z.boolean(),
@@ -36566,17 +36581,17 @@ var init_memory_tool_schemas = __esm({
36566
36581
  ProvisionDefaultsSchema = {
36567
36582
  id: "provision-defaults",
36568
36583
  upstreamName: "provisionDefaultsTool",
36569
- description: "Provision the standard 14-vault memory structure (Ideas, Inspiration, Knowledge, Library, People, Communications, Calendar, Tasks, Projects, Issues, Improvement Log, Experiments, Sprint, Skills) for an identity. Idempotent \u2014 existing vaults are untouched. Optionally issues a fresh API key entitled to all 14. Requires admin scope.",
36584
+ description: "Provision the standard 15-vault memory structure (Ideas, Inspiration, Knowledge, Library, People, Deals, Communications, Calendar, Tasks, Projects, Issues, Improvement Log, Experiments, Sprint, Skills) for an identity. Idempotent \u2014 existing records are untouched and existing vault contracts are refreshed. Optionally issues a fresh API key entitled to all 15. Requires admin scope.",
36570
36585
  input: {
36571
- granteeIdentity: import_zod37.z.string().min(1).describe("Identity that should OWN the 14 default vaults (e.g. an email or user id)."),
36572
- issueKey: import_zod37.z.boolean().optional().describe("When true, also issue a new API key for the identity entitled to all 14 vaults and return its secret once. Default false."),
36586
+ granteeIdentity: import_zod37.z.string().min(1).describe("Identity that should OWN the 15 default vaults (e.g. an email or user id)."),
36587
+ issueKey: import_zod37.z.boolean().optional().describe("When true, also issue a new API key for the identity entitled to all 15 vaults and return its secret once. Default false."),
36573
36588
  plan: import_zod37.z.enum(["free", "pro", "team", "enterprise"]).optional().describe("Subscription plan carried by the issued key. Optional; defaults to free. Only used when issueKey is true.")
36574
36589
  },
36575
36590
  output: {
36576
36591
  ok: import_zod37.z.boolean().describe("True when provisioning succeeded; false on auth/scope error."),
36577
36592
  identity: import_zod37.z.string().optional().describe("Identity the vaults were provisioned for."),
36578
- created: import_zod37.z.array(import_zod37.z.string()).optional().describe("Vault names newly created on this call (empty when all 14 already existed)."),
36579
- vaults: import_zod37.z.array(import_zod37.z.string()).optional().describe("All 14 default vault names the identity now owns."),
36593
+ created: import_zod37.z.array(import_zod37.z.string()).optional().describe("Vault names newly created on this call (empty when all 15 already existed)."),
36594
+ vaults: import_zod37.z.array(import_zod37.z.string()).optional().describe("All 15 default vault names the identity now owns."),
36580
36595
  keyId: import_zod37.z.string().optional().describe("Stable id of the issued key. Present only when issueKey was true."),
36581
36596
  secret: import_zod37.z.string().optional().describe("The issued key secret \u2014 RETURNED ONCE. Present only when issueKey was true."),
36582
36597
  plan: import_zod37.z.string().optional().describe("Plan assigned to the issued key. Present only when issueKey was true."),
@@ -41218,16 +41233,55 @@ function workspaceRecord(vault, note) {
41218
41233
  }
41219
41234
  function defaultType(vault) {
41220
41235
  if (vault === "People" || vault === "Communications") return "unclassified";
41236
+ if (vault === "Deals") return "deal";
41221
41237
  if (vault === "Projects") return "project";
41222
41238
  if (vault === "Tasks") return "task";
41239
+ if (vault === "Calendar") return "event";
41223
41240
  return "unclassified";
41224
41241
  }
41225
41242
  function defaultStatus(vault) {
41226
41243
  if (vault === "People") return "active";
41244
+ if (vault === "Deals") return "lead";
41227
41245
  if (vault === "Projects") return "active";
41228
41246
  if (vault === "Tasks") return "to_do";
41247
+ if (vault === "Calendar") return "scheduled";
41229
41248
  return "inbox";
41230
41249
  }
41250
+ function nonEmptyStrings(value) {
41251
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
41252
+ }
41253
+ function validateNewRecord(vault, props) {
41254
+ const type = typeof props.type === "string" ? props.type : "";
41255
+ if (vault === "People" && !["person", "organization"].includes(type)) return "People records must be a person or organization";
41256
+ if (vault === "Deals") {
41257
+ if (type !== "deal") return "Deals records must have type deal";
41258
+ if (typeof props.organization_ref !== "string" && nonEmptyStrings(props.person_refs).length === 0) {
41259
+ return "Deals require a known organization or person";
41260
+ }
41261
+ }
41262
+ if (vault === "Projects") {
41263
+ if (!["project", "vault_settings"].includes(type)) return "Projects records must have type project";
41264
+ if (type === "project" && !["codebase", "client", "personal", "workstream"].includes(String(props.project_kind ?? ""))) {
41265
+ return "Projects require project_kind: codebase, client, personal, or workstream";
41266
+ }
41267
+ }
41268
+ if (vault === "Tasks") {
41269
+ if (!["task", "milestone"].includes(type)) return "Tasks records must have type task or milestone";
41270
+ const hasProjectRef = typeof props.project_ref === "string" && props.project_ref.trim().length > 0;
41271
+ const hasProjectTitle = typeof props.project === "string" && props.project.trim().length > 0;
41272
+ if (hasProjectRef !== hasProjectTitle) return "Tasks project_ref and project must be supplied together when a task is linked to a project";
41273
+ }
41274
+ if (vault === "Communications") {
41275
+ if (!["email", "slack", "message", "call", "meeting", "social_media", "thread", "decision"].includes(type)) return "Communications records need a valid communication type";
41276
+ if (!["none", "needs_reply", "needs_review", "waiting"].includes(String(props.attention_state ?? ""))) {
41277
+ return "Communications require attention_state: none, needs_reply, needs_review, or waiting";
41278
+ }
41279
+ if (type === "email" && props.direction === "draft" && props.approval_state !== "pending") {
41280
+ return "Email drafts awaiting review must have approval_state pending";
41281
+ }
41282
+ }
41283
+ return null;
41284
+ }
41231
41285
  function shouldRetryMemoryRead(error) {
41232
41286
  return /deadlock|timeout|timed out|temporar|econnreset|fetch failed/i.test(error ?? "");
41233
41287
  }
@@ -41274,7 +41328,7 @@ var init_vault_routes = __esm({
41274
41328
  "use strict";
41275
41329
  import_hono22 = require("hono");
41276
41330
  init_memory();
41277
- VAULTS = ["People", "Projects", "Tasks", "Communications"];
41331
+ VAULTS = ["People", "Deals", "Projects", "Tasks", "Communications", "Calendar"];
41278
41332
  MAX_VAULT_RECORDS = 200;
41279
41333
  MAX_MEMORY_READ_CONCURRENCY = 4;
41280
41334
  MAX_MEMORY_READ_ATTEMPTS = 3;
@@ -41308,6 +41362,8 @@ var init_vault_routes = __esm({
41308
41362
  const content = typeof body.content === "string" && body.content.length <= 1e5 ? body.content : "";
41309
41363
  const props = propsValue(body.props) ?? {};
41310
41364
  if (!isVault(vault) || !path6 || !title) return c.json({ ok: false, error: "vault, path, and title are required" }, 400);
41365
+ const validationError = validateNewRecord(vault, props);
41366
+ if (validationError) return c.json({ ok: false, error: validationError }, 400);
41311
41367
  const baseRevision = typeof body.baseRevision === "number" && Number.isInteger(body.baseRevision) ? body.baseRevision : void 0;
41312
41368
  const result = await memoryCall("putTool", { vault, path: path6, title, content: content || title, props, ...baseRevision === void 0 ? {} : { baseRevision } }, token);
41313
41369
  return c.json(result, result.ok ? 200 : result.conflict ? 409 : 502);
@@ -41348,12 +41404,15 @@ var init_vault_routes = __esm({
41348
41404
  }
41349
41405
  const current = await readMemory("getTool", { vault, path: path6 }, token);
41350
41406
  if (!current.ok || !current.note) return c.json(current, current.ok ? 404 : 502);
41407
+ const nextProps = { ...current.note.props ?? {}, ...props ?? {} };
41408
+ const validationError = validateNewRecord(vault, nextProps);
41409
+ if (validationError) return c.json({ ok: false, error: validationError }, 400);
41351
41410
  const result = await memoryCall("putTool", {
41352
41411
  vault,
41353
41412
  path: path6,
41354
41413
  title: title ?? current.note.title,
41355
41414
  content: content ?? current.note.content,
41356
- props: { ...current.note.props ?? {}, ...props ?? {} },
41415
+ props: nextProps,
41357
41416
  baseRevision: baseRevision ?? current.note.revision
41358
41417
  }, token);
41359
41418
  return c.json(result, result.ok ? 200 : result.conflict ? 409 : 502);
@@ -41388,20 +41447,25 @@ var init_vault_routes = __esm({
41388
41447
  const content = typeof body.content === "string" && body.content.length <= 1e5 ? body.content : void 0;
41389
41448
  const feedback = typeof body.feedback === "string" ? body.feedback.trim().slice(0, 1e4) : void 0;
41390
41449
  const baseRevision = typeof body.baseRevision === "number" && Number.isInteger(body.baseRevision) ? body.baseRevision : void 0;
41391
- if (!path6 || !action || !["accept", "deny", "edit"].includes(action) || body.title !== void 0 && !title) {
41450
+ const normalizedAction = action === "accept" ? "approve" : action;
41451
+ if (!path6 || !normalizedAction || !["approve", "deny", "edit"].includes(normalizedAction) || body.title !== void 0 && !title) {
41392
41452
  return c.json({ ok: false, error: "valid path, action, and optional draft fields are required" }, 400);
41393
41453
  }
41394
41454
  const current = await readMemory("getTool", { vault: "Communications", path: path6 }, token);
41395
41455
  if (!current.ok || !current.note) return c.json(current, current.ok ? 404 : 502);
41396
41456
  if (current.note.props?.type !== "email") return c.json({ ok: false, error: "only email communications can be reviewed" }, 400);
41397
- const reviewed = action === "accept" || action === "deny";
41398
- const reviewState = action === "accept" ? "accepted" : action === "deny" ? "denied" : "pending";
41399
- const status = action === "accept" ? "triaged" : action === "deny" ? "archived" : typeof current.note.props?.status === "string" ? current.note.props.status : "inbox";
41457
+ const reviewed = normalizedAction === "approve" || normalizedAction === "deny";
41458
+ const reviewState = normalizedAction === "approve" ? "accepted" : normalizedAction === "deny" ? "denied" : "pending";
41459
+ const approvalState = normalizedAction === "approve" ? "approved" : normalizedAction === "deny" ? "denied" : "pending";
41460
+ const status = normalizedAction === "approve" ? "triaged" : normalizedAction === "deny" ? "archived" : "inbox";
41400
41461
  const props = {
41401
41462
  ...current.note.props ?? {},
41402
41463
  status,
41403
41464
  review_state: reviewState,
41465
+ approval_state: approvalState,
41466
+ attention_state: normalizedAction === "edit" ? "needs_review" : "none",
41404
41467
  ...reviewed ? { reviewed_at: (/* @__PURE__ */ new Date()).toISOString() } : {},
41468
+ ...normalizedAction === "approve" ? { approved_at: (/* @__PURE__ */ new Date()).toISOString() } : {},
41405
41469
  ...feedback ? { review_feedback: feedback } : {}
41406
41470
  };
41407
41471
  const result = await memoryCall("putTool", {
@@ -41428,7 +41492,7 @@ var init_vault_routes = __esm({
41428
41492
  path: `Inbox/activity-${stamp}`,
41429
41493
  title,
41430
41494
  content: content || title,
41431
- props: { status: "triaged", type: "decision", occurred_at: (/* @__PURE__ */ new Date()).toISOString(), ...props }
41495
+ props: { status: "triaged", type: "decision", attention_state: "none", occurred_at: (/* @__PURE__ */ new Date()).toISOString(), ...props }
41432
41496
  }, token);
41433
41497
  return c.json(result, result.ok ? 200 : 502);
41434
41498
  });