@torsday/omnifocus-mcp 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to `@torsday/omnifocus-mcp` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). See [ADR-0011](./docs/adr/0011-versioning-and-stability.md) for the explicit definition of breaking vs additive changes in this project.
|
|
6
6
|
|
|
7
|
+
## [1.0.2](https://github.com/torsday/omnifocus-mcp/compare/v1.0.1...v1.0.2) (2026-04-26)
|
|
8
|
+
|
|
9
|
+
**Summary** — One contributor-facing fix and one architectural-decision spike note; otherwise an internal-infrastructure release validating the post-v1.0.1 release flow under the new release-please + OIDC + PAT identity. **Bytes on the wire are identical to v1.0.1**: the published bundle, tool surface, tool descriptions, and runtime behaviour are unchanged. Consumers running `npx -y @torsday/omnifocus-mcp` see no difference. Internal-only commits (CI hygiene, release-please workflow tuning, comment-block cleanups) are intentionally hidden from this CHANGELOG by `release-please-config.json` and are not enumerated below.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **`scripts/seed-integration-db.js` runs under ESM** — `package.json` declares `"type": "module"`, so every `.js` file is interpreted as ESM by Node. The seed script was the lone holdout still using CommonJS `require()` and threw `ReferenceError: require is not defined in ES module scope` at the first line of execution. One-line conversion: `const { spawnSync } = require("node:child_process")` → `import { spawnSync } from "node:child_process"`. Affects only contributors running `pnpm test:integration` locally or the `integration.yml` workflow on `mac-local`; the published package's runtime is unchanged. ([#448](https://github.com/torsday/omnifocus-mcp/issues/448))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
|
|
18
|
+
- **Tier-3 CHANGELOG-action spike resolved — don't automate** — `docs/spikes/2026-04-tier-3-changelog-action.md` records the decision: stick with the existing manual `/release-notes` polish flow rather than building a GitHub Action that auto-polishes the Release PR via the Anthropic API. Three structural reasons in the note: ~10 min/release × ~6 releases/year is roughly 1 hour/year of polish work — automation that adds operational surface (new repo secret, rotation burden, API outage as a release-block failure mode) to save 1 hour/year is the wrong trade; the skip-the-polish decision (chore-only releases need no polish) requires maintainer judgment that an action can't make; and with a Closed contributing stance there are no future maintainers to onboard. Empirical anchor: v1.0.1's polish — the first release under release-please — showed substantial quality delta from auto-draft to polished prose at acceptable manual cost. ([#432](https://github.com/torsday/omnifocus-mcp/issues/432))
|
|
19
|
+
|
|
7
20
|
## [1.0.1](https://github.com/torsday/omnifocus-mcp/compare/v1.0.0...v1.0.1) (2026-04-26)
|
|
8
21
|
|
|
9
22
|
**Summary** — Documentation polish pass. The README, SPEC, DESIGN, and `docs/project-views.md` are now aligned with the post-v1.0.0 reality of the project (public, shipped, npm-published) rather than the pre-1.0 framing they carried at v1.0.0's tag. Quick Start is restructured so every supported MCP client — not only Claude Desktop — gets equal-footing setup instructions; a new agent-readable Security & trust section surfaces the existing threat-model guarantees with file-level enforcement references. No behavioural or API changes: bytes on the wire, tool surface, and tool descriptions are identical to v1.0.0.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {McpServer,ResourceTemplate}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {createHash}from'crypto';import fu,{homedir}from'os';import {z}from'zod';import go from'pino';import {spawn,execFile}from'child_process';import rt from'fs';import to,{join,sep}from'path';import {createInterface}from'readline';import {fileURLToPath}from'url';import {AsyncLocalStorage}from'async_hooks';import {ulid}from'ulid';import {EventEmitter}from'events';import {LRUCache}from'lru-cache';import {realpath,stat}from'fs/promises';var re={name:"@torsday/omnifocus-mcp",version:"1.0.1",description:"MCP server exposing the full OmniFocus surface to LLM agents \u2014 80 typed tools spanning tasks, projects, tags, folders, perspectives, forecast, review, notes, attachments, and sync, with a strict typed-error taxonomy and per-tool circuit breakers, rate limiter, and idempotency-key support. macOS-only; talks to OmniFocus 4 via JXA + OmniJS.",homepage:"https://github.com/torsday/omnifocus-mcp#readme"};var Ue=Object.freeze({listTasks:"jxa",getTask:"jxa",getTasksMany:"jxa",createTask:"jxa",updateTask:"jxa",completeTask:"jxa",uncompleteTask:"jxa",dropTask:"jxa",undropTask:"jxa",deleteTask:"jxa",moveTask:"omnijs",batchMoveTasks:"omnijs",reorderTask:"omnijs",duplicateTask:"jxa",batchCreateTasks:"jxa",batchUpdateTasks:"jxa",batchCompleteTasks:"jxa",batchUncompleteTasks:"jxa",batchDeleteTasks:"jxa",batchDropTasks:"jxa",batchUndropTasks:"jxa",listProjects:"jxa",getProject:"jxa",getProjectsMany:"jxa",createProject:"jxa",updateProject:"jxa",completeProject:"jxa",batchCompleteProjects:"jxa",dropProject:"jxa",batchDropProjects:"jxa",moveProject:"jxa",deleteProject:"jxa",markProjectReviewed:"jxa",listProjectsDueForReview:"jxa",setProjectReviewInterval:"jxa",listTags:"jxa",getTag:"jxa",getTagsMany:"jxa",createTag:"jxa",updateTag:"jxa",deleteTag:"jxa",listFolders:"jxa",getFolder:"jxa",createFolder:"jxa",updateFolder:"jxa",deleteFolder:"jxa",searchTasks:"jxa",getForecast:"jxa",listPerspectives:"jxa",evaluatePerspective:"jxa",evaluateCustomPerspective:"omnijs",syncTrigger:"jxa",getLastSync:"jxa",listAttachments:"jxa",addAttachment:"jxa",removeAttachment:"jxa",saveAttachmentToPath:"jxa",appLaunch:"jxa",pluginInvoke:"omnijs",getChangesSince:"jxa",runJxaScript:"jxa",runOmniJsScript:"omnijs"});var Le=class n{jxa;omnijs;constructor(e){this.jxa=e.jxa,this.omnijs=e.omnijs;}get routingTable(){return Ue}static fromTransports(e,t){return new n({jxa:e,omnijs:t})}pick(e){return Ue[e]==="jxa"?this.jxa:this.omnijs}listTasks(e){return this.pick("listTasks").listTasks(e)}getTask(e){return this.pick("getTask").getTask(e)}getTasksMany(e){return this.pick("getTasksMany").getTasksMany(e)}createTask(e){return this.pick("createTask").createTask(e)}updateTask(e,t){return this.pick("updateTask").updateTask(e,t)}completeTask(e,t){return this.pick("completeTask").completeTask(e,t)}uncompleteTask(e){return this.pick("uncompleteTask").uncompleteTask(e)}dropTask(e,t){return this.pick("dropTask").dropTask(e,t)}undropTask(e){return this.pick("undropTask").undropTask(e)}deleteTask(e){return this.pick("deleteTask").deleteTask(e)}moveTask(e,t){return this.pick("moveTask").moveTask(e,t)}batchMoveTasks(e){return this.pick("batchMoveTasks").batchMoveTasks(e)}reorderTask(e,t){return this.pick("reorderTask").reorderTask(e,t)}duplicateTask(e,t){return this.pick("duplicateTask").duplicateTask(e,t)}batchCreateTasks(e){return this.pick("batchCreateTasks").batchCreateTasks(e)}batchUpdateTasks(e){return this.pick("batchUpdateTasks").batchUpdateTasks(e)}batchCompleteTasks(e){return this.pick("batchCompleteTasks").batchCompleteTasks(e)}batchUncompleteTasks(e){return this.pick("batchUncompleteTasks").batchUncompleteTasks(e)}batchDeleteTasks(e){return this.pick("batchDeleteTasks").batchDeleteTasks(e)}batchDropTasks(e){return this.pick("batchDropTasks").batchDropTasks(e)}batchUndropTasks(e){return this.pick("batchUndropTasks").batchUndropTasks(e)}listProjects(e){return this.pick("listProjects").listProjects(e)}getProject(e){return this.pick("getProject").getProject(e)}getProjectsMany(e){return this.pick("getProjectsMany").getProjectsMany(e)}createProject(e){return this.pick("createProject").createProject(e)}updateProject(e,t){return this.pick("updateProject").updateProject(e,t)}completeProject(e,t){return this.pick("completeProject").completeProject(e,t)}dropProject(e,t){return this.pick("dropProject").dropProject(e,t)}batchCompleteProjects(e){return this.pick("batchCompleteProjects").batchCompleteProjects(e)}batchDropProjects(e){return this.pick("batchDropProjects").batchDropProjects(e)}moveProject(e,t){return this.pick("moveProject").moveProject(e,t)}deleteProject(e){return this.pick("deleteProject").deleteProject(e)}markProjectReviewed(e){return this.pick("markProjectReviewed").markProjectReviewed(e)}listProjectsDueForReview(){return this.pick("listProjectsDueForReview").listProjectsDueForReview()}setProjectReviewInterval(e,t){return this.pick("setProjectReviewInterval").setProjectReviewInterval(e,t)}listTags(e){return this.pick("listTags").listTags(e)}getTag(e){return this.pick("getTag").getTag(e)}getTagsMany(e){return this.pick("getTagsMany").getTagsMany(e)}createTag(e){return this.pick("createTag").createTag(e)}updateTag(e,t){return this.pick("updateTag").updateTag(e,t)}deleteTag(e){return this.pick("deleteTag").deleteTag(e)}listFolders(e){return this.pick("listFolders").listFolders(e)}getFolder(e){return this.pick("getFolder").getFolder(e)}createFolder(e){return this.pick("createFolder").createFolder(e)}updateFolder(e,t){return this.pick("updateFolder").updateFolder(e,t)}deleteFolder(e){return this.pick("deleteFolder").deleteFolder(e)}searchTasks(e){return this.pick("searchTasks").searchTasks(e)}getForecast(e){return this.pick("getForecast").getForecast(e)}listPerspectives(){return this.pick("listPerspectives").listPerspectives()}evaluatePerspective(e){return this.pick("evaluatePerspective").evaluatePerspective(e)}evaluateCustomPerspective(e){return this.pick("evaluateCustomPerspective").evaluateCustomPerspective(e)}syncTrigger(){return this.pick("syncTrigger").syncTrigger()}getLastSync(){return this.pick("getLastSync").getLastSync()}listAttachments(e){return this.pick("listAttachments").listAttachments(e)}addAttachment(e){return this.pick("addAttachment").addAttachment(e)}removeAttachment(e){return this.pick("removeAttachment").removeAttachment(e)}saveAttachmentToPath(e){return this.pick("saveAttachmentToPath").saveAttachmentToPath(e)}appLaunch(){return this.pick("appLaunch").appLaunch()}pluginInvoke(e){return this.pick("pluginInvoke").pluginInvoke(e)}runJxaScript(e,t){let r=this.pick("runJxaScript");return typeof r.runJxaScript!="function"?Promise.reject(new TypeError("Router dispatched runJxaScript to a transport that does not implement it")):r.runJxaScript(e,t)}runOmniJsScript(e,t){let r=this.pick("runOmniJsScript");return typeof r.runOmniJsScript!="function"?Promise.reject(new TypeError("Router dispatched runOmniJsScript to a transport that does not implement it")):r.runOmniJsScript(e,t)}getChangesSince(e){return this.pick("getChangesSince").getChangesSince(e)}};var ac=new Set(["createTask","updateTask","completeTask","uncompleteTask","dropTask","undropTask","deleteTask","moveTask","reorderTask","duplicateTask","batchCreateTasks","batchUpdateTasks","batchCompleteTasks","createProject","updateProject","completeProject","dropProject","moveProject","deleteProject","markProjectReviewed","setProjectReviewInterval","createTag","updateTag","deleteTag","createFolder","updateFolder","deleteFolder","syncTrigger","addAttachment","removeAttachment","appLaunch","pluginInvoke","runJxaScript","runOmniJsScript"]);function sc(n,e){return Ue[n]==="omnijs"?e.omniJsQueue:ac.has(n)?e.jxaWriteQueue:e.readPool}function po(n,e){return new Proxy(n,{get(t,r,o){if(typeof r!="string"||!(r in Ue))return Reflect.get(t,r,o);let a=r,s=sc(a,e),l=Reflect.get(t,a,o).bind(t);return (...u)=>s.run(()=>l(...u))}})}var st=class{name;size;inFlight=0;waiters=[];constructor(e){if(!Number.isInteger(e.size)||e.size<1)throw new RangeError(`ReadPool.size must be a positive integer (got ${String(e.size)})`);this.size=e.size,this.name=e.name??"read-pool";}async run(e){await this.acquire();try{return await e()}finally{this.release();}}inFlightCount(){return this.inFlight}waitingCount(){return this.waiters.length}pendingCount(){return this.inFlight+this.waiters.length}acquire(){return this.inFlight<this.size?(this.inFlight++,Promise.resolve()):new Promise(e=>{this.waiters.push(()=>{this.inFlight++,e();});})}release(){this.inFlight--;let e=this.waiters.shift();e!==void 0&&e();}};var E=class extends Error{code;remediationClass;suggestion;details;constructor(e,t,r={}){super(t,r.cause!==void 0?{cause:r.cause}:void 0),this.name=new.target.name,this.code=e,r.remediationClass!==void 0&&(this.remediationClass=r.remediationClass),r.suggestion!==void 0&&(this.suggestion=r.suggestion),r.details!==void 0&&(this.details=r.details);}toJSON(){let e={name:this.name,code:this.code,message:this.message};return this.remediationClass!==void 0&&(e.remediationClass=this.remediationClass),this.suggestion!==void 0&&(e.suggestion=this.suggestion),this.details!==void 0&&(e.details=this.details),e}};function uo(n){return n instanceof E}var we=class extends E{constructor(e={}){super("OF_NOT_RUNNING","OmniFocus is not running.",{remediationClass:"environment",suggestion:"Launch OmniFocus and retry.",...e});}},je=class extends E{constructor(e={}){super("OF_PERMISSION_DENIED","Automation permission for OmniFocus is denied.",{remediationClass:"environment",suggestion:"Open System Settings \u2192 Privacy & Security \u2192 Automation; grant this terminal or client access to OmniFocus. See docs/troubleshooting.md for step-by-step recovery.",...e});}},it=class extends E{constructor(e,t={}){super("OF_FEATURE_REQUIRES_PRO",e,{remediationClass:"environment",suggestion:"This feature requires OmniFocus Pro. Upgrade or use a different tool.",...t});}};var I=class extends E{constructor(e,t={}){super("OF_VALIDATION",e,{remediationClass:"input",suggestion:"Fix the input and retry. See `details` for field-level reasons.",...t});}},P=class extends E{constructor(e,t={}){super("OF_NOT_FOUND",e,{remediationClass:"input",suggestion:"Confirm the ID with the corresponding `*_list` tool. Use OmniFocus persistent IDs, not names.",...t});}},be=class extends E{constructor(e,t={}){super("OF_CONFLICT",e,{remediationClass:"input",suggestion:"The resource was modified since you read it. Re-read with the corresponding `*_get` tool, merge your changes, and retry with the fresh `modifiedAt` value.",...t});}},Pe=class extends E{constructor(e,t={}){super("OF_TIMEOUT",e,{remediationClass:"transient",suggestion:"Retry once. If repeated, OmniFocus may be wedged \u2014 relaunch it.",...t});}},ct=class extends E{constructor(e,t={}){super("OF_RATE_LIMITED",e,{remediationClass:"transient",suggestion:"Wait details.retryAfterMs milliseconds then retry.",...t,details:{retryAfterMs:6e4,...t.details}});}},dt=class extends E{constructor(e,t={}){super("OF_QUEUE_FULL",e,{remediationClass:"transient",suggestion:"The write queue is saturated. Wait for in-flight writes to drain, then retry.",...t});}},Je=class extends E{constructor(e,t={}){super("OF_CIRCUIT_OPEN",e,{remediationClass:"transient",suggestion:"This tool failed repeatedly and is rejecting calls fast. Wait details.retryAfterMs milliseconds for the circuit to half-open.",...t,details:{retryAfterMs:6e4,...t.details}});}},Oe=class extends E{constructor(e,t={}){super("OF_TRANSPORT_UNAVAILABLE",e,{remediationClass:"infrastructure",suggestion:"The required transport is unreachable. Verify OmniFocus is running and responsive.",...t});}},L=class extends E{constructor(e,t={}){super("OF_SCRIPT_ERROR",e,{remediationClass:"infrastructure",suggestion:"The OmniFocus script failed. Inspect `details.transport` and `details.reason` for context.",...t});}},lt=class extends E{constructor(e={}){super("OF_SHUTTING_DOWN","Server is shutting down; not accepting new requests.",{remediationClass:"lifecycle",suggestion:"Reconnect to a fresh server instance.",...e});}},pt=class extends E{constructor(e,t,r,o={}){super("OF_LOOP_DETECTED",`Tool "${e}" has been called ${t} time(s) with identical arguments within ${r}s. The agent appears to be stuck.`,{remediationClass:"input",suggestion:"Act on the result of the previous call before repeating this tool. If you need the same data again, verify the previous response was consumed.",details:{tool:e,count:t,windowSeconds:r},...o});}};var Be=class{name;cap;inFlight=0;queue=[];constructor(e){if(!Number.isInteger(e.cap)||e.cap<1)throw new RangeError(`WriteQueue.cap must be a positive integer (got ${String(e.cap)})`);this.cap=e.cap,this.name=e.name??"write-queue";}run(e){if(this.pendingCount()>=this.cap)throw new dt(`${this.name} is full (cap ${this.cap}); ${this.pendingCount()} pending`,{details:{queue:this.name,cap:this.cap,pending:this.pendingCount()}});let{promise:t,resolve:r,reject:o}=Promise.withResolvers();return this.queue.push({fn:e,resolve:r,reject:o}),this.pump(),t}inFlightCount(){return this.inFlight}waitingCount(){return this.queue.length}pendingCount(){return this.inFlight+this.queue.length}pump(){if(this.inFlight>0)return;let e=this.queue.shift();e!==void 0&&(this.inFlight++,(async()=>{try{let t=await e.fn();e.resolve(t);}catch(t){e.reject(t);}finally{this.inFlight--,this.pump();}})());}};var dc=z.string().regex(/^\d+\/\d+$/,'must be "N/SECONDS" format, e.g. "120/60"').transform(n=>{let[e,t]=n.split("/").map(Number);return {limit:e,windowSeconds:t}}),lc=z.object({OMNIFOCUS_LOG_LEVEL:z.enum(["trace","debug","info","warn","error"]).default("info"),OMNIFOCUS_INTEGRATION:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_E2E:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_E2E_USE_MEMORY:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_ALLOW_RAW_SCRIPT:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_CACHE_TTL_MS:z.coerce.number().int().positive().default(3e4),OMNIFOCUS_CACHE_CAPACITY:z.coerce.number().int().positive().default(256),OMNIFOCUS_READ_POOL_SIZE:z.coerce.number().int().min(1).max(8).default(2),OMNIFOCUS_WRITE_QUEUE_CAP:z.coerce.number().int().positive().default(50),OMNIFOCUS_JXA_TIMEOUT_MS:z.coerce.number().int().positive().default(3e4),OMNIFOCUS_OMNIJS_TIMEOUT_MS:z.coerce.number().int().positive().default(45e3),OMNIFOCUS_ATTACHMENT_PATHS:z.string().prefault(homedir()).transform(n=>n.split(":").filter(Boolean)),OMNIFOCUS_MAX_ATTACHMENT_MB:z.coerce.number().int().positive().default(100),OMNIFOCUS_TOOL_RATE_LIMIT:dc.prefault("120/60")});function mo(n=process.env,e=t=>{process.stderr.write(`[omnifocus-mcp] Config error: ${t}
|
|
2
|
+
import {McpServer,ResourceTemplate}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {createHash}from'crypto';import fu,{homedir}from'os';import {z}from'zod';import go from'pino';import {spawn,execFile}from'child_process';import rt from'fs';import to,{join,sep}from'path';import {createInterface}from'readline';import {fileURLToPath}from'url';import {AsyncLocalStorage}from'async_hooks';import {ulid}from'ulid';import {EventEmitter}from'events';import {LRUCache}from'lru-cache';import {realpath,stat}from'fs/promises';var re={name:"@torsday/omnifocus-mcp",version:"1.0.2",description:"MCP server exposing the full OmniFocus surface to LLM agents \u2014 80 typed tools spanning tasks, projects, tags, folders, perspectives, forecast, review, notes, attachments, and sync, with a strict typed-error taxonomy and per-tool circuit breakers, rate limiter, and idempotency-key support. macOS-only; talks to OmniFocus 4 via JXA + OmniJS.",homepage:"https://github.com/torsday/omnifocus-mcp#readme"};var Ue=Object.freeze({listTasks:"jxa",getTask:"jxa",getTasksMany:"jxa",createTask:"jxa",updateTask:"jxa",completeTask:"jxa",uncompleteTask:"jxa",dropTask:"jxa",undropTask:"jxa",deleteTask:"jxa",moveTask:"omnijs",batchMoveTasks:"omnijs",reorderTask:"omnijs",duplicateTask:"jxa",batchCreateTasks:"jxa",batchUpdateTasks:"jxa",batchCompleteTasks:"jxa",batchUncompleteTasks:"jxa",batchDeleteTasks:"jxa",batchDropTasks:"jxa",batchUndropTasks:"jxa",listProjects:"jxa",getProject:"jxa",getProjectsMany:"jxa",createProject:"jxa",updateProject:"jxa",completeProject:"jxa",batchCompleteProjects:"jxa",dropProject:"jxa",batchDropProjects:"jxa",moveProject:"jxa",deleteProject:"jxa",markProjectReviewed:"jxa",listProjectsDueForReview:"jxa",setProjectReviewInterval:"jxa",listTags:"jxa",getTag:"jxa",getTagsMany:"jxa",createTag:"jxa",updateTag:"jxa",deleteTag:"jxa",listFolders:"jxa",getFolder:"jxa",createFolder:"jxa",updateFolder:"jxa",deleteFolder:"jxa",searchTasks:"jxa",getForecast:"jxa",listPerspectives:"jxa",evaluatePerspective:"jxa",evaluateCustomPerspective:"omnijs",syncTrigger:"jxa",getLastSync:"jxa",listAttachments:"jxa",addAttachment:"jxa",removeAttachment:"jxa",saveAttachmentToPath:"jxa",appLaunch:"jxa",pluginInvoke:"omnijs",getChangesSince:"jxa",runJxaScript:"jxa",runOmniJsScript:"omnijs"});var Le=class n{jxa;omnijs;constructor(e){this.jxa=e.jxa,this.omnijs=e.omnijs;}get routingTable(){return Ue}static fromTransports(e,t){return new n({jxa:e,omnijs:t})}pick(e){return Ue[e]==="jxa"?this.jxa:this.omnijs}listTasks(e){return this.pick("listTasks").listTasks(e)}getTask(e){return this.pick("getTask").getTask(e)}getTasksMany(e){return this.pick("getTasksMany").getTasksMany(e)}createTask(e){return this.pick("createTask").createTask(e)}updateTask(e,t){return this.pick("updateTask").updateTask(e,t)}completeTask(e,t){return this.pick("completeTask").completeTask(e,t)}uncompleteTask(e){return this.pick("uncompleteTask").uncompleteTask(e)}dropTask(e,t){return this.pick("dropTask").dropTask(e,t)}undropTask(e){return this.pick("undropTask").undropTask(e)}deleteTask(e){return this.pick("deleteTask").deleteTask(e)}moveTask(e,t){return this.pick("moveTask").moveTask(e,t)}batchMoveTasks(e){return this.pick("batchMoveTasks").batchMoveTasks(e)}reorderTask(e,t){return this.pick("reorderTask").reorderTask(e,t)}duplicateTask(e,t){return this.pick("duplicateTask").duplicateTask(e,t)}batchCreateTasks(e){return this.pick("batchCreateTasks").batchCreateTasks(e)}batchUpdateTasks(e){return this.pick("batchUpdateTasks").batchUpdateTasks(e)}batchCompleteTasks(e){return this.pick("batchCompleteTasks").batchCompleteTasks(e)}batchUncompleteTasks(e){return this.pick("batchUncompleteTasks").batchUncompleteTasks(e)}batchDeleteTasks(e){return this.pick("batchDeleteTasks").batchDeleteTasks(e)}batchDropTasks(e){return this.pick("batchDropTasks").batchDropTasks(e)}batchUndropTasks(e){return this.pick("batchUndropTasks").batchUndropTasks(e)}listProjects(e){return this.pick("listProjects").listProjects(e)}getProject(e){return this.pick("getProject").getProject(e)}getProjectsMany(e){return this.pick("getProjectsMany").getProjectsMany(e)}createProject(e){return this.pick("createProject").createProject(e)}updateProject(e,t){return this.pick("updateProject").updateProject(e,t)}completeProject(e,t){return this.pick("completeProject").completeProject(e,t)}dropProject(e,t){return this.pick("dropProject").dropProject(e,t)}batchCompleteProjects(e){return this.pick("batchCompleteProjects").batchCompleteProjects(e)}batchDropProjects(e){return this.pick("batchDropProjects").batchDropProjects(e)}moveProject(e,t){return this.pick("moveProject").moveProject(e,t)}deleteProject(e){return this.pick("deleteProject").deleteProject(e)}markProjectReviewed(e){return this.pick("markProjectReviewed").markProjectReviewed(e)}listProjectsDueForReview(){return this.pick("listProjectsDueForReview").listProjectsDueForReview()}setProjectReviewInterval(e,t){return this.pick("setProjectReviewInterval").setProjectReviewInterval(e,t)}listTags(e){return this.pick("listTags").listTags(e)}getTag(e){return this.pick("getTag").getTag(e)}getTagsMany(e){return this.pick("getTagsMany").getTagsMany(e)}createTag(e){return this.pick("createTag").createTag(e)}updateTag(e,t){return this.pick("updateTag").updateTag(e,t)}deleteTag(e){return this.pick("deleteTag").deleteTag(e)}listFolders(e){return this.pick("listFolders").listFolders(e)}getFolder(e){return this.pick("getFolder").getFolder(e)}createFolder(e){return this.pick("createFolder").createFolder(e)}updateFolder(e,t){return this.pick("updateFolder").updateFolder(e,t)}deleteFolder(e){return this.pick("deleteFolder").deleteFolder(e)}searchTasks(e){return this.pick("searchTasks").searchTasks(e)}getForecast(e){return this.pick("getForecast").getForecast(e)}listPerspectives(){return this.pick("listPerspectives").listPerspectives()}evaluatePerspective(e){return this.pick("evaluatePerspective").evaluatePerspective(e)}evaluateCustomPerspective(e){return this.pick("evaluateCustomPerspective").evaluateCustomPerspective(e)}syncTrigger(){return this.pick("syncTrigger").syncTrigger()}getLastSync(){return this.pick("getLastSync").getLastSync()}listAttachments(e){return this.pick("listAttachments").listAttachments(e)}addAttachment(e){return this.pick("addAttachment").addAttachment(e)}removeAttachment(e){return this.pick("removeAttachment").removeAttachment(e)}saveAttachmentToPath(e){return this.pick("saveAttachmentToPath").saveAttachmentToPath(e)}appLaunch(){return this.pick("appLaunch").appLaunch()}pluginInvoke(e){return this.pick("pluginInvoke").pluginInvoke(e)}runJxaScript(e,t){let r=this.pick("runJxaScript");return typeof r.runJxaScript!="function"?Promise.reject(new TypeError("Router dispatched runJxaScript to a transport that does not implement it")):r.runJxaScript(e,t)}runOmniJsScript(e,t){let r=this.pick("runOmniJsScript");return typeof r.runOmniJsScript!="function"?Promise.reject(new TypeError("Router dispatched runOmniJsScript to a transport that does not implement it")):r.runOmniJsScript(e,t)}getChangesSince(e){return this.pick("getChangesSince").getChangesSince(e)}};var ac=new Set(["createTask","updateTask","completeTask","uncompleteTask","dropTask","undropTask","deleteTask","moveTask","reorderTask","duplicateTask","batchCreateTasks","batchUpdateTasks","batchCompleteTasks","createProject","updateProject","completeProject","dropProject","moveProject","deleteProject","markProjectReviewed","setProjectReviewInterval","createTag","updateTag","deleteTag","createFolder","updateFolder","deleteFolder","syncTrigger","addAttachment","removeAttachment","appLaunch","pluginInvoke","runJxaScript","runOmniJsScript"]);function sc(n,e){return Ue[n]==="omnijs"?e.omniJsQueue:ac.has(n)?e.jxaWriteQueue:e.readPool}function po(n,e){return new Proxy(n,{get(t,r,o){if(typeof r!="string"||!(r in Ue))return Reflect.get(t,r,o);let a=r,s=sc(a,e),l=Reflect.get(t,a,o).bind(t);return (...u)=>s.run(()=>l(...u))}})}var st=class{name;size;inFlight=0;waiters=[];constructor(e){if(!Number.isInteger(e.size)||e.size<1)throw new RangeError(`ReadPool.size must be a positive integer (got ${String(e.size)})`);this.size=e.size,this.name=e.name??"read-pool";}async run(e){await this.acquire();try{return await e()}finally{this.release();}}inFlightCount(){return this.inFlight}waitingCount(){return this.waiters.length}pendingCount(){return this.inFlight+this.waiters.length}acquire(){return this.inFlight<this.size?(this.inFlight++,Promise.resolve()):new Promise(e=>{this.waiters.push(()=>{this.inFlight++,e();});})}release(){this.inFlight--;let e=this.waiters.shift();e!==void 0&&e();}};var E=class extends Error{code;remediationClass;suggestion;details;constructor(e,t,r={}){super(t,r.cause!==void 0?{cause:r.cause}:void 0),this.name=new.target.name,this.code=e,r.remediationClass!==void 0&&(this.remediationClass=r.remediationClass),r.suggestion!==void 0&&(this.suggestion=r.suggestion),r.details!==void 0&&(this.details=r.details);}toJSON(){let e={name:this.name,code:this.code,message:this.message};return this.remediationClass!==void 0&&(e.remediationClass=this.remediationClass),this.suggestion!==void 0&&(e.suggestion=this.suggestion),this.details!==void 0&&(e.details=this.details),e}};function uo(n){return n instanceof E}var we=class extends E{constructor(e={}){super("OF_NOT_RUNNING","OmniFocus is not running.",{remediationClass:"environment",suggestion:"Launch OmniFocus and retry.",...e});}},je=class extends E{constructor(e={}){super("OF_PERMISSION_DENIED","Automation permission for OmniFocus is denied.",{remediationClass:"environment",suggestion:"Open System Settings \u2192 Privacy & Security \u2192 Automation; grant this terminal or client access to OmniFocus. See docs/troubleshooting.md for step-by-step recovery.",...e});}},it=class extends E{constructor(e,t={}){super("OF_FEATURE_REQUIRES_PRO",e,{remediationClass:"environment",suggestion:"This feature requires OmniFocus Pro. Upgrade or use a different tool.",...t});}};var I=class extends E{constructor(e,t={}){super("OF_VALIDATION",e,{remediationClass:"input",suggestion:"Fix the input and retry. See `details` for field-level reasons.",...t});}},P=class extends E{constructor(e,t={}){super("OF_NOT_FOUND",e,{remediationClass:"input",suggestion:"Confirm the ID with the corresponding `*_list` tool. Use OmniFocus persistent IDs, not names.",...t});}},be=class extends E{constructor(e,t={}){super("OF_CONFLICT",e,{remediationClass:"input",suggestion:"The resource was modified since you read it. Re-read with the corresponding `*_get` tool, merge your changes, and retry with the fresh `modifiedAt` value.",...t});}},Pe=class extends E{constructor(e,t={}){super("OF_TIMEOUT",e,{remediationClass:"transient",suggestion:"Retry once. If repeated, OmniFocus may be wedged \u2014 relaunch it.",...t});}},ct=class extends E{constructor(e,t={}){super("OF_RATE_LIMITED",e,{remediationClass:"transient",suggestion:"Wait details.retryAfterMs milliseconds then retry.",...t,details:{retryAfterMs:6e4,...t.details}});}},dt=class extends E{constructor(e,t={}){super("OF_QUEUE_FULL",e,{remediationClass:"transient",suggestion:"The write queue is saturated. Wait for in-flight writes to drain, then retry.",...t});}},Je=class extends E{constructor(e,t={}){super("OF_CIRCUIT_OPEN",e,{remediationClass:"transient",suggestion:"This tool failed repeatedly and is rejecting calls fast. Wait details.retryAfterMs milliseconds for the circuit to half-open.",...t,details:{retryAfterMs:6e4,...t.details}});}},Oe=class extends E{constructor(e,t={}){super("OF_TRANSPORT_UNAVAILABLE",e,{remediationClass:"infrastructure",suggestion:"The required transport is unreachable. Verify OmniFocus is running and responsive.",...t});}},L=class extends E{constructor(e,t={}){super("OF_SCRIPT_ERROR",e,{remediationClass:"infrastructure",suggestion:"The OmniFocus script failed. Inspect `details.transport` and `details.reason` for context.",...t});}},lt=class extends E{constructor(e={}){super("OF_SHUTTING_DOWN","Server is shutting down; not accepting new requests.",{remediationClass:"lifecycle",suggestion:"Reconnect to a fresh server instance.",...e});}},pt=class extends E{constructor(e,t,r,o={}){super("OF_LOOP_DETECTED",`Tool "${e}" has been called ${t} time(s) with identical arguments within ${r}s. The agent appears to be stuck.`,{remediationClass:"input",suggestion:"Act on the result of the previous call before repeating this tool. If you need the same data again, verify the previous response was consumed.",details:{tool:e,count:t,windowSeconds:r},...o});}};var Be=class{name;cap;inFlight=0;queue=[];constructor(e){if(!Number.isInteger(e.cap)||e.cap<1)throw new RangeError(`WriteQueue.cap must be a positive integer (got ${String(e.cap)})`);this.cap=e.cap,this.name=e.name??"write-queue";}run(e){if(this.pendingCount()>=this.cap)throw new dt(`${this.name} is full (cap ${this.cap}); ${this.pendingCount()} pending`,{details:{queue:this.name,cap:this.cap,pending:this.pendingCount()}});let{promise:t,resolve:r,reject:o}=Promise.withResolvers();return this.queue.push({fn:e,resolve:r,reject:o}),this.pump(),t}inFlightCount(){return this.inFlight}waitingCount(){return this.queue.length}pendingCount(){return this.inFlight+this.queue.length}pump(){if(this.inFlight>0)return;let e=this.queue.shift();e!==void 0&&(this.inFlight++,(async()=>{try{let t=await e.fn();e.resolve(t);}catch(t){e.reject(t);}finally{this.inFlight--,this.pump();}})());}};var dc=z.string().regex(/^\d+\/\d+$/,'must be "N/SECONDS" format, e.g. "120/60"').transform(n=>{let[e,t]=n.split("/").map(Number);return {limit:e,windowSeconds:t}}),lc=z.object({OMNIFOCUS_LOG_LEVEL:z.enum(["trace","debug","info","warn","error"]).default("info"),OMNIFOCUS_INTEGRATION:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_E2E:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_E2E_USE_MEMORY:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_ALLOW_RAW_SCRIPT:z.string().prefault("").transform(n=>n==="1"),OMNIFOCUS_CACHE_TTL_MS:z.coerce.number().int().positive().default(3e4),OMNIFOCUS_CACHE_CAPACITY:z.coerce.number().int().positive().default(256),OMNIFOCUS_READ_POOL_SIZE:z.coerce.number().int().min(1).max(8).default(2),OMNIFOCUS_WRITE_QUEUE_CAP:z.coerce.number().int().positive().default(50),OMNIFOCUS_JXA_TIMEOUT_MS:z.coerce.number().int().positive().default(3e4),OMNIFOCUS_OMNIJS_TIMEOUT_MS:z.coerce.number().int().positive().default(45e3),OMNIFOCUS_ATTACHMENT_PATHS:z.string().prefault(homedir()).transform(n=>n.split(":").filter(Boolean)),OMNIFOCUS_MAX_ATTACHMENT_MB:z.coerce.number().int().positive().default(100),OMNIFOCUS_TOOL_RATE_LIMIT:dc.prefault("120/60")});function mo(n=process.env,e=t=>{process.stderr.write(`[omnifocus-mcp] Config error: ${t}
|
|
3
3
|
`),process.exit(1);}){let t=lc.safeParse({OMNIFOCUS_LOG_LEVEL:n.OMNIFOCUS_LOG_LEVEL,OMNIFOCUS_INTEGRATION:n.OMNIFOCUS_INTEGRATION,OMNIFOCUS_E2E:n.OMNIFOCUS_E2E,OMNIFOCUS_E2E_USE_MEMORY:n.OMNIFOCUS_E2E_USE_MEMORY,OMNIFOCUS_ALLOW_RAW_SCRIPT:n.OMNIFOCUS_ALLOW_RAW_SCRIPT,OMNIFOCUS_CACHE_TTL_MS:n.OMNIFOCUS_CACHE_TTL_MS,OMNIFOCUS_CACHE_CAPACITY:n.OMNIFOCUS_CACHE_CAPACITY,OMNIFOCUS_READ_POOL_SIZE:n.OMNIFOCUS_READ_POOL_SIZE,OMNIFOCUS_WRITE_QUEUE_CAP:n.OMNIFOCUS_WRITE_QUEUE_CAP,OMNIFOCUS_JXA_TIMEOUT_MS:n.OMNIFOCUS_JXA_TIMEOUT_MS,OMNIFOCUS_OMNIJS_TIMEOUT_MS:n.OMNIFOCUS_OMNIJS_TIMEOUT_MS,OMNIFOCUS_ATTACHMENT_PATHS:n.OMNIFOCUS_ATTACHMENT_PATHS,OMNIFOCUS_MAX_ATTACHMENT_MB:n.OMNIFOCUS_MAX_ATTACHMENT_MB,OMNIFOCUS_TOOL_RATE_LIMIT:n.OMNIFOCUS_TOOL_RATE_LIMIT});if(!t.success){let r=t.error.issues.map(o=>` ${o.path.join(".")}: ${o.message}`);return e(`Invalid environment configuration:
|
|
4
4
|
${r.join(`
|
|
5
5
|
`)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@torsday/omnifocus-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "MCP server exposing the full OmniFocus surface to LLM agents — 80 typed tools spanning tasks, projects, tags, folders, perspectives, forecast, review, notes, attachments, and sync, with a strict typed-error taxonomy and per-tool circuit breakers, rate limiter, and idempotency-key support. macOS-only; talks to OmniFocus 4 via JXA + OmniJS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|