@withone/cli 2.4.0 → 2.5.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
CHANGED
|
@@ -185,7 +185,7 @@ Opens your browser, you authorize, done. The CLI polls until the connection is l
|
|
|
185
185
|
|
|
186
186
|
### `one list`
|
|
187
187
|
|
|
188
|
-
List your active connections with their status, connection keys, and
|
|
188
|
+
List your active connections with their status, connection keys, and the access this key has on each.
|
|
189
189
|
|
|
190
190
|
```bash
|
|
191
191
|
one list
|
|
@@ -199,15 +199,15 @@ one list
|
|
|
199
199
|
|
|
200
200
|
You need the connection key (rightmost column) when executing actions.
|
|
201
201
|
|
|
202
|
-
**Access reporting.** Every connection carries an `access` field
|
|
202
|
+
**Access reporting.** Every connection carries an `access` field: what this key may run there. The CLI reads it from One (`GET /v1/access/me`, the access chosen on the consent page or later in the dashboard) and narrows it by any limits you set with [`one config`](#one-config) — the server's answer is the ceiling, local settings can only lower it.
|
|
203
203
|
|
|
204
|
-
| Policy | Means |
|
|
205
|
-
|
|
206
|
-
| `{"policy": "full"}` | Every action on the connection |
|
|
207
|
-
| `{"policy": "methods", "methods": ["GET"]}` | Only actions with those
|
|
208
|
-
| `{"policy": "actions", "actions": [{"actionId": "...", "title": "...", "method": "..."}]}` | Only these specific actions |
|
|
204
|
+
| Policy | Means | `level` |
|
|
205
|
+
|--------|-------|---------|
|
|
206
|
+
| `{"policy": "full"}` | Every action on the connection | `full` (Full access) |
|
|
207
|
+
| `{"policy": "methods", "methods": ["GET"]}` | Only actions with those methods | `read-only`, `read-write` (GET, POST, PUT, PATCH), or `custom` |
|
|
208
|
+
| `{"policy": "actions", "actions": [{"actionId": "...", "title": "...", "method": "..."}]}` | Only these specific actions | `custom`, or `none` when empty |
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
A connection the key does not reach is not listed. When the policy is `actions`, those actions are exactly what may run — `actions load <actionId>` reads their docs, no find needed.
|
|
211
211
|
|
|
212
212
|
```jsonc
|
|
213
213
|
// one --agent list
|
|
@@ -219,14 +219,14 @@ An action allowlist wins over the permission level (and is then method-filtered
|
|
|
219
219
|
"platform": "gmail",
|
|
220
220
|
"state": "operational",
|
|
221
221
|
"key": "live::gmail::default::abc123",
|
|
222
|
-
"access": { "policy": "methods", "methods": ["GET"] }
|
|
222
|
+
"access": { "policy": "methods", "methods": ["GET"], "level": "read-only" }
|
|
223
223
|
}
|
|
224
224
|
],
|
|
225
|
-
"
|
|
225
|
+
"accessSource": "server"
|
|
226
226
|
}
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
-
`knowledgeOnly: true` appears when knowledge-only mode is on (execution disabled), and `unresolvedActionIds` lists
|
|
229
|
+
`accessSource` is `"server"` when One reported the key's access and `"local"` when it could not (an older API); then `access` shows only the CLI's own settings, the human table labels the column "Access (CLI settings only)", and `accessHint` says One may allow less. `knowledgeOnly: true` appears when knowledge-only mode is on (execution disabled), and `unresolvedActionIds` lists action ids that could not be looked up.
|
|
230
230
|
|
|
231
231
|
This mirrors the `access` field on the One MCP server's `list_one_integrations` tool, so both surfaces report access the same way.
|
|
232
232
|
|
|
@@ -104,6 +104,20 @@ var OneApi = class {
|
|
|
104
104
|
if (!text) return {};
|
|
105
105
|
return JSON.parse(text);
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* The calling key's own access, as One enforces it: `GET /v1/access/me`.
|
|
109
|
+
* Resolves `null` for a key with no restrictions. Throws `ApiError` when the
|
|
110
|
+
* API does not answer it (for example an older backend without the route).
|
|
111
|
+
*/
|
|
112
|
+
async getOwnAccess() {
|
|
113
|
+
const body = await this.request("/access/me");
|
|
114
|
+
if (body === null) return null;
|
|
115
|
+
if (typeof body !== "object" || !("rules" in body || "methods" in body)) {
|
|
116
|
+
throw new ApiError(502, "Unexpected answer from /access/me");
|
|
117
|
+
}
|
|
118
|
+
const doc = body;
|
|
119
|
+
return { methods: doc.methods ?? null, rules: doc.rules ?? null };
|
|
120
|
+
}
|
|
107
121
|
async whoami() {
|
|
108
122
|
return this.request("/users/whoami");
|
|
109
123
|
}
|
|
@@ -2285,7 +2299,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
2285
2299
|
if (flowStack.includes(resolvedKey)) {
|
|
2286
2300
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
2287
2301
|
}
|
|
2288
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
2302
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-4A5ANCTT.js");
|
|
2289
2303
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
2290
2304
|
const subContext = await executeFlow(
|
|
2291
2305
|
subFlow,
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
validateActionInput,
|
|
29
29
|
walkSteps,
|
|
30
30
|
writeCache
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-MRQ47KSZ.js";
|
|
32
32
|
import {
|
|
33
33
|
memSqlCommand
|
|
34
34
|
} from "./chunk-7FPQOAQ4.js";
|
|
@@ -2610,21 +2610,91 @@ async function resolveAllowedActions(api, actionIds) {
|
|
|
2610
2610
|
);
|
|
2611
2611
|
return resolved.filter((a) => a !== null);
|
|
2612
2612
|
}
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2613
|
+
var UNRESTRICTED = { reachable: true, methods: null, actionIds: null };
|
|
2614
|
+
var UNREACHABLE = { reachable: false, methods: [], actionIds: [] };
|
|
2615
|
+
function serverEnvelope(doc, connectionKey) {
|
|
2616
|
+
if (!doc) return UNRESTRICTED;
|
|
2617
|
+
if (doc.rules === null) return { reachable: true, methods: doc.methods, actionIds: null };
|
|
2618
|
+
const rule = doc.rules.find((r) => r.connectionKey === connectionKey);
|
|
2619
|
+
if (!rule) return UNREACHABLE;
|
|
2620
|
+
return {
|
|
2621
|
+
reachable: true,
|
|
2622
|
+
methods: rule.methods ?? doc.methods,
|
|
2623
|
+
actionIds: rule.actionIds ?? null
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
function localEnvelope(permissions, actionIds, connectionKeys, connectionKey) {
|
|
2627
|
+
if (!connectionKeys.includes("*") && !connectionKeys.includes(connectionKey)) return UNREACHABLE;
|
|
2628
|
+
return {
|
|
2629
|
+
reachable: true,
|
|
2630
|
+
methods: PERMISSION_METHODS[permissions],
|
|
2631
|
+
actionIds: actionIds.includes("*") ? null : actionIds
|
|
2632
|
+
};
|
|
2633
|
+
}
|
|
2634
|
+
function intersectList(a, b) {
|
|
2635
|
+
if (a === null) return b;
|
|
2636
|
+
if (b === null) return a;
|
|
2637
|
+
const upper = new Set(b.map((x) => x.toUpperCase()));
|
|
2638
|
+
return a.filter((x) => upper.has(x.toUpperCase()));
|
|
2639
|
+
}
|
|
2640
|
+
function intersectEnvelopes(a, b) {
|
|
2641
|
+
if (!a.reachable || !b.reachable) return UNREACHABLE;
|
|
2642
|
+
return {
|
|
2643
|
+
reachable: true,
|
|
2644
|
+
methods: intersectList(a.methods, b.methods),
|
|
2645
|
+
actionIds: a.actionIds === null ? b.actionIds : b.actionIds === null ? a.actionIds : a.actionIds.filter((id) => b.actionIds.includes(id))
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
function envelopeToAccess(envelope, resolved, localMethods = null) {
|
|
2649
|
+
if (!envelope.reachable || envelope.methods !== null && envelope.methods.length === 0) {
|
|
2650
|
+
return { access: { policy: "actions", actions: [] }, unresolved: [] };
|
|
2617
2651
|
}
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2652
|
+
if (envelope.actionIds !== null) {
|
|
2653
|
+
const actions2 = envelope.actionIds.flatMap((id) => {
|
|
2654
|
+
const hit = resolved.find((a) => a.actionId === id);
|
|
2655
|
+
if (!hit) return [];
|
|
2656
|
+
if (localMethods && !localMethods.includes(hit.method.toUpperCase())) return [];
|
|
2657
|
+
return [{ actionId: hit.actionId, title: hit.title, method: hit.method }];
|
|
2658
|
+
});
|
|
2659
|
+
return {
|
|
2660
|
+
access: { policy: "actions", actions: actions2 },
|
|
2661
|
+
unresolved: envelope.actionIds.filter((id) => !resolved.some((a) => a.actionId === id))
|
|
2662
|
+
};
|
|
2621
2663
|
}
|
|
2622
|
-
|
|
2664
|
+
if (envelope.methods !== null) {
|
|
2665
|
+
return { access: { policy: "methods", methods: envelope.methods.map((m) => m.toUpperCase()) }, unresolved: [] };
|
|
2666
|
+
}
|
|
2667
|
+
return { access: { policy: "full" }, unresolved: [] };
|
|
2623
2668
|
}
|
|
2624
|
-
|
|
2669
|
+
var READ_WRITE = ["GET", "PATCH", "POST", "PUT"];
|
|
2670
|
+
function accessLevel(access) {
|
|
2625
2671
|
switch (access.policy) {
|
|
2626
2672
|
case "full":
|
|
2627
2673
|
return "full";
|
|
2674
|
+
case "methods": {
|
|
2675
|
+
const set = [...new Set(access.methods.map((m) => m.toUpperCase()))].sort();
|
|
2676
|
+
if (set.length === 0) return "none";
|
|
2677
|
+
if (set.length === 1 && set[0] === "GET") return "read-only";
|
|
2678
|
+
if (set.join(",") === READ_WRITE.join(",")) return "read-write";
|
|
2679
|
+
return "custom";
|
|
2680
|
+
}
|
|
2681
|
+
case "actions":
|
|
2682
|
+
return access.actions.length === 0 ? "none" : "custom";
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
var LEVEL_LABELS = {
|
|
2686
|
+
full: "Full access",
|
|
2687
|
+
"read-write": "Read & write",
|
|
2688
|
+
"read-only": "Read only",
|
|
2689
|
+
custom: "Custom",
|
|
2690
|
+
none: "No access"
|
|
2691
|
+
};
|
|
2692
|
+
function formatAccess(access, maxActions = 2) {
|
|
2693
|
+
const level = accessLevel(access);
|
|
2694
|
+
if (level !== "custom") return LEVEL_LABELS[level];
|
|
2695
|
+
switch (access.policy) {
|
|
2696
|
+
case "full":
|
|
2697
|
+
return LEVEL_LABELS.full;
|
|
2628
2698
|
case "methods":
|
|
2629
2699
|
return access.methods.join(", ");
|
|
2630
2700
|
case "actions": {
|
|
@@ -2847,18 +2917,30 @@ async function connectionListCommand(options) {
|
|
|
2847
2917
|
const spinner = createSpinner();
|
|
2848
2918
|
spinner.start("Loading connections...");
|
|
2849
2919
|
try {
|
|
2850
|
-
const allConnections = await
|
|
2920
|
+
const [allConnections, serverAccess] = await Promise.all([
|
|
2921
|
+
api.listConnections(),
|
|
2922
|
+
api.getOwnAccess().then(
|
|
2923
|
+
(doc) => ({ ok: true, doc }),
|
|
2924
|
+
() => ({ ok: false, doc: null })
|
|
2925
|
+
)
|
|
2926
|
+
]);
|
|
2851
2927
|
const ac = getAccessControlFromAllSources();
|
|
2852
2928
|
const permissions = ac.permissions || "admin";
|
|
2853
2929
|
const allowedKeys = ac.connectionKeys || ["*"];
|
|
2854
2930
|
const actionIds = ac.actionIds || ["*"];
|
|
2855
2931
|
const knowledgeOnly = ac.knowledgeAgent || false;
|
|
2856
|
-
const
|
|
2857
|
-
const
|
|
2858
|
-
const
|
|
2859
|
-
const
|
|
2860
|
-
const
|
|
2861
|
-
const
|
|
2932
|
+
const envelopeFor = (key) => intersectEnvelopes(serverEnvelope(serverAccess.doc, key), localEnvelope(permissions, actionIds, allowedKeys, key));
|
|
2933
|
+
const accessFiltered = allConnections.filter((conn) => envelopeFor(conn.key).reachable);
|
|
2934
|
+
const namedActionIds = new Set(actionIds.includes("*") ? [] : actionIds);
|
|
2935
|
+
for (const rule of serverAccess.doc?.rules ?? []) for (const id of rule.actionIds ?? []) namedActionIds.add(id);
|
|
2936
|
+
const resolvedActions = await resolveAllowedActions(api, [...namedActionIds]);
|
|
2937
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
2938
|
+
const accessFor = (conn) => {
|
|
2939
|
+
const { access, unresolved: missing } = envelopeToAccess(envelopeFor(conn.key), resolvedActions, PERMISSION_METHODS[permissions]);
|
|
2940
|
+
missing.forEach((id) => unresolved.add(id));
|
|
2941
|
+
return access;
|
|
2942
|
+
};
|
|
2943
|
+
const hintText = accessHint(permissions, actionIds, knowledgeOnly, serverAccess.ok ? serverAccess.doc : void 0);
|
|
2862
2944
|
const searchQuery = options?.search?.toLowerCase();
|
|
2863
2945
|
const filtered = searchQuery ? accessFiltered.filter((conn) => conn.platform.toLowerCase().includes(searchQuery)) : accessFiltered;
|
|
2864
2946
|
const limitArg = options?.limit ? parseInt(options.limit, 10) : void 0;
|
|
@@ -2875,10 +2957,11 @@ async function connectionListCommand(options) {
|
|
|
2875
2957
|
key: conn.key,
|
|
2876
2958
|
...conn.name && { name: conn.name },
|
|
2877
2959
|
...conn.tags?.length && { tags: conn.tags },
|
|
2878
|
-
access: accessFor(conn
|
|
2960
|
+
access: withLevel(accessFor(conn))
|
|
2879
2961
|
})),
|
|
2962
|
+
accessSource: serverAccess.ok ? "server" : "local",
|
|
2880
2963
|
...knowledgeOnly && { knowledgeOnly: true },
|
|
2881
|
-
...
|
|
2964
|
+
...unresolved.size > 0 && { unresolvedActionIds: [...unresolved] },
|
|
2882
2965
|
...hintText && { accessHint: hintText },
|
|
2883
2966
|
...limited.length < filtered.length && {
|
|
2884
2967
|
hint: `Showing ${limited.length} of ${filtered.length} connections. Use --search <query> to filter by platform or --limit <n> to see more.`
|
|
@@ -2896,6 +2979,13 @@ async function connectionListCommand(options) {
|
|
|
2896
2979
|
Try: ${pc6.cyan("one connection list")} to see all connections.`,
|
|
2897
2980
|
"No Results"
|
|
2898
2981
|
);
|
|
2982
|
+
} else if (serverAccess.doc?.rules && allConnections.length === 0) {
|
|
2983
|
+
p4.note(
|
|
2984
|
+
`This key reaches no connections: it can search actions and read their docs, but runs none.
|
|
2985
|
+
|
|
2986
|
+
Change it in the dashboard under API keys.`,
|
|
2987
|
+
"No Connections"
|
|
2988
|
+
);
|
|
2899
2989
|
} else {
|
|
2900
2990
|
p4.note(
|
|
2901
2991
|
`No connections yet.
|
|
@@ -2913,10 +3003,9 @@ Add one with: ${pc6.cyan("one connection add gmail")}`,
|
|
|
2913
3003
|
state: conn.state,
|
|
2914
3004
|
key: conn.key,
|
|
2915
3005
|
tags: conn.tags?.length ? conn.tags.join(", ") : "",
|
|
2916
|
-
access: formatAccess(accessFor(conn
|
|
3006
|
+
access: formatAccess(accessFor(conn))
|
|
2917
3007
|
}));
|
|
2918
3008
|
const hasTags = rows.some((r) => r.tags);
|
|
2919
|
-
const hasScopedAccess = rows.some((r) => r.access !== "full");
|
|
2920
3009
|
printTable(
|
|
2921
3010
|
[
|
|
2922
3011
|
{ key: "status", label: "" },
|
|
@@ -2924,21 +3013,22 @@ Add one with: ${pc6.cyan("one connection add gmail")}`,
|
|
|
2924
3013
|
{ key: "state", label: "Status" },
|
|
2925
3014
|
{ key: "key", label: "Connection Key", color: pc6.dim },
|
|
2926
3015
|
...hasTags ? [{ key: "tags", label: "Tags", color: pc6.dim }] : [],
|
|
2927
|
-
|
|
3016
|
+
{ key: "access", label: serverAccess.ok ? "Access" : "Access (CLI settings only)", color: pc6.yellow }
|
|
2928
3017
|
],
|
|
2929
3018
|
rows
|
|
2930
3019
|
);
|
|
2931
3020
|
console.log();
|
|
2932
|
-
if (hintText) {
|
|
2933
|
-
const lines = [hintText];
|
|
2934
|
-
if (
|
|
2935
|
-
lines.push(
|
|
2936
|
-
`Could not resolve ${unresolvedActionIds.length} allowlisted action id(s): ${unresolvedActionIds.join(", ")}`
|
|
2937
|
-
);
|
|
3021
|
+
if (hintText || unresolved.size > 0) {
|
|
3022
|
+
const lines = hintText ? [hintText] : [];
|
|
3023
|
+
if (unresolved.size > 0) {
|
|
3024
|
+
lines.push(`Could not resolve ${unresolved.size} allowed action id(s): ${[...unresolved].join(", ")}`);
|
|
2938
3025
|
}
|
|
2939
|
-
p4.note(
|
|
3026
|
+
p4.note(
|
|
3027
|
+
`${wrapText(lines.join("\n"))}
|
|
2940
3028
|
|
|
2941
|
-
|
|
3029
|
+
This key's access: dashboard \u2192 API keys. This CLI's own limits: ${pc6.cyan("one config")}`,
|
|
3030
|
+
"Access"
|
|
3031
|
+
);
|
|
2942
3032
|
}
|
|
2943
3033
|
if (displayed.length < filtered.length) {
|
|
2944
3034
|
p4.note(
|
|
@@ -3012,21 +3102,35 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
3012
3102
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
3013
3103
|
}
|
|
3014
3104
|
}
|
|
3015
|
-
function accessHint(permissions, actionIds, knowledgeOnly) {
|
|
3105
|
+
function accessHint(permissions, actionIds, knowledgeOnly, server) {
|
|
3016
3106
|
const parts = [];
|
|
3107
|
+
if (server === void 0) {
|
|
3108
|
+
parts.push(
|
|
3109
|
+
"One did not report this key's access, so each `access` shows only this CLI's own settings; One may allow less. Check the key in the dashboard under API keys."
|
|
3110
|
+
);
|
|
3111
|
+
} else if (server?.rules && server.rules.length === 0) {
|
|
3112
|
+
parts.push("This key reaches no connections: it can read docs and search actions, but no action will execute.");
|
|
3113
|
+
} else if (server?.rules?.some((r) => r.actionIds)) {
|
|
3114
|
+
parts.push(
|
|
3115
|
+
"Some connections are action-scoped: their `access.actions` are the only actions you may run there \u2014 use them directly: `actions load <actionId>` reads their docs, no find needed."
|
|
3116
|
+
);
|
|
3117
|
+
}
|
|
3017
3118
|
if (!actionIds.includes("*")) {
|
|
3018
3119
|
parts.push(
|
|
3019
|
-
"Action-scoped: each connection's `access.actions` are the only actions you may run \u2014 use them directly: `actions load <actionId>` reads their docs, no find needed."
|
|
3120
|
+
"Action-scoped (local settings): each connection's `access.actions` are the only actions you may run \u2014 use them directly: `actions load <actionId>` reads their docs, no find needed."
|
|
3020
3121
|
);
|
|
3021
3122
|
} else if (permissions !== "admin") {
|
|
3022
3123
|
const methods = PERMISSION_METHODS[permissions]?.join(", ") ?? "";
|
|
3023
|
-
parts.push(`Permission level "${permissions}": only ${methods} actions will execute.`);
|
|
3124
|
+
parts.push(`Permission level "${permissions}" (local settings): only ${methods} actions will execute.`);
|
|
3024
3125
|
}
|
|
3025
3126
|
if (knowledgeOnly) {
|
|
3026
3127
|
parts.push("Knowledge-only mode: `actions execute` is disabled \u2014 read knowledge and write code instead.");
|
|
3027
3128
|
}
|
|
3028
3129
|
return parts.length > 0 ? parts.join(" ") : null;
|
|
3029
3130
|
}
|
|
3131
|
+
function withLevel(access) {
|
|
3132
|
+
return { ...access, level: accessLevel(access) };
|
|
3133
|
+
}
|
|
3030
3134
|
function wrapText(text5, width = 72) {
|
|
3031
3135
|
return text5.split("\n").map((paragraph) => {
|
|
3032
3136
|
const lines = [];
|
|
@@ -11411,7 +11515,7 @@ Request specific sections:
|
|
|
11411
11515
|
- Always use the **exact action ID** from a find answer \u2014 don't guess
|
|
11412
11516
|
- Always read **knowledge** before executing any action
|
|
11413
11517
|
- Connection keys come from \`one connection list\` \u2014 don't hardcode them
|
|
11414
|
-
- \`connection list\` also reports an \`access\` field per connection (\`full\` / \`methods\` / \`actions\`) \u2014
|
|
11518
|
+
- \`connection list\` also reports an \`access\` field per connection (\`full\` / \`methods\` / \`actions\`, plus a \`level\`: full, read-write, read-only, custom, none) \u2014 what One enforces for this key, narrowed by \`one config\`. Read it before planning so you don't propose an action that will be refused. \`accessSource: "local"\` means One did not report it, so it is unverified
|
|
11415
11519
|
- Skills stay in lockstep with the CLI version automatically \u2014 every command checks a \`.one-cli-version\` marker in the canonical skill dir and refreshes the files if the CLI has been upgraded. Check manually with \`one config skills status\`; force a resync with \`one config skills sync\`
|
|
11416
11520
|
- Building an app whose users connect their own tools? \`one skills add connect\` (run inside the app) installs the One Connect skill from the \`@withone/connect\` version the app uses, into \`.agents/skills/one-connect\` and \`.claude/skills/one-connect\`. \`one --agent skills list\` shows what is installed; any \`one\` command in the project refreshes it after an SDK upgrade
|
|
11417
11521
|
`;
|
|
@@ -11427,7 +11531,7 @@ Always follow this sequence. Never execute without reading the action's document
|
|
|
11427
11531
|
one --agent connection list
|
|
11428
11532
|
\`\`\`
|
|
11429
11533
|
|
|
11430
|
-
Returns platforms, status, connection keys, tags, and an \`access\` field per connection
|
|
11534
|
+
Returns platforms, status, connection keys, tags, and an \`access\` field per connection: what One enforces for this key (the consent page's choices, or the dashboard's), narrowed by \`one config\`. \`access.level\` names it as the consent page does (full, read-write, read-only, custom, none):
|
|
11431
11535
|
|
|
11432
11536
|
| \`access\` | Meaning |
|
|
11433
11537
|
|----------|---------|
|
|
@@ -11435,9 +11539,9 @@ Returns platforms, status, connection keys, tags, and an \`access\` field per co
|
|
|
11435
11539
|
| \`{"policy": "methods", "methods": ["GET"]}\` | Only actions with these HTTP methods will execute |
|
|
11436
11540
|
| \`{"policy": "actions", "actions": [{"actionId", "title", "method"}]}\` | Only these exact actions \u2014 use them directly: \`actions load <actionId>\` reads their docs, no find needed |
|
|
11437
11541
|
|
|
11438
|
-
Also present when relevant: \`knowledgeOnly: true\` (execution disabled \u2014 read the docs and write code instead), \`unresolvedActionIds\` (allowlisted ids that could not be looked up), and \`accessHint\` (a one-line summary of the restriction).
|
|
11542
|
+
\`accessSource\` is \`server\` when One reported it, \`local\` when it could not (then it is unverified). Also present when relevant: \`knowledgeOnly: true\` (execution disabled \u2014 read the docs and write code instead), \`unresolvedActionIds\` (allowlisted ids that could not be looked up), and \`accessHint\` (a one-line summary of the restriction).
|
|
11439
11543
|
|
|
11440
|
-
Read \`access\` before planning \u2014 it prevents proposing an action
|
|
11544
|
+
Read \`access\` before planning \u2014 it prevents proposing an action that will be refused. The key's access changes in the dashboard (API keys); this CLI's own limits with \`one config\`.
|
|
11441
11545
|
|
|
11442
11546
|
### 1b. Delete a Connection
|
|
11443
11547
|
|
package/package.json
CHANGED
package/skills/one/SKILL.md
CHANGED
|
@@ -47,7 +47,7 @@ Always follow this sequence when the user wants to do something on a connected p
|
|
|
47
47
|
one --agent connection list
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
Returns connected platforms with their connection keys (needed for execution), platform names in kebab-case (needed for finding actions), and an `access` field per connection telling you what you may run there.
|
|
50
|
+
Returns connected platforms with their connection keys (needed for execution), platform names in kebab-case (needed for finding actions), and an `access` field per connection telling you what you may run there. `access` is what One enforces for this key (the choices made on the consent page, or later in the dashboard), narrowed by any limits set with `one config`; `access.level` names it the way the consent page does: `full`, `read-write`, `read-only`, `custom` or `none`. When telling the user their access, use those words (Full access, Read & write, Read only, Custom, No access).
|
|
51
51
|
|
|
52
52
|
**Read `access` before you plan a workflow** — it saves you from discovering a restriction as a 403 halfway through:
|
|
53
53
|
|
|
@@ -57,6 +57,8 @@ Returns connected platforms with their connection keys (needed for execution), p
|
|
|
57
57
|
| `{"policy": "methods", "methods": ["GET"]}` | Only actions with these HTTP methods will execute — don't propose writes |
|
|
58
58
|
| `{"policy": "actions", "actions": [...]}` | Only these exact actions may run. Each has `actionId`, `title`, `method` — **use them directly**: `actions load <actionId>` reads their docs, no find needed |
|
|
59
59
|
|
|
60
|
+
`accessSource` is `"server"` when One reported the key's access, or `"local"` when it could not (the `accessHint` says so) — then `access` reflects only this CLI's settings and One may allow less: tell the user it is unverified rather than calling it full access.
|
|
61
|
+
|
|
60
62
|
Two more fields appear only when relevant:
|
|
61
63
|
- `"knowledgeOnly": true` — `actions execute` is disabled. `actions find` returns each action's whole document with how to call it from code; write integration code instead of executing.
|
|
62
64
|
- `"unresolvedActionIds": [...]` — allowlisted ids that couldn't be looked up; treat them as unavailable and tell the user.
|