@corvio/cli 0.1.0-beta.25 → 0.1.0-beta.27
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 +3 -3
- package/dist/cli.js +83 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,8 +15,8 @@ corvio files get <asset_id> --content --json
|
|
|
15
15
|
corvio files organize <asset_id> --instruction 'Create a reusable decision brief' --yes --json
|
|
16
16
|
corvio files operation <operation_id> --json
|
|
17
17
|
corvio files resume <operation_id> --yes --json
|
|
18
|
-
corvio docs table-read <document_id> --limit 25 --json
|
|
19
|
-
corvio docs table-mutate <document_id> --input ./table-change.json --change-summary 'Updated owner and due date' --yes --json
|
|
18
|
+
corvio docs table-read <workspace_id/document_id> --limit 25 --json
|
|
19
|
+
corvio docs table-mutate <workspace_id/document_id> --input ./table-change.json --change-summary 'Updated owner and due date' --yes --json
|
|
20
20
|
corvio sync init --dir ./knowledge --root-node-id <node_id> --json
|
|
21
21
|
corvio update check --json
|
|
22
22
|
```
|
|
@@ -32,7 +32,7 @@ fresh host session. Until a reviewed WorkBuddy marketplace listing is live, a Wo
|
|
|
32
32
|
auto-update from Corvio. Remote MCP changes are server-delivered and normally need only a refreshed host session unless new OAuth scopes
|
|
33
33
|
require reauthorization.
|
|
34
34
|
|
|
35
|
-
The CLI rejects unknown/duplicate options and malformed integer bounds before network access. Normal API calls have a bounded timeout (`CORVIO_REQUEST_TIMEOUT_MS`, maximum ten minutes); only reads, explicit idempotency contracts, revision guards, and other owner-declared safe operations retry automatically. Document updates preflight the current revision when `--expected-revision` is omitted. `docs table-read` returns a bounded stable-ID projection; `docs table-mutate` accepts a JSON payload for at most 50 cell updates or row appends and requires the fetched revision, while formulas, styles, structure, sorting, and semantic transformations remain `corvio ask --allow-actions` work. When the executing principal is a connected Agent, document and table mutations also require `--change-summary`, create a visible document-level comment after the guarded update, and return its receipt; a comment failure is reported as a partial effect rather than silent success. When a Corvio document or comment supplied the task, use `corvio agent closeout` to return the verified outcome, optionally resolve the thread, and read both document and thread back. Downloads, uploads, and Markdown pulls verify SHA-256 receipts before replacing local files; local writes are atomic, remote default filenames cannot escape the current directory, and Sync refuses symbolic-link traversal while checkpointing each successful push.
|
|
35
|
+
The CLI rejects unknown/duplicate options and malformed integer bounds before network access. Normal API calls have a bounded timeout (`CORVIO_REQUEST_TIMEOUT_MS`, maximum ten minutes); only reads, explicit idempotency contracts, revision guards, and other owner-declared safe operations retry automatically. Document commands accept both bare document IDs and canonical `workspace_id/document_id` handles; a canonical handle that disagrees with the selected Workspace fails before remote access, and successful reads return `canonical_id` for direct reuse. Document updates preflight the current revision when `--expected-revision` is omitted. `docs table-read` returns a bounded stable-ID projection; `docs table-mutate` accepts a JSON payload for at most 50 cell updates or row appends and requires the fetched revision, while formulas, styles, structure, sorting, and semantic transformations remain `corvio ask --allow-actions` work. When the executing principal is a connected Agent, document and table mutations also require `--change-summary`, create a visible document-level comment after the guarded update, and return its receipt; a comment failure is reported as a partial effect rather than silent success. When a Corvio document or comment supplied the task, use `corvio agent closeout` to return the verified outcome, optionally resolve the thread, and read both document and thread back. Downloads, uploads, and Markdown pulls verify SHA-256 receipts before replacing local files; local writes are atomic, remote default filenames cannot escape the current directory, and Sync refuses symbolic-link traversal while checkpointing each successful push.
|
|
36
36
|
|
|
37
37
|
For `corvio ask`, pass the user's natural goal, complete decision-relevant context, and explicit constraints. Unless the user chose them,
|
|
38
38
|
do not invent taxonomy, titles, artifact counts, or Corvio's internal plan. Read the terminal Question receipt and use `artifact.url` or
|
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
agentCredentialPath,
|
|
40
40
|
} from "./core.js";
|
|
41
41
|
|
|
42
|
-
const VERSION = "0.1.0-beta.
|
|
42
|
+
const VERSION = "0.1.0-beta.27";
|
|
43
43
|
const DEFAULT_API_BASE = "https://api.corvio.ai/v1";
|
|
44
44
|
const DEFAULT_APP_BASE = "https://corvio.ai";
|
|
45
45
|
const USER_AGENT = `corvio-cli/${VERSION}`;
|
|
@@ -180,8 +180,8 @@ const COMMAND_HELP = Object.freeze({
|
|
|
180
180
|
questions: `Usage:\n corvio questions list [--limit <n>] [--cursor <cursor>] [--conversation-id <id>]\n corvio questions get <question-id>`,
|
|
181
181
|
conversations: `Usage:\n corvio conversations list [--limit <n>] [--cursor <cursor>]\n corvio conversations get <conversation-id>`,
|
|
182
182
|
search: `Usage: corvio search <query> [--limit <n>] [--page-id <id>] [--node-id <id>]`,
|
|
183
|
-
docs: `Usage:\n corvio docs list [--limit <n>] [--cursor <cursor>] [--lifecycle active|archived]\n corvio docs get <id> [--output <path>]\n corvio docs table-read <id> [--table-id <id>] [--after-row-id <id>] [--limit <1-100>]\n corvio docs table-mutate <id> --input <json> --yes [--operation-id <id>] [--change-summary <text>]\n corvio docs create --title <title> [--file <path>|--markdown <text>] [--parent-node-id <id>] [--idempotency-key <key>]\n corvio docs update <id> [--title <title>] [--file <path>|--markdown <text>] [--expected-revision <n>] [--change-summary <text>]\n corvio docs move <id> --parent-node-id <id>\n corvio docs archive <id> --yes\n corvio docs restore <id> --yes\n corvio docs share <id> --yes [--display-name <name>]\n corvio docs open <id>\n\nA selected Markdown file is uploaded once as a provenance-preserving Asset, then its source_asset_id becomes an editable Page without resending the body; inspect the returned document ID, node ID, revision, and URL. Other formats or semantic restructuring belong to \`corvio files organize\` or \`corvio ask --allow-actions\`. \`docs update\` replaces the Page body: use it only when whole-body replacement is the smallest faithful change; delegate large localized semantic edits, reorder, splice, or formatting to \`corvio ask --allow-actions\` with the canonical document handle. Use table-read plus table-mutate for bounded stable-ID cell updates or row appends without round-tripping a whole document. Agent-authenticated document changes require --change-summary and create a visible document-level comment after the guarded update. When a document/comment is the task owner, use \`corvio agent closeout\` to return verified work to that same collaboration surface and read it back.`,
|
|
184
|
-
projects: `Usage:\n corvio projects list [--limit <n>]\n corvio projects create --title <title> [--idempotency-key <key>]\n\nProjects are durable grouping owners in the Corvio Docs tree. Reuse a matching Project instead of creating one ceremonial Project per file. 'corvio folders' is an alias.`,
|
|
183
|
+
docs: `Usage:\n corvio docs list [--limit <n>] [--cursor <cursor>] [--lifecycle active|archived]\n corvio docs get <id> [--output <path>]\n corvio docs table-read <id> [--table-id <id>] [--after-row-id <id>] [--limit <1-100>]\n corvio docs table-mutate <id> --input <json> --yes [--operation-id <id>] [--change-summary <text>]\n corvio docs create --title <title> [--file <path>|--markdown <text>] [--parent-node-id <id>] [--idempotency-key <key>]\n corvio docs update <id> [--title <title>] [--file <path>|--markdown <text>] [--expected-revision <n>] [--change-summary <text>]\n corvio docs move <id> --parent-node-id <id>\n corvio docs archive <id> --yes\n corvio docs restore <id> --yes\n corvio docs share <id> --yes [--display-name <name>]\n corvio docs open <id>\n\nA selected Markdown file is uploaded once as a provenance-preserving Asset, then its source_asset_id becomes an editable Page without resending the body; inspect the returned document ID, node ID, revision, and URL. Other formats or semantic restructuring belong to \`corvio files organize\` or \`corvio ask --allow-actions\`. \`docs update\` replaces the Page body: use it only when whole-body replacement is the smallest faithful change; delegate large localized semantic edits, reorder, splice, or formatting to \`corvio ask --allow-actions\` with the canonical document handle. Use table-read plus table-mutate for bounded stable-ID cell updates or row appends without round-tripping a whole document. \`docs move\` accepts a non-Project document and a Project destination; Projects stay at the Workspace root and cannot be nested. Use \`corvio files organize\` or \`corvio ask --allow-actions\` when deeper structure needs semantic branch Pages and leaves. Agent-authenticated document changes require --change-summary and create a visible document-level comment after the guarded update. When a document/comment is the task owner, use \`corvio agent closeout\` to return verified work to that same collaboration surface and read it back.`,
|
|
184
|
+
projects: `Usage:\n corvio projects list [--limit <n>]\n corvio projects create --title <title> [--idempotency-key <key>]\n\nProjects are durable root-level grouping owners in the Corvio Docs tree and cannot be nested under another Project. Reuse a matching Project instead of creating one ceremonial Project per file; use semantic branch Pages and leaves for deeper Work Models. 'corvio folders' is an alias.`,
|
|
185
185
|
files: `Usage:\n corvio files list [--limit <n>]\n corvio files get <id> [--content]\n corvio files download <id> [--output <path>]\n corvio files upload --file <path> [--mime-type <type>] [--organize --instruction <text> --additional-asset-ids <id,id> --yes]\n corvio files organize <id> --instruction <text> --yes [--additional-asset-ids <id,id>] [--processing-profile auto|economy|standard|deep] [--scan-mode auto|always|off] [--skills-extraction-mode auto|always|off]\n corvio files operation <operation-id>\n corvio files resume <operation-id> --yes\n corvio files cancel <operation-id> --yes\n corvio files open <id>\n\nUse --content only when source facts are needed. It returns one bounded AI-safe projection with hash, completeness, and truncation receipts; it does not rewrite or materialize the original. Upload alone preserves the exact original, provenance, hash, policy, and stable Asset ID. Organization is a separate asynchronous value step: one coherent source set can produce reader-facing structure, source reconciliation, Memory candidates, and qualifying Project Skills. Pass --instruction a weak natural goal plus explicit user constraints and only authority facts needed to prevent wrong identity or scope. Keep source-derived facts in the source; do not precompute an outline, edit checklist, taxonomy, titles, artifact count, or sole leaf target from current visibility. For a newly finalized Asset that should enter a Work Model or Skill evaluation, use organize directly instead of duplicate ask requests just to await processing. Use 'files operation' to reach terminal and inspect output_document plus skills_evaluation; always requires evaluation but may correctly return evaluated_no_qualifying_skill. Resume reuses the same durable operation after resolving its blocker; cancel is idempotent.`,
|
|
186
186
|
sync: `Usage:\n corvio sync init --root-node-id <id> [--dir <path>] [--name <name>]\n corvio sync status|plan|pull [--dir <path>]\n corvio sync push --yes [--dir <path>]\n corvio sync resolve --conflict-id <id> --strategy use-remote|keep-local --yes [--dir <path>]`,
|
|
187
187
|
update: `Usage: corvio update check [--json]\n\nCompare this executable with the reviewed API policy and the npm beta dist-tag.`,
|
|
@@ -189,8 +189,11 @@ const COMMAND_HELP = Object.freeze({
|
|
|
189
189
|
|
|
190
190
|
function contextualHelp(command, action) {
|
|
191
191
|
const normalizedCommand = command === "workspace" ? "workspaces" : command === "folders" ? "projects" : command;
|
|
192
|
-
const
|
|
193
|
-
if (!
|
|
192
|
+
const baseCommandHelp = COMMAND_HELP[normalizedCommand];
|
|
193
|
+
if (!baseCommandHelp) return HELP.trimEnd();
|
|
194
|
+
const commandHelp = normalizedCommand === "docs"
|
|
195
|
+
? `${baseCommandHelp}\n\nDocument commands accept either a bare document ID or the canonical workspace_id/document_id handle returned by Corvio. A canonical handle that disagrees with the selected Workspace fails before any remote request. Document reads return canonical_id for direct reuse.`
|
|
196
|
+
: baseCommandHelp;
|
|
194
197
|
if (!action) return commandHelp;
|
|
195
198
|
const matchingLine = commandHelp
|
|
196
199
|
.split("\n")
|
|
@@ -277,6 +280,53 @@ function resourcePath(value) {
|
|
|
277
280
|
return encodeURIComponent(String(value));
|
|
278
281
|
}
|
|
279
282
|
|
|
283
|
+
function resolveDocumentId(value, selection) {
|
|
284
|
+
const raw = String(value || "").trim();
|
|
285
|
+
if (!raw) {
|
|
286
|
+
throw new CliError("Provide a document ID or canonical workspace/document handle.", {
|
|
287
|
+
code: "document_id_required",
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
const handle = raw.startsWith("document:") ? raw.slice("document:".length) : raw;
|
|
291
|
+
if (!handle.includes("/")) return handle;
|
|
292
|
+
const parts = handle.split("/");
|
|
293
|
+
if (parts.length !== 2 || parts.some((part) => !part.trim())) {
|
|
294
|
+
throw new CliError(
|
|
295
|
+
"Document handles must be a document ID or canonical workspace_id/document_id pair.",
|
|
296
|
+
{ code: "document_handle_invalid" },
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
const [workspaceId, documentId] = parts.map((part) => part.trim());
|
|
300
|
+
if (!selection?.workspaceId) {
|
|
301
|
+
throw new CliError(
|
|
302
|
+
"A canonical document handle requires an explicit or resolved Workspace route.",
|
|
303
|
+
{ code: "document_workspace_route_unavailable", exitCode: EXIT.AUTH },
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
if (selection?.workspaceId && workspaceId !== selection.workspaceId) {
|
|
307
|
+
throw new CliError(
|
|
308
|
+
`The document handle belongs to Workspace ${workspaceId}, but the current route is ${selection.workspaceId}.`,
|
|
309
|
+
{
|
|
310
|
+
code: "document_workspace_mismatch",
|
|
311
|
+
exitCode: EXIT.AUTH,
|
|
312
|
+
details: {
|
|
313
|
+
handle_workspace_id: workspaceId,
|
|
314
|
+
selected_workspace_id: selection.workspaceId,
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
return documentId;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function withCanonicalDocumentId(value, selection, fallbackDocumentId = null) {
|
|
323
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
324
|
+
const workspaceId = String(selection?.workspaceId || "").trim();
|
|
325
|
+
const documentId = String(fallbackDocumentId || value.id || "").trim();
|
|
326
|
+
if (!workspaceId || !documentId) return value;
|
|
327
|
+
return { ...value, canonical_id: `${workspaceId}/${documentId}` };
|
|
328
|
+
}
|
|
329
|
+
|
|
280
330
|
function safeRemoteFileName(value, fallback) {
|
|
281
331
|
const normalized = String(value || "").replaceAll("\\", "/");
|
|
282
332
|
const name = basename(normalized).trim();
|
|
@@ -2821,7 +2871,7 @@ async function search(options, positionals) {
|
|
|
2821
2871
|
}
|
|
2822
2872
|
|
|
2823
2873
|
async function docs(options, action, id) {
|
|
2824
|
-
const { api, executionIdentity } = await executionClient(options);
|
|
2874
|
+
const { api, executionIdentity, selection } = await executionClient(options);
|
|
2825
2875
|
const documentId = id || options.id;
|
|
2826
2876
|
let result;
|
|
2827
2877
|
if (action === "list") {
|
|
@@ -2830,8 +2880,19 @@ async function docs(options, action, id) {
|
|
|
2830
2880
|
throw new CliError("--lifecycle must be active or archived.", { code: "document_lifecycle_invalid" });
|
|
2831
2881
|
}
|
|
2832
2882
|
result = await api.request("/documents", { query: { ...pageQuery(options), lifecycle } });
|
|
2883
|
+
if (Array.isArray(result?.data)) {
|
|
2884
|
+
result = {
|
|
2885
|
+
...result,
|
|
2886
|
+
data: result.data.map((item) => withCanonicalDocumentId(item, selection)),
|
|
2887
|
+
};
|
|
2888
|
+
}
|
|
2833
2889
|
} else if (action === "get") {
|
|
2834
|
-
|
|
2890
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
2891
|
+
result = withCanonicalDocumentId(
|
|
2892
|
+
await api.request(`/documents/${resourcePath(targetId)}`),
|
|
2893
|
+
selection,
|
|
2894
|
+
targetId,
|
|
2895
|
+
);
|
|
2835
2896
|
if (executionIdentity === "agent") {
|
|
2836
2897
|
result = {
|
|
2837
2898
|
...result,
|
|
@@ -2843,7 +2904,7 @@ async function docs(options, action, id) {
|
|
|
2843
2904
|
result = { ...result, output: options.output };
|
|
2844
2905
|
}
|
|
2845
2906
|
} else if (action === "table-read") {
|
|
2846
|
-
const targetId = documentId
|
|
2907
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
2847
2908
|
result = await api.request(`/documents/${resourcePath(targetId)}/table`, {
|
|
2848
2909
|
query: {
|
|
2849
2910
|
table_id: options["table-id"] || undefined,
|
|
@@ -2853,7 +2914,7 @@ async function docs(options, action, id) {
|
|
|
2853
2914
|
});
|
|
2854
2915
|
} else if (action === "table-mutate") {
|
|
2855
2916
|
requireConfirmation(options, "Mutating a document table");
|
|
2856
|
-
const targetId = documentId
|
|
2917
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
2857
2918
|
const payload = await readJsonObject(option(options, "input", { required: true }), "--input");
|
|
2858
2919
|
const changeSummary = String(options["change-summary"] || "").trim();
|
|
2859
2920
|
if (executionIdentity === "agent" && !changeSummary) {
|
|
@@ -2931,7 +2992,7 @@ async function docs(options, action, id) {
|
|
|
2931
2992
|
code: "document_update_empty",
|
|
2932
2993
|
});
|
|
2933
2994
|
}
|
|
2934
|
-
const targetId = documentId
|
|
2995
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
2935
2996
|
const changeSummary = String(options["change-summary"] || "").trim();
|
|
2936
2997
|
if (executionIdentity === "agent" && !changeSummary) {
|
|
2937
2998
|
throw new CliError(
|
|
@@ -3005,7 +3066,8 @@ async function docs(options, action, id) {
|
|
|
3005
3066
|
}
|
|
3006
3067
|
} else if (action === "move") {
|
|
3007
3068
|
rejectTogether(options, "before-node-id", "after-node-id");
|
|
3008
|
-
const
|
|
3069
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
3070
|
+
const current = await api.request(`/documents/${resourcePath(targetId)}`);
|
|
3009
3071
|
result = await api.request(`/nodes/${resourcePath(current.node_id)}:move`, {
|
|
3010
3072
|
method: "POST",
|
|
3011
3073
|
headers: { "idempotency-key": idempotencyKey(options) },
|
|
@@ -3017,25 +3079,31 @@ async function docs(options, action, id) {
|
|
|
3017
3079
|
});
|
|
3018
3080
|
} else if (action === "archive") {
|
|
3019
3081
|
requireConfirmation(options, "Archiving a document");
|
|
3020
|
-
|
|
3082
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
3083
|
+
result = await api.request(`/documents/${resourcePath(targetId)}`, { method: "DELETE" });
|
|
3021
3084
|
} else if (action === "restore") {
|
|
3022
3085
|
requireConfirmation(options, "Restoring an archived document");
|
|
3023
|
-
|
|
3086
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
3087
|
+
result = await api.request(`/documents/${resourcePath(targetId)}/restore`, { method: "POST", retrySafe: true });
|
|
3024
3088
|
} else if (action === "share") {
|
|
3025
3089
|
requireConfirmation(options, "Creating a document share link");
|
|
3026
|
-
|
|
3090
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
3091
|
+
result = await api.request(`/documents/${resourcePath(targetId)}/shares`, {
|
|
3027
3092
|
method: "POST",
|
|
3028
3093
|
retrySafe: true,
|
|
3029
3094
|
body: { public_display_name: options["display-name"] || null },
|
|
3030
3095
|
});
|
|
3031
3096
|
} else if (action === "open") {
|
|
3032
|
-
const targetId = documentId
|
|
3097
|
+
const targetId = resolveDocumentId(documentId, selection);
|
|
3033
3098
|
const target = `${String(process.env.CORVIO_APP_BASE || DEFAULT_APP_BASE).replace(/\/+$/, "")}/app/d/${resourcePath(targetId)}`;
|
|
3034
3099
|
const opened = options["no-input"] ? false : await openBrowser(target);
|
|
3035
3100
|
result = { document_id: targetId, url: target, opened };
|
|
3036
3101
|
} else {
|
|
3037
3102
|
throw new CliError("docs action must be list, get, table-read, table-mutate, create, update, move, archive, restore, share, or open.");
|
|
3038
3103
|
}
|
|
3104
|
+
if (!new Set(["list", "create"]).has(action)) {
|
|
3105
|
+
result = withCanonicalDocumentId(result, selection, resolveDocumentId(documentId, selection));
|
|
3106
|
+
}
|
|
3039
3107
|
writeResult(result, { json: options.json });
|
|
3040
3108
|
}
|
|
3041
3109
|
|