ainecto 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/bin/ainecto.js +343 -66
- package/dist/bin/ainecto.js.map +1 -1
- package/dist/bin/mcp.js +1 -1
- package/package.json +1 -1
package/dist/bin/ainecto.js
CHANGED
|
@@ -615,7 +615,7 @@ async function readAllStdin(stdin) {
|
|
|
615
615
|
}
|
|
616
616
|
|
|
617
617
|
// src/core/version.ts
|
|
618
|
-
var CLI_VERSION = true ? "0.
|
|
618
|
+
var CLI_VERSION = true ? "0.7.0" : "dev";
|
|
619
619
|
var PACKAGE_NAME = "@ainecto/mcp";
|
|
620
620
|
var CLI_USER_AGENT = `${PACKAGE_NAME} ${CLI_VERSION}`;
|
|
621
621
|
|
|
@@ -816,7 +816,7 @@ function redactSecretString(value) {
|
|
|
816
816
|
|
|
817
817
|
// src/core/catalog/generated.prod.ts
|
|
818
818
|
var generatedTools = [
|
|
819
|
-
{ "mcpName": "create_comments", "commandPath": ["comments", "create"], "group": "generic", "description": "Add comments, questions, or replies to a document. Anyone who can read the document may comment and reply. Set parentCommentId to reply to a top-level comment. To mention people, get their userId and displayName from list_mention_candidates, write @<displayName> in the body, and list their userIds in mentionUserIds (clientMutationId is then required). Items are applied in order and each one commits on its own; results report each item (ok, or status and error).", "inputSchema": { "additionalProperties": false, "properties": { "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" }, "items": { "description": "Comments to add, applied in order", "items": { "additionalProperties": false, "properties": { "body": { "description": "Comment text (plain text, 1..10000 characters). To mention someone, include @<displayName> exactly as returned by mcp__ainecto__list_mention_candidates.", "maxLength": 1e4, "minLength": 1, "type": "string" }, "clientMutationId": { "description": "Idempotency key (visible ASCII, at most 128 characters). Required when mentionUserIds is not empty; reuse the same value when retrying the same item so the mention email is not sent twice.", "maxLength": 128, "type": "string" }, "kind": { "description": "Top-level comments only: COMMENT (default) or QUESTION. A QUESTION can later be resolved with mcp__ainecto__resolve_comments.", "enum": ["COMMENT", "QUESTION"], "type": "string" }, "mentionUserIds": { "description": "userIds to mention (from mcp__ainecto__list_mention_candidates). Each one's @<displayName> must appear in body; newly mentioned people get a notification email.", "items": { "type": "string" }, "maxItems": 20, "type": "array", "uniqueItems": true }, "parentCommentId": { "description": "Reply to this top-level comment id (from mcp__ainecto__list_comments). Replies are one level deep: replying to a reply is rejected.", "minimum": 1, "type": "integer" } }, "required": ["body"], "type": "object" }, "minItems": 1, "type": "array" }, "mailLanguage": { "description": "Language of the
|
|
819
|
+
{ "mcpName": "create_comments", "commandPath": ["comments", "create"], "group": "generic", "description": "Add comments, questions, or replies to a document. Anyone who can read the document may comment and reply. Set parentCommentId to reply to a top-level comment. To mention people, get their userId and displayName from list_mention_candidates, write @<displayName> in the body, and list their userIds in mentionUserIds (clientMutationId is then required). Items are applied in order and each one commits on its own; results report each item (ok, or status and error).", "inputSchema": { "additionalProperties": false, "properties": { "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" }, "items": { "description": "Comments to add, applied in order", "items": { "additionalProperties": false, "properties": { "body": { "description": "Comment text (plain text, 1..10000 characters). To mention someone, include @<displayName> exactly as returned by mcp__ainecto__list_mention_candidates.", "maxLength": 1e4, "minLength": 1, "type": "string" }, "clientMutationId": { "description": "Idempotency key (visible ASCII, at most 128 characters). Required when mentionUserIds is not empty; reuse the same value when retrying the same item so the mention email is not sent twice.", "maxLength": 128, "type": "string" }, "kind": { "description": "Top-level comments only: COMMENT (default) or QUESTION. A QUESTION can later be resolved with mcp__ainecto__resolve_comments.", "enum": ["COMMENT", "QUESTION"], "type": "string" }, "mentionUserIds": { "description": "userIds to mention (from mcp__ainecto__list_mention_candidates). Each one's @<displayName> must appear in body; newly mentioned people get a notification email.", "items": { "type": "string" }, "maxItems": 20, "type": "array", "uniqueItems": true }, "parentCommentId": { "description": "Reply to this top-level comment id (from mcp__ainecto__list_comments). Replies are one level deep: replying to a reply is rejected. The thread's original author and earlier repliers get a notification email (except people mentioned in this reply, who get the mention email instead).", "minimum": 1, "type": "integer" } }, "required": ["body"], "type": "object" }, "minItems": 1, "type": "array" }, "mailLanguage": { "description": "Language of the comment notification email (mention or reply). Defaults to en.", "enum": ["en", "ko"], "type": "string" } }, "required": ["documentUuid", "items"], "type": "object" }, "required": ["documentUuid", "items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "b3ad621ef51c3003" },
|
|
820
820
|
{ "mcpName": "create_documents", "commandPath": ["documents", "create"], "group": "document", "description": "Create documents. If a document body is tens of KB or more, prefer request_upload_token (purpose=document.create) and upload the body with curl.", "inputSchema": { "properties": { "items": { "description": "Documents", "items": { "properties": { "body": { "description": "Deprecated compatibility alias for typePayload.body when document type is markdown. \uBCF8\uBB38\uC774 \uC218\uC2ED KB \uC774\uC0C1\uC73C\uB85C \uD06C\uBA74 LLM \uD1A0\uD070 \uC808\uC57D\uC744 \uC704\uD574 `request_upload_token (purpose=document.create)` \uB97C \uD638\uCD9C\uD574 uploadUrl \uC744 \uBC1B\uACE0 curl \uB85C \uC9C1\uC811 PUT \uC73C\uB85C \uBCF4\uB0BC \uAC83.", "type": "string" }, "folderUuid": { "description": "Optional folder UUID", "type": "string" }, "projectUuid": { "description": "Project UUID", "type": "string" }, "title": { "description": "Document title", "type": "string" }, "type": { "description": "Document type. Creatable values: erd, markdown, diagram, openapi, html, file.", "enum": ["erd", "markdown", "diagram", "openapi", "html", "file"], "type": "string" }, "typePayload": { "description": 'Type-specific payload for enabled document types. markdown: {body}; diagram: {diagramSource,sourceLanguage,edgeStyle,isModule,metadata}; openapi: {content}; html: {content} (a full HTML page); file: no JSON payload \u2014 bytes go through request_upload_token(purpose=document.create, scopeJson={projectUuid,folderUuid?,type:"file",title,filename}) then one curl PUT (images\xB7PDF\xB7mp4/webm\xB7audio\xB7text/code\xB7CSV only).', "type": "object" } }, "required": ["projectUuid", "type", "title"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "aa868b0e2821006a" },
|
|
821
821
|
{ "mcpName": "create_folders", "commandPath": ["folders", "create"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Folders", "items": { "properties": { "name": { "description": "Folder name", "type": "string" }, "parentFolderUuid": { "description": "Parent folder UUID", "type": "string" }, "projectUuid": { "description": "Project UUID", "type": "string" } }, "required": ["projectUuid", "name"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "30f45b887259609f" },
|
|
822
822
|
{ "mcpName": "create_projects", "commandPath": ["projects", "create"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Projects", "items": { "properties": { "description": { "description": "Description", "type": "string" }, "name": { "description": "Project name", "type": "string" }, "projectKey": { "description": "Unique project key", "type": "string" }, "workspaceUuid": { "description": "Workspace UUID \u2014 null uses user's default workspace", "type": "string" } }, "required": ["name"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "edf5cf688d7c039a" },
|
|
@@ -851,15 +851,19 @@ var generatedTools = [
|
|
|
851
851
|
{ "mcpName": "erd_list_tables", "commandPath": ["erd", "list-tables"], "group": "erd", "description": "", "inputSchema": { "properties": { "documentUuid": { "description": "ERD document UUID", "type": "string" } }, "required": ["documentUuid"], "type": "object" }, "required": ["documentUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "34324dfc7ef461c8" },
|
|
852
852
|
{ "mcpName": "get_attachment", "commandPath": ["attachment", "get"], "group": "attachment", "description": "", "inputSchema": { "properties": { "uuid": { "description": "Attachment UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "required": ["uuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "1e0e7f1bf33b669c" },
|
|
853
853
|
{ "mcpName": "get_document", "commandPath": ["document", "get"], "group": "document", "description": "Read a document. The body comes back for the types whose create/update take one: markdown \u2192 content; openapi \u2192 content (the spec text) + format/specVersion/pathCount/operationCount; html \u2192 content (the HTML text); file \u2192 file {filename, contentType, sizeBytes, viewerKind} + content for text/CSV (first 64 KB); diagram \u2192 diagramSource/sourceLanguage/edgeStyle/isModule/metadata; erd \u2192 metadata only (read tables/refs via erd_list_*).", "inputSchema": { "properties": { "uuid": { "description": "Document UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "required": ["uuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "2efef592c2d6dd7a" },
|
|
854
|
+
{ "mcpName": "get_my_work_summary", "commandPath": ["my-work-summary", "get"], "group": "generic", "description": `One-call summary of what is waiting for the signed-in user in AiNecto \u2014 call it when the user asks things like "do I have anything to do?", "anything new?", "anything to review?" or "did anyone ask me something?". Returns notifications {unread (not yet read by the person, newest 100 counted; unreadCapped when there are more), unreadByKind, newForThisConnection (not yet acknowledged by this connection \u2014 the same number as the line at the end of tool results)}, mentionsToRead {items the person has not read that mention them, each with target title and url}, and todos {open, leaseExpired, inProgress, items: questions and requests waiting for the user's agent}. For details use list_notifications and list_agent_todos; to read the document and its comments use get_document with the target uuid. Read-only: nothing is marked read or acknowledged.`, "inputSchema": { "additionalProperties": false, "properties": { "projectUuid": { "description": "Older single-value form of projectUuids.", "type": "string" }, "projectUuids": { "description": "Only items in any of these projects. Use it when the user names a project or the project you are working in is clear. With workspaceUuids too, both must match. A workspace or project you cannot see matches nothing.", "items": { "type": "string" }, "type": "array", "uniqueItems": true }, "workspaceUuids": { "description": "Only items in any of these workspaces.", "items": { "type": "string" }, "type": "array", "uniqueItems": true } }, "type": "object" }, "required": [], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "bc63904d51058f42" },
|
|
854
855
|
{ "mcpName": "get_project", "commandPath": ["project", "get"], "group": "generic", "description": "", "inputSchema": { "properties": { "uuid": { "description": "Project UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "required": ["uuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "192403c3484ac774" },
|
|
855
856
|
{ "mcpName": "get_version", "commandPath": ["version", "get"], "group": "generic", "description": "", "inputSchema": { "properties": { "documentUuid": { "description": "Document UUID", "type": "string" }, "versionNumber": { "description": "Version number", "type": "integer" } }, "required": ["documentUuid", "versionNumber"], "type": "object" }, "required": ["documentUuid", "versionNumber"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "4e308c1a8c7203d1" },
|
|
856
857
|
{ "mcpName": "get_workspace", "commandPath": ["workspace", "get"], "group": "workspace", "description": "", "inputSchema": { "properties": { "uuid": { "description": "Workspace UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "required": ["uuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "db6d1b4879d57c56" },
|
|
857
858
|
{ "mcpName": "identity_get_self", "commandPath": ["tools", "run", "identity-get-self"], "group": "generic", "description": "Return the authenticated MCP caller identity summary; never returns email or token claims.", "inputSchema": { "additionalProperties": false, "properties": {}, "type": "object" }, "required": [], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "f29c86804eb91700" },
|
|
859
|
+
{ "mcpName": "list_agent_todos", "commandPath": ["agent-todos", "list"], "group": "generic", "description": "List the to-dos that ask the signed-in user's agent to act now (for example a question that mentions the user). This is the current state, not a feed: a to-do you have not finished comes back on every call until it is completed, dismissed, or closed because the person did it themselves. Each item has todoId, kind, obligation, openedAt, summary, target (title and url), action and state. To work on one, claim it with update_agent_todos and complete it with a one-line note. Actions that affect other people (assigning, approving, inviting) need the user's confirmation first.", "inputSchema": { "additionalProperties": false, "properties": { "after": { "description": "todoId of the last item of the previous page.", "type": "string" }, "kinds": { "description": "Only these kinds.", "items": { "enum": ["COMMENT_MENTIONED", "COMMENT_REPLIED", "QUESTION_ANSWERED", "QUESTION_RESOLVED", "QUESTION_MENTIONED"], "type": "string" }, "type": "array", "uniqueItems": true }, "limit": { "description": "Items per call, default 20.", "maximum": 50, "minimum": 1, "type": "integer" }, "projectUuid": { "description": "Older single-value form of projectUuids.", "type": "string" }, "projectUuids": { "description": "Only to-dos in any of these projects. Use it when the user names a project or the project you are working in is clear. With workspaceUuids too, both must match. A workspace or project you cannot see matches nothing.", "items": { "type": "string" }, "type": "array", "uniqueItems": true }, "state": { "description": "OPEN (default): to-dos you can take, including ones whose lease expired. MINE: to-dos currently leased (claimed) and not expired.", "items": { "enum": ["OPEN", "MINE"], "type": "string" }, "type": "array", "uniqueItems": true }, "workspaceUuids": { "description": "Only to-dos in any of these workspaces.", "items": { "type": "string" }, "type": "array", "uniqueItems": true } }, "type": "object" }, "required": [], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "9c228a3044a546cf" },
|
|
858
860
|
{ "mcpName": "list_attachments", "commandPath": ["attachments", "list"], "group": "attachment", "description": "", "inputSchema": { "properties": { "projectUuid": { "description": "Project UUID", "type": "string" } }, "required": ["projectUuid"], "type": "object" }, "required": ["projectUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "fae7152d1e4a930b" },
|
|
859
861
|
{ "mcpName": "list_comments", "commandPath": ["comments", "list"], "group": "generic", "description": "List the active comments on a document, oldest first, including replies (a reply has parentCommentId set; replies are one level deep). Each comment has id, kind (COMMENT or QUESTION), body, author, mentions (userId, label and position in the body), and for questions questionState (UNANSWERED, ANSWERED, RESOLVED) and resolvedAt. Anyone who can read the document can list its comments.", "inputSchema": { "additionalProperties": false, "properties": { "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" } }, "required": ["documentUuid"], "type": "object" }, "required": ["documentUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "4c60115a00f61404" },
|
|
860
862
|
{ "mcpName": "list_documents", "commandPath": ["documents", "list"], "group": "document", "description": "", "inputSchema": { "properties": { "folderUuid": { "description": "Optional folder UUID", "type": "string" }, "limit": { "description": "Result cap when q is set (default 50)", "type": "integer" }, "projectUuid": { "description": "Project UUID", "type": "string" }, "q": { "description": "Optional full-text query. When provided, results come from the search index instead of folder listing.", "type": "string" }, "type": { "description": "Optional document type filter. Readable values: erd, markdown, diagram, openapi, html, file.", "enum": ["erd", "markdown", "diagram", "openapi", "html", "file"], "type": "string" } }, "type": "object" }, "required": [], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "2171496b44dc2abf" },
|
|
861
863
|
{ "mcpName": "list_folders", "commandPath": ["folders", "list"], "group": "generic", "description": "", "inputSchema": { "properties": { "projectUuid": { "description": "Project UUID", "type": "string" } }, "required": ["projectUuid"], "type": "object" }, "required": ["projectUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "461dc6735ac92c3b" },
|
|
864
|
+
{ "mcpName": "list_history", "commandPath": ["history", "list"], "group": "generic", "description": "List recent activity (who did what, people and agents) in a workspace, a project, or on one resource, newest first. Give at least one of workspaceUuid, projectUuid, or resourceType with resourceUuid; you need editor access or higher in that scope. This is a list to refresh, not a gap-free feed: to see what is new, read the first page again and skip ids you have already seen; to get each new notification exactly once use list_notifications. Each item has id, kind, at, lastAt, coalesceCount, actor, target (title and url only when you can read it now), changes and summary.", "inputSchema": { "additionalProperties": false, "properties": { "actorType": { "description": "Only people (USER) or only agents (AGENT).", "enum": ["USER", "AGENT"], "type": "string" }, "before": { "description": "nextCursor of the previous page (older items).", "type": "string" }, "kinds": { "description": "Only these kinds.", "items": { "enum": ["COMMENT_MENTIONED", "COMMENT_REPLIED", "QUESTION_ANSWERED", "QUESTION_RESOLVED", "QUESTION_MENTIONED"], "type": "string" }, "type": "array", "uniqueItems": true }, "limit": { "description": "Items per call, default 20.", "maximum": 50, "minimum": 1, "type": "integer" }, "projectUuid": { "description": "Activity in this project.", "type": "string" }, "resourceType": { "description": "With resourceUuid: activity on one resource.", "enum": ["DOCUMENT", "PROJECT"], "type": "string" }, "resourceUuid": { "description": "UUID of the resource named by resourceType.", "type": "string" }, "workspaceUuid": { "description": "Activity in this workspace.", "type": "string" } }, "type": "object" }, "required": [], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "235832683071654b" },
|
|
862
865
|
{ "mcpName": "list_mention_candidates", "commandPath": ["mention-candidates", "list"], "group": "generic", "description": "List the people you can mention in comments on a document: userId and displayName. Only people who can read the document are listed. To mention someone, write @<displayName> exactly in the comment body and pass their userId in mentionUserIds of create_comments or update_comments. Page with nextCursor while hasMore is true.", "inputSchema": { "additionalProperties": false, "properties": { "cursor": { "description": "nextCursor from the previous page (same documentUuid and query).", "type": "string" }, "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" }, "limit": { "description": "Page size, 1..50. Defaults to 20.", "maximum": 50, "minimum": 1, "type": "integer" }, "query": { "description": "Name filter, 0..100 characters. Omit or leave empty for the first page of everyone.", "maxLength": 100, "type": "string" } }, "required": ["documentUuid"], "type": "object" }, "required": ["documentUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "896a5a6ff357268b" },
|
|
866
|
+
{ "mcpName": "list_notifications", "commandPath": ["notifications", "list"], "group": "generic", "description": "Read new notifications for the signed-in user, oldest first and without gaps \u2014 for an agent that checks the inbox periodically. The server remembers, per connection and per filter (kinds, workspaceUuids, projectUuids, directOnly), how far you have acknowledged; a new filter starts from now. Each response carries ackToken: pass it as ack in your next call (with the same filter) after you have handled the batch \u2014 if you do not, the next call returns the same batch again (identify duplicates by id and seq; an item that comes back with a higher seq and a larger groupCount is an update of the same entry). Each item has id, seq, kind, at, summary (one line), actor, target (title and url only when you can read it now), action (what the user is asked to do) and humanRead. An item you can no longer read comes back as {id, seq, at, redacted: true}. This tool never marks anything read for the person; open to-dos are in list_agent_todos. Calls closer than 30 seconds apart (except a call that carries ack) return retryAfterSeconds instead of items.", "inputSchema": { "additionalProperties": false, "properties": { "ack": { "description": "The ackToken of the previous response. Send it with the same filter once you have handled (or safely stored) that batch; only then does the saved position move past it. Without it, the same batch is returned again.", "type": "string" }, "cursor": { "description": 'Where to read from. "saved" (default): after what this connection last acknowledged for this same filter. "latest": from now on (moves the saved position to now). "earliest": everything still kept (90 days). Or a nextCursor from a previous response: read after it without using or changing the saved position.', "type": "string" }, "directOnly": { "description": "Only notifications that point at you directly (mentions, questions to you).", "type": "boolean" }, "kinds": { "description": "Only these notification kinds.", "items": { "enum": ["COMMENT_MENTIONED", "COMMENT_REPLIED", "QUESTION_ANSWERED", "QUESTION_RESOLVED", "QUESTION_MENTIONED"], "type": "string" }, "type": "array", "uniqueItems": true }, "limit": { "description": "Items per call, default 20.", "maximum": 50, "minimum": 1, "type": "integer" }, "projectUuid": { "description": "Older single-value form of projectUuids.", "type": "string" }, "projectUuids": { "description": "Only notifications in any of these projects. Use it when the user names a project or the project you are working in is clear. With workspaceUuids too, both must match. A workspace or project you cannot see matches nothing.", "items": { "type": "string" }, "type": "array", "uniqueItems": true }, "workspaceUuids": { "description": "Only notifications in any of these workspaces.", "items": { "type": "string" }, "type": "array", "uniqueItems": true } }, "type": "object" }, "required": [], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "0c2bb3fdc8291b03" },
|
|
863
867
|
{ "mcpName": "list_projects", "commandPath": ["projects", "list"], "group": "generic", "description": "", "inputSchema": { "properties": { "limit": { "description": "Result cap when q is set (default 50)", "type": "integer" }, "q": { "description": "Optional full-text query", "type": "string" }, "workspaceUuid": { "description": "Optional Workspace UUID", "type": "string" } }, "type": "object" }, "required": [], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "939bfcc088425771" },
|
|
864
868
|
{ "mcpName": "list_trash", "commandPath": ["trash", "list"], "group": "generic", "description": "", "inputSchema": { "properties": {}, "type": "object" }, "required": [], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "329250aecc06a298" },
|
|
865
869
|
{ "mcpName": "list_versions", "commandPath": ["versions", "list"], "group": "generic", "description": "", "inputSchema": { "properties": { "documentUuid": { "description": "Document UUID", "type": "string" } }, "required": ["documentUuid"], "type": "object" }, "required": ["documentUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "f08f9faee3ba9107" },
|
|
@@ -877,7 +881,8 @@ var generatedTools = [
|
|
|
877
881
|
{ "mcpName": "unarchive_folders", "commandPath": ["folders", "unarchive"], "group": "generic", "description": "", "inputSchema": { "properties": { "uuids": { "description": "Folder UUIDs", "items": { "type": "string" }, "type": "array" } }, "required": ["uuids"], "type": "object" }, "required": ["uuids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "2a24cc44696b7906" },
|
|
878
882
|
{ "mcpName": "unarchive_projects", "commandPath": ["projects", "unarchive"], "group": "generic", "description": "", "inputSchema": { "properties": { "uuids": { "description": "Project UUIDs", "items": { "type": "string" }, "type": "array" } }, "required": ["uuids"], "type": "object" }, "required": ["uuids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "6925e444671afe19" },
|
|
879
883
|
{ "mcpName": "unarchive_workspaces", "commandPath": ["workspaces", "unarchive"], "group": "workspace", "description": "", "inputSchema": { "properties": { "uuids": { "description": "Workspace UUIDs", "items": { "type": "string" }, "type": "array" } }, "required": ["uuids"], "type": "object" }, "required": ["uuids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "8dafe9bc6378c3f2" },
|
|
880
|
-
{ "mcpName": "
|
|
884
|
+
{ "mcpName": "update_agent_todos", "commandPath": ["agent-todos", "update"], "group": "generic", "description": "Claim, renew, complete, release, or dismiss the signed-in user's agent to-dos. Only the session holding the current leaseToken may renew, release, or complete a claimed to-do \u2014 even another session of the same connection gets CLAIMED_BY_OTHER. Results are per item: {todoId, ok: true, state, leaseToken?, claimExpiresAt?} or {todoId, ok: false, error} with error one of CLAIMED_BY_OTHER, LEASE_LOST, ALREADY_DONE, CLOSED_BY_HUMAN, SUPERSEDED, ACCESS_LOST, NOT_FOUND, INVALID \u2014 on CLOSED_BY_HUMAN or SUPERSEDED stop working on it. Retrying the same complete or dismiss returns ok again. There is no tool to mark the person's notifications read.", "inputSchema": { "additionalProperties": false, "properties": { "items": { "description": "To-dos to update; each item is applied and reported on its own.", "items": { "additionalProperties": false, "properties": { "action": { "description": "claim: take it (returns leaseToken, valid 30 minutes). renew: extend your lease. complete: done (with leaseToken if you claimed it; without one only while it is still OPEN). release: give it back. dismiss: not a to-do.", "enum": ["claim", "renew", "complete", "release", "dismiss"], "type": "string" }, "leaseToken": { "description": "Required for renew and release, and for complete or dismiss of a to-do you claimed.", "type": "string" }, "note": { "description": "For complete or dismiss: one line on what you did (at most 500 characters, no document bodies). The person sees it in the inbox.", "maxLength": 500, "type": "string" }, "todoId": { "description": "todoId from list_agent_todos.", "type": "string" } }, "required": ["todoId", "action"], "type": "object" }, "maxItems": 50, "minItems": 1, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "da38f4f54f68dbce" },
|
|
885
|
+
{ "mcpName": "update_comments", "commandPath": ["comments", "update"], "group": "generic", "description": "Edit your own comments on a document. Only the author can edit, and only while they can still read the document. A resolved question and a top-level comment that already has replies are locked. Items are applied in order and each one commits on its own; results report each item.", "inputSchema": { "additionalProperties": false, "properties": { "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" }, "items": { "description": "Edits, applied in order", "items": { "additionalProperties": false, "properties": { "body": { "description": "New comment text (replaces the old text).", "maxLength": 1e4, "minLength": 1, "type": "string" }, "clientMutationId": { "description": "Idempotency key (visible ASCII, at most 128 characters). Required when mentionUserIds is not empty; reuse the same value when retrying the same item so the mention email is not sent twice.", "maxLength": 128, "type": "string" }, "id": { "description": "Comment id (from mcp__ainecto__list_comments)", "minimum": 1, "type": "integer" }, "mentionUserIds": { "description": "The complete set of userIds mentioned after the edit; omit to remove all mentions. Each one's @<displayName> must appear in body. Only people who were not mentioned before get a notification email.", "items": { "type": "string" }, "maxItems": 20, "type": "array", "uniqueItems": true } }, "required": ["id", "body"], "type": "object" }, "minItems": 1, "type": "array" }, "mailLanguage": { "description": "Language of the comment notification email (mention or reply). Defaults to en.", "enum": ["en", "ko"], "type": "string" } }, "required": ["documentUuid", "items"], "type": "object" }, "required": ["documentUuid", "items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "3c13611a49c95979" },
|
|
881
886
|
{ "mcpName": "update_documents", "commandPath": ["documents", "update"], "group": "document", "description": "Update documents. If a replacement body is tens of KB or more, prefer request_upload_token (purpose=document.update) and upload the body with curl.", "inputSchema": { "properties": { "items": { "description": "Updates", "items": { "properties": { "body": { "description": "Deprecated compatibility alias for typePayload.body when document type is markdown. \uBCF8\uBB38\uC774 \uC218\uC2ED KB \uC774\uC0C1\uC73C\uB85C \uD06C\uBA74 LLM \uD1A0\uD070 \uC808\uC57D\uC744 \uC704\uD574 `request_upload_token (purpose=document.update)` \uB97C \uD638\uCD9C\uD574 uploadUrl \uC744 \uBC1B\uACE0 curl \uB85C \uC9C1\uC811 PUT \uC73C\uB85C \uBCF4\uB0BC \uAC83.", "type": "string" }, "title": { "description": "New title", "type": "string" }, "typePayload": { "description": "Type-specific payload for enabled document types. markdown: {body}; diagram: {diagramSource,sourceLanguage,edgeStyle,isModule,metadata}; openapi: {content}; html: {content} (a full HTML page); file: {file:{filename,contentType,sizeBytes,viewerKind}} (+content for text/CSV, first 64 KB).", "type": "object" }, "uuid": { "description": "Document UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "c2088f9ef5b49c6c" },
|
|
882
887
|
{ "mcpName": "update_folders", "commandPath": ["folders", "update"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Updates", "items": { "properties": { "name": { "description": "New name", "type": "string" }, "uuid": { "description": "Folder UUID", "type": "string" } }, "required": ["uuid", "name"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "43c58a96ee632b5f" },
|
|
883
888
|
{ "mcpName": "update_projects", "commandPath": ["projects", "update"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Updates", "items": { "properties": { "description": { "description": "New description", "type": "string" }, "name": { "description": "New name", "type": "string" }, "uuid": { "description": "Project UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "7d849ef0a830aa8c" },
|
|
@@ -1527,6 +1532,9 @@ async function promptConfirmation(io, message) {
|
|
|
1527
1532
|
|
|
1528
1533
|
// src/adapters/cli/bespokeCommands.ts
|
|
1529
1534
|
var ATTACHMENTS_UPLOAD_COMMAND_PATH = ["attachments", "upload"];
|
|
1535
|
+
var NOTIFICATIONS_POLL_COMMAND_PATH = ["notifications", "poll"];
|
|
1536
|
+
var NOTIFICATIONS_ACK_COMMAND_PATH = ["notifications", "ack"];
|
|
1537
|
+
var AGENT_TODOS_POLL_COMMAND_PATH = ["agent-todos", "poll"];
|
|
1530
1538
|
|
|
1531
1539
|
// src/adapters/cli/generatedCommandRouter.ts
|
|
1532
1540
|
function matchGeneratedCommand(tools, argv) {
|
|
@@ -1612,6 +1620,34 @@ function findRestStart(argv, commandPath) {
|
|
|
1612
1620
|
// src/core/upload/attachmentUpload.ts
|
|
1613
1621
|
import { readFile as readFile3, stat as stat2 } from "fs/promises";
|
|
1614
1622
|
import { basename, extname } from "path";
|
|
1623
|
+
|
|
1624
|
+
// src/core/mcp/toolPayload.ts
|
|
1625
|
+
function unwrapMcpToolPayload(value) {
|
|
1626
|
+
if (!isRecord7(value) || !Array.isArray(value.content)) {
|
|
1627
|
+
return value;
|
|
1628
|
+
}
|
|
1629
|
+
const text = value.content.map((item) => isRecord7(item) && typeof item.text === "string" ? item.text : "").find((itemText) => itemText.trim().startsWith("{"));
|
|
1630
|
+
if (!text) {
|
|
1631
|
+
return value;
|
|
1632
|
+
}
|
|
1633
|
+
try {
|
|
1634
|
+
return JSON.parse(text);
|
|
1635
|
+
} catch {
|
|
1636
|
+
return value;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
function toolErrorText(value) {
|
|
1640
|
+
if (!isRecord7(value) || !Array.isArray(value.content)) {
|
|
1641
|
+
return "The tool returned an error.";
|
|
1642
|
+
}
|
|
1643
|
+
const text = value.content.map((item) => isRecord7(item) && typeof item.text === "string" ? item.text : "").filter(Boolean).join("\n");
|
|
1644
|
+
return text || "The tool returned an error.";
|
|
1645
|
+
}
|
|
1646
|
+
function isRecord7(value) {
|
|
1647
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// src/core/upload/attachmentUpload.ts
|
|
1615
1651
|
var AttachmentUploadError = class extends Error {
|
|
1616
1652
|
constructor(code, message, details) {
|
|
1617
1653
|
super(message);
|
|
@@ -1709,7 +1745,7 @@ async function requestUploadToken(client, metadata, context) {
|
|
|
1709
1745
|
requestArgs.ttlSeconds = context.ttlSeconds;
|
|
1710
1746
|
}
|
|
1711
1747
|
const response = unwrapMcpToolPayload(await client.toolsCall(context.requestToolName, requestArgs));
|
|
1712
|
-
if (!
|
|
1748
|
+
if (!isRecord8(response)) {
|
|
1713
1749
|
throw new AttachmentUploadError("UPLOAD_TOKEN_PROTOCOL_ERROR", "request_upload_token response was not an object.");
|
|
1714
1750
|
}
|
|
1715
1751
|
const token = response.token;
|
|
@@ -1779,7 +1815,7 @@ function parsePutResponse(text) {
|
|
|
1779
1815
|
} catch {
|
|
1780
1816
|
throw new AttachmentUploadError("ATTACHMENT_UPLOAD_PROTOCOL_ERROR", "Attachment PUT response was not valid JSON.");
|
|
1781
1817
|
}
|
|
1782
|
-
if (!
|
|
1818
|
+
if (!isRecord8(parsed)) {
|
|
1783
1819
|
throw new AttachmentUploadError("ATTACHMENT_UPLOAD_PROTOCOL_ERROR", "Attachment PUT response was not an object.");
|
|
1784
1820
|
}
|
|
1785
1821
|
if (typeof parsed.storageKey !== "string") {
|
|
@@ -1811,20 +1847,6 @@ function validatePutResult(token, metadata, putResult) {
|
|
|
1811
1847
|
});
|
|
1812
1848
|
}
|
|
1813
1849
|
}
|
|
1814
|
-
function unwrapMcpToolPayload(value) {
|
|
1815
|
-
if (!isRecord7(value) || !Array.isArray(value.content)) {
|
|
1816
|
-
return value;
|
|
1817
|
-
}
|
|
1818
|
-
const text = value.content.map((item) => isRecord7(item) && typeof item.text === "string" ? item.text : "").find((itemText) => itemText.trim().startsWith("{"));
|
|
1819
|
-
if (!text) {
|
|
1820
|
-
return value;
|
|
1821
|
-
}
|
|
1822
|
-
try {
|
|
1823
|
-
return JSON.parse(text);
|
|
1824
|
-
} catch {
|
|
1825
|
-
return value;
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
1850
|
function emitProgress(context, stage, path, filename) {
|
|
1829
1851
|
context.onProgress?.({
|
|
1830
1852
|
stage,
|
|
@@ -1857,7 +1879,7 @@ var MIME_BY_EXTENSION = {
|
|
|
1857
1879
|
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
1858
1880
|
".zip": "application/zip"
|
|
1859
1881
|
};
|
|
1860
|
-
function
|
|
1882
|
+
function isRecord8(value) {
|
|
1861
1883
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1862
1884
|
}
|
|
1863
1885
|
|
|
@@ -1981,9 +2003,256 @@ function renderAttachmentUploadResult(result, json) {
|
|
|
1981
2003
|
return renderSuccess(lines.join("\n"), { json: false });
|
|
1982
2004
|
}
|
|
1983
2005
|
|
|
2006
|
+
// src/adapters/cli/inboxPollCommands.ts
|
|
2007
|
+
import { mkdir as mkdir2, open, readFile as readFile4, rename as rename2 } from "fs/promises";
|
|
2008
|
+
import { dirname as dirname2 } from "path";
|
|
2009
|
+
var EXIT_NOTHING_NEW = 3;
|
|
2010
|
+
var LIST_NOTIFICATIONS = "mcp__ainecto__list_notifications";
|
|
2011
|
+
var LIST_AGENT_TODOS = "mcp__ainecto__list_agent_todos";
|
|
2012
|
+
function isInboxPollCommand(domain, action) {
|
|
2013
|
+
return [NOTIFICATIONS_POLL_COMMAND_PATH, NOTIFICATIONS_ACK_COMMAND_PATH, AGENT_TODOS_POLL_COMMAND_PATH].some(([d, a]) => d === domain && a === action);
|
|
2014
|
+
}
|
|
2015
|
+
var EXIT_USAGE = 2;
|
|
2016
|
+
var USAGE_ERRORS = /* @__PURE__ */ new Set(["UNKNOWN_FLAG", "FLAG_REQUIRES_VALUE", "MISSING_REQUIRED_FLAG", "INVALID_FLAG_VALUE"]);
|
|
2017
|
+
async function executeInboxPollCommand(options) {
|
|
2018
|
+
try {
|
|
2019
|
+
if (options.domain === "agent-todos") return await agentTodosPoll(options);
|
|
2020
|
+
if (options.action === "ack") return await notificationsAck(options);
|
|
2021
|
+
return await notificationsPoll(options);
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
if (error instanceof CliCommandError && USAGE_ERRORS.has(error.code)) {
|
|
2024
|
+
options.io.stderr.write(renderError(error, { json: options.json }));
|
|
2025
|
+
return EXIT_USAGE;
|
|
2026
|
+
}
|
|
2027
|
+
throw error;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
async function notificationsPoll(options) {
|
|
2031
|
+
const flags = parseFlags(options.argv, ["--cursor-file", "--kinds", "--workspace", "--project", "--limit"], ["--direct-only"]);
|
|
2032
|
+
const cursorPath = requireFlag(flags, "--cursor-file", "notifications poll");
|
|
2033
|
+
const filter = {
|
|
2034
|
+
kinds: flags.values["--kinds"]?.split(",").map((kind) => kind.trim()).filter(Boolean).sort(),
|
|
2035
|
+
...scopeFilter(flags),
|
|
2036
|
+
directOnly: flags.switches.has("--direct-only")
|
|
2037
|
+
};
|
|
2038
|
+
if (filter.kinds?.length === 0) filter.kinds = void 0;
|
|
2039
|
+
const limit = flags.values["--limit"] === void 0 ? void 0 : positiveInt("--limit", flags.values["--limit"]);
|
|
2040
|
+
const saved = await readCursorFile(cursorPath);
|
|
2041
|
+
if (saved?.ackToken && saved.pendingItems?.length) {
|
|
2042
|
+
if (!sameFilter(saved.filter, filter)) {
|
|
2043
|
+
throw new CliCommandError(
|
|
2044
|
+
"PENDING_BATCH_OTHER_FILTER",
|
|
2045
|
+
`${cursorPath} holds an unacknowledged batch for a different filter. Run \`ainecto notifications ack --cursor-file ${cursorPath}\` after handling it, or use another cursor file for this filter.`,
|
|
2046
|
+
{ cursorFile: cursorPath }
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
options.io.stdout.write(renderSuccess({ items: saved.pendingItems, pending: true, stream: saved.stream }, { json: options.json }));
|
|
2050
|
+
return 0;
|
|
2051
|
+
}
|
|
2052
|
+
const result = await callTool(options.client, LIST_NOTIFICATIONS, {
|
|
2053
|
+
cursor: "saved",
|
|
2054
|
+
...filter.kinds ? { kinds: filter.kinds } : {},
|
|
2055
|
+
...scopeArgs(filter),
|
|
2056
|
+
...filter.directOnly ? { directOnly: true } : {},
|
|
2057
|
+
...limit !== void 0 ? { limit } : {}
|
|
2058
|
+
});
|
|
2059
|
+
const items = Array.isArray(result.items) ? result.items : [];
|
|
2060
|
+
const stream = typeof result.stream === "string" ? result.stream : void 0;
|
|
2061
|
+
if (typeof result.retryAfterSeconds === "number") {
|
|
2062
|
+
options.io.stderr.write(`Polled too soon; try again in ${result.retryAfterSeconds}s.
|
|
2063
|
+
`);
|
|
2064
|
+
return EXIT_NOTHING_NEW;
|
|
2065
|
+
}
|
|
2066
|
+
if (items.length === 0) {
|
|
2067
|
+
await writeCursorFile(cursorPath, { v: 1, filter, stream });
|
|
2068
|
+
if (options.json) options.io.stdout.write(renderSuccess({ items: [], stream }, { json: true }));
|
|
2069
|
+
return EXIT_NOTHING_NEW;
|
|
2070
|
+
}
|
|
2071
|
+
await writeCursorFile(cursorPath, {
|
|
2072
|
+
v: 1,
|
|
2073
|
+
filter,
|
|
2074
|
+
stream,
|
|
2075
|
+
ackToken: typeof result.ackToken === "string" ? result.ackToken : void 0,
|
|
2076
|
+
pendingItems: items
|
|
2077
|
+
});
|
|
2078
|
+
options.io.stdout.write(renderSuccess({ items, hasMore: result.hasMore === true, stream }, { json: options.json }));
|
|
2079
|
+
return 0;
|
|
2080
|
+
}
|
|
2081
|
+
async function notificationsAck(options) {
|
|
2082
|
+
const flags = parseFlags(options.argv, ["--cursor-file"], []);
|
|
2083
|
+
const cursorPath = requireFlag(flags, "--cursor-file", "notifications ack");
|
|
2084
|
+
const saved = await readCursorFile(cursorPath);
|
|
2085
|
+
if (!saved?.ackToken) {
|
|
2086
|
+
if (options.json) options.io.stdout.write(renderSuccess({ acked: false }, { json: true }));
|
|
2087
|
+
return EXIT_NOTHING_NEW;
|
|
2088
|
+
}
|
|
2089
|
+
await callTool(options.client, LIST_NOTIFICATIONS, {
|
|
2090
|
+
cursor: "saved",
|
|
2091
|
+
ack: saved.ackToken,
|
|
2092
|
+
...saved.filter.kinds ? { kinds: saved.filter.kinds } : {},
|
|
2093
|
+
...scopeArgs(saved.filter),
|
|
2094
|
+
...saved.filter.directOnly ? { directOnly: true } : {},
|
|
2095
|
+
limit: 1
|
|
2096
|
+
});
|
|
2097
|
+
const acked = saved.pendingItems?.length ?? 0;
|
|
2098
|
+
await writeCursorFile(cursorPath, { v: 1, filter: saved.filter, stream: saved.stream });
|
|
2099
|
+
options.io.stdout.write(renderSuccess({ acked: true, items: acked }, { json: options.json }));
|
|
2100
|
+
return 0;
|
|
2101
|
+
}
|
|
2102
|
+
async function agentTodosPoll(options) {
|
|
2103
|
+
const flags = parseFlags(options.argv, ["--workspace", "--project", "--seen-file"], ["--only-new"]);
|
|
2104
|
+
const scope = scopeArgs(scopeFilter(flags));
|
|
2105
|
+
const onlyNew = flags.switches.has("--only-new");
|
|
2106
|
+
const seenPath = flags.values["--seen-file"];
|
|
2107
|
+
if (onlyNew && !seenPath) {
|
|
2108
|
+
throw new CliCommandError("MISSING_REQUIRED_FLAG", "--only-new needs --seen-file <path>.", { flag: "--seen-file" });
|
|
2109
|
+
}
|
|
2110
|
+
const items = [];
|
|
2111
|
+
let after;
|
|
2112
|
+
for (let page = 0; page < 20; page += 1) {
|
|
2113
|
+
const result = await callTool(options.client, LIST_AGENT_TODOS, { state: ["OPEN"], ...scope, limit: 50, ...after ? { after } : {} });
|
|
2114
|
+
const pageItems = Array.isArray(result.items) ? result.items.filter(isRecord9) : [];
|
|
2115
|
+
items.push(...pageItems);
|
|
2116
|
+
const last = pageItems[pageItems.length - 1];
|
|
2117
|
+
if (result.hasMore !== true || !last || typeof last.todoId !== "string") break;
|
|
2118
|
+
after = last.todoId;
|
|
2119
|
+
}
|
|
2120
|
+
let shown = items;
|
|
2121
|
+
if (onlyNew && seenPath) {
|
|
2122
|
+
const seen = new Set(await readSeenFile(seenPath));
|
|
2123
|
+
shown = items.filter((item) => typeof item.todoId === "string" && !seen.has(item.todoId));
|
|
2124
|
+
await writeJsonAtomic(seenPath, items.map((item) => item.todoId).filter((id) => typeof id === "string"));
|
|
2125
|
+
}
|
|
2126
|
+
if (shown.length === 0) {
|
|
2127
|
+
if (options.json) options.io.stdout.write(renderSuccess({ items: [] }, { json: true }));
|
|
2128
|
+
return EXIT_NOTHING_NEW;
|
|
2129
|
+
}
|
|
2130
|
+
options.io.stdout.write(renderSuccess({ items: shown }, { json: options.json }));
|
|
2131
|
+
return 0;
|
|
2132
|
+
}
|
|
2133
|
+
async function callTool(client, name, args) {
|
|
2134
|
+
const raw = await client.toolsCall(name, args);
|
|
2135
|
+
if (isToolError(raw)) {
|
|
2136
|
+
throw new CliCommandError("TOOL_ERROR", toolErrorText(raw), { tool: name });
|
|
2137
|
+
}
|
|
2138
|
+
const payload = unwrapMcpToolPayload(raw);
|
|
2139
|
+
if (!isRecord9(payload)) {
|
|
2140
|
+
throw new CliCommandError("MCP_PROTOCOL_ERROR", `${name} did not return an object.`, { tool: name });
|
|
2141
|
+
}
|
|
2142
|
+
return payload;
|
|
2143
|
+
}
|
|
2144
|
+
function scopeFilter(flags) {
|
|
2145
|
+
const workspaces = uuidSet(flags.lists["--workspace"]);
|
|
2146
|
+
const projects = uuidSet(flags.lists["--project"]);
|
|
2147
|
+
return {
|
|
2148
|
+
...workspaces.length ? { workspaceUuids: workspaces } : {},
|
|
2149
|
+
...projects.length ? { projectUuids: projects } : {}
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
function uuidSet(values) {
|
|
2153
|
+
return [...new Set(values ?? [])].sort();
|
|
2154
|
+
}
|
|
2155
|
+
function scopeArgs(filter) {
|
|
2156
|
+
const workspaces = filter.workspaceUuids ?? [];
|
|
2157
|
+
const projects = filter.projectUuids ?? [];
|
|
2158
|
+
if (workspaces.length === 0 && projects.length === 1) return { projectUuid: projects[0] };
|
|
2159
|
+
return {
|
|
2160
|
+
...workspaces.length ? { workspaceUuids: workspaces } : {},
|
|
2161
|
+
...projects.length ? { projectUuids: projects } : {}
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
function parseFlags(argv, valueFlags, switchFlags) {
|
|
2165
|
+
const values = {};
|
|
2166
|
+
const lists = {};
|
|
2167
|
+
const switches = /* @__PURE__ */ new Set();
|
|
2168
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
2169
|
+
const arg = argv[index];
|
|
2170
|
+
if (!arg) continue;
|
|
2171
|
+
if (valueFlags.includes(arg)) {
|
|
2172
|
+
const value = argv[index + 1];
|
|
2173
|
+
if (!value || value.startsWith("--")) {
|
|
2174
|
+
throw new CliCommandError("FLAG_REQUIRES_VALUE", `${arg} requires a value.`, { flag: arg });
|
|
2175
|
+
}
|
|
2176
|
+
values[arg] = value;
|
|
2177
|
+
(lists[arg] ??= []).push(value);
|
|
2178
|
+
index += 1;
|
|
2179
|
+
} else if (switchFlags.includes(arg)) {
|
|
2180
|
+
switches.add(arg);
|
|
2181
|
+
} else {
|
|
2182
|
+
throw new CliCommandError("UNKNOWN_FLAG", `Unknown argument ${arg}.`, { flag: arg });
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
return { values, lists, switches };
|
|
2186
|
+
}
|
|
2187
|
+
function requireFlag(flags, flag, command) {
|
|
2188
|
+
const value = flags.values[flag];
|
|
2189
|
+
if (!value) throw new CliCommandError("MISSING_REQUIRED_FLAG", `${command} needs ${flag} <path>.`, { flag });
|
|
2190
|
+
return value;
|
|
2191
|
+
}
|
|
2192
|
+
function positiveInt(flag, value) {
|
|
2193
|
+
if (!value || !/^[1-9]\d*$/.test(value)) {
|
|
2194
|
+
throw new CliCommandError("INVALID_FLAG_VALUE", `${flag} must be a positive integer.`, { flag, value });
|
|
2195
|
+
}
|
|
2196
|
+
return Number.parseInt(value, 10);
|
|
2197
|
+
}
|
|
2198
|
+
function sameFilter(a, b) {
|
|
2199
|
+
return JSON.stringify(a.kinds ?? []) === JSON.stringify(b.kinds ?? []) && JSON.stringify(a.workspaceUuids ?? []) === JSON.stringify(b.workspaceUuids ?? []) && JSON.stringify(a.projectUuids ?? []) === JSON.stringify(b.projectUuids ?? []) && a.directOnly === b.directOnly;
|
|
2200
|
+
}
|
|
2201
|
+
function normalizeSavedFilter(saved) {
|
|
2202
|
+
const { projectUuid, ...rest } = saved;
|
|
2203
|
+
if (rest.projectUuids?.length || !projectUuid) return rest;
|
|
2204
|
+
return { ...rest, projectUuids: [projectUuid] };
|
|
2205
|
+
}
|
|
2206
|
+
async function readCursorFile(path) {
|
|
2207
|
+
const text = await readFile4(path, "utf8").catch((error) => {
|
|
2208
|
+
if (error.code === "ENOENT") return void 0;
|
|
2209
|
+
throw error;
|
|
2210
|
+
});
|
|
2211
|
+
if (text === void 0 || !text.trim()) return void 0;
|
|
2212
|
+
try {
|
|
2213
|
+
const parsed = JSON.parse(text);
|
|
2214
|
+
if (parsed?.v !== 1 || !isRecord9(parsed.filter)) throw new Error("shape");
|
|
2215
|
+
return { ...parsed, filter: normalizeSavedFilter(parsed.filter) };
|
|
2216
|
+
} catch {
|
|
2217
|
+
throw new CliCommandError("INVALID_CURSOR_FILE", `${path} is not a cursor file written by ainecto notifications poll.`, { cursorFile: path });
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
async function writeCursorFile(path, value) {
|
|
2221
|
+
await writeJsonAtomic(path, value);
|
|
2222
|
+
}
|
|
2223
|
+
async function readSeenFile(path) {
|
|
2224
|
+
const text = await readFile4(path, "utf8").catch((error) => {
|
|
2225
|
+
if (error.code === "ENOENT") return void 0;
|
|
2226
|
+
throw error;
|
|
2227
|
+
});
|
|
2228
|
+
if (!text?.trim()) return [];
|
|
2229
|
+
try {
|
|
2230
|
+
const parsed = JSON.parse(text);
|
|
2231
|
+
return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
|
|
2232
|
+
} catch {
|
|
2233
|
+
throw new CliCommandError("INVALID_SEEN_FILE", `${path} is not a seen file written by ainecto agent-todos poll.`, { seenFile: path });
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
async function writeJsonAtomic(path, value) {
|
|
2237
|
+
await mkdir2(dirname2(path), { recursive: true });
|
|
2238
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
2239
|
+
const handle = await open(temp, "w", 384);
|
|
2240
|
+
try {
|
|
2241
|
+
await handle.writeFile(`${JSON.stringify(value, null, 2)}
|
|
2242
|
+
`, "utf8");
|
|
2243
|
+
await handle.sync();
|
|
2244
|
+
} finally {
|
|
2245
|
+
await handle.close();
|
|
2246
|
+
}
|
|
2247
|
+
await rename2(temp, path);
|
|
2248
|
+
}
|
|
2249
|
+
function isRecord9(value) {
|
|
2250
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2251
|
+
}
|
|
2252
|
+
|
|
1984
2253
|
// src/adapters/cli/initCommand.ts
|
|
1985
|
-
import { chmod as chmod2, mkdir as
|
|
1986
|
-
import { dirname as
|
|
2254
|
+
import { chmod as chmod2, mkdir as mkdir3, rename as rename3, rm as rm2, rmdir, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
2255
|
+
import { dirname as dirname4, join as join3, relative, resolve as resolve2, sep as sep2 } from "path";
|
|
1987
2256
|
|
|
1988
2257
|
// src/core/harness/agentTargets.ts
|
|
1989
2258
|
import { basename as basename2 } from "path";
|
|
@@ -2003,7 +2272,7 @@ function buildServerEntry(input) {
|
|
|
2003
2272
|
return { command: "npx", args };
|
|
2004
2273
|
}
|
|
2005
2274
|
function readRoleFromEntry(entry) {
|
|
2006
|
-
if (!
|
|
2275
|
+
if (!isRecord10(entry) || !Array.isArray(entry.args)) {
|
|
2007
2276
|
return void 0;
|
|
2008
2277
|
}
|
|
2009
2278
|
const index = entry.args.indexOf("--role");
|
|
@@ -2017,13 +2286,13 @@ function readServerEntry(existing) {
|
|
|
2017
2286
|
try {
|
|
2018
2287
|
const parsed = JSON.parse(existing);
|
|
2019
2288
|
const servers = parsed?.mcpServers;
|
|
2020
|
-
return
|
|
2289
|
+
return isRecord10(servers) ? servers[SERVER_NAME] : void 0;
|
|
2021
2290
|
} catch {
|
|
2022
2291
|
return void 0;
|
|
2023
2292
|
}
|
|
2024
2293
|
}
|
|
2025
2294
|
function isOurBridge(entry) {
|
|
2026
|
-
if (!
|
|
2295
|
+
if (!isRecord10(entry)) {
|
|
2027
2296
|
return false;
|
|
2028
2297
|
}
|
|
2029
2298
|
const { command, args } = entry;
|
|
@@ -2087,7 +2356,7 @@ function readServers(root) {
|
|
|
2087
2356
|
if (servers === void 0) {
|
|
2088
2357
|
return {};
|
|
2089
2358
|
}
|
|
2090
|
-
if (!
|
|
2359
|
+
if (!isRecord10(servers)) {
|
|
2091
2360
|
throw new Error(
|
|
2092
2361
|
'Existing MCP config has an "mcpServers" value that is not an object, so it was left untouched. Fix it by hand and run init again.'
|
|
2093
2362
|
);
|
|
@@ -2106,7 +2375,7 @@ function parseConfigObject(existing) {
|
|
|
2106
2375
|
`Existing MCP config is not valid JSON, so it was left untouched. Fix it by hand and run init again. (${error instanceof Error ? error.message : String(error)})`
|
|
2107
2376
|
);
|
|
2108
2377
|
}
|
|
2109
|
-
if (!
|
|
2378
|
+
if (!isRecord10(parsed)) {
|
|
2110
2379
|
throw new Error("Existing MCP config must be a JSON object; it was left untouched.");
|
|
2111
2380
|
}
|
|
2112
2381
|
return parsed;
|
|
@@ -2115,7 +2384,7 @@ function stringify(value) {
|
|
|
2115
2384
|
return `${JSON.stringify(value, null, 2)}
|
|
2116
2385
|
`;
|
|
2117
2386
|
}
|
|
2118
|
-
function
|
|
2387
|
+
function isRecord10(value) {
|
|
2119
2388
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2120
2389
|
}
|
|
2121
2390
|
|
|
@@ -2254,14 +2523,14 @@ function managedBlockProblem(key, body) {
|
|
|
2254
2523
|
return void 0;
|
|
2255
2524
|
}
|
|
2256
2525
|
function hasUnclosedFence(content) {
|
|
2257
|
-
let
|
|
2526
|
+
let open2;
|
|
2258
2527
|
for (const line of content.split("\n")) {
|
|
2259
2528
|
const fence = fenceOf(line);
|
|
2260
2529
|
if (!fence) continue;
|
|
2261
|
-
if (!
|
|
2262
|
-
else if (fence.char ===
|
|
2530
|
+
if (!open2) open2 = { char: fence.char, length: fence.length };
|
|
2531
|
+
else if (fence.char === open2.char && fence.length >= open2.length && fence.info === "") open2 = void 0;
|
|
2263
2532
|
}
|
|
2264
|
-
return
|
|
2533
|
+
return open2 !== void 0;
|
|
2265
2534
|
}
|
|
2266
2535
|
function canonicalManagedBlock(block) {
|
|
2267
2536
|
return block.trim();
|
|
@@ -2321,24 +2590,24 @@ function hit(at, marker) {
|
|
|
2321
2590
|
return at >= 0 ? { at, length: marker.length } : void 0;
|
|
2322
2591
|
}
|
|
2323
2592
|
function isInsideFencedBlock(content, index) {
|
|
2324
|
-
let
|
|
2593
|
+
let open2;
|
|
2325
2594
|
let offset = 0;
|
|
2326
2595
|
for (const line of content.split("\n")) {
|
|
2327
2596
|
const nextOffset = offset + line.length + 1;
|
|
2328
2597
|
if (index < nextOffset) {
|
|
2329
|
-
return
|
|
2598
|
+
return open2 !== void 0;
|
|
2330
2599
|
}
|
|
2331
2600
|
const fence = fenceOf(line);
|
|
2332
2601
|
if (fence) {
|
|
2333
|
-
if (!
|
|
2334
|
-
|
|
2335
|
-
} else if (fence.char ===
|
|
2336
|
-
|
|
2602
|
+
if (!open2) {
|
|
2603
|
+
open2 = { char: fence.char, length: fence.length };
|
|
2604
|
+
} else if (fence.char === open2.char && fence.length >= open2.length && fence.info === "") {
|
|
2605
|
+
open2 = void 0;
|
|
2337
2606
|
}
|
|
2338
2607
|
}
|
|
2339
2608
|
offset = nextOffset;
|
|
2340
2609
|
}
|
|
2341
|
-
return
|
|
2610
|
+
return open2 !== void 0;
|
|
2342
2611
|
}
|
|
2343
2612
|
function fenceOf(line) {
|
|
2344
2613
|
const match = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
|
|
@@ -2667,9 +2936,9 @@ function isStringArray(value) {
|
|
|
2667
2936
|
import { createHash as createHash4 } from "crypto";
|
|
2668
2937
|
|
|
2669
2938
|
// src/core/harness/repositoryRole.ts
|
|
2670
|
-
import { lstat, readFile as
|
|
2939
|
+
import { lstat, readFile as readFile5, realpath } from "fs/promises";
|
|
2671
2940
|
import { homedir as homedir2 } from "os";
|
|
2672
|
-
import { dirname as
|
|
2941
|
+
import { dirname as dirname3, join as join2, resolve, sep } from "path";
|
|
2673
2942
|
function readConfigRole(path, content) {
|
|
2674
2943
|
if (content === void 0 || !content.trim()) {
|
|
2675
2944
|
return { kind: "absent" };
|
|
@@ -2707,7 +2976,7 @@ function rolesInFiles(files) {
|
|
|
2707
2976
|
}
|
|
2708
2977
|
async function findRepositoryRole(cwd, home = homedir2()) {
|
|
2709
2978
|
const stopAt = await realOrResolved(home);
|
|
2710
|
-
for (let dir = await realOrResolved(cwd); ; dir =
|
|
2979
|
+
for (let dir = await realOrResolved(cwd); ; dir = dirname3(dir)) {
|
|
2711
2980
|
if (samePath(dir, stopAt)) {
|
|
2712
2981
|
return { kind: "none" };
|
|
2713
2982
|
}
|
|
@@ -2737,7 +3006,7 @@ async function findRepositoryRole(cwd, home = homedir2()) {
|
|
|
2737
3006
|
}
|
|
2738
3007
|
return { kind: "role", role: result.roles[0], dir };
|
|
2739
3008
|
}
|
|
2740
|
-
if (
|
|
3009
|
+
if (dirname3(dir) === dir) {
|
|
2741
3010
|
return { kind: "none" };
|
|
2742
3011
|
}
|
|
2743
3012
|
}
|
|
@@ -2774,16 +3043,16 @@ async function readConfigInside(dir, path) {
|
|
|
2774
3043
|
if (!samePath(real, realDir) && !real.startsWith(realDir + sep) && !(process.platform === "win32" && real.toLowerCase().startsWith((realDir + sep).toLowerCase()))) {
|
|
2775
3044
|
throw new Error(`${path} points outside ${dir} (${real})`);
|
|
2776
3045
|
}
|
|
2777
|
-
return
|
|
3046
|
+
return readFile5(real, "utf8");
|
|
2778
3047
|
}
|
|
2779
3048
|
async function findGitRoot(cwd) {
|
|
2780
|
-
for (let at = resolve(cwd); ; at =
|
|
3049
|
+
for (let at = resolve(cwd); ; at = dirname3(at)) {
|
|
2781
3050
|
try {
|
|
2782
3051
|
await lstat(join2(at, ".git"));
|
|
2783
3052
|
return at;
|
|
2784
3053
|
} catch {
|
|
2785
3054
|
}
|
|
2786
|
-
if (
|
|
3055
|
+
if (dirname3(at) === at) {
|
|
2787
3056
|
return void 0;
|
|
2788
3057
|
}
|
|
2789
3058
|
}
|
|
@@ -2794,7 +3063,7 @@ async function readManagedFile(root, path) {
|
|
|
2794
3063
|
}
|
|
2795
3064
|
async function readIfExists(absolutePath) {
|
|
2796
3065
|
try {
|
|
2797
|
-
return await
|
|
3066
|
+
return await readFile5(absolutePath, "utf8");
|
|
2798
3067
|
} catch (error) {
|
|
2799
3068
|
if (isNodeError2(error, "ENOENT")) {
|
|
2800
3069
|
return void 0;
|
|
@@ -2807,7 +3076,7 @@ async function assertInsideRepository(root, relativePath) {
|
|
|
2807
3076
|
const realRoot = await realpath(root);
|
|
2808
3077
|
let realParent;
|
|
2809
3078
|
try {
|
|
2810
|
-
realParent = await realpath(
|
|
3079
|
+
realParent = await realpath(dirname3(absolutePath));
|
|
2811
3080
|
} catch (error) {
|
|
2812
3081
|
if (isNodeError2(error, "ENOENT")) {
|
|
2813
3082
|
return;
|
|
@@ -3818,11 +4087,11 @@ async function createProject(options, name) {
|
|
|
3818
4087
|
return first;
|
|
3819
4088
|
}
|
|
3820
4089
|
function unwrapToolJson(result) {
|
|
3821
|
-
if (!
|
|
4090
|
+
if (!isRecord11(result) || !Array.isArray(result.content)) {
|
|
3822
4091
|
return result;
|
|
3823
4092
|
}
|
|
3824
|
-
const first = result.content.find((item) =>
|
|
3825
|
-
if (!
|
|
4093
|
+
const first = result.content.find((item) => isRecord11(item) && item.type === "text");
|
|
4094
|
+
if (!isRecord11(first) || typeof first.text !== "string") {
|
|
3826
4095
|
return result;
|
|
3827
4096
|
}
|
|
3828
4097
|
try {
|
|
@@ -3832,13 +4101,13 @@ function unwrapToolJson(result) {
|
|
|
3832
4101
|
}
|
|
3833
4102
|
}
|
|
3834
4103
|
function extractProjects(value) {
|
|
3835
|
-
const candidates = Array.isArray(value) ? value :
|
|
4104
|
+
const candidates = Array.isArray(value) ? value : isRecord11(value) ? ["projects", "items", "created", "data", "hits"].flatMap((key) => {
|
|
3836
4105
|
const nested = value[key];
|
|
3837
4106
|
return Array.isArray(nested) ? nested : [];
|
|
3838
4107
|
}) : [];
|
|
3839
4108
|
const projects = [];
|
|
3840
4109
|
for (const candidate of candidates) {
|
|
3841
|
-
if (
|
|
4110
|
+
if (isRecord11(candidate) && typeof candidate.uuid === "string") {
|
|
3842
4111
|
projects.push({
|
|
3843
4112
|
uuid: candidate.uuid,
|
|
3844
4113
|
name: typeof candidate.name === "string" ? candidate.name : candidate.uuid
|
|
@@ -3879,9 +4148,9 @@ async function applyPlan(root, plan, dryRun, snapshot, recordFirst = true) {
|
|
|
3879
4148
|
}
|
|
3880
4149
|
const applied = [];
|
|
3881
4150
|
try {
|
|
3882
|
-
const
|
|
3883
|
-
const recordWrites = plan.writes.filter((write) =>
|
|
3884
|
-
const recordDeletes = plan.deletes.filter((path) =>
|
|
4151
|
+
const isRecord12 = (path) => !recordFirst && path === HARNESS_RECORD_PATH;
|
|
4152
|
+
const recordWrites = plan.writes.filter((write) => isRecord12(write.path));
|
|
4153
|
+
const recordDeletes = plan.deletes.filter((path) => isRecord12(path));
|
|
3885
4154
|
const createdDirectories = [...plan.record?.createdDirectories ?? []];
|
|
3886
4155
|
const rememberDirectories = (directories) => {
|
|
3887
4156
|
for (const directory of directories) {
|
|
@@ -3923,8 +4192,8 @@ async function applyPlan(root, plan, dryRun, snapshot, recordFirst = true) {
|
|
|
3923
4192
|
};
|
|
3924
4193
|
try {
|
|
3925
4194
|
await apply(
|
|
3926
|
-
orderedWrites(plan.writes.filter((write) => !
|
|
3927
|
-
plan.deletes.filter((path) => !
|
|
4195
|
+
orderedWrites(plan.writes.filter((write) => !isRecord12(write.path)), recordFirst),
|
|
4196
|
+
plan.deletes.filter((path) => !isRecord12(path))
|
|
3928
4197
|
);
|
|
3929
4198
|
await recordDirectoriesOrExplain(false);
|
|
3930
4199
|
await apply(recordWrites, recordDeletes);
|
|
@@ -3961,8 +4230,8 @@ async function assertUnchangedSinceSnapshot(root, relativePath, snapshot) {
|
|
|
3961
4230
|
}
|
|
3962
4231
|
async function writeManagedFile(root, write, onDirectoriesCreated) {
|
|
3963
4232
|
const absolutePath = join3(root, write.path);
|
|
3964
|
-
const targetDirectory =
|
|
3965
|
-
const firstCreated = await
|
|
4233
|
+
const targetDirectory = dirname4(absolutePath);
|
|
4234
|
+
const firstCreated = await mkdir3(targetDirectory, { recursive: true });
|
|
3966
4235
|
const created = createdChain(root, firstCreated, targetDirectory);
|
|
3967
4236
|
onDirectoriesCreated?.(created);
|
|
3968
4237
|
const previousMode = await fileMode(absolutePath);
|
|
@@ -3971,7 +4240,7 @@ async function writeManagedFile(root, write, onDirectoriesCreated) {
|
|
|
3971
4240
|
if (previousMode !== void 0) {
|
|
3972
4241
|
await chmod2(tmpPath, previousMode);
|
|
3973
4242
|
}
|
|
3974
|
-
await
|
|
4243
|
+
await rename3(tmpPath, absolutePath);
|
|
3975
4244
|
return created;
|
|
3976
4245
|
}
|
|
3977
4246
|
function createdChain(root, firstCreated, targetDirectory) {
|
|
@@ -3980,12 +4249,12 @@ function createdChain(root, firstCreated, targetDirectory) {
|
|
|
3980
4249
|
}
|
|
3981
4250
|
const stop = resolve2(firstCreated);
|
|
3982
4251
|
const made = [];
|
|
3983
|
-
for (let at = resolve2(targetDirectory); ; at =
|
|
4252
|
+
for (let at = resolve2(targetDirectory); ; at = dirname4(at)) {
|
|
3984
4253
|
const asRelative = relative(root, at);
|
|
3985
4254
|
if (asRelative && !asRelative.startsWith("..")) {
|
|
3986
4255
|
made.push(asRelative.split(sep2).join("/"));
|
|
3987
4256
|
}
|
|
3988
|
-
if (at === stop ||
|
|
4257
|
+
if (at === stop || dirname4(at) === at) {
|
|
3989
4258
|
break;
|
|
3990
4259
|
}
|
|
3991
4260
|
}
|
|
@@ -3995,7 +4264,7 @@ async function fileMode(absolutePath) {
|
|
|
3995
4264
|
try {
|
|
3996
4265
|
return (await stat3(absolutePath)).mode & 4095;
|
|
3997
4266
|
} catch (error) {
|
|
3998
|
-
if (
|
|
4267
|
+
if (isRecord11(error) && error.code === "ENOENT") {
|
|
3999
4268
|
return void 0;
|
|
4000
4269
|
}
|
|
4001
4270
|
throw error;
|
|
@@ -4035,7 +4304,7 @@ function basenameOf(path) {
|
|
|
4035
4304
|
const parts = path.split(/[\\/]/).filter(Boolean);
|
|
4036
4305
|
return parts[parts.length - 1] ?? "ainecto-project";
|
|
4037
4306
|
}
|
|
4038
|
-
function
|
|
4307
|
+
function isRecord11(value) {
|
|
4039
4308
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4040
4309
|
}
|
|
4041
4310
|
|
|
@@ -4139,7 +4408,7 @@ async function runAinectoCli(argv, io) {
|
|
|
4139
4408
|
});
|
|
4140
4409
|
}
|
|
4141
4410
|
let routeTools = getGeneratedTools(env);
|
|
4142
|
-
let remote = isAttachmentsUploadCommand(domain, action) || domain === "tools" && (action === "list" || action === "call") || matchGeneratedCommand(routeTools, parsed.positionals) !== void 0;
|
|
4411
|
+
let remote = isAttachmentsUploadCommand(domain, action) || isInboxPollCommand(domain, action) || domain === "tools" && (action === "list" || action === "call") || matchGeneratedCommand(routeTools, parsed.positionals) !== void 0;
|
|
4143
4412
|
if (!remote) {
|
|
4144
4413
|
const live = await loadLiveTools(env, connect(null).client).catch(() => void 0);
|
|
4145
4414
|
if (live && matchGeneratedCommand(live, parsed.positionals)) {
|
|
@@ -4160,6 +4429,9 @@ async function runAinectoCli(argv, io) {
|
|
|
4160
4429
|
io
|
|
4161
4430
|
});
|
|
4162
4431
|
}
|
|
4432
|
+
if (isInboxPollCommand(domain, action)) {
|
|
4433
|
+
return await executeInboxPollCommand({ domain, action, argv: rest, client, json: parsed.json, io });
|
|
4434
|
+
}
|
|
4163
4435
|
const generatedResult = await executeGeneratedCommand({
|
|
4164
4436
|
tools: routeTools,
|
|
4165
4437
|
argv: parsed.positionals,
|
|
@@ -4324,6 +4596,11 @@ function helpText() {
|
|
|
4324
4596
|
" ainecto tools list [--env prod|dev] [--endpoint URL] [--json]",
|
|
4325
4597
|
" ainecto tools call <mcpName> [-f payload.json|@-] [inline-json] [--json]",
|
|
4326
4598
|
" ainecto attachments upload --document-uuid <uuid> <file...> [--json]",
|
|
4599
|
+
" ainecto notifications poll --cursor-file <path> [--kinds A,B] [--workspace <uuid>]... [--project <uuid>]... [--direct-only] [--limit N] [--json]",
|
|
4600
|
+
" ainecto notifications ack --cursor-file <path> (after the agent handled the polled batch)",
|
|
4601
|
+
" ainecto agent-todos poll [--workspace <uuid>]... [--project <uuid>]... [--only-new --seen-file <path>] [--json]",
|
|
4602
|
+
" --workspace and --project may repeat: any of the given workspaces AND any of the given projects",
|
|
4603
|
+
" poll exit codes: 0 new items \xB7 3 nothing new \xB7 1 error \xB7 2 usage error",
|
|
4327
4604
|
" ainecto <generated-command> [flags] [-f payload.json] [--yes] [--json]",
|
|
4328
4605
|
" ainecto mcp [--env prod|dev] [--endpoint URL] [--role design|development|test|validation]",
|
|
4329
4606
|
"",
|