@ainecto/mcp 0.5.0 → 0.6.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 +26 -70
- package/dist/bin/ainecto.js +72 -300
- package/dist/bin/ainecto.js.map +1 -1
- package/dist/bin/mcp.js +10 -45
- package/dist/bin/mcp.js.map +1 -1
- package/package.json +2 -4
package/dist/bin/ainecto.js
CHANGED
|
@@ -8,20 +8,17 @@ import { dirname, join } from "path";
|
|
|
8
8
|
|
|
9
9
|
// src/core/harness/role.ts
|
|
10
10
|
var HARNESS_ROLES = ["design", "development", "test", "validation"];
|
|
11
|
-
var ROLE_SCOPE_PREFIX = "
|
|
12
|
-
var ROLE_HEADER = "X-
|
|
11
|
+
var ROLE_SCOPE_PREFIX = "ainecto:role:";
|
|
12
|
+
var ROLE_HEADER = "X-AiNecto-Role";
|
|
13
13
|
var ROLE_ENV_VAR = "AINECTO_ROLE";
|
|
14
|
-
var LEGACY_ROLE_ENV_VAR = "AI_ERD_ROLE";
|
|
15
14
|
function resolveRole(input = {}) {
|
|
16
15
|
if (input.role !== void 0) {
|
|
17
16
|
return { role: assertRole(input.role), source: "flag" };
|
|
18
17
|
}
|
|
19
18
|
const envVars = input.envVars ?? process.env;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return { role: assertRole(fromEnv), source: "env", envVar };
|
|
24
|
-
}
|
|
19
|
+
const fromEnv = envVars[ROLE_ENV_VAR];
|
|
20
|
+
if (fromEnv && fromEnv.trim()) {
|
|
21
|
+
return { role: assertRole(fromEnv), source: "env" };
|
|
25
22
|
}
|
|
26
23
|
return { source: "none" };
|
|
27
24
|
}
|
|
@@ -124,19 +121,8 @@ import { URLSearchParams } from "url";
|
|
|
124
121
|
// src/core/config/endpoints.ts
|
|
125
122
|
var DEFAULT_ENDPOINTS = {
|
|
126
123
|
prod: "https://ainecto.com/mcp",
|
|
127
|
-
dev: "https://dev.
|
|
128
|
-
};
|
|
129
|
-
var LEGACY_PROD_ENDPOINT = "https://ai-erd.com/mcp";
|
|
130
|
-
var LEGACY_DEFAULT_ENDPOINTS = [
|
|
131
|
-
LEGACY_PROD_ENDPOINT,
|
|
132
|
-
"https://dev.ainecto.com/mcp"
|
|
133
|
-
];
|
|
134
|
-
var TOKEN_SLOT_FALLBACKS = {
|
|
135
|
-
[DEFAULT_ENDPOINTS.prod]: [LEGACY_PROD_ENDPOINT]
|
|
124
|
+
dev: "https://dev.ainecto.com/mcp"
|
|
136
125
|
};
|
|
137
|
-
function fallbackTokenEndpointsFor(endpoint) {
|
|
138
|
-
return TOKEN_SLOT_FALLBACKS[normalizeEndpoint(endpoint)] ?? [];
|
|
139
|
-
}
|
|
140
126
|
function resolveEndpoint(input = {}) {
|
|
141
127
|
const envVars = input.envVars ?? process.env;
|
|
142
128
|
const env = input.env ?? "prod";
|
|
@@ -159,7 +145,7 @@ function isDefaultEndpointFor(env, endpoint) {
|
|
|
159
145
|
}
|
|
160
146
|
function isDefaultEndpoint(endpoint) {
|
|
161
147
|
const normalized = normalizeEndpoint(endpoint);
|
|
162
|
-
return Object.values(DEFAULT_ENDPOINTS).includes(normalized)
|
|
148
|
+
return Object.values(DEFAULT_ENDPOINTS).includes(normalized);
|
|
163
149
|
}
|
|
164
150
|
function assertTrustedEndpointUrl(value, label = "URL") {
|
|
165
151
|
const url = typeof value === "string" ? new URL(value) : value;
|
|
@@ -249,7 +235,7 @@ var OAuthClient = class {
|
|
|
249
235
|
assertEnvTokenEndpointAllowed(this.options.endpoint, this.envVars);
|
|
250
236
|
return envToken;
|
|
251
237
|
}
|
|
252
|
-
const stored = await this.
|
|
238
|
+
const stored = await this.options.tokenStore.load(this.options.endpoint);
|
|
253
239
|
if (!stored) {
|
|
254
240
|
return void 0;
|
|
255
241
|
}
|
|
@@ -265,7 +251,7 @@ var OAuthClient = class {
|
|
|
265
251
|
return this.refreshStoredToken({ ...stored, refreshToken: stored.refreshToken });
|
|
266
252
|
}
|
|
267
253
|
async refreshAfterUnauthorized() {
|
|
268
|
-
const stored = await this.
|
|
254
|
+
const stored = await this.options.tokenStore.load(this.options.endpoint);
|
|
269
255
|
if (this.options.readOnly || !stored?.refreshToken) {
|
|
270
256
|
return void 0;
|
|
271
257
|
}
|
|
@@ -310,29 +296,8 @@ var OAuthClient = class {
|
|
|
310
296
|
await loopback.close();
|
|
311
297
|
}
|
|
312
298
|
}
|
|
313
|
-
/**
|
|
314
|
-
* ★대체로 읽는 옛 칸도 함께 지운다. 새 칸만 지우면 다음 읽기가 곧바로 옛 칸으로 대체돼
|
|
315
|
-
* «로그아웃했는데 여전히 로그인됨»이 된다. 로그인은 기계당 한 번이므로 옛 CLI 의 칸도 같이 끝난다.
|
|
316
|
-
*/
|
|
317
299
|
async logout() {
|
|
318
300
|
await this.options.tokenStore.delete(this.options.endpoint);
|
|
319
|
-
for (const fallback of fallbackTokenEndpointsFor(this.options.endpoint)) {
|
|
320
|
-
await this.options.tokenStore.delete(fallback);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
/** 이 주소의 칸, 비었으면 옛 기본 주소의 칸({@link fallbackTokenEndpointsFor}). 쓰기는 늘 이 주소의 칸이다. */
|
|
324
|
-
async loadStored() {
|
|
325
|
-
const own = await this.options.tokenStore.load(this.options.endpoint);
|
|
326
|
-
if (own) {
|
|
327
|
-
return own;
|
|
328
|
-
}
|
|
329
|
-
for (const fallback of fallbackTokenEndpointsFor(this.options.endpoint)) {
|
|
330
|
-
const stored = await this.options.tokenStore.load(fallback);
|
|
331
|
-
if (stored) {
|
|
332
|
-
return stored;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return void 0;
|
|
336
301
|
}
|
|
337
302
|
/** 부르는 쪽이 refresh token 이 있음을 이미 확인했다 — 타입이 그것을 요구한다. */
|
|
338
303
|
async refreshStoredToken(stored) {
|
|
@@ -650,9 +615,8 @@ async function readAllStdin(stdin) {
|
|
|
650
615
|
}
|
|
651
616
|
|
|
652
617
|
// src/core/version.ts
|
|
653
|
-
var CLI_VERSION = true ? "0.
|
|
618
|
+
var CLI_VERSION = true ? "0.6.0" : "dev";
|
|
654
619
|
var PACKAGE_NAME = "@ainecto/mcp";
|
|
655
|
-
var LEGACY_PACKAGE_NAME = "@ai-erd/mcp";
|
|
656
620
|
var CLI_USER_AGENT = `${PACKAGE_NAME} ${CLI_VERSION}`;
|
|
657
621
|
|
|
658
622
|
// src/core/mcp/rpcClient.ts
|
|
@@ -852,16 +816,18 @@ function redactSecretString(value) {
|
|
|
852
816
|
|
|
853
817
|
// src/core/catalog/generated.prod.ts
|
|
854
818
|
var generatedTools = [
|
|
855
|
-
{ "mcpName": "
|
|
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 mention notification email. Defaults to en.", "enum": ["en", "ko"], "type": "string" } }, "required": ["documentUuid", "items"], "type": "object" }, "required": ["documentUuid", "items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "a673b909d16835ef" },
|
|
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" },
|
|
856
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" },
|
|
857
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" },
|
|
858
823
|
{ "mcpName": "create_workspaces", "commandPath": ["workspaces", "create"], "group": "workspace", "description": "", "inputSchema": { "properties": { "items": { "description": "Workspaces", "items": { "properties": { "description": { "description": "Description", "type": "string" }, "name": { "description": "Workspace name", "type": "string" } }, "required": ["name"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "d9d1b0d561828b8e" },
|
|
859
824
|
{ "mcpName": "delete_attachments", "commandPath": ["attachments", "delete"], "group": "attachment", "description": "", "inputSchema": { "properties": { "uuids": { "description": "Attachment UUIDs", "items": { "type": "string" }, "type": "array" } }, "required": ["uuids"], "type": "object" }, "required": ["uuids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "b22c24bffdfe3d7d" },
|
|
825
|
+
{ "mcpName": "delete_comments", "commandPath": ["comments", "delete"], "group": "generic", "description": "Delete your own comments on a document. Only the author can delete. A resolved question and a top-level comment that still has replies cannot be deleted. Each id is applied on its own; results report each id.", "inputSchema": { "additionalProperties": false, "properties": { "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" }, "ids": { "description": "Comment ids to delete (from mcp__ainecto__list_comments)", "items": { "minimum": 1, "type": "integer" }, "minItems": 1, "type": "array" } }, "required": ["documentUuid", "ids"], "type": "object" }, "required": ["documentUuid", "ids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "17b9658b5a47f866" },
|
|
860
826
|
{ "mcpName": "delete_documents", "commandPath": ["documents", "delete"], "group": "document", "description": "", "inputSchema": { "properties": { "uuids": { "description": "Document UUIDs", "items": { "type": "string" }, "type": "array" } }, "required": ["uuids"], "type": "object" }, "required": ["uuids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "3a725ae70956c270" },
|
|
861
827
|
{ "mcpName": "delete_folders", "commandPath": ["folders", "delete"], "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": "2254cde89c9e8f06" },
|
|
862
828
|
{ "mcpName": "delete_projects", "commandPath": ["projects", "delete"], "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": "6521c33a28cb5465" },
|
|
863
829
|
{ "mcpName": "delete_workspaces", "commandPath": ["workspaces", "delete"], "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": "3177868221137066" },
|
|
864
|
-
{ "mcpName": "diagram_apply_changes", "commandPath": ["tools", "run", "diagram-apply-changes"], "group": "generic", "description": "Required single-call mutation path for diagram node/edge/group create/update/delete changes. Put nodes, edges, and groups in one request and call this once. Do not look for type-specific diagram CUD tools; this tool is the only diagram CUD entry point.", "inputSchema": { "properties": { "description": { "description": "Reason for batch (audit)", "type": "string" }, "diagramUuid": { "description": "Diagram UUID", "type": "string" }, "edges": { "description": "Edge operations", "items": { "properties": { "action": { "description": "Operation kind", "enum": ["create", "update", "delete"], "type": "string" }, "bridgeType": { "description": "
|
|
830
|
+
{ "mcpName": "diagram_apply_changes", "commandPath": ["tools", "run", "diagram-apply-changes"], "group": "generic", "description": "Required single-call mutation path for diagram node/edge/group create/update/delete changes. Put nodes, edges, and groups in one request and call this once. Do not look for type-specific diagram CUD tools; this tool is the only diagram CUD entry point.", "inputSchema": { "properties": { "description": { "description": "Reason for batch (audit)", "type": "string" }, "diagramUuid": { "description": "Diagram UUID", "type": "string" }, "edges": { "description": "Edge operations", "items": { "properties": { "action": { "description": "Operation kind", "enum": ["create", "update", "delete"], "type": "string" }, "bridgeType": { "description": "Omit (null) for a plain node-to-node edge. Set only when a group is an endpoint: GROUP_TO_GROUP|NODE_TO_GROUP|GROUP_TO_NODE", "enum": ["GROUP_TO_GROUP", "NODE_TO_GROUP", "GROUP_TO_NODE"], "type": "string" }, "fromUuid": { "description": "Source", "type": "string" }, "label": { "description": "Edge label", "type": "string" }, "lineStyle": { "description": "Line style", "type": "string" }, "strokeColor": { "description": "Stroke color", "type": "string" }, "strokeWidth": { "description": "Stroke width", "type": "integer" }, "toUuid": { "description": "Target", "type": "string" }, "uuid": { "description": "Required for update/delete", "type": "string" } }, "required": ["action"], "type": "object" }, "type": "array" }, "groups": { "description": "Group operations", "items": { "properties": { "action": { "description": "Operation kind", "enum": ["create", "update", "delete"], "type": "string" }, "collapsed": { "description": "Collapsed state", "type": "boolean" }, "color": { "description": "Group color", "type": "string" }, "height": { "description": "Explicit height; omit to keep it derived from member nodes", "type": "number" }, "linkMode": { "description": "Link mode", "type": "string" }, "linkedDiagramUuid": { "description": "Linked diagram UUID", "type": "string" }, "name": { "description": "Group name", "type": "string" }, "parentGroupUuid": { "description": "Parent group UUID", "type": "string" }, "sortOrder": { "description": "Sort order", "type": "integer" }, "uuid": { "description": "Required for update/delete", "type": "string" }, "width": { "description": "Explicit width; omit to keep it derived from member nodes", "type": "number" } }, "required": ["action"], "type": "object" }, "type": "array" }, "nodes": { "description": "Node operations", "items": { "properties": { "action": { "description": "Operation kind", "enum": ["create", "update", "delete"], "type": "string" }, "fillColor": { "description": "Fill color", "type": "string" }, "groupUuid": { "description": "Group UUID; empty string clears membership", "type": "string" }, "height": { "description": "Height", "type": "number" }, "shape": { "description": "Node shape (start/end/diamond/cylinder/parallelogram/stadium/hexagon/rect/roundRect/...)", "enum": ["rect", "roundRect", "stadium", "diamond", "decision", "circle", "start", "doubleCircle", "end", "hexagon", "cylinder", "parallelogram"], "type": "string" }, "strokeColor": { "description": "Stroke color", "type": "string" }, "text": { "description": "Node text/label. Supports newlines (\\n) for multi-line display.", "maxLength": 4e3, "type": "string" }, "textColor": { "description": "Text color", "type": "string" }, "type": { "description": "Node type", "type": "string" }, "uuid": { "description": "Required for update/delete; optional for create", "type": "string" }, "width": { "description": "Width", "type": "number" }, "x": { "description": "X", "type": "number" }, "y": { "description": "Y", "type": "number" } }, "required": ["action"], "type": "object" }, "type": "array" } }, "required": ["diagramUuid", "description"], "type": "object" }, "required": ["description", "diagramUuid"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "2c829103f86f4168" },
|
|
865
831
|
{ "mcpName": "diagram_get_edge", "commandPath": ["tools", "run", "diagram-get-edge"], "group": "generic", "description": "", "inputSchema": { "properties": { "edgeUuid": { "description": "Edge UUID", "type": "string" } }, "required": ["edgeUuid"], "type": "object" }, "required": ["edgeUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "2c03c4f7daa69898" },
|
|
866
832
|
{ "mcpName": "diagram_get_group", "commandPath": ["tools", "run", "diagram-get-group"], "group": "generic", "description": "", "inputSchema": { "properties": { "groupUuid": { "description": "Group UUID", "type": "string" } }, "required": ["groupUuid"], "type": "object" }, "required": ["groupUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "55c5aa27b8cf489d" },
|
|
867
833
|
{ "mcpName": "diagram_get_node", "commandPath": ["tools", "run", "diagram-get-node"], "group": "generic", "description": "", "inputSchema": { "properties": { "nodeUuid": { "description": "Node UUID", "type": "string" } }, "required": ["nodeUuid"], "type": "object" }, "required": ["nodeUuid"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "646d553238328a9e" },
|
|
@@ -884,14 +850,16 @@ var generatedTools = [
|
|
|
884
850
|
{ "mcpName": "erd_list_table_groups", "commandPath": ["erd", "list-table-groups"], "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": "775bff53bbc21c9e" },
|
|
885
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" },
|
|
886
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" },
|
|
887
|
-
{ "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); 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": "
|
|
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" },
|
|
888
854
|
{ "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" },
|
|
889
855
|
{ "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" },
|
|
890
856
|
{ "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" },
|
|
891
857
|
{ "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" },
|
|
892
858
|
{ "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" },
|
|
893
|
-
{ "mcpName": "
|
|
859
|
+
{ "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
|
+
{ "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" },
|
|
894
861
|
{ "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" },
|
|
862
|
+
{ "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" },
|
|
895
863
|
{ "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" },
|
|
896
864
|
{ "mcpName": "list_trash", "commandPath": ["trash", "list"], "group": "generic", "description": "", "inputSchema": { "properties": {}, "type": "object" }, "required": [], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "329250aecc06a298" },
|
|
897
865
|
{ "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" },
|
|
@@ -901,14 +869,16 @@ var generatedTools = [
|
|
|
901
869
|
{ "mcpName": "move_documents", "commandPath": ["documents", "move"], "group": "document", "description": "", "inputSchema": { "properties": { "clientMutationId": { "description": "Optional mutation identifier for client retry tracing", "maxLength": 128, "minLength": 1, "pattern": "^[\\x21-\\x7E]{1,128}$", "type": "string" }, "items": { "description": "Moves", "items": { "properties": { "newFolderUuid": { "description": "New folder UUID \u2014 null/empty for root", "type": "string" }, "targetProjectUuid": { "description": "Target project UUID \u2014 omit to stay in current project", "type": "string" }, "targetWorkspaceUuid": { "description": "Guard only: must match targetProjectUuid workspace", "type": "string" }, "uuid": { "description": "Document UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "45899053743a0c1e" },
|
|
902
870
|
{ "mcpName": "move_folders", "commandPath": ["folders", "move"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Moves", "items": { "properties": { "newParentFolderUuid": { "description": "New parent UUID \u2014 null/empty for root", "type": "string" }, "uuid": { "description": "Folder UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "eff4458d2f35587a" },
|
|
903
871
|
{ "mcpName": "move_projects", "commandPath": ["projects", "move"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Moves", "items": { "properties": { "targetWorkspaceUuid": { "description": "Destination workspace UUID (you need write access there)", "type": "string" }, "uuid": { "description": "Project UUID", "type": "string" } }, "required": ["uuid", "targetWorkspaceUuid"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "abe0196da3c48ad5" },
|
|
904
|
-
{ "mcpName": "request_upload_token", "commandPath": ["tools", "run", "request-upload-token"], "group": "attachment", "description": "Use this for large payloads of tens of KB or more to save LLM tokens. purpose=mcp.call returns a short-lived bearer token that can call any MCP tool, including erd_apply_changes, via curl. purpose=document.create/update/append uploads document bodies directly to the upload endpoint with PUT/curl. Tokens are reusable for 5 minutes by default.", "inputSchema": { "properties": { "maxBytes": { "description": "\uCD5C\uB300 \uC5C5\uB85C\uB4DC byte (\uC11C\uBC84 \uCE21 \uD55C\uB3C4)", "type": "integer" }, "purpose": { "description": "Token \uC6A9\uB3C4. `mcp.call` \uC740 curl \uB85C /mcp \uD638\uCD9C, `document.create/update/append` \uB294 PUT body \uB85C \uBCF8\uBB38 \uC5C5\uB85C\uB4DC, `attachment.upload` \uB294 \uD30C\uC77C bytes \uC5C5\uB85C\uB4DC. \uCF58\uD150\uCE20\uAC00 \uD06C\uBA74 (\uC218\uC2ED KB \uC774\uC0C1) LLM \uD1A0\uD070 \uC808\uC57D\uC744 \uC704\uD574 \uC774 \uB3C4\uAD6C\uB85C 5\uBD84 \uC7AC\uC0AC\uC6A9 \uD1A0\uD070\uC744 \uBC1B\uACE0 curl \uB85C \uBCF4\uB0B4\uB294 \uAC83\uC744 \uAC15\uB825 \uAD8C\uC7A5.", "enum": ["mcp.call", "document.create", "document.update", "document.append", "attachment.upload"], "type": "string" }, "scopeJson": { "description": "\uC120\uD0DD \u2014 JSON scope. document.create \uB294 projectUuid, type, title \uC744 \uD3EC\uD568\uD558\uACE0 creatable type values \uB294 erd, markdown, diagram, openapi, html. document.update/document.append \uB294 documentUuid \uB97C \uD3EC\uD568. attachment.upload
|
|
872
|
+
{ "mcpName": "request_upload_token", "commandPath": ["tools", "run", "request-upload-token"], "group": "attachment", "description": "Use this for large payloads of tens of KB or more to save LLM tokens. purpose=mcp.call returns a short-lived bearer token that can call any MCP tool, including erd_apply_changes, via curl. purpose=document.create/update/append uploads document bodies directly to the upload endpoint with PUT/curl. Tokens are reusable for 5 minutes by default.", "inputSchema": { "properties": { "maxBytes": { "description": "\uCD5C\uB300 \uC5C5\uB85C\uB4DC byte (\uC11C\uBC84 \uCE21 \uD55C\uB3C4)", "type": "integer" }, "purpose": { "description": "Token \uC6A9\uB3C4. `mcp.call` \uC740 curl \uB85C /mcp \uD638\uCD9C, `document.create/update/append` \uB294 PUT body \uB85C \uBCF8\uBB38 \uC5C5\uB85C\uB4DC, `attachment.upload` \uB294 \uD30C\uC77C bytes \uC5C5\uB85C\uB4DC. \uCF58\uD150\uCE20\uAC00 \uD06C\uBA74 (\uC218\uC2ED KB \uC774\uC0C1) LLM \uD1A0\uD070 \uC808\uC57D\uC744 \uC704\uD574 \uC774 \uB3C4\uAD6C\uB85C 5\uBD84 \uC7AC\uC0AC\uC6A9 \uD1A0\uD070\uC744 \uBC1B\uACE0 curl \uB85C \uBCF4\uB0B4\uB294 \uAC83\uC744 \uAC15\uB825 \uAD8C\uC7A5.", "enum": ["mcp.call", "document.create", "document.update", "document.append", "attachment.upload"], "type": "string" }, "scopeJson": { "description": "\uC120\uD0DD \u2014 JSON scope. document.create \uB294 projectUuid, type, title \uC744 \uD3EC\uD568\uD558\uACE0 creatable type values \uB294 erd, markdown, diagram, openapi, html, file. document.update/document.append \uB294 documentUuid \uB97C \uD3EC\uD568. type=file \uC740 filename \uB3C4 \uD3EC\uD568(\uD655\uC7A5\uC790\uB85C \uD615\uC2DD \uD310\uC815) \u2014 PUT \uC758 Content-Type \uC740 \uD30C\uC77C MIME, \uBCF8\uBB38\uC740 \uD30C\uC77C \uBC14\uC774\uD2B8. attachment.upload: {documentUuid, filename}; storageKey \uB294 \uC11C\uBC84\uAC00 \uBC1C\uAE09 scope \uC5D0 \uB123\uB294\uB2E4.", "type": "string" }, "ttlSeconds": { "description": "TTL (\uCD08). \uAE30\uBCF8 300 (5\uBD84)", "type": "integer" } }, "required": ["purpose"], "type": "object" }, "required": ["purpose"], "payloadMode": "binary-upload", "destructive": false, "sourceCatalog": "prod", "schemaHash": "fe1984b3979abf86" },
|
|
873
|
+
{ "mcpName": "resolve_comments", "commandPath": ["tools", "run", "resolve-comments"], "group": "generic", "description": "Mark questions on a document as resolved. Only top-level comments with kind QUESTION can be resolved, and it needs edit access to the document (readers can comment but cannot resolve). Resolving cannot be undone. Each id is applied on its own; results report each id.", "inputSchema": { "additionalProperties": false, "properties": { "documentUuid": { "description": "Document UUID the comments belong to", "type": "string" }, "ids": { "description": "Question ids to resolve (top-level comments with kind QUESTION)", "items": { "minimum": 1, "type": "integer" }, "minItems": 1, "type": "array" } }, "required": ["documentUuid", "ids"], "type": "object" }, "required": ["documentUuid", "ids"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "7b32b72b3a0d64ba" },
|
|
905
874
|
{ "mcpName": "restore_versions", "commandPath": ["versions", "restore"], "group": "generic", "description": "", "inputSchema": { "properties": { "items": { "description": "Restores", "items": { "properties": { "documentUuid": { "description": "Document UUID", "type": "string" }, "versionNumber": { "description": "Version number to restore", "type": "integer" } }, "required": ["documentUuid", "versionNumber"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "005b5b08a19fc605" },
|
|
906
|
-
{ "mcpName": "search_documents", "commandPath": ["documents", "search"], "group": "document", "description": "", "inputSchema": { "properties": { "limit": { "description": "\uACB0\uACFC \uAC1C\uC218 (\uAE30\uBCF8 20, \uCD5C\uB300 50)", "type": "integer" }, "offset": { "description": "\uD398\uC774\uC9C0\uB124\uC774\uC158 offset (\uAE30\uBCF8 0)", "type": "integer" }, "projectUuid": { "description": "\uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8\uB85C \uD55C\uC815 (\uC120\uD0DD)", "type": "string" }, "q": { "description": "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC", "type": "string" }, "type": { "description": "Optional document type filter. Readable values: erd, markdown, diagram, openapi, html.", "enum": ["erd", "markdown", "diagram", "openapi", "html"], "type": "string" } }, "required": ["q"], "type": "object" }, "required": ["q"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "
|
|
875
|
+
{ "mcpName": "search_documents", "commandPath": ["documents", "search"], "group": "document", "description": "", "inputSchema": { "properties": { "limit": { "description": "\uACB0\uACFC \uAC1C\uC218 (\uAE30\uBCF8 20, \uCD5C\uB300 50)", "type": "integer" }, "offset": { "description": "\uD398\uC774\uC9C0\uB124\uC774\uC158 offset (\uAE30\uBCF8 0)", "type": "integer" }, "projectUuid": { "description": "\uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8\uB85C \uD55C\uC815 (\uC120\uD0DD)", "type": "string" }, "q": { "description": "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC", "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" } }, "required": ["q"], "type": "object" }, "required": ["q"], "payloadMode": "flags", "destructive": false, "sourceCatalog": "prod", "schemaHash": "e82abba1358754e8" },
|
|
907
876
|
{ "mcpName": "unarchive_documents", "commandPath": ["documents", "unarchive"], "group": "document", "description": "", "inputSchema": { "properties": { "uuids": { "description": "Document UUIDs", "items": { "type": "string" }, "type": "array" } }, "required": ["uuids"], "type": "object" }, "required": ["uuids"], "payloadMode": "file-json", "destructive": true, "sourceCatalog": "prod", "schemaHash": "f2810e71583a320f" },
|
|
908
877
|
{ "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" },
|
|
909
878
|
{ "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" },
|
|
910
879
|
{ "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" },
|
|
911
|
-
{ "mcpName": "
|
|
880
|
+
{ "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 mention notification email. Defaults to en.", "enum": ["en", "ko"], "type": "string" } }, "required": ["documentUuid", "items"], "type": "object" }, "required": ["documentUuid", "items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "fa37fedfdebd8d54" },
|
|
881
|
+
{ "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" },
|
|
912
882
|
{ "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" },
|
|
913
883
|
{ "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" },
|
|
914
884
|
{ "mcpName": "update_workspaces", "commandPath": ["workspaces", "update"], "group": "workspace", "description": "", "inputSchema": { "properties": { "items": { "description": "Updates", "items": { "properties": { "description": { "description": "New description", "type": "string" }, "name": { "description": "New name", "type": "string" }, "uuid": { "description": "Workspace UUID", "type": "string" } }, "required": ["uuid"], "type": "object" }, "type": "array" } }, "required": ["items"], "type": "object" }, "required": ["items"], "payloadMode": "file-json", "destructive": false, "sourceCatalog": "prod", "schemaHash": "553275e6da799c5a" },
|
|
@@ -2018,7 +1988,6 @@ import { dirname as dirname3, join as join3, relative, resolve as resolve2, sep
|
|
|
2018
1988
|
// src/core/harness/agentTargets.ts
|
|
2019
1989
|
import { basename as basename2 } from "path";
|
|
2020
1990
|
var SERVER_NAME = "ainecto";
|
|
2021
|
-
var LEGACY_SERVER_NAME = "ai-erd";
|
|
2022
1991
|
var AGENT_TARGETS = [
|
|
2023
1992
|
{ id: "claude-code", label: "Claude Code", path: ".mcp.json" },
|
|
2024
1993
|
{ id: "cursor", label: "Cursor", path: ".cursor/mcp.json" }
|
|
@@ -2048,43 +2017,30 @@ function readServerEntry(existing) {
|
|
|
2048
2017
|
try {
|
|
2049
2018
|
const parsed = JSON.parse(existing);
|
|
2050
2019
|
const servers = parsed?.mcpServers;
|
|
2051
|
-
return isRecord8(servers) ? servers[
|
|
2020
|
+
return isRecord8(servers) ? servers[SERVER_NAME] : void 0;
|
|
2052
2021
|
} catch {
|
|
2053
2022
|
return void 0;
|
|
2054
2023
|
}
|
|
2055
2024
|
}
|
|
2056
|
-
function ourKeyIn(servers) {
|
|
2057
|
-
if (Object.prototype.hasOwnProperty.call(servers, SERVER_NAME)) {
|
|
2058
|
-
return SERVER_NAME;
|
|
2059
|
-
}
|
|
2060
|
-
return isOurBridge(servers[LEGACY_SERVER_NAME]) ? LEGACY_SERVER_NAME : void 0;
|
|
2061
|
-
}
|
|
2062
|
-
function legacyBridgeIn(servers) {
|
|
2063
|
-
return isOurBridge(servers[LEGACY_SERVER_NAME]);
|
|
2064
|
-
}
|
|
2065
2025
|
function isOurBridge(entry) {
|
|
2066
2026
|
if (!isRecord8(entry)) {
|
|
2067
2027
|
return false;
|
|
2068
2028
|
}
|
|
2069
2029
|
const { command, args } = entry;
|
|
2070
2030
|
const argList = Array.isArray(args) ? args.filter((arg) => typeof arg === "string") : [];
|
|
2071
|
-
const isOurPackage = (arg) =>
|
|
2031
|
+
const isOurPackage = (arg) => arg === PACKAGE_NAME || arg.startsWith(`${PACKAGE_NAME}@`);
|
|
2072
2032
|
if (argList.some((arg) => isOurPackage(arg) || arg === "--role")) {
|
|
2073
2033
|
return true;
|
|
2074
2034
|
}
|
|
2075
2035
|
const bin = typeof command === "string" ? basename2(command) : "";
|
|
2076
2036
|
return OUR_BINS.includes(bin);
|
|
2077
2037
|
}
|
|
2078
|
-
var OUR_BINS = ["ainecto"
|
|
2038
|
+
var OUR_BINS = ["ainecto"];
|
|
2079
2039
|
function mergeServerEntry(existing, entry) {
|
|
2080
2040
|
const root = parseConfigObject(existing);
|
|
2081
2041
|
const servers = readServers(root);
|
|
2082
|
-
const
|
|
2083
|
-
const
|
|
2084
|
-
const replacedEntry = ourKey === void 0 ? void 0 : servers[ourKey];
|
|
2085
|
-
if (legacyBridgeIn(servers)) {
|
|
2086
|
-
delete servers[LEGACY_SERVER_NAME];
|
|
2087
|
-
}
|
|
2042
|
+
const replaced = Object.prototype.hasOwnProperty.call(servers, SERVER_NAME);
|
|
2043
|
+
const replacedEntry = replaced ? servers[SERVER_NAME] : void 0;
|
|
2088
2044
|
servers[SERVER_NAME] = entry;
|
|
2089
2045
|
return { content: stringify({ ...root, mcpServers: servers }), replaced, replacedEntry };
|
|
2090
2046
|
}
|
|
@@ -2094,14 +2050,13 @@ function removeServerEntry(existing, restore) {
|
|
|
2094
2050
|
}
|
|
2095
2051
|
const root = parseConfigObject(existing);
|
|
2096
2052
|
const servers = readServers(root);
|
|
2097
|
-
const
|
|
2098
|
-
const removed = ourKey !== void 0;
|
|
2053
|
+
const removed = Object.prototype.hasOwnProperty.call(servers, SERVER_NAME);
|
|
2099
2054
|
if (restore !== void 0) {
|
|
2100
|
-
servers[
|
|
2055
|
+
servers[SERVER_NAME] = restore.value;
|
|
2101
2056
|
return { content: stringify({ ...root, mcpServers: servers }), removed, emptied: false };
|
|
2102
2057
|
}
|
|
2103
|
-
if (
|
|
2104
|
-
delete servers[
|
|
2058
|
+
if (removed) {
|
|
2059
|
+
delete servers[SERVER_NAME];
|
|
2105
2060
|
}
|
|
2106
2061
|
const otherKeys = Object.keys(root).filter((key) => key !== "mcpServers");
|
|
2107
2062
|
const emptied = Object.keys(servers).length === 0 && otherKeys.length === 0;
|
|
@@ -2167,14 +2122,8 @@ function isRecord8(value) {
|
|
|
2167
2122
|
// src/core/harness/harnessDoc.ts
|
|
2168
2123
|
var MARKER_BEGIN = "<!-- ainecto:begin -->";
|
|
2169
2124
|
var MARKER_END = "<!-- ainecto:end -->";
|
|
2170
|
-
var
|
|
2171
|
-
var LEGACY_MARKER_END = "<!-- ai-erd:end -->";
|
|
2172
|
-
var MARKERS = {
|
|
2173
|
-
begin: [MARKER_BEGIN, LEGACY_MARKER_BEGIN],
|
|
2174
|
-
end: [MARKER_END, LEGACY_MARKER_END]
|
|
2175
|
-
};
|
|
2125
|
+
var MARKERS = { begin: MARKER_BEGIN, end: MARKER_END };
|
|
2176
2126
|
var HARNESS_DIR = ".ainecto";
|
|
2177
|
-
var LEGACY_HARNESS_DIR = ".ai-erd";
|
|
2178
2127
|
var HARNESS_DOC_PATH = `${HARNESS_DIR}/HARNESS.md`;
|
|
2179
2128
|
var HARNESS_CONFIG_PATH = `${HARNESS_DIR}/config.json`;
|
|
2180
2129
|
var HARNESS_RECORD_PATH = `${HARNESS_DIR}/init-record.json`;
|
|
@@ -2201,7 +2150,7 @@ function documentContractProblem(key, body) {
|
|
|
2201
2150
|
}
|
|
2202
2151
|
}
|
|
2203
2152
|
if (key === AGENT_NOTE_KEY) {
|
|
2204
|
-
return managedBlockProblem(key,
|
|
2153
|
+
return managedBlockProblem(key, body);
|
|
2205
2154
|
}
|
|
2206
2155
|
return void 0;
|
|
2207
2156
|
}
|
|
@@ -2264,14 +2213,11 @@ Or run \`ainecto init --role <design|development|test|validation>\` to rewrite t
|
|
|
2264
2213
|
Generated by \`ainecto init\`. Remove everything it wrote with \`ainecto init --undo\`.
|
|
2265
2214
|
`;
|
|
2266
2215
|
function renderAgentNote(template) {
|
|
2267
|
-
return fillTemplate(
|
|
2216
|
+
return fillTemplate(template ?? DEFAULT_AGENT_NOTE, {
|
|
2268
2217
|
harnessDocPath: HARNESS_DOC_PATH,
|
|
2269
2218
|
serverName: SERVER_NAME
|
|
2270
2219
|
});
|
|
2271
2220
|
}
|
|
2272
|
-
function withCurrentMarkers(template) {
|
|
2273
|
-
return template.split(LEGACY_MARKER_BEGIN).join(MARKER_BEGIN).split(LEGACY_MARKER_END).join(MARKER_END);
|
|
2274
|
-
}
|
|
2275
2221
|
var DEFAULT_AGENT_NOTE = `${MARKER_BEGIN}
|
|
2276
2222
|
## AiNecto Harness
|
|
2277
2223
|
|
|
@@ -2360,30 +2306,19 @@ function assertNoDanglingMarker(content) {
|
|
|
2360
2306
|
}
|
|
2361
2307
|
function ownedMarkerCount(content, kind) {
|
|
2362
2308
|
let count = 0;
|
|
2363
|
-
for (let
|
|
2309
|
+
for (let hit2 = ownedMarker(content, kind, 0); hit2 !== void 0; hit2 = ownedMarker(content, kind, hit2.at + 1)) {
|
|
2364
2310
|
count += 1;
|
|
2365
2311
|
}
|
|
2366
2312
|
return count;
|
|
2367
2313
|
}
|
|
2368
2314
|
function ownedMarker(content, kind, from) {
|
|
2369
|
-
|
|
2370
|
-
for (const marker of MARKERS[kind]) {
|
|
2371
|
-
const at = ownedMarkerIndex(content, marker, from);
|
|
2372
|
-
if (at >= 0 && (best === void 0 || at < best.at)) {
|
|
2373
|
-
best = { at, length: marker.length };
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
return best;
|
|
2315
|
+
return hit(ownedMarkerIndex(content, MARKERS[kind], from), MARKERS[kind]);
|
|
2377
2316
|
}
|
|
2378
2317
|
function anyMarker(content, kind, from) {
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
best = { at, length: marker.length };
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
return best;
|
|
2318
|
+
return hit(content.indexOf(MARKERS[kind], from), MARKERS[kind]);
|
|
2319
|
+
}
|
|
2320
|
+
function hit(at, marker) {
|
|
2321
|
+
return at >= 0 ? { at, length: marker.length } : void 0;
|
|
2387
2322
|
}
|
|
2388
2323
|
function isInsideFencedBlock(content, index) {
|
|
2389
2324
|
let open;
|
|
@@ -2514,14 +2449,12 @@ function ownedMarkerIndex(content, marker, from) {
|
|
|
2514
2449
|
|
|
2515
2450
|
// src/core/harness/initRecord.ts
|
|
2516
2451
|
var RECORD_KIND = "ainecto/init-record";
|
|
2517
|
-
var LEGACY_RECORD_KIND = "ai-erd/init-record";
|
|
2518
2452
|
var RECORD_VERSION = 2;
|
|
2519
2453
|
var ABSENT = { at: "absent" };
|
|
2520
2454
|
function emptyRecord() {
|
|
2521
2455
|
return { version: RECORD_VERSION, files: {}, createdDirectories: [] };
|
|
2522
2456
|
}
|
|
2523
|
-
function readRecord(content
|
|
2524
|
-
const HARNESS_RECORD_PATH2 = recordPath;
|
|
2457
|
+
function readRecord(content) {
|
|
2525
2458
|
if (content === void 0) {
|
|
2526
2459
|
return { state: "absent" };
|
|
2527
2460
|
}
|
|
@@ -2529,26 +2462,26 @@ function readRecord(content, recordPath = HARNESS_RECORD_PATH) {
|
|
|
2529
2462
|
try {
|
|
2530
2463
|
parsed = JSON.parse(content);
|
|
2531
2464
|
} catch {
|
|
2532
|
-
return { state: "corrupt", reason: `${
|
|
2465
|
+
return { state: "corrupt", reason: `${HARNESS_RECORD_PATH} is not valid JSON` };
|
|
2533
2466
|
}
|
|
2534
2467
|
if (!isObject(parsed)) {
|
|
2535
|
-
return { state: "corrupt", reason: `${
|
|
2468
|
+
return { state: "corrupt", reason: `${HARNESS_RECORD_PATH} is not a JSON object` };
|
|
2536
2469
|
}
|
|
2537
|
-
if (parsed.kind !== RECORD_KIND
|
|
2470
|
+
if (parsed.kind !== RECORD_KIND) {
|
|
2538
2471
|
return {
|
|
2539
2472
|
state: "corrupt",
|
|
2540
|
-
reason: `${
|
|
2473
|
+
reason: `${HARNESS_RECORD_PATH} exists but is not an AiNecto init record (kind=${JSON.stringify(parsed.kind)})`
|
|
2541
2474
|
};
|
|
2542
2475
|
}
|
|
2543
2476
|
if (parsed.version !== RECORD_VERSION) {
|
|
2544
2477
|
return {
|
|
2545
2478
|
state: "legacy",
|
|
2546
|
-
reason: `${
|
|
2479
|
+
reason: `${HARNESS_RECORD_PATH} was written by another version of this CLI (record version ${JSON.stringify(parsed.version)}, this CLI reads ${RECORD_VERSION})`
|
|
2547
2480
|
};
|
|
2548
2481
|
}
|
|
2549
2482
|
const files = parsed.files;
|
|
2550
2483
|
if (!isObject(files)) {
|
|
2551
|
-
return { state: "corrupt", reason: `${
|
|
2484
|
+
return { state: "corrupt", reason: `${HARNESS_RECORD_PATH} has no "files" object` };
|
|
2552
2485
|
}
|
|
2553
2486
|
const out = {};
|
|
2554
2487
|
for (const [path, raw] of Object.entries(files)) {
|
|
@@ -2556,14 +2489,14 @@ function readRecord(content, recordPath = HARNESS_RECORD_PATH) {
|
|
|
2556
2489
|
if ("problem" in read) {
|
|
2557
2490
|
return {
|
|
2558
2491
|
state: "corrupt",
|
|
2559
|
-
reason: `${
|
|
2492
|
+
reason: `${HARNESS_RECORD_PATH} has an unusable entry for ${path} \u2014 it ${read.problem}`
|
|
2560
2493
|
};
|
|
2561
2494
|
}
|
|
2562
2495
|
out[path] = read.contract;
|
|
2563
2496
|
}
|
|
2564
2497
|
const directories = parsed.createdDirectories;
|
|
2565
2498
|
if (directories !== void 0 && !isStringArray(directories)) {
|
|
2566
|
-
return { state: "corrupt", reason: `${
|
|
2499
|
+
return { state: "corrupt", reason: `${HARNESS_RECORD_PATH} has a malformed createdDirectories` };
|
|
2567
2500
|
}
|
|
2568
2501
|
return {
|
|
2569
2502
|
state: "valid",
|
|
@@ -2574,46 +2507,6 @@ function readRecord(content, recordPath = HARNESS_RECORD_PATH) {
|
|
|
2574
2507
|
}
|
|
2575
2508
|
};
|
|
2576
2509
|
}
|
|
2577
|
-
var LEGACY_MANAGED_KEYS = [
|
|
2578
|
-
"created",
|
|
2579
|
-
"originals",
|
|
2580
|
-
"lastWritten",
|
|
2581
|
-
"lastWrittenFragment",
|
|
2582
|
-
"lastWrittenBody",
|
|
2583
|
-
"replacedEntries",
|
|
2584
|
-
"replacedBlocks",
|
|
2585
|
-
"blockAdded",
|
|
2586
|
-
"foreignMarkers"
|
|
2587
|
-
];
|
|
2588
|
-
function legacyManagedRecord(configContent) {
|
|
2589
|
-
if (configContent === void 0) {
|
|
2590
|
-
return false;
|
|
2591
|
-
}
|
|
2592
|
-
let parsed;
|
|
2593
|
-
try {
|
|
2594
|
-
parsed = JSON.parse(configContent);
|
|
2595
|
-
} catch {
|
|
2596
|
-
return false;
|
|
2597
|
-
}
|
|
2598
|
-
if (!isObject(parsed) || !isObject(parsed.managed)) {
|
|
2599
|
-
return false;
|
|
2600
|
-
}
|
|
2601
|
-
const managed = parsed.managed;
|
|
2602
|
-
const hasLegacyShape = LEGACY_MANAGED_KEYS.some(
|
|
2603
|
-
(key) => Object.prototype.hasOwnProperty.call(managed, key)
|
|
2604
|
-
);
|
|
2605
|
-
if (!hasLegacyShape) {
|
|
2606
|
-
return false;
|
|
2607
|
-
}
|
|
2608
|
-
if (typeof parsed.generatedBy === "string") {
|
|
2609
|
-
return true;
|
|
2610
|
-
}
|
|
2611
|
-
const lastWritten = managed.lastWritten;
|
|
2612
|
-
return isObject(lastWritten) && [HARNESS_CONFIG_PATH, `${LEGACY_HARNESS_DIR}/config.json`].some((path) => Object.prototype.hasOwnProperty.call(lastWritten, path));
|
|
2613
|
-
}
|
|
2614
|
-
function legacyManagedNotice(configPath) {
|
|
2615
|
-
return `${configPath} holds an init record written by an older version of this CLI (a "managed" field). This version keeps its record in ${HARNESS_RECORD_PATH} and cannot read that one, so your saved originals are still in there and nothing was changed. Undo with the version that wrote it (for example: npx -y -p @ai-erd/mcp@0.2 ai-erd init --undo), then run this version again.`;
|
|
2616
|
-
}
|
|
2617
2510
|
function serializeRecord(record) {
|
|
2618
2511
|
return `${JSON.stringify({
|
|
2619
2512
|
kind: RECORD_KIND,
|
|
@@ -2787,29 +2680,17 @@ function readConfigRole(path, content) {
|
|
|
2787
2680
|
const raw = parsed?.mcpServers;
|
|
2788
2681
|
servers = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
|
|
2789
2682
|
} catch {
|
|
2790
|
-
return content.includes(SERVER_NAME)
|
|
2683
|
+
return content.includes(SERVER_NAME) ? { kind: "problem", reason: `${path} is not valid JSON` } : { kind: "absent" };
|
|
2791
2684
|
}
|
|
2792
|
-
const
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
if (!isOurBridge(entry)) {
|
|
2796
|
-
continue;
|
|
2797
|
-
}
|
|
2798
|
-
const role = readRoleFromEntry(entry);
|
|
2799
|
-
if (role === void 0) {
|
|
2800
|
-
return { kind: "problem", reason: `${path} has the "${key}" bridge without a valid --role` };
|
|
2801
|
-
}
|
|
2802
|
-
if (!roles.includes(role)) {
|
|
2803
|
-
roles.push(role);
|
|
2804
|
-
}
|
|
2685
|
+
const entry = servers[SERVER_NAME];
|
|
2686
|
+
if (!isOurBridge(entry)) {
|
|
2687
|
+
return { kind: "absent" };
|
|
2805
2688
|
}
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
reason: `${path} has both the "${SERVER_NAME}" and the "${LEGACY_SERVER_NAME}" bridge with different roles (${roles.join(", ")})`
|
|
2810
|
-
};
|
|
2689
|
+
const role = readRoleFromEntry(entry);
|
|
2690
|
+
if (role === void 0) {
|
|
2691
|
+
return { kind: "problem", reason: `${path} has the "${SERVER_NAME}" bridge without a valid --role` };
|
|
2811
2692
|
}
|
|
2812
|
-
return
|
|
2693
|
+
return { kind: "role", role };
|
|
2813
2694
|
}
|
|
2814
2695
|
function rolesInFiles(files) {
|
|
2815
2696
|
const roles = [];
|
|
@@ -3029,9 +2910,6 @@ function initRefusal(files, previous) {
|
|
|
3029
2910
|
if (state.state === "corrupt" || state.state === "legacy") {
|
|
3030
2911
|
return `${state.reason}. Nothing was changed \u2014 move that file aside (or restore it) and run again.`;
|
|
3031
2912
|
}
|
|
3032
|
-
if (state.state === "absent" && legacyManagedRecord(files.get(HARNESS_CONFIG_PATH))) {
|
|
3033
|
-
return legacyManagedNotice(HARNESS_CONFIG_PATH);
|
|
3034
|
-
}
|
|
3035
2913
|
const carried = state.state === "valid" ? state.record : emptyRecord();
|
|
3036
2914
|
for (const [path, contract] of Object.entries(carried.files)) {
|
|
3037
2915
|
if (contract.scope !== "fields") {
|
|
@@ -3238,10 +3116,10 @@ function planUndo(input) {
|
|
|
3238
3116
|
const notes = [];
|
|
3239
3117
|
const tail = () => {
|
|
3240
3118
|
notes.push(`Codex keeps its own global config \u2014 remove it with: ${codexRemoveCommand()}`);
|
|
3241
|
-
notes.push(`If you set ${ROLE_ENV_VAR}
|
|
3119
|
+
notes.push(`If you set ${ROLE_ENV_VAR} anywhere, unset it too.`);
|
|
3242
3120
|
};
|
|
3243
3121
|
if (state.state === "absent") {
|
|
3244
|
-
notes.push(
|
|
3122
|
+
notes.push(`No record of a previous init in ${HARNESS_RECORD_PATH} \u2014 no local file was changed.`);
|
|
3245
3123
|
tail();
|
|
3246
3124
|
return { writes, deletes, codexCommand: codexRemoveCommand(), notes };
|
|
3247
3125
|
}
|
|
@@ -3502,95 +3380,6 @@ function previousRole(path, existing) {
|
|
|
3502
3380
|
return read.kind === "role" ? read.role : void 0;
|
|
3503
3381
|
}
|
|
3504
3382
|
|
|
3505
|
-
// src/core/harness/legacyLayout.ts
|
|
3506
|
-
var LEGACY_PATHS = new Map(
|
|
3507
|
-
[HARNESS_DOC_PATH, HARNESS_CONFIG_PATH, HARNESS_RECORD_PATH].map((path) => [path, toLegacy(path)])
|
|
3508
|
-
);
|
|
3509
|
-
var LEGACY_RECORD_PATH = toLegacy(HARNESS_RECORD_PATH);
|
|
3510
|
-
var LEGACY_SNAPSHOT_PATHS = [...LEGACY_PATHS.values()];
|
|
3511
|
-
function adoptLegacyLayout(disk) {
|
|
3512
|
-
const files = /* @__PURE__ */ new Map();
|
|
3513
|
-
for (const [path, content] of disk) {
|
|
3514
|
-
if (!LEGACY_SNAPSHOT_PATHS.includes(path)) {
|
|
3515
|
-
files.set(path, content);
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
const view = { files, moves: [], legacyDirCreatedByUs: false, notes: [] };
|
|
3519
|
-
if (!LEGACY_SNAPSHOT_PATHS.some((path) => disk.get(path) !== void 0)) {
|
|
3520
|
-
return view;
|
|
3521
|
-
}
|
|
3522
|
-
const legacyRecord = disk.get(LEGACY_RECORD_PATH);
|
|
3523
|
-
if (legacyRecord === void 0) {
|
|
3524
|
-
const legacyConfig = LEGACY_PATHS.get(HARNESS_CONFIG_PATH);
|
|
3525
|
-
if (disk.get(HARNESS_RECORD_PATH) === void 0 && legacyManagedRecord(disk.get(legacyConfig))) {
|
|
3526
|
-
return { ...view, refusal: legacyManagedNotice(legacyConfig) };
|
|
3527
|
-
}
|
|
3528
|
-
view.notes.push(
|
|
3529
|
-
`${LEGACY_HARNESS_DIR}/ was left in place \u2014 there is no ${LEGACY_RECORD_PATH} showing that an earlier version of this CLI wrote it. Remove it by hand if it is a leftover.`
|
|
3530
|
-
);
|
|
3531
|
-
return view;
|
|
3532
|
-
}
|
|
3533
|
-
const state = readRecord(legacyRecord, LEGACY_RECORD_PATH);
|
|
3534
|
-
if (state.state !== "valid") {
|
|
3535
|
-
return {
|
|
3536
|
-
...view,
|
|
3537
|
-
refusal: state.state === "absent" ? `${LEGACY_RECORD_PATH} could not be read. Nothing was changed.` : `${state.reason}. Nothing was changed \u2014 move that file aside (or restore it) and run again.`
|
|
3538
|
-
};
|
|
3539
|
-
}
|
|
3540
|
-
const clash = [...LEGACY_PATHS].filter(([to, from]) => disk.get(to) !== void 0 && disk.get(from) !== void 0).map(([to]) => to);
|
|
3541
|
-
if (clash.length > 0) {
|
|
3542
|
-
return {
|
|
3543
|
-
...view,
|
|
3544
|
-
refusal: `Both ${LEGACY_HARNESS_DIR}/ and ${HARNESS_DIR}/ hold AiNecto setup files (${clash.join(", ")}): an older version of this CLI (0.4.x) ran here after this one, or a move was interrupted. Nothing was changed. Undo the older setup with \`npx -y -p @ai-erd/mcp@0.4.6 ai-erd init --undo\` (or remove the ${LEGACY_HARNESS_DIR}/ leftovers by hand), then run again.`
|
|
3545
|
-
};
|
|
3546
|
-
}
|
|
3547
|
-
const record = state.record;
|
|
3548
|
-
const renamed = {
|
|
3549
|
-
...record,
|
|
3550
|
-
files: Object.fromEntries(Object.entries(record.files).map(([path, contract]) => [toCurrent(path), contract])),
|
|
3551
|
-
// «하네스 폴더를 우리가 만들었다»는 같은 사실이다 — 이름만 옮긴다. 새 폴더를 이번에 만들면 적용이 또 적는다.
|
|
3552
|
-
createdDirectories: record.createdDirectories.map(toCurrent)
|
|
3553
|
-
};
|
|
3554
|
-
const moves = [];
|
|
3555
|
-
for (const [to, from] of LEGACY_PATHS) {
|
|
3556
|
-
const content = disk.get(from);
|
|
3557
|
-
if (content === void 0) {
|
|
3558
|
-
continue;
|
|
3559
|
-
}
|
|
3560
|
-
files.set(to, to === HARNESS_RECORD_PATH ? serializeRecord(renamed) : content);
|
|
3561
|
-
moves.push({ from, to });
|
|
3562
|
-
}
|
|
3563
|
-
return {
|
|
3564
|
-
files,
|
|
3565
|
-
moves,
|
|
3566
|
-
legacyDirCreatedByUs: record.createdDirectories.includes(LEGACY_HARNESS_DIR),
|
|
3567
|
-
notes: [`${LEGACY_HARNESS_DIR}/ \u2192 ${HARNESS_DIR}/: moved what an earlier version of this CLI wrote (the folder was renamed).`]
|
|
3568
|
-
};
|
|
3569
|
-
}
|
|
3570
|
-
function withLegacyMoves(plan, view) {
|
|
3571
|
-
if (view.moves.length === 0) {
|
|
3572
|
-
return view.notes.length === 0 ? plan : { ...plan, notes: [...view.notes, ...plan.notes] };
|
|
3573
|
-
}
|
|
3574
|
-
const movedTo = new Set(view.moves.map((move) => move.to));
|
|
3575
|
-
const planned = /* @__PURE__ */ new Set([...plan.writes.map((write) => write.path), ...plan.deletes]);
|
|
3576
|
-
const carried = view.moves.filter((move) => !planned.has(move.to)).map((move) => ({ path: move.to, content: view.files.get(move.to), existed: false }));
|
|
3577
|
-
return {
|
|
3578
|
-
...plan,
|
|
3579
|
-
// 새 경로는 디스크에 아직 없다 — «만든다»가 사실이다.
|
|
3580
|
-
writes: [...plan.writes.map((write) => movedTo.has(write.path) ? { ...write, existed: false } : write), ...carried],
|
|
3581
|
-
// 새 경로의 삭제는 디스크에 없는 파일이다 — 대신 옛 파일을 지운다.
|
|
3582
|
-
deletes: [...plan.deletes.filter((path) => !movedTo.has(path)), ...view.moves.map((move) => move.from)],
|
|
3583
|
-
notes: [...view.notes, ...plan.notes],
|
|
3584
|
-
removableDirectories: view.legacyDirCreatedByUs ? [...plan.removableDirectories ?? [], LEGACY_HARNESS_DIR] : plan.removableDirectories
|
|
3585
|
-
};
|
|
3586
|
-
}
|
|
3587
|
-
function toLegacy(path) {
|
|
3588
|
-
return `${LEGACY_HARNESS_DIR}${path.slice(HARNESS_DIR.length)}`;
|
|
3589
|
-
}
|
|
3590
|
-
function toCurrent(path) {
|
|
3591
|
-
return path === LEGACY_HARNESS_DIR || path.startsWith(`${LEGACY_HARNESS_DIR}/`) ? `${HARNESS_DIR}${path.slice(LEGACY_HARNESS_DIR.length)}` : path;
|
|
3592
|
-
}
|
|
3593
|
-
|
|
3594
3383
|
// src/core/harness/documentFetch.ts
|
|
3595
3384
|
var DOC_KEY2 = "HARNESS.DOC";
|
|
3596
3385
|
var AGENT_NOTE_KEY2 = "HARNESS.AGENT_NOTE";
|
|
@@ -3735,19 +3524,10 @@ async function runInit(initialOptions) {
|
|
|
3735
3524
|
const args = parseInitArgs(options.argv);
|
|
3736
3525
|
const root = resolve2(options.cwd);
|
|
3737
3526
|
const rootNotes = await repositoryRootNotes(root);
|
|
3738
|
-
const
|
|
3739
|
-
const layout = adoptLegacyLayout(disk);
|
|
3740
|
-
const files = layout.files;
|
|
3527
|
+
const files = await readSnapshot(root);
|
|
3741
3528
|
if (args.undo) {
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
{ action: args.dryRun ? "undo (dry-run)" : "undo", updated: [], removed: [], notes: [...rootNotes, layout.refusal] },
|
|
3745
|
-
{ json: options.json }
|
|
3746
|
-
));
|
|
3747
|
-
return 0;
|
|
3748
|
-
}
|
|
3749
|
-
const plan2 = withLegacyMoves(planUndo({ files }), layout);
|
|
3750
|
-
await applyPlan(root, plan2, args.dryRun, disk, false);
|
|
3529
|
+
const plan2 = planUndo({ files });
|
|
3530
|
+
await applyPlan(root, plan2, args.dryRun, files, false);
|
|
3751
3531
|
options.io.stdout.write(renderSuccess(
|
|
3752
3532
|
{
|
|
3753
3533
|
action: args.dryRun ? "undo (dry-run)" : "undo",
|
|
@@ -3759,7 +3539,7 @@ async function runInit(initialOptions) {
|
|
|
3759
3539
|
));
|
|
3760
3540
|
return 0;
|
|
3761
3541
|
}
|
|
3762
|
-
const refusal =
|
|
3542
|
+
const refusal = initRefusal(files);
|
|
3763
3543
|
if (refusal !== void 0) {
|
|
3764
3544
|
throw new Error(refusal);
|
|
3765
3545
|
}
|
|
@@ -3794,12 +3574,11 @@ async function runInit(initialOptions) {
|
|
|
3794
3574
|
const documents = args.dryRun ? { versions: {}, fallbacks: {}, unavailableReason: "skipped in --dry-run" } : await fetchHarnessDocuments({
|
|
3795
3575
|
endpoint: options.endpoint,
|
|
3796
3576
|
accessToken: await options.accessToken?.(),
|
|
3797
|
-
//
|
|
3798
|
-
|
|
3799
|
-
client: "ai-erd-cli",
|
|
3577
|
+
// 서버가 문서의 클라이언트별 변형 키를 이 이름으로 찾는다.
|
|
3578
|
+
client: "ainecto-cli",
|
|
3800
3579
|
fetchImpl: options.fetchImpl
|
|
3801
3580
|
});
|
|
3802
|
-
const plan =
|
|
3581
|
+
const plan = planInit({
|
|
3803
3582
|
role,
|
|
3804
3583
|
env: options.env,
|
|
3805
3584
|
projectName: project.name,
|
|
@@ -3808,11 +3587,11 @@ async function runInit(initialOptions) {
|
|
|
3808
3587
|
cliVersion: options.cliVersion,
|
|
3809
3588
|
files,
|
|
3810
3589
|
documents
|
|
3811
|
-
})
|
|
3590
|
+
});
|
|
3812
3591
|
if (plan.refusal !== void 0) {
|
|
3813
3592
|
throw new Error(plan.refusal);
|
|
3814
3593
|
}
|
|
3815
|
-
await applyPlan(root, plan, args.dryRun,
|
|
3594
|
+
await applyPlan(root, plan, args.dryRun, files);
|
|
3816
3595
|
if (!args.dryRun && previousRole2 !== void 0 && previousRole2 !== role) {
|
|
3817
3596
|
options.io.stderr.write(`Role changes from ${previousRole2} to ${role}: \`ainecto\` commands now, MCP tools from a new session.
|
|
3818
3597
|
`);
|
|
@@ -3824,8 +3603,6 @@ async function runInit(initialOptions) {
|
|
|
3824
3603
|
project: { uuid: project.uuid, name: project.name },
|
|
3825
3604
|
endpoint: options.endpoint,
|
|
3826
3605
|
written: plan.writes.map((write) => `${write.existed ? "updated" : "created"} ${write.path}`),
|
|
3827
|
-
// 옛 폴더(.ai-erd/)를 옮길 때만 생긴다 — 지운 것을 말하지 않으면 사용자는 옛 파일이 어디 갔는지 모른다.
|
|
3828
|
-
...plan.deletes.length > 0 ? { removed: plan.deletes } : {},
|
|
3829
3606
|
codex: `Codex keeps a single global config, so init does not touch it. Run: ${plan.codexCommand}`,
|
|
3830
3607
|
codexPerSession: plan.codexProfile,
|
|
3831
3608
|
codexEnvFallback: `Without a profile, start the session with ${ROLE_ENV_VAR}=${role}.`,
|
|
@@ -3848,9 +3625,6 @@ async function runInit(initialOptions) {
|
|
|
3848
3625
|
`Codex: save the profile above as $CODEX_HOME/${role}.config.toml and start with \`codex -p ${role}\`.`,
|
|
3849
3626
|
role === "design" ? "To check the role, change a table through `ainecto` \u2014 Design may, and the change lands in AiNecto." : `To check the role, try changing a table through \`ainecto\` \u2014 ${role} is told to stop.`,
|
|
3850
3627
|
`If the new Claude Code session still has no role, run \`claude mcp get ${SERVER_NAME}\`: a local-scope "${SERVER_NAME}" entry hides .mcp.json (remove it with \`claude mcp remove ${SERVER_NAME} -s local\`).`,
|
|
3851
|
-
// ★서버 이름이 바뀌었다(0.5.0). 예전에 같은 이름("ai-erd")이라 .mcp.json 이 덮던 사용자·Codex 전역 항목이
|
|
3852
|
-
// 이제는 «따로» 붙어, 그 세션이 역할 없는 서버를 하나 더 본다. 그 항목을 지우는 법을 같이 말한다.
|
|
3853
|
-
`If you added AiNecto earlier as "${LEGACY_SERVER_NAME}" (Claude Code user scope, or Codex), remove it \u2014 it no longer hides behind this "${SERVER_NAME}" entry: \`claude mcp remove ${LEGACY_SERVER_NAME} -s user\`, \`codex mcp remove ${LEGACY_SERVER_NAME}\`.`,
|
|
3854
3628
|
"Undo everything with: ainecto init --undo"
|
|
3855
3629
|
]
|
|
3856
3630
|
},
|
|
@@ -4086,7 +3860,7 @@ function boundProjectUuid(config) {
|
|
|
4086
3860
|
}
|
|
4087
3861
|
async function readSnapshot(root) {
|
|
4088
3862
|
const snapshot = /* @__PURE__ */ new Map();
|
|
4089
|
-
for (const path of
|
|
3863
|
+
for (const path of MANAGED_PATHS) {
|
|
4090
3864
|
snapshot.set(path, await readManagedFile(root, path));
|
|
4091
3865
|
}
|
|
4092
3866
|
return snapshot;
|
|
@@ -4105,7 +3879,7 @@ async function applyPlan(root, plan, dryRun, snapshot, recordFirst = true) {
|
|
|
4105
3879
|
}
|
|
4106
3880
|
const applied = [];
|
|
4107
3881
|
try {
|
|
4108
|
-
const isRecord10 = (path) => !recordFirst &&
|
|
3882
|
+
const isRecord10 = (path) => !recordFirst && path === HARNESS_RECORD_PATH;
|
|
4109
3883
|
const recordWrites = plan.writes.filter((write) => isRecord10(write.path));
|
|
4110
3884
|
const recordDeletes = plan.deletes.filter((path) => isRecord10(path));
|
|
4111
3885
|
const createdDirectories = [...plan.record?.createdDirectories ?? []];
|
|
@@ -4415,7 +4189,7 @@ async function commandRole(explicit, cwd) {
|
|
|
4415
4189
|
return explicitRole;
|
|
4416
4190
|
}
|
|
4417
4191
|
if (explicitRole !== null && explicitRole !== found.role) {
|
|
4418
|
-
const given = explicit.source === "env" ? `${
|
|
4192
|
+
const given = explicit.source === "env" ? `${ROLE_ENV_VAR}=${explicitRole}` : `--role ${explicitRole}`;
|
|
4419
4193
|
throw new Error(
|
|
4420
4194
|
`This repository's AI sessions have the role ${found.role} (set in ${found.dir}). ${given} does not match \u2014 the role changes only with \`ainecto init --role <role>\`, after asking the user.`
|
|
4421
4195
|
);
|
|
@@ -4557,8 +4331,6 @@ function helpText() {
|
|
|
4557
4331
|
" ainecto init [--role <design|development|test|validation>] [--project <uuid>] [--dry-run]",
|
|
4558
4332
|
" In a terminal, asks for the role and project when they are not given.",
|
|
4559
4333
|
" ainecto init --undo",
|
|
4560
|
-
"",
|
|
4561
|
-
"`ai-erd` (the older name) is the same command and still works.",
|
|
4562
4334
|
""
|
|
4563
4335
|
].join("\n");
|
|
4564
4336
|
}
|