@topolo/cli 0.13.4 → 0.13.6
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.
|
@@ -10,7 +10,6 @@ import { spawn, spawnSync } from "child_process";
|
|
|
10
10
|
import { dirname, resolve, sep } from "path";
|
|
11
11
|
import { fileURLToPath } from "url";
|
|
12
12
|
import { createConnection } from "net";
|
|
13
|
-
import { tmpdir } from "os";
|
|
14
13
|
import { WebSocket } from "undici";
|
|
15
14
|
|
|
16
15
|
// src/lib/claude-native-pack.ts
|
|
@@ -53,6 +52,14 @@ async function nativeClaudePackOperation(manager, sidebar, plan, apply, checkpoi
|
|
|
53
52
|
if (!plan.noEffects && member.group !== null && groups.filter((g) => g.name === member.group).length > 1)
|
|
54
53
|
throw new Error("Ambiguous native sidebar group: " + member.group);
|
|
55
54
|
}
|
|
55
|
+
const nativeDescriptor = async (member) => {
|
|
56
|
+
if (typeof manager.getSessionWhenLoaded !== "function") throw new Error("Qualified native session descriptor API is unavailable.");
|
|
57
|
+
const descriptor = await manager.getSessionWhenLoaded(member.sessionId, "topolo-agent-pack", { warnOnMiss: false });
|
|
58
|
+
checkDeadline();
|
|
59
|
+
if (!descriptor || descriptor.sessionId !== member.sessionId || descriptor.cwd !== member.cwd || descriptor.title !== member.title)
|
|
60
|
+
throw new Error("Owned native session descriptor identity changed: " + member.key);
|
|
61
|
+
return descriptor;
|
|
62
|
+
};
|
|
56
63
|
const snapshot = async (members = plan.members) => {
|
|
57
64
|
const result = [];
|
|
58
65
|
for (const member of members) {
|
|
@@ -62,8 +69,13 @@ async function nativeClaudePackOperation(manager, sidebar, plan, apply, checkpoi
|
|
|
62
69
|
throw new Error("Owned session identity or active membership changed: " + member.key);
|
|
63
70
|
if (manager.hasLosableWork(member.sessionId) || session.isRunning || session.starting || session.pendingToolPermissions?.length)
|
|
64
71
|
throw new Error("Session has live or pending work; no changes permitted: " + member.key);
|
|
65
|
-
if (!plan.noEffects
|
|
66
|
-
|
|
72
|
+
if (!plan.noEffects) {
|
|
73
|
+
const descriptor = await nativeDescriptor(member);
|
|
74
|
+
if (manager.hasLosableWork(member.sessionId) || descriptor.isRunning || descriptor.starting || descriptor.pendingToolPermissions?.length)
|
|
75
|
+
throw new Error("Session has live or pending work; no changes permitted: " + member.key);
|
|
76
|
+
if (descriptor.backend?.kind !== "local" || descriptor.backend.remoteTarget || descriptor.worktreePath || descriptor.worktreeLazy || descriptor.spawnedFrom)
|
|
77
|
+
throw new Error("Incoming session is not a qualified local role.");
|
|
78
|
+
}
|
|
67
79
|
result.push({
|
|
68
80
|
key: member.key,
|
|
69
81
|
sessionId: session.sessionId,
|
|
@@ -92,8 +104,13 @@ async function nativeClaudePackOperation(manager, sidebar, plan, apply, checkpoi
|
|
|
92
104
|
throw new Error("Outgoing native identity differs.");
|
|
93
105
|
if (manager.hasLosableWork(member.sessionId) || session.isRunning || session.starting || session.pendingToolPermissions?.length)
|
|
94
106
|
throw new Error("Outgoing session has live or pending work.");
|
|
95
|
-
if (!plan.noEffects
|
|
96
|
-
|
|
107
|
+
if (!plan.noEffects) {
|
|
108
|
+
const descriptor = await nativeDescriptor(member);
|
|
109
|
+
if (manager.hasLosableWork(member.sessionId) || descriptor.isRunning || descriptor.starting || descriptor.pendingToolPermissions?.length)
|
|
110
|
+
throw new Error("Outgoing session has live or pending work.");
|
|
111
|
+
if (descriptor.backend?.kind !== "local" || descriptor.backend.remoteTarget || descriptor.worktreePath || descriptor.worktreeLazy || descriptor.spawnedFrom || !manager.archiveCascadeClosureOf || manager.archiveCascadeClosureOf(descriptor).length)
|
|
112
|
+
throw new Error("Outgoing native archive closure is not qualified.");
|
|
113
|
+
}
|
|
97
114
|
result.push({ key: member.key, sessionId: member.sessionId, cwd: session.cwd, title: session.title, archived: session.isArchived === true });
|
|
98
115
|
}
|
|
99
116
|
return result;
|
|
@@ -145,7 +162,8 @@ async function nativeClaudePackOperation(manager, sidebar, plan, apply, checkpoi
|
|
|
145
162
|
for (const member of plan.members) {
|
|
146
163
|
const session = await manager.getSession(member.sessionId);
|
|
147
164
|
if (session.isArchived) {
|
|
148
|
-
|
|
165
|
+
const descriptor = await nativeDescriptor(member);
|
|
166
|
+
if (descriptor.backend?.kind !== "local" || descriptor.backend.remoteTarget || descriptor.worktreePath || descriptor.worktreeLazy || descriptor.spawnedFrom)
|
|
149
167
|
throw new Error("Incoming session is not a qualified local role.");
|
|
150
168
|
await effect({ operation: "unarchive", sessionId: member.sessionId }, async () => {
|
|
151
169
|
await manager.unarchiveSession(member.sessionId);
|
|
@@ -311,9 +329,13 @@ async function nativeClaudeApprovalOperation(manager, routes, operation, fingerp
|
|
|
311
329
|
let state = manager[symbol];
|
|
312
330
|
if (state?.auditFailed) throw new Error("Native approval audit unavailable; use the original native interaction.");
|
|
313
331
|
const owned = async (route) => {
|
|
332
|
+
if (typeof manager.getSessionWhenLoaded !== "function") throw new Error("Qualified native session descriptor API is unavailable.");
|
|
333
|
+
const descriptor = await manager.getSessionWhenLoaded(route.sessionId, "topolo-agent-pack-approval", { warnOnMiss: false });
|
|
314
334
|
const session = await manager.getSession(route.sessionId);
|
|
315
|
-
if (!session || session.sessionId !== route.sessionId || session.cwd !== route.cwd || session.title !== route.title || session.isArchived
|
|
335
|
+
if (!session || session.sessionId !== route.sessionId || session.cwd !== route.cwd || session.title !== route.title || session.isArchived)
|
|
316
336
|
throw new Error("Native approval session identity differs: " + route.key);
|
|
337
|
+
if (!descriptor || descriptor.sessionId !== route.sessionId || descriptor.cwd !== route.cwd || descriptor.title !== route.title || descriptor.isArchived || descriptor.backend?.kind !== "local" || descriptor.backend.remoteTarget || descriptor.worktreePath || descriptor.worktreeLazy || descriptor.spawnedFrom)
|
|
338
|
+
throw new Error("Native approval session descriptor identity differs: " + route.key);
|
|
317
339
|
return session;
|
|
318
340
|
};
|
|
319
341
|
if (state && state.identity !== identity) {
|
|
@@ -816,7 +838,7 @@ async function configureClaudePack(options, evaluate = evaluateClaudeMain, quali
|
|
|
816
838
|
if (options.apply && plan.approvalRoutes.length) {
|
|
817
839
|
const directory2 = resolve(root, "claude/private");
|
|
818
840
|
mkdirSync(directory2, { recursive: true, mode: 448 });
|
|
819
|
-
const socketDirectory = resolve(
|
|
841
|
+
const socketDirectory = resolve("/tmp", "topolo-claude-pack-" + createHash("sha256").update(root).digest("hex").slice(0, 16));
|
|
820
842
|
mkdirSync(socketDirectory, { recursive: true, mode: 448 });
|
|
821
843
|
for (const path of [directory2, socketDirectory]) {
|
|
822
844
|
const stat = lstatSync(path);
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ function registerAgentPacksCommand(program2) {
|
|
|
10
10
|
const packs = program2.command("agent-packs").description("Install and operate Topolo Agent Packs in supported local hosts").option("--store <path>", "Portable pack library (default ~/AgentPacks)");
|
|
11
11
|
packs.command("configure").description("Qualify and configure an adopted Claude roster through its live native backend").argument("<pack>").option("--harness <name>", "Host adapter", "claude").requiredOption("--policy <path>", "Reviewed execution policy JSON").requiredOption("--endpoint <url>", "Explicit loopback main-process inspector endpoint, enabled separately with authorization").requiredOption("--pid <pid>", "Expected Claude main-process PID").option("--apply", "Apply native groups, pins, models, effort and permission modes; otherwise preflight only").action(async (pack, options) => {
|
|
12
12
|
if (options.harness !== "claude") throw new Error("Native configure is currently qualified only for Claude Desktop.");
|
|
13
|
-
const { configureClaudePack } = await import("./claude-pack-backend-
|
|
13
|
+
const { configureClaudePack } = await import("./claude-pack-backend-AWCWJJA5.js");
|
|
14
14
|
const result = await configureClaudePack({
|
|
15
15
|
store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
|
|
16
16
|
pack,
|
|
@@ -62,7 +62,7 @@ function registerAgentPacksCommand(program2) {
|
|
|
62
62
|
throw new Error("Only a one-request once/deny response is supported.");
|
|
63
63
|
decision = response.decision;
|
|
64
64
|
}
|
|
65
|
-
const { operateClaudeApprovals } = await import("./claude-pack-backend-
|
|
65
|
+
const { operateClaudeApprovals } = await import("./claude-pack-backend-AWCWJJA5.js");
|
|
66
66
|
console.log(JSON.stringify(await operateClaudeApprovals({
|
|
67
67
|
store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
|
|
68
68
|
kind: args[0],
|
|
@@ -77,7 +77,7 @@ function registerAgentPacksCommand(program2) {
|
|
|
77
77
|
if (options.policy || options.endpoint || options.pid || options.apply) {
|
|
78
78
|
if (options.harness !== "claude" || !options.policy || !options.endpoint || !options.pid || args.length !== 1)
|
|
79
79
|
throw new Error("Native switch/recovery requires one Claude pack, --policy, --endpoint and --pid.");
|
|
80
|
-
const { configureClaudePack } = await import("./claude-pack-backend-
|
|
80
|
+
const { configureClaudePack } = await import("./claude-pack-backend-AWCWJJA5.js");
|
|
81
81
|
const result2 = await configureClaudePack({
|
|
82
82
|
store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
|
|
83
83
|
pack: args[0],
|
|
@@ -124,7 +124,7 @@ import { platform as platform2 } from "os";
|
|
|
124
124
|
import { createInterface } from "readline/promises";
|
|
125
125
|
import { stdin as input } from "process";
|
|
126
126
|
|
|
127
|
-
// node_modules/@topolo/sdk/dist/index.js
|
|
127
|
+
// node_modules/.pnpm/@topolo+sdk@0.23.19/node_modules/@topolo/sdk/dist/index.js
|
|
128
128
|
function record(value) {
|
|
129
129
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
130
130
|
}
|
|
@@ -3734,10 +3734,10 @@ async function pollUntilApproved(params) {
|
|
|
3734
3734
|
throw new Error("Device code expired. Run `topolo auth login` again.");
|
|
3735
3735
|
}
|
|
3736
3736
|
|
|
3737
|
-
// node_modules/@topolo/sdk/dist/node/credential-store.js
|
|
3737
|
+
// node_modules/.pnpm/@topolo+sdk@0.23.19/node_modules/@topolo/sdk/dist/node/credential-store.js
|
|
3738
3738
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, chmod as chmod2, lstat, readdir as readdir2, rename as rename2, link } from "fs/promises";
|
|
3739
|
-
import { existsSync as existsSync2, lstatSync, readdirSync, readFileSync as readFileSync2, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync, rmdirSync } from "fs";
|
|
3740
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
3739
|
+
import { existsSync as existsSync2, mkdirSync, lstatSync, readdirSync, readFileSync as readFileSync2, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync, rmdirSync, linkSync } from "fs";
|
|
3740
|
+
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
3741
3741
|
import { homedir as homedir2, platform } from "os";
|
|
3742
3742
|
import { dirname as dirname2, join as join3 } from "path";
|
|
3743
3743
|
import { createHash, randomUUID } from "crypto";
|
|
@@ -4608,20 +4608,33 @@ var ConfigOwnershipError = class extends TopoloSdkError2 {
|
|
|
4608
4608
|
super("state_conflict", "Credential configuration ownership cannot be verified. Retain the unresolved operation instead of starting another renewal.");
|
|
4609
4609
|
}
|
|
4610
4610
|
};
|
|
4611
|
+
function lockEntryExists(path) {
|
|
4612
|
+
try {
|
|
4613
|
+
lstatSync(path);
|
|
4614
|
+
return true;
|
|
4615
|
+
} catch (error) {
|
|
4616
|
+
if (error.code === "ENOENT") return false;
|
|
4617
|
+
throw new ConfigOwnershipError();
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4611
4620
|
async function withConfigWriteLock(operation) {
|
|
4612
4621
|
const lockPath = `${configPath()}.lock`;
|
|
4613
4622
|
await mkdir2(dirname2(lockPath), { recursive: true });
|
|
4614
4623
|
const startedAt = performance.now();
|
|
4615
4624
|
while (true) {
|
|
4616
4625
|
try {
|
|
4626
|
+
if (lockEntryExists(lockPath + ".reconcile")) throw Object.assign(new Error(), { code: "EEXIST" });
|
|
4617
4627
|
await mkdir2(lockPath, { mode: 448 });
|
|
4628
|
+
if (lockEntryExists(lockPath + ".reconcile")) {
|
|
4629
|
+
throw new ConfigOwnershipError();
|
|
4630
|
+
}
|
|
4618
4631
|
break;
|
|
4619
4632
|
} catch (error) {
|
|
4620
4633
|
if (error.code !== "EEXIST") throw error;
|
|
4621
4634
|
if (performance.now() - startedAt >= CONFIG_LOCK_TIMEOUT_MS) {
|
|
4622
4635
|
throw new TopoloSdkError2("state_conflict", "Credential configuration is still held or unresolved. This waiter did not dispatch a renewal.");
|
|
4623
4636
|
}
|
|
4624
|
-
await new Promise((
|
|
4637
|
+
await new Promise((resolve22) => setTimeout(resolve22, CONFIG_LOCK_RETRY_MS));
|
|
4625
4638
|
}
|
|
4626
4639
|
}
|
|
4627
4640
|
const directory = await lstat(lockPath);
|
|
@@ -4632,7 +4645,7 @@ async function withConfigWriteLock(operation) {
|
|
|
4632
4645
|
await writeFile2(markerPath, marker, { flag: "wx", mode: 384 });
|
|
4633
4646
|
const assertDirectory = async () => {
|
|
4634
4647
|
const current = await lstat(lockPath);
|
|
4635
|
-
if (!current.isDirectory() || current.isSymbolicLink() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
4648
|
+
if (lockEntryExists(lockPath + ".reconcile") || !current.isDirectory() || current.isSymbolicLink() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
4636
4649
|
throw new ConfigOwnershipError();
|
|
4637
4650
|
};
|
|
4638
4651
|
const assertOwned = async () => {
|
|
@@ -4649,7 +4662,7 @@ async function withConfigWriteLock(operation) {
|
|
|
4649
4662
|
};
|
|
4650
4663
|
const assertDirectorySync = () => {
|
|
4651
4664
|
const current = lstatSync(lockPath);
|
|
4652
|
-
if (!current.isDirectory() || current.isSymbolicLink() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
4665
|
+
if (lockEntryExists(lockPath + ".reconcile") || !current.isDirectory() || current.isSymbolicLink() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
4653
4666
|
throw new ConfigOwnershipError();
|
|
4654
4667
|
};
|
|
4655
4668
|
const assertOwnedSync = () => {
|
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.13.
|
|
5
|
-
"topoloPublishedVersion": "0.13.
|
|
4
|
+
"version": "0.13.6",
|
|
5
|
+
"topoloPublishedVersion": "0.13.6",
|
|
6
6
|
"description": "Public command-line interface for Topolo customer organizations, developers, and agents.",
|
|
7
7
|
"license": "UNLICENSED",
|
|
8
8
|
"author": "Topolo",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
34
|
-
"@topolo/mcp": "0.14.
|
|
35
|
-
"@topolo/sdk": "0.23.
|
|
34
|
+
"@topolo/mcp": "0.14.24",
|
|
35
|
+
"@topolo/sdk": "0.23.19",
|
|
36
36
|
"commander": "^12.1.0",
|
|
37
37
|
"undici": "6.29.0"
|
|
38
38
|
},
|