@withone/cli 2.0.0 → 2.2.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 +1 -0
- package/dist/index.js +32 -15
- package/package.json +1 -1
- package/skills/one/SKILL.md +1 -0
package/README.md
CHANGED
|
@@ -269,6 +269,7 @@ one actions find shopify "list products" -t knowledge
|
|
|
269
269
|
- **`--task`** describes the whole job in one line, in general terms, which helps choose between similar actions.
|
|
270
270
|
- **`-t knowledge`** searches the catalog for writing code and building flows and relays, which includes the platform's own (passthrough) endpoints; the default is the catalog for running actions now.
|
|
271
271
|
- **`--ai-model`** names the model running the CLI (e.g. `claude-sonnet-5`), for tuning documentation per model later.
|
|
272
|
+
- **`--no-knowledge`** lists the chosen actions (actionId, title, method, path) without fetching their documentation; load it later with `one actions load <actionId>`.
|
|
272
273
|
|
|
273
274
|
Each intent's answer gives the action(s) to use with their docs, any actions also needed beside them, a **substitute** when the model was unsure (use one or the other, never both), and a few alternatives, then says once how to execute. Always read the docs before executing. The access settings from `one config` apply: an action they refuse is never offered.
|
|
274
275
|
|
package/dist/index.js
CHANGED
|
@@ -1476,6 +1476,7 @@ var PORT_RANGE_START = 49152;
|
|
|
1476
1476
|
var PORT_RANGE_END = 65535;
|
|
1477
1477
|
var MAX_PORT_ATTEMPTS = 5;
|
|
1478
1478
|
var MAX_KEY_NAME_LENGTH = 120;
|
|
1479
|
+
var MAX_GRANT_LENGTH = 4e3;
|
|
1479
1480
|
var MAX_ERROR_LENGTH = 200;
|
|
1480
1481
|
var CHECK_MARK = `<div style="width:48px;height:48px;border-radius:50%;background:rgba(34,197,94,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 16px">
|
|
1481
1482
|
<svg width="24" height="24" fill="none" stroke="#22c55e" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
@@ -1539,9 +1540,10 @@ function startCallbackServer(expectedState) {
|
|
|
1539
1540
|
return;
|
|
1540
1541
|
}
|
|
1541
1542
|
const keyName = cleanParam(url.searchParams.get("name"), MAX_KEY_NAME_LENGTH);
|
|
1543
|
+
const grant = cleanParam(url.searchParams.get("grant"), MAX_GRANT_LENGTH);
|
|
1542
1544
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1543
1545
|
res.end(SUCCESS_HTML);
|
|
1544
|
-
resolveResult({ kind: "key", apiKey, keyName });
|
|
1546
|
+
resolveResult({ kind: "key", apiKey, keyName, grant });
|
|
1545
1547
|
return;
|
|
1546
1548
|
}
|
|
1547
1549
|
const error2 = cleanParam(url.searchParams.get("error"), MAX_ERROR_LENGTH);
|
|
@@ -1593,6 +1595,9 @@ function noteWidth() {
|
|
|
1593
1595
|
const usable = (typeof columns === "number" && columns > 0 ? columns : 80) - 8;
|
|
1594
1596
|
return Math.max(usable, 40);
|
|
1595
1597
|
}
|
|
1598
|
+
function grantNoteLines(grant, label) {
|
|
1599
|
+
return grant ? wrapForNote(`${label} ${grant}`).split("\n") : [];
|
|
1600
|
+
}
|
|
1596
1601
|
async function browserLogin(opts) {
|
|
1597
1602
|
const state = crypto.randomUUID();
|
|
1598
1603
|
const spin = createSpinner();
|
|
@@ -1650,7 +1655,7 @@ ${describeInstallContext(context)}`
|
|
|
1650
1655
|
const apiBase = getApiBase();
|
|
1651
1656
|
const api = new OneApi(outcome.apiKey, apiBase);
|
|
1652
1657
|
const whoami = await api.whoami();
|
|
1653
|
-
return { apiKey: outcome.apiKey, whoami, keyName: outcome.keyName };
|
|
1658
|
+
return { apiKey: outcome.apiKey, whoami, keyName: outcome.keyName, grant: outcome.grant };
|
|
1654
1659
|
} catch (err) {
|
|
1655
1660
|
spin.stop("Authentication failed.");
|
|
1656
1661
|
if (err instanceof Error && err.message === "timeout") {
|
|
@@ -1709,7 +1714,7 @@ async function loginCommand() {
|
|
|
1709
1714
|
}
|
|
1710
1715
|
const result = await browserLogin({ scope: targetScope });
|
|
1711
1716
|
if (!result) return;
|
|
1712
|
-
const { apiKey, whoami, keyName } = result;
|
|
1717
|
+
const { apiKey, whoami, keyName, grant } = result;
|
|
1713
1718
|
saveCredentials(apiKey, targetScope, { keyName, whoami });
|
|
1714
1719
|
const pc16 = (await import("picocolors")).default;
|
|
1715
1720
|
const env = getEnvFromApiKey(apiKey);
|
|
@@ -1724,6 +1729,7 @@ async function loginCommand() {
|
|
|
1724
1729
|
`${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`
|
|
1725
1730
|
];
|
|
1726
1731
|
if (keyName) infoLines.push(`${pc16.dim("Key:")} ${keyName}`);
|
|
1732
|
+
infoLines.push(...grantNoteLines(grant, pc16.dim("Access:")));
|
|
1727
1733
|
if (whoami.organization) infoLines.push(`${pc16.dim("Org:")} ${whoami.organization.name}`);
|
|
1728
1734
|
if (whoami.project) infoLines.push(`${pc16.dim("Project:")} ${whoami.project.name}`);
|
|
1729
1735
|
infoLines.push("");
|
|
@@ -1780,6 +1786,7 @@ async function nonInteractiveInit(options) {
|
|
|
1780
1786
|
const scope = options.global ? "global" : options.project ? "project" : "global";
|
|
1781
1787
|
let apiKey;
|
|
1782
1788
|
let keyName;
|
|
1789
|
+
let grant;
|
|
1783
1790
|
let whoami;
|
|
1784
1791
|
if (auth === "browser") {
|
|
1785
1792
|
const result = await browserLogin({ scope });
|
|
@@ -1788,6 +1795,7 @@ async function nonInteractiveInit(options) {
|
|
|
1788
1795
|
}
|
|
1789
1796
|
apiKey = result.apiKey;
|
|
1790
1797
|
keyName = result.keyName;
|
|
1798
|
+
grant = result.grant;
|
|
1791
1799
|
whoami = result.whoami;
|
|
1792
1800
|
} else {
|
|
1793
1801
|
const key = options.apiKey?.trim();
|
|
@@ -1834,6 +1842,7 @@ async function nonInteractiveInit(options) {
|
|
|
1834
1842
|
env: getEnvFromApiKey(apiKey)
|
|
1835
1843
|
},
|
|
1836
1844
|
keyName,
|
|
1845
|
+
grant,
|
|
1837
1846
|
skillInstalled: installed,
|
|
1838
1847
|
skillFailed: failed
|
|
1839
1848
|
});
|
|
@@ -1851,6 +1860,7 @@ async function nonInteractiveInit(options) {
|
|
|
1851
1860
|
console.log(` ${pc4.dim("Account:")} ${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}`);
|
|
1852
1861
|
console.log(` ${pc4.dim("User:")} ${whoami.user.name} ${pc4.dim(`(${whoami.user.email})`)}`);
|
|
1853
1862
|
if (keyName) console.log(` ${pc4.dim("Key:")} ${keyName}`);
|
|
1863
|
+
if (grant) console.log(` ${pc4.dim("Access:")} ${grant}`);
|
|
1854
1864
|
console.log(` ${pc4.dim("Config:")} ${tildify(configPath)}`);
|
|
1855
1865
|
if (installed.length > 0) {
|
|
1856
1866
|
console.log(` ${pc4.dim("Skill:")} ${pc4.green("installed")} ${pc4.dim("\xB7 " + installed.join(", "))}`);
|
|
@@ -2046,6 +2056,7 @@ async function handleUpdateKey(statuses, scope) {
|
|
|
2046
2056
|
}
|
|
2047
2057
|
let newKey;
|
|
2048
2058
|
let keyName;
|
|
2059
|
+
let grant;
|
|
2049
2060
|
let whoamiResult;
|
|
2050
2061
|
if (authMethod === "browser") {
|
|
2051
2062
|
const result = await browserLogin({ scope });
|
|
@@ -2055,6 +2066,7 @@ async function handleUpdateKey(statuses, scope) {
|
|
|
2055
2066
|
}
|
|
2056
2067
|
newKey = result.apiKey;
|
|
2057
2068
|
keyName = result.keyName;
|
|
2069
|
+
grant = result.grant;
|
|
2058
2070
|
whoamiResult = result.whoami;
|
|
2059
2071
|
} else {
|
|
2060
2072
|
p3.note(`Get your API key at:
|
|
@@ -2108,7 +2120,8 @@ ${pc4.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
|
2108
2120
|
[
|
|
2109
2121
|
`${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}`,
|
|
2110
2122
|
`${whoamiResult.user.name} ${pc4.dim(`(${whoamiResult.user.email})`)}`,
|
|
2111
|
-
...keyName ? [`${pc4.dim("Key:")} ${keyName}`] : []
|
|
2123
|
+
...keyName ? [`${pc4.dim("Key:")} ${keyName}`] : [],
|
|
2124
|
+
...grantNoteLines(grant, pc4.dim("Access:"))
|
|
2112
2125
|
].join("\n"),
|
|
2113
2126
|
"Account"
|
|
2114
2127
|
);
|
|
@@ -2370,7 +2383,8 @@ async function freshSetup(scope, options) {
|
|
|
2370
2383
|
[
|
|
2371
2384
|
`${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}`,
|
|
2372
2385
|
`${result.whoami.user.name} ${pc4.dim(`(${result.whoami.user.email})`)}`,
|
|
2373
|
-
...result.keyName ? [`${pc4.dim("Key:")} ${result.keyName}`] : []
|
|
2386
|
+
...result.keyName ? [`${pc4.dim("Key:")} ${result.keyName}`] : [],
|
|
2387
|
+
...grantNoteLines(result.grant, pc4.dim("Access:"))
|
|
2374
2388
|
].join("\n"),
|
|
2375
2389
|
"Account"
|
|
2376
2390
|
);
|
|
@@ -3580,7 +3594,7 @@ function document(action, details, platform, settings) {
|
|
|
3580
3594
|
truncated: true
|
|
3581
3595
|
};
|
|
3582
3596
|
}
|
|
3583
|
-
async function find(requests, task, deps, settings, knowledgeCatalog = false) {
|
|
3597
|
+
async function find(requests, task, deps, settings, { knowledgeCatalog = false, knowledge = true } = {}) {
|
|
3584
3598
|
if (requests.length === 0 || requests.length > FIND_MAX_INTENTS) {
|
|
3585
3599
|
throw new FindArgsError(`Send between 1 and ${FIND_MAX_INTENTS} platform and intent pairs.`);
|
|
3586
3600
|
}
|
|
@@ -3600,19 +3614,19 @@ async function find(requests, task, deps, settings, knowledgeCatalog = false) {
|
|
|
3600
3614
|
if (!reaches(intent.platform)) return { intent, unreachable: true };
|
|
3601
3615
|
const narrowed = narrow(answers[next++], settings);
|
|
3602
3616
|
const { answer } = narrowed;
|
|
3603
|
-
const picks = settings.knowledgeAgent ? answer.selected.slice(0, 1) : answer.selected;
|
|
3617
|
+
const picks = knowledge && settings.knowledgeAgent ? answer.selected.slice(0, 1) : answer.selected;
|
|
3604
3618
|
return {
|
|
3605
3619
|
intent,
|
|
3606
3620
|
unreachable: false,
|
|
3607
3621
|
narrowed,
|
|
3608
3622
|
picks,
|
|
3609
3623
|
deferred: [...answer.selected.slice(picks.length), ...answer.alsoSelected ?? []],
|
|
3610
|
-
runnerUpDocumented: !settings.knowledgeAgent && answer.runnerUp !== void 0
|
|
3624
|
+
runnerUpDocumented: knowledge && !settings.knowledgeAgent && answer.runnerUp !== void 0
|
|
3611
3625
|
};
|
|
3612
3626
|
});
|
|
3613
3627
|
const ids = /* @__PURE__ */ new Set();
|
|
3614
3628
|
for (const plan of plans) {
|
|
3615
|
-
if (plan.unreachable) continue;
|
|
3629
|
+
if (plan.unreachable || !knowledge) continue;
|
|
3616
3630
|
plan.picks.forEach((a) => ids.add(a.systemId));
|
|
3617
3631
|
if (plan.runnerUpDocumented && plan.narrowed.answer.runnerUp) ids.add(plan.narrowed.answer.runnerUp.systemId);
|
|
3618
3632
|
}
|
|
@@ -3646,9 +3660,9 @@ async function find(requests, task, deps, settings, knowledgeCatalog = false) {
|
|
|
3646
3660
|
};
|
|
3647
3661
|
}
|
|
3648
3662
|
const { answer } = plan.narrowed;
|
|
3649
|
-
const selected = [];
|
|
3663
|
+
const selected = knowledge ? [] : plan.picks.map(ref);
|
|
3650
3664
|
const deferred = [];
|
|
3651
|
-
for (const [index, pick] of plan.picks.entries()) {
|
|
3665
|
+
for (const [index, pick] of (knowledge ? plan.picks : []).entries()) {
|
|
3652
3666
|
const doc = document(ref(pick), details.get(pick.systemId) ?? new Error("not fetched"), plan.intent.platform, settings);
|
|
3653
3667
|
if (!admit(doc)) {
|
|
3654
3668
|
deferred.push(...plan.picks.slice(index).map(ref));
|
|
@@ -3676,7 +3690,7 @@ async function find(requests, task, deps, settings, knowledgeCatalog = false) {
|
|
|
3676
3690
|
result[index].runnerUp = doc;
|
|
3677
3691
|
}
|
|
3678
3692
|
});
|
|
3679
|
-
const documented = result.some((a) => a.selected.
|
|
3693
|
+
const documented = result.some((a) => a.selected.some((s) => "knowledge" in s) || a.runnerUp && "knowledge" in a.runnerUp);
|
|
3680
3694
|
return { answers: result, ...documented ? { guide: closingGuide(settings) } : {} };
|
|
3681
3695
|
}
|
|
3682
3696
|
async function load(actionIds, options, deps, settings) {
|
|
@@ -3844,7 +3858,9 @@ ${doc.knowledge}`;
|
|
|
3844
3858
|
const parts = [`## ${answer.platform}: ${answer.intent}
|
|
3845
3859
|
|
|
3846
3860
|
${answer.status}`];
|
|
3847
|
-
|
|
3861
|
+
const documented = answer.selected.filter((s) => "knowledge" in s);
|
|
3862
|
+
parts.push(...documented.map(shown));
|
|
3863
|
+
parts.push(...listing("Chosen for this intent", answer.selected.filter((s) => !("knowledge" in s))));
|
|
3848
3864
|
parts.push(
|
|
3849
3865
|
...listing(
|
|
3850
3866
|
answer.selected.length === 0 ? "Chosen for this intent, documentation left out to keep the answer small" : "Also chosen for this intent, documentation left out to keep the answer small",
|
|
@@ -3931,7 +3947,7 @@ async function actionsFindCommand(pairs, options) {
|
|
|
3931
3947
|
options.task,
|
|
3932
3948
|
findDeps(api, connectionKeys, options.cache !== false),
|
|
3933
3949
|
settings,
|
|
3934
|
-
options.type === "knowledge"
|
|
3950
|
+
{ knowledgeCatalog: options.type === "knowledge", knowledge: options.knowledge !== false }
|
|
3935
3951
|
);
|
|
3936
3952
|
if (isAgentMode()) {
|
|
3937
3953
|
json(result);
|
|
@@ -11427,6 +11443,7 @@ One call for the whole task: one platform and intent pair per operation, on any
|
|
|
11427
11443
|
- **\`--task\`** (optional) is the whole job in one line, **in general terms**: what it does, without names, addresses, IDs, or message text. It helps choose between similar actions.
|
|
11428
11444
|
- **\`-t knowledge\`** searches the catalog for writing code and building flows and relays, which includes the platform's own (passthrough) endpoints; the default, \`-t execute\`, is the catalog for running actions now. Knowledge-only mode always uses \`knowledge\`.
|
|
11429
11445
|
- **\`--ai-model\`** (optional) names the model running the CLI (e.g. \`claude-sonnet-5\`); it will be used to tune documentation per model.
|
|
11446
|
+
- **\`--no-knowledge\`** (optional) lists the chosen actions without their documentation, when only the actionIds are needed. Load the documentation with \`actions load\` before executing.
|
|
11430
11447
|
|
|
11431
11448
|
In \`--agent\` mode:
|
|
11432
11449
|
|
|
@@ -13176,7 +13193,7 @@ program.command("platforms").alias("p").description("List available platforms").
|
|
|
13176
13193
|
await platformsCommand(options);
|
|
13177
13194
|
});
|
|
13178
13195
|
var actions = program.command("actions").alias("a").description("Find, read, and execute platform actions (workflow: find \u2192 execute)");
|
|
13179
|
-
actions.command("find <pairs...>").alias("f").description('Find the action for every operation a task needs, across platforms, with its documentation, in one call: one actions find <platform> "<intent>" [<platform> "<intent>" ...] (up to 10 pairs). Each intent names the operation alone ("send an email"), without its data. Large documents come back as a digest; each names the exact `actions load` command for what it left out').option("--task <task>", 'The whole task in one line, in general terms (e.g. "email a report to a contact"): what it does, without names, addresses, IDs or message text. Helps choose between similar actions').option("-t, --type <type>", "execute (default: actions to run now) or knowledge (the catalog for writing code and building flows and relays, with the platform's own endpoints). Knowledge-only mode always uses knowledge").option("--ai-model <model>", "The AI model running the CLI (e.g. claude-sonnet-5), which helps optimize the documentation returned. Optional").option("--no-cache", "Bypass the cache for action documentation and re-fetch it (the fresh response still refreshes the cache)").action(async (pairs, options) => {
|
|
13196
|
+
actions.command("find <pairs...>").alias("f").description('Find the action for every operation a task needs, across platforms, with its documentation, in one call: one actions find <platform> "<intent>" [<platform> "<intent>" ...] (up to 10 pairs). Each intent names the operation alone ("send an email"), without its data. Large documents come back as a digest; each names the exact `actions load` command for what it left out').option("--task <task>", 'The whole task in one line, in general terms (e.g. "email a report to a contact"): what it does, without names, addresses, IDs or message text. Helps choose between similar actions').option("-t, --type <type>", "execute (default: actions to run now) or knowledge (the catalog for writing code and building flows and relays, with the platform's own endpoints). Knowledge-only mode always uses knowledge").option("--ai-model <model>", "The AI model running the CLI (e.g. claude-sonnet-5), which helps optimize the documentation returned. Optional").option("--no-cache", "Bypass the cache for action documentation and re-fetch it (the fresh response still refreshes the cache)").option("--no-knowledge", "List the chosen actions (actionId, title, method, path) without their documentation; load it with `one actions load <actionId>`").action(async (pairs, options) => {
|
|
13180
13197
|
await actionsFindCommand(pairs, options);
|
|
13181
13198
|
});
|
|
13182
13199
|
actions.command("load <actionIds...>").alias("l").description("More of an action's documentation (up to 10 actions): the digest by default, --section for one a digest left out, --full for the whole document, --toc for its contents. Also how to read an alternative from a find answer").option("--section <name>", 'Return only the named section(s) \u2014 by heading, id, or alias (e.g. "Response Fields", response, optional). Repeatable or comma-separated', collect, []).option("--full", "Return the whole document instead of the digest").option("--toc", "List every section (id, heading, size) without the document").option("--no-cache", "Bypass the cache and re-fetch from the API (the fresh response still refreshes the cache)").option("--cache-status", "Print cache metadata without fetching").action(async (actionIds, options) => {
|
package/package.json
CHANGED
package/skills/one/SKILL.md
CHANGED
|
@@ -83,6 +83,7 @@ one --agent actions find <platform> "<intent>" [<platform> "<intent>" ...] --tas
|
|
|
83
83
|
- **`--task`** (optional) is the whole job in one line, **in general terms**: `"email a weather report to a contact"`, without names, addresses, IDs, or message text. It helps choose between similar actions.
|
|
84
84
|
- **`-t knowledge`** searches the catalog for writing code and building flows and relays (it includes the platform's own passthrough endpoints); the default, `-t execute`, is the catalog for running actions now.
|
|
85
85
|
- **`--ai-model`** (optional): the model you are running as (e.g. `claude-sonnet-5`), used to tune documentation per model.
|
|
86
|
+
- **`--no-knowledge`** (optional): list the chosen actions without their documentation, when you only need the actionIds. Load the documentation with `actions load` before executing.
|
|
86
87
|
- Platform names are lowercase; multi-word names use dashes: `gmail`, `hubspot`, `ship-station`, `google-calendar`.
|
|
87
88
|
|
|
88
89
|
Each entry of `answers[]` carries:
|