From 72c0dc029487646bcb8e3c8242876a0621e03ff1 Mon Sep 17 00:00:00 2001 From: leemour Date: Sat, 14 Nov 2026 13:24:16 +0100 Subject: [PATCH 1/3] docs(memo): review memo 0.135.0, translate the Import page Moves the reviewed memo release from v0.131.87 to v0.135.0, the newest on npm, prepared with docs:updates for memo only. - New page: Import files and records, in Russian and Spanish, with a sidebar icon. A correction fixes its search example: bare `memo search --source` is refused; `memo search notes --source import:` finds an imported document (checked on 0.135.0 in a throwaway home). - Updated RU/ES: notes (format detection, overlap refusal, format change), usage (meetings and documents lists), sources (transcripts, import link), mcp (schedules), people (meetings), configuration, installation, and the commands reference intro. The changelog's new entries stay in English, as before. - Source fingerprints accepted, release-notes review recorded (roadmap unchanged), search language regenerated. Co-Authored-By: Claude Opus 5.5 --- docs/release-notes-review.json | 6 +- lib/docs-sidebar-tree.tsx | 2 + lib/search-language.generated.js | 4 +- scripts/docs-corrections.json | 25 + tools.json | 2 +- translations/memo/changelog.es.md | 127 ++++++ translations/memo/changelog.ru.md | 127 ++++++ translations/memo/commands.es.md | 635 +++++++------------------- translations/memo/commands.ru.md | 635 +++++++------------------- translations/memo/configuration.es.md | 2 +- translations/memo/configuration.ru.md | 2 +- translations/memo/import.es.md | 274 +++++++++++ translations/memo/import.ru.md | 271 +++++++++++ translations/memo/installation.es.md | 2 +- translations/memo/installation.ru.md | 2 +- translations/memo/mcp.es.md | 4 + translations/memo/mcp.ru.md | 4 + translations/memo/notes.es.md | 22 +- translations/memo/notes.ru.md | 22 +- translations/memo/people.es.md | 2 + translations/memo/people.ru.md | 2 + translations/memo/sources.es.md | 7 +- translations/memo/sources.ru.md | 7 +- translations/memo/usage.es.md | 34 ++ translations/memo/usage.ru.md | 34 ++ translations/sources.json | 40 +- 26 files changed, 1301 insertions(+), 993 deletions(-) create mode 100644 translations/memo/import.es.md create mode 100644 translations/memo/import.ru.md diff --git a/docs/release-notes-review.json b/docs/release-notes-review.json index 5d404f73..cbbd37c7 100644 --- a/docs/release-notes-review.json +++ b/docs/release-notes-review.json @@ -24,10 +24,10 @@ "conclusion": "Reviewed drive 0.62.0 to 0.65.0 from the changelog and the docs diff since v0.61.0. Added: `drive documents add --profiles ` keeps one Drive document's text in the shared store as a source added by hand, for memo's Add to memory. It tries the named profiles in order, at most `max_add_profiles` (default 5, at most 50), moves on only after an access refusal, answers `duplicate_of` for a file a sync already imported, and does not run over MCP. Also added: `account remove --keep-data|--delete-data`, `folders browse [--parent]`, and `schedule pause|resume`. May break callers: a profile with no saved sign-in fails with `oauth.missing`, not `oauth.expired`. `memories add --supersedes` retires the old memory only once the owner confirms. The shared store moves to version 57 and then, on cli-core 0.634.0, to 64. Fixed: a document's owner and last editor no longer land in your memory or its review, and a spent Google quota is a rate limit, not a permission refusal. RU/ES changelog (kept in English, as before), commands, configuration and usage reviewed. Since `documents add` ships, the memo troubleshooting correction that worked around it was retired. The roadmap is unchanged since v0.61.0: its Next item, `mirrors watch` as a background service, has not shipped." }, "memo": { - "version": "v0.131.87", + "version": "v0.135.0", "roadmapSha256": "70388c0f1018e20198377af9494404c331071cdec6701ade37df8d4cec6e5d6b", - "reviewedAt": "2026-11-12", - "conclusion": "Reviewed memo 0.131.73 to 0.131.87 from the changelog and the docs diff since v0.131.72. `search all` finds meetings from every meeting account, and `--harder` lets a hosted model reorder the first 30 results after the owner allows a provider with `models search-consents`. People: `people list` shows one kind at a time (person, automated, organization, stranger, unsorted); `people check` and `search people` look up names in either script; `people confirm`, `reject` and `resolve` decide matches; `people links check` and `links resolve` keep handle people that look wrong; `unlink` needs `--from`, and an agent's unlink or unmerge only proposes the split; an account under another person's name, or a company's phone, no longer joins the owner. Digests by name (`digest list|add|edit|run|pause|resume|remove`, `backfill --since-time|--until-time`). `sources add` reads an image with the chosen AI model, and `sources preview` shows a page before adding it. Also `models ai` and `models local-only`, `records import` from a CSV sheet, `stats projects show`, and `groups update --scope`. Tasks found in messages take project task fields and appear in `tasks list`. RU/ES business, changelog and commands (both kept in English), mail, mcp, people, roadmap, search, security, sources, tasks, troubleshooting and usage reviewed. The people correction lost its `kind:identity_link` replacement, which the source now writes as `memo people confirm`; the troubleshooting correction for `drive documents add` was retired because drive 0.65.0 ships it. Roadmap changed: \"Meetings in search all and in a person's context\" became \"Meetings in a person's context\", because `search all` now reads meetings; nothing else under Next or Later shipped. Earlier: Reviewed Memo 0.131.72, covering 0.131.67 to 0.131.72 from the changelog and the source diff since v0.131.66. New guide sources (in the sidebar under Guides): memo sources add, show, mentions and remove keep one file, web page or pasted text as a document, sources suggest has the chosen reader propose facts from a source for the owner to confirm, and sources readers list and set pick that reader. Memories and facts follow their sources: a changed, removed, replaced or contradicted source opens a source review and never changes the record's status. An agent's memories add --supersedes waits as proposed. memo people show, review, scan, link, unlink and unmerge, with automatic joins by e-mail address and phone number. 0.131.71 makes EmbeddingGemma the default search model, adds search all --only crm and leaves deals and leads out when permissions deny them, and adds account groups, stages, relationship roles and organization, deal and lead context. 0.131.67 to 0.131.70 add templates and digest brief for the morning digest, digest backfill, review agenda --before-time and .html folder import. search all does not search meetings in this release. EN/RU/ES pages carried into the translations: sources (new), memories, people, mcp, security, troubleshooting, usage, search, mail, notes, configuration, how-it-works and installation, plus the changelog sections 0.131.67 to 0.131.72 and the generated command reference (both kept in English). The comparison page marks finding facts in text as partial for memo (sources suggest, confirmed by the owner) and names the source review. Roadmap: unchanged, nothing under Next or Later shipped. Earlier: Reviewed Memo 0.131.66, covering 0.131.13 to 0.131.66 from the changelog and the source diff since v0.131.12. 0.131.66 renames subscriptions add and update --every to --period (may break callers, --every on subscriptions is now an unknown option), and records import and check take --region for a vCard file. 0.131.65 fixes review agenda's no-schedule health lines and counts undated tasks. Mail import left memo in 0.131.25: memo mail add, check and inspect moved to the mail CLI, memo sync reads notes only, and the config's mail section is retired, so the mail, configuration and troubleshooting pages drop the Himalaya import. New: memo review (one list of what waits for you, status and show), schedule command and agent with --notify-on and --deliver-to, review agenda, the mail-triage agent with mail review, mail findings and messages acknowledge or reset, invoices, payments and orders, then business data in 0.131.64: products, contracts, subscriptions with price history (--period), wallets, transactions with splits, order and invoice lines, refunds and net paid, and records import, check, list, show, link and delete over the records envelope (JSON, streaming JSONL and vCard). memo's English pages also gained the #757 wording fixes (the personal mail profile, when the triage schedule starts claude, the update check, agent_decisions, deletions of mail, proposals, and the project-state scenario's look lines), carried into RU/ES. memo show opens any reference and lists the source records behind a business entry, and search all gains events with imported phone calls, deals and leads (crm) and business data, each lane left out over MCP when the server denies listing it. memo events list lists every calendar account's events, phone calls included, over the last 30 days and the next 7 by default. Also: organizations show and rename, folders remove, store recover, models set and add, --compact, the morning digest as one wirecat.report/1 document, and a conflict failure (exit 15) for a changed task. EN/RU/ES pages carried into the translations: business (new, in the sidebar under Guides), mail, usage, configuration, how-it-works, search, people (a new section on importing a phone's contacts with --region), security, notes, troubleshooting, mcp, tags, tasks, memories, index, installation, recipes, roadmap, archive and scenarios, plus every changelog section from 0.131.13 (kept in English) and the generated command reference (English). The comparison page is checked against 0.131.66: a row for business data, and search all's lanes in the sources note. Roadmap changed: Removing the Himalaya import shipped and left Later, and What works today no longer names the Himalaya import or mail add; nothing else under Next or Later shipped. Earlier: Reviewed Memo 0.131.12, covering 0.131.11 and 0.131.12 from the changelog and the source diff. Mail rules, Gmail cleanup and restore moved to the mail CLI: the old memo mail rules, delete, restore and runs commands now only name their replacement and change nothing, and memo doctor no longer reports Gmail cleanup. The mail guide, commands, configuration, how-it-works, index, mcp, remote and security pages and every changelog section are carried into RU/ES; the generated command reference stays English. The comparison page no longer lists mail cleanup as a memo feature. Roadmap: unchanged; Removing the Himalaya import stays planned. Earlier: Reviewed Memo 0.131.10, covering 0.131.3 to 0.131.10 from the changelog and the source diff. The docs gain the import: false setting for mail, task move by project, the --project option on memories, and the new task column rule and revision paragraph. memo mail status is gone: mail status replaces it. EN/RU/ES pages (changelog, commands, mail, memories, tasks) carried into the translations; the generated command reference stays English. Roadmap: unchanged, nothing under Next or Later shipped; Removing the Himalaya import stays planned. Earlier: Reviewed Memo 0.131.2, covering 0.109.0 to 0.131.1 as captured in the source diff and the changelog. Mail now comes in through the mail CLI, which fills the shared store; Memo searches it, and the Himalaya import is described as the older path that a later version removes. The docs gain memo people list, tasks counts, history, move, claim and release, memories and facts remove or reject, the mcp serve, revoke and server subcommands, and the record_input, keep_successful_runs_for_days and runs_size_limit_mb settings. EN/RU/ES pages (commands, configuration, how-it-works, index, installation, mail, mcp, memories, people, recipes, remote, roadmap, search, security, tasks, troubleshooting, usage) and every changelog section from 0.109.0 carried into the translations; the generated command reference stays English as before. Roadmap: under Next, Reading mail without Himalaya is replaced by Removing the Himalaya import; nothing else under Next or Later shipped. Earlier: Reviewed Memo 0.108.0 with exact Core 0.431.0/Base 0.57.1. 0.108.0 parses mail with postal-mime 4.1.4 (a few malformed messages read differently; re-importing one can store slightly different text) and answers a bare memo --version before the program loads; the command tree is unchanged. configuration.md now says keys are added by hand and memo config unset removes one, so the portal correction is retired. EN/RU/ES configuration and the 0.108.0 release notes reviewed. Roadmap unchanged: nothing under Next or Later shipped. Earlier: Reviewed Memo 0.98.0–0.107.0 with exact Core 0.431.0/Base 0.57.0. 0.107.0 adds doctor file-permission checks (files.problems with the chmod fix on stderr) and owner-only config.json saves; 0.104.0 adds config.issues with a runnable fix, memo config unset, run logs (runs list/show/path, record, keep_runs_for_days), renames config.exists to config.found, refuses retired permission keys and removes sync --account and the ignored --brief/--full of search all/notes; 0.103.0 moves notes folders to obsidian/local accounts on the shared store; 0.100.0/0.101.0 add people and confirmed-member lanes to projects evidence; 0.105.0 adds store info, skill status/show --for and run errors; 0.106.0 moves run recording to Core. EN/RU/ES configuration, installation, mcp, notes, search, tags, tasks, scenarios, generated reference and 0.98–0.107 release notes reviewed; doctor shape, config unset and the refusal checked on an isolated install. The released changelog has no 0.102.0 section, and configuration.md still says Memo has no config command (portal correction; cli-memo source issues). Roadmap unchanged: nothing under Next or Later shipped (tag merging still has no apply command)." + "reviewedAt": "2026-11-14", + "conclusion": "Reviewed memo 0.132.0 to 0.135.0 from the changelog and the docs diff since v0.131.87. Added: `memo import` brings a folder of documents, `.vtt`/`.srt` transcripts and, with `--transcribe`, recordings heard by the local speech model, or a records file, into an `import:` or `phone:` account, keyed by path so a second run changes nothing; a new Import page documents it with a records adapter and an Asterisk CDR example. `memo sources add` keeps meeting transcripts. `memo meetings list|show` gives one row per real meeting across calendars, Zoom and imported calls, and `memo documents list|show|tree` lists every account's documents. May break callers: `memo folders add` detects `obsidian` or `markdown` when `--format` is not given and refuses a folder inside or around one memo already reads (`folder.overlap`); date-only list queries and due dates read the computer's zone; a `readonly` level no longer stops a sync; `memo search meetings` shows 20 hits by default. Fixed: a folder's notes are read again after a format change, and `documents show` counts code points. RU/ES changelog (kept in English, as before), commands, configuration, installation, mcp, notes, people, sources and usage reviewed; import translated. The roadmap is unchanged since v0.131.87." }, "wa": { "version": "v0.38.0", diff --git a/lib/docs-sidebar-tree.tsx b/lib/docs-sidebar-tree.tsx index de828efd..ea9cce2c 100644 --- a/lib/docs-sidebar-tree.tsx +++ b/lib/docs-sidebar-tree.tsx @@ -19,6 +19,7 @@ import { Download, FileChartColumn, FileCode2, + FileInput, FilePlus2, FileSearch, FileText, @@ -93,6 +94,7 @@ export const sidebarIcons = { pbx: PhoneCall, notes: StickyNote, sources: FilePlus2, + import: FileInput, tags: Tag, tasks: ListTodo, memories: Brain, diff --git a/lib/search-language.generated.js b/lib/search-language.generated.js index 700e8975..c4dfc3ee 100644 --- a/lib/search-language.generated.js +++ b/lib/search-language.generated.js @@ -1,3 +1,3 @@ -// Generated from pinned @wirecat/cli-core. Source SHA-256: 7e4717fe3a0764f1c58a4ecec8cfd4a1faac49807539f0a48f7422da46658efe +// Generated from pinned @wirecat/cli-core. Source SHA-256: 4ca9a1a46844de62cd61faef40ca7a2ef664ed7e9e0b61b51733f075a5c1d391 // Apache Lucene notices: /search-language-notices.txt -var me,ln={lang:void 0,message:void 0,abortEarly:void 0,abortPipeEarly:void 0};function Fe(e){return!e&&!me?ln:{lang:e?.lang??me?.lang,message:e?.message,abortEarly:e?.abortEarly??me?.abortEarly,abortPipeEarly:e?.abortPipeEarly??me?.abortPipeEarly}}var cn;function pn(e){return cn?.get(e)}var fn;function yn(e){return fn?.get(e)}var mn;function hn(e,r){return mn?.get(e)?.get(r)}function ae(e){let r=typeof e;return r==="string"?`"${e}"`:r==="number"||r==="bigint"||r==="boolean"?`${e}`:r==="object"||r==="function"?(e&&Object.getPrototypeOf(e)?.constructor?.name)??"null":r}function E(e,r,n,t,i){let s=i&&"input"in i?i.input:n.value,u=i?.expected??e.expects??null,c=i?.received??ae(s),l={kind:e.kind,type:e.type,input:s,expected:u,received:c,message:`Invalid ${r}: ${u?`Expected ${u} but r`:"R"}eceived ${c}`,requirement:e.requirement,path:i?.path,issues:i?.issues,lang:t.lang,abortEarly:t.abortEarly,abortPipeEarly:t.abortPipeEarly},o=e.kind==="schema",f=i?.message??e.message??hn(e.reference,l.lang)??(o?yn(l.lang):null)??t.message??pn(l.lang);f!==void 0&&(l.message=typeof f=="function"?f(l):f),o&&(n.typed=!1),n.issues?n.issues.push(l):n.issues=[l]}function dn(e,r){return e===r||Number.isNaN(e)&&Number.isNaN(r)}function vn(e,r){return Object.prototype.hasOwnProperty.call(e,r)&&r!=="__proto__"&&r!=="prototype"&&r!=="constructor"}function Me(e,r){let n=[...new Set(e)];return n.length>1?`(${n.join(` ${r} `)})`:n[0]??"never"}function R(e){return e["~standard"]={version:1,vendor:"valibot",validate:r=>e["~run"]({value:r},Fe())},e}function Le(e){if(e.path){let r="";for(let n of e.path)if(typeof n.key=="string"||typeof n.key=="number")r?r+=`.${n.key}`:r+=n.key;else return null;return r}return null}var gn=/^\d{4}-(?:0[1-9]|1[0-2])-(?:[12]\d|0[1-9]|3[01])[T ](?:0\d|1\d|2[0-3])(?::[0-5]\d){2}(?:\.\d{1,9})?(?:Z| ?[+-](?:0\d|1\d|2[0-3])(?::?[0-5]\d)?)$/u;function xe(e,r){return{kind:"validation",type:"ends_with",reference:xe,async:!1,expects:`"${e}"`,requirement:e,message:r,"~run"(n,t){return n.typed&&!n.value.endsWith(this.requirement)&&E(this,"end",n,t,{received:`"${n.value.slice(-this.requirement.length)}"`}),n}}}function X(e){return{kind:"validation",type:"integer",reference:X,async:!1,expects:null,requirement:Number.isInteger,message:e,"~run"(r,n){return r.typed&&!this.requirement(r.value)&&E(this,"integer",r,n),r}}}function we(e){return{kind:"validation",type:"iso_timestamp",reference:we,async:!1,expects:null,requirement:gn,message:e,"~run"(r,n){return r.typed&&!this.requirement.test(r.value)&&E(this,"timestamp",r,n),r}}}function te(e,r){return{kind:"validation",type:"max_length",reference:te,async:!1,expects:`<=${e}`,requirement:e,message:r,"~run"(n,t){return n.typed&&n.value.length>this.requirement&&E(this,"length",n,t,{received:`${n.value.length}`}),n}}}function B(e,r){return{kind:"validation",type:"min_value",reference:B,async:!1,expects:`>=${e instanceof Date?e.toJSON():ae(e)}`,requirement:e,message:r,"~run"(n,t){return n.typed&&!(n.value>=this.requirement)&&E(this,"value",n,t,{received:n.value instanceof Date?n.value.toJSON():ae(n.value)}),n}}}function V(e,r){return{kind:"validation",type:"regex",reference:V,async:!1,expects:`${e}`,requirement:e,message:r,"~run"(n,t){return n.typed&&!this.requirement.test(n.value)&&E(this,"format",n,t),n}}}var kn={abortEarly:!0};function Ge(e,r,n){return typeof e.fallback=="function"?e.fallback(r,n):e.fallback}function _e(e,r,n){return typeof e.default=="function"?e.default(r,n):e.default}function M(e,r){return R({kind:"schema",type:"array",reference:M,expects:"Array",async:!1,item:e,message:r,"~run"(n,t){let i=n.value;if(Array.isArray(i)){n.typed=!0,n.value=[];for(let s=0;s{for(let P of x.options){if(P.type==="variant")f(P,new Set($).add(P.key));else{let S=!0,C=0;for(let _ of $){let T=P.entries[_];if(_ in s?T["~run"]({typed:!1,value:s[_]},kn).issues:T.type!=="exact_optional"&&T.type!=="optional"&&T.type!=="nullish"){S=!1,l!==_&&(ctypeof e=="object"&&e!==null&&e[Xe]===!0;var Q={bytes:8192,depth:32,nodes:256},Be=K({start:L(),end:L()}),bn=K({kind:z("predicate"),field:N(),operator:Y(["term","phrase","wildcard","regex","range"]),value:N(),upper:d(N()),lower_inclusive:d(F()),upper_inclusive:d(F()),span:Be,implicit:d(z(!0)),slop:d(A(L(),X(),B(0)))}),Ae=re("kind",[bn,K({kind:z("boolean"),clauses:M(K({occur:Y(["must","should","must_not"]),node:Ee(()=>Ae)})),span:Be})]),Ve=K({version:z(1),language:z("lucene-v1"),root:Ae});function O(e,r,n,t={},i={}){throw new H("validation_error",`${t.command??"query"}: ${e} at position ${r.start+1}${n?` \u2014 ${n}`:""}`,{reason:e,span:r,...n?{alternative:n}:{},...t.guide?{guide:t.guide}:{},...i})}var W=e=>e.kind==="predicate"?[e]:e.clauses.flatMap(({node:r})=>W(r));var fe=e=>/[ \t\n\r\u3000]/u.test(e),Oe=new Set(["+","-","!","(",")",":","=","^","@","<",">","[","]",'"',"{","}","~","\\","/"]),ve=(e,r,n)=>{let t="";for(let i=0;i=e.length&&n("query.invalid-escape",r),e[i]==="u"){let s=e.slice(i+1,i+5);/^[0-9a-fA-F]{4}$/.test(s)||n("query.invalid-escape",r),t+=String.fromCharCode(Number.parseInt(s,16)),i+=4}else t+=e[i]}return t},xn=(e,r=O)=>{let n=[],t=0,i=!1;for(;t=e.length&&r("query.unclosed-literal",{start:s,end:t},u==="/"?wn(e,s):void 0),t++,u==="/"&&/^[dgimsuvy]+(?:$|[ \t\n\r)])/.test(e.slice(t))&&r("query.unsupported-regex-flags",{start:t,end:t+1},"Lucene regex does not take JavaScript flags"),c=u==='"'?"quoted":"regex"}else if(i&&u!=="]"&&u!=="}"){for(;t")&&e[t]==="="&&(t++,c+="="),(u==="["||u==="{")&&(i=!0),(u==="]"||u==="}")&&(i=!1);else{for(t++;t=e.length&&r("query.invalid-escape",{start:t,end:t+1}),t+=2;continue}if(x==="@"&&/^@(?:\p{L}|[\p{L}\p{N}][^\s@]*\.[\p{L}\p{N}])/u.test(e.slice(t))){t++;continue}if(fe(x)||Oe.has(x)&&x!=="+"&&x!=="-")break;t++}let[l,o]=n.slice(-2);if(l?.kind==="term"&&o?.kind===":"&&o.span.end===s&&e[t]===":"&&/^[a-z][a-z_-]*$/u.test(e.slice(s,t))&&/^:[^\s()"]/u.test(e.slice(t)))for(;t{for(let n of e.matchAll(/(?<=^|[\s(])([\p{L}\p{N}_.-]+):([^\s"()]+)/gu)){let[t,i,s=""]=n;if(!(rn.index+t.length))return/[:=/?*~^@<>![\]{}\\]/u.test(s)?`put the value in quotes: ${i}:"${s}"`:void 0}},wn=(e,r)=>{let n=`${/[^\s()"]*$/u.exec(e.slice(0,r))?.[0]??""}${/^[^\s()"]*/u.exec(e.slice(r))?.[0]??""}`;return Ye(e,r)??`/ starts a regular expression; put the value in quotes: "${n}"`},qe=(e,{defaultField:r="text",proximity:n=!1,...t}={})=>{let i=(k,a,p)=>O(k,a,p??Ye(e,a.start),t);(e.length>Q.bytes||new TextEncoder().encode(e).length>Q.bytes)&&i("query.too-large",{start:0,end:e.length});let s=xn(e,i),u=0,c=0,l=0,o=()=>s[u],f=()=>s[u++],x=k=>(o().kind!==k&&i("query.invalid-syntax",o().span),f()),$=k=>(++c>Q.nodes&&i("query.too-large",k.span),k),P=(k,a)=>{let p=k[0],m=k.at(-1);return(!p||!m)&&i("query.invalid-syntax",o().span),k.length===1?p:{node:$({kind:"boolean",clauses:k.map(({node:v,modifier:g})=>({node:v,occur:g??a})),span:{start:p.node.span.start,end:m.node.span.end}})}},S=(k,a=!1)=>{++l>Q.depth&&i("query.too-large",o().span);let p=[];do p.push(C(k,a));while(!["EOF",")"].includes(o().kind));let m=P(p,"must");return l--,m.modifier==="must_not"?$({kind:"boolean",clauses:[{node:m.node,occur:"must_not"}],span:m.node.span}):m.node},C=(k,a)=>{let p=[_(k,a)];for(;o().kind==="OR";)f(),p.push(_(k,a));return P(p,"should")},_=(k,a)=>{let p=[T(k,a)];for(;o().kind==="AND";)f(),p.push(T(k,a));return P(p,"must")},T=(k,a)=>{let p;["+","-","NOT","!"].includes(o().kind)&&(p=f().kind==="+"?"must":"must_not");let m=k,v,g=a;if(o().kind==="term"&&[":","=","<",">","<=",">="].includes(s[u+1]?.kind??"")){let y=f();m=ve(y.raw,y.span,i),v=y.span.start,g=!1;let b=f();if(b.kind===":"&&["<",">","<=",">="].includes(o().kind)&&(b=f()),["<",">","<=",">="].includes(b.kind)){let q=f();["term","number","quoted"].includes(q.kind)||i("query.invalid-syntax",q.span);let G=ve(q.kind==="quoted"?q.raw.slice(1,-1):q.raw,q.span,i),U=b.kind.startsWith(">");return{node:$({kind:"predicate",field:m,operator:"range",value:U?G:"*",upper:U?"*":G,lower_inclusive:!U||b.kind.endsWith("="),upper_inclusive:U||b.kind.endsWith("="),span:{start:y.span.start,end:q.span.end}}),...p?{modifier:p}:{}}}}let h;if(o().kind==="("){let y=f().span.start;h=S(m,g);let b=x(")").span.end;h={...h,span:{start:y,end:b}}}else if(["[","{"].includes(o().kind)){let y=f(),b=f();["rangeValue","quoted"].includes(b.kind)||i("query.invalid-syntax",b.span);let q=f();q.raw!=="TO"&&i("query.invalid-syntax",q.span);let G=f();["rangeValue","quoted"].includes(G.kind)||i("query.invalid-syntax",G.span);let U=f();["]","}"].includes(U.kind)||i("query.invalid-syntax",U.span);let oe=ne=>ve(ne.kind==="quoted"?ne.raw.slice(1,-1):ne.raw,ne.span,i);h=$({kind:"predicate",field:m,operator:"range",value:oe(b),upper:oe(G),lower_inclusive:y.kind==="[",upper_inclusive:U.kind==="]",span:{start:v??y.span.start,end:U.span.end}})}else{let y=f();["term","number","quoted","regex"].includes(y.kind)||i("query.invalid-syntax",y.span);let b=["term","number"].includes(y.kind)?y.raw:y.raw.slice(1,-1);m==="fn"&&i("query.unsupported-operator",y.span,"interval functions are not supported");let q=["term","number"].includes(y.kind)&&/(?a.implicit);k&&O("query.bare-word",k.span,`"${k.value}" has no field; write field:value`,t,{word:k.value})}return{version:1,language:"lucene-v1",root:ue}};var Se=(e,r)=>{/^\d{4}-\d{2}-\d{2}$/u.test(e)||O("query.invalid-date",r,"use an ISO date or a quoted timestamp with offset");let n=Number(e.slice(0,4)),t=Number(e.slice(5,7)),i=Number(e.slice(8,10)),s=new Date(0);return s.setUTCFullYear(n,t-1,i),s.setUTCHours(0,0,0,0),(s.getUTCFullYear()!==n||s.getUTCMonth()!==t-1||s.getUTCDate()!==i)&&O("query.invalid-date",r),s},Ze=(e,r,n,t)=>{let i=Se(e,t);n&&i.setUTCDate(i.getUTCDate()+1);let s=i.getUTCFullYear()*1e4+(i.getUTCMonth()+1)*100+i.getUTCDate(),u=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit",era:"short"}),c=f=>{let x=u.formatToParts(f),$=S=>Number(x.find(C=>C.type===S)?.value);return(x.find(S=>S.type==="era")?.value==="BC"?1-$("year"):$("year"))*1e4+$("month")*100+$("day")},l=i.getTime()-2*864e5,o=i.getTime()+2*864e5;for(;l{let i=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit"}).format(n);if(e==="today")return i;let s=Se(i,t);return s.setUTCDate(s.getUTCDate()-1),s.toISOString().slice(0,10)},ie=(e,r,n,t,i,s=Date.now())=>{if(e==="*")return{inclusive:t};let u=e.toLowerCase();if(u==="today"||u==="yesterday")return ie(En(u,r,s,i),r,n,t,i);let[,c,l]=Je.exec(u)??[];if(c&&l)return{time:s-Number(c)*(_n[l]??0),inclusive:t};if(/^\d{4}-\d{2}-\d{2}$/u.test(e))return{time:Ze(e,r,n==="lower"?!t:t,i),inclusive:n==="lower"};/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/u.test(e)||O("query.invalid-date",i,"use an ISO date, today, yesterday, 30m/2h/7d ago, or a quoted timestamp with offset"),Se(e.slice(0,10),i);let o=Date.parse(e);return(!Number.isFinite(o)||Number(e.slice(11,13))>23||Number(e.slice(14,16))>59||Number(e.slice(17,19))>59)&&O("query.invalid-date",i),{time:o,inclusive:t}},De=(e,r,n,t,i,s,u=Date.now())=>{let c=e===r&&Je.test(e.toLowerCase()),l=ie(e,i,"lower",n,s,u),o=ie(c?"*":r,i,"upper",t,s,u);return{...l.time===void 0?{}:{lower:l.time},...o.time===void 0?{}:{upper:o.time},lower_inclusive:l.inclusive,upper_inclusive:o.inclusive}};var nt=A(N(),V(/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,"a lower-case word, words joined by -")),Ne=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,j=A(N(),V(/\S/,"must not be empty")),Z=A(N(),V(/^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/,"dotted lower-case words, such as `page.next`")),ye=class extends Error{registry;problems;constructor(r,n){super(`${r} registry: ${n.join("; ")}`),this.registry=r,this.problems=n,this.name="RegistryError"}},An=e=>e.map(r=>{let n=Le(r);return n?`${n}: ${r.message}`:r.message}),Qe=(e,r,n,t=()=>[])=>{let i=Ue(r,n);if(!i.success)throw new ye(e,An(i.issues));let s=t(i.output);if(s.length>0)throw new ye(e,s);return i.output},je=e=>[...new Set(e.filter((r,n)=>e.indexOf(r)!==n))].sort();var On=/\{([a-z][a-z0-9]*(?:_[a-z0-9]+)*)\}/g,We=e=>[...e.matchAll(On)].map(r=>r[1]??"");var $e=2;var Ie=A(N(),we("an ISO 8601 time in UTC"),xe("Z","an ISO 8601 time in UTC, ending in `Z`")),qn=A(N(),V(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{2}:\d{2}$/,"an ISO 8601 time with its offset")),en=A(N(),V(/^[a-z]+:\S+$/,"a reference such as `note:42`")),Ce=re("kind",[D({kind:z("command"),step:Z,command:j,args:le(N(),ce()),line:d(j),why:j,safe_to_auto_execute:F()}),D({kind:z("user_action"),step:Z,why:j,safe_to_auto_execute:z(!1)})]),st=D({field:j,why:j,step:d(Z)}),Ke=A(L(),X(),B(1)),He=D({value:A(L(),X(),B(0)),relation:Y(["eq","gte"])}),Sn=re("mode",[D({mode:z("page"),limit:Ke,has_more:F(),next_page:d(A(L(),X(),B(2))),total:d(He)}),D({mode:z("cursor"),limit:Ke,has_more:F(),next_cursor:d(j),total:d(He)})]),nn=D({code:Y(pe),reason:d(Z),source:j}),ut=D({run_id:j,duration_ms:A(L(),X(),B(0)),accounts:d(M(j)),complete:F(),issues:d(M(nn)),truncated:d(F()),timezone:d(j),now:d(Ie),now_local:d(qn),window:d(D({since:d(Ie),until:d(Ie)}))});var ot=d(A(M(Ce),te($e)));var at=D({type:z("end"),complete:F(),issues:d(M(nn)),page:Sn});var pt=en.pipe[1].requirement.source;var Te="internal_error",Dn="command.crashed",vt=D({error:D({code:Y([...pe,Te]),reason:Z,message:j,param:d(j),details:d(le(N(),ce())),next:d(A(M(Ce),te($e))),retry:D({safe:F(),after_ms:d(A(L(),X(),B(0)))}),run_id:d(j)})}),Nn=D({reason:Z,code:Y([...pe,Te]),message:A(j,te(120)),details:M(A(N(),V(Ne,"a snake_case key"))),step:d(Z)}),Re=e=>Qe("error reasons",M(Nn),e,r=>[...je(r.map(n=>n.reason)).map(n=>`"${n}" is listed twice`),...r.flatMap(n=>We(n.message).filter(t=>!n.details.includes(t)).map(t=>`${n.reason}: the message names {${t}}, which is not one of its details`))]);var gt=Re([{reason:"input.invalid",code:"validation_error",message:"the input is not valid",details:[]},{reason:"batch.read-budget",code:"validation_error",message:"batch stored-text read budget exhausted",details:[]},{reason:"batch.output-budget",code:"validation_error",message:"batch output budget exhausted",details:[]},{reason:"config.invalid",code:"configuration_error",message:"the configuration is not valid",details:[]},{reason:"auth.failed",code:"authentication_error",message:"the sign-in did not work",details:[]},{reason:"access.denied",code:"permission_error",message:"this account may not do that",details:[]},{reason:"item.not-found",code:"not_found",message:"nothing found by that name",details:[]},{reason:"tool.not-installed",code:"not_found",message:"no wcat- program by that name is on PATH",details:["tool","installed"]},{reason:"confirmation.required",code:"confirmation_required",message:"this changes something; confirm it",details:[]},{reason:"provider.rate-limited",code:"rate_limited",message:"too many requests; wait",details:[]},{reason:"command.timed-out",code:"timeout",message:"the command took too long",details:["timeout_ms"]},{reason:"network.failed",code:"network_error",message:"the network did not answer",details:[]},{reason:"provider.refused",code:"provider_error",message:"the provider refused",details:[]},{reason:"provider.unavailable",code:"provider_unavailable",message:"the provider is down",details:[]},{reason:"provider.invalid-response",code:"invalid_response",message:"the answer could not be read",details:[]},{reason:"output.too-large",code:"invalid_response",message:"the output is over {max_bytes} bytes",details:["max_bytes","buffered_bytes","partial_output"]},{reason:"output.fields-unavailable",code:"invalid_response",message:"fields can be picked only from whole JSON values",details:[]},{reason:"outcome.unknown",code:"outcome_unknown",message:"it is not known whether it worked",details:[]},{reason:"write.conflict",code:"conflict",message:"it changed since it was read; read it again",details:[]},{reason:"command.cancelled",code:"cancelled",message:"the command was cancelled",details:[]},{reason:Dn,code:Te,message:"the command failed; this is a bug",details:[]}]);var rn=(e,r)=>{try{r()}catch(n){if(!de(n)||typeof n.details.reason!="string"||n.details.span===void 0)throw n;let{reason:t,span:i,alternative:s}=n.details;O(t,i,s,e)}},tn=e=>e.operator==="range"?[e.value,e.upper??"*"].filter(r=>r!=="*"):[e.value],jn=(e,r,n)=>{let t=(i,s)=>O(i,r.span,s,n);if(r.value===""&&e.type!=="txt"&&t("query.missing-value"),r.operator!=="wildcard")switch(e.type){case"enum":e.values?.includes(r.value.toLowerCase())||t("query.unknown-value",`${e.name} takes ${e.values?.join(", ")}`);return;case"bool":["true","false"].includes(r.value.toLowerCase())||t("query.unknown-value",`${e.name} takes true, false`);return;case"num":for(let i of tn(r))(!Number.isFinite(Number(i))||i.trim()==="")&&t("query.invalid-number",`${e.name} takes a number`);return;case"time":rn(n,()=>{for(let i of tn(r))ie(i,n.zone??"UTC","lower",!0,r.span)});return;default:return}},ge=(e,r,n={})=>{let t=new Map(r.fields.map(s=>[s.name,s])),i=(s,u)=>{if(s.kind==="boolean"){for(let o of s.clauses)i(o.node,u&&o.occur==="must");return}let c=t.get(s.field);c||O("query.unknown-field",s.span,`no field "${s.field}"`,n,{fields:r.fields.map(o=>o.name)}),r.backend==="native"&&!c.native&&O("query.unsupported-field",s.span,`the source cannot filter by ${c.name}`,n,{supported:r.fields.filter(o=>o.native).map(o=>o.name)});let l=s.operator==="wildcard"&&s.value==="*";!l&&!c.operators.includes(s.operator)&&O("query.unsupported-operator",s.span,`${c.name} takes ${c.operators.join(", ")}`,n),c.placement==="and"&&!u&&O("query.unsupported-placement",s.span,`${c.name} only as a required term, not under OR or NOT`,n),!l&&(jn(c,s,n),c.validate&&rn(n,()=>c.validate?.(s)))};return i(e.root,!0),e};var In=["span","alternative","guide"],$n=Re([["query.bare-word","a word in the query has no field",["word"]],["query.invalid-ast","the query tree is not valid",[]],["query.invalid-date","a date in the query cannot be read",[]],["query.invalid-escape","an escape in the query is not valid",[]],["query.invalid-number","a number in the query cannot be read",[]],["query.invalid-regex","a regular expression in the query is not valid",[]],["query.invalid-syntax","the query cannot be parsed",[]],["query.invalid-timezone","the time zone is not known",[]],["query.missing-value","a field in the query has no value",[]],["query.too-large","the query is over one of its limits",[]],["query.unclosed-literal","a quote or bracket in the query is not closed",[]],["query.unknown-field","a field in the query is not known",["fields"]],["query.unknown-value","a value in the query is not known",[]],["query.unsupported-field","this list cannot filter by that field",["supported"]],["query.unsupported-operator","this field does not take that operator",[]],["query.unsupported-placement","this field works only as a required term",[]],["query.unsupported-regex","that regular expression is not supported",[]],["query.unsupported-regex-flags","regular expression flags are not supported",[]],["query.unsupported-version","the query version is not supported",[]]].map(([e,r,n])=>({reason:e,code:"validation_error",message:r,details:[...In,...n]})));var Cn=/^[a-z0-9-]{1,32}$/,sn=e=>{let r=e.trim().toLowerCase();return Cn.test(r)?r:void 0};var J={...Q,pattern:1024,states:1e4,expansions:1e4,candidates:5e4,bodyBytes:8388608,milliseconds:2e3,work:1e7},ke={command:"search",guide:"https://github.com/WireCatLabs/cli-core/blob/main/docs/search/query-language.md"},pr={...ke,proximity:!0},be=50;function I(e,r,n){O(e,r,n,ke)}function ee(e){throw new H("validation_error",`search exceeded its ${e} budget \u2014 narrow the chat or date range`,{reason:"query.too-large",budget:e,complete:!1})}var Tn={"":1,b:1,k:1024,kb:1024,m:1024**2,mb:1024**2,g:1024**3,gb:1024**3},Rn=(e,r)=>{let[,n,t]=/^(\d+(?:\.\d+)?)\s*([a-z]*)$/iu.exec(e.trim())??[],i=Tn[t?.toLowerCase()??""];return(n===void 0||i===void 0)&&I("query.invalid-size",r,"use bytes or KB/MB/GB, e.g. 10MB"),Math.round(Number(n)*i)},se=e=>{e.value===""&&I("query.missing-value",e.span)},zn=e=>{for(let r of e.operator==="range"?[e.value,e.upper]:[e.value])r!==void 0&&r!=="*"&&Rn(r,e.span)},Pn=e=>{sn(e.value)===void 0&&I("query.invalid-tag",e.span,"a tag is 1-32 letters a-z, digits and hyphens")},Fn=e=>{/^(?:person|organization|document):[1-9]\d*$/u.test(e.value)||I("query.invalid-reference",e.span,"use person:, organization: or document:, quoted")},Mn=e=>{/^\d+$/u.test(e.value)||I("query.invalid-topic",e.span,"use a thread id in one chat")},w=["term","phrase"],ze=[{name:"text",example:"invoice",index:"message_stems \u222A message_words; wildcard and regex: message_words",aliases:[],type:"txt",operators:["term","phrase","wildcard","regex"],normalization:"Snowball 3.1.1 by script (Cyrillic, Latin; the store's search_stemmers), then v1",support:"A1"},{name:"exact",example:"exact:invoice",index:"message_words",aliases:[],type:"txt",operators:["term","phrase","wildcard","regex"],normalization:"NFKD/marks/NFC/lowercase v1",support:"A1"},{name:"body",example:"body:/.*invoice.*/",index:"messages.text / bounded postfilter",aliases:[],type:"txt",operators:["term","phrase","wildcard","regex"],normalization:"raw, case-sensitive",support:"A1"},{name:"from",example:'from:"Alice Synthetic"',index:"identities / sender index",aliases:[],type:"kw",operators:w,normalization:"account-scoped resolution",support:"A1"},...["to","cc","bcc"].map(e=>({name:e,example:`${e}:"Alice Synthetic"`,index:"email_recipients",aliases:[],type:"kw",operators:w,normalization:"account-scoped resolution; mail only",support:"A1"})),{name:"subject",example:'subject:"quarterly planning"',index:"email_words, then the subject",aliases:[],type:"txt",operators:w,normalization:"every word, folded as text is; mail only",support:"A1",validate:se},{name:"mailbox",example:'mailbox:INBOX OR mailbox:"[Gmail]/Sent Mail"',index:"email_mailboxes",aliases:[],type:"kw",operators:w,normalization:"a folder or label by its id (ASCII case folded) or name (case folded in any script); mail only",support:"A1"},{name:"label",example:"label:Projects",index:"email_mailboxes",aliases:[],type:"kw",operators:w,normalization:"the same as mailbox:; mail only",support:"A1"},{name:"list",example:"list:github.com",index:"emails.headers list-id",aliases:[],type:"kw",operators:w,normalization:"the List-Id of a mailing list, lower case; a domain matches every list under it; mail only",support:"A1",validate:se},{name:"is",example:"is:unread",index:"emails.read / emails.flagged / messages.starred",aliases:[],type:"enum",operators:w,normalization:"lowercase; read and unread are mail only; starred is a flagged email or a message the owner starred; an unknown state matches neither read nor unread",support:"A1",values:["unread","read","starred"]},{name:"chat",example:'chat:"Work fixture"',index:"chats / message time index",aliases:[],type:"kw",operators:w,normalization:"account-scoped resolution",support:"A1"},{name:"date",example:"date:[2026-01-01 TO 2026-02-01}",index:"messages.sent_at",aliases:[],type:"time",operators:[...w,"range"],normalization:"ISO/calendar timezone; today, yesterday, 30m/2h/7d ago",support:"A1"},{name:"source",example:"source:internal",index:"notes (internal) / documents (file)",aliases:[],type:"enum",operators:w,normalization:"lowercase; notes only: internal is written in memo, file is from a notes folder",support:"A1",values:["internal","file"]},{name:"kind",example:"kind:private",index:"chats.kind / peerKind metadata",aliases:[],type:"enum",operators:w,normalization:"lowercase",support:"A1",values:["private","saved","bot","service","group","channel","unknown"]},{name:"has",example:"has:file",index:"attachments / messages_fts links",aliases:[],type:"enum",operators:w,normalization:"lowercase",support:"A1",values:["text","attachment","link","file","photo","image","video","audio","voice","sticker","contact","location","poll"]},{name:"topic",example:"chat:7 AND topic:42",index:"messages.thread_native_id",aliases:[],type:"kw",operators:w,normalization:"string id, one chat required",support:"A1",validate:Mn},{name:"in",example:"in:bots",index:"accounts.provider",aliases:[],type:"kw",operators:w,normalization:"lowercase provider/account class",support:"A1"},{name:"preset",example:"preset:secret",index:"bounded local candidate detector",aliases:[],type:"enum",operators:w,normalization:"versioned candidate detector",support:"A1",values:["password","code","api-key","secret","card","bank","passport","phone","email","telegram-link","url","contact","location"]},{name:"filename",example:"filename:*.pdf",index:"attachments.name / bounded postfilter",aliases:[],type:"kw",operators:[...w,"wildcard","regex"],normalization:"NFKD/marks/NFC/lowercase v1, whole name",support:"A2"},{name:"mime",example:'mime:"application/pdf" OR mime:image',index:"attachments.mime / bounded postfilter",aliases:[],type:"kw",operators:[...w,"wildcard"],normalization:"lowercase; a value without / matches the first part; only where the messenger reports a type",support:"A2"},{name:"size",example:"size>10MB",index:"attachments.size",aliases:[],type:"kw",operators:[...w,"range"],normalization:"bytes; KB/MB/GB are 1024-based",support:"A2",validate:zn},{name:"content",example:"content:invoice",index:"attachment_words",aliases:[],type:"txt",operators:w,normalization:"NFKD/marks/NFC/lowercase v1; the text of files attachments extract read or an agent wrote",support:"A2",validate:se},{name:"transcript",example:"transcript:invoice",index:"attachment_words \u222A transcript_stems; garbled spellings from transcript_words_vocab",aliases:[],type:"txt",operators:w,normalization:"any form of the word (Snowball), widened to spellings speech recognition garbles; what a voice message said",support:"A2",validate:se},...[["title",'title:"quarterly report"',"documents.metadata, then the title column","every word, folded as text is; notes and files only","txt"],["site","site:wikipedia","documents.metadata (og:site_name)","contained, folded as text is; notes and files only","kw"],["lang","lang:ru","documents.metadata (html lang)","language tag or its prefix, lowercase; notes and files only","kw"],["author","author:ivanov","documents.metadata (meta author, JSON-LD)","contained, folded as text is; notes and files only","kw"],["keyword","keyword:invoices","documents.metadata (meta keywords)","whole keyword, folded as text is; notes and files only","kw"]].map(([e,r,n,t,i])=>({name:e,example:r,index:n,aliases:[],type:i,operators:w,normalization:t,support:"A2",validate:se})),...[["phone",'phone:"8 900 000-00-01"',"a phone found in the text, written any way; a number without + is read in phone_countries"],["email","email:ana@example.com","an address found in the text, lower-cased"],["url",'url:"https://example.com/a"',"a link found in the text, without utm_*, fbclid and the fragment"],["domain","domain:google.com","the site of a link or an address in the text; docs.google.com means google.com"],["link",'link:"click?id=1"',"a part of a link, quoted; Latin letters in any case; in mail also the body of a letter with a tracking link"]].map(([e,r,n])=>({name:e,example:r,index:"mentions (kind, value) / (domain); in mail a tracking link is kept as its site",aliases:[],type:"kw",operators:w,normalization:n,support:"A2",validate:se})),{name:"mentions",example:'mentions:"person:12"',index:"mentions (target_type, target_id)",aliases:[],type:"kw",operators:w,normalization:"a person (by name, phone or address), an organization or a document, linked; quoted",support:"A2",validate:Fn},{name:"tag",example:"tag:work",index:"tags: the message, its chat or its sender",aliases:[],type:"kw",operators:w,normalization:"lowercase a-z, 0-9 and -, 1-32 characters",support:"A2",validate:Pn}],Ln={entity:"message",backend:"sql",fields:ze},un=new Set(["text","exact","transcript","content"]),Gn=e=>{for(let r of W(e.root)){let n=ze.find(({name:t})=>t===r.field);if(!n&&["after","before"].includes(r.field)){let t=["term","phrase"].includes(r.operator)&&/^[\w:.+-]+$/u.test(r.value);I("legacy_date_field",r.span,t?`use date${r.field==="after"?">=":"<"}${r.value}`:"use date>=YYYY-MM-DD or date:[a TO b]")}r.slop!==void 0&&!un.has(r.field)&&I("query.unsupported-operator",r.span,`"a b"~N takes words: ${[...un].join(", ")}`),r.slop!==void 0&&r.slop>be&&I("query.invalid-number",r.span,`words at most ${be} apart: "a b"~${be}`),n&&r.operator==="wildcard"&&!n.operators.includes("wildcard")&&I("query.unsupported-operator",r.span,`${n.name} takes ${n.operators.join(", ")}`)}return ge(e,Ln,ke)};var on=e=>e.normalize("NFKD").replace(/\p{M}+/gu,"").normalize("NFC").toLowerCase(),Un=e=>on(e).replace(/\p{Cc}/gu," ").replace(/\s+/gu," ").trim();var an={kind:"char",ranges:[[0,1114111]],negate:!1},Pe=e=>({kind:"char",ranges:[[e.codePointAt(0)??0,e.codePointAt(0)??0]],negate:!1}),Xn=(e,r={start:0,end:e.length})=>{e.length>J.pattern*2&&ee("pattern");let n=[...e];n.length>J.pattern&&ee("pattern");let t=0,i=0,s=()=>I("query.invalid-regex",r,"use the supported Lucene regex subset"),u=()=>t>=n.length?s():n[t++],c=()=>{if(n[t]!=="\\")return;let a=n[t+1]??"",p;if(a.toLowerCase()==="d"&&(p=[[48,57]]),a.toLowerCase()==="w"&&(p=[[48,57],[65,90],[95,95],[97,122]]),a.toLowerCase()==="s"&&(p=[[9,10],[13,13],[32,32]]),p)return t+=2,{kind:"char",ranges:p,negate:a===a.toUpperCase()};if(/^[a-zA-Z]$/u.test(a))return s()},l=()=>(n[t]==="\\"&&t++,u()),o=()=>{++i>J.depth&&ee("pattern depth");let a=[f()];for(;n[t]==="|";)t++,a.push(f());return i--,a.length===1?a[0]:{kind:"union",children:a}},f=()=>{let a=[];do a.push(x());while(t{let a=$();for(;["?","*","+","{"].includes(n[t]??"");){let p=u(),m=p==="+"?1:0,v=p==="?"?1:null;if(p==="{"){let g=()=>{let h=t;for(;/^[0-9]$/u.test(n[t]??"");)t++;return t===h?s():Number(n.slice(h,t).join(""))};if(m=g(),v=m,n[t]===","&&(t++,v=n[t]==="}"?null:g()),u()!=="}"||v!==null&&vJ.states||v!==null&&v>J.states)&&ee("automaton states"),a={kind:"repeat",child:a,min:m,max:v}}return a},$=()=>{let a=c();if(a)return a;let p=u();if((p==="~"||p==="<")&&I("query.unsupported-regex",r,"complement, named automata and numeric intervals are not supported"),p===".")return an;if(p==="#")return{kind:"empty"};if(p==="@")return{kind:"repeat",child:an,min:0,max:null};if(p==='"'){let m=[];for(;n[t]!=='"';)m.push(Pe(u()));return t++,{kind:"concat",children:m}}if(p==="("){if(n[t]===")")return t++,{kind:"epsilon"};n[t]==="?"&&I("query.unsupported-regex",r,"JavaScript groups and lookaround are not Lucene operators");let m=o();return u()!==")"?s():m}if(p==="["){let m=n[t]==="^";m&&t++;let v=[];do{let h=c();if(h){v.push(h);continue}let y=l().codePointAt(0)??0,b=y;if(n[t]==="-"&&(t++,b=l().codePointAt(0)??0),b(S.length>=J.states&&ee("automaton states"),S.push({epsilon:[],edges:[]}),S.length-1),_=(a,p)=>{S[a].epsilon.push(p)},T=(a,p,m)=>{if(a.kind==="char"){S[p].edges.push({to:m,atom:a});return}if(a.kind==="empty")return;if(a.kind==="epsilon"){_(p,m);return}if(a.kind==="union"){for(let g of a.children)T(g,p,m);return}if(a.kind==="concat"){let g=p;a.children.forEach((h,y)=>{let b=y===a.children.length-1?m:C();T(h,g,b),g=b}),a.children.length===0&&_(p,m);return}let v=p;for(let g=0;g{let m=()=>{++p.work>(p.maxWork??J.work)&&ee("automaton work")},v=h=>{let y=[...h];for(;y.length;){let b=y.pop();for(let q of S[b].epsilon)m(),h.has(q)||(h.add(q),y.push(q))}return h},g=v(new Set([ue]));for(let h of a){let y=h.codePointAt(0)??0,b=new Set;for(let q of g)for(let G of S[q].edges)m(),G.atom.ranges.some(([oe,ne])=>y>=oe&&y<=ne)!==G.atom.negate&&b.add(G.to);if(g=v(b),g.size===0)return!1}return g.has(k)}}},Bn=e=>{let r=[...e],n="";for(let t=0;t"~\\]/u.test(s)?`\\${s}`:s}else n+=i==="*"?".*":i==="?"?".":/[|&?*+(){}[\].#@<>"~\\]/u.test(i)?`\\${i}`:i}return n};export{ze as QUERY_FIELDS,Xn as compileAutomaton,De as dateRange,Un as normalize,qe as parseLucene,Gn as validateFields,Bn as wildcardPattern}; +var me,ln={lang:void 0,message:void 0,abortEarly:void 0,abortPipeEarly:void 0};function Fe(e){return!e&&!me?ln:{lang:e?.lang??me?.lang,message:e?.message,abortEarly:e?.abortEarly??me?.abortEarly,abortPipeEarly:e?.abortPipeEarly??me?.abortPipeEarly}}var cn;function pn(e){return cn?.get(e)}var fn;function yn(e){return fn?.get(e)}var mn;function hn(e,r){return mn?.get(e)?.get(r)}function ae(e){let r=typeof e;return r==="string"?`"${e}"`:r==="number"||r==="bigint"||r==="boolean"?`${e}`:r==="object"||r==="function"?(e&&Object.getPrototypeOf(e)?.constructor?.name)??"null":r}function E(e,r,n,t,i){let s=i&&"input"in i?i.input:n.value,u=i?.expected??e.expects??null,c=i?.received??ae(s),l={kind:e.kind,type:e.type,input:s,expected:u,received:c,message:`Invalid ${r}: ${u?`Expected ${u} but r`:"R"}eceived ${c}`,requirement:e.requirement,path:i?.path,issues:i?.issues,lang:t.lang,abortEarly:t.abortEarly,abortPipeEarly:t.abortPipeEarly},o=e.kind==="schema",f=i?.message??e.message??hn(e.reference,l.lang)??(o?yn(l.lang):null)??t.message??pn(l.lang);f!==void 0&&(l.message=typeof f=="function"?f(l):f),o&&(n.typed=!1),n.issues?n.issues.push(l):n.issues=[l]}function dn(e,r){return e===r||Number.isNaN(e)&&Number.isNaN(r)}function vn(e,r){return Object.prototype.hasOwnProperty.call(e,r)&&r!=="__proto__"&&r!=="prototype"&&r!=="constructor"}function Me(e,r){let n=[...new Set(e)];return n.length>1?`(${n.join(` ${r} `)})`:n[0]??"never"}function R(e){return e["~standard"]={version:1,vendor:"valibot",validate:r=>e["~run"]({value:r},Fe())},e}function Le(e){if(e.path){let r="";for(let n of e.path)if(typeof n.key=="string"||typeof n.key=="number")r?r+=`.${n.key}`:r+=n.key;else return null;return r}return null}var gn=/^\d{4}-(?:0[1-9]|1[0-2])-(?:[12]\d|0[1-9]|3[01])[T ](?:0\d|1\d|2[0-3])(?::[0-5]\d){2}(?:\.\d{1,9})?(?:Z| ?[+-](?:0\d|1\d|2[0-3])(?::?[0-5]\d)?)$/u;function xe(e,r){return{kind:"validation",type:"ends_with",reference:xe,async:!1,expects:`"${e}"`,requirement:e,message:r,"~run"(n,t){return n.typed&&!n.value.endsWith(this.requirement)&&E(this,"end",n,t,{received:`"${n.value.slice(-this.requirement.length)}"`}),n}}}function X(e){return{kind:"validation",type:"integer",reference:X,async:!1,expects:null,requirement:Number.isInteger,message:e,"~run"(r,n){return r.typed&&!this.requirement(r.value)&&E(this,"integer",r,n),r}}}function we(e){return{kind:"validation",type:"iso_timestamp",reference:we,async:!1,expects:null,requirement:gn,message:e,"~run"(r,n){return r.typed&&!this.requirement.test(r.value)&&E(this,"timestamp",r,n),r}}}function te(e,r){return{kind:"validation",type:"max_length",reference:te,async:!1,expects:`<=${e}`,requirement:e,message:r,"~run"(n,t){return n.typed&&n.value.length>this.requirement&&E(this,"length",n,t,{received:`${n.value.length}`}),n}}}function B(e,r){return{kind:"validation",type:"min_value",reference:B,async:!1,expects:`>=${e instanceof Date?e.toJSON():ae(e)}`,requirement:e,message:r,"~run"(n,t){return n.typed&&!(n.value>=this.requirement)&&E(this,"value",n,t,{received:n.value instanceof Date?n.value.toJSON():ae(n.value)}),n}}}function V(e,r){return{kind:"validation",type:"regex",reference:V,async:!1,expects:`${e}`,requirement:e,message:r,"~run"(n,t){return n.typed&&!this.requirement.test(n.value)&&E(this,"format",n,t),n}}}var kn={abortEarly:!0};function Ge(e,r,n){return typeof e.fallback=="function"?e.fallback(r,n):e.fallback}function _e(e,r,n){return typeof e.default=="function"?e.default(r,n):e.default}function M(e,r){return R({kind:"schema",type:"array",reference:M,expects:"Array",async:!1,item:e,message:r,"~run"(n,t){let i=n.value;if(Array.isArray(i)){n.typed=!0,n.value=[];for(let s=0;s{for(let P of x.options){if(P.type==="variant")f(P,new Set($).add(P.key));else{let S=!0,C=0;for(let _ of $){let T=P.entries[_];if(_ in s?T["~run"]({typed:!1,value:s[_]},kn).issues:T.type!=="exact_optional"&&T.type!=="optional"&&T.type!=="nullish"){S=!1,l!==_&&(ctypeof e=="object"&&e!==null&&e[Xe]===!0;var Q={bytes:8192,depth:32,nodes:256},Be=K({start:L(),end:L()}),bn=K({kind:z("predicate"),field:N(),operator:Y(["term","phrase","wildcard","regex","range"]),value:N(),upper:d(N()),lower_inclusive:d(F()),upper_inclusive:d(F()),span:Be,implicit:d(z(!0)),slop:d(A(L(),X(),B(0)))}),Ae=re("kind",[bn,K({kind:z("boolean"),clauses:M(K({occur:Y(["must","should","must_not"]),node:Ee(()=>Ae)})),span:Be})]),Ve=K({version:z(1),language:z("lucene-v1"),root:Ae});function O(e,r,n,t={},i={}){throw new H("validation_error",`${t.command??"query"}: ${e} at position ${r.start+1}${n?` \u2014 ${n}`:""}`,{reason:e,span:r,...n?{alternative:n}:{},...t.guide?{guide:t.guide}:{},...i})}var W=e=>e.kind==="predicate"?[e]:e.clauses.flatMap(({node:r})=>W(r));var fe=e=>/[ \t\n\r\u3000]/u.test(e),Oe=new Set(["+","-","!","(",")",":","=","^","@","<",">","[","]",'"',"{","}","~","\\","/"]),ve=(e,r,n)=>{let t="";for(let i=0;i=e.length&&n("query.invalid-escape",r),e[i]==="u"){let s=e.slice(i+1,i+5);/^[0-9a-fA-F]{4}$/.test(s)||n("query.invalid-escape",r),t+=String.fromCharCode(Number.parseInt(s,16)),i+=4}else t+=e[i]}return t},xn=(e,r=O)=>{let n=[],t=0,i=!1;for(;t=e.length&&r("query.unclosed-literal",{start:s,end:t},u==="/"?wn(e,s):void 0),t++,u==="/"&&/^[dgimsuvy]+(?:$|[ \t\n\r)])/.test(e.slice(t))&&r("query.unsupported-regex-flags",{start:t,end:t+1},"Lucene regex does not take JavaScript flags"),c=u==='"'?"quoted":"regex"}else if(i&&u!=="]"&&u!=="}"){for(;t")&&e[t]==="="&&(t++,c+="="),(u==="["||u==="{")&&(i=!0),(u==="]"||u==="}")&&(i=!1);else{for(t++;t=e.length&&r("query.invalid-escape",{start:t,end:t+1}),t+=2;continue}if(x==="@"&&/^@(?:\p{L}|[\p{L}\p{N}][^\s@]*\.[\p{L}\p{N}])/u.test(e.slice(t))){t++;continue}if(fe(x)||Oe.has(x)&&x!=="+"&&x!=="-")break;t++}let[l,o]=n.slice(-2);if(l?.kind==="term"&&o?.kind===":"&&o.span.end===s&&e[t]===":"&&/^[a-z][a-z_-]*$/u.test(e.slice(s,t))&&/^:[^\s()"]/u.test(e.slice(t)))for(;t{for(let n of e.matchAll(/(?<=^|[\s(])([\p{L}\p{N}_.-]+):([^\s"()]+)/gu)){let[t,i,s=""]=n;if(!(rn.index+t.length))return/[:=/?*~^@<>![\]{}\\]/u.test(s)?`put the value in quotes: ${i}:"${s}"`:void 0}},wn=(e,r)=>{let n=`${/[^\s()"]*$/u.exec(e.slice(0,r))?.[0]??""}${/^[^\s()"]*/u.exec(e.slice(r))?.[0]??""}`;return Ye(e,r)??`/ starts a regular expression; put the value in quotes: "${n}"`},qe=(e,{defaultField:r="text",proximity:n=!1,...t}={})=>{let i=(k,a,p)=>O(k,a,p??Ye(e,a.start),t);(e.length>Q.bytes||new TextEncoder().encode(e).length>Q.bytes)&&i("query.too-large",{start:0,end:e.length});let s=xn(e,i),u=0,c=0,l=0,o=()=>s[u],f=()=>s[u++],x=k=>(o().kind!==k&&i("query.invalid-syntax",o().span),f()),$=k=>(++c>Q.nodes&&i("query.too-large",k.span),k),P=(k,a)=>{let p=k[0],m=k.at(-1);return(!p||!m)&&i("query.invalid-syntax",o().span),k.length===1?p:{node:$({kind:"boolean",clauses:k.map(({node:v,modifier:g})=>({node:v,occur:g??a})),span:{start:p.node.span.start,end:m.node.span.end}})}},S=(k,a=!1)=>{++l>Q.depth&&i("query.too-large",o().span);let p=[];do p.push(C(k,a));while(!["EOF",")"].includes(o().kind));let m=P(p,"must");return l--,m.modifier==="must_not"?$({kind:"boolean",clauses:[{node:m.node,occur:"must_not"}],span:m.node.span}):m.node},C=(k,a)=>{let p=[_(k,a)];for(;o().kind==="OR";)f(),p.push(_(k,a));return P(p,"should")},_=(k,a)=>{let p=[T(k,a)];for(;o().kind==="AND";)f(),p.push(T(k,a));return P(p,"must")},T=(k,a)=>{let p;["+","-","NOT","!"].includes(o().kind)&&(p=f().kind==="+"?"must":"must_not");let m=k,v,g=a;if(o().kind==="term"&&[":","=","<",">","<=",">="].includes(s[u+1]?.kind??"")){let y=f();m=ve(y.raw,y.span,i),v=y.span.start,g=!1;let b=f();if(b.kind===":"&&["<",">","<=",">="].includes(o().kind)&&(b=f()),["<",">","<=",">="].includes(b.kind)){let q=f();["term","number","quoted"].includes(q.kind)||i("query.invalid-syntax",q.span);let G=ve(q.kind==="quoted"?q.raw.slice(1,-1):q.raw,q.span,i),U=b.kind.startsWith(">");return{node:$({kind:"predicate",field:m,operator:"range",value:U?G:"*",upper:U?"*":G,lower_inclusive:!U||b.kind.endsWith("="),upper_inclusive:U||b.kind.endsWith("="),span:{start:y.span.start,end:q.span.end}}),...p?{modifier:p}:{}}}}let h;if(o().kind==="("){let y=f().span.start;h=S(m,g);let b=x(")").span.end;h={...h,span:{start:y,end:b}}}else if(["[","{"].includes(o().kind)){let y=f(),b=f();["rangeValue","quoted"].includes(b.kind)||i("query.invalid-syntax",b.span);let q=f();q.raw!=="TO"&&i("query.invalid-syntax",q.span);let G=f();["rangeValue","quoted"].includes(G.kind)||i("query.invalid-syntax",G.span);let U=f();["]","}"].includes(U.kind)||i("query.invalid-syntax",U.span);let oe=ne=>ve(ne.kind==="quoted"?ne.raw.slice(1,-1):ne.raw,ne.span,i);h=$({kind:"predicate",field:m,operator:"range",value:oe(b),upper:oe(G),lower_inclusive:y.kind==="[",upper_inclusive:U.kind==="]",span:{start:v??y.span.start,end:U.span.end}})}else{let y=f();["term","number","quoted","regex"].includes(y.kind)||i("query.invalid-syntax",y.span);let b=["term","number"].includes(y.kind)?y.raw:y.raw.slice(1,-1);m==="fn"&&i("query.unsupported-operator",y.span,"interval functions are not supported");let q=["term","number"].includes(y.kind)&&/(?a.implicit);k&&O("query.bare-word",k.span,`"${k.value}" has no field; write field:value`,t,{word:k.value})}return{version:1,language:"lucene-v1",root:ue}};var Se=(e,r)=>{/^\d{4}-\d{2}-\d{2}$/u.test(e)||O("query.invalid-date",r,"use an ISO date or a quoted timestamp with offset");let n=Number(e.slice(0,4)),t=Number(e.slice(5,7)),i=Number(e.slice(8,10)),s=new Date(0);return s.setUTCFullYear(n,t-1,i),s.setUTCHours(0,0,0,0),(s.getUTCFullYear()!==n||s.getUTCMonth()!==t-1||s.getUTCDate()!==i)&&O("query.invalid-date",r),s},Ze=(e,r,n,t)=>{let i=Se(e,t);n&&i.setUTCDate(i.getUTCDate()+1);let s=i.getUTCFullYear()*1e4+(i.getUTCMonth()+1)*100+i.getUTCDate(),u=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit",era:"short"}),c=f=>{let x=u.formatToParts(f),$=S=>Number(x.find(C=>C.type===S)?.value);return(x.find(S=>S.type==="era")?.value==="BC"?1-$("year"):$("year"))*1e4+$("month")*100+$("day")},l=i.getTime()-2*864e5,o=i.getTime()+2*864e5;for(;l{let i=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit"}).format(n);if(e==="today")return i;let s=Se(i,t);return s.setUTCDate(s.getUTCDate()-1),s.toISOString().slice(0,10)},ie=(e,r,n,t,i,s=Date.now())=>{if(e==="*")return{inclusive:t};let u=e.toLowerCase();if(u==="today"||u==="yesterday")return ie(En(u,r,s,i),r,n,t,i);let[,c,l]=Je.exec(u)??[];if(c&&l)return{time:s-Number(c)*(_n[l]??0),inclusive:t};if(/^\d{4}-\d{2}-\d{2}$/u.test(e))return{time:Ze(e,r,n==="lower"?!t:t,i),inclusive:n==="lower"};/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/u.test(e)||O("query.invalid-date",i,"use an ISO date, today, yesterday, 30m/2h/7d ago, or a quoted timestamp with offset"),Se(e.slice(0,10),i);let o=Date.parse(e);return(!Number.isFinite(o)||Number(e.slice(11,13))>23||Number(e.slice(14,16))>59||Number(e.slice(17,19))>59)&&O("query.invalid-date",i),{time:o,inclusive:t}},De=(e,r,n,t,i,s,u=Date.now())=>{let c=e===r&&Je.test(e.toLowerCase()),l=ie(e,i,"lower",n,s,u),o=ie(c?"*":r,i,"upper",t,s,u);return{...l.time===void 0?{}:{lower:l.time},...o.time===void 0?{}:{upper:o.time},lower_inclusive:l.inclusive,upper_inclusive:o.inclusive}};var nt=A(N(),V(/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,"a lower-case word, words joined by -")),Ne=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,j=A(N(),V(/\S/,"must not be empty")),Z=A(N(),V(/^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/,"dotted lower-case words, such as `page.next`")),ye=class extends Error{registry;problems;constructor(r,n){super(`${r} registry: ${n.join("; ")}`),this.registry=r,this.problems=n,this.name="RegistryError"}},An=e=>e.map(r=>{let n=Le(r);return n?`${n}: ${r.message}`:r.message}),Qe=(e,r,n,t=()=>[])=>{let i=Ue(r,n);if(!i.success)throw new ye(e,An(i.issues));let s=t(i.output);if(s.length>0)throw new ye(e,s);return i.output},je=e=>[...new Set(e.filter((r,n)=>e.indexOf(r)!==n))].sort();var On=/\{([a-z][a-z0-9]*(?:_[a-z0-9]+)*)\}/g,We=e=>[...e.matchAll(On)].map(r=>r[1]??"");var $e=2;var Ie=A(N(),we("an ISO 8601 time in UTC"),xe("Z","an ISO 8601 time in UTC, ending in `Z`")),qn=A(N(),V(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{2}:\d{2}$/,"an ISO 8601 time with its offset")),en=A(N(),V(/^[a-z]+:\S+$/,"a reference such as `note:42`")),Ce=re("kind",[D({kind:z("command"),step:Z,command:j,args:le(N(),ce()),line:d(j),why:j,safe_to_auto_execute:F()}),D({kind:z("user_action"),step:Z,why:j,safe_to_auto_execute:z(!1)})]),st=D({field:j,why:j,step:d(Z)}),Ke=A(L(),X(),B(1)),He=D({value:A(L(),X(),B(0)),relation:Y(["eq","gte"])}),Sn=re("mode",[D({mode:z("page"),limit:Ke,has_more:F(),next_page:d(A(L(),X(),B(2))),total:d(He)}),D({mode:z("cursor"),limit:Ke,has_more:F(),next_cursor:d(j),total:d(He)})]),nn=D({code:Y(pe),reason:d(Z),source:j}),ut=D({run_id:j,duration_ms:A(L(),X(),B(0)),accounts:d(M(j)),complete:F(),issues:d(M(nn)),truncated:d(F()),timezone:d(j),now:d(Ie),now_local:d(qn),window:d(D({since:d(Ie),until:d(Ie)}))});var ot=d(A(M(Ce),te($e)));var at=D({type:z("end"),complete:F(),issues:d(M(nn)),page:Sn});var pt=en.pipe[1].requirement.source;var Te="internal_error",Dn="command.crashed",vt=D({error:D({code:Y([...pe,Te]),reason:Z,message:j,param:d(j),details:d(le(N(),ce())),next:d(A(M(Ce),te($e))),retry:D({safe:F(),after_ms:d(A(L(),X(),B(0)))}),run_id:d(j)})}),Nn=D({reason:Z,code:Y([...pe,Te]),message:A(j,te(120)),details:M(A(N(),V(Ne,"a snake_case key"))),step:d(Z)}),Re=e=>Qe("error reasons",M(Nn),e,r=>[...je(r.map(n=>n.reason)).map(n=>`"${n}" is listed twice`),...r.flatMap(n=>We(n.message).filter(t=>!n.details.includes(t)).map(t=>`${n.reason}: the message names {${t}}, which is not one of its details`))]);var gt=Re([{reason:"input.invalid",code:"validation_error",message:"the input is not valid",details:[]},{reason:"batch.read-budget",code:"validation_error",message:"batch stored-text read budget exhausted",details:[]},{reason:"batch.output-budget",code:"validation_error",message:"batch output budget exhausted",details:[]},{reason:"config.invalid",code:"configuration_error",message:"the configuration is not valid",details:[]},{reason:"auth.failed",code:"authentication_error",message:"the sign-in did not work",details:[]},{reason:"access.denied",code:"permission_error",message:"this account may not do that",details:[]},{reason:"item.not-found",code:"not_found",message:"nothing found by that name",details:[]},{reason:"tool.not-installed",code:"not_found",message:"no wcat- program by that name is on PATH",details:["tool","installed"]},{reason:"confirmation.required",code:"confirmation_required",message:"this changes something; confirm it",details:[]},{reason:"provider.rate-limited",code:"rate_limited",message:"too many requests; wait",details:[]},{reason:"command.timed-out",code:"timeout",message:"the command took too long",details:["timeout_ms"]},{reason:"network.failed",code:"network_error",message:"the network did not answer",details:[]},{reason:"provider.refused",code:"provider_error",message:"the provider refused",details:[]},{reason:"provider.unavailable",code:"provider_unavailable",message:"the provider is down",details:[]},{reason:"provider.invalid-response",code:"invalid_response",message:"the answer could not be read",details:[]},{reason:"output.too-large",code:"invalid_response",message:"the output is over {max_bytes} bytes",details:["max_bytes","buffered_bytes","partial_output"]},{reason:"output.fields-unavailable",code:"invalid_response",message:"fields can be picked only from whole JSON values",details:[]},{reason:"outcome.unknown",code:"outcome_unknown",message:"it is not known whether it worked",details:[]},{reason:"write.conflict",code:"conflict",message:"it changed since it was read; read it again",details:[]},{reason:"command.cancelled",code:"cancelled",message:"the command was cancelled",details:[]},{reason:Dn,code:Te,message:"the command failed; this is a bug",details:[]}]);var rn=(e,r)=>{try{r()}catch(n){if(!de(n)||typeof n.details.reason!="string"||n.details.span===void 0)throw n;let{reason:t,span:i,alternative:s}=n.details;O(t,i,s,e)}},tn=e=>e.operator==="range"?[e.value,e.upper??"*"].filter(r=>r!=="*"):[e.value],jn=(e,r,n)=>{let t=(i,s)=>O(i,r.span,s,n);if(r.value===""&&e.type!=="txt"&&t("query.missing-value"),r.operator!=="wildcard")switch(e.type){case"enum":e.values?.includes(r.value.toLowerCase())||t("query.unknown-value",`${e.name} takes ${e.values?.join(", ")}`);return;case"bool":["true","false"].includes(r.value.toLowerCase())||t("query.unknown-value",`${e.name} takes true, false`);return;case"num":for(let i of tn(r))(!Number.isFinite(Number(i))||i.trim()==="")&&t("query.invalid-number",`${e.name} takes a number`);return;case"time":rn(n,()=>{for(let i of tn(r))ie(i,n.zone??"UTC","lower",!0,r.span)});return;default:return}},ge=(e,r,n={})=>{let t=new Map(r.fields.map(s=>[s.name,s])),i=(s,u)=>{if(s.kind==="boolean"){for(let o of s.clauses)i(o.node,u&&o.occur==="must");return}let c=t.get(s.field);c||O("query.unknown-field",s.span,`no field "${s.field}"`,n,{fields:r.fields.map(o=>o.name)}),r.backend==="native"&&!c.native&&O("query.unsupported-field",s.span,`the source cannot filter by ${c.name}`,n,{supported:r.fields.filter(o=>o.native).map(o=>o.name)});let l=s.operator==="wildcard"&&s.value==="*";!l&&!c.operators.includes(s.operator)&&O("query.unsupported-operator",s.span,`${c.name} takes ${c.operators.join(", ")}`,n),c.placement==="and"&&!u&&O("query.unsupported-placement",s.span,`${c.name} only as a required term, not under OR or NOT`,n),!l&&(jn(c,s,n),c.validate&&rn(n,()=>c.validate?.(s)))};return i(e.root,!0),e};var In=["span","alternative","guide"],$n=Re([["query.bare-word","a word in the query has no field",["word"]],["query.invalid-ast","the query tree is not valid",[]],["query.invalid-date","a date in the query cannot be read",[]],["query.invalid-escape","an escape in the query is not valid",[]],["query.invalid-number","a number in the query cannot be read",[]],["query.invalid-regex","a regular expression in the query is not valid",[]],["query.invalid-syntax","the query cannot be parsed",[]],["query.invalid-timezone","the time zone is not known",[]],["query.missing-value","a field in the query has no value",[]],["query.too-large","the query is over one of its limits",[]],["query.unclosed-literal","a quote or bracket in the query is not closed",[]],["query.unknown-field","a field in the query is not known",["fields"]],["query.unknown-value","a value in the query is not known",[]],["query.unsupported-field","this list cannot filter by that field",["supported"]],["query.unsupported-operator","this field does not take that operator",[]],["query.unsupported-placement","this field works only as a required term",[]],["query.unsupported-regex","that regular expression is not supported",[]],["query.unsupported-regex-flags","regular expression flags are not supported",[]],["query.unsupported-version","the query version is not supported",[]]].map(([e,r,n])=>({reason:e,code:"validation_error",message:r,details:[...In,...n]})));var Cn=/^[a-z0-9-]{1,32}$/,sn=e=>{let r=e.trim().toLowerCase();return Cn.test(r)?r:void 0};var J={...Q,pattern:1024,states:1e4,expansions:1e4,candidates:5e4,bodyBytes:8388608,milliseconds:2e3,work:1e7},ke={command:"search",guide:"https://github.com/WireCatLabs/cli-core/blob/main/docs/search/query-language.md"},pr={...ke,proximity:!0},be=50;function I(e,r,n){O(e,r,n,ke)}function ee(e){throw new H("validation_error",`search exceeded its ${e} budget \u2014 narrow the chat or date range`,{reason:"query.too-large",budget:e,complete:!1})}var Tn={"":1,b:1,k:1024,kb:1024,m:1024**2,mb:1024**2,g:1024**3,gb:1024**3},Rn=(e,r)=>{let[,n,t]=/^(\d+(?:\.\d+)?)\s*([a-z]*)$/iu.exec(e.trim())??[],i=Tn[t?.toLowerCase()??""];return(n===void 0||i===void 0)&&I("query.invalid-size",r,"use bytes or KB/MB/GB, e.g. 10MB"),Math.round(Number(n)*i)},se=e=>{e.value===""&&I("query.missing-value",e.span)},zn=e=>{for(let r of e.operator==="range"?[e.value,e.upper]:[e.value])r!==void 0&&r!=="*"&&Rn(r,e.span)},Pn=e=>{sn(e.value)===void 0&&I("query.invalid-tag",e.span,"a tag is 1-32 letters a-z, digits and hyphens")},Fn=e=>{/^(?:person|organization|document):[1-9]\d*$/u.test(e.value)||I("query.invalid-reference",e.span,"use person:, organization: or document:, quoted")},Mn=e=>{/^\d+$/u.test(e.value)||I("query.invalid-topic",e.span,"use a thread id in one chat")},w=["term","phrase"],ze=[{name:"text",example:"invoice",index:"message_stems \u222A message_words; wildcard and regex: message_words",aliases:[],type:"txt",operators:["term","phrase","wildcard","regex"],normalization:"Snowball 3.1.1 by script (Cyrillic, Latin; the store's search_stemmers), then v1",support:"A1"},{name:"exact",example:"exact:invoice",index:"message_words",aliases:[],type:"txt",operators:["term","phrase","wildcard","regex"],normalization:"NFKD/marks/NFC/lowercase v1",support:"A1"},{name:"body",example:"body:/.*invoice.*/",index:"messages.text / bounded postfilter",aliases:[],type:"txt",operators:["term","phrase","wildcard","regex"],normalization:"raw, case-sensitive",support:"A1"},{name:"from",example:'from:"Alice Synthetic"',index:"identities / sender index",aliases:[],type:"kw",operators:w,normalization:"account-scoped resolution",support:"A1"},...["to","cc","bcc"].map(e=>({name:e,example:`${e}:"Alice Synthetic"`,index:"email_recipients",aliases:[],type:"kw",operators:w,normalization:"account-scoped resolution; mail only",support:"A1"})),{name:"subject",example:'subject:"quarterly planning"',index:"email_words, then the subject",aliases:[],type:"txt",operators:w,normalization:"every word, folded as text is; mail only",support:"A1",validate:se},{name:"mailbox",example:'mailbox:INBOX OR mailbox:"[Gmail]/Sent Mail"',index:"email_mailboxes",aliases:[],type:"kw",operators:w,normalization:"a folder or label by its id (ASCII case folded) or name (case folded in any script); mail only",support:"A1"},{name:"label",example:"label:Projects",index:"email_mailboxes",aliases:[],type:"kw",operators:w,normalization:"the same as mailbox:; mail only",support:"A1"},{name:"list",example:"list:github.com",index:"emails.headers list-id",aliases:[],type:"kw",operators:w,normalization:"the List-Id of a mailing list, lower case; a domain matches every list under it; mail only",support:"A1",validate:se},{name:"is",example:"is:unread",index:"emails.read / emails.flagged / messages.starred",aliases:[],type:"enum",operators:w,normalization:"lowercase; read and unread are mail only; starred is a flagged email or a message the owner starred; an unknown state matches neither read nor unread",support:"A1",values:["unread","read","starred"]},{name:"chat",example:'chat:"Work fixture"',index:"chats / message time index",aliases:[],type:"kw",operators:w,normalization:"account-scoped resolution",support:"A1"},{name:"date",example:"date:[2026-01-01 TO 2026-02-01}",index:"messages.sent_at",aliases:[],type:"time",operators:[...w,"range"],normalization:"ISO/calendar timezone; today, yesterday, 30m/2h/7d ago",support:"A1"},{name:"source",example:"source:internal",index:"notes (internal) / documents (file)",aliases:[],type:"enum",operators:w,normalization:"lowercase; notes only: internal is written in memo, file is from a notes folder",support:"A1",values:["internal","file"]},{name:"kind",example:"kind:private",index:"chats.kind / peerKind metadata",aliases:[],type:"enum",operators:w,normalization:"lowercase",support:"A1",values:["private","saved","bot","service","group","channel","unknown"]},{name:"has",example:"has:file",index:"attachments / messages_fts links / message_transcripts",aliases:[],type:"enum",operators:w,normalization:"lowercase",support:"A1",values:["text","attachment","link","file","photo","image","video","audio","voice","sticker","contact","location","poll","transcript"]},{name:"topic",example:"chat:7 AND topic:42",index:"messages.thread_native_id",aliases:[],type:"kw",operators:w,normalization:"string id, one chat required",support:"A1",validate:Mn},{name:"in",example:"in:bots",index:"accounts.provider",aliases:[],type:"kw",operators:w,normalization:"lowercase provider/account class",support:"A1"},{name:"preset",example:"preset:secret",index:"bounded local candidate detector",aliases:[],type:"enum",operators:w,normalization:"versioned candidate detector",support:"A1",values:["password","code","api-key","secret","card","bank","passport","phone","email","telegram-link","url","contact","location"]},{name:"filename",example:"filename:*.pdf",index:"attachments.name / bounded postfilter",aliases:[],type:"kw",operators:[...w,"wildcard","regex"],normalization:"NFKD/marks/NFC/lowercase v1, whole name",support:"A2"},{name:"mime",example:'mime:"application/pdf" OR mime:image',index:"attachments.mime / bounded postfilter",aliases:[],type:"kw",operators:[...w,"wildcard"],normalization:"lowercase; a value without / matches the first part; only where the messenger reports a type",support:"A2"},{name:"size",example:"size>10MB",index:"attachments.size",aliases:[],type:"kw",operators:[...w,"range"],normalization:"bytes; KB/MB/GB are 1024-based",support:"A2",validate:zn},{name:"content",example:"content:invoice",index:"attachment_words",aliases:[],type:"txt",operators:w,normalization:"NFKD/marks/NFC/lowercase v1; the text of files attachments extract read or an agent wrote",support:"A2",validate:se},{name:"transcript",example:"transcript:invoice",index:"attachment_words \u222A transcript_stems; garbled spellings from transcript_words_vocab",aliases:[],type:"txt",operators:w,normalization:"any form of the word (Snowball), widened to spellings speech recognition garbles; what a voice message said",support:"A2",validate:se},...[["title",'title:"quarterly report"',"documents.metadata, then the title column","every word, folded as text is; notes and files only","txt"],["site","site:wikipedia","documents.metadata (og:site_name)","contained, folded as text is; notes and files only","kw"],["lang","lang:ru","documents.metadata (html lang)","language tag or its prefix, lowercase; notes and files only","kw"],["author","author:ivanov","documents.metadata (meta author, JSON-LD)","contained, folded as text is; notes and files only","kw"],["keyword","keyword:invoices","documents.metadata (meta keywords)","whole keyword, folded as text is; notes and files only","kw"]].map(([e,r,n,t,i])=>({name:e,example:r,index:n,aliases:[],type:i,operators:w,normalization:t,support:"A2",validate:se})),...[["phone",'phone:"8 900 000-00-01"',"a phone found in the text, written any way; a number without + is read in phone_countries"],["email","email:ana@example.com","an address found in the text, lower-cased"],["url",'url:"https://example.com/a"',"a link found in the text, without utm_*, fbclid and the fragment"],["domain","domain:google.com","the site of a link or an address in the text; docs.google.com means google.com"],["link",'link:"click?id=1"',"a part of a link, quoted; Latin letters in any case; in mail also the body of a letter with a tracking link"]].map(([e,r,n])=>({name:e,example:r,index:"mentions (kind, value) / (domain); in mail a tracking link is kept as its site",aliases:[],type:"kw",operators:w,normalization:n,support:"A2",validate:se})),{name:"mentions",example:'mentions:"person:12"',index:"mentions (target_type, target_id)",aliases:[],type:"kw",operators:w,normalization:"a person (by name, phone or address), an organization or a document, linked; quoted",support:"A2",validate:Fn},{name:"tag",example:"tag:work",index:"tags: the message, its chat or its sender",aliases:[],type:"kw",operators:w,normalization:"lowercase a-z, 0-9 and -, 1-32 characters",support:"A2",validate:Pn}],Ln={entity:"message",backend:"sql",fields:ze},un=new Set(["text","exact","transcript","content"]),Gn=e=>{for(let r of W(e.root)){let n=ze.find(({name:t})=>t===r.field);if(!n&&["after","before"].includes(r.field)){let t=["term","phrase"].includes(r.operator)&&/^[\w:.+-]+$/u.test(r.value);I("legacy_date_field",r.span,t?`use date${r.field==="after"?">=":"<"}${r.value}`:"use date>=YYYY-MM-DD or date:[a TO b]")}r.slop!==void 0&&!un.has(r.field)&&I("query.unsupported-operator",r.span,`"a b"~N takes words: ${[...un].join(", ")}`),r.slop!==void 0&&r.slop>be&&I("query.invalid-number",r.span,`words at most ${be} apart: "a b"~${be}`),n&&r.operator==="wildcard"&&!n.operators.includes("wildcard")&&I("query.unsupported-operator",r.span,`${n.name} takes ${n.operators.join(", ")}`)}return ge(e,Ln,ke)};var on=e=>e.normalize("NFKD").replace(/\p{M}+/gu,"").normalize("NFC").toLowerCase(),Un=e=>on(e).replace(/\p{Cc}/gu," ").replace(/\s+/gu," ").trim();var an={kind:"char",ranges:[[0,1114111]],negate:!1},Pe=e=>({kind:"char",ranges:[[e.codePointAt(0)??0,e.codePointAt(0)??0]],negate:!1}),Xn=(e,r={start:0,end:e.length})=>{e.length>J.pattern*2&&ee("pattern");let n=[...e];n.length>J.pattern&&ee("pattern");let t=0,i=0,s=()=>I("query.invalid-regex",r,"use the supported Lucene regex subset"),u=()=>t>=n.length?s():n[t++],c=()=>{if(n[t]!=="\\")return;let a=n[t+1]??"",p;if(a.toLowerCase()==="d"&&(p=[[48,57]]),a.toLowerCase()==="w"&&(p=[[48,57],[65,90],[95,95],[97,122]]),a.toLowerCase()==="s"&&(p=[[9,10],[13,13],[32,32]]),p)return t+=2,{kind:"char",ranges:p,negate:a===a.toUpperCase()};if(/^[a-zA-Z]$/u.test(a))return s()},l=()=>(n[t]==="\\"&&t++,u()),o=()=>{++i>J.depth&&ee("pattern depth");let a=[f()];for(;n[t]==="|";)t++,a.push(f());return i--,a.length===1?a[0]:{kind:"union",children:a}},f=()=>{let a=[];do a.push(x());while(t{let a=$();for(;["?","*","+","{"].includes(n[t]??"");){let p=u(),m=p==="+"?1:0,v=p==="?"?1:null;if(p==="{"){let g=()=>{let h=t;for(;/^[0-9]$/u.test(n[t]??"");)t++;return t===h?s():Number(n.slice(h,t).join(""))};if(m=g(),v=m,n[t]===","&&(t++,v=n[t]==="}"?null:g()),u()!=="}"||v!==null&&vJ.states||v!==null&&v>J.states)&&ee("automaton states"),a={kind:"repeat",child:a,min:m,max:v}}return a},$=()=>{let a=c();if(a)return a;let p=u();if((p==="~"||p==="<")&&I("query.unsupported-regex",r,"complement, named automata and numeric intervals are not supported"),p===".")return an;if(p==="#")return{kind:"empty"};if(p==="@")return{kind:"repeat",child:an,min:0,max:null};if(p==='"'){let m=[];for(;n[t]!=='"';)m.push(Pe(u()));return t++,{kind:"concat",children:m}}if(p==="("){if(n[t]===")")return t++,{kind:"epsilon"};n[t]==="?"&&I("query.unsupported-regex",r,"JavaScript groups and lookaround are not Lucene operators");let m=o();return u()!==")"?s():m}if(p==="["){let m=n[t]==="^";m&&t++;let v=[];do{let h=c();if(h){v.push(h);continue}let y=l().codePointAt(0)??0,b=y;if(n[t]==="-"&&(t++,b=l().codePointAt(0)??0),b(S.length>=J.states&&ee("automaton states"),S.push({epsilon:[],edges:[]}),S.length-1),_=(a,p)=>{S[a].epsilon.push(p)},T=(a,p,m)=>{if(a.kind==="char"){S[p].edges.push({to:m,atom:a});return}if(a.kind==="empty")return;if(a.kind==="epsilon"){_(p,m);return}if(a.kind==="union"){for(let g of a.children)T(g,p,m);return}if(a.kind==="concat"){let g=p;a.children.forEach((h,y)=>{let b=y===a.children.length-1?m:C();T(h,g,b),g=b}),a.children.length===0&&_(p,m);return}let v=p;for(let g=0;g{let m=()=>{++p.work>(p.maxWork??J.work)&&ee("automaton work")},v=h=>{let y=[...h];for(;y.length;){let b=y.pop();for(let q of S[b].epsilon)m(),h.has(q)||(h.add(q),y.push(q))}return h},g=v(new Set([ue]));for(let h of a){let y=h.codePointAt(0)??0,b=new Set;for(let q of g)for(let G of S[q].edges)m(),G.atom.ranges.some(([oe,ne])=>y>=oe&&y<=ne)!==G.atom.negate&&b.add(G.to);if(g=v(b),g.size===0)return!1}return g.has(k)}}},Bn=e=>{let r=[...e],n="";for(let t=0;t"~\\]/u.test(s)?`\\${s}`:s}else n+=i==="*"?".*":i==="?"?".":/[|&?*+(){}[\].#@<>"~\\]/u.test(i)?`\\${i}`:i}return n};export{ze as QUERY_FIELDS,Xn as compileAutomaton,De as dateRange,Un as normalize,qe as parseLucene,Gn as validateFields,Bn as wildcardPattern}; diff --git a/scripts/docs-corrections.json b/scripts/docs-corrections.json index f0e7c003..95c38346 100644 --- a/scripts/docs-corrections.json +++ b/scripts/docs-corrections.json @@ -2799,5 +2799,30 @@ } ] } + }, + { + "tool": "memo", + "slug": "import", + "reason": "memo search takes a resource and a query; on 0.135.0 an imported document is found by `memo search notes --source import:` (checked in a throwaway home), and bare `memo search --source` is refused as an unknown option.", + "replacements": { + "en": [ + { + "before": "`memo search --source import:handbook`", + "after": "`memo search notes budget --source import:handbook`" + } + ], + "ru": [ + { + "before": "`memo search --source import:handbook`", + "after": "`memo search notes budget --source import:handbook`" + } + ], + "es": [ + { + "before": "`memo search --source import:handbook`", + "after": "`memo search notes budget --source import:handbook`" + } + ] + } } ] diff --git a/tools.json b/tools.json index a489657b..cdcbc803 100644 --- a/tools.json +++ b/tools.json @@ -102,7 +102,7 @@ "ru": "Заметки, почта и сообщения в одном месте для вашего ИИ-агента: поиск, теги, люди и память, на вашем компьютере.", "es": "Tus notas, correo y mensajes en un solo lugar para tu agente de IA: búsqueda, etiquetas, personas y recuerdos, en tu ordenador." }, - "docsRef": "v0.131.87", + "docsRef": "v0.135.0", "profile": false }, { diff --git a/translations/memo/changelog.es.md b/translations/memo/changelog.es.md index f4e538f8..3f02f173 100644 --- a/translations/memo/changelog.es.md +++ b/translations/memo/changelog.es.md @@ -8,6 +8,133 @@ la API. Las notas técnicas exactas de las nuevas versiones se conservan en inglés; las instrucciones de uso están traducidas en sus guías. +## 0.135.0 — 14.11.2026 + +### Changed — may break callers + +- **`memo search meetings` without `--limit` shows 20 hits, not 100** (cli-core 0.663.0). The page now comes from + the shared default limit, as other lists do. Pass `--limit` for a longer page. +- **Meeting time flags take one grammar** (cli-core 0.663.0). `memo meetings prepare` and `memo search meetings` + take an ISO date or time with or without seconds and zone, a date alone, `today`, or `30m`, `2h`, `7d` ago; a time + without a zone reads the computer's zone. A `memo tasks update --due` or `--remind-time` date alone is that day. + +## 0.134.0 — 14.11.2026 + +### Changed — may break callers + +- **Dates in list queries read the computer's zone, and a due date alone is the end of that day** (cli-core + 0.661.0). `today` and a bare date in `memo tasks list` and the other list queries started in UTC, and now start + at local midnight, as search and the digest do. `memo tasks update --due 2026-11-20` sets the end of the 20th, so + the task is not overdue all that day. +- **`memo folders add` picks a new folder's format when `--format` is not given.** A folder with Obsidian's own + `.obsidian` folder in it or above it is `obsidian`, any other folder `markdown`; before, every folder was + `obsidian`, so a `#word` in plain Markdown became a tag. The `--json` answer names where the format came from + (`format_from`: `detected`, `option` or `saved`). `--format` still wins, and a folder memo already knows keeps + its format. A bare path written before folder ids counts as never chosen, so it is detected too. + See [Add a folder](./notes.md#add-a-folder). +- **`memo folders add` refuses a folder inside or around one memo already reads.** Each file under both would be + two notes. The `validation_error` names both folders, with reason `folder.overlap`; `memo doctor` reports such a + pair in an existing config. See [Add a folder](./notes.md#add-a-folder). +- **A `readonly` level no longer stops a sync** (cli-core 0.662.0, was 0.661.0). A command that only fetches from a + service into the local store runs at `readonly`; `deny` still refuses it. Commands that write the owner's files or + call another service stay blocked by `readonly`. +- **`memo models ai check` counts as reaching another service** (cli-core 0.662.0), so `readonly` stops its paid + request to the model provider. + +### Fixed + +- **`memo documents show` says more text follows after emoji** (cli-core 0.661.0). `has_more` compared a length in + UTF-16 units with one in code points, so a part holding emoji could report no more text before the end, and + WireCat Desktop's "Show more" disappeared early. `text_offset`, `text_length`, `--cursor` and `--max-chars` all + count Unicode code points. +- **Changing a folder's format reads its notes again.** After `memo folders add --format` or `memo folders update + --format` with another format, the next `memo sync --only notes` parses every note of that folder again, even + unchanged ones, so tags and links read in the old format are replaced. See + [Markdown or Obsidian](./notes.md#markdown-or-obsidian). + +## 0.133.0 — 14.11.2026 + +### Added + +- **`memo documents list`, `show` and `tree`: every document of every account.** Drive files, notes folders, + sources added by hand and imports in one paged list with a total, newest change first, each with its source, + folder, kind, size, link and whether its text is stored; narrowed by source, kind, folder, edit time, tag, person + and words of its text. `tree` gives each account's folder tree with counts. + See [usage](./usage.md#every-document). +- **`memo meetings list` and `show`: meetings, calls and calendar events as one row per real meeting.** A calendar + event and its Zoom meeting are one row; each row names its sources, participants with their person refs, join + links, recording, transcript and summary flags, linked documents and findings waiting for you. A window is read by + overlap (`started_at:`, by days or by instants with their offset), latest first or oldest first (`--order start`). + `show` adds the transcript lines with their times. See [usage](./usage.md#meetings-and-calls-in-one-list). + +## 0.132.0 — 13.11.2026 + +### Added + +- **`memo import` brings a folder of documents, transcripts and recordings, or a records file, into memo's search.** + Text, Markdown, PDF and Word files, `.vtt` and `.srt` transcripts and, with `--transcribe`, recordings heard by the + local speech model each become a document of the account you name, `--account import:` or + `phone:`, keyed by its path in the folder: the same folder twice changes nothing, an edited file updates + its own document, a recording is heard once, and a file gone from the folder is kept. A `.json` or `.jsonl` file + goes to the records import. Links are not followed, nothing leaves the computer, and `--dry-run` writes nothing + ([Import files and records](./import.md)). +- **`memo sources add` keeps meeting transcripts.** A `.vtt` (WebVTT) or `.srt` (SubRip) file exported from a video + call is kept as searchable text, one `Name: text` line per turn without the timings; before, it was refused as + `source.unsupported`. WireCat Desktop's "Add to memory" takes them too + ([Sources you add by hand](./sources.md#add-a-source)). +- **An agent over MCP may run a schedule you made.** `schedule list`, `agents list`, `run` and `exec` are offered, as + in every WireCat CLI. Making, removing, pausing or resuming a schedule needs `mcp.authority`, which defaults to + `deny`. See [MCP](./mcp.md). +- **`memo context` lists the recorded calls and meetings a person took part in, in `meetings`**, beside `events`: + each with its `meeting:` ref, account, title, start, length and whether it has a transcript. `meetings show` of the + CLI that owns the account opens one. From cli-core 0.650.0, which also links a call to the CRM contact with the same + phone. + +### Changed — may break callers + +- **`memo projects meetings link --fingerprint` with a stale fingerprint answers `conflict`, not + `configuration_error`** (reason `meeting-project.stale`). From cli-core 0.651.0. A script that checks the code + checks `conflict`, lists the proposals again and links with the new fingerprint. +- **memo needs `@wirecat/cli-core` 0.649.0**, which adds the `document` record type and the import-only provider + `import`, and lets search read the documents of import-only accounts. +- **`memo stats tasks show` has no `--chat` any more: name the chat in the query, `-- chat:7`.** From cli-core + 0.648.0, as in tg and MAX. A chat with no account named is still refused. +- **Built on cli-core 0.656.0** (was 0.651.0). See the + [cli-core changelog](https://github.com/WireCatLabs/cli-core/blob/main/CHANGELOG.md). +- **A model address WireCat refuses now answers the reason `model.address-refused`, not `ai.address-refused`.** From + cli-core 0.650.0, in `memo models ai set`, `memo answers create --analyze` and every other call to a model. A + script that checks the old name checks the new one. + +### Fixed + +- **`memo review show --compact` prints the proposal as one line**, as `review` lists it: id, kind, title, score, + who proposed it and the day. It printed the same `key: value` lines as without `--compact`. +- **`memo review confirm` and `reject --compact` print one line per decision and one per refusal**, under + `# decided: N` and `# refused: N`. They printed only the counts. +- **`memo projects meetings link --fingerprint` keeps your `--reason` when you confirm an agent's proposed link.** The + agent's reason stayed. From cli-core 0.651.0. +- **`memo notes add --export` writes the note's first `--subject` as a link in the file too**, as it does every later + one. The file named only the others. `notes edit --export` and `notes export` still leave it out: the store does not + return a note's first subject yet. +- **The sync health of the digest no longer credits a schedule with no profile to one named `default`.** A tg, MAX or + WhatsApp sync timer that names no profile, in its arguments or its environment, now counts for no account, so a + profile called `default` is never picked for you. +- **A release with new commands or a breaking change gets a new minor version.** `bin/release` raised only the patch + number, so 0.131.86 and 0.131.87 shipped new commands as patches. +- **`memo mcp --help` no longer speaks of "this profile".** Memo has no profiles; it serves memo's commands. +- **`memo sync` finishes when the shared WireCat config starts with a byte-order mark.** A + `~/.config/WireCat/config.json` saved by a Windows editor made the meaning-search step fail with "not valid JSON", + so the sync ended incomplete. A config that cannot be read at all also no longer counts as the "read only" setup + answer (cli-core 0.656.0). +- **`memo store recover run --json` prints JSON.** It printed the text report: `store recover` has a `--json` of its + own, and it took the flag. A script or WireCat Desktop reading the answer now gets the JSON object. + +### Security + +- **`sources suggest` reaches only the hosts of the readers.** Its Ollama and API readers go through the host check: + OpenAI's and Anthropic's APIs, this computer, and the addresses you set for Ollama and for the shared AI model. A + local model may take up to 15 minutes on one source. + ## 0.131.87 — 12.11.2026 ### Added diff --git a/translations/memo/changelog.ru.md b/translations/memo/changelog.ru.md index cbd038d9..5d05203f 100644 --- a/translations/memo/changelog.ru.md +++ b/translations/memo/changelog.ru.md @@ -8,6 +8,133 @@ title: "История изменений" Точные технические записи новых выпусков сохранены на английском; инструкции по использованию переведены в соответствующих руководствах. +## 0.135.0 — 14.11.2026 + +### Changed — may break callers + +- **`memo search meetings` without `--limit` shows 20 hits, not 100** (cli-core 0.663.0). The page now comes from + the shared default limit, as other lists do. Pass `--limit` for a longer page. +- **Meeting time flags take one grammar** (cli-core 0.663.0). `memo meetings prepare` and `memo search meetings` + take an ISO date or time with or without seconds and zone, a date alone, `today`, or `30m`, `2h`, `7d` ago; a time + without a zone reads the computer's zone. A `memo tasks update --due` or `--remind-time` date alone is that day. + +## 0.134.0 — 14.11.2026 + +### Changed — may break callers + +- **Dates in list queries read the computer's zone, and a due date alone is the end of that day** (cli-core + 0.661.0). `today` and a bare date in `memo tasks list` and the other list queries started in UTC, and now start + at local midnight, as search and the digest do. `memo tasks update --due 2026-11-20` sets the end of the 20th, so + the task is not overdue all that day. +- **`memo folders add` picks a new folder's format when `--format` is not given.** A folder with Obsidian's own + `.obsidian` folder in it or above it is `obsidian`, any other folder `markdown`; before, every folder was + `obsidian`, so a `#word` in plain Markdown became a tag. The `--json` answer names where the format came from + (`format_from`: `detected`, `option` or `saved`). `--format` still wins, and a folder memo already knows keeps + its format. A bare path written before folder ids counts as never chosen, so it is detected too. + See [Add a folder](./notes.md#add-a-folder). +- **`memo folders add` refuses a folder inside or around one memo already reads.** Each file under both would be + two notes. The `validation_error` names both folders, with reason `folder.overlap`; `memo doctor` reports such a + pair in an existing config. See [Add a folder](./notes.md#add-a-folder). +- **A `readonly` level no longer stops a sync** (cli-core 0.662.0, was 0.661.0). A command that only fetches from a + service into the local store runs at `readonly`; `deny` still refuses it. Commands that write the owner's files or + call another service stay blocked by `readonly`. +- **`memo models ai check` counts as reaching another service** (cli-core 0.662.0), so `readonly` stops its paid + request to the model provider. + +### Fixed + +- **`memo documents show` says more text follows after emoji** (cli-core 0.661.0). `has_more` compared a length in + UTF-16 units with one in code points, so a part holding emoji could report no more text before the end, and + WireCat Desktop's "Show more" disappeared early. `text_offset`, `text_length`, `--cursor` and `--max-chars` all + count Unicode code points. +- **Changing a folder's format reads its notes again.** After `memo folders add --format` or `memo folders update + --format` with another format, the next `memo sync --only notes` parses every note of that folder again, even + unchanged ones, so tags and links read in the old format are replaced. See + [Markdown or Obsidian](./notes.md#markdown-or-obsidian). + +## 0.133.0 — 14.11.2026 + +### Added + +- **`memo documents list`, `show` and `tree`: every document of every account.** Drive files, notes folders, + sources added by hand and imports in one paged list with a total, newest change first, each with its source, + folder, kind, size, link and whether its text is stored; narrowed by source, kind, folder, edit time, tag, person + and words of its text. `tree` gives each account's folder tree with counts. + See [usage](./usage.md#every-document). +- **`memo meetings list` and `show`: meetings, calls and calendar events as one row per real meeting.** A calendar + event and its Zoom meeting are one row; each row names its sources, participants with their person refs, join + links, recording, transcript and summary flags, linked documents and findings waiting for you. A window is read by + overlap (`started_at:`, by days or by instants with their offset), latest first or oldest first (`--order start`). + `show` adds the transcript lines with their times. See [usage](./usage.md#meetings-and-calls-in-one-list). + +## 0.132.0 — 13.11.2026 + +### Added + +- **`memo import` brings a folder of documents, transcripts and recordings, or a records file, into memo's search.** + Text, Markdown, PDF and Word files, `.vtt` and `.srt` transcripts and, with `--transcribe`, recordings heard by the + local speech model each become a document of the account you name, `--account import:` or + `phone:`, keyed by its path in the folder: the same folder twice changes nothing, an edited file updates + its own document, a recording is heard once, and a file gone from the folder is kept. A `.json` or `.jsonl` file + goes to the records import. Links are not followed, nothing leaves the computer, and `--dry-run` writes nothing + ([Import files and records](./import.md)). +- **`memo sources add` keeps meeting transcripts.** A `.vtt` (WebVTT) or `.srt` (SubRip) file exported from a video + call is kept as searchable text, one `Name: text` line per turn without the timings; before, it was refused as + `source.unsupported`. WireCat Desktop's "Add to memory" takes them too + ([Sources you add by hand](./sources.md#add-a-source)). +- **An agent over MCP may run a schedule you made.** `schedule list`, `agents list`, `run` and `exec` are offered, as + in every WireCat CLI. Making, removing, pausing or resuming a schedule needs `mcp.authority`, which defaults to + `deny`. See [MCP](./mcp.md). +- **`memo context` lists the recorded calls and meetings a person took part in, in `meetings`**, beside `events`: + each with its `meeting:` ref, account, title, start, length and whether it has a transcript. `meetings show` of the + CLI that owns the account opens one. From cli-core 0.650.0, which also links a call to the CRM contact with the same + phone. + +### Changed — may break callers + +- **`memo projects meetings link --fingerprint` with a stale fingerprint answers `conflict`, not + `configuration_error`** (reason `meeting-project.stale`). From cli-core 0.651.0. A script that checks the code + checks `conflict`, lists the proposals again and links with the new fingerprint. +- **memo needs `@wirecat/cli-core` 0.649.0**, which adds the `document` record type and the import-only provider + `import`, and lets search read the documents of import-only accounts. +- **`memo stats tasks show` has no `--chat` any more: name the chat in the query, `-- chat:7`.** From cli-core + 0.648.0, as in tg and MAX. A chat with no account named is still refused. +- **Built on cli-core 0.656.0** (was 0.651.0). See the + [cli-core changelog](https://github.com/WireCatLabs/cli-core/blob/main/CHANGELOG.md). +- **A model address WireCat refuses now answers the reason `model.address-refused`, not `ai.address-refused`.** From + cli-core 0.650.0, in `memo models ai set`, `memo answers create --analyze` and every other call to a model. A + script that checks the old name checks the new one. + +### Fixed + +- **`memo review show --compact` prints the proposal as one line**, as `review` lists it: id, kind, title, score, + who proposed it and the day. It printed the same `key: value` lines as without `--compact`. +- **`memo review confirm` and `reject --compact` print one line per decision and one per refusal**, under + `# decided: N` and `# refused: N`. They printed only the counts. +- **`memo projects meetings link --fingerprint` keeps your `--reason` when you confirm an agent's proposed link.** The + agent's reason stayed. From cli-core 0.651.0. +- **`memo notes add --export` writes the note's first `--subject` as a link in the file too**, as it does every later + one. The file named only the others. `notes edit --export` and `notes export` still leave it out: the store does not + return a note's first subject yet. +- **The sync health of the digest no longer credits a schedule with no profile to one named `default`.** A tg, MAX or + WhatsApp sync timer that names no profile, in its arguments or its environment, now counts for no account, so a + profile called `default` is never picked for you. +- **A release with new commands or a breaking change gets a new minor version.** `bin/release` raised only the patch + number, so 0.131.86 and 0.131.87 shipped new commands as patches. +- **`memo mcp --help` no longer speaks of "this profile".** Memo has no profiles; it serves memo's commands. +- **`memo sync` finishes when the shared WireCat config starts with a byte-order mark.** A + `~/.config/WireCat/config.json` saved by a Windows editor made the meaning-search step fail with "not valid JSON", + so the sync ended incomplete. A config that cannot be read at all also no longer counts as the "read only" setup + answer (cli-core 0.656.0). +- **`memo store recover run --json` prints JSON.** It printed the text report: `store recover` has a `--json` of its + own, and it took the flag. A script or WireCat Desktop reading the answer now gets the JSON object. + +### Security + +- **`sources suggest` reaches only the hosts of the readers.** Its Ollama and API readers go through the host check: + OpenAI's and Anthropic's APIs, this computer, and the addresses you set for Ollama and for the shared AI model. A + local model may take up to 15 minutes on one source. + ## 0.131.87 — 12.11.2026 ### Added diff --git a/translations/memo/commands.es.md b/translations/memo/commands.es.md index d31f4c3c..a829d320 100644 --- a/translations/memo/commands.es.md +++ b/translations/memo/commands.es.md @@ -5,7 +5,7 @@ title: "Todos los comandos" -Consulta aquí los comandos de Memo y sus opciones. Para seleccionar cuentas, las lecturas usan `--source`: una cuenta como `telegram:1` o `email:work`, todas las cuentas de un proveedor, un tipo de origen o `group:`. Las escrituras de una cuenta usan `--account telegram:1`. Memo no elige una cuenta por ti. Añade `--json` para obtener una respuesta legible por scripts o agentes. Consulta las [recetas](./recipes.md) para tareas completas y [usar Memo](./usage.md) para un día habitual. +Consulta aquí los comandos de Memo y sus opciones. Para seleccionar cuentas, las lecturas usan `--source`: una cuenta como `telegram:1` o `email:work`, todas las cuentas de un proveedor, un tipo de origen o `group:`. Las escrituras de una cuenta usan `--account telegram:1`. Memo no elige una cuenta por ti. Añade `--json` para obtener una respuesta legible por scripts o agentes. Consulta las [recetas](./recipes.md) para tareas completas, [usar Memo](./usage.md) para un día habitual e [importar](./import.md) para traer archivos y registros de otras fuentes. ## Global options @@ -38,8 +38,6 @@ memo context [options] | `--source ` | the accounts to read: every one when left out, or the group's in a group run; for :, the one account of that messenger. | | `--trimmed` | each email's own text, without quoted earlier mail or the signature — for an agent's reads. | -**Returns:** messages, mail, notes and events about a person, each with a link to its source - **Example:** `memo context telegram:'Kai Sample'`, `memo context person:7 --json`, `memo context email:kai@example.com --limit 5 --json` ## `memo show` @@ -58,8 +56,6 @@ memo show [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** what any reference names, and the command that opens it - **Example:** `memo show chat:max/500/-1001 document:413`, `memo show note:12 msg:telegram/1/77/42 --json`, `memo show contract:2 invoice:4 --json` ## `memo notes` @@ -189,8 +185,6 @@ memo notes remove [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** delete a note you wrote here; a file it was exported to stays - **Example:** `memo notes remove note:12` ### `memo notes export` @@ -209,8 +203,6 @@ memo notes export [options] | `--format ` | the files' format: obsidian, markdown. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** write the notes you wrote here as files, never overwriting one you edited - **Example:** `memo notes export --output-dir ~/notes/memo --format obsidian` ### `memo notes links` @@ -233,8 +225,6 @@ memo notes links show [options] |---|---| | `--json` | print the standard JSON answer. | -**Returns:** show the note files about a person - **Example:** `memo notes links show telegram:101 --json` #### `memo notes links add` @@ -257,8 +247,6 @@ memo notes links add [options] | `--json` | print the standard JSON answer. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** link an imported note file to a person - **Example:** `memo notes links add telegram:101 ~/notes/People/Kai.md` #### `memo notes links clear` @@ -280,8 +268,6 @@ memo notes links clear [options] | `--json` | print the standard JSON answer. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** remove the owner's note-file links for a person - **Example:** `memo notes links clear telegram:101` ## `memo sources` @@ -313,8 +299,6 @@ memo sources add [options] | `--max-chars ` | most characters of text to keep, up to 2000000 (default 200000). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** keep a file, a web page or pasted text as a document - **Example:** `memo sources add ~/Downloads/runner-notes.pdf --subject project:3 --keep-copy`, `memo sources add https://example.org/release-notes --title 'Release notes' --json`, `memo sources add - --title 'Call with Kai' --subject person:12` ### `memo sources preview` @@ -333,8 +317,6 @@ memo sources preview [options] |---|---| | `--json` | print JSON; --json=title,excerpt keeps only those fields. | -**Returns:** read a web page as sources add would, and keep nothing - **Example:** `memo sources preview https://example.org/release-notes`, `memo sources preview https://example.org/release-notes --json=title,excerpt` ### `memo sources show` @@ -354,8 +336,6 @@ memo sources show [options] | `--bytes ` | most UTF-8 bytes of its text, up to 1048576 (default 16384). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one source: its text, what is kept, and what cites it - **Example:** `memo sources show document:42`, `memo sources show document:42 --bytes 65536 --json` ### `memo sources mentions` @@ -374,8 +354,6 @@ memo sources mentions [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** known people and organizations named in a source - **Example:** `memo sources mentions document:42 --json` ### `memo sources remove` @@ -398,8 +376,6 @@ memo sources remove [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** remove a source you added, and its kept copy - **Example:** `memo sources remove document:42` ### `memo sources suggest` @@ -426,8 +402,6 @@ memo sources suggest [options] | `--rescan` | read it again although this reader already read this text. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** have the chosen reader propose facts from a source, for you to confirm - **Example:** `memo sources suggest document:42`, `memo sources suggest document:42 --subject person:12 --json`, `memo sources suggest document:42 --provider ollama --model llama3.2 --rescan` ### `memo sources readers` @@ -450,8 +424,6 @@ memo sources readers list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** each reader: installed, signed in, and your pick - **Example:** `memo sources readers list`, `memo sources readers list available:true --json` #### `memo sources readers set` @@ -476,10 +448,68 @@ memo sources readers set [options] | `--base-url ` | Ollama only: its address on this computer, when not http://127.0.0.1:11434. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** choose the reader that reads your sources - **Example:** `memo sources readers set claude-code`, `memo sources readers set ollama --model llama3.2`, `memo sources readers set ollama --model llama3.2 --base-url http://127.0.0.1:11500` +## `memo documents` + +every document the store holds, of every account: Drive, notes folders, added sources, imports + +### `memo documents list` + +documents of every account, newest change first, with their source, folder and kind + +```sh +memo documents list [query] [options] +``` + +| Argument | | What it is | +|---|---|---| +| `query` | optional | field:value terms that narrow the list — the fields are below. | + +| Option | What it does | +|---|---| +| `--limit ` | documents per page, 1–500. Default: `50`. | +| `--page ` | which page, from 1. Default: `1`. | +| `--json` | print JSON; --json=ref,title keeps only those fields. | + +**Example:** `memo documents list budget kind:pdf`, `memo documents list source:google-drive:me@example.com folder:Contracts --page 2 --json` + +### `memo documents tree` + +the accounts holding documents, each with its folders and how many documents each holds + +```sh +memo documents tree [options] +``` + +| Option | What it does | +|---|---| +| `--source ` | only this provider:account, or every account of a provider; repeat for more. | +| `--depth ` | folder levels to list, 0–20. Default: `3`. | +| `--json` | print JSON; --json=source,count keeps only those fields. | + +**Example:** `memo documents tree --depth 2 --json` + +### `memo documents show` + +one document: a part of its text, its tags, the people it names and its meetings + +```sh +memo documents show [options] +``` + +| Argument | | What it is | +|---|---|---| +| `document` | required | document:, from documents list. | + +| Option | What it does | +|---|---| +| `--cursor ` | the character its text starts at: where the last read ended. Default: `0`. | +| `--max-chars ` | characters of text at most, 1–200000. Default: `20000`. | +| `--json` | print JSON; --json=ref,text keeps only those fields. | + +**Example:** `memo documents show document:12 --cursor 20000 --max-chars 20000 --json` + ## `memo folders` folders of notes: the id links and the store use, and the path on this computer @@ -500,11 +530,9 @@ memo folders add [options] | Option | What it does | |---|---| -| `--format ` | how its notes are written: obsidian, markdown (default: obsidian). | +| `--format ` | how its notes are written: obsidian, markdown (default for a new folder: obsidian in an Obsidian vault, one with a .obsidian folder in it or above it, markdown otherwise). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** give a folder of notes an id, or show the one it has - **Example:** `memo folders add ~/notes` ### `memo folders update` @@ -527,8 +555,6 @@ memo folders update [options] | `--format ` | how its notes are written: obsidian, markdown. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** bind a folder id from another computer to the folder's path on this one - **Example:** `memo folders update 1 ~/notes` ### `memo folders remove` @@ -551,8 +577,6 @@ memo folders remove [options] | `--yes` | confirm --allow-delete. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** stop reading a notes folder here; its notes stay unless --allow-delete - **Example:** `memo folders remove 1`, `memo folders remove 1 --allow-delete --yes` ### `memo folders list` @@ -571,8 +595,6 @@ memo folders list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** folders of notes on this computer, and those the store knows from another - **Example:** `memo folders list --json` ## `memo messages` @@ -599,8 +621,6 @@ memo messages show [options] | `--trimmed` | each email's own text, without quoted earlier mail or the signature — for an agent's reads. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one stored message or email whole, with optional stored neighbours - **Example:** `memo messages show 'msg:email/me%40example.com/thread/42' --before-n 2 --after-n 2` ### `memo messages acknowledge` @@ -772,8 +792,6 @@ memo people add [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** add a person by name, before any message names them - **Example:** `memo people add Lena Example` ### `memo people list` @@ -795,8 +813,6 @@ memo people list [query] [options] | `--page ` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people of one kind, most messages first: person by default - **Example:** `memo people list --json`, `memo people list kind:organization --sort name --page 2` ### `memo people check` @@ -816,8 +832,6 @@ memo people check [options] | `--limit ` | most people, up to 50. Default: `8`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people with a name like this one, to check before adding a person - **Example:** `memo people check ivan petrov --json` ### `memo people show` @@ -836,8 +850,6 @@ memo people show [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one person: identities by source, merges and open matches - **Example:** `memo people show person:12`, `memo people show telegram:Lena --json` ### `memo people review` @@ -854,8 +866,6 @@ memo people review [options] | `--limit ` | most proposals, up to 500. Default: `50`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people that may be one, and splits an agent proposed, waiting for you - **Example:** `memo people review`, `memo people review --kind split --json` ### `memo people confirm` @@ -882,8 +892,6 @@ memo people confirm [options] | `--reason ` | why, in a few words. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** confirm matches and splits by id, or all that people review lists; only you - **Example:** `memo people confirm 17080 17082-17085`, `memo people confirm all --kind split --yes` ### `memo people reject` @@ -910,8 +918,6 @@ memo people reject [options] | `--reason ` | why they are turned down, in a few words. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** turn down matches and splits by id, or all that people review lists; only you - **Example:** `memo people reject 17081 --reason 'two people'`, `memo people reject all --kind link --reason 'not one'` ### `memo people resolve` @@ -940,8 +946,6 @@ memo people resolve [organization] [options] | `--reason ` | why, in a few words. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a match's mailbox, or both its people, are a company's; only you - **Example:** `memo people resolve 17092 company`, `memo people resolve 17093 company organization:12 --json`, `memo people resolve 17094 organization --name "Shop Ltd"` ### `memo people links` @@ -962,8 +966,6 @@ memo people links check [options] | `--page ` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people that may be wrong, with why and the command that fixes each - **Example:** `memo people links check`, `memo people links check --page 2 --json` #### `memo people links resolve` @@ -987,8 +989,6 @@ memo people links resolve [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a person people links check doubts is right as they are, or test data; only you - **Example:** `memo people links resolve person:42 keep`, `memo people links resolve person:42 keep --from-app --json`, `memo people links resolve person:42 test` ### `memo people scan` @@ -1005,8 +1005,6 @@ memo people scan [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** match people across sources now; memo sync does it too - **Example:** `memo people scan` ### `memo people link` @@ -1031,8 +1029,6 @@ memo people link [options] | `--reason ` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say two identities are one person; an agent's link waits for you - **Example:** `memo people link max:Lena telegram:Lena`, `memo people link max:Lena telegram:Lena --reason 'same phone in her signature'` ### `memo people unlink` @@ -1057,8 +1053,6 @@ memo people unlink [options] | `--from ` | the person they leave, person: or person:me; refused when they sit on another. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** take identities off a person, to one new person; an agent's waits for you - **Example:** `memo people unlink telegram:12345 --from person:me`, `memo people unlink email:lena@example.com max:6789 --from person:42 --reason 'her husband's mailbox'` ### `memo people unmerge` @@ -1082,8 +1076,6 @@ memo people unmerge [options] | `--reason ` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** undo a merge: its identities go back to their person; an agent's waits for you - **Example:** `memo people unmerge merge:12-34`, `memo people unmerge merge:12-34 --reason 'a shared mailbox'` ## `memo tags` @@ -1120,8 +1112,6 @@ memo tags add [options] | `--account ` | the account of --chat, --contact or --meeting: the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** put labels on one source - **Example:** `memo tags add follow-up --note note:12`, `memo tags add harbour --project HRB` ### `memo tags remove` @@ -1154,8 +1144,6 @@ memo tags remove [options] | `--account ` | the account of --chat, --contact or --meeting: the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** remove labels from one source - **Example:** `memo tags remove follow-up --note note:12` ### `memo tags list` @@ -1176,8 +1164,6 @@ memo tags list [query] [options] | `--limit ` | most labels to show. Default: `100`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** list source labels, of every account or of the ones --source names - **Example:** `memo tags list tag:follow-up`, `memo tags list --source email:me@example.com --json` ## `memo tasks` @@ -1204,8 +1190,6 @@ memo tasks unlink [options] | `--kind ` | blocked-by, follow-up-of, related-to, duplicate-of, discovered-from. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** unlink reviewed project task relationships - **Example:** `memo tasks unlink HRB-2 HRB-1 --kind blocked-by` ### `memo tasks links` @@ -1224,8 +1208,6 @@ memo tasks links [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** a task's links to other tasks - **Example:** `memo tasks links HRB-2 --json` ### `memo tasks status` @@ -1244,8 +1226,6 @@ memo tasks status [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** whether a task can start, and what it still waits for - **Example:** `memo tasks status HRB-2` ### `memo tasks add` @@ -1281,8 +1261,6 @@ memo tasks add [source] [options] | `--into ` | link the source to this task instead of opening one that may be the same job. | | `--new` | open the task even when one like it is open or was closed in the last 14 days. | -**Returns:** add a task from a message, note or document, or one of your own in a project - **Example:** `memo tasks add 'msg:telegram/1/77/42' --account telegram:1 --type request`, `memo tasks add --project HRB --title 'Draft the budget' --type feature`, `memo tasks add --project INBOX --title 'Reply on Avito to Ivan' --external-id avito:4512345678 --source-url https://www.avito.ru/4512345678` ### `memo tasks list` @@ -1357,8 +1335,6 @@ memo tasks comments add [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** comment on a task, in your name or the agent's that runs memo - **Example:** `memo tasks comments add HRB-1 Booked the hall for Friday` #### `memo tasks comments list` @@ -1378,8 +1354,6 @@ memo tasks comments list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** a task's comments, oldest first, with who wrote each and when - **Example:** `memo tasks comments list HRB-1 --json` ### `memo tasks history` @@ -1398,8 +1372,6 @@ memo tasks history [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** who changed a task, what and when, oldest first - **Example:** `memo tasks history HRB-1 --json` ### `memo tasks close` @@ -1424,8 +1396,6 @@ memo tasks close [options] | `--reason ` | why it is closed. | | `--revision ` | refuse the write unless the task is still at this revision (conflict, task.stale, exit 15). | -**Returns:** close a task as done or dismissed - **Example:** `memo tasks close 7 --account telegram:1 --as dismissed --reason 'answered by phone'` ### `memo tasks assign` @@ -1450,8 +1420,6 @@ memo tasks assign [options] | `--revision ` | refuse the write unless the task is still at this revision (conflict, task.stale, exit 15). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** name who works on a task, or with --clear take them off it - **Example:** `memo tasks assign 7 person:3`, `memo tasks assign HRB-1 person:3 --clear --revision 4` ### `memo tasks move` @@ -1476,8 +1444,6 @@ memo tasks move [options] | `--revision ` | refuse the write unless the task is still at this revision (conflict, task.stale, exit 15). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** put a project task before or after another in its board column - **Example:** `memo tasks move HRB-3 --status in_progress --before HRB-1 --revision 4` ### `memo tasks agenda` @@ -1527,8 +1493,8 @@ memo tasks update [options] | `--parent ` | parent task in the same project; none clears it. | | `--title ` | one line: the action and its object — send Alex the API token. | | `--description <text>` | the detail, in Markdown; none clears it. | -| `--due <time>` | when it must be done: an ISO 8601 time or 2h, 3d from now; none clears it. | -| `--remind-time <time>` | when to look at it again: an ISO 8601 time or 2h, 3d from now; none clears it. | +| `--due <time>` | when it must be done: an ISO 8601 time, a date (its end), today, or 2h, 3d from now; none clears it. | +| `--remind-time <time>` | when to look at it again: an ISO 8601 time, a date (its start), today, or 2h, 3d from now; none clears it. | | `--assignee <person...>` | who does it: sender (whoever sent the task's message) or person:<id>; none clears it. Leave it out when unsure: a task with no assignee is better than none. | | `--account <account>` | the account it acts as: telegram:<account>, email:<account>, notes:<id>. | | `--json` | print JSON. | @@ -1661,7 +1627,6 @@ memo stats tasks show [query] [options] | Option | What it does | |---|---| | `--by <group>` | chat (default) or meeting: this account's tasks; project: the owner's project tasks, every project. | -| `--chat <chat>` | only this chat; a stored chat, by its id or title. | | `--type <type>` | only this type: question, request, mention or promise. | | `--timezone <zone>` | the IANA timezone for calendar days in the period, such as created>=today. | | `--source <accounts>` | the account: telegram:<account>, email:<account>, notes:<id>, or group:<name> of one. | @@ -1692,8 +1657,6 @@ memo stats projects show [options] | `--page <n>` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** each project's linked chats: messages in a period, last activity, busiest chats - **Example:** `memo stats projects show`, `memo stats projects show --since-time 7d --json` ## `memo organizations` @@ -1720,8 +1683,6 @@ memo organizations add <name> [options] | `--scope <scope>` | personal, work. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** add an organization - **Example:** `memo organizations add 'Harbour Studio' --kind company --scope work`, `memo organizations add 'Harbour Family' --kind family` ### `memo organizations rename` @@ -1743,8 +1704,6 @@ memo organizations rename <organization> <name> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** rename an organization - **Example:** `memo organizations rename organization:1 'Harbour Studio Ltd'`, `memo organizations rename 1 'Harbour Studio Ltd' --json` ### `memo organizations show` @@ -1763,8 +1722,6 @@ memo organizations show <organization> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one organization - **Example:** `memo organizations show organization:1` ### `memo organizations list` @@ -1804,8 +1761,6 @@ memo organizations context <organization> [options] | `--limit <n>` | most items in each section. Default: `20`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one organization: people, customers, deals, money, tasks, notes - **Example:** `memo organizations context organization:1`, `memo organizations context 1 --json` ## `memo projects` @@ -1836,8 +1791,6 @@ memo projects meetings list <project> [query] [options] | `--limit <n>` | meetings per page, at most 500. Default: `50`. | | `--page <n>` | which page, from 1. | -**Returns:** meetings linked to a project in one account, or with confirmed:false proposed - **Example:** `memo projects meetings list HRB --source zoom:me@example.com` #### `memo projects meetings link` @@ -1862,8 +1815,6 @@ memo projects meetings link <project> <meeting-id> [options] | `--fingerprint <hash>` | required when confirming an existing proposal. | | `--reason <text>` | why the reviewed meeting belongs to this project. | -**Returns:** link a stored meeting to a project, or confirm a proposed link - **Example:** `memo projects meetings link HRB 31 --account zoom:me@example.com` ### `memo projects add` @@ -1888,8 +1839,6 @@ memo projects add <name> [options] | `--scope <scope>` | personal, work. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** add a project of yours, with a short key its tasks use - **Example:** `memo projects add 'Harbour' --key HRB --type client --organization 1` ### `memo projects list` @@ -1928,8 +1877,6 @@ memo projects context <project> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one project: key documents, pending findings and open tasks; start work here - **Example:** `memo projects context HRB`, `memo projects context project:2 --json` ### `memo projects evidence` @@ -1967,8 +1914,6 @@ memo projects evidence <project> [options] | `--include-proposed` | also read chats and members proposed for the project, after the confirmed ones. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** find what the store holds about a project: names, words, people, linked chats - **Example:** `memo projects evidence SYH --source telegram:1,email:personal --contact 'Alice Example'`, `memo projects evidence SYH --source all --context-query 'crane tender' --since-time 180d --json` ### `memo projects status` @@ -2019,8 +1964,6 @@ memo projects actions add <file> [options] |---|---| | `--json` | print JSON; --json=id,status keeps only those fields. | -**Returns:** stage an agent's cited facts and follow-ups about one project for review - **Example:** `memo projects actions add findings.json` #### `memo projects actions list` @@ -2073,8 +2016,6 @@ memo projects actions confirm <project> <id> [findings] [options] | `--fingerprint <hash>` | a findings batch's fingerprint, as projects actions list gives it. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** confirm a proposal, yours or an agent's with --reason - **Example:** `memo projects actions confirm SYH 12 budget accountant --fingerprint 3f9a0c --reason 'both are stated plainly'`, `memo projects actions confirm SYH key:4` #### `memo projects actions reject` @@ -2100,8 +2041,6 @@ memo projects actions reject <project> <id> [options] | `--fingerprint <hash>` | a findings batch's fingerprint, as projects actions list gives it. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** reject a proposal - **Example:** `memo projects actions reject SYH 12 --fingerprint 3f9a0c --reason 'not about this project'` ### `memo projects annotations` @@ -2125,8 +2064,6 @@ memo projects annotations show <project> [options] | `--max-read-bytes <bytes>` | source input byte budget, at most 4194304. | | `--json` | print the standard JSON answer. | -**Returns:** read selected project annotations without creating a file; not a full backup - **Example:** `memo projects annotations show HRB --max-read-bytes 1048576 --json` #### `memo projects annotations export` @@ -2149,8 +2086,6 @@ memo projects annotations export <project> [options] | `--max-read-bytes <bytes>` | source input byte budget, at most 4194304. | | `--json` | print JSON; --json=project,counts keeps only those fields. | -**Returns:** write selected annotations to a new private file, omitting source bodies - **Example:** `memo projects annotations export HRB --output harbour-annotations.json --json` #### `memo projects annotations check` @@ -2173,8 +2108,6 @@ memo projects annotations check <file> [options] | `--max-read-bytes <bytes>` | destination input byte budget, at most 4194304. | | `--json` | print JSON; --json=ready,fingerprint keeps only those fields. | -**Returns:** check bindings and conflicts in an existing target without restoring - **Example:** `memo projects annotations check harbour-annotations.json --target-store ./trial/wirecat.db --project project:2 --bindings bindings.json --json` #### `memo projects annotations restore` @@ -2200,8 +2133,6 @@ memo projects annotations restore <file> [options] | `--json` | print JSON; --json=project,counts keeps only those fields. | | `--fingerprint <hash>` | exact fingerprint returned by the successful target preview. | -**Returns:** owner: restore selected annotations with the exact successful check fingerprint - **Example:** `memo projects annotations restore harbour-annotations.json --target-store ./trial/wirecat.db --project project:2 --bindings bindings.json --fingerprint aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --json` ### `memo projects key-documents` @@ -2230,8 +2161,6 @@ memo projects key-documents add <project> <reference> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** mark a note:, document: or msg: reference as a key document of the project - **Example:** `memo projects key-documents add HRB note:12 --reason 'the brief'` #### `memo projects key-documents remove` @@ -2255,8 +2184,6 @@ memo projects key-documents remove <project> <reference> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** unmark a key document; the note, file or message stays. Only you remove one - **Example:** `memo projects key-documents remove HRB note:12` #### `memo projects key-documents list` @@ -2313,8 +2240,6 @@ memo relationships add <from> <to> [options] | `--end-date <date>` | the last day it held, included; it ends at the start of the day after. | | `--reason <text>` | why you think so, in a sentence. | -**Returns:** state that a person, organization, project or chat belongs or relates to another - **Example:** `memo relationships add person:3 organization:1 --role employee --position CTO --start-date 2026-01-01`, `memo relationships add person:3 person:5 --kind reports-to`, `memo relationships add organization:1 organization:2 --kind customer-of --reason 'signed in October'` ### `memo relationships list` @@ -2366,8 +2291,6 @@ memo relationships update <id> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** set a relationship's role, engagement or a chat's purpose in a project - **Example:** `memo relationships update 12 --purpose sales`, `memo relationships update 12 --engagement low`, `memo relationships update 12 --role approver --role-note 'signs the acts'` ### `memo relationships remove` @@ -2391,8 +2314,6 @@ memo relationships remove <id> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** remove a relationship; removing a suggested one rejects it - **Example:** `memo relationships remove 4` ### `memo relationships confirm` @@ -2416,8 +2337,6 @@ memo relationships confirm <id> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** confirm a suggested relationship - **Example:** `memo relationships confirm 4` ### `memo relationships end` @@ -2441,8 +2360,6 @@ memo relationships end <id> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** say that a relationship ended - **Example:** `memo relationships end 4 --end-date 2026-09-30` ### `memo relationships roles` @@ -2465,8 +2382,6 @@ memo relationships roles list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the roles a relationship may take - **Example:** `memo relationships roles list`, `memo relationships roles list list:deal --json` #### `memo relationships roles add` @@ -2491,8 +2406,6 @@ memo relationships roles add <list> <role> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** add a role of your own - **Example:** `memo relationships roles add organization board-member --label 'Board member'` #### `memo relationships roles remove` @@ -2516,8 +2429,6 @@ memo relationships roles remove <list> <role> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** remove a role of your own - **Example:** `memo relationships roles remove organization board-member` ### `memo relationships scan` @@ -2542,8 +2453,6 @@ memo relationships scan [project] [options] | `--yes` | write the proposals; without it nothing is written. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** propose chats and people for a project; nothing is written without --yes - **Example:** `memo relationships scan HRB --source all`, `memo relationships scan HRB --source telegram:1,email:personal --yes`, `memo relationships scan --source email:me@example.com` ## `memo reminders` @@ -2571,8 +2480,6 @@ memo reminders add <task> [options] | `--at-time <time>` | when to remind: an ISO 8601 time with its UTC offset. | | `--timezone <zone>` | IANA timezone; the computer's when not given. | -**Returns:** add a reminder for an open task - **Example:** `memo reminders add 7 --at-time 2026-10-20T09:00:00+02:00 --timezone Europe/Madrid --account telegram:1` ### `memo reminders list` @@ -2612,8 +2519,6 @@ memo reminders claim [options] | `--json` | print JSON; --json=id,title keeps only those fields. | | `--limit <n>` | most due reminders, at most 500. Default: `100`. | -**Returns:** hand out due reminders, each with a receipt to acknowledge - **Example:** `memo reminders claim --account telegram:1 --json` ### `memo reminders acknowledge` @@ -2636,8 +2541,6 @@ memo reminders acknowledge <id> <receipt> [options] | `--account <account>` | the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** confirm that a handed-out reminder was shown - **Example:** `memo reminders acknowledge 3 3:1 --account telegram:1` ### `memo reminders cancel` @@ -2659,8 +2562,6 @@ memo reminders cancel <id> [options] | `--account <account>` | the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** cancel a reminder - **Example:** `memo reminders cancel 3 --account telegram:1` ### `memo reminders update` @@ -2684,8 +2585,6 @@ memo reminders update <id> [options] | `--at-time <time>` | the new time: an ISO 8601 time with its UTC offset. | | `--revision <n>` | the reminder's current revision, as reminders list gives it. | -**Returns:** move a reminder to another time - **Example:** `memo reminders update 3 --revision 1 --at-time 2026-10-21T09:00:00+02:00 --account telegram:1` ## `memo vocabulary` @@ -2713,8 +2612,6 @@ memo vocabulary inspect <source> <survivor> [options] | `--limit <n>` | samples per table, 1–100 (default 10); counts remain complete. | | `--json` | print the standard JSON answer. | -**Returns:** inspect two tags before consolidation, without merging them - **Example:** `memo vocabulary inspect tag:1 tag:2 --fingerprint v1:all:all:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --limit 5 --json` ### `memo vocabulary list` @@ -2735,8 +2632,6 @@ memo vocabulary list [query] [options] | `--max-read-bytes <bytes>` | catalog input byte budget. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** list canonical IDs, aliases, usage counts and a preview fingerprint - **Example:** `memo vocabulary list kind:tag` ### `memo vocabulary show` @@ -2759,8 +2654,6 @@ memo vocabulary show <name> [options] | `--max-read-bytes <bytes>` | catalog input byte budget. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the project, tag or topic an exact name or alias names; ambiguity is reported - **Example:** `memo vocabulary show Harbour --kind project` ### `memo vocabulary check` @@ -2786,8 +2679,6 @@ memo vocabulary check [name] [options] | `--max-comparisons <n>` | without a name: most name comparisons. | | `--limit <n>` | without a name: most candidate pairs. | -**Returns:** check a new name for existing labels, or the vocabulary for likely synonyms - **Example:** `memo vocabulary check on-boarding --kind tag`, `memo vocabulary check --limit 20 --json` ### `memo vocabulary create` @@ -2810,8 +2701,6 @@ memo vocabulary create <name> [options] | `--fingerprint <hash>` | the creation_fingerprint vocabulary check <name> gave. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** owner: create a distinct tag or topic after vocabulary check <name> - **Example:** `memo vocabulary create onboarding --kind tag --fingerprint 3f9a` ### `memo vocabulary aliases` @@ -2838,8 +2727,6 @@ memo vocabulary aliases add <reference> <name> [options] | `--fingerprint <hash>` | the current vocabulary preview fingerprint. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** owner: add another name for a project, tag or topic - **Example:** `memo vocabulary aliases add project:2 Harbor --fingerprint 3f9a` #### `memo vocabulary aliases remove` @@ -2862,8 +2749,6 @@ memo vocabulary aliases remove <reference> <alias-id> [options] | `--fingerprint <hash>` | the current vocabulary preview fingerprint. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** owner: remove another name from a project, tag or topic - **Example:** `memo vocabulary aliases remove project:2 5 --fingerprint 3f9a` ## `memo memories` @@ -3038,8 +2923,6 @@ memo memories remove <ref> [options] | `--json` | print JSON; --json=id,title keeps only those fields. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** forget a memory: erase its text, its links to sources and its search entry - **Example:** `memo memories remove memory:4` ### `memo memories check` @@ -3085,8 +2968,6 @@ memo memories challenge <ref> [options] | `--suggest <text>` | what the memory should say instead, for you to take or leave. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a memory no longer holds, citing what contradicts it; you decide - **Example:** `memo memories challenge memory:4 --evidence note:15 --reason 'the later note moves delivery to the 30th'`, `memo memories challenge memory:4 --evidence note:15 --reason 'moved' --suggest 'Delivery is on the 30th' --json` ## `memo mentions` @@ -3111,8 +2992,6 @@ memo mentions list [query] [options] | `--limit <n>` | most mentions. Default: `100`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the mentions in the texts --source names matching the query, newest text first - **Example:** `memo mentions list kind:phone --source notes`, `memo mentions list domain:example.com --source email:personal,email:work --json`, `memo mentions list kind:place --source mail` ### `memo mentions show` @@ -3132,8 +3011,6 @@ memo mentions show <id> [options] | `--source <accounts>` | the mailboxes a mail mention may be in: email:<account>, email or group:<name>. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one mention, the text around it, and who it may be - **Example:** `memo mentions show 12`, `memo mentions show 40 --source email:personal --json` ### `memo mentions confirm` @@ -3158,8 +3035,6 @@ memo mentions confirm <id> [person] [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** say what a mention is, everywhere its value is written - **Example:** `memo mentions confirm 12 person:7`, `memo mentions confirm 40 --source email:personal` ### `memo mentions reject` @@ -3183,8 +3058,6 @@ memo mentions reject <id> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** dismiss a mention's value everywhere, and on later imports - **Example:** `memo mentions reject 12`, `memo mentions reject 40 --source email:personal` ## `memo facts` @@ -3387,8 +3260,6 @@ memo facts remove <ref> [options] | `--json` | print JSON; --json=id,title keeps only those fields. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** forget a fact: erase its text, its links to sources and its tags - **Example:** `memo facts remove fact:4` ### `memo facts challenge` @@ -3414,8 +3285,6 @@ memo facts challenge <ref> [options] | `--suggest <text>` | what the fact should say instead, for you to take or leave. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a fact no longer holds, citing what contradicts it; you decide - **Example:** `memo facts challenge fact:4 --evidence 'msg:telegram/1/77/50' --reason 'reversed in chat'` ## `memo invoices` @@ -3439,8 +3308,6 @@ memo invoices list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most invoices, up to 500. Default: `100`. | -**Returns:** invoices, newest first; review:proposed lists what waits for you - **Example:** `memo invoices list project:HRB open:true`, `memo invoices list review:proposed --json` ### `memo invoices show` @@ -3459,8 +3326,6 @@ memo invoices show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one invoice with its lines and the payments allocated to it - **Example:** `memo invoices show invoice:4` ### `memo invoices add` @@ -3494,8 +3359,6 @@ memo invoices add <amount> <currency> <description> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record an invoice; an agent's waits for your review - **Example:** `memo invoices add 50000.00 RUB Bed rental, November --kind receivable --organization organization:3 --project HRB`, `memo invoices add 1200.50 EUR Hosting --kind payable --person person:7 --title 2026-118 --due 2026-11-15` ### `memo invoices lines` @@ -3526,8 +3389,6 @@ memo invoices lines add <invoice> <quantity> [description] [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a line to an invoice - **Example:** `memo invoices lines add invoice:4 1 --product product:4`, `memo invoices lines add invoice:4 2 Delivery --amount 1500.00` #### `memo invoices lines remove` @@ -3551,8 +3412,6 @@ memo invoices lines remove <invoice> <position> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take a line off an invoice - **Example:** `memo invoices lines remove invoice:4 2` ## `memo payments` @@ -3576,8 +3435,6 @@ memo payments list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most payments, up to 500. Default: `100`. | -**Returns:** payments, newest first; review:proposed lists what waits for you - **Example:** `memo payments list project:HRB direction:in`, `memo payments list review:proposed --json` ### `memo payments show` @@ -3596,8 +3453,6 @@ memo payments show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one payment with the invoices it is allocated to - **Example:** `memo payments show payment:9` ### `memo payments add` @@ -3630,8 +3485,6 @@ memo payments add <amount> <currency> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a payment; an agent's waits for your review - **Example:** `memo payments add 25000.00 RUB --kind in --organization organization:3 --occurred-time 2026-11-01 --project HRB`, `memo payments add 5000.00 RUB --kind out --organization organization:3 --refund-of payment:9` ### `memo payments allocate` @@ -3656,8 +3509,6 @@ memo payments allocate <payment> <invoice> <amount> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** settle part of an invoice with part of a payment - **Example:** `memo payments allocate payment:9 invoice:4 25000.00` ### `memo payments unlink` @@ -3681,8 +3532,6 @@ memo payments unlink <payment> <invoice> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take back a payment's allocation to an invoice - **Example:** `memo payments unlink payment:9 invoice:4` ## `memo orders` @@ -3706,8 +3555,6 @@ memo orders list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most orders, up to 500. Default: `100`. | -**Returns:** orders, newest first; review:proposed is what waits for you - **Example:** `memo orders list status:shipped`, `memo orders list number:A-1042 'supplier:"Shop One"' --json` ### `memo orders show` @@ -3726,8 +3573,6 @@ memo orders show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one order with its customer, shop, amount, status and the mail it was read from - **Example:** `memo orders show order:3` ### `memo orders add` @@ -3760,8 +3605,6 @@ memo orders add <shop> [amount] [currency] [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record an order; an agent's waits for your review - **Example:** `memo orders add 'Shop One' 2499.00 RUB --kind personal --title A-1042`, `memo orders add 'Office Supply' --kind client --organization organization:3` ### `memo orders lines` @@ -3792,8 +3635,6 @@ memo orders lines add <order> <quantity> [description] [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a line to an order - **Example:** `memo orders lines add order:3 12 --product product:4`, `memo orders lines add order:3 1 Rental, first week --product product:4 --amount 2000.00`, `memo orders lines add order:3 2 Helmet --amount 2500.00` #### `memo orders lines remove` @@ -3817,8 +3658,6 @@ memo orders lines remove <order> <position> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take a line off an order - **Example:** `memo orders lines remove order:3 2` ## `memo pipelines` @@ -3886,8 +3725,6 @@ memo pipelines add <name> <stage> [options] | `--kind <kind>` | what it holds: deal or lead; deal by default. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** make a pipeline with its stages - **Example:** `memo pipelines add Sales Call Quote Contract won lost`, `memo pipelines add Inbound new called --kind lead` ## `memo deals` @@ -3911,7 +3748,7 @@ memo deals list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most deals, up to 500. Default: `100`. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals list +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals list **Example:** `memo deals list status:open project:HRB`, `memo deals list stage:Quote --json` @@ -3931,7 +3768,7 @@ memo deals show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals show +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals show **Example:** `memo deals show deal:5` @@ -3976,7 +3813,7 @@ memo deals update <ref> [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--project <project>` | the project: its key or project:<id>. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals update +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals update **Example:** `memo deals update deal:5 --project HRB` @@ -4008,7 +3845,7 @@ memo deals add <title> <stage> [amount] [currency] [options] | `--evidence <ref...>` | what shows it, up to 8: msg:, note:, document: or another reference. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals add +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals add **Example:** `memo deals add 'Site for the clinic' Call 500000.00 RUB --organization organization:3 --project HRB`, `memo deals add 'Support contract' Sales/Quote --person person:7 --role decision-maker --due 2026-12-01` @@ -4031,7 +3868,7 @@ memo deals move <ref> <stage> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals move +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals move **Example:** `memo deals move deal:5 Quote`, `memo deals move deal:5 stage:5` @@ -4056,7 +3893,7 @@ memo deals close <ref> <outcome> [options] | `--reason <text>` | why it was won or lost, kept with it. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals close +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals close **Example:** `memo deals close deal:5 won`, `memo deals close deal:6 lost --reason 'chose a cheaper studio'` @@ -4081,7 +3918,7 @@ memo leads list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most leads, up to 500. Default: `100`. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads list +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads list **Example:** `memo leads list status:open` @@ -4101,7 +3938,7 @@ memo leads show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads show +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads show **Example:** `memo leads show lead:3` @@ -4146,7 +3983,7 @@ memo leads update <ref> [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--project <project>` | the project: its key or project:<id>. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads update +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads update **Example:** `memo leads update lead:3 --project HRB` @@ -4178,7 +4015,7 @@ memo leads add <title> [stage] [amount] [currency] [options] | `--evidence <ref...>` | what shows it, up to 8: msg:, note:, document: or another reference. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads add +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads add **Example:** `memo leads add 'Call from the site'`, `memo leads add 'Clinic in Kazan' contacted --person person:9` @@ -4201,7 +4038,7 @@ memo leads move <ref> <stage> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads move +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads move **Example:** `memo leads move lead:3 qualified`, `memo leads move lead:3 stage:5` @@ -4226,7 +4063,7 @@ memo leads close <ref> <outcome> [options] | `--reason <text>` | why it was won or lost, kept with it. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads close +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads close **Example:** `memo leads close lead:3 lost --reason 'no budget'` @@ -4455,8 +4292,6 @@ memo products list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most products, up to 500. Default: `100`. | -**Returns:** products and services, by name; archived:true lists those no longer sold - **Example:** `memo products list kind:service`, `memo products list archived:true --json` ### `memo products show` @@ -4475,8 +4310,6 @@ memo products show <product> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one product or service with its price, unit, supplier and stock code - **Example:** `memo products show product:4` ### `memo products add` @@ -4504,8 +4337,6 @@ memo products add <name> [amount] [currency] [options] | `--description <text>` | what it is, in a sentence. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a product or service - **Example:** `memo products add 'Bike rental, month' 10000.00 RUB --kind service --unit month`, `memo products add 'Helmet' 2500.00 RUB --sku H-12 --supplier organization:3` ### `memo products update` @@ -4532,8 +4363,6 @@ memo products update <product> [options] | `--archived <on\|off>` | on: no longer sold, and lines and subscriptions keep pointing at it; off: sold again. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** change or archive a product - **Example:** `memo products update product:4 --amount 12000.00 --currency RUB`, `memo products update product:4 --archived on` ## `memo contracts` @@ -4557,8 +4386,6 @@ memo contracts list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most contracts, up to 500. Default: `100`. | -**Returns:** contracts, newest first; expires:2026-12-31 lists those that end by then - **Example:** `memo contracts list status:active`, `memo contracts list expires:2026-12-31 --json` ### `memo contracts show` @@ -4577,8 +4404,6 @@ memo contracts show <contract> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one contract with its dates, renewal and the last day to give notice - **Example:** `memo contracts show contract:2` ### `memo contracts add` @@ -4612,8 +4437,6 @@ memo contracts add <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a contract - **Example:** `memo contracts add 'Rental agreement' --kind service --start-date 2026-11-01 --end-date 2027-10-31 --auto-renew on --notice-days 30 --amount 120000.00 --currency RUB`, `memo contracts add 'NDA with the studio' --kind nda --project HRB` ### `memo contracts update` @@ -4645,8 +4468,6 @@ memo contracts update <contract> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** change a contract - **Example:** `memo contracts update contract:2 --status terminated`, `memo contracts update contract:2 --end-date 2027-12-31` ## `memo subscriptions` @@ -4670,8 +4491,6 @@ memo subscriptions list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most subscriptions, up to 500. Default: `100`. | -**Returns:** subscriptions, newest first; renews:2026-12-01 lists those that renew by then - **Example:** `memo subscriptions list status:active direction:payable`, `memo subscriptions list renews:2026-12-01 --json` ### `memo subscriptions show` @@ -4690,8 +4509,6 @@ memo subscriptions show <subscription> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one subscription with its parties, dates, current price and every price it had - **Example:** `memo subscriptions show subscription:5` ### `memo subscriptions add` @@ -4728,8 +4545,6 @@ memo subscriptions add <name> <amount> <currency> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a subscription; an agent's waits for your review - **Example:** `memo subscriptions add Hosting 990.00 RUB --kind payable --supplier organization:3 --period 1-month --start-date 2026-11-01`, `memo subscriptions add 'Bike rental' 10000.00 RUB --kind receivable --customer organization:3 --period 1-month --trial-end-date 2026-11-14 --status trial` ### `memo subscriptions update` @@ -4762,8 +4577,6 @@ memo subscriptions update <subscription> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** change a subscription - **Example:** `memo subscriptions update subscription:5 --status paused`, `memo subscriptions update subscription:5 --period 1-year` ### `memo subscriptions cancel` @@ -4787,8 +4600,6 @@ memo subscriptions cancel <subscription> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** cancel a subscription - **Example:** `memo subscriptions cancel subscription:5 --occurred-time 2026-11-30` ### `memo subscriptions prices` @@ -4819,8 +4630,6 @@ memo subscriptions prices add <subscription> <amount> <currency> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a subscription's new price - **Example:** `memo subscriptions prices add subscription:5 1190.00 RUB --start-date 2027-01-01` ## `memo wallets` @@ -4844,8 +4653,6 @@ memo wallets list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most wallets, up to 500. Default: `100`. | -**Returns:** wallets with their balances today; kind:card lists the cards - **Example:** `memo wallets list`, `memo wallets list kind:card --json` ### `memo wallets show` @@ -4865,8 +4672,6 @@ memo wallets show <wallet> [options] | `--until-time <time>` | the balance up to and including this day, such as 2026-10-31; today when left out. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one wallet with its balance and what is pending - **Example:** `memo wallets show wallet:2`, `memo wallets show wallet:2 --until-time 2026-10-31` ### `memo wallets add` @@ -4890,8 +4695,6 @@ memo wallets add <name> <currency> [options] | `--institution <text>` | the bank or other company that holds it, by name. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a bank account, card or cash wallet - **Example:** `memo wallets add 'Main card' RUB --kind card --institution 'Bank One'` ### `memo wallets update` @@ -4918,8 +4721,6 @@ memo wallets update <wallet> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** rename a wallet or set its opening balance - **Example:** `memo wallets update wallet:2 --opening-balance 15000.00 --opening-date 2026-01-01` ## `memo transactions` @@ -4943,8 +4744,6 @@ memo transactions list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most transactions, up to 500. Default: `100`. | -**Returns:** transactions, newest first - **Example:** `memo transactions list 'wallet:"wallet:2"' status:pending`, `memo transactions list uncategorized:true --json` ### `memo transactions show` @@ -4963,8 +4762,6 @@ memo transactions show <transaction> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one transaction with its wallet, payment, splits and what is not categorized - **Example:** `memo transactions show transaction:12` ### `memo transactions add` @@ -4996,8 +4793,6 @@ memo transactions add <wallet> <amount> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a transaction; an agent's waits for your review - **Example:** `memo transactions add wallet:2 500.00 --kind out --occurred-time 2026-11-14 --description 'Coffee shop'`, `memo transactions add wallet:2 10000.00 --kind in --payment payment:9` ### `memo transactions update` @@ -5023,8 +4818,6 @@ memo transactions update <transaction> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** book a transaction or link it to its payment - **Example:** `memo transactions update transaction:12 --status booked`, `memo transactions update transaction:12 --payment payment:9` ### `memo transactions splits` @@ -5054,8 +4847,6 @@ memo transactions splits add <transaction> <amount> <category> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** put part of a transaction under a category - **Example:** `memo transactions splits add transaction:12 300.00 Rent --project HRB` #### `memo transactions splits remove` @@ -5079,8 +4870,6 @@ memo transactions splits remove <transaction> <position> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take a split off a transaction - **Example:** `memo transactions splits remove transaction:12 1` ## `memo records` @@ -5104,13 +4893,11 @@ memo records import <file> [options] | Option | What it does | |---|---| | `--dry-run` | check and plan the import; write nothing. a dry run holds the store's write lock and grows the write-ahead log for its length. | -| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, pipeline. | +| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, document, pipeline. | | `--account <account>` | the source the envelope is for: <provider>:<account> (sheet:rentals) or its source.account alone; phone:<device> for a vCard file. | | `--region <country>` | a vCard file's country for phone numbers without +, such as ru or gb; without it they are kept, not matched. | | `--json` | print JSON; --json=created,errors keeps only those fields. | -**Returns:** import a source's records; money waits for your review - **Example:** `memo records import payments.jsonl --account rentals --dry-run`, `memo records import envelope.json --account rentals --json`, `memo records import contacts.vcf --account phone:pixel --region gb` ### `memo records check` @@ -5129,13 +4916,11 @@ memo records check <file> [options] | Option | What it does | |---|---| -| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, pipeline. | +| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, document, pipeline. | | `--account <account>` | the source the envelope is for: <provider>:<account> (sheet:rentals) or its source.account alone; phone:<device> for a vCard file. | | `--region <country>` | a vCard file's country for phone numbers without +, such as ru or gb; without it they are kept, not matched. | | `--json` | print JSON; --json=created,errors keeps only those fields. | -**Returns:** check a records file against the store; write nothing - **Example:** `memo records check - --account rentals`, `memo records check invoices.csv --type invoice --account sheet:rentals` ### `memo records templates` @@ -5158,8 +4943,6 @@ memo records templates list [query] [options] |---|---| | `--json` | print JSON; --json=types keeps only those fields. | -**Returns:** the types a sheet can hold, with their columns - **Example:** `memo records templates list --json`, `memo records templates list type:invoice` #### `memo records templates show` @@ -5172,7 +4955,7 @@ memo records templates show <type> [options] | Argument | | What it is | |---|---|---| -| `type` | required | one of invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, pipeline. | +| `type` | required | one of invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, document, pipeline. | | Option | What it does | |---|---| @@ -5181,8 +4964,6 @@ memo records templates show <type> [options] | `--account <account>` | the source a JSON template names: <provider>:<account>, such as sheet:rentals. | | `--json` | print JSON; --json=text keeps only those fields. | -**Returns:** the CSV or JSON file to fill for one type - **Example:** `memo records templates show invoice --locale ru`, `memo records templates show invoice --format json --account sheet:rentals` ### `memo records list` @@ -5203,8 +4984,6 @@ memo records list [query] [options] | `--limit <n>` | most records, up to 500. Default: `100`. | | `--json` | print JSON; --json=type,external_id,entity keeps only those fields. | -**Returns:** a source's records; waiting:true lists what needs records link - **Example:** `memo records list waiting:true --account sheet:rentals`, `memo records list type:organization --account sheet:rentals --json`, `memo records list 'entity:"organization:3"' deleted:false --account sheet:rentals` ### `memo records link` @@ -5229,8 +5008,6 @@ memo records link <record> <ref> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** say which of your entries a source's record is - **Example:** `memo records link organization:client organization:3 --account sheet:rentals` ### `memo records show` @@ -5250,8 +5027,6 @@ memo records show <record> [options] | `--account <account>` | the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals. | | `--json` | print JSON; --json=fields,relations,incoming,entity keeps only those fields. | -**Returns:** one record as its source said it - **Example:** `memo records show custom:quote:Q-7 --account example-erp:demo`, `memo records show organization:client --account sheet:rentals --json` ### `memo records delete` @@ -5273,8 +5048,6 @@ memo records delete <record> [options] | `--account <account>` | the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals. | | `--json` | print JSON; --json=deleted,flagged,errors keeps only those fields. | -**Returns:** mark a source's record deleted - **Example:** `memo records delete payment:sheet-12 --account sheet:rentals` ### `memo records match` @@ -5292,10 +5065,33 @@ memo records match [options] | `--account <account>` | the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals. | | `--json` | print JSON; --json=linked,created,unmatched keeps only those fields. | -**Returns:** match a source's waiting people and organizations - **Example:** `memo records match --account sheet:rentals` +## `memo import` + +bring a folder of text, Markdown, PDF and Word files, .vtt or .srt transcripts and, with --transcribe, recordings, one such file, or a records file (JSON or JSONL) into the store, under the account you name. Each file is a document keyed by its path in the folder: the same folder twice changes nothing, an edited file updates its document, and a file gone from the folder is kept. Links are not followed and nothing leaves this computer; the text is kept as data, never run + +This command changes the local store or your files. + +```sh +memo import <path> [options] +``` + +| Argument | | What it is | +|---|---|---| +| `path` | required | a folder, a .txt, .md, .pdf, .docx, .vtt, .srt or audio file, or a records file (.json, .jsonl; - for stdin). | + +| Option | What it does | +|---|---| +| `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | +| `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | +| `--account <account>` | the source the files belong to: import:<name> (import:handbook), or phone:<exchange> for call transcripts; never chosen for you. | +| `--transcribe` | hear recordings (.wav, .mp3, .m4a, .ogg, .opus, .flac) with the local speech model; a recording heard before and unchanged is not heard again. Without it recordings are skipped. | +| `--dry-run` | read every file and plan the import; write nothing. Holds the store's write lock meanwhile. | +| `--json` | print JSON; --json=created,skipped keeps only those fields. | + +**Example:** `memo import ~/Documents/handbook --account import:handbook --dry-run`, `memo import ./recordings --account phone:office-pbx --transcribe --json`, `memo import crm-notes.jsonl --account import:crm-notes` + ## `memo meetings` stored meeting evidence and reviewed findings @@ -5424,6 +5220,47 @@ memo meetings actions reject <id> [options] **Example:** `memo meetings actions reject 5 --fingerprint aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --account zoom:me@example.com` +### `memo meetings list` + +meetings, calls and calendar events of every account as one row per real meeting, latest start first + +```sh +memo meetings list [query] [options] +``` + +| Argument | | What it is | +|---|---|---| +| `query` | optional | field:value terms that narrow the list — the fields are below. | + +| Option | What it does | +|---|---| +| `--limit <n>` | rows per page, 1–1000; a month for a calendar fits in 1000. Default: `50`. | +| `--page <n>` | which page, from 1. Default: `1`. | +| `--order <recent\|start>` | recent: latest start first; start: oldest first, for a calendar window. Default: `recent`. | +| `--json` | print JSON; --json=ref,title keeps only those fields. | + +**Example:** `memo meetings list kind:call has_transcript:true`, `memo meetings list 'started_at:[2026-11-01T00:00:00+01:00 TO 2026-12-01T00:00:00+01:00}' --order start --json` + +### `memo meetings show` + +one meeting row: its people, transcript lines with times, summaries, findings, calendar text and documents + +```sh +memo meetings show <meeting> [options] +``` + +| Argument | | What it is | +|---|---|---| +| `meeting` | required | event:<id> or meeting:<account>/<id>, from meetings list. | + +| Option | What it does | +|---|---| +| `--cursor <cursor>` | the transcript line to start at: where the last read ended. Default: `0`. | +| `--limit <n>` | transcript lines at most, 1–2000. Default: `200`. | +| `--json` | print JSON; --json=ref,transcript keeps only those fields. | + +**Example:** `memo meetings show event:42 --limit 500 --json`, `memo meetings show meeting:3/7` + ### `memo meetings passage` read a cited cue with bounded context before and after it @@ -5467,12 +5304,12 @@ memo meetings prepare <series-id> [options] |---|---| | `--context-source <id=cursor>` | one stored app.profile or email.mailbox, optionally =cursor; repeat (tg.personal). Default: ``. | | `--context-query <words>` | literal words to find within the selected communications. | -| `--context-since-time <time>` | communications window start as zoned ISO timestamp (default fourteen days before end). | -| `--context-before-time <time>` | exclusive communications end as zoned ISO timestamp (default preparation start). | +| `--context-since-time <time>` | communications window start, an ISO date or time or 7d ago (default fourteen days before end). | +| `--context-before-time <time>` | exclusive communications end, an ISO date or time (default preparation start). | | `--project <project>` | include unconfirmed word evidence for one existing project name, key or alias. | -| `--since-time <time>` | window start as ISO timestamp with zone (default now). | -| `--before-time <time>` | exclusive window end as ISO timestamp (default seven days after start). | -| `--history-since-time <time>` | history start as ISO timestamp (default thirty days before start). | +| `--since-time <time>` | window start, an ISO date or time, local without a zone (default now). | +| `--before-time <time>` | exclusive window end, an ISO date or time; a date alone covers that day (default seven days after start). | +| `--history-since-time <time>` | history start, an ISO date or time or 30d ago (default thirty days before start). | | `--meetings <n>` | prior occurrences and separate related-meeting limit, 1–20 (default 5). | | `--cues <n>` | cues per occurrence, 1–100 (default 10). | | `--context-limit <n>` | entries per context category, 1–100 (default 20). | @@ -5513,8 +5350,6 @@ memo actions add <kind> [options] | `--payload <json>` | what to do, as JSON, such as the reply's text. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** propose an action, such as a reply or a ban, in the account that would act - **Example:** `memo actions add reply --reason 'Kai asked twice' --account telegram:1 --target 'msg:telegram/1/77/42' --payload '{"text":"Friday works"}'` ### `memo actions list` @@ -5536,8 +5371,6 @@ memo actions list [query] [options] | `--brief` | without each findings batch's cited sources. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** proposed actions, newest first - **Example:** `memo actions list status:proposed` ### `memo actions show` @@ -5556,8 +5389,6 @@ memo actions show <id> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one proposed action; a findings batch with its fingerprint and sources - **Example:** `memo actions show 5` ### `memo actions confirm` @@ -5583,8 +5414,6 @@ memo actions confirm <id> [findings] [options] | `--reason <text>` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** confirm it: a task to act on, or a findings batch's facts and tasks - **Example:** `memo actions confirm 5` ### `memo actions edit` @@ -5610,8 +5439,6 @@ memo actions edit <id> <finding> [options] | `--set <field=value...>` | a field and its new value: JSON for a list, null empties it. Default: ``. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** change a finding still waiting in a findings batch before you confirm it - **Example:** `memo actions edit 5 f2 --fingerprint 3f9a --set title="Send the signed contract" dueAt=null` ### `memo actions reject` @@ -5636,8 +5463,6 @@ memo actions reject <id> [options] | `--reason <text>` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** reject it; nothing is done. For a findings batch, every finding still waiting - **Example:** `memo actions reject 5` ## `memo review` @@ -5687,8 +5512,6 @@ memo review show <id> [options] | `--after-n <n>` | messages or document paragraphs after the evidence, at most 5. Default: `2`. | | `--compact` | one line, as review prints it. | -**Returns:** one proposal with its titles, signals and the text around each piece of evidence - **Example:** `memo review show 17079`, `memo review show 17080 --brief --json` ### `memo review confirm` @@ -5713,8 +5536,6 @@ memo review confirm <ids> [options] | `--reason <text>` | why, in a few words; required when an agent decides. | | `--compact` | one line per decision. | -**Returns:** confirm proposals by id or range; each on its own - **Example:** `memo review confirm 17078-17081`, `memo review confirm 17080/f1,17080/f3`, `memo review confirm close:Q-15` ### `memo review reject` @@ -5739,8 +5560,6 @@ memo review reject <ids> [options] | `--reason <text>` | why it is turned down, in a few words. | | `--compact` | one line per decision. | -**Returns:** turn proposals down, with why - **Example:** `memo review reject 17081 --reason "not this project"`, `memo review reject close:Q-15 --reason 'still open'` ### `memo review agenda` @@ -5761,8 +5580,6 @@ memo review agenda [options] | `--compact` | one line per item, shorter excerpts, the smaller budget: for an agent. | | `--json` | print JSON. | -**Returns:** morning digest: watched, owed, mail, meetings, calendar, Drive, CRM, tasks - **Example:** `memo review agenda --compact`, `memo review agenda --since-time 3d --json` ### `memo review status` @@ -5804,8 +5621,6 @@ memo agents list [query] [options] | `--page <n>` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one row per tool call, newest first: agent, tool, outcome and times - **Example:** `memo agents list agent:claude-code --limit 20` ## `memo mcp` @@ -5829,8 +5644,6 @@ memo mcp serve [options] | `--port <port>` | local HTTP port (default 8767); requires --http. | | `--public-url <url>` | tunnel's HTTPS address without /mcp, or a path of it such as https://<name>.ts.net/memo; requires --http. | -**Returns:** serve this profile's commands to an AI agent - **Example:** `memo mcp serve`, `memo mcp serve --http --public-url https://laptop.example.ts.net` ### `memo mcp revoke` @@ -5847,8 +5660,6 @@ memo mcp revoke [options] |---|---| | `--json` | print JSON. | -**Returns:** forget every login given to a browser app - **Example:** `memo mcp revoke --json` ### `memo mcp server` @@ -5872,8 +5683,6 @@ memo mcp server start [options] | `--permission <key=level>` | make a permission stricter for this server only; repeat for more keys. | | `--json` | print JSON. | -**Returns:** start the HTTP MCP server in the background - **Example:** `memo mcp server start --public-url https://laptop.example.ts.net` #### `memo mcp server stop` @@ -5890,8 +5699,6 @@ memo mcp server stop [options] |---|---| | `--json` | print JSON. | -**Returns:** stop the background HTTP MCP server - **Example:** `memo mcp server stop` #### `memo mcp server status` @@ -5906,8 +5713,6 @@ memo mcp server status [options] |---|---| | `--json` | print JSON. | -**Returns:** whether the HTTP MCP server runs, its login code and the apps logged in - **Example:** `memo mcp server status --json` ## `memo models` @@ -6028,8 +5833,6 @@ memo models consents show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether enrichment is on, with which provider and model, how many records it… - **Example:** `memo models consents show --json` #### `memo models consents set` @@ -6053,8 +5856,6 @@ memo models consents set <provider> [options] | `--yes` | agree that the records go to this provider, and turn enrichment on. | | `--json` | print JSON. | -**Returns:** turn enrichment on for one provider and model; without --yes, say what would… - **Example:** `memo models consents set openai --model gpt-4o-mini`, `memo models consents set openai --model gpt-4o-mini --yes` #### `memo models consents revoke` @@ -6071,8 +5872,6 @@ memo models consents revoke [options] |---|---| | `--json` | print JSON. | -**Returns:** turn enrichment off and delete what the model wrote; search reads only the… - **Example:** `memo models consents revoke` ### `memo models search-consents` @@ -6091,8 +5890,6 @@ memo models search-consents show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether search all --harder may call the model, which one, and whether its… - **Example:** `memo models search-consents show --json` #### `memo models search-consents set` @@ -6117,8 +5914,6 @@ memo models search-consents set <provider> [options] | `--yes` | agree that a --harder search sends its question and hits, and allow it. | | `--json` | print JSON. | -**Returns:** allow search all --harder to call the model; without --yes, say what it… - **Example:** `memo models search-consents set anthropic`, `memo models search-consents set anthropic --yes` #### `memo models search-consents revoke` @@ -6135,8 +5930,6 @@ memo models search-consents revoke [options] |---|---| | `--json` | print JSON. | -**Returns:** stop search all --harder from calling the model; it gives the plain order again - **Example:** `memo models search-consents revoke` ### `memo models keys` @@ -6203,8 +5996,6 @@ memo models ai show [options] |---|---| | `--json` | print JSON. | -**Returns:** the chosen model, its key, and whether images may go to it - **Example:** `memo models ai show` #### `memo models ai set` @@ -6230,8 +6021,6 @@ memo models ai set <provider> [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** choose the AI model: anthropic, openai or compatible, or ollama (beta) - **Example:** `memo models ai set anthropic --model claude-haiku-4-5 --secret-stdin --allow-remote`, `memo models ai set openai --model openai/gpt-4o-mini --base-url https://openrouter.ai/api/v1 --secret-stdin`, `memo models ai set ollama --model llama3.2-vision` #### `memo models ai unset` @@ -6249,8 +6038,6 @@ memo models ai unset [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** stop using a model; its key stays until models ai remove - **Example:** `memo models ai unset` #### `memo models ai remove` @@ -6272,8 +6059,6 @@ memo models ai remove [origin] [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** remove the key stored for an address - **Example:** `memo models ai remove https://api.anthropic.com` #### `memo models ai revoke` @@ -6291,15 +6076,13 @@ memo models ai revoke [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** stop sending images to the AI model; the model itself stays chosen - **Example:** `memo models ai revoke` #### `memo models ai check` send one short request (billed by the provider, usually under a cent) and say what is wrong -This command changes the local store or your files. +**Reads from an outside service.** ```sh memo models ai check [options] @@ -6310,8 +6093,6 @@ memo models ai check [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** send one short paid request and say what is wrong - **Example:** `memo models ai check` ### `memo models local-only` @@ -6330,8 +6111,6 @@ memo models local-only show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether local only is on, and where each feature sends data - **Example:** `memo models local-only show` #### `memo models local-only set` @@ -6353,8 +6132,6 @@ memo models local-only set <state> [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** turn local only on or off; only you turn it off - **Example:** `memo models local-only set on`, `memo models local-only set off` ### `memo models picture-reading` @@ -6373,8 +6150,6 @@ memo models picture-reading show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether pictures are read, and by which agent - **Example:** `memo models picture-reading show` #### `memo models picture-reading set` @@ -6398,8 +6173,6 @@ memo models picture-reading set <mode> [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** never, or on request with `images read`; only you turn it on - **Example:** `memo models picture-reading set request --agent claude`, `memo models picture-reading set request --agent codex --model gpt-5`, `memo models picture-reading set never` ## `memo templates` @@ -6444,8 +6217,6 @@ memo templates show <key> [options] | `--locale <code>` | the template's language, ISO 639-1; the owner's first language if not given. | | `--json` | print JSON. | -**Returns:** the template that applies, and the bodies your changes replaced - **Example:** `memo templates show report/morning-digest --channel telegram`, `memo templates show report/weekly-gaps --channel email --locale en --json` ### `memo templates edit` @@ -6470,8 +6241,6 @@ memo templates edit <key> [options] | `--undo` | put back the body your last change replaced; twice is back where you were. | | `--json` | print JSON. | -**Returns:** change a template in $EDITOR or from --file; checked before it is saved - **Example:** `memo templates edit report/morning-digest --channel telegram`, `memo templates edit report/morning-digest --channel text --file digest.text.liquid`, `memo templates edit report/morning-digest --channel telegram --undo` ### `memo templates preview` @@ -6493,8 +6262,6 @@ memo templates preview <key> [options] | `--file <file>` | preview this draft instead of the template that applies; - reads stdin. | | `--json` | print JSON. | -**Returns:** what would be sent on that channel; saves nothing - **Example:** `memo templates preview report/morning-digest --channel telegram`, `memo templates preview report/morning-digest --channel email --locale en --file draft.liquid` ### `memo templates reset` @@ -6517,8 +6284,6 @@ memo templates reset <key> [options] | `--locale <code>` | the template's language, ISO 639-1; the owner's first language if not given. | | `--json` | print JSON. | -**Returns:** go back to the shipped template; edit --undo brings yours back - **Example:** `memo templates reset report/morning-digest --channel telegram` ## `memo search` @@ -6549,7 +6314,7 @@ memo search all <query> [options] | `--harder` | a hosted model reorders the first 30 hits; sends the question and those hits to the provider you chose with memo models search-consents set <provider> --yes, only after that. | | `--project <project>` | rank the key documents of this project (id, project:<id>, key, exact name or alias) first; nothing is left out. | -**Returns:** hit — kind, ref, provider, account, title, timestamp, excerpt, url, and 17 more; every field: memo commands info search all +**Returns:** hit — kind, ref, provider, account, title, timestamp, excerpt, url, and 18 more; every field: memo commands info search all **Example:** `memo search all 'budget harbour'`, `memo search all 'Rental agreement' --only business`, `memo search all 'release date' --source zoom:work,notes --json` @@ -6704,9 +6469,9 @@ memo search meetings <query> [options] | `--series-id <id>` | only meetings in this stored series. | | `--project <project>` | meetings confirmed in this project, by name, key or alias. | | `--topic-name <name>` | meetings with this topic, by name or alias. | -| `--since-time <time>` | meetings starting at or after this ISO 8601 date or time. | +| `--since-time <time>` | meetings starting at or after this ISO 8601 date or time, or 30m, 2h, 7d ago. | | `--until-time <time>` | meetings starting at or before this ISO 8601 date or time; a date alone covers that whole local day. | -| `--limit <n>` | how many hits, 1 through 1000 (default 100). | +| `--limit <n>` | how many hits, 1 through 1000; the profile's defaults.limit when absent. | | `--cursor <cursor>` | continue from the previous page's page.next_cursor, with the same query and filters. | | `--max-read-bytes <bytes>` | most stored bytes to read, 1 through 67108864 (default 4194304). | | `--source <accounts>` | the meeting account: provider:account (zoom:me@example.com), or a provider that has one. | @@ -6714,6 +6479,8 @@ memo search meetings <query> [options] **Returns:** meeting hit — ref, meeting, scope, id, excerpt, offset_ms, language, line, and 5 more; every field: memo commands info search meetings +**Next usually:** `memo meetings show <meeting>` + **Example:** `memo search meetings budget --source zoom:me@example.com --project Harbour --since-time 2026-10-01 --limit 10 --json` ## `memo events` @@ -6787,8 +6554,6 @@ memo answers create <question> [query] [options] | `--allow-remote` | explicitly consent to sending this evidence to the configured model. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** prepare cited evidence for your agent, or explicitly call a configured model - **Example:** `memo answers create 'what did Kai say about the budget?' --all`, `memo answers create 'when is the launch?' --source telegram:1` ## `memo sync` @@ -6810,8 +6575,6 @@ memo sync [options] | `--timeout <duration>` | stop after this long, e.g. 10m; progress so far is kept (default: no limit). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** sync notes, make stored mail searchable by meaning, and match people - **Example:** `memo sync`, `memo sync --only mail`, `memo sync --only notes --folder ~/notes --no-embed` ## `memo store` @@ -6846,6 +6609,8 @@ memo store recover [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | +**Example:** `memo store recover` + #### `memo store recover run` copy every readable row into a new file with the sqlite3 program, rebuild the search indexes, mentions and vector index, check it, and put it in place of the store; the damaged file is kept beside it. Refuses while a WireCat timer or process has the store @@ -6860,8 +6625,6 @@ memo store recover run [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** rebuild a damaged store from every row it can read - **Example:** `memo store recover run` ## `memo groups` @@ -6884,8 +6647,6 @@ memo groups list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the saved groups, then all, with accounts, profiles and duplicates - **Example:** `memo groups list`, `memo groups list --json` ### `memo groups add` @@ -6907,8 +6668,6 @@ memo groups add <group> <source> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** put an account in a group - **Example:** `memo groups add work bitrix24:acme`, `memo groups add personal telegram:102` ### `memo groups remove` @@ -6930,8 +6689,6 @@ memo groups remove <group> <source> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** take an account out of a group - **Example:** `memo groups remove work telegram:102` ### `memo groups move` @@ -6954,8 +6711,6 @@ memo groups move <source> <from> <to> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** move an account between groups - **Example:** `memo groups move telegram:102 personal work` ### `memo groups rename` @@ -6977,8 +6732,6 @@ memo groups rename <group> <name> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** rename a group - **Example:** `memo groups rename work office` ### `memo groups delete` @@ -6999,8 +6752,6 @@ memo groups delete <group> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** delete a group - **Example:** `memo groups delete clients` ### `memo groups update` @@ -7023,8 +6774,6 @@ memo groups update <source> [options] | `--chat <chat>` | one chat of the account, by its id there. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** set an account's or one chat's scope, personal or work - **Example:** `memo groups update bitrix24:acme --scope work`, `memo groups update telegram:102 --chat 7 --scope account` ## `memo jobs` @@ -7045,8 +6794,6 @@ memo jobs start [options] |---|---| | `--every <duration>` | how often: 5m, 90s, 1h — a minute or more. | -**Returns:** sync every --every (default auto.every, else 5m), starting a minute from now - **Example:** `memo jobs start --every 10m` ### `memo jobs stop` @@ -7059,8 +6806,6 @@ This command changes the local store or your files. memo jobs stop ``` -**Returns:** stop syncing on a timer and remove the timer - **Example:** `memo jobs stop` ### `memo jobs status` @@ -7075,8 +6820,6 @@ memo jobs status [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** whether the timer is on, its interval, its next run and how the last one ended - **Example:** `memo jobs status --json` ## `memo config` @@ -7095,8 +6838,6 @@ memo config show [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** every setting, its value, its default and whether the file sets it - **Example:** `memo config show`, `memo config show --json` ### `memo config migrate` @@ -7113,8 +6854,6 @@ memo config migrate [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** write each setting the file lacks at its default, keeping yours - **Example:** `memo config migrate` ### `memo config unset` @@ -7135,8 +6874,6 @@ memo config unset <key> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** remove one setting from the config file, even one memo does not know - **Example:** `memo config unset permissions.notes.edit` ## `memo doctor` @@ -7153,8 +6890,6 @@ memo doctor [options] | `--deep` | also read every page of the store and check every search index (about 30 s for 6 GB); without it, only the file header and schema. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the state this installation is in, without connecting unless --online - **Example:** `memo doctor`, `memo doctor --json` ## `memo upgrade` @@ -7172,8 +6907,6 @@ memo upgrade [options] | `--check` | say whether a newer version exists, and install nothing. | | `--json` | print JSON. | -**Returns:** upgrade memo with the package manager that installed it; --check only looks - **Example:** `memo upgrade --check` ## `memo schedule` @@ -7204,8 +6937,6 @@ memo schedule command <name> <args> [options] | `--deliver-to <route>` | also send the result, when --notify-on says so, by the owner's own tg or mail: telegram-bot:<profile>/<chat id or user:id>, or email:<profile>/<address>; repeat it for more. | | `--json` | print JSON. | -**Returns:** run memo <args…> on a timer — reads save what they read, so this is how a… - **Example:** `memo schedule command digest --at 08:30 -- review status`, `memo schedule command mail-sync --every 1h -- sync --only mail` ### `memo schedule agent` @@ -7240,8 +6971,6 @@ memo schedule agent <name> <harness> <prompt> [options] | `--mail-batch <n>` | with --on-new-mail: or once this many emails wait (default 10, or the config file's). | | `--json` | print JSON. | -**Returns:** start an agent (claude, codex, gemini, cursor, opencode, openclaw, hermes,… - **Example:** `memo schedule agent triage claude 'read memo review status and list what needs me today' --at 08:45 --max-cost 1`, `memo schedule agent mail-triage claude 'Run memo skill show mail-triage and follow it.' --every 5m --on-new-mail mail-triage --mail-wait 1h --mail-batch 20 --max-cost 1 --max-cost-per-day 5`, `memo schedule agent weekly claude 'read memo review status and sum up the week' --at 09:00 --model opus` ### `memo schedule list` @@ -7312,8 +7041,6 @@ memo schedule run <name> [options] | `--deliver-to <route>` | send it along only this one of its own routes; repeat it for more. | | `--json` | print JSON. | -**Returns:** run a schedule now, as its timer would, and wait for it; a paused one runs too - **Example:** `memo schedule run digest` ### `memo schedule remove` @@ -7334,8 +7061,6 @@ memo schedule remove <name> [options] |---|---| | `--json` | print JSON. | -**Returns:** stop a schedule and remove its timer; its past output stays - **Example:** `memo schedule remove digest` ### `memo schedule pause` @@ -7356,8 +7081,6 @@ memo schedule pause <name> [options] |---|---| | `--json` | print JSON. | -**Returns:** take a schedule off its timer and keep it; run runs it, resume puts it back - **Example:** `memo schedule pause digest` ### `memo schedule resume` @@ -7378,8 +7101,6 @@ memo schedule resume <name> [options] |---|---| | `--json` | print JSON. | -**Returns:** put a paused schedule back on its timer - **Example:** `memo schedule resume digest` ### `memo schedule exec` @@ -7401,8 +7122,6 @@ memo schedule exec <file> [seal] [options] |---|---| | `--json` | print JSON. | -**Returns:** what a timer runs, given the schedule's file; to run one by hand, use run - **Example:** `memo schedule exec ~/.local/state/cli-memo/schedules/digest/schedule.json` ## `memo digest` @@ -7427,8 +7146,6 @@ memo digest brief show [digest] [options] |---|---| | `--json` | print JSON. | -**Returns:** the brief a digest follows, and the bodies your changes replaced - **Example:** `memo digest brief show`, `memo digest brief show --json` #### `memo digest brief edit` @@ -7451,8 +7168,6 @@ memo digest brief edit [digest] [options] | `--undo` | put back the body your last change replaced. | | `--json` | print JSON. | -**Returns:** write the brief in $EDITOR or from --file; only you, never an agent - **Example:** `memo digest brief edit`, `memo digest brief edit --file brief.md`, `memo digest brief edit --undo` #### `memo digest brief reset` @@ -7473,8 +7188,6 @@ memo digest brief reset [digest] [options] |---|---| | `--json` | print JSON. | -**Returns:** remove the brief; edit --undo brings it back - **Example:** `memo digest brief reset` ### `memo digest list` @@ -7491,8 +7204,6 @@ memo digest list [query] [options] |---|---| | `--json` | print JSON. | -**Returns:** your digests: when each runs, what it reads, where it goes, last and next run - **Example:** `memo digest list`, `memo digest list name:weekly --json` ### `memo digest add` @@ -7525,8 +7236,6 @@ memo digest add <name> [options] | `--json` | print JSON. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** make a digest: its times, sources, routes and brief, on its timer - **Example:** `memo digest add evening --title 'Evening digest' --at 18:00 --deliver-to telegram-bot:personal/user:42`, `memo digest add weekly --title 'The week' --at 'mon 09:00' --source telegram,mail,tasks` ### `memo digest edit` @@ -7558,8 +7267,6 @@ memo digest edit <name> [options] | `--json` | print JSON. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** change a digest; each option given replaces what it says, the rest stays - **Example:** `memo digest edit evening --at 08:30 --at 18:00`, `memo digest edit weekly --source all --deliver-to none` ### `memo digest run` @@ -7583,8 +7290,6 @@ memo digest run <name> [options] | `--deliver-to <route>` | send it only along this one of the digest's routes; repeat it for more. | | `--json` | print JSON. | -**Returns:** build a digest now and send it along its routes, or only some, or none - **Example:** `memo digest run evening`, `memo digest run weekly --no-notify --json` ### `memo digest pause` @@ -7604,8 +7309,6 @@ memo digest pause <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON. | -**Returns:** take a digest off its timer; it stays, and run still builds it - **Example:** `memo digest pause weekly` ### `memo digest resume` @@ -7625,8 +7328,6 @@ memo digest resume <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON. | -**Returns:** put a paused digest back on its timer - **Example:** `memo digest resume weekly` ### `memo digest remove` @@ -7646,8 +7347,6 @@ memo digest remove <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON. | -**Returns:** remove a digest and its timer; its past runs, brief and templates stay - **Example:** `memo digest remove weekly` ### `memo digest backfill` @@ -7672,8 +7371,6 @@ memo digest backfill [digest] [options] | `--yes` | build them; without it, only the estimate is printed. | | `--json` | print JSON. | -**Returns:** build a digest's past runs, without sending them - **Example:** `memo digest backfill --since-time 2026-11-01 --until-time 2026-11-07`, `memo digest backfill --since-time 2026-11-01 --until-time 2026-11-07 --yes --json` ## `memo commands` @@ -7692,6 +7389,8 @@ memo commands [path] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | +**Example:** `memo commands` + ### `memo commands info` one command contract, or all schemas, error reasons and explicit overrides @@ -7708,8 +7407,6 @@ memo commands info [path] [options] |---|---| | `--json` | print JSON. | -**Returns:** one command contract, or all schemas, error reasons and explicit overrides - **Example:** `memo commands info --json` ## `memo skill` @@ -7733,8 +7430,6 @@ memo skill show [name] [options] | `--for <agents>` | print the copy installed for these agents instead of this version's. One of: `claude`, `agents`. | | `--json` | print JSON. | -**Returns:** print the tool's instructions for AI agents - **Example:** `memo skill show` ### `memo skill install` @@ -7752,8 +7447,6 @@ memo skill install [options] | `--for <agents>` | which agents to install for. One of: `claude`, `agents`, `hermes`, `all`. Default: `all`. | | `--json` | print JSON. | -**Returns:** install the tool's instructions for AI agents - **Example:** `memo skill install --for all` ### `memo skill status` @@ -7768,8 +7461,6 @@ memo skill status [options] |---|---| | `--json` | print JSON. | -**Returns:** whether the installed instructions for AI agents match this version - **Example:** `memo skill status`, `memo skill status --json` ## `memo guide` @@ -7788,8 +7479,6 @@ memo guide [name] [options] |---|---| | `--json` | print JSON. | -**Returns:** scenarios: the commands for a common task, in order, and why each - **Example:** `memo guide`, `memo guide person-brief --json` ## `memo runs` @@ -7810,8 +7499,8 @@ memo runs list [query] [options] | Option | What it does | |---|---| -| `--limit <n>` | how many to show. Default: `20`. | -| `--page <n>` | which page, starting at 1. Default: `1`. | +| `--limit <n>` | how many to show. | +| `--page <n>` | which page, starting at 1. | | `--json` | print JSON. | **Returns:** run — run_id, command, started_at, status, cli_version, profile, completed_at, requests, and 23 more; every field: memo commands info runs list diff --git a/translations/memo/commands.ru.md b/translations/memo/commands.ru.md index 3e97ef6c..47bb8c60 100644 --- a/translations/memo/commands.ru.md +++ b/translations/memo/commands.ru.md @@ -5,7 +5,7 @@ title: "Все команды" <!-- Generated from the command tree by pnpm generate. Do not edit. --> -Найдите здесь любую команду Memo и её параметры. Для выбора аккаунтов чтение использует `--source`: один аккаунт, например `telegram:1` или `email:work`, все аккаунты провайдера, тип источника или `group:<name>`. Для записи от имени аккаунта используется `--account telegram:1`. Memo не выбирает аккаунт за вас. Добавьте `--json`, чтобы получить ответ для скрипта или агента. Полные задачи описаны в [рецептах](./recipes.md), обычный день — в разделе [использование Memo](./usage.md). +Найдите здесь любую команду Memo и её параметры. Для выбора аккаунтов чтение использует `--source`: один аккаунт, например `telegram:1` или `email:work`, все аккаунты провайдера, тип источника или `group:<name>`. Для записи от имени аккаунта используется `--account telegram:1`. Memo не выбирает аккаунт за вас. Добавьте `--json`, чтобы получить ответ для скрипта или агента. Полные задачи описаны в [рецептах](./recipes.md), обычный день в разделе [использование Memo](./usage.md), а файлы и записи из других источников в разделе [импорт](./import.md). ## Global options @@ -38,8 +38,6 @@ memo context <person> [options] | `--source <accounts>` | the accounts to read: every one when left out, or the group's in a group run; for <messenger>:<name>, the one account of that messenger. | | `--trimmed` | each email's own text, without quoted earlier mail or the signature — for an agent's reads. | -**Returns:** messages, mail, notes and events about a person, each with a link to its source - **Example:** `memo context telegram:'Kai Sample'`, `memo context person:7 --json`, `memo context email:kai@example.com --limit 5 --json` ## `memo show` @@ -58,8 +56,6 @@ memo show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** what any reference names, and the command that opens it - **Example:** `memo show chat:max/500/-1001 document:413`, `memo show note:12 msg:telegram/1/77/42 --json`, `memo show contract:2 invoice:4 --json` ## `memo notes` @@ -189,8 +185,6 @@ memo notes remove <id> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** delete a note you wrote here; a file it was exported to stays - **Example:** `memo notes remove note:12` ### `memo notes export` @@ -209,8 +203,6 @@ memo notes export [options] | `--format <format>` | the files' format: obsidian, markdown. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** write the notes you wrote here as files, never overwriting one you edited - **Example:** `memo notes export --output-dir ~/notes/memo --format obsidian` ### `memo notes links` @@ -233,8 +225,6 @@ memo notes links show <identity> [options] |---|---| | `--json` | print the standard JSON answer. | -**Returns:** show the note files about a person - **Example:** `memo notes links show telegram:101 --json` #### `memo notes links add` @@ -257,8 +247,6 @@ memo notes links add <identity> <path> [options] | `--json` | print the standard JSON answer. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** link an imported note file to a person - **Example:** `memo notes links add telegram:101 ~/notes/People/Kai.md` #### `memo notes links clear` @@ -280,8 +268,6 @@ memo notes links clear <identity> [options] | `--json` | print the standard JSON answer. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** remove the owner's note-file links for a person - **Example:** `memo notes links clear telegram:101` ## `memo sources` @@ -313,8 +299,6 @@ memo sources add <source> [options] | `--max-chars <n>` | most characters of text to keep, up to 2000000 (default 200000). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** keep a file, a web page or pasted text as a document - **Example:** `memo sources add ~/Downloads/runner-notes.pdf --subject project:3 --keep-copy`, `memo sources add https://example.org/release-notes --title 'Release notes' --json`, `memo sources add - --title 'Call with Kai' --subject person:12` ### `memo sources preview` @@ -333,8 +317,6 @@ memo sources preview <url> [options] |---|---| | `--json` | print JSON; --json=title,excerpt keeps only those fields. | -**Returns:** read a web page as sources add would, and keep nothing - **Example:** `memo sources preview https://example.org/release-notes`, `memo sources preview https://example.org/release-notes --json=title,excerpt` ### `memo sources show` @@ -354,8 +336,6 @@ memo sources show <ref> [options] | `--bytes <bytes>` | most UTF-8 bytes of its text, up to 1048576 (default 16384). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one source: its text, what is kept, and what cites it - **Example:** `memo sources show document:42`, `memo sources show document:42 --bytes 65536 --json` ### `memo sources mentions` @@ -374,8 +354,6 @@ memo sources mentions <ref> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** known people and organizations named in a source - **Example:** `memo sources mentions document:42 --json` ### `memo sources remove` @@ -398,8 +376,6 @@ memo sources remove <ref> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** remove a source you added, and its kept copy - **Example:** `memo sources remove document:42` ### `memo sources suggest` @@ -426,8 +402,6 @@ memo sources suggest <ref> [options] | `--rescan` | read it again although this reader already read this text. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** have the chosen reader propose facts from a source, for you to confirm - **Example:** `memo sources suggest document:42`, `memo sources suggest document:42 --subject person:12 --json`, `memo sources suggest document:42 --provider ollama --model llama3.2 --rescan` ### `memo sources readers` @@ -450,8 +424,6 @@ memo sources readers list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** each reader: installed, signed in, and your pick - **Example:** `memo sources readers list`, `memo sources readers list available:true --json` #### `memo sources readers set` @@ -476,10 +448,68 @@ memo sources readers set <reader> [options] | `--base-url <url>` | Ollama only: its address on this computer, when not http://127.0.0.1:11434. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** choose the reader that reads your sources - **Example:** `memo sources readers set claude-code`, `memo sources readers set ollama --model llama3.2`, `memo sources readers set ollama --model llama3.2 --base-url http://127.0.0.1:11500` +## `memo documents` + +every document the store holds, of every account: Drive, notes folders, added sources, imports + +### `memo documents list` + +documents of every account, newest change first, with their source, folder and kind + +```sh +memo documents list [query] [options] +``` + +| Argument | | What it is | +|---|---|---| +| `query` | optional | field:value terms that narrow the list — the fields are below. | + +| Option | What it does | +|---|---| +| `--limit <n>` | documents per page, 1–500. Default: `50`. | +| `--page <n>` | which page, from 1. Default: `1`. | +| `--json` | print JSON; --json=ref,title keeps only those fields. | + +**Example:** `memo documents list budget kind:pdf`, `memo documents list source:google-drive:me@example.com folder:Contracts --page 2 --json` + +### `memo documents tree` + +the accounts holding documents, each with its folders and how many documents each holds + +```sh +memo documents tree [options] +``` + +| Option | What it does | +|---|---| +| `--source <accounts>` | only this provider:account, or every account of a provider; repeat for more. | +| `--depth <n>` | folder levels to list, 0–20. Default: `3`. | +| `--json` | print JSON; --json=source,count keeps only those fields. | + +**Example:** `memo documents tree --depth 2 --json` + +### `memo documents show` + +one document: a part of its text, its tags, the people it names and its meetings + +```sh +memo documents show <document> [options] +``` + +| Argument | | What it is | +|---|---|---| +| `document` | required | document:<id>, from documents list. | + +| Option | What it does | +|---|---| +| `--cursor <cursor>` | the character its text starts at: where the last read ended. Default: `0`. | +| `--max-chars <n>` | characters of text at most, 1–200000. Default: `20000`. | +| `--json` | print JSON; --json=ref,text keeps only those fields. | + +**Example:** `memo documents show document:12 --cursor 20000 --max-chars 20000 --json` + ## `memo folders` folders of notes: the id links and the store use, and the path on this computer @@ -500,11 +530,9 @@ memo folders add <path> [options] | Option | What it does | |---|---| -| `--format <format>` | how its notes are written: obsidian, markdown (default: obsidian). | +| `--format <format>` | how its notes are written: obsidian, markdown (default for a new folder: obsidian in an Obsidian vault, one with a .obsidian folder in it or above it, markdown otherwise). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** give a folder of notes an id, or show the one it has - **Example:** `memo folders add ~/notes` ### `memo folders update` @@ -527,8 +555,6 @@ memo folders update <id> <path> [options] | `--format <format>` | how its notes are written: obsidian, markdown. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** bind a folder id from another computer to the folder's path on this one - **Example:** `memo folders update 1 ~/notes` ### `memo folders remove` @@ -551,8 +577,6 @@ memo folders remove <folder> [options] | `--yes` | confirm --allow-delete. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** stop reading a notes folder here; its notes stay unless --allow-delete - **Example:** `memo folders remove 1`, `memo folders remove 1 --allow-delete --yes` ### `memo folders list` @@ -571,8 +595,6 @@ memo folders list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** folders of notes on this computer, and those the store knows from another - **Example:** `memo folders list --json` ## `memo messages` @@ -599,8 +621,6 @@ memo messages show <message> [options] | `--trimmed` | each email's own text, without quoted earlier mail or the signature — for an agent's reads. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one stored message or email whole, with optional stored neighbours - **Example:** `memo messages show 'msg:email/me%40example.com/thread/42' --before-n 2 --after-n 2` ### `memo messages acknowledge` @@ -772,8 +792,6 @@ memo people add <name> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** add a person by name, before any message names them - **Example:** `memo people add Lena Example` ### `memo people list` @@ -795,8 +813,6 @@ memo people list [query] [options] | `--page <n>` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people of one kind, most messages first: person by default - **Example:** `memo people list --json`, `memo people list kind:organization --sort name --page 2` ### `memo people check` @@ -816,8 +832,6 @@ memo people check <name> [options] | `--limit <n>` | most people, up to 50. Default: `8`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people with a name like this one, to check before adding a person - **Example:** `memo people check ivan petrov --json` ### `memo people show` @@ -836,8 +850,6 @@ memo people show <who> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one person: identities by source, merges and open matches - **Example:** `memo people show person:12`, `memo people show telegram:Lena --json` ### `memo people review` @@ -854,8 +866,6 @@ memo people review [options] | `--limit <n>` | most proposals, up to 500. Default: `50`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people that may be one, and splits an agent proposed, waiting for you - **Example:** `memo people review`, `memo people review --kind split --json` ### `memo people confirm` @@ -882,8 +892,6 @@ memo people confirm <ids> [options] | `--reason <text>` | why, in a few words. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** confirm matches and splits by id, or all that people review lists; only you - **Example:** `memo people confirm 17080 17082-17085`, `memo people confirm all --kind split --yes` ### `memo people reject` @@ -910,8 +918,6 @@ memo people reject <ids> [options] | `--reason <text>` | why they are turned down, in a few words. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** turn down matches and splits by id, or all that people review lists; only you - **Example:** `memo people reject 17081 --reason 'two people'`, `memo people reject all --kind link --reason 'not one'` ### `memo people resolve` @@ -940,8 +946,6 @@ memo people resolve <id> <answer> [organization] [options] | `--reason <text>` | why, in a few words. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a match's mailbox, or both its people, are a company's; only you - **Example:** `memo people resolve 17092 company`, `memo people resolve 17093 company organization:12 --json`, `memo people resolve 17094 organization --name "Shop Ltd"` ### `memo people links` @@ -962,8 +966,6 @@ memo people links check [options] | `--page <n>` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** people that may be wrong, with why and the command that fixes each - **Example:** `memo people links check`, `memo people links check --page 2 --json` #### `memo people links resolve` @@ -987,8 +989,6 @@ memo people links resolve <who> <answer> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a person people links check doubts is right as they are, or test data; only you - **Example:** `memo people links resolve person:42 keep`, `memo people links resolve person:42 keep --from-app --json`, `memo people links resolve person:42 test` ### `memo people scan` @@ -1005,8 +1005,6 @@ memo people scan [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** match people across sources now; memo sync does it too - **Example:** `memo people scan` ### `memo people link` @@ -1031,8 +1029,6 @@ memo people link <identity> <other> [options] | `--reason <text>` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say two identities are one person; an agent's link waits for you - **Example:** `memo people link max:Lena telegram:Lena`, `memo people link max:Lena telegram:Lena --reason 'same phone in her signature'` ### `memo people unlink` @@ -1057,8 +1053,6 @@ memo people unlink <identities> [options] | `--from <person>` | the person they leave, person:<uid> or person:me; refused when they sit on another. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** take identities off a person, to one new person; an agent's waits for you - **Example:** `memo people unlink telegram:12345 --from person:me`, `memo people unlink email:lena@example.com max:6789 --from person:42 --reason 'her husband's mailbox'` ### `memo people unmerge` @@ -1082,8 +1076,6 @@ memo people unmerge <merge> [options] | `--reason <text>` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** undo a merge: its identities go back to their person; an agent's waits for you - **Example:** `memo people unmerge merge:12-34`, `memo people unmerge merge:12-34 --reason 'a shared mailbox'` ## `memo tags` @@ -1120,8 +1112,6 @@ memo tags add <tag> [options] | `--account <account>` | the account of --chat, --contact or --meeting: the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** put labels on one source - **Example:** `memo tags add follow-up --note note:12`, `memo tags add harbour --project HRB` ### `memo tags remove` @@ -1154,8 +1144,6 @@ memo tags remove <tag> [options] | `--account <account>` | the account of --chat, --contact or --meeting: the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** remove labels from one source - **Example:** `memo tags remove follow-up --note note:12` ### `memo tags list` @@ -1176,8 +1164,6 @@ memo tags list [query] [options] | `--limit <n>` | most labels to show. Default: `100`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** list source labels, of every account or of the ones --source names - **Example:** `memo tags list tag:follow-up`, `memo tags list --source email:me@example.com --json` ## `memo tasks` @@ -1204,8 +1190,6 @@ memo tasks unlink <task> <other-task> [options] | `--kind <kind>` | blocked-by, follow-up-of, related-to, duplicate-of, discovered-from. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** unlink reviewed project task relationships - **Example:** `memo tasks unlink HRB-2 HRB-1 --kind blocked-by` ### `memo tasks links` @@ -1224,8 +1208,6 @@ memo tasks links <task> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** a task's links to other tasks - **Example:** `memo tasks links HRB-2 --json` ### `memo tasks status` @@ -1244,8 +1226,6 @@ memo tasks status <task> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** whether a task can start, and what it still waits for - **Example:** `memo tasks status HRB-2` ### `memo tasks add` @@ -1281,8 +1261,6 @@ memo tasks add [source] [options] | `--into <id>` | link the source to this task instead of opening one that may be the same job. | | `--new` | open the task even when one like it is open or was closed in the last 14 days. | -**Returns:** add a task from a message, note or document, or one of your own in a project - **Example:** `memo tasks add 'msg:telegram/1/77/42' --account telegram:1 --type request`, `memo tasks add --project HRB --title 'Draft the budget' --type feature`, `memo tasks add --project INBOX --title 'Reply on Avito to Ivan' --external-id avito:4512345678 --source-url https://www.avito.ru/4512345678` ### `memo tasks list` @@ -1357,8 +1335,6 @@ memo tasks comments add <id> <text> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** comment on a task, in your name or the agent's that runs memo - **Example:** `memo tasks comments add HRB-1 Booked the hall for Friday` #### `memo tasks comments list` @@ -1378,8 +1354,6 @@ memo tasks comments list <id> [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** a task's comments, oldest first, with who wrote each and when - **Example:** `memo tasks comments list HRB-1 --json` ### `memo tasks history` @@ -1398,8 +1372,6 @@ memo tasks history <id> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** who changed a task, what and when, oldest first - **Example:** `memo tasks history HRB-1 --json` ### `memo tasks close` @@ -1424,8 +1396,6 @@ memo tasks close <id> [options] | `--reason <text>` | why it is closed. | | `--revision <n>` | refuse the write unless the task is still at this revision (conflict, task.stale, exit 15). | -**Returns:** close a task as done or dismissed - **Example:** `memo tasks close 7 --account telegram:1 --as dismissed --reason 'answered by phone'` ### `memo tasks assign` @@ -1450,8 +1420,6 @@ memo tasks assign <id> <person> [options] | `--revision <n>` | refuse the write unless the task is still at this revision (conflict, task.stale, exit 15). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** name who works on a task, or with --clear take them off it - **Example:** `memo tasks assign 7 person:3`, `memo tasks assign HRB-1 person:3 --clear --revision 4` ### `memo tasks move` @@ -1476,8 +1444,6 @@ memo tasks move <id> [options] | `--revision <n>` | refuse the write unless the task is still at this revision (conflict, task.stale, exit 15). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** put a project task before or after another in its board column - **Example:** `memo tasks move HRB-3 --status in_progress --before HRB-1 --revision 4` ### `memo tasks agenda` @@ -1527,8 +1493,8 @@ memo tasks update <task> [options] | `--parent <id>` | parent task in the same project; none clears it. | | `--title <title>` | one line: the action and its object — send Alex the API token. | | `--description <text>` | the detail, in Markdown; none clears it. | -| `--due <time>` | when it must be done: an ISO 8601 time or 2h, 3d from now; none clears it. | -| `--remind-time <time>` | when to look at it again: an ISO 8601 time or 2h, 3d from now; none clears it. | +| `--due <time>` | when it must be done: an ISO 8601 time, a date (its end), today, or 2h, 3d from now; none clears it. | +| `--remind-time <time>` | when to look at it again: an ISO 8601 time, a date (its start), today, or 2h, 3d from now; none clears it. | | `--assignee <person...>` | who does it: sender (whoever sent the task's message) or person:<id>; none clears it. Leave it out when unsure: a task with no assignee is better than none. | | `--account <account>` | the account it acts as: telegram:<account>, email:<account>, notes:<id>. | | `--json` | print JSON. | @@ -1661,7 +1627,6 @@ memo stats tasks show [query] [options] | Option | What it does | |---|---| | `--by <group>` | chat (default) or meeting: this account's tasks; project: the owner's project tasks, every project. | -| `--chat <chat>` | only this chat; a stored chat, by its id or title. | | `--type <type>` | only this type: question, request, mention or promise. | | `--timezone <zone>` | the IANA timezone for calendar days in the period, such as created>=today. | | `--source <accounts>` | the account: telegram:<account>, email:<account>, notes:<id>, or group:<name> of one. | @@ -1692,8 +1657,6 @@ memo stats projects show [options] | `--page <n>` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** each project's linked chats: messages in a period, last activity, busiest chats - **Example:** `memo stats projects show`, `memo stats projects show --since-time 7d --json` ## `memo organizations` @@ -1720,8 +1683,6 @@ memo organizations add <name> [options] | `--scope <scope>` | personal, work. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** add an organization - **Example:** `memo organizations add 'Harbour Studio' --kind company --scope work`, `memo organizations add 'Harbour Family' --kind family` ### `memo organizations rename` @@ -1743,8 +1704,6 @@ memo organizations rename <organization> <name> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** rename an organization - **Example:** `memo organizations rename organization:1 'Harbour Studio Ltd'`, `memo organizations rename 1 'Harbour Studio Ltd' --json` ### `memo organizations show` @@ -1763,8 +1722,6 @@ memo organizations show <organization> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one organization - **Example:** `memo organizations show organization:1` ### `memo organizations list` @@ -1804,8 +1761,6 @@ memo organizations context <organization> [options] | `--limit <n>` | most items in each section. Default: `20`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one organization: people, customers, deals, money, tasks, notes - **Example:** `memo organizations context organization:1`, `memo organizations context 1 --json` ## `memo projects` @@ -1836,8 +1791,6 @@ memo projects meetings list <project> [query] [options] | `--limit <n>` | meetings per page, at most 500. Default: `50`. | | `--page <n>` | which page, from 1. | -**Returns:** meetings linked to a project in one account, or with confirmed:false proposed - **Example:** `memo projects meetings list HRB --source zoom:me@example.com` #### `memo projects meetings link` @@ -1862,8 +1815,6 @@ memo projects meetings link <project> <meeting-id> [options] | `--fingerprint <hash>` | required when confirming an existing proposal. | | `--reason <text>` | why the reviewed meeting belongs to this project. | -**Returns:** link a stored meeting to a project, or confirm a proposed link - **Example:** `memo projects meetings link HRB 31 --account zoom:me@example.com` ### `memo projects add` @@ -1888,8 +1839,6 @@ memo projects add <name> [options] | `--scope <scope>` | personal, work. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** add a project of yours, with a short key its tasks use - **Example:** `memo projects add 'Harbour' --key HRB --type client --organization 1` ### `memo projects list` @@ -1928,8 +1877,6 @@ memo projects context <project> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one project: key documents, pending findings and open tasks; start work here - **Example:** `memo projects context HRB`, `memo projects context project:2 --json` ### `memo projects evidence` @@ -1967,8 +1914,6 @@ memo projects evidence <project> [options] | `--include-proposed` | also read chats and members proposed for the project, after the confirmed ones. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** find what the store holds about a project: names, words, people, linked chats - **Example:** `memo projects evidence SYH --source telegram:1,email:personal --contact 'Alice Example'`, `memo projects evidence SYH --source all --context-query 'crane tender' --since-time 180d --json` ### `memo projects status` @@ -2019,8 +1964,6 @@ memo projects actions add <file> [options] |---|---| | `--json` | print JSON; --json=id,status keeps only those fields. | -**Returns:** stage an agent's cited facts and follow-ups about one project for review - **Example:** `memo projects actions add findings.json` #### `memo projects actions list` @@ -2073,8 +2016,6 @@ memo projects actions confirm <project> <id> [findings] [options] | `--fingerprint <hash>` | a findings batch's fingerprint, as projects actions list gives it. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** confirm a proposal, yours or an agent's with --reason - **Example:** `memo projects actions confirm SYH 12 budget accountant --fingerprint 3f9a0c --reason 'both are stated plainly'`, `memo projects actions confirm SYH key:4` #### `memo projects actions reject` @@ -2100,8 +2041,6 @@ memo projects actions reject <project> <id> [options] | `--fingerprint <hash>` | a findings batch's fingerprint, as projects actions list gives it. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** reject a proposal - **Example:** `memo projects actions reject SYH 12 --fingerprint 3f9a0c --reason 'not about this project'` ### `memo projects annotations` @@ -2125,8 +2064,6 @@ memo projects annotations show <project> [options] | `--max-read-bytes <bytes>` | source input byte budget, at most 4194304. | | `--json` | print the standard JSON answer. | -**Returns:** read selected project annotations without creating a file; not a full backup - **Example:** `memo projects annotations show HRB --max-read-bytes 1048576 --json` #### `memo projects annotations export` @@ -2149,8 +2086,6 @@ memo projects annotations export <project> [options] | `--max-read-bytes <bytes>` | source input byte budget, at most 4194304. | | `--json` | print JSON; --json=project,counts keeps only those fields. | -**Returns:** write selected annotations to a new private file, omitting source bodies - **Example:** `memo projects annotations export HRB --output harbour-annotations.json --json` #### `memo projects annotations check` @@ -2173,8 +2108,6 @@ memo projects annotations check <file> [options] | `--max-read-bytes <bytes>` | destination input byte budget, at most 4194304. | | `--json` | print JSON; --json=ready,fingerprint keeps only those fields. | -**Returns:** check bindings and conflicts in an existing target without restoring - **Example:** `memo projects annotations check harbour-annotations.json --target-store ./trial/wirecat.db --project project:2 --bindings bindings.json --json` #### `memo projects annotations restore` @@ -2200,8 +2133,6 @@ memo projects annotations restore <file> [options] | `--json` | print JSON; --json=project,counts keeps only those fields. | | `--fingerprint <hash>` | exact fingerprint returned by the successful target preview. | -**Returns:** owner: restore selected annotations with the exact successful check fingerprint - **Example:** `memo projects annotations restore harbour-annotations.json --target-store ./trial/wirecat.db --project project:2 --bindings bindings.json --fingerprint aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --json` ### `memo projects key-documents` @@ -2230,8 +2161,6 @@ memo projects key-documents add <project> <reference> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** mark a note:, document: or msg: reference as a key document of the project - **Example:** `memo projects key-documents add HRB note:12 --reason 'the brief'` #### `memo projects key-documents remove` @@ -2255,8 +2184,6 @@ memo projects key-documents remove <project> <reference> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** unmark a key document; the note, file or message stays. Only you remove one - **Example:** `memo projects key-documents remove HRB note:12` #### `memo projects key-documents list` @@ -2313,8 +2240,6 @@ memo relationships add <from> <to> [options] | `--end-date <date>` | the last day it held, included; it ends at the start of the day after. | | `--reason <text>` | why you think so, in a sentence. | -**Returns:** state that a person, organization, project or chat belongs or relates to another - **Example:** `memo relationships add person:3 organization:1 --role employee --position CTO --start-date 2026-01-01`, `memo relationships add person:3 person:5 --kind reports-to`, `memo relationships add organization:1 organization:2 --kind customer-of --reason 'signed in October'` ### `memo relationships list` @@ -2366,8 +2291,6 @@ memo relationships update <id> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** set a relationship's role, engagement or a chat's purpose in a project - **Example:** `memo relationships update 12 --purpose sales`, `memo relationships update 12 --engagement low`, `memo relationships update 12 --role approver --role-note 'signs the acts'` ### `memo relationships remove` @@ -2391,8 +2314,6 @@ memo relationships remove <id> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** remove a relationship; removing a suggested one rejects it - **Example:** `memo relationships remove 4` ### `memo relationships confirm` @@ -2416,8 +2337,6 @@ memo relationships confirm <id> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** confirm a suggested relationship - **Example:** `memo relationships confirm 4` ### `memo relationships end` @@ -2441,8 +2360,6 @@ memo relationships end <id> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** say that a relationship ended - **Example:** `memo relationships end 4 --end-date 2026-09-30` ### `memo relationships roles` @@ -2465,8 +2382,6 @@ memo relationships roles list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the roles a relationship may take - **Example:** `memo relationships roles list`, `memo relationships roles list list:deal --json` #### `memo relationships roles add` @@ -2491,8 +2406,6 @@ memo relationships roles add <list> <role> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** add a role of your own - **Example:** `memo relationships roles add organization board-member --label 'Board member'` #### `memo relationships roles remove` @@ -2516,8 +2429,6 @@ memo relationships roles remove <list> <role> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** remove a role of your own - **Example:** `memo relationships roles remove organization board-member` ### `memo relationships scan` @@ -2542,8 +2453,6 @@ memo relationships scan [project] [options] | `--yes` | write the proposals; without it nothing is written. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** propose chats and people for a project; nothing is written without --yes - **Example:** `memo relationships scan HRB --source all`, `memo relationships scan HRB --source telegram:1,email:personal --yes`, `memo relationships scan --source email:me@example.com` ## `memo reminders` @@ -2571,8 +2480,6 @@ memo reminders add <task> [options] | `--at-time <time>` | when to remind: an ISO 8601 time with its UTC offset. | | `--timezone <zone>` | IANA timezone; the computer's when not given. | -**Returns:** add a reminder for an open task - **Example:** `memo reminders add 7 --at-time 2026-10-20T09:00:00+02:00 --timezone Europe/Madrid --account telegram:1` ### `memo reminders list` @@ -2612,8 +2519,6 @@ memo reminders claim [options] | `--json` | print JSON; --json=id,title keeps only those fields. | | `--limit <n>` | most due reminders, at most 500. Default: `100`. | -**Returns:** hand out due reminders, each with a receipt to acknowledge - **Example:** `memo reminders claim --account telegram:1 --json` ### `memo reminders acknowledge` @@ -2636,8 +2541,6 @@ memo reminders acknowledge <id> <receipt> [options] | `--account <account>` | the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** confirm that a handed-out reminder was shown - **Example:** `memo reminders acknowledge 3 3:1 --account telegram:1` ### `memo reminders cancel` @@ -2659,8 +2562,6 @@ memo reminders cancel <id> [options] | `--account <account>` | the account it acts as: provider:account, such as telegram:1 or email:personal. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** cancel a reminder - **Example:** `memo reminders cancel 3 --account telegram:1` ### `memo reminders update` @@ -2684,8 +2585,6 @@ memo reminders update <id> [options] | `--at-time <time>` | the new time: an ISO 8601 time with its UTC offset. | | `--revision <n>` | the reminder's current revision, as reminders list gives it. | -**Returns:** move a reminder to another time - **Example:** `memo reminders update 3 --revision 1 --at-time 2026-10-21T09:00:00+02:00 --account telegram:1` ## `memo vocabulary` @@ -2713,8 +2612,6 @@ memo vocabulary inspect <source> <survivor> [options] | `--limit <n>` | samples per table, 1–100 (default 10); counts remain complete. | | `--json` | print the standard JSON answer. | -**Returns:** inspect two tags before consolidation, without merging them - **Example:** `memo vocabulary inspect tag:1 tag:2 --fingerprint v1:all:all:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --limit 5 --json` ### `memo vocabulary list` @@ -2735,8 +2632,6 @@ memo vocabulary list [query] [options] | `--max-read-bytes <bytes>` | catalog input byte budget. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** list canonical IDs, aliases, usage counts and a preview fingerprint - **Example:** `memo vocabulary list kind:tag` ### `memo vocabulary show` @@ -2759,8 +2654,6 @@ memo vocabulary show <name> [options] | `--max-read-bytes <bytes>` | catalog input byte budget. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the project, tag or topic an exact name or alias names; ambiguity is reported - **Example:** `memo vocabulary show Harbour --kind project` ### `memo vocabulary check` @@ -2786,8 +2679,6 @@ memo vocabulary check [name] [options] | `--max-comparisons <n>` | without a name: most name comparisons. | | `--limit <n>` | without a name: most candidate pairs. | -**Returns:** check a new name for existing labels, or the vocabulary for likely synonyms - **Example:** `memo vocabulary check on-boarding --kind tag`, `memo vocabulary check --limit 20 --json` ### `memo vocabulary create` @@ -2810,8 +2701,6 @@ memo vocabulary create <name> [options] | `--fingerprint <hash>` | the creation_fingerprint vocabulary check <name> gave. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** owner: create a distinct tag or topic after vocabulary check <name> - **Example:** `memo vocabulary create onboarding --kind tag --fingerprint 3f9a` ### `memo vocabulary aliases` @@ -2838,8 +2727,6 @@ memo vocabulary aliases add <reference> <name> [options] | `--fingerprint <hash>` | the current vocabulary preview fingerprint. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** owner: add another name for a project, tag or topic - **Example:** `memo vocabulary aliases add project:2 Harbor --fingerprint 3f9a` #### `memo vocabulary aliases remove` @@ -2862,8 +2749,6 @@ memo vocabulary aliases remove <reference> <alias-id> [options] | `--fingerprint <hash>` | the current vocabulary preview fingerprint. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** owner: remove another name from a project, tag or topic - **Example:** `memo vocabulary aliases remove project:2 5 --fingerprint 3f9a` ## `memo memories` @@ -3038,8 +2923,6 @@ memo memories remove <ref> [options] | `--json` | print JSON; --json=id,title keeps only those fields. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** forget a memory: erase its text, its links to sources and its search entry - **Example:** `memo memories remove memory:4` ### `memo memories check` @@ -3085,8 +2968,6 @@ memo memories challenge <ref> [options] | `--suggest <text>` | what the memory should say instead, for you to take or leave. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a memory no longer holds, citing what contradicts it; you decide - **Example:** `memo memories challenge memory:4 --evidence note:15 --reason 'the later note moves delivery to the 30th'`, `memo memories challenge memory:4 --evidence note:15 --reason 'moved' --suggest 'Delivery is on the 30th' --json` ## `memo mentions` @@ -3111,8 +2992,6 @@ memo mentions list [query] [options] | `--limit <n>` | most mentions. Default: `100`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the mentions in the texts --source names matching the query, newest text first - **Example:** `memo mentions list kind:phone --source notes`, `memo mentions list domain:example.com --source email:personal,email:work --json`, `memo mentions list kind:place --source mail` ### `memo mentions show` @@ -3132,8 +3011,6 @@ memo mentions show <id> [options] | `--source <accounts>` | the mailboxes a mail mention may be in: email:<account>, email or group:<name>. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one mention, the text around it, and who it may be - **Example:** `memo mentions show 12`, `memo mentions show 40 --source email:personal --json` ### `memo mentions confirm` @@ -3158,8 +3035,6 @@ memo mentions confirm <id> [person] [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** say what a mention is, everywhere its value is written - **Example:** `memo mentions confirm 12 person:7`, `memo mentions confirm 40 --source email:personal` ### `memo mentions reject` @@ -3183,8 +3058,6 @@ memo mentions reject <id> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** dismiss a mention's value everywhere, and on later imports - **Example:** `memo mentions reject 12`, `memo mentions reject 40 --source email:personal` ## `memo facts` @@ -3387,8 +3260,6 @@ memo facts remove <ref> [options] | `--json` | print JSON; --json=id,title keeps only those fields. | | `--reason <text>` | why, in a few words; required when an agent decides for you. | -**Returns:** forget a fact: erase its text, its links to sources and its tags - **Example:** `memo facts remove fact:4` ### `memo facts challenge` @@ -3414,8 +3285,6 @@ memo facts challenge <ref> [options] | `--suggest <text>` | what the fact should say instead, for you to take or leave. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** say a fact no longer holds, citing what contradicts it; you decide - **Example:** `memo facts challenge fact:4 --evidence 'msg:telegram/1/77/50' --reason 'reversed in chat'` ## `memo invoices` @@ -3439,8 +3308,6 @@ memo invoices list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most invoices, up to 500. Default: `100`. | -**Returns:** invoices, newest first; review:proposed lists what waits for you - **Example:** `memo invoices list project:HRB open:true`, `memo invoices list review:proposed --json` ### `memo invoices show` @@ -3459,8 +3326,6 @@ memo invoices show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one invoice with its lines and the payments allocated to it - **Example:** `memo invoices show invoice:4` ### `memo invoices add` @@ -3494,8 +3359,6 @@ memo invoices add <amount> <currency> <description> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record an invoice; an agent's waits for your review - **Example:** `memo invoices add 50000.00 RUB Bed rental, November --kind receivable --organization organization:3 --project HRB`, `memo invoices add 1200.50 EUR Hosting --kind payable --person person:7 --title 2026-118 --due 2026-11-15` ### `memo invoices lines` @@ -3526,8 +3389,6 @@ memo invoices lines add <invoice> <quantity> [description] [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a line to an invoice - **Example:** `memo invoices lines add invoice:4 1 --product product:4`, `memo invoices lines add invoice:4 2 Delivery --amount 1500.00` #### `memo invoices lines remove` @@ -3551,8 +3412,6 @@ memo invoices lines remove <invoice> <position> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take a line off an invoice - **Example:** `memo invoices lines remove invoice:4 2` ## `memo payments` @@ -3576,8 +3435,6 @@ memo payments list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most payments, up to 500. Default: `100`. | -**Returns:** payments, newest first; review:proposed lists what waits for you - **Example:** `memo payments list project:HRB direction:in`, `memo payments list review:proposed --json` ### `memo payments show` @@ -3596,8 +3453,6 @@ memo payments show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one payment with the invoices it is allocated to - **Example:** `memo payments show payment:9` ### `memo payments add` @@ -3630,8 +3485,6 @@ memo payments add <amount> <currency> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a payment; an agent's waits for your review - **Example:** `memo payments add 25000.00 RUB --kind in --organization organization:3 --occurred-time 2026-11-01 --project HRB`, `memo payments add 5000.00 RUB --kind out --organization organization:3 --refund-of payment:9` ### `memo payments allocate` @@ -3656,8 +3509,6 @@ memo payments allocate <payment> <invoice> <amount> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** settle part of an invoice with part of a payment - **Example:** `memo payments allocate payment:9 invoice:4 25000.00` ### `memo payments unlink` @@ -3681,8 +3532,6 @@ memo payments unlink <payment> <invoice> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take back a payment's allocation to an invoice - **Example:** `memo payments unlink payment:9 invoice:4` ## `memo orders` @@ -3706,8 +3555,6 @@ memo orders list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most orders, up to 500. Default: `100`. | -**Returns:** orders, newest first; review:proposed is what waits for you - **Example:** `memo orders list status:shipped`, `memo orders list number:A-1042 'supplier:"Shop One"' --json` ### `memo orders show` @@ -3726,8 +3573,6 @@ memo orders show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one order with its customer, shop, amount, status and the mail it was read from - **Example:** `memo orders show order:3` ### `memo orders add` @@ -3760,8 +3605,6 @@ memo orders add <shop> [amount] [currency] [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record an order; an agent's waits for your review - **Example:** `memo orders add 'Shop One' 2499.00 RUB --kind personal --title A-1042`, `memo orders add 'Office Supply' --kind client --organization organization:3` ### `memo orders lines` @@ -3792,8 +3635,6 @@ memo orders lines add <order> <quantity> [description] [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a line to an order - **Example:** `memo orders lines add order:3 12 --product product:4`, `memo orders lines add order:3 1 Rental, first week --product product:4 --amount 2000.00`, `memo orders lines add order:3 2 Helmet --amount 2500.00` #### `memo orders lines remove` @@ -3817,8 +3658,6 @@ memo orders lines remove <order> <position> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take a line off an order - **Example:** `memo orders lines remove order:3 2` ## `memo pipelines` @@ -3886,8 +3725,6 @@ memo pipelines add <name> <stage> [options] | `--kind <kind>` | what it holds: deal or lead; deal by default. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** make a pipeline with its stages - **Example:** `memo pipelines add Sales Call Quote Contract won lost`, `memo pipelines add Inbound new called --kind lead` ## `memo deals` @@ -3911,7 +3748,7 @@ memo deals list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most deals, up to 500. Default: `100`. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals list +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals list **Example:** `memo deals list status:open project:HRB`, `memo deals list stage:Quote --json` @@ -3931,7 +3768,7 @@ memo deals show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals show +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals show **Example:** `memo deals show deal:5` @@ -3976,7 +3813,7 @@ memo deals update <ref> [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--project <project>` | the project: its key or project:<id>. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals update +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals update **Example:** `memo deals update deal:5 --project HRB` @@ -4008,7 +3845,7 @@ memo deals add <title> <stage> [amount] [currency] [options] | `--evidence <ref...>` | what shows it, up to 8: msg:, note:, document: or another reference. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals add +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals add **Example:** `memo deals add 'Site for the clinic' Call 500000.00 RUB --organization organization:3 --project HRB`, `memo deals add 'Support contract' Sales/Quote --person person:7 --role decision-maker --due 2026-12-01` @@ -4031,7 +3868,7 @@ memo deals move <ref> <stage> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals move +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals move **Example:** `memo deals move deal:5 Quote`, `memo deals move deal:5 stage:5` @@ -4056,7 +3893,7 @@ memo deals close <ref> <outcome> [options] | `--reason <text>` | why it was won or lost, kept with it. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info deals close +**Returns:** deal — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info deals close **Example:** `memo deals close deal:5 won`, `memo deals close deal:6 lost --reason 'chose a cheaper studio'` @@ -4081,7 +3918,7 @@ memo leads list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most leads, up to 500. Default: `100`. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads list +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads list **Example:** `memo leads list status:open` @@ -4101,7 +3938,7 @@ memo leads show <ref> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads show +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads show **Example:** `memo leads show lead:3` @@ -4146,7 +3983,7 @@ memo leads update <ref> [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--project <project>` | the project: its key or project:<id>. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads update +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads update **Example:** `memo leads update lead:3 --project HRB` @@ -4178,7 +4015,7 @@ memo leads add <title> [stage] [amount] [currency] [options] | `--evidence <ref...>` | what shows it, up to 8: msg:, note:, document: or another reference. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads add +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads add **Example:** `memo leads add 'Call from the site'`, `memo leads add 'Clinic in Kazan' contacted --person person:9` @@ -4201,7 +4038,7 @@ memo leads move <ref> <stage> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads move +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads move **Example:** `memo leads move lead:3 qualified`, `memo leads move lead:3 stage:5` @@ -4226,7 +4063,7 @@ memo leads close <ref> <outcome> [options] | `--reason <text>` | why it was won or lost, kept with it. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 27 more; every field: memo commands info leads close +**Returns:** lead — id, ref, kind, title, summary, pipeline, pipeline_name, stage, and 29 more; every field: memo commands info leads close **Example:** `memo leads close lead:3 lost --reason 'no budget'` @@ -4455,8 +4292,6 @@ memo products list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most products, up to 500. Default: `100`. | -**Returns:** products and services, by name; archived:true lists those no longer sold - **Example:** `memo products list kind:service`, `memo products list archived:true --json` ### `memo products show` @@ -4475,8 +4310,6 @@ memo products show <product> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one product or service with its price, unit, supplier and stock code - **Example:** `memo products show product:4` ### `memo products add` @@ -4504,8 +4337,6 @@ memo products add <name> [amount] [currency] [options] | `--description <text>` | what it is, in a sentence. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a product or service - **Example:** `memo products add 'Bike rental, month' 10000.00 RUB --kind service --unit month`, `memo products add 'Helmet' 2500.00 RUB --sku H-12 --supplier organization:3` ### `memo products update` @@ -4532,8 +4363,6 @@ memo products update <product> [options] | `--archived <on\|off>` | on: no longer sold, and lines and subscriptions keep pointing at it; off: sold again. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** change or archive a product - **Example:** `memo products update product:4 --amount 12000.00 --currency RUB`, `memo products update product:4 --archived on` ## `memo contracts` @@ -4557,8 +4386,6 @@ memo contracts list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most contracts, up to 500. Default: `100`. | -**Returns:** contracts, newest first; expires:2026-12-31 lists those that end by then - **Example:** `memo contracts list status:active`, `memo contracts list expires:2026-12-31 --json` ### `memo contracts show` @@ -4577,8 +4404,6 @@ memo contracts show <contract> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one contract with its dates, renewal and the last day to give notice - **Example:** `memo contracts show contract:2` ### `memo contracts add` @@ -4612,8 +4437,6 @@ memo contracts add <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a contract - **Example:** `memo contracts add 'Rental agreement' --kind service --start-date 2026-11-01 --end-date 2027-10-31 --auto-renew on --notice-days 30 --amount 120000.00 --currency RUB`, `memo contracts add 'NDA with the studio' --kind nda --project HRB` ### `memo contracts update` @@ -4645,8 +4468,6 @@ memo contracts update <contract> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** change a contract - **Example:** `memo contracts update contract:2 --status terminated`, `memo contracts update contract:2 --end-date 2027-12-31` ## `memo subscriptions` @@ -4670,8 +4491,6 @@ memo subscriptions list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most subscriptions, up to 500. Default: `100`. | -**Returns:** subscriptions, newest first; renews:2026-12-01 lists those that renew by then - **Example:** `memo subscriptions list status:active direction:payable`, `memo subscriptions list renews:2026-12-01 --json` ### `memo subscriptions show` @@ -4690,8 +4509,6 @@ memo subscriptions show <subscription> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one subscription with its parties, dates, current price and every price it had - **Example:** `memo subscriptions show subscription:5` ### `memo subscriptions add` @@ -4728,8 +4545,6 @@ memo subscriptions add <name> <amount> <currency> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a subscription; an agent's waits for your review - **Example:** `memo subscriptions add Hosting 990.00 RUB --kind payable --supplier organization:3 --period 1-month --start-date 2026-11-01`, `memo subscriptions add 'Bike rental' 10000.00 RUB --kind receivable --customer organization:3 --period 1-month --trial-end-date 2026-11-14 --status trial` ### `memo subscriptions update` @@ -4762,8 +4577,6 @@ memo subscriptions update <subscription> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** change a subscription - **Example:** `memo subscriptions update subscription:5 --status paused`, `memo subscriptions update subscription:5 --period 1-year` ### `memo subscriptions cancel` @@ -4787,8 +4600,6 @@ memo subscriptions cancel <subscription> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** cancel a subscription - **Example:** `memo subscriptions cancel subscription:5 --occurred-time 2026-11-30` ### `memo subscriptions prices` @@ -4819,8 +4630,6 @@ memo subscriptions prices add <subscription> <amount> <currency> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a subscription's new price - **Example:** `memo subscriptions prices add subscription:5 1190.00 RUB --start-date 2027-01-01` ## `memo wallets` @@ -4844,8 +4653,6 @@ memo wallets list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most wallets, up to 500. Default: `100`. | -**Returns:** wallets with their balances today; kind:card lists the cards - **Example:** `memo wallets list`, `memo wallets list kind:card --json` ### `memo wallets show` @@ -4865,8 +4672,6 @@ memo wallets show <wallet> [options] | `--until-time <time>` | the balance up to and including this day, such as 2026-10-31; today when left out. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one wallet with its balance and what is pending - **Example:** `memo wallets show wallet:2`, `memo wallets show wallet:2 --until-time 2026-10-31` ### `memo wallets add` @@ -4890,8 +4695,6 @@ memo wallets add <name> <currency> [options] | `--institution <text>` | the bank or other company that holds it, by name. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** add a bank account, card or cash wallet - **Example:** `memo wallets add 'Main card' RUB --kind card --institution 'Bank One'` ### `memo wallets update` @@ -4918,8 +4721,6 @@ memo wallets update <wallet> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** rename a wallet or set its opening balance - **Example:** `memo wallets update wallet:2 --opening-balance 15000.00 --opening-date 2026-01-01` ## `memo transactions` @@ -4943,8 +4744,6 @@ memo transactions list [query] [options] | `--json` | print JSON; --json=ref,title keeps only those fields. | | `--limit <n>` | most transactions, up to 500. Default: `100`. | -**Returns:** transactions, newest first - **Example:** `memo transactions list 'wallet:"wallet:2"' status:pending`, `memo transactions list uncategorized:true --json` ### `memo transactions show` @@ -4963,8 +4762,6 @@ memo transactions show <transaction> [options] |---|---| | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** one transaction with its wallet, payment, splits and what is not categorized - **Example:** `memo transactions show transaction:12` ### `memo transactions add` @@ -4996,8 +4793,6 @@ memo transactions add <wallet> <amount> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** record a transaction; an agent's waits for your review - **Example:** `memo transactions add wallet:2 500.00 --kind out --occurred-time 2026-11-14 --description 'Coffee shop'`, `memo transactions add wallet:2 10000.00 --kind in --payment payment:9` ### `memo transactions update` @@ -5023,8 +4818,6 @@ memo transactions update <transaction> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** book a transaction or link it to its payment - **Example:** `memo transactions update transaction:12 --status booked`, `memo transactions update transaction:12 --payment payment:9` ### `memo transactions splits` @@ -5054,8 +4847,6 @@ memo transactions splits add <transaction> <amount> <category> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** put part of a transaction under a category - **Example:** `memo transactions splits add transaction:12 300.00 Rent --project HRB` #### `memo transactions splits remove` @@ -5079,8 +4870,6 @@ memo transactions splits remove <transaction> <position> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON; --json=ref,title keeps only those fields. | -**Returns:** take a split off a transaction - **Example:** `memo transactions splits remove transaction:12 1` ## `memo records` @@ -5104,13 +4893,11 @@ memo records import <file> [options] | Option | What it does | |---|---| | `--dry-run` | check and plan the import; write nothing. a dry run holds the store's write lock and grows the write-ahead log for its length. | -| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, pipeline. | +| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, document, pipeline. | | `--account <account>` | the source the envelope is for: <provider>:<account> (sheet:rentals) or its source.account alone; phone:<device> for a vCard file. | | `--region <country>` | a vCard file's country for phone numbers without +, such as ru or gb; without it they are kept, not matched. | | `--json` | print JSON; --json=created,errors keeps only those fields. | -**Returns:** import a source's records; money waits for your review - **Example:** `memo records import payments.jsonl --account rentals --dry-run`, `memo records import envelope.json --account rentals --json`, `memo records import contacts.vcf --account phone:pixel --region gb` ### `memo records check` @@ -5129,13 +4916,11 @@ memo records check <file> [options] | Option | What it does | |---|---| -| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, pipeline. | +| `--type <type>` | the one type a CSV sheet holds: invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, document, pipeline. | | `--account <account>` | the source the envelope is for: <provider>:<account> (sheet:rentals) or its source.account alone; phone:<device> for a vCard file. | | `--region <country>` | a vCard file's country for phone numbers without +, such as ru or gb; without it they are kept, not matched. | | `--json` | print JSON; --json=created,errors keeps only those fields. | -**Returns:** check a records file against the store; write nothing - **Example:** `memo records check - --account rentals`, `memo records check invoices.csv --type invoice --account sheet:rentals` ### `memo records templates` @@ -5158,8 +4943,6 @@ memo records templates list [query] [options] |---|---| | `--json` | print JSON; --json=types keeps only those fields. | -**Returns:** the types a sheet can hold, with their columns - **Example:** `memo records templates list --json`, `memo records templates list type:invoice` #### `memo records templates show` @@ -5172,7 +4955,7 @@ memo records templates show <type> [options] | Argument | | What it is | |---|---|---| -| `type` | required | one of invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, pipeline. | +| `type` | required | one of invoice, payment, person, organization, project, order, product, contract, subscription, wallet, transaction, deal, lead, document, pipeline. | | Option | What it does | |---|---| @@ -5181,8 +4964,6 @@ memo records templates show <type> [options] | `--account <account>` | the source a JSON template names: <provider>:<account>, such as sheet:rentals. | | `--json` | print JSON; --json=text keeps only those fields. | -**Returns:** the CSV or JSON file to fill for one type - **Example:** `memo records templates show invoice --locale ru`, `memo records templates show invoice --format json --account sheet:rentals` ### `memo records list` @@ -5203,8 +4984,6 @@ memo records list [query] [options] | `--limit <n>` | most records, up to 500. Default: `100`. | | `--json` | print JSON; --json=type,external_id,entity keeps only those fields. | -**Returns:** a source's records; waiting:true lists what needs records link - **Example:** `memo records list waiting:true --account sheet:rentals`, `memo records list type:organization --account sheet:rentals --json`, `memo records list 'entity:"organization:3"' deleted:false --account sheet:rentals` ### `memo records link` @@ -5229,8 +5008,6 @@ memo records link <record> <ref> [options] | `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** say which of your entries a source's record is - **Example:** `memo records link organization:client organization:3 --account sheet:rentals` ### `memo records show` @@ -5250,8 +5027,6 @@ memo records show <record> [options] | `--account <account>` | the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals. | | `--json` | print JSON; --json=fields,relations,incoming,entity keeps only those fields. | -**Returns:** one record as its source said it - **Example:** `memo records show custom:quote:Q-7 --account example-erp:demo`, `memo records show organization:client --account sheet:rentals --json` ### `memo records delete` @@ -5273,8 +5048,6 @@ memo records delete <record> [options] | `--account <account>` | the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals. | | `--json` | print JSON; --json=deleted,flagged,errors keeps only those fields. | -**Returns:** mark a source's record deleted - **Example:** `memo records delete payment:sheet-12 --account sheet:rentals` ### `memo records match` @@ -5292,10 +5065,33 @@ memo records match [options] | `--account <account>` | the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals. | | `--json` | print JSON; --json=linked,created,unmatched keeps only those fields. | -**Returns:** match a source's waiting people and organizations - **Example:** `memo records match --account sheet:rentals` +## `memo import` + +bring a folder of text, Markdown, PDF and Word files, .vtt or .srt transcripts and, with --transcribe, recordings, one such file, or a records file (JSON or JSONL) into the store, under the account you name. Each file is a document keyed by its path in the folder: the same folder twice changes nothing, an edited file updates its document, and a file gone from the folder is kept. Links are not followed and nothing leaves this computer; the text is kept as data, never run + +This command changes the local store or your files. + +```sh +memo import <path> [options] +``` + +| Argument | | What it is | +|---|---|---| +| `path` | required | a folder, a .txt, .md, .pdf, .docx, .vtt, .srt or audio file, or a records file (.json, .jsonl; - for stdin). | + +| Option | What it does | +|---|---| +| `--as-owner` | act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal. | +| `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | +| `--account <account>` | the source the files belong to: import:<name> (import:handbook), or phone:<exchange> for call transcripts; never chosen for you. | +| `--transcribe` | hear recordings (.wav, .mp3, .m4a, .ogg, .opus, .flac) with the local speech model; a recording heard before and unchanged is not heard again. Without it recordings are skipped. | +| `--dry-run` | read every file and plan the import; write nothing. Holds the store's write lock meanwhile. | +| `--json` | print JSON; --json=created,skipped keeps only those fields. | + +**Example:** `memo import ~/Documents/handbook --account import:handbook --dry-run`, `memo import ./recordings --account phone:office-pbx --transcribe --json`, `memo import crm-notes.jsonl --account import:crm-notes` + ## `memo meetings` stored meeting evidence and reviewed findings @@ -5424,6 +5220,47 @@ memo meetings actions reject <id> [options] **Example:** `memo meetings actions reject 5 --fingerprint aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --account zoom:me@example.com` +### `memo meetings list` + +meetings, calls and calendar events of every account as one row per real meeting, latest start first + +```sh +memo meetings list [query] [options] +``` + +| Argument | | What it is | +|---|---|---| +| `query` | optional | field:value terms that narrow the list — the fields are below. | + +| Option | What it does | +|---|---| +| `--limit <n>` | rows per page, 1–1000; a month for a calendar fits in 1000. Default: `50`. | +| `--page <n>` | which page, from 1. Default: `1`. | +| `--order <recent\|start>` | recent: latest start first; start: oldest first, for a calendar window. Default: `recent`. | +| `--json` | print JSON; --json=ref,title keeps only those fields. | + +**Example:** `memo meetings list kind:call has_transcript:true`, `memo meetings list 'started_at:[2026-11-01T00:00:00+01:00 TO 2026-12-01T00:00:00+01:00}' --order start --json` + +### `memo meetings show` + +one meeting row: its people, transcript lines with times, summaries, findings, calendar text and documents + +```sh +memo meetings show <meeting> [options] +``` + +| Argument | | What it is | +|---|---|---| +| `meeting` | required | event:<id> or meeting:<account>/<id>, from meetings list. | + +| Option | What it does | +|---|---| +| `--cursor <cursor>` | the transcript line to start at: where the last read ended. Default: `0`. | +| `--limit <n>` | transcript lines at most, 1–2000. Default: `200`. | +| `--json` | print JSON; --json=ref,transcript keeps only those fields. | + +**Example:** `memo meetings show event:42 --limit 500 --json`, `memo meetings show meeting:3/7` + ### `memo meetings passage` read a cited cue with bounded context before and after it @@ -5467,12 +5304,12 @@ memo meetings prepare <series-id> [options] |---|---| | `--context-source <id=cursor>` | one stored app.profile or email.mailbox, optionally =cursor; repeat (tg.personal). Default: ``. | | `--context-query <words>` | literal words to find within the selected communications. | -| `--context-since-time <time>` | communications window start as zoned ISO timestamp (default fourteen days before end). | -| `--context-before-time <time>` | exclusive communications end as zoned ISO timestamp (default preparation start). | +| `--context-since-time <time>` | communications window start, an ISO date or time or 7d ago (default fourteen days before end). | +| `--context-before-time <time>` | exclusive communications end, an ISO date or time (default preparation start). | | `--project <project>` | include unconfirmed word evidence for one existing project name, key or alias. | -| `--since-time <time>` | window start as ISO timestamp with zone (default now). | -| `--before-time <time>` | exclusive window end as ISO timestamp (default seven days after start). | -| `--history-since-time <time>` | history start as ISO timestamp (default thirty days before start). | +| `--since-time <time>` | window start, an ISO date or time, local without a zone (default now). | +| `--before-time <time>` | exclusive window end, an ISO date or time; a date alone covers that day (default seven days after start). | +| `--history-since-time <time>` | history start, an ISO date or time or 30d ago (default thirty days before start). | | `--meetings <n>` | prior occurrences and separate related-meeting limit, 1–20 (default 5). | | `--cues <n>` | cues per occurrence, 1–100 (default 10). | | `--context-limit <n>` | entries per context category, 1–100 (default 20). | @@ -5513,8 +5350,6 @@ memo actions add <kind> [options] | `--payload <json>` | what to do, as JSON, such as the reply's text. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** propose an action, such as a reply or a ban, in the account that would act - **Example:** `memo actions add reply --reason 'Kai asked twice' --account telegram:1 --target 'msg:telegram/1/77/42' --payload '{"text":"Friday works"}'` ### `memo actions list` @@ -5536,8 +5371,6 @@ memo actions list [query] [options] | `--brief` | without each findings batch's cited sources. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** proposed actions, newest first - **Example:** `memo actions list status:proposed` ### `memo actions show` @@ -5556,8 +5389,6 @@ memo actions show <id> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one proposed action; a findings batch with its fingerprint and sources - **Example:** `memo actions show 5` ### `memo actions confirm` @@ -5583,8 +5414,6 @@ memo actions confirm <id> [findings] [options] | `--reason <text>` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** confirm it: a task to act on, or a findings batch's facts and tasks - **Example:** `memo actions confirm 5` ### `memo actions edit` @@ -5610,8 +5439,6 @@ memo actions edit <id> <finding> [options] | `--set <field=value...>` | a field and its new value: JSON for a list, null empties it. Default: ``. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** change a finding still waiting in a findings batch before you confirm it - **Example:** `memo actions edit 5 f2 --fingerprint 3f9a --set title="Send the signed contract" dueAt=null` ### `memo actions reject` @@ -5636,8 +5463,6 @@ memo actions reject <id> [options] | `--reason <text>` | why, in a few words; required when an agent decides for you. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** reject it; nothing is done. For a findings batch, every finding still waiting - **Example:** `memo actions reject 5` ## `memo review` @@ -5687,8 +5512,6 @@ memo review show <id> [options] | `--after-n <n>` | messages or document paragraphs after the evidence, at most 5. Default: `2`. | | `--compact` | one line, as review prints it. | -**Returns:** one proposal with its titles, signals and the text around each piece of evidence - **Example:** `memo review show 17079`, `memo review show 17080 --brief --json` ### `memo review confirm` @@ -5713,8 +5536,6 @@ memo review confirm <ids> [options] | `--reason <text>` | why, in a few words; required when an agent decides. | | `--compact` | one line per decision. | -**Returns:** confirm proposals by id or range; each on its own - **Example:** `memo review confirm 17078-17081`, `memo review confirm 17080/f1,17080/f3`, `memo review confirm close:Q-15` ### `memo review reject` @@ -5739,8 +5560,6 @@ memo review reject <ids> [options] | `--reason <text>` | why it is turned down, in a few words. | | `--compact` | one line per decision. | -**Returns:** turn proposals down, with why - **Example:** `memo review reject 17081 --reason "not this project"`, `memo review reject close:Q-15 --reason 'still open'` ### `memo review agenda` @@ -5761,8 +5580,6 @@ memo review agenda [options] | `--compact` | one line per item, shorter excerpts, the smaller budget: for an agent. | | `--json` | print JSON. | -**Returns:** morning digest: watched, owed, mail, meetings, calendar, Drive, CRM, tasks - **Example:** `memo review agenda --compact`, `memo review agenda --since-time 3d --json` ### `memo review status` @@ -5804,8 +5621,6 @@ memo agents list [query] [options] | `--page <n>` | which page, from 1. Default: `1`. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** one row per tool call, newest first: agent, tool, outcome and times - **Example:** `memo agents list agent:claude-code --limit 20` ## `memo mcp` @@ -5829,8 +5644,6 @@ memo mcp serve [options] | `--port <port>` | local HTTP port (default 8767); requires --http. | | `--public-url <url>` | tunnel's HTTPS address without /mcp, or a path of it such as https://<name>.ts.net/memo; requires --http. | -**Returns:** serve this profile's commands to an AI agent - **Example:** `memo mcp serve`, `memo mcp serve --http --public-url https://laptop.example.ts.net` ### `memo mcp revoke` @@ -5847,8 +5660,6 @@ memo mcp revoke [options] |---|---| | `--json` | print JSON. | -**Returns:** forget every login given to a browser app - **Example:** `memo mcp revoke --json` ### `memo mcp server` @@ -5872,8 +5683,6 @@ memo mcp server start [options] | `--permission <key=level>` | make a permission stricter for this server only; repeat for more keys. | | `--json` | print JSON. | -**Returns:** start the HTTP MCP server in the background - **Example:** `memo mcp server start --public-url https://laptop.example.ts.net` #### `memo mcp server stop` @@ -5890,8 +5699,6 @@ memo mcp server stop [options] |---|---| | `--json` | print JSON. | -**Returns:** stop the background HTTP MCP server - **Example:** `memo mcp server stop` #### `memo mcp server status` @@ -5906,8 +5713,6 @@ memo mcp server status [options] |---|---| | `--json` | print JSON. | -**Returns:** whether the HTTP MCP server runs, its login code and the apps logged in - **Example:** `memo mcp server status --json` ## `memo models` @@ -6028,8 +5833,6 @@ memo models consents show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether enrichment is on, with which provider and model, how many records it… - **Example:** `memo models consents show --json` #### `memo models consents set` @@ -6053,8 +5856,6 @@ memo models consents set <provider> [options] | `--yes` | agree that the records go to this provider, and turn enrichment on. | | `--json` | print JSON. | -**Returns:** turn enrichment on for one provider and model; without --yes, say what would… - **Example:** `memo models consents set openai --model gpt-4o-mini`, `memo models consents set openai --model gpt-4o-mini --yes` #### `memo models consents revoke` @@ -6071,8 +5872,6 @@ memo models consents revoke [options] |---|---| | `--json` | print JSON. | -**Returns:** turn enrichment off and delete what the model wrote; search reads only the… - **Example:** `memo models consents revoke` ### `memo models search-consents` @@ -6091,8 +5890,6 @@ memo models search-consents show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether search all --harder may call the model, which one, and whether its… - **Example:** `memo models search-consents show --json` #### `memo models search-consents set` @@ -6117,8 +5914,6 @@ memo models search-consents set <provider> [options] | `--yes` | agree that a --harder search sends its question and hits, and allow it. | | `--json` | print JSON. | -**Returns:** allow search all --harder to call the model; without --yes, say what it… - **Example:** `memo models search-consents set anthropic`, `memo models search-consents set anthropic --yes` #### `memo models search-consents revoke` @@ -6135,8 +5930,6 @@ memo models search-consents revoke [options] |---|---| | `--json` | print JSON. | -**Returns:** stop search all --harder from calling the model; it gives the plain order again - **Example:** `memo models search-consents revoke` ### `memo models keys` @@ -6203,8 +5996,6 @@ memo models ai show [options] |---|---| | `--json` | print JSON. | -**Returns:** the chosen model, its key, and whether images may go to it - **Example:** `memo models ai show` #### `memo models ai set` @@ -6230,8 +6021,6 @@ memo models ai set <provider> [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** choose the AI model: anthropic, openai or compatible, or ollama (beta) - **Example:** `memo models ai set anthropic --model claude-haiku-4-5 --secret-stdin --allow-remote`, `memo models ai set openai --model openai/gpt-4o-mini --base-url https://openrouter.ai/api/v1 --secret-stdin`, `memo models ai set ollama --model llama3.2-vision` #### `memo models ai unset` @@ -6249,8 +6038,6 @@ memo models ai unset [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** stop using a model; its key stays until models ai remove - **Example:** `memo models ai unset` #### `memo models ai remove` @@ -6272,8 +6059,6 @@ memo models ai remove [origin] [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** remove the key stored for an address - **Example:** `memo models ai remove https://api.anthropic.com` #### `memo models ai revoke` @@ -6291,15 +6076,13 @@ memo models ai revoke [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** stop sending images to the AI model; the model itself stays chosen - **Example:** `memo models ai revoke` #### `memo models ai check` send one short request (billed by the provider, usually under a cent) and say what is wrong -This command changes the local store or your files. +**Reads from an outside service.** ```sh memo models ai check [options] @@ -6310,8 +6093,6 @@ memo models ai check [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** send one short paid request and say what is wrong - **Example:** `memo models ai check` ### `memo models local-only` @@ -6330,8 +6111,6 @@ memo models local-only show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether local only is on, and where each feature sends data - **Example:** `memo models local-only show` #### `memo models local-only set` @@ -6353,8 +6132,6 @@ memo models local-only set <state> [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** turn local only on or off; only you turn it off - **Example:** `memo models local-only set on`, `memo models local-only set off` ### `memo models picture-reading` @@ -6373,8 +6150,6 @@ memo models picture-reading show [options] |---|---| | `--json` | print JSON. | -**Returns:** whether pictures are read, and by which agent - **Example:** `memo models picture-reading show` #### `memo models picture-reading set` @@ -6398,8 +6173,6 @@ memo models picture-reading set <mode> [options] | `--from-app` | you did this in WireCat Desktop. | | `--json` | print JSON. | -**Returns:** never, or on request with `images read`; only you turn it on - **Example:** `memo models picture-reading set request --agent claude`, `memo models picture-reading set request --agent codex --model gpt-5`, `memo models picture-reading set never` ## `memo templates` @@ -6444,8 +6217,6 @@ memo templates show <key> [options] | `--locale <code>` | the template's language, ISO 639-1; the owner's first language if not given. | | `--json` | print JSON. | -**Returns:** the template that applies, and the bodies your changes replaced - **Example:** `memo templates show report/morning-digest --channel telegram`, `memo templates show report/weekly-gaps --channel email --locale en --json` ### `memo templates edit` @@ -6470,8 +6241,6 @@ memo templates edit <key> [options] | `--undo` | put back the body your last change replaced; twice is back where you were. | | `--json` | print JSON. | -**Returns:** change a template in $EDITOR or from --file; checked before it is saved - **Example:** `memo templates edit report/morning-digest --channel telegram`, `memo templates edit report/morning-digest --channel text --file digest.text.liquid`, `memo templates edit report/morning-digest --channel telegram --undo` ### `memo templates preview` @@ -6493,8 +6262,6 @@ memo templates preview <key> [options] | `--file <file>` | preview this draft instead of the template that applies; - reads stdin. | | `--json` | print JSON. | -**Returns:** what would be sent on that channel; saves nothing - **Example:** `memo templates preview report/morning-digest --channel telegram`, `memo templates preview report/morning-digest --channel email --locale en --file draft.liquid` ### `memo templates reset` @@ -6517,8 +6284,6 @@ memo templates reset <key> [options] | `--locale <code>` | the template's language, ISO 639-1; the owner's first language if not given. | | `--json` | print JSON. | -**Returns:** go back to the shipped template; edit --undo brings yours back - **Example:** `memo templates reset report/morning-digest --channel telegram` ## `memo search` @@ -6549,7 +6314,7 @@ memo search all <query> [options] | `--harder` | a hosted model reorders the first 30 hits; sends the question and those hits to the provider you chose with memo models search-consents set <provider> --yes, only after that. | | `--project <project>` | rank the key documents of this project (id, project:<id>, key, exact name or alias) first; nothing is left out. | -**Returns:** hit — kind, ref, provider, account, title, timestamp, excerpt, url, and 17 more; every field: memo commands info search all +**Returns:** hit — kind, ref, provider, account, title, timestamp, excerpt, url, and 18 more; every field: memo commands info search all **Example:** `memo search all 'budget harbour'`, `memo search all 'Rental agreement' --only business`, `memo search all 'release date' --source zoom:work,notes --json` @@ -6704,9 +6469,9 @@ memo search meetings <query> [options] | `--series-id <id>` | only meetings in this stored series. | | `--project <project>` | meetings confirmed in this project, by name, key or alias. | | `--topic-name <name>` | meetings with this topic, by name or alias. | -| `--since-time <time>` | meetings starting at or after this ISO 8601 date or time. | +| `--since-time <time>` | meetings starting at or after this ISO 8601 date or time, or 30m, 2h, 7d ago. | | `--until-time <time>` | meetings starting at or before this ISO 8601 date or time; a date alone covers that whole local day. | -| `--limit <n>` | how many hits, 1 through 1000 (default 100). | +| `--limit <n>` | how many hits, 1 through 1000; the profile's defaults.limit when absent. | | `--cursor <cursor>` | continue from the previous page's page.next_cursor, with the same query and filters. | | `--max-read-bytes <bytes>` | most stored bytes to read, 1 through 67108864 (default 4194304). | | `--source <accounts>` | the meeting account: provider:account (zoom:me@example.com), or a provider that has one. | @@ -6714,6 +6479,8 @@ memo search meetings <query> [options] **Returns:** meeting hit — ref, meeting, scope, id, excerpt, offset_ms, language, line, and 5 more; every field: memo commands info search meetings +**Next usually:** `memo meetings show <meeting>` + **Example:** `memo search meetings budget --source zoom:me@example.com --project Harbour --since-time 2026-10-01 --limit 10 --json` ## `memo events` @@ -6787,8 +6554,6 @@ memo answers create <question> [query] [options] | `--allow-remote` | explicitly consent to sending this evidence to the configured model. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** prepare cited evidence for your agent, or explicitly call a configured model - **Example:** `memo answers create 'what did Kai say about the budget?' --all`, `memo answers create 'when is the launch?' --source telegram:1` ## `memo sync` @@ -6810,8 +6575,6 @@ memo sync [options] | `--timeout <duration>` | stop after this long, e.g. 10m; progress so far is kept (default: no limit). | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** sync notes, make stored mail searchable by meaning, and match people - **Example:** `memo sync`, `memo sync --only mail`, `memo sync --only notes --folder ~/notes --no-embed` ## `memo store` @@ -6846,6 +6609,8 @@ memo store recover [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | +**Example:** `memo store recover` + #### `memo store recover run` copy every readable row into a new file with the sqlite3 program, rebuild the search indexes, mentions and vector index, check it, and put it in place of the store; the damaged file is kept beside it. Refuses while a WireCat timer or process has the store @@ -6860,8 +6625,6 @@ memo store recover run [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** rebuild a damaged store from every row it can read - **Example:** `memo store recover run` ## `memo groups` @@ -6884,8 +6647,6 @@ memo groups list [query] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the saved groups, then all, with accounts, profiles and duplicates - **Example:** `memo groups list`, `memo groups list --json` ### `memo groups add` @@ -6907,8 +6668,6 @@ memo groups add <group> <source> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** put an account in a group - **Example:** `memo groups add work bitrix24:acme`, `memo groups add personal telegram:102` ### `memo groups remove` @@ -6930,8 +6689,6 @@ memo groups remove <group> <source> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** take an account out of a group - **Example:** `memo groups remove work telegram:102` ### `memo groups move` @@ -6954,8 +6711,6 @@ memo groups move <source> <from> <to> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** move an account between groups - **Example:** `memo groups move telegram:102 personal work` ### `memo groups rename` @@ -6977,8 +6732,6 @@ memo groups rename <group> <name> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** rename a group - **Example:** `memo groups rename work office` ### `memo groups delete` @@ -6999,8 +6752,6 @@ memo groups delete <group> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** delete a group - **Example:** `memo groups delete clients` ### `memo groups update` @@ -7023,8 +6774,6 @@ memo groups update <source> [options] | `--chat <chat>` | one chat of the account, by its id there. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** set an account's or one chat's scope, personal or work - **Example:** `memo groups update bitrix24:acme --scope work`, `memo groups update telegram:102 --chat 7 --scope account` ## `memo jobs` @@ -7045,8 +6794,6 @@ memo jobs start [options] |---|---| | `--every <duration>` | how often: 5m, 90s, 1h — a minute or more. | -**Returns:** sync every --every (default auto.every, else 5m), starting a minute from now - **Example:** `memo jobs start --every 10m` ### `memo jobs stop` @@ -7059,8 +6806,6 @@ This command changes the local store or your files. memo jobs stop ``` -**Returns:** stop syncing on a timer and remove the timer - **Example:** `memo jobs stop` ### `memo jobs status` @@ -7075,8 +6820,6 @@ memo jobs status [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** whether the timer is on, its interval, its next run and how the last one ended - **Example:** `memo jobs status --json` ## `memo config` @@ -7095,8 +6838,6 @@ memo config show [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** every setting, its value, its default and whether the file sets it - **Example:** `memo config show`, `memo config show --json` ### `memo config migrate` @@ -7113,8 +6854,6 @@ memo config migrate [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** write each setting the file lacks at its default, keeping yours - **Example:** `memo config migrate` ### `memo config unset` @@ -7135,8 +6874,6 @@ memo config unset <key> [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** remove one setting from the config file, even one memo does not know - **Example:** `memo config unset permissions.notes.edit` ## `memo doctor` @@ -7153,8 +6890,6 @@ memo doctor [options] | `--deep` | also read every page of the store and check every search index (about 30 s for 6 GB); without it, only the file header and schema. | | `--json` | print JSON; --json=id,title keeps only those fields. | -**Returns:** the state this installation is in, without connecting unless --online - **Example:** `memo doctor`, `memo doctor --json` ## `memo upgrade` @@ -7172,8 +6907,6 @@ memo upgrade [options] | `--check` | say whether a newer version exists, and install nothing. | | `--json` | print JSON. | -**Returns:** upgrade memo with the package manager that installed it; --check only looks - **Example:** `memo upgrade --check` ## `memo schedule` @@ -7204,8 +6937,6 @@ memo schedule command <name> <args> [options] | `--deliver-to <route>` | also send the result, when --notify-on says so, by the owner's own tg or mail: telegram-bot:<profile>/<chat id or user:id>, or email:<profile>/<address>; repeat it for more. | | `--json` | print JSON. | -**Returns:** run memo <args…> on a timer — reads save what they read, so this is how a… - **Example:** `memo schedule command digest --at 08:30 -- review status`, `memo schedule command mail-sync --every 1h -- sync --only mail` ### `memo schedule agent` @@ -7240,8 +6971,6 @@ memo schedule agent <name> <harness> <prompt> [options] | `--mail-batch <n>` | with --on-new-mail: or once this many emails wait (default 10, or the config file's). | | `--json` | print JSON. | -**Returns:** start an agent (claude, codex, gemini, cursor, opencode, openclaw, hermes,… - **Example:** `memo schedule agent triage claude 'read memo review status and list what needs me today' --at 08:45 --max-cost 1`, `memo schedule agent mail-triage claude 'Run memo skill show mail-triage and follow it.' --every 5m --on-new-mail mail-triage --mail-wait 1h --mail-batch 20 --max-cost 1 --max-cost-per-day 5`, `memo schedule agent weekly claude 'read memo review status and sum up the week' --at 09:00 --model opus` ### `memo schedule list` @@ -7312,8 +7041,6 @@ memo schedule run <name> [options] | `--deliver-to <route>` | send it along only this one of its own routes; repeat it for more. | | `--json` | print JSON. | -**Returns:** run a schedule now, as its timer would, and wait for it; a paused one runs too - **Example:** `memo schedule run digest` ### `memo schedule remove` @@ -7334,8 +7061,6 @@ memo schedule remove <name> [options] |---|---| | `--json` | print JSON. | -**Returns:** stop a schedule and remove its timer; its past output stays - **Example:** `memo schedule remove digest` ### `memo schedule pause` @@ -7356,8 +7081,6 @@ memo schedule pause <name> [options] |---|---| | `--json` | print JSON. | -**Returns:** take a schedule off its timer and keep it; run runs it, resume puts it back - **Example:** `memo schedule pause digest` ### `memo schedule resume` @@ -7378,8 +7101,6 @@ memo schedule resume <name> [options] |---|---| | `--json` | print JSON. | -**Returns:** put a paused schedule back on its timer - **Example:** `memo schedule resume digest` ### `memo schedule exec` @@ -7401,8 +7122,6 @@ memo schedule exec <file> [seal] [options] |---|---| | `--json` | print JSON. | -**Returns:** what a timer runs, given the schedule's file; to run one by hand, use run - **Example:** `memo schedule exec ~/.local/state/cli-memo/schedules/digest/schedule.json` ## `memo digest` @@ -7427,8 +7146,6 @@ memo digest brief show [digest] [options] |---|---| | `--json` | print JSON. | -**Returns:** the brief a digest follows, and the bodies your changes replaced - **Example:** `memo digest brief show`, `memo digest brief show --json` #### `memo digest brief edit` @@ -7451,8 +7168,6 @@ memo digest brief edit [digest] [options] | `--undo` | put back the body your last change replaced. | | `--json` | print JSON. | -**Returns:** write the brief in $EDITOR or from --file; only you, never an agent - **Example:** `memo digest brief edit`, `memo digest brief edit --file brief.md`, `memo digest brief edit --undo` #### `memo digest brief reset` @@ -7473,8 +7188,6 @@ memo digest brief reset [digest] [options] |---|---| | `--json` | print JSON. | -**Returns:** remove the brief; edit --undo brings it back - **Example:** `memo digest brief reset` ### `memo digest list` @@ -7491,8 +7204,6 @@ memo digest list [query] [options] |---|---| | `--json` | print JSON. | -**Returns:** your digests: when each runs, what it reads, where it goes, last and next run - **Example:** `memo digest list`, `memo digest list name:weekly --json` ### `memo digest add` @@ -7525,8 +7236,6 @@ memo digest add <name> [options] | `--json` | print JSON. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** make a digest: its times, sources, routes and brief, on its timer - **Example:** `memo digest add evening --title 'Evening digest' --at 18:00 --deliver-to telegram-bot:personal/user:42`, `memo digest add weekly --title 'The week' --at 'mon 09:00' --source telegram,mail,tasks` ### `memo digest edit` @@ -7558,8 +7267,6 @@ memo digest edit <name> [options] | `--json` | print JSON. | | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | -**Returns:** change a digest; each option given replaces what it says, the rest stays - **Example:** `memo digest edit evening --at 08:30 --at 18:00`, `memo digest edit weekly --source all --deliver-to none` ### `memo digest run` @@ -7583,8 +7290,6 @@ memo digest run <name> [options] | `--deliver-to <route>` | send it only along this one of the digest's routes; repeat it for more. | | `--json` | print JSON. | -**Returns:** build a digest now and send it along its routes, or only some, or none - **Example:** `memo digest run evening`, `memo digest run weekly --no-notify --json` ### `memo digest pause` @@ -7604,8 +7309,6 @@ memo digest pause <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON. | -**Returns:** take a digest off its timer; it stays, and run still builds it - **Example:** `memo digest pause weekly` ### `memo digest resume` @@ -7625,8 +7328,6 @@ memo digest resume <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON. | -**Returns:** put a paused digest back on its timer - **Example:** `memo digest resume weekly` ### `memo digest remove` @@ -7646,8 +7347,6 @@ memo digest remove <name> [options] | `--from-app` | you did this in WireCat Desktop: record it as yours, with no terminal question. | | `--json` | print JSON. | -**Returns:** remove a digest and its timer; its past runs, brief and templates stay - **Example:** `memo digest remove weekly` ### `memo digest backfill` @@ -7672,8 +7371,6 @@ memo digest backfill [digest] [options] | `--yes` | build them; without it, only the estimate is printed. | | `--json` | print JSON. | -**Returns:** build a digest's past runs, without sending them - **Example:** `memo digest backfill --since-time 2026-11-01 --until-time 2026-11-07`, `memo digest backfill --since-time 2026-11-01 --until-time 2026-11-07 --yes --json` ## `memo commands` @@ -7692,6 +7389,8 @@ memo commands [path] [options] |---|---| | `--json` | print JSON; --json=id,title keeps only those fields. | +**Example:** `memo commands` + ### `memo commands info` one command contract, or all schemas, error reasons and explicit overrides @@ -7708,8 +7407,6 @@ memo commands info [path] [options] |---|---| | `--json` | print JSON. | -**Returns:** one command contract, or all schemas, error reasons and explicit overrides - **Example:** `memo commands info --json` ## `memo skill` @@ -7733,8 +7430,6 @@ memo skill show [name] [options] | `--for <agents>` | print the copy installed for these agents instead of this version's. One of: `claude`, `agents`. | | `--json` | print JSON. | -**Returns:** print the tool's instructions for AI agents - **Example:** `memo skill show` ### `memo skill install` @@ -7752,8 +7447,6 @@ memo skill install [options] | `--for <agents>` | which agents to install for. One of: `claude`, `agents`, `hermes`, `all`. Default: `all`. | | `--json` | print JSON. | -**Returns:** install the tool's instructions for AI agents - **Example:** `memo skill install --for all` ### `memo skill status` @@ -7768,8 +7461,6 @@ memo skill status [options] |---|---| | `--json` | print JSON. | -**Returns:** whether the installed instructions for AI agents match this version - **Example:** `memo skill status`, `memo skill status --json` ## `memo guide` @@ -7788,8 +7479,6 @@ memo guide [name] [options] |---|---| | `--json` | print JSON. | -**Returns:** scenarios: the commands for a common task, in order, and why each - **Example:** `memo guide`, `memo guide person-brief --json` ## `memo runs` @@ -7810,8 +7499,8 @@ memo runs list [query] [options] | Option | What it does | |---|---| -| `--limit <n>` | how many to show. Default: `20`. | -| `--page <n>` | which page, starting at 1. Default: `1`. | +| `--limit <n>` | how many to show. | +| `--page <n>` | which page, starting at 1. | | `--json` | print JSON. | **Returns:** run — run_id, command, started_at, status, cli_version, profile, completed_at, requests, and 23 more; every field: memo commands info runs list diff --git a/translations/memo/configuration.es.md b/translations/memo/configuration.es.md index 40b6d6db..45bb62db 100644 --- a/translations/memo/configuration.es.md +++ b/translations/memo/configuration.es.md @@ -37,7 +37,7 @@ válido se corrige a mano en la línea y la columna que indica `memo doctor`. | Clave | Significado | |---|---| -| `folders` | Tus carpetas de notas. Cada una tiene el `id` que le dio el almacén local, su `path` en este ordenador y su `format`: `obsidian` (el predeterminado) o `markdown`. `memo folders add` escribe una entrada; la importación rechaza una entrada sin `id`. Consulta [Markdown u Obsidian](./notes.md#markdown-or-obsidian). | +| `folders` | Tus carpetas de notas. Cada una tiene el `id` que le dio el almacén local, su `path` en este ordenador y su `format`: `obsidian` o `markdown`, que elige `memo folders add` cuando no indicas `--format`. `memo folders add` escribe una entrada; la importación rechaza una entrada sin `id`. Consulta [Markdown u Obsidian](./notes.md#markdown-or-obsidian). | | `ignore` | Archivos y carpetas que la importación omite: una ruta dentro de la carpeta, una carpeta o un patrón como `**/Private*`. `--ignore` añade reglas para una sola ejecución. | | `embed` | `false` deja las notas fuera de la búsqueda por significado. | | `export` | `dir` y `format` para `memo notes export` y `--export` cuando no indicas ninguna carpeta. | diff --git a/translations/memo/configuration.ru.md b/translations/memo/configuration.ru.md index 36097614..340adcde 100644 --- a/translations/memo/configuration.ru.md +++ b/translations/memo/configuration.ru.md @@ -37,7 +37,7 @@ migrate` записывает каждую настройку, которой н | Ключ | Значение | |---|---| -| `folders` | Ваши папки с заметками. У каждой есть `id`, который ей присвоило локальное хранилище, `path` на этом компьютере и `format`: `obsidian` (по умолчанию) или `markdown`. `memo folders add` добавляет запись; запись без `id` импорт отклоняет. См. [Markdown или Obsidian](./notes.md#markdown-or-obsidian). | +| `folders` | Ваши папки с заметками. У каждой есть `id`, который ей присвоило локальное хранилище, `path` на этом компьютере и `format`: `obsidian` или `markdown`. Если вы не указали `--format`, его выбирает `memo folders add`. `memo folders add` добавляет запись; запись без `id` импорт отклоняет. См. [Markdown или Obsidian](./notes.md#markdown-or-obsidian). | | `ignore` | Файлы и папки, которые импорт пропускает: путь внутри папки, папка или шаблон, например `**/Private*`. `--ignore` добавляет правила на один запуск. | | `embed` | `false` исключает заметки из поиска по смыслу. | | `export` | `dir` и `format` для `memo notes export` и `--export`, когда вы не указываете папку. | diff --git a/translations/memo/import.es.md b/translations/memo/import.es.md new file mode 100644 index 00000000..6fae1bf7 --- /dev/null +++ b/translations/memo/import.es.md @@ -0,0 +1,274 @@ +--- +title: "Importar archivos y registros" +--- + +Esta página te ayuda a traer a Memo datos que ninguna herramienta de WireCat sincroniza: una carpeta de archivos de +texto, transcripciones o los registros que escribe un pequeño script tuyo. Tras la importación los encuentran +`memo search`, un agente por MCP y todo lo demás que lee el almacén de Memo, junto a tus mensajes, tu correo y tus +notas. + +```sh +memo import ~/Documents/handbook --account import:handbook --dry-run +memo import ~/Documents/handbook --account import:handbook +memo import crm-notes.jsonl --account import:crm-notes +``` + +## La cuenta + +Cada importación indica la cuenta a la que pertenece con `--account <provider>:<account>`. Memo nunca elige una por +ti: sin `--account`, el error lista las cuentas que ya tienen importaciones. Una cuenta nueva se crea la primera vez +que la nombras. + +- **`import:<name>`** para documentos, notas y exportaciones: `import:handbook`, `import:crm-notes`. +- **`phone:<exchange>`** para transcripciones de llamadas, junto a las llamadas de esa centralita: `phone:office-pbx`. + +Los archivos solo van a estos dos proveedores, que no pertenecen a ninguna sincronización. Cualquier otra cuenta, como +la de un mensajero o la de Drive, se rechaza (`record.provider-not-imported`): es de su propia sincronización. Usa una +cuenta por fuente, y así `memo search --source import:handbook` encuentra solo sus documentos. + +## Qué lee la importación de una carpeta + +| Archivo | Se convierte en | +|---|---| +| `.txt`, `.text` | Un documento cuyo título es el nombre del archivo | +| `.md`, `.markdown` | Un documento cuyo título es el primer encabezado, después del front matter, o si no el nombre del archivo | +| `.pdf`, `.docx` | Un documento que leen en este ordenador los lectores de [Archivos que Memo puede leer](./notes.md#files-memo-can-read). Su título es el del propio archivo, o si no su nombre. Un PDF escaneado no tiene texto y se omite | +| `.vtt`, `.srt` | Una transcripción: una línea `Name: text` por intervención, como la guarda [Fuentes que añades a mano](./sources.md#add-a-source). Los tiempos y los hablantes van a `metadata.transcript` | +| `.wav`, `.mp3`, `.m4a`, `.ogg`, `.opus`, `.flac` | Con `--transcribe`, lo que se dijo, reconocido en este ordenador ([Grabaciones](#recordings)). Sin esa opción, la grabación se omite | +| `.json`, `.jsonl` indicado por sí solo | Registros, tal como los lee `memo records import` ([Integraciones propias](#custom-integrations)) | + +Memo recorre la carpeta y sus subcarpetas. Deja fuera los nombres que empiezan por `.` (`.git`, `.obsidian`). La +respuesta lista en `skipped` cada otro archivo que no importó, con el motivo: un tipo de archivo sin lector, un +archivo que no es texto UTF-8, un archivo vacío o un enlace simbólico. + +En lugar de una carpeta puedes indicar un solo archivo `.txt` o `.md`. Su documento se identifica solo por el nombre +del archivo, así que dos archivos con el mismo nombre de carpetas distintas son un solo documento. En ese caso, importa +su carpeta. + +## Grabaciones + +```sh +memo import ./recordings --account import:voice-memos --transcribe +``` + +`--transcribe` reconoce cada grabación con el modelo de voz local `parakeet-v3`, que entiende 25 idiomas. La grabación +nunca sale de este ordenador. Cada fragmento que reconoció el modelo es una línea del texto del documento, con el +momento en que empieza en la grabación: + +```text +[00:00] Depot, good morning. +[01:01] The crane is due Friday. +``` + +- **El modelo no se descarga solo.** Ocupa unos 670 MB. Sin él, la importación se detiene antes de escribir nada e + indica el comando que lo descarga una vez, como `tg models download parakeet-v3`. Todas las herramientas de WireCat + de este ordenador lo comparten. +- **Una grabación se reconoce una sola vez.** Su documento guarda el hash de los bytes de la grabación. La siguiente + importación con `--transcribe` encuentra el mismo hash y vuelve a enviar el texto guardado, así que la grabación no + se reconoce de nuevo y el documento queda `unchanged`. Una grabación modificada se reconoce otra vez. +- `--dry-run` no transcribe: lista las grabaciones nuevas en `skipped`. +- Una grabación se trata como una sola voz: no distingue a los hablantes. Una grabación de más de una hora, o una que + el decodificador no puede leer, aparece en `skipped` y el resto de la carpeta se importa. +- Memo lee MP3, Ogg, Opus y FLAC con sus propios decodificadores. WAV, M4A y otros formatos necesitan `ffmpeg` + instalado. + +## Repítela cuando quieras + +- **La misma carpeta dos veces no cambia nada.** Cada archivo se identifica por su ruta dentro de la carpeta, así que + la segunda ejecución responde `unchanged` para cada archivo. +- **Un archivo editado actualiza su propio documento.** Se sustituyen su texto, su título y sus fechas, y el documento + conserva su referencia, así que los enlaces y los hechos que lo citan siguen apuntando a él. +- **Un archivo que desaparece de la carpeta se queda.** Memo no borra lo que importaste cuando el archivo desaparece. + Para quitar uno, envía un registro `delete` para él ([Integraciones propias](#custom-integrations)). +- **Un archivo renombrado o movido es un documento nuevo.** La ruta es su clave. +- **Una carpeta movida actualiza cada documento una vez.** Las rutas dentro de ella no cambian, así que no se añade + ningún documento, pero la `url` de cada uno indica el nuevo lugar. +- Un archivo cuya fecha de modificación cambió pero cuyo texto no, cuenta como `updated`. + +`--dry-run` lee todos los archivos y planifica la importación sin escribir nada. Mientras se ejecuta, bloquea la +escritura en el almacén. `--json` muestra el recibo para un script. + +## Qué se guarda + +Cada archivo es un registro `document` con: + +| Campo | Valor | +|---|---| +| `title` | El primer encabezado Markdown, o el nombre del archivo sin su extensión | +| `text` | El texto del archivo | +| `created_at` | Cuándo se creó el archivo, si el sistema de archivos lo indica; si no, su fecha de modificación | +| `updated_at` | Su fecha de modificación | +| `url` | La dirección `file://` del archivo en este ordenador | +| `metadata.path` | Su ruta dentro de la carpeta | +| `metadata.format` | `text`, `markdown`, `pdf`, `docx`, `vtt` o `srt` | +| `metadata.extractor` | El lector de un archivo PDF o Word, con su versión | +| `metadata.transcript` | Para una transcripción: `cues`, `start_seconds`, `end_seconds` y `speakers` | +| `metadata.audio` | Para una grabación: su duración en `seconds`, el `model` de voz y el número de `pieces` | +| `metadata.sha256` | El hash de los bytes del archivo | +| `metadata.size` | Su tamaño en bytes | + +El recibo dice qué ejecución lo escribió: su `source.batchId` indica la hora de la importación, y la ejecución de un +agente añade el nombre del agente. + +## Límites + +- **10.000 archivos** en una importación de carpeta. Un árbol más grande se rechaza entero: importa sus carpetas una a + una. +- **32 niveles de carpetas.** Las carpetas más profundas aparecen en `skipped`. +- **50 MiB** por archivo, **256 MiB** por grabación. Un archivo más grande se omite. +- **Un millón de caracteres** de texto por documento, dentro de 1 MiB. Un texto más largo se corta: la respuesta lista + el archivo en `cut` y su `metadata.truncated` es `true`. + +## Seguridad + +- **Nada sale de este ordenador.** Memo lee los archivos donde están y solo escribe en su almacén local. +- **Los enlaces no se siguen.** Un enlace simbólico dentro de la carpeta se omite, así que una importación nunca lee + un archivo fuera de la carpeta que indicaste. La propia carpeta que indicas sí puede ser un enlace. +- **Sin credenciales.** Un archivo cuyo texto contiene algo con forma de credencial, como una clave privada o un token + `Bearer`, se rechaza y aparece en `skipped` (`record.secret-field`). Los demás archivos se importan. +- **El texto son datos.** Memo lo guarda y busca en él, y no ejecuta nada de su contenido. Un agente que lee un + documento importado lo lee como fuente, no como instrucciones. +- **La importación de un agente queda a nombre del agente.** Si se ejecuta desde la terminal de un agente, el campo + `by` del recibo nombra al agente. Por MCP, un agente no puede ejecutar `memo import`: entrega los registros con + `records import`. + +## Integraciones propias + +Una fuente sin herramienta de WireCat llega a Memo mediante un archivo de registros: el **sobre de registros**, un +formato JSON con versión que leen tanto `memo import` como `memo records import`. Un script obtiene los datos de la API +o de una exportación de la fuente, escribe el sobre y se lo da a Memo. No necesitas conocer la base de datos de Memo. + +El sobre en JSONL: la primera línea indica la versión del formato y la fuente, y cada línea siguiente es un registro. + +```jsonl +{"schema_version":1,"source":{"provider":"import","account":"crm-notes","batch_id":"2026-11-13"}} +{"key":"p1","type":"person","external_id":"contact-17","operation":"upsert","fields":{"name":"Ana Example","email":"ana@example.com"}} +{"key":"n1","type":"document","external_id":"note-901","operation":"upsert","fields":{"title":"Delivery call","text":"The crane is due Friday.","created_at":"2026-11-10T09:02:00+01:00","metadata":{"manager":"reception"}},"relations":[{"role":"about","type":"person","external_id":"contact-17"}]} +``` + +- **`external_id` es el id del registro en la fuente.** Mantenlo estable: el mismo id es el mismo registro en cada + ejecución, así que volver a ejecutar el script actualiza lo que cambió y deja el resto. Nunca uses un número de fila + ni la hora de la ejecución. +- **`operation`** es `upsert`, o `delete` para quitar un registro que enviaste antes. +- **`fields`** contienen los datos del registro. Las claves que un tipo no conoce se guardan tal como llegan. + `metadata` guarda todo lo demás que valga la pena saber. +- **`relations`** enlazan registros de la misma cuenta, o una entidad del almacén por `ref`: un documento `about` una + persona, una organización, un trato o una llamada. +- `memo records templates show <type> --format json` muestra un registro de ejemplo de cada tipo. El formato completo, + cada tipo y cada regla están en [The records envelope](https://github.com/WireCatLabs/cli-core/blob/main/docs/storage/records-envelope.md). + +Comprueba un archivo antes de escribirlo y luego impórtalo: + +```sh +memo import crm-notes.jsonl --account import:crm-notes --dry-run +memo import crm-notes.jsonl --account import:crm-notes +``` + +### Un adaptador de fuente en 20 líneas + +Este script de Node convierte una exportación de notas de un CRM separada por tabuladores (`id`, `date`, el correo del +cliente, `text`) en el sobre por stdout: cada cliente es una persona identificada por su correo, y cada nota un +documento sobre esa persona. Memo lo lee desde stdin con `-`: + +```js +// notes-to-envelope.mjs: node notes-to-envelope.mjs notes.tsv | memo import - --account import:crm-notes +import { readFileSync } from "node:fs" + +const [, ...rows] = readFileSync(process.argv[2], "utf8").trim().split("\n") +const line = (value) => process.stdout.write(`${JSON.stringify(value)}\n`) +const people = new Set() + +line({ schema_version: 1, source: { provider: "import", account: "crm-notes", batch_id: new Date().toISOString() } }) +for (const row of rows) { + const [id, date, email, text] = row.split("\t") + if (!people.has(email)) { + people.add(email) + line({ key: email, type: "person", external_id: email, operation: "upsert", fields: { name: email, email } }) + } + line({ + key: id, type: "document", external_id: `note-${id}`, operation: "upsert", + fields: { title: `Note ${id}`, text, created_at: date }, + relations: [{ role: "about", type: "person", external_id: email }], + }) +} +``` + +Las fechas deben llevar su desfase horario (`2026-11-10T09:00:00+01:00`). Una persona se identifica por un correo +exacto, nunca por el nombre. Si ningún contacto tiene ese correo, se crea una persona nueva. + +### Ejemplo: historial de llamadas de Asterisk + +Una centralita [Asterisk](https://www.asterisk.org/) escribe un registro de detalle de llamada (CDR) por cada llamada, +en `/var/log/asterisk/cdr-csv/Master.csv`, y puede grabar llamadas con MixMonitor. Este script hace que las llamadas se +puedan buscar: cada llamada pasa a ser un evento `call`, y la transcripción de su grabación, cuando la hay, un +documento `about` esa llamada. Ambos van a la cuenta `phone:office-pbx`. + +El script toma el texto de cada grabación de un archivo `.txt` junto a ella, que puede escribir cualquier herramienta +local de reconocimiento de voz. Usa este camino o +`memo import /var/spool/asterisk/monitor --account phone:office-pbx --transcribe`, no los dos: ese comando también +importa los archivos `.txt` que encuentra allí, y las mismas palabras se guardarían dos veces. +`memo import --transcribe` crea un documento por grabación, pero sin enlazarlo con su llamada. + +Convierte el CDR en el sobre: + +```js +// asterisk-cdr.mjs: node asterisk-cdr.mjs Master.csv +01:00 | memo import - --account phone:office-pbx +import { existsSync, readFileSync } from "node:fs" + +const [file, offset] = process.argv.slice(2) +const cells = (row) => { + const out = [""] + let quoted = false + for (let i = 0; i < row.length; i++) { + if (row[i] === '"' && quoted && row[i + 1] === '"') out[out.length - 1] += row[i++] + else if (row[i] === '"') quoted = !quoted + else if (row[i] === "," && !quoted) out.push("") + else out[out.length - 1] += row[i] + } + return out +} +const line = (value) => process.stdout.write(`${JSON.stringify(value)}\n`) + +line({ + schema_version: 1, + source: { provider: "phone", account: "office-pbx", batch_id: new Date().toISOString() }, + options: { phone_region: "es" }, +}) +for (const row of readFileSync(file, "utf8").trim().split("\n")) { + const c = cells(row) + const [src, dst, start, seconds, disposition, id, recording] = [c[1], c[2], c[9], c[13], c[14], c[16], c[17]] + const inbound = dst.length <= 4 + const startedAt = `${start.replace(" ", "T")}${offset}` + line({ + key: id, type: "event", external_id: id, operation: "upsert", + fields: { + kind: "call", phone: inbound ? src : dst, started_at: startedAt, duration: Number(seconds), + direction: !inbound ? "out" : disposition === "ANSWERED" ? "in" : "missed", + }, + }) + const transcript = recording && recording.replace(/\.\w+$/, ".txt") + if (!transcript || !existsSync(transcript)) continue + line({ + key: `t-${id}`, type: "document", external_id: `transcript-${id}`, operation: "upsert", + fields: { + title: `Call ${inbound ? "from" : "to"} ${inbound ? src : dst}`, + text: readFileSync(transcript, "utf8"), + created_at: startedAt, + metadata: { recording, disposition }, + }, + relations: [{ role: "about", type: "event", external_id: id }], + }) +} +``` + +- **El `uniqueid` del CDR es el id del registro.** Es estable, así que ejecutar el script cada noche actualiza las + llamadas que cambiaron y añade las nuevas. +- **El CDR no tiene zona horaria.** Pasa el desfase de la centralita (`+01:00`), o `+00:00` cuando `cdr.conf` define + `usegmtime=yes`. El sobre rechaza una hora sin desfase. +- **`phone_region`** lee los números locales sin `+` como números de ese país, así que una llamada se enlaza con la + persona cuyo contacto tiene ese número. +- Las columnas son las de `cdr_csv` con `loguniqueid` y `loguserfield` activados: el `uniqueid` es la columna 17 y el + `userfield` la 18. El script lee la ruta de la grabación del `userfield`, que el plan de marcación rellena con + `Set(CDR(userfield)=${MIXMONITOR_FILENAME})`. Una plantilla `cdr_custom` necesita su propio orden. Los números de + cuatro cifras o menos se toman como extensiones internas. Comprueba las columnas con tu propio `Master.csv` antes + de la primera ejecución. diff --git a/translations/memo/import.ru.md b/translations/memo/import.ru.md new file mode 100644 index 00000000..83f61354 --- /dev/null +++ b/translations/memo/import.ru.md @@ -0,0 +1,271 @@ +--- +title: "Импорт файлов и записей" +--- + +Эта страница поможет добавить в Memo данные, которые не синхронизирует ни один инструмент WireCat: папку текстовых +файлов, расшифровки или записи, которые пишет ваш собственный небольшой скрипт. После импорта их находят +`memo search`, агент через MCP и всё остальное, что читает хранилище Memo, рядом с вашими сообщениями, почтой и +заметками. + +```sh +memo import ~/Documents/handbook --account import:handbook --dry-run +memo import ~/Documents/handbook --account import:handbook +memo import crm-notes.jsonl --account import:crm-notes +``` + +## Аккаунт + +Каждый импорт называет аккаунт, которому он принадлежит: `--account <provider>:<account>`. Memo никогда не выбирает +аккаунт за вас: без `--account` ошибка перечисляет аккаунты, в которых уже есть импорт. Новый аккаунт появляется, +когда вы впервые его называете. + +- **`import:<name>`** для документов, заметок и выгрузок: `import:handbook`, `import:crm-notes`. +- **`phone:<exchange>`** для расшифровок звонков, рядом со звонками этой АТС: `phone:office-pbx`. + +Файлы попадают только к этим двум провайдерам, которыми не владеет ни одна синхронизация. Любой другой аккаунт, +например мессенджера или Drive, импорт отклоняет (`record.provider-not-imported`): им владеет его собственная +синхронизация. Держите по одному аккаунту на источник, тогда `memo search --source import:handbook` найдёт только его +документы. + +## Что читает импорт папки + +| Файл | Что получается | +|---|---| +| `.txt`, `.text` | Документ, его название это имя файла | +| `.md`, `.markdown` | Документ, его название это первый заголовок после front matter, а если заголовка нет, имя файла | +| `.pdf`, `.docx` | Документ, который читают на этом компьютере те же читатели, что в разделе [Файлы, которые читает Memo](./notes.md#files-memo-can-read). Название берётся из самого файла, иначе это его имя. В отсканированном PDF нет текста, и такой файл пропускается | +| `.vtt`, `.srt` | Расшифровка: одна строка `Name: text` на реплику, как в разделе [Источники, которые вы добавляете сами](./sources.md#add-a-source). Метки времени и говорящие попадают в `metadata.transcript` | +| `.wav`, `.mp3`, `.m4a`, `.ogg`, `.opus`, `.flac` | С `--transcribe` это сказанное в записи, распознанное на этом компьютере ([Записи](#recordings)). Без него запись пропускается | +| `.json`, `.jsonl`, переданный отдельно | Записи, так же как их читает `memo records import` ([Свои интеграции](#custom-integrations)) | + +Memo обходит папку и все вложенные папки. Имена, которые начинаются с `.` (`.git`, `.obsidian`), он не трогает. +Каждый другой файл, который не попал в импорт, ответ перечисляет в `skipped` с причиной: для такого типа файлов нет +читателя, файл не в текстовой кодировке UTF-8, файл пустой или это символическая ссылка. + +Вместо папки можно передать один файл `.txt` или `.md`. Его документ определяется только по имени файла, поэтому два +файла с одним именем из разных папок станут одним документом. В таком случае импортируйте их папку. + +## Записи + +```sh +memo import ./recordings --account import:voice-memos --transcribe +``` + +С `--transcribe` каждую запись распознаёт локальная модель речи `parakeet-v3`, которая понимает 25 языков. Запись +не покидает этот компьютер. Каждый распознанный фрагмент становится строкой текста документа с отметкой, где он +начинается в записи: + +```text +[00:00] Depot, good morning. +[01:01] The crane is due Friday. +``` + +- **Модель не скачивается сама.** Она весит около 670 МБ. Без неё импорт останавливается, ничего не записав, и + называет команду, которая скачает модель один раз, например `tg models download parakeet-v3`. Все инструменты + WireCat на этом компьютере пользуются одной копией. +- **Каждая запись распознаётся один раз.** Документ хранит хеш байтов записи. Следующий импорт с `--transcribe` + находит тот же хеш и снова отправляет сохранённый текст, так что запись не распознаётся заново, а документ остаётся + `unchanged`. Изменённая запись распознаётся заново. +- `--dry-run` ничего не распознаёт: новые записи он показывает в `skipped`. +- Вся запись считается одним голосом: говорящие не различаются. Запись длиннее часа или та, которую декодер не может + прочитать, попадает в `skipped`, а остальная папка импортируется. +- MP3, Ogg, Opus и FLAC Memo читает своими декодерами. Для WAV, M4A и других форматов нужен установленный `ffmpeg`. + +## Повторяйте когда угодно + +- **Та же папка второй раз ничего не меняет.** Каждый файл определяется по своему пути внутри папки, поэтому второй + запуск отвечает `unchanged` для каждого файла. +- **Изменённый файл обновляет свой документ.** Его текст, название и даты заменяются, а ссылка на документ остаётся + прежней, поэтому ссылки и факты, которые на него опираются, по-прежнему ведут к нему. +- **Файл, который исчез из папки, остаётся.** Memo не удаляет импортированное, когда файл пропадает. Чтобы убрать + документ, отправьте для него запись `delete` ([Свои интеграции](#custom-integrations)). +- **Переименованный или перенесённый файл становится новым документом.** Ключ документа это путь. +- **Перенесённая папка один раз обновляет все документы.** Пути внутри неё не меняются, поэтому новых документов не + появляется, но `url` каждого указывает на новое место. +- Файл, у которого изменилось время изменения, а текст остался прежним, считается `updated`. + +`--dry-run` читает все файлы и планирует импорт, ничего не записывая. Пока он работает, хранилище закрыто для записи. +`--json` выводит квитанцию для скрипта. + +## Что сохраняется + +Каждый файл становится записью `document` с полями: + +| Поле | Значение | +|---|---| +| `title` | Первый заголовок Markdown или имя файла без расширения | +| `text` | Текст файла | +| `created_at` | Когда файл был создан, если это сообщает файловая система, иначе время его изменения | +| `updated_at` | Время его изменения | +| `url` | Адрес файла на этом компьютере в виде `file://` | +| `metadata.path` | Его путь внутри папки | +| `metadata.format` | `text`, `markdown`, `pdf`, `docx`, `vtt` или `srt` | +| `metadata.extractor` | Читатель файла PDF или Word и его версия | +| `metadata.transcript` | Для расшифровки: `cues`, `start_seconds`, `end_seconds` и `speakers` | +| `metadata.audio` | Для записи: её длина в `seconds`, модель речи `model` и число фрагментов `pieces` | +| `metadata.sha256` | Хеш байтов файла | +| `metadata.size` | Его размер в байтах | + +Квитанция показывает, какой запуск её записал: `source.batchId` называет время импорта, а запуск агента добавляет имя +агента. + +## Ограничения + +- **10 000 файлов** в одном импорте папки. Дерево побольше отклоняется целиком: импортируйте его папки по одной. +- **32 уровня вложенности.** Более глубокие папки попадают в `skipped`. +- **50 МиБ** на файл, **256 МиБ** на запись. Файл крупнее пропускается. +- **Миллион символов** текста на документ, в пределах 1 МиБ. Более длинный текст обрезается: ответ показывает файл в + `cut`, а его `metadata.truncated` равно `true`. + +## Безопасность + +- **Ничего не покидает этот компьютер.** Memo читает файлы там, где они лежат, и пишет только в своё локальное + хранилище. +- **Ссылки не открываются.** Символическая ссылка внутри папки пропускается, поэтому импорт никогда не читает файл за + пределами названной вами папки. Сама названная папка может быть ссылкой. +- **Никаких учётных данных.** Файл, в тексте которого есть что-то похожее на учётные данные, например закрытый ключ + или токен `Bearer`, отклоняется и попадает в `skipped` (`record.secret-field`). Остальные файлы импортируются. +- **Текст это данные.** Memo хранит его и ищет по нему, но ничего из него не выполняет. Агент, который читает + импортированный документ, читает его как источник, а не как инструкции. +- **Импорт агента записывается на агента.** Если импорт запущен из терминала агента, поле `by` в квитанции называет + агента. Через MCP агент вообще не может запустить `memo import`: он передаёт записи через `records import`. + +## Свои интеграции + +Источник, для которого нет инструмента WireCat, попадает в Memo через файл записей. Это **конверт записей**, формат +JSON с номером версии, который читают и `memo import`, и `memo records import`. Скрипт берёт данные из API или +выгрузки источника, пишет конверт и отдаёт его Memo. Знать устройство базы данных Memo для этого не нужно. + +Конверт в виде JSONL: первая строка называет версию формата и источник, каждая следующая строка это одна запись. + +```jsonl +{"schema_version":1,"source":{"provider":"import","account":"crm-notes","batch_id":"2026-11-13"}} +{"key":"p1","type":"person","external_id":"contact-17","operation":"upsert","fields":{"name":"Ana Example","email":"ana@example.com"}} +{"key":"n1","type":"document","external_id":"note-901","operation":"upsert","fields":{"title":"Delivery call","text":"The crane is due Friday.","created_at":"2026-11-10T09:02:00+01:00","metadata":{"manager":"reception"}},"relations":[{"role":"about","type":"person","external_id":"contact-17"}]} +``` + +- **`external_id` это id записи в источнике.** Он не должен меняться: один и тот же id означает одну и ту же запись + при каждом запуске, поэтому повторный запуск скрипта обновит изменившееся и не тронет остальное. Не используйте + номер строки или время запуска. +- **`operation`** это `upsert` или `delete`, чтобы удалить запись, отправленную раньше. +- **`fields`** содержат данные записи. Ключи, которых тип не знает, сохраняются как есть. В `metadata` можно положить + всё остальное, что стоит знать. +- **`relations`** связывают записи одного аккаунта или сущность хранилища по `ref`: например, документ `about` + человека, организацию, сделку или звонок. +- `memo records templates show <type> --format json` выводит пример записи каждого типа. Полный формат, все типы и + все правила описаны на странице [The records envelope](https://github.com/WireCatLabs/cli-core/blob/main/docs/storage/records-envelope.md). + +Проверьте файл, прежде чем записывать, и затем импортируйте его: + +```sh +memo import crm-notes.jsonl --account import:crm-notes --dry-run +memo import crm-notes.jsonl --account import:crm-notes +``` + +### Адаптер источника в 20 строк + +Этот скрипт на Node превращает выгрузку заметок из CRM с табуляцией в качестве разделителя (`id`, `date`, e-mail +клиента, `text`) в конверт на stdout. Каждый клиент становится человеком, которого находят по e-mail, каждая заметка +документом об этом человеке. Memo читает конверт из stdin, если вместо файла указать `-`: + +```js +// notes-to-envelope.mjs: node notes-to-envelope.mjs notes.tsv | memo import - --account import:crm-notes +import { readFileSync } from "node:fs" + +const [, ...rows] = readFileSync(process.argv[2], "utf8").trim().split("\n") +const line = (value) => process.stdout.write(`${JSON.stringify(value)}\n`) +const people = new Set() + +line({ schema_version: 1, source: { provider: "import", account: "crm-notes", batch_id: new Date().toISOString() } }) +for (const row of rows) { + const [id, date, email, text] = row.split("\t") + if (!people.has(email)) { + people.add(email) + line({ key: email, type: "person", external_id: email, operation: "upsert", fields: { name: email, email } }) + } + line({ + key: id, type: "document", external_id: `note-${id}`, operation: "upsert", + fields: { title: `Note ${id}`, text, created_at: date }, + relations: [{ role: "about", type: "person", external_id: email }], + }) +} +``` + +Даты должны быть со смещением часового пояса (`2026-11-10T09:00:00+01:00`). Человек находится только по точному +e-mail, никогда по имени. Если такого адреса нет ни у одного контакта, создаётся новый человек. + +### Пример: история звонков из Asterisk + +АТС [Asterisk](https://www.asterisk.org/) пишет запись о каждом звонке (CDR) в +`/var/log/asterisk/cdr-csv/Master.csv` и умеет записывать звонки через MixMonitor. Этот скрипт делает звонки +доступными для поиска: каждый звонок становится событием `call`, а расшифровка его записи, если она есть, документом +`about` этого звонка. И то, и другое попадает в аккаунт `phone:office-pbx`. + +Текст каждой записи скрипт берёт из файла `.txt` рядом с ней, который может написать любая локальная программа +распознавания речи. Используйте либо этот путь, либо +`memo import /var/spool/asterisk/monitor --account phone:office-pbx --transcribe`, но не оба: эта команда тоже +импортирует найденные там файлы `.txt`, и одни и те же слова сохранятся дважды. `memo import --transcribe` создаёт +документ для каждой записи, но не связывает его со звонком. + +Превратите CDR в конверт: + +```js +// asterisk-cdr.mjs: node asterisk-cdr.mjs Master.csv +01:00 | memo import - --account phone:office-pbx +import { existsSync, readFileSync } from "node:fs" + +const [file, offset] = process.argv.slice(2) +const cells = (row) => { + const out = [""] + let quoted = false + for (let i = 0; i < row.length; i++) { + if (row[i] === '"' && quoted && row[i + 1] === '"') out[out.length - 1] += row[i++] + else if (row[i] === '"') quoted = !quoted + else if (row[i] === "," && !quoted) out.push("") + else out[out.length - 1] += row[i] + } + return out +} +const line = (value) => process.stdout.write(`${JSON.stringify(value)}\n`) + +line({ + schema_version: 1, + source: { provider: "phone", account: "office-pbx", batch_id: new Date().toISOString() }, + options: { phone_region: "es" }, +}) +for (const row of readFileSync(file, "utf8").trim().split("\n")) { + const c = cells(row) + const [src, dst, start, seconds, disposition, id, recording] = [c[1], c[2], c[9], c[13], c[14], c[16], c[17]] + const inbound = dst.length <= 4 + const startedAt = `${start.replace(" ", "T")}${offset}` + line({ + key: id, type: "event", external_id: id, operation: "upsert", + fields: { + kind: "call", phone: inbound ? src : dst, started_at: startedAt, duration: Number(seconds), + direction: !inbound ? "out" : disposition === "ANSWERED" ? "in" : "missed", + }, + }) + const transcript = recording && recording.replace(/\.\w+$/, ".txt") + if (!transcript || !existsSync(transcript)) continue + line({ + key: `t-${id}`, type: "document", external_id: `transcript-${id}`, operation: "upsert", + fields: { + title: `Call ${inbound ? "from" : "to"} ${inbound ? src : dst}`, + text: readFileSync(transcript, "utf8"), + created_at: startedAt, + metadata: { recording, disposition }, + }, + relations: [{ role: "about", type: "event", external_id: id }], + }) +} +``` + +- **`uniqueid` из CDR это id записи.** Он не меняется, поэтому ночной запуск скрипта обновляет изменившиеся звонки и + добавляет новые. +- **В CDR нет часового пояса.** Передайте смещение АТС (`+01:00`) или `+00:00`, если в `cdr.conf` задано + `usegmtime=yes`. Конверт не принимает время без смещения. +- **`phone_region`** читает местные номера без `+` как номера этой страны, поэтому звонок связывается с человеком, у + которого этот номер есть в контакте. +- Столбцы соответствуют `cdr_csv` с включёнными `loguniqueid` и `loguserfield`: `uniqueid` в столбце 17, а + `userfield` в столбце 18. Путь к записи скрипт берёт из `userfield`, который заполняет план набора командой + `Set(CDR(userfield)=${MIXMONITOR_FILENAME})`. Для шаблона `cdr_custom` нужен свой порядок столбцов. Номера из + четырёх цифр и короче считаются внутренними. Перед первым запуском сверьте столбцы со своим `Master.csv`. diff --git a/translations/memo/installation.es.md b/translations/memo/installation.es.md index c167a415..a69fcd99 100644 --- a/translations/memo/installation.es.md +++ b/translations/memo/installation.es.md @@ -81,7 +81,7 @@ memo commands --json # every command and option, for agents and scripts Memo no requiere iniciar sesión ni una configuración inicial. Añade una carpeta de notas, léela y busca: ```sh -memo folders add ~/Documents/Notes # your notes folder; Obsidian format by default +memo folders add ~/Documents/Notes # your notes folder; Obsidian format when it is a vault memo sync --only notes # reads the notes, their links and tags memo search notes "budget" ``` diff --git a/translations/memo/installation.ru.md b/translations/memo/installation.ru.md index 61aa802c..6507f877 100644 --- a/translations/memo/installation.ru.md +++ b/translations/memo/installation.ru.md @@ -81,7 +81,7 @@ memo commands --json # every command and option, for agents and scripts Memo не требует входа или отдельной настройки. Добавьте папку заметок, прочитайте её и выполните поиск: ```sh -memo folders add ~/Documents/Notes # your notes folder; Obsidian format by default +memo folders add ~/Documents/Notes # your notes folder; Obsidian format when it is a vault memo sync --only notes # reads the notes, their links and tags memo search notes "budget" ``` diff --git a/translations/memo/mcp.es.md b/translations/memo/mcp.es.md index d7f489d9..fb9ca205 100644 --- a/translations/memo/mcp.es.md +++ b/translations/memo/mcp.es.md @@ -81,6 +81,10 @@ Pon el bloqueo en el entorno del proceso que inicia la aplicación. El agente no Las exclusiones reservadas a CLI son los comandos `mcp`, `upgrade`, `skill install`, `jobs start` y `jobs stop`: inician otro servidor, sustituyen el programa, instalan instrucciones en otras aplicaciones o gestionan un temporizador. +`schedule list`, `agents list`, `run` y `exec` están disponibles, como en todo CLI de WireCat: un agente puede iniciar +una programación que creaste tú. `schedule command`, `agent`, `remove`, `pause` y `resume` necesitan `mcp.authority`, +que por defecto es `deny`, así que solo tú creas, quitas o detienes una. + `notes add` y `notes edit` reciben la nota como `text`. `--text-file` y `--export` no se ofrecen, y una ejecución por MCP los rechaza antes de guardar nada. Así un agente no puede hacer que Memo lea un archivo de este equipo o la propia entrada del servidor, ni que escriba un archivo en una carpeta que elija. diff --git a/translations/memo/mcp.ru.md b/translations/memo/mcp.ru.md index b4498ac1..f2a3573a 100644 --- a/translations/memo/mcp.ru.md +++ b/translations/memo/mcp.ru.md @@ -82,6 +82,10 @@ Memo использует общий интерфейс MCP из cli-core. В н Исключения только для CLI: команды `mcp`, `upgrade`, `skill install`, `jobs start` и `jobs stop`. Они запускают другой сервер, заменяют выполняемую программу, устанавливают инструкции в другие приложения или управляют таймером. +`schedule list`, `agents list`, `run` и `exec` доступны, как в каждом CLI WireCat: агент может запустить расписание, +которое вы создали. `schedule command`, `agent`, `remove`, `pause` и `resume` требуют `mcp.authority`, а это право по +умолчанию `deny`. Поэтому создать, удалить или остановить расписание можете только вы. + `notes add` и `notes edit` принимают заметку как `text`. `--text-file` и `--export` не предлагаются, а запуск через MCP отклоняет их до сохранения. Так агент не может заставить Memo прочитать файл на этом компьютере или собственный ввод сервера либо записать файл в выбранную им папку. diff --git a/translations/memo/notes.es.md b/translations/memo/notes.es.md index 621c7f3d..22e8d64a 100644 --- a/translations/memo/notes.es.md +++ b/translations/memo/notes.es.md @@ -27,18 +27,18 @@ Tell me how many notes it found and which files it could not read. **O ejecuta tú los comandos.** Sustituye `/path/to/notes` por la ruta completa de tu carpeta. -Para una carpeta de archivos Markdown normales: - ```sh -memo folders add /path/to/notes --format markdown +memo folders add /path/to/notes memo sync --only notes --no-embed ``` -Para una bóveda de Obsidian: +Memo elige el formato por ti. Una carpeta es una bóveda de Obsidian cuando ella, o una carpeta superior, tiene la +carpeta propia de Obsidian, `.obsidian`: Memo la lee como `obsidian`. Cualquier otra carpeta es `markdown`. Con +`--json`, la respuesta trae `format` y `format_from`: `detected`, `option` si indicaste `--format`, o `saved` para una +carpeta que Memo ya conocía. Para elegirlo tú, añade `--format`: ```sh -memo folders add /path/to/vault --format obsidian -memo sync --only notes --no-embed +memo folders add /path/to/notes --format markdown ``` `memo folders add` muestra el ID de la carpeta, por ejemplo `1`. `memo sync --only notes` lee las notas y @@ -61,7 +61,9 @@ segundo. Solo contiene recuentos, nunca un nombre de archivo: `label` es el ID de la carpeta. -Puedes añadir más de una carpeta. `memo folders list` las muestra todas. +Puedes añadir más de una carpeta. `memo folders list` las muestra todas. Memo rechaza una carpeta que está dentro +de otra que ya lee, o que la contiene (motivo `folder.overlap`), porque cada archivo compartido serían dos notas. +`memo doctor` señala ese par en una configuración antigua. ### Quitar una carpeta @@ -80,7 +82,7 @@ El almacén conserva el ID de la carpeta, así que `memo folders update` puede v El formato le dice a Memo cómo se escriben los enlaces y las etiquetas en tus notas. No necesitas Obsidian para usar Memo, y Obsidian no tiene que estar abierto. -| | `markdown` | `obsidian` (el predeterminado) | +| | `markdown` | `obsidian` | |---|---|---| | Enlaces a otras notas | Enlaces Markdown al archivo (abajo) | `[[Other note]]`, `[[Other note\|label]]`, también con `#heading` | | Etiquetas | el campo `tags:` al principio del archivo | el campo `tags:` y `#tags` en el texto | @@ -98,6 +100,10 @@ enlaces escritos como referencias, como `[Kai](person:7)` o un simple `msg:teleg Una **bóveda de Obsidian** es una carpeta de notas Markdown que Obsidian abre como un solo espacio de trabajo. Memo omite las carpetas ocultas, como `.obsidian`. +Para cambiar el formato de una carpeta, añádela de nuevo con `--format` o usa `memo folders update` con `--format`. El +siguiente `memo sync --only notes` vuelve a leer todas las notas de esa carpeta, así que una `#word` que antes era +etiqueta deja de serlo. + ### Archivos que Memo puede leer | Archivos | Extensiones | Qué guarda Memo | diff --git a/translations/memo/notes.ru.md b/translations/memo/notes.ru.md index acc82004..88c63f6d 100644 --- a/translations/memo/notes.ru.md +++ b/translations/memo/notes.ru.md @@ -27,18 +27,18 @@ Tell me how many notes it found and which files it could not read. **Или выполните команды сами.** Замените `/path/to/notes` на полный путь к вашей папке. -Для папки с обычными файлами Markdown: - ```sh -memo folders add /path/to/notes --format markdown +memo folders add /path/to/notes memo sync --only notes --no-embed ``` -Для папки Obsidian: +Формат Memo выберет сам. Папка считается папкой Obsidian, если в ней или в папке выше есть служебная папка +Obsidian `.obsidian`: такую папку Memo читает как `obsidian`. Любая другая папка получает `markdown`. С `--json` в +ответе есть `format` и `format_from`: `detected`, `option`, если вы указали `--format`, или `saved` для папки, которую +Memo уже знал. Чтобы выбрать формат самому, добавьте `--format`: ```sh -memo folders add /path/to/vault --format obsidian -memo sync --only notes --no-embed +memo folders add /path/to/notes --format markdown ``` `memo folders add` выводит ID папки, например `1`. `memo sync --only notes` читает заметки и сообщает, @@ -61,7 +61,9 @@ memo sync --only notes --no-embed `label` это ID папки. -Можно добавить несколько папок. `memo folders list` показывает их все. +Можно добавить несколько папок. `memo folders list` показывает их все. Папку внутри той, что Memo уже читает, или +папку, которая её содержит, Memo не добавит (причина `folder.overlap`): каждый общий файл стал бы двумя заметками. +В старом файле настроек такую пару назовёт `memo doctor`. ### Удалите папку @@ -80,7 +82,7 @@ memo folders remove 1 --allow-delete --yes # also deletes its notes from t Формат сообщает Memo, как в ваших заметках записаны ссылки и теги. Чтобы пользоваться Memo, Obsidian не нужен, и Obsidian не обязательно держать открытым. -| | `markdown` | `obsidian` (по умолчанию) | +| | `markdown` | `obsidian` | |---|---|---| | Ссылки на другие заметки | Ссылки Markdown на файл (см. ниже) | `[[Other note]]`, `[[Other note\|label]]`, а также с `#heading` | | Теги | поле `tags:` в начале файла | поле `tags:` и `#tags` в тексте | @@ -98,6 +100,10 @@ memo folders remove 1 --allow-delete --yes # also deletes its notes from t **Папка Obsidian** (vault) — это папка с заметками Markdown, которую Obsidian открывает как одно рабочее пространство. Memo пропускает скрытые папки, например `.obsidian`. +Чтобы сменить формат папки, добавьте её ещё раз с `--format` или выполните `memo folders update` с `--format`. +Следующий `memo sync --only notes` заново прочитает все заметки этой папки, и `#word`, который раньше считался тегом, +перестанет им быть. + ### Файлы, которые читает Memo | Файлы | Расширения | Что сохраняет Memo | diff --git a/translations/memo/people.es.md b/translations/memo/people.es.md index 18034b61..b3848b46 100644 --- a/translations/memo/people.es.md +++ b/translations/memo/people.es.md @@ -94,6 +94,8 @@ fuente que no leyó, con el motivo. La respuesta reúne: - los eventos de calendario a los que está invitada, los próximos y los últimos pasados, de cada calendario que gcal guardó. La respuesta nombra los calendarios que leyó. El título y el lugar de un evento los escribe quien envió la invitación, y `--json` lista esos campos bajo `untrusted`; +- `meetings`: las llamadas y reuniones grabadas en las que participó, de la más reciente a la más antigua, cada una con + su cuenta. `meetings show` de la herramienta dueña de la cuenta abre una; - la nota sobre ella, las notas que enlazan a ella y las notas que escribiste sobre ella en Memo; - las tareas abiertas que tratan sobre ella o que tiene asignadas. - los archivos de Google Drive que posee o que editó por última vez, tal como los indica Google. No has revisado estos diff --git a/translations/memo/people.ru.md b/translations/memo/people.ru.md index e51519a2..55ae9fb6 100644 --- a/translations/memo/people.ru.md +++ b/translations/memo/people.ru.md @@ -92,6 +92,8 @@ memo context person:7 - события календаря, на которые он приглашён: ближайшие и последние прошедшие, из каждого календаря, который сохранил gcal. Ответ называет прочитанные календари. Название и место события пишет тот, кто отправил приглашение, а `--json` перечисляет эти поля в `untrusted`; +- `meetings`: записанные звонки и встречи, в которых он участвовал, сначала новые, у каждой указан аккаунт. Открыть + встречу можно через `meetings show` того инструмента, которому принадлежит аккаунт; - главная заметка о нём, заметки, которые ссылаются на него, и заметки, которые вы написали о нём в Memo; - открытые задачи, которые касаются его или назначены ему. - файлы Google Drive, которыми он владеет или которые последним изменял, как их показывает Google. Эти связи вы не diff --git a/translations/memo/sources.es.md b/translations/memo/sources.es.md index 15742a15..32b933b2 100644 --- a/translations/memo/sources.es.md +++ b/translations/memo/sources.es.md @@ -6,6 +6,8 @@ Esta página te ayuda a dar a Memo una cosa que recordar: un archivo, una págin guarda como un documento propio, así que la encuentras al buscar, un agente la encuentra cuando consulta algo y los hechos pueden citarla. Una carpeta vigilada sirve para muchos archivos que cambian a menudo ([Notas y carpetas](./notes.md)). Esta página es para una sola fuente. +Las transcripciones, exportaciones y registros de una fuente que ninguna herramienta de WireCat sincroniza entran con +`memo import` ([Importar archivos y registros](./import.md)). ## Añadir una fuente @@ -17,7 +19,7 @@ pbpaste | memo sources add - --subject person:12 | Das | Memo lee | |---|---| -| La ruta de un archivo | El archivo, con los lectores de [Archivos que Memo puede leer](./notes.md#files-memo-can-read), y páginas web guardadas como `.html` o `.htm` | +| La ruta de un archivo | El archivo, con los lectores de [Archivos que Memo puede leer](./notes.md#files-memo-can-read), páginas web guardadas como `.html` o `.htm`, y transcripciones de reuniones guardadas como `.vtt` o `.srt` | | Una dirección `http` o `https` | La página, una vez, desde este ordenador, tal como está hoy | | `-` | El texto de stdin | @@ -36,6 +38,9 @@ pbpaste | memo sources add - --subject person:12 - **`--max-chars`** guarda como mucho esa cantidad de caracteres de texto, hasta 2.000.000 (por defecto 200.000). La respuesta dice `truncated: true` cuando solo se guardó la primera parte. +Una transcripción de reunión guardada como WebVTT (`.vtt`) o SubRip (`.srt`) se guarda como lo que se dijo: una línea +por intervención, `Name: text` cuando el archivo nombra a quien habla, sin los tiempos. + Un PDF escaneado no tiene texto que Memo pueda leer. Se guarda solo por su título y sus temas (`read: "no-text"`). Una imagen (PNG, JPEG o WebP, hasta 4 MB) la lee tu modelo de IA cuando elegiste uno y aceptaste que las imágenes diff --git a/translations/memo/sources.ru.md b/translations/memo/sources.ru.md index 92333319..2e20aaca 100644 --- a/translations/memo/sources.ru.md +++ b/translations/memo/sources.ru.md @@ -6,6 +6,8 @@ title: "Источники, которые вы добавляете сами" хранит ее как отдельный документ, поэтому вы находите ее поиском, агент находит ее, когда что-то ищет, а факты могут на нее ссылаться. Папка, за которой следит Memo, нужна для многих файлов, которые часто меняются ([Заметки и папки](./notes.md)). Эта страница про один источник. +Расшифровки, выгрузки и записи из источника, который не синхронизирует ни один инструмент WireCat, добавляются через +`memo import` ([Импорт файлов и записей](./import.md)). ## Добавьте источник @@ -17,7 +19,7 @@ pbpaste | memo sources add - --subject person:12 | Что дать | Что читает Memo | |---|---| -| Путь к файлу | Файл, теми же читателями, что в разделе [Файлы, которые читает Memo](./notes.md#files-memo-can-read), и веб-страницы, сохраненные как `.html` или `.htm` | +| Путь к файлу | Файл, теми же читателями, что в разделе [Файлы, которые читает Memo](./notes.md#files-memo-can-read), веб-страницы, сохраненные как `.html` или `.htm`, и расшифровки встреч в форматах `.vtt` и `.srt` | | Адрес `http` или `https` | Страницу, один раз, с этого компьютера, в том виде, в каком она есть сегодня | | `-` | Текст из stdin | @@ -35,6 +37,9 @@ pbpaste | memo sources add - --subject person:12 - **`--max-chars`** оставляет не больше этого числа символов текста, до 2 000 000 (по умолчанию 200 000). Ответ пишет `truncated: true`, когда сохранена только первая часть. +Расшифровка встречи в формате WebVTT (`.vtt`) или SubRip (`.srt`) сохраняется как запись разговора: одна строка на +реплику, `Name: text`, если файл называет говорящего, без меток времени. + У отсканированного PDF нет текста, который Memo может прочитать. Такой источник хранится только по заголовку и предметам (`read: "no-text"`). diff --git a/translations/memo/usage.es.md b/translations/memo/usage.es.md index d5927846..b34d7252 100644 --- a/translations/memo/usage.es.md +++ b/translations/memo/usage.es.md @@ -51,6 +51,40 @@ memo events list account:phone:pixel starts_at>=2026-10-01 memo events show event:42 # one event, and the accounts and calendars that hold it ``` +## Reuniones y llamadas en una sola lista + +`memo meetings list` reúne en una lista los eventos del calendario, las reuniones de Zoom o Meet y las llamadas +telefónicas importadas, con una fila por cada reunión real: un evento del calendario y su reunión de Zoom son una sola +fila cuando el almacén los vinculó, o cuando comparten sala y sus horas se solapan. Cada fila dice de dónde viene, quién +participó (con sus referencias `person:`), sus enlaces para unirse y si hay una grabación, una transcripción o un +resumen guardados. Una fila aparece cuando se solapa con el periodo indicado. Sin periodo, son los últimos 30 días y +los 7 siguientes, y `started_at:[* TO *]` las lee todas. `memo meetings show` añade las líneas de la transcripción con +sus horas, los resúmenes, los hallazgos que esperan tu decisión y el texto del calendario. + +```sh +memo meetings list # every account, latest first +memo meetings list 'started_at:[2026-11-01 TO 2026-12-01}' kind:call +memo meetings list 'started_at:[2026-11-09T00:00:00+01:00 TO 2026-11-16T00:00:00+01:00}' --order start +memo meetings list 'started_at:[* TO *]' --page 3 # every row, no window +memo meetings list has_transcript:true person:"person:12" +memo meetings show event:42 --limit 100 # or meeting:<account>/<id> +``` + +## Todos los documentos + +`memo documents list` lista los documentos de todas las cuentas: Drive, carpetas de notas, fuentes que añadiste e +importaciones, primero los cambiados más recientemente, con su fuente, carpeta, tipo y enlace. Una palabra busca en su +texto igual que `memo search notes`. `memo documents tree` da las carpetas de cada cuenta con cuántos documentos tiene +cada una, y `memo documents show` una parte del texto de un documento con sus etiquetas, personas y reuniones. + +```sh +memo documents list # every account, newest first +memo documents list budget kind:pdf source:google-drive +memo documents list 'folder:"Projects/Acme"' --page 2 +memo documents tree --depth 2 +memo documents show document:42 --cursor 20000 +``` + ## Prepararte para una conversación ```text prompt diff --git a/translations/memo/usage.ru.md b/translations/memo/usage.ru.md index 2ad1a571..e8ec1e5e 100644 --- a/translations/memo/usage.ru.md +++ b/translations/memo/usage.ru.md @@ -51,6 +51,40 @@ memo events list account:phone:pixel starts_at>=2026-10-01 memo events show event:42 # one event, and the accounts and calendars that hold it ``` +## Встречи и звонки одним списком + +`memo meetings list` собирает в один список события календаря, встречи из Zoom или Meet и импортированные телефонные +звонки. Одна строка соответствует одной настоящей встрече: событие календаря и его встреча в Zoom дают одну строку, +если хранилище их связало или если у них общая комната и время пересекается. В строке видно, откуда она, кто +участвовал (со ссылками `person:`), ссылки для входа и есть ли сохранённая запись, расшифровка или итоги. В список +попадают строки, которые пересекаются с заданным периодом. Без периода это последние 30 дней и следующие 7, а +`started_at:[* TO *]` показывает всё. `memo meetings show` добавляет строки расшифровки со временем, итоги, находки, +которые ждут вашего решения, и текст из календаря. + +```sh +memo meetings list # every account, latest first +memo meetings list 'started_at:[2026-11-01 TO 2026-12-01}' kind:call +memo meetings list 'started_at:[2026-11-09T00:00:00+01:00 TO 2026-11-16T00:00:00+01:00}' --order start +memo meetings list 'started_at:[* TO *]' --page 3 # every row, no window +memo meetings list has_transcript:true person:"person:12" +memo meetings show event:42 --limit 100 # or meeting:<account>/<id> +``` + +## Все документы + +`memo documents list` показывает документы всех аккаунтов: Drive, папки заметок, добавленные вами источники и +импорт. Сначала идут недавно изменённые, у каждого указаны источник, папка, тип и ссылка. Слово ищется по их тексту +так же, как в `memo search notes`. `memo documents tree` показывает папки каждого аккаунта и число документов в +каждой, а `memo documents show` открывает часть текста одного документа с его тегами, людьми и встречами. + +```sh +memo documents list # every account, newest first +memo documents list budget kind:pdf source:google-drive +memo documents list 'folder:"Projects/Acme"' --page 2 +memo documents tree --depth 2 +memo documents show document:42 --cursor 20000 +``` + ## Подготовьтесь к разговору ```text prompt diff --git a/translations/sources.json b/translations/sources.json index 3667fc98..5de7470d 100644 --- a/translations/sources.json +++ b/translations/sources.json @@ -134,26 +134,26 @@ "drive/security.es": "83136ae99091d45b53280de032919b042ff8b92a553cf26241caa165fbde6c1c", "memo/archive.es": "f3dcc4b5db9d406e7ba44e1f2ff2371f7550be8a5c8a2c342b731acc152b819a", "memo/archive.ru": "f3dcc4b5db9d406e7ba44e1f2ff2371f7550be8a5c8a2c342b731acc152b819a", - "memo/commands.es": "8c5008e5224dd51ae853d9563f6553dc1929b97f54fde78ec68006a7982d40f5", - "memo/commands.ru": "8c5008e5224dd51ae853d9563f6553dc1929b97f54fde78ec68006a7982d40f5", - "memo/configuration.es": "ffa2586fe7bed1bb3190dc9438680ff28754cf89b38e85597e47db5b12191968", - "memo/configuration.ru": "ffa2586fe7bed1bb3190dc9438680ff28754cf89b38e85597e47db5b12191968", + "memo/commands.es": "9cf5347d9ac0b703f3f47f59c941dcfb068713213593766b872f84a59db76313", + "memo/commands.ru": "9cf5347d9ac0b703f3f47f59c941dcfb068713213593766b872f84a59db76313", + "memo/configuration.es": "e51ec26a8f6f046aec2e0139e90bfd71dfb3560bcadf8b4e5e7bf6353b3f71e6", + "memo/configuration.ru": "e51ec26a8f6f046aec2e0139e90bfd71dfb3560bcadf8b4e5e7bf6353b3f71e6", "memo/how-it-works.es": "a4334d7aedd13cecebd81cdac383c4d0fcdc66f5db319f06f41f9176fe05a7bc", "memo/how-it-works.ru": "a4334d7aedd13cecebd81cdac383c4d0fcdc66f5db319f06f41f9176fe05a7bc", "memo/index.es": "0f2d82be400fa4fd500ef2ae76a7197efd05226f85a444c8eff5119e814c1225", "memo/index.ru": "0f2d82be400fa4fd500ef2ae76a7197efd05226f85a444c8eff5119e814c1225", - "memo/installation.es": "e1e859957ac295b2a624f2972b777ddc7657e66839e9e428d97ea5a1d9f193bd", - "memo/installation.ru": "e1e859957ac295b2a624f2972b777ddc7657e66839e9e428d97ea5a1d9f193bd", + "memo/installation.es": "a21e2bb792deedffa78e742ac6228c799ee6e0981331506b778ac1e36ecf8f8e", + "memo/installation.ru": "a21e2bb792deedffa78e742ac6228c799ee6e0981331506b778ac1e36ecf8f8e", "memo/mail.es": "6b816bf0695e4b9a9a71bdfceb10f7e024764bff5439588df83ebab7c0687570", "memo/mail.ru": "6b816bf0695e4b9a9a71bdfceb10f7e024764bff5439588df83ebab7c0687570", - "memo/mcp.es": "ed75f410811bc4fd122f999f0834be78a02e7faefb184dcd3a67ae267795194a", - "memo/mcp.ru": "ed75f410811bc4fd122f999f0834be78a02e7faefb184dcd3a67ae267795194a", + "memo/mcp.es": "afc0b2c393c6278e0773f38cf6568d61a0692d116385affeb6c8eb2f358492f7", + "memo/mcp.ru": "afc0b2c393c6278e0773f38cf6568d61a0692d116385affeb6c8eb2f358492f7", "memo/memories.es": "1074d3a2ff96073a8f6c5d016771fb054bc04ebe54af7d9c0e4e79a682edba52", "memo/memories.ru": "1074d3a2ff96073a8f6c5d016771fb054bc04ebe54af7d9c0e4e79a682edba52", - "memo/notes.es": "4939b53ae245315970423739a7b1e3e627adacf0414d7bd9345169b7c47ddb0d", - "memo/notes.ru": "4939b53ae245315970423739a7b1e3e627adacf0414d7bd9345169b7c47ddb0d", - "memo/people.es": "8c8019615cff2d41bf18a6a3f201455ba0f8eb966e75c582a7abd5eca0a3f014", - "memo/people.ru": "8c8019615cff2d41bf18a6a3f201455ba0f8eb966e75c582a7abd5eca0a3f014", + "memo/notes.es": "d0639c5bd07f3135d1ee981b6de2bfaccd6e6608a0d5dc333b3ccfac46786bcf", + "memo/notes.ru": "d0639c5bd07f3135d1ee981b6de2bfaccd6e6608a0d5dc333b3ccfac46786bcf", + "memo/people.es": "e0e2121c5202268d001bb4539d810a18b87e011b418d2377e77817ebbb126450", + "memo/people.ru": "e0e2121c5202268d001bb4539d810a18b87e011b418d2377e77817ebbb126450", "memo/recipes.es": "7cc3be723a7a3a8520d14a253e7f00762efa97c4d64f7a4fcb50a2440f165815", "memo/recipes.ru": "7cc3be723a7a3a8520d14a253e7f00762efa97c4d64f7a4fcb50a2440f165815", "memo/search.es": "e5789173a01c7d618d483c9fcad85aae046c68618fd53e4768a62df181936112", @@ -166,10 +166,10 @@ "memo/tasks.ru": "3b8da5be6f2c0f86b7609bf51400334a6b704dfec29088b470e3a04def6896f3", "memo/troubleshooting.es": "c2a00336743573881a4f52e463d6437f5f8b24d610376629df4fea9744106766", "memo/troubleshooting.ru": "c2a00336743573881a4f52e463d6437f5f8b24d610376629df4fea9744106766", - "memo/usage.es": "cc8e550b5998849ac89d2eb2ac9d9940cd999ab63ccf1cea287f4adc4f97749c", - "memo/usage.ru": "cc8e550b5998849ac89d2eb2ac9d9940cd999ab63ccf1cea287f4adc4f97749c", - "memo/changelog.ru": "4704e1fb209b4f046679f9bb9604e5b745762e9d379d9389ac3501ea65018d83", - "memo/changelog.es": "4704e1fb209b4f046679f9bb9604e5b745762e9d379d9389ac3501ea65018d83", + "memo/usage.es": "487e0d167e300b2c98262780797f9d09dfa0d19aa5f8fe6982c2e866cec14739", + "memo/usage.ru": "487e0d167e300b2c98262780797f9d09dfa0d19aa5f8fe6982c2e866cec14739", + "memo/changelog.ru": "51de2ce89dce8c19a341be49b6e089ca6268e2392bfcdc9cd748db4322e3e64e", + "memo/changelog.es": "51de2ce89dce8c19a341be49b6e089ca6268e2392bfcdc9cd748db4322e3e64e", "zm/troubleshooting.ru": "a77eb83235b65c4b414ee057d23392e564cc87c48f70c9baee602fbddf774b11", "zm/roadmap.es": "827f2f0b1a71b9c5e523331d4c1d63a5721c3f39359c862b775576cc70471747", "zm/mcp.ru": "3aacea4a4f4caeff6ac63c746f7c8dcb332da2186ba8923817d69d2b8ff63b7b", @@ -346,8 +346,8 @@ "b24/roadmap.es": "ad65b393bc1ca75c1770bd37937b85197171cc6d914a603b71dfddf731372064", "memo/business.ru": "ec5e405cfaa5956077bebbb2da3046ef3906f3e8410872e9025dd92bc9cb2d39", "memo/business.es": "ec5e405cfaa5956077bebbb2da3046ef3906f3e8410872e9025dd92bc9cb2d39", - "memo/sources.ru": "6a679486956f01f6962d53502eb9388fbcf1a1e5e4c752f3f5c0607328cdbc86", - "memo/sources.es": "6a679486956f01f6962d53502eb9388fbcf1a1e5e4c752f3f5c0607328cdbc86", + "memo/sources.ru": "0743ec579291526d033e4c41ce80ca90d74757442632ac4e526cea7697d46785", + "memo/sources.es": "0743ec579291526d033e4c41ce80ca90d74757442632ac4e526cea7697d46785", "b24/mcp.ru": "82279c8aecaf6c0f133e47fabde6f09d4360393cd9edcbca5cff2b03b45548d5", "b24/mcp.es": "82279c8aecaf6c0f133e47fabde6f09d4360393cd9edcbca5cff2b03b45548d5", "b24/permissions.ru": "3675affc621dd865aa13ada05355a0da7e422a6c9f23950a74042e0c140c5375", @@ -373,5 +373,7 @@ "pbx/changelog.ru": "6f683991ba73794859fe662b15a66c727951628d434f83835fbdce8697c0bb7f", "pbx/changelog.es": "6f683991ba73794859fe662b15a66c727951628d434f83835fbdce8697c0bb7f", "pbx/roadmap.ru": "23836d2fc5a2c7d8481c3038c1ddc1b72c998e8e8a275300d501c2f43c364655", - "pbx/roadmap.es": "23836d2fc5a2c7d8481c3038c1ddc1b72c998e8e8a275300d501c2f43c364655" + "pbx/roadmap.es": "23836d2fc5a2c7d8481c3038c1ddc1b72c998e8e8a275300d501c2f43c364655", + "memo/import.ru": "f6c0426d8d49eee0eab108046cc15cd3e655387f240af7e7837f8d76288487c3", + "memo/import.es": "f6c0426d8d49eee0eab108046cc15cd3e655387f240af7e7837f8d76288487c3" } From a0fc3310409f170c243dc2ddd368e0eded319c97 Mon Sep 17 00:00:00 2001 From: leemour <leemour@gmail.com> Date: Sat, 14 Nov 2026 13:31:05 +0100 Subject: [PATCH 2/3] test(search): the playground covers has:transcript The search language regenerated for memo 0.135.0 offers a 14th has: value, transcript. Two demo voice notes, one about Atlas and one not, now carry a transcript, so the playground finds an example for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- lib/search-playground/engine.ts | 4 ++-- scripts/search-playground.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/search-playground/engine.ts b/lib/search-playground/engine.ts index 4820ef4d..63432b96 100644 --- a/lib/search-playground/engine.ts +++ b/lib/search-playground/engine.ts @@ -257,7 +257,7 @@ export function createDemoMessages(dates: ReturnType<typeof createDemoDates> = d "Sam", "15:00", "Atlas invoice voice note: please check the billing address before the deadline.", - ["voice"], + ["voice", "transcript"], -1, ), row( @@ -268,7 +268,7 @@ export function createDemoMessages(dates: ReturnType<typeof createDemoDates> = d "Leo", "15:05", "A voice note with my design course recommendation and the weekly workload.", - ["voice"], + ["voice", "transcript"], -1, ), row( diff --git a/scripts/search-playground.test.ts b/scripts/search-playground.test.ts index 42143ab1..19066b0b 100644 --- a/scripts/search-playground.test.ts +++ b/scripts/search-playground.test.ts @@ -213,7 +213,7 @@ describe("reversible query filters and value suggestions", () => { describe("discoverable sample search paths", () => { it("has an Atlas example and another topic for every attachment filter", () => { const kinds = demoFields.find((field) => field.name === "has")?.values ?? [] - expect(kinds.length).toBe(13) + expect(kinds.length).toBe(14) for (const kind of kinds) { expect(searchDemo(`Atlas has:${kind}`).length, kind).toBeGreaterThan(0) expect(searchDemo(`has:${kind} NOT Atlas`).length, kind).toBeGreaterThan(0) From 6e225b2fc53b81d7f1faa4bfd92f61c564f2c6ae Mon Sep 17 00:00:00 2001 From: leemour <leemour@gmail.com> Date: Sat, 14 Nov 2026 13:46:39 +0100 Subject: [PATCH 3/3] docs(memo): a reviewed description and sidebar title for Import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The site build requires a reviewed description for every memo page, so the new Import page failed it. Adds the description in EN/RU/ES and a short sidebar title (Import / Импорт / Importar). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- lib/memo-descriptions.ts | 5 +++++ lib/tool-sidebar-titles.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/lib/memo-descriptions.ts b/lib/memo-descriptions.ts index b0717c87..6c255b83 100644 --- a/lib/memo-descriptions.ts +++ b/lib/memo-descriptions.ts @@ -8,6 +8,8 @@ export const memoDescriptions: Record<string, Record<string, string>> = { "how-it-works": "Where Memo keeps your text, what an import changes, how links and references work.", notes: "Import Markdown folders and Obsidian vaults, read documents and write notes about people.", sources: "Add one file, web page or pasted text for Memo to keep, and see who it names.", + import: + "Bring a folder of files, transcripts or recordings, or a records file from your own script, into Memo's search.", tags: "Label notes, emails, messages, people and projects, then find everything with a label.", search: "Find words, phrases, tags and dates across notes, mail and messages, with each source.", scenarios: @@ -37,6 +39,7 @@ export const memoDescriptions: Record<string, Record<string, string>> = { "how-it-works": "Где Memo хранит текст, что меняет импорт и как работают ссылки и ссылки на источники.", notes: "Импортируйте папки Markdown и хранилища Obsidian, читайте документы и пишите заметки о людях.", sources: "Добавьте файл, веб-страницу или текст, чтобы Memo его хранил, и посмотрите, кого он называет.", + import: "Добавьте в поиск Memo папку файлов, расшифровок или записей, или файл записей из своего скрипта.", tags: "Отмечайте тегами заметки, письма, сообщения, людей и проекты и находите всё по тегу.", search: "Ищите слова, фразы, теги и даты в заметках, почте и сообщениях с указанием источника.", scenarios: @@ -66,6 +69,8 @@ export const memoDescriptions: Record<string, Record<string, string>> = { "how-it-works": "Dónde guarda Memo tu texto, qué cambia una importación y cómo funcionan enlaces y referencias.", notes: "Importa carpetas Markdown y bóvedas de Obsidian, lee documentos y escribe notas sobre personas.", sources: "Añade un archivo, una página web o un texto pegado para que Memo lo guarde, y mira a quién nombra.", + import: + "Trae a la búsqueda de Memo una carpeta de archivos, transcripciones o grabaciones, o un archivo de registros de tu propio script.", tags: "Etiqueta notas, correos, mensajes, personas y proyectos, y encuentra todo por su etiqueta.", search: "Busca palabras, frases, etiquetas y fechas en notas, correo y mensajes, con cada fuente.", scenarios: diff --git a/lib/tool-sidebar-titles.ts b/lib/tool-sidebar-titles.ts index bba52453..9c73cbe2 100644 --- a/lib/tool-sidebar-titles.ts +++ b/lib/tool-sidebar-titles.ts @@ -48,6 +48,7 @@ const byTool: Record<string, Record<string, Names>> = { }, memo: { sources: { en: "Your sources", ru: "Свои источники", es: "Tus fuentes" }, + import: { en: "Import", ru: "Импорт", es: "Importar" }, people: { en: "People and projects", ru: "Люди и проекты", es: "Personas y proyectos" }, remote: { en: "Browser and phone", ru: "Браузер и телефон", es: "Navegador y teléfono" }, archive: { en: "Keeping up to date", ru: "Обновление", es: "Mantener al día" },