@topolo/cli 0.12.4 → 0.12.7
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/dist/index.js +59 -11
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3799,10 +3799,10 @@ function runOrThrow(result, operation) {
|
|
|
3799
3799
|
}
|
|
3800
3800
|
function createPlatformInstallationSecretBackend(options = {}) {
|
|
3801
3801
|
const platform22 = options.platform ?? hostPlatform();
|
|
3802
|
-
const
|
|
3802
|
+
const spawn3 = options.spawn ?? ((command, args, spawnOptions) => spawnSync(command, args, spawnOptions));
|
|
3803
3803
|
const root = options.root ?? installationStorePath();
|
|
3804
3804
|
if (platform22 === "darwin") {
|
|
3805
|
-
const write = (account, value) => runOrThrow(
|
|
3805
|
+
const write = (account, value) => runOrThrow(spawn3("/usr/bin/expect", ["-c", MACOS_KEYCHAIN_WRITE_SCRIPT], {
|
|
3806
3806
|
input: `${value}
|
|
3807
3807
|
`,
|
|
3808
3808
|
encoding: "utf8",
|
|
@@ -3813,7 +3813,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3813
3813
|
}
|
|
3814
3814
|
}), "macOS Keychain write");
|
|
3815
3815
|
const read = (account) => {
|
|
3816
|
-
const result =
|
|
3816
|
+
const result = spawn3("security", [
|
|
3817
3817
|
"find-generic-password",
|
|
3818
3818
|
"-a",
|
|
3819
3819
|
account,
|
|
@@ -3825,7 +3825,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3825
3825
|
return runOrThrow(result, "macOS Keychain read");
|
|
3826
3826
|
};
|
|
3827
3827
|
const remove = (account) => {
|
|
3828
|
-
const result =
|
|
3828
|
+
const result = spawn3("security", [
|
|
3829
3829
|
"delete-generic-password",
|
|
3830
3830
|
"-a",
|
|
3831
3831
|
account,
|
|
@@ -3875,7 +3875,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3875
3875
|
if (platform22 === "linux") {
|
|
3876
3876
|
return {
|
|
3877
3877
|
async set(account, value) {
|
|
3878
|
-
runOrThrow(
|
|
3878
|
+
runOrThrow(spawn3("secret-tool", [
|
|
3879
3879
|
"store",
|
|
3880
3880
|
"--label=Topolo external agent installation",
|
|
3881
3881
|
"service",
|
|
@@ -3885,7 +3885,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3885
3885
|
], { input: value, encoding: "utf8" }), "Linux Secret Service write");
|
|
3886
3886
|
},
|
|
3887
3887
|
async get(account) {
|
|
3888
|
-
const result =
|
|
3888
|
+
const result = spawn3("secret-tool", [
|
|
3889
3889
|
"lookup",
|
|
3890
3890
|
"service",
|
|
3891
3891
|
KEYCHAIN_SERVICE,
|
|
@@ -3896,7 +3896,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3896
3896
|
return runOrThrow(result, "Linux Secret Service read");
|
|
3897
3897
|
},
|
|
3898
3898
|
async delete(account) {
|
|
3899
|
-
const result =
|
|
3899
|
+
const result = spawn3("secret-tool", [
|
|
3900
3900
|
"clear",
|
|
3901
3901
|
"service",
|
|
3902
3902
|
KEYCHAIN_SERVICE,
|
|
@@ -3909,7 +3909,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3909
3909
|
}
|
|
3910
3910
|
if (platform22 === "win32") {
|
|
3911
3911
|
const secretPath = (account) => join(root, ".secrets", `${account.replace(":", "-")}.bin`);
|
|
3912
|
-
const powershell = (script, path, input2) =>
|
|
3912
|
+
const powershell = (script, path, input2) => spawn3(
|
|
3913
3913
|
"powershell.exe",
|
|
3914
3914
|
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
3915
3915
|
{ input: input2, encoding: "utf8", env: { ...process.env, TOPOLO_SECRET_PATH: path } }
|
|
@@ -4748,7 +4748,9 @@ function formatPretty(info) {
|
|
|
4748
4748
|
}
|
|
4749
4749
|
|
|
4750
4750
|
// src/commands/actions.ts
|
|
4751
|
+
import { spawn as spawn2 } from "child_process";
|
|
4751
4752
|
import { readFileSync as readFileSync2 } from "fs";
|
|
4753
|
+
import { platform as platform3 } from "os";
|
|
4752
4754
|
import { basename, extname } from "path";
|
|
4753
4755
|
|
|
4754
4756
|
// src/commands/api.ts
|
|
@@ -4888,7 +4890,7 @@ function registerActionsCommand(program2) {
|
|
|
4888
4890
|
fail2(err, mode);
|
|
4889
4891
|
}
|
|
4890
4892
|
});
|
|
4891
|
-
actions.command("call <action>").description("Call a permission-scoped Topolo action").option("-d, --data <json-or-@file>", "JSON action input or @path to a JSON file", "{}").option("--resource-type <type>", "App-local resource alias, such as workspace").option("--resource-id <id>", "Resource id for the selected resource type").option("--confirm", "Acknowledge a mutating action").option("--detail", "Return the complete action response instead of a bounded agent projection").option("--json", "Output JSON").option("--no-json", "Output human-readable text").action(async (action, opts, command) => {
|
|
4893
|
+
actions.command("call <action>").description("Call a permission-scoped Topolo action").option("-d, --data <json-or-@file>", "JSON action input or @path to a JSON file", "{}").option("--resource-type <type>", "App-local resource alias, such as workspace").option("--resource-id <id>", "Resource id for the selected resource type").option("--confirm", "Acknowledge a mutating action").option("--no-browser", "Print an approval verification URL without opening it").option("--detail", "Return the complete action response instead of a bounded agent projection").option("--json", "Output JSON").option("--no-json", "Output human-readable text").action(async (action, opts, command) => {
|
|
4892
4894
|
const mode = resolveOutputMode(opts.json ?? command.parent?.opts().json);
|
|
4893
4895
|
try {
|
|
4894
4896
|
const topolo = await buildClient();
|
|
@@ -4901,8 +4903,16 @@ function registerActionsCommand(program2) {
|
|
|
4901
4903
|
confirm: opts.confirm === true,
|
|
4902
4904
|
...resource ? { resource } : {}
|
|
4903
4905
|
});
|
|
4904
|
-
const
|
|
4905
|
-
|
|
4906
|
+
const approval = externalApprovalHandoff(action, result);
|
|
4907
|
+
const detailed = detailRequested(opts.detail, command);
|
|
4908
|
+
const output = detailed ? result : {
|
|
4909
|
+
...compactActionResult(action, result),
|
|
4910
|
+
...approval ? { approval } : {}
|
|
4911
|
+
};
|
|
4912
|
+
const opened = approval && mode === "pretty" && opts.browser !== false ? tryOpenApproval(approval.verificationUrl) : false;
|
|
4913
|
+
emit(output, mode, () => approval ? `${JSON.stringify(output, null, 2)}
|
|
4914
|
+
|
|
4915
|
+
Approval required. ${opened ? "Opening" : "Open"} ${approval.verificationUrl}` : JSON.stringify(output, null, 2));
|
|
4906
4916
|
} catch (err) {
|
|
4907
4917
|
fail2(err, mode);
|
|
4908
4918
|
}
|
|
@@ -5023,6 +5033,44 @@ function registerActionsCommand(program2) {
|
|
|
5023
5033
|
}
|
|
5024
5034
|
});
|
|
5025
5035
|
}
|
|
5036
|
+
function externalApprovalHandoff(action, result) {
|
|
5037
|
+
if (!action.includes("agent_invocations.")) return null;
|
|
5038
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) return null;
|
|
5039
|
+
const invocation = result.invocation;
|
|
5040
|
+
if (!invocation || typeof invocation !== "object" || Array.isArray(invocation)) return null;
|
|
5041
|
+
const record2 = invocation;
|
|
5042
|
+
if (record2.status !== "awaiting_approval") return null;
|
|
5043
|
+
const approval = record2.approval;
|
|
5044
|
+
if (!approval || typeof approval !== "object" || Array.isArray(approval)) return null;
|
|
5045
|
+
const handoff = approval;
|
|
5046
|
+
if (typeof handoff.requestId !== "string" || typeof handoff.verificationUrl !== "string") return null;
|
|
5047
|
+
try {
|
|
5048
|
+
const url = new URL(handoff.verificationUrl);
|
|
5049
|
+
if (url.protocol !== "https:" || !/(^|\.)topolo\.(?:app|us|dev)$/.test(url.hostname)) return null;
|
|
5050
|
+
} catch {
|
|
5051
|
+
return null;
|
|
5052
|
+
}
|
|
5053
|
+
return {
|
|
5054
|
+
requestId: handoff.requestId,
|
|
5055
|
+
expiresAt: typeof handoff.expiresAt === "string" ? handoff.expiresAt : null,
|
|
5056
|
+
verificationUrl: handoff.verificationUrl
|
|
5057
|
+
};
|
|
5058
|
+
}
|
|
5059
|
+
function tryOpenApproval(url) {
|
|
5060
|
+
try {
|
|
5061
|
+
const os = platform3();
|
|
5062
|
+
const command = os === "darwin" ? "open" : os === "win32" ? "start" : "xdg-open";
|
|
5063
|
+
const child = spawn2(command, os === "win32" ? ["", url] : [url], {
|
|
5064
|
+
detached: true,
|
|
5065
|
+
stdio: "ignore",
|
|
5066
|
+
...os === "win32" ? { shell: true } : {}
|
|
5067
|
+
});
|
|
5068
|
+
child.unref();
|
|
5069
|
+
return true;
|
|
5070
|
+
} catch {
|
|
5071
|
+
return false;
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5026
5074
|
async function actionExecutionContext(topolo) {
|
|
5027
5075
|
const environment = selectedEnvironment();
|
|
5028
5076
|
const config = await readConfig();
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
3
|
"packageManager": "pnpm@10.17.1",
|
|
4
|
-
"version": "0.12.
|
|
5
|
-
"topoloPublishedVersion": "0.12.
|
|
4
|
+
"version": "0.12.7",
|
|
5
|
+
"topoloPublishedVersion": "0.12.7",
|
|
6
6
|
"description": "Public command-line interface for Topolo customer organizations, developers, and agents.",
|
|
7
7
|
"license": "UNLICENSED",
|
|
8
8
|
"author": "Topolo",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
31
|
-
"@topolo/mcp": "0.
|
|
31
|
+
"@topolo/mcp": "0.14.1",
|
|
32
32
|
"@topolo/sdk": "0.21.2",
|
|
33
33
|
"commander": "^12.1.0"
|
|
34
34
|
},
|