@super-one/cli 0.50.3-alpha → 0.50.4-alpha
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/MANIFEST.json +2 -2
- package/lib/cli.mjs +72 -29
- package/package.json +1 -1
package/MANIFEST.json
CHANGED
package/lib/cli.mjs
CHANGED
|
@@ -170,7 +170,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
170
170
|
HOST_ACTION_SUPERONE_TOOL_DESCRIPTORS = [
|
|
171
171
|
{
|
|
172
172
|
"name": "session_collab_list_agents",
|
|
173
|
-
"description": "List the
|
|
173
|
+
"description": "List the agent profiles available for user-approved child sessions. Inspect each profile's harness and defaultConfig before session_collab_request. You may reuse one agentId for multiple launches.",
|
|
174
174
|
"inputSchema": {
|
|
175
175
|
"type": "object",
|
|
176
176
|
"properties": {},
|
|
@@ -179,7 +179,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
181
|
"name": "session_collab_request",
|
|
182
|
-
"description": 'Request approval for one or more child
|
|
182
|
+
"description": 'Request user approval for one or more child sessions. Call session_collab_list_agents first; repeat an agentId to reuse a profile. Invent a human-friendly name and a task-specific role for every launch. Omitted config fields inherit profile defaults. Before setting config.cwd or config.worktree, call read_manual({ domain: "product", topic: "collaboration" }); same-repo isolation belongs in config.worktree, not a worktree-leaf cwd. The user may edit model, effort, provider, permission, and sandbox settings. Each approved launch returns a private one-shot credential for session_collab_start.',
|
|
183
183
|
"inputSchema": {
|
|
184
184
|
"type": "object",
|
|
185
185
|
"properties": {
|
|
@@ -251,10 +251,12 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
251
251
|
]
|
|
252
252
|
},
|
|
253
253
|
"cwd": {
|
|
254
|
-
"type": "string"
|
|
254
|
+
"type": "string",
|
|
255
|
+
"description": 'Set only to a genuinely different project root. Omit for the current project. Never pass ~/.worktrees/... or another same-repo worktree leaf; use config.worktree for same-repo isolation. See read_manual({ domain: "product", topic: "collaboration" }).'
|
|
255
256
|
},
|
|
256
257
|
"worktree": {
|
|
257
258
|
"type": "object",
|
|
259
|
+
"description": 'Request a host-managed worktree for same-repo isolation while cwd stays omitted or at the project root. Set enabled, baseBranch, and mode; use a unique branchName with branch. See read_manual({ domain: "product", topic: "collaboration" }) for implementer and reviewer recipes.',
|
|
258
260
|
"properties": {
|
|
259
261
|
"enabled": {
|
|
260
262
|
"type": "boolean"
|
|
@@ -272,7 +274,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
272
274
|
},
|
|
273
275
|
"branchName": {
|
|
274
276
|
"type": "string",
|
|
275
|
-
"description": "
|
|
277
|
+
"description": 'With mode "branch", create this unique branch. Git cannot check out one branch in two worktrees.'
|
|
276
278
|
},
|
|
277
279
|
"carryLocalChanges": {
|
|
278
280
|
"type": "boolean"
|
|
@@ -310,7 +312,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
310
312
|
},
|
|
311
313
|
{
|
|
312
314
|
"name": "session_collab_start",
|
|
313
|
-
"description": "
|
|
315
|
+
"description": "Start the approved child session for one credential and deliver its task. The call returns when the child begins replying, not when its first turn finishes. A credential starts at most one session; retries return the same session id. Start all approved children back-to-back, then continue other work while they run asynchronously.",
|
|
314
316
|
"inputSchema": {
|
|
315
317
|
"type": "object",
|
|
316
318
|
"properties": {
|
|
@@ -326,7 +328,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
326
328
|
},
|
|
327
329
|
{
|
|
328
330
|
"name": "session_collab_send",
|
|
329
|
-
"description": "Send a persistent
|
|
331
|
+
"description": "Send a persistent Markdown message through one parent-child mailbox. Use clientMessageId for retry-safe delivery. The host wakes the peer and later wakes you when it replies. After sending, continue other work or end your turn. Never sleep, resend, or poll session_collab_retrieve while waiting.",
|
|
330
332
|
"inputSchema": {
|
|
331
333
|
"type": "object",
|
|
332
334
|
"properties": {
|
|
@@ -351,7 +353,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
351
353
|
},
|
|
352
354
|
{
|
|
353
355
|
"name": "session_collab_retrieve",
|
|
354
|
-
"description": 'Retrieve
|
|
356
|
+
"description": 'Retrieve queued Markdown messages for this session from one or more parent-child mailboxes. Call after a collaboration wake, or once before acting on peer input. This is a non-blocking read: status "empty" is not a retry signal. Do not sleep or poll; end your turn and wait for the next wake.',
|
|
355
357
|
"inputSchema": {
|
|
356
358
|
"type": "object",
|
|
357
359
|
"properties": {
|
|
@@ -3268,7 +3270,13 @@ var init_auth = __esm({
|
|
|
3268
3270
|
/** WebSocket ticket: 30 seconds, single /ws upgrade. */
|
|
3269
3271
|
wsTicketMs: 30 * 1e3,
|
|
3270
3272
|
/** Refresh family expires after 90 days of inactivity. */
|
|
3271
|
-
refreshInactivityMs: 90 * 24 * 60 * 60 * 1e3
|
|
3273
|
+
refreshInactivityMs: 90 * 24 * 60 * 60 * 1e3,
|
|
3274
|
+
/**
|
|
3275
|
+
* Immediately-previous refresh token remains redeemable this long after
|
|
3276
|
+
* rotation. Mitigates lost-response / concurrent-refresh races without
|
|
3277
|
+
* disabling reuse detection for older generations (RFC 6819 §5.2.2.3).
|
|
3278
|
+
*/
|
|
3279
|
+
refreshReuseGraceMs: 60 * 1e3
|
|
3272
3280
|
};
|
|
3273
3281
|
OPERATION_SCOPES = {
|
|
3274
3282
|
readEnvironment: ["environment:read"],
|
|
@@ -57179,8 +57187,8 @@ import { fileURLToPath } from "node:url";
|
|
|
57179
57187
|
function resolveCliReleaseVersion() {
|
|
57180
57188
|
const fromEnv = process.env.SUPERONE_CLI_VERSION?.trim();
|
|
57181
57189
|
if (fromEnv) return fromEnv;
|
|
57182
|
-
if ("0.50.
|
|
57183
|
-
return "0.50.
|
|
57190
|
+
if ("0.50.4-alpha".trim()) {
|
|
57191
|
+
return "0.50.4-alpha".trim();
|
|
57184
57192
|
}
|
|
57185
57193
|
const fromDist = readDistManifestVersion();
|
|
57186
57194
|
if (fromDist) return fromDist;
|
|
@@ -57525,26 +57533,52 @@ var AuthService = class {
|
|
|
57525
57533
|
return exchange();
|
|
57526
57534
|
}
|
|
57527
57535
|
/**
|
|
57528
|
-
* Rotate refresh credential
|
|
57529
|
-
*
|
|
57530
|
-
*
|
|
57536
|
+
* Rotate refresh credential.
|
|
57537
|
+
*
|
|
57538
|
+
* Reuse of a rotated refresh hash outside
|
|
57539
|
+
* {@link AUTH_CREDENTIAL_LIFETIMES.refreshReuseGraceMs} is treated as theft
|
|
57540
|
+
* and permanently revokes the family. Inside the grace window, presenting any
|
|
57541
|
+
* previously rotated hash re-rotates the *current* session and returns a fresh
|
|
57542
|
+
* pair (lost-response / concurrent-refresh races — RFC 6819 §5.2.2.3 style).
|
|
57543
|
+
*
|
|
57544
|
+
* Requires proof signature over `proofPayload` with the registered device key.
|
|
57531
57545
|
*/
|
|
57532
57546
|
refreshAccess(input) {
|
|
57533
57547
|
const refreshHash = this.hashSecret(input.refreshToken);
|
|
57534
57548
|
const now = Date.now();
|
|
57535
|
-
const
|
|
57549
|
+
const loadByHash = (hash2) => this.db.prepare(
|
|
57550
|
+
`SELECT client_session_id, device_public_key_pem, device_public_key_fingerprint,
|
|
57551
|
+
scopes_json, refresh_family_id, refresh_hash, refresh_expires_at, revoked_at
|
|
57552
|
+
FROM client_sessions WHERE refresh_hash = ?`
|
|
57553
|
+
).get(hash2);
|
|
57554
|
+
const loadBySessionId = (clientSessionId) => this.db.prepare(
|
|
57536
57555
|
`SELECT client_session_id, device_public_key_pem, device_public_key_fingerprint,
|
|
57537
|
-
|
|
57538
|
-
|
|
57539
|
-
).get(
|
|
57556
|
+
scopes_json, refresh_family_id, refresh_hash, refresh_expires_at, revoked_at
|
|
57557
|
+
FROM client_sessions WHERE client_session_id = ?`
|
|
57558
|
+
).get(clientSessionId);
|
|
57559
|
+
let row = loadByHash(refreshHash);
|
|
57540
57560
|
if (!row) {
|
|
57541
|
-
const reused = this.db.prepare(
|
|
57542
|
-
|
|
57543
|
-
|
|
57561
|
+
const reused = this.db.prepare(
|
|
57562
|
+
`SELECT client_session_id, seen_at FROM refresh_reuse_log WHERE refresh_hash = ?`
|
|
57563
|
+
).get(refreshHash);
|
|
57564
|
+
if (!reused) {
|
|
57565
|
+
throw Object.assign(new Error("invalid refresh token"), { code: "unauthorized" });
|
|
57566
|
+
}
|
|
57567
|
+
const withinGrace = now - reused.seen_at <= AUTH_CREDENTIAL_LIFETIMES.refreshReuseGraceMs;
|
|
57568
|
+
if (withinGrace) {
|
|
57569
|
+
row = loadBySessionId(reused.client_session_id);
|
|
57570
|
+
if (!row) {
|
|
57571
|
+
throw Object.assign(new Error("invalid refresh token"), { code: "unauthorized" });
|
|
57572
|
+
}
|
|
57573
|
+
} else {
|
|
57574
|
+
this.db.prepare(
|
|
57575
|
+
"UPDATE client_sessions SET revoked_at = ? WHERE client_session_id = ? AND revoked_at IS NULL"
|
|
57576
|
+
).run(now, reused.client_session_id);
|
|
57544
57577
|
this.onRevoke?.(reused.client_session_id);
|
|
57545
|
-
throw Object.assign(new Error("refresh token reuse detected; session revoked"), {
|
|
57578
|
+
throw Object.assign(new Error("refresh token reuse detected; session revoked"), {
|
|
57579
|
+
code: "unauthorized"
|
|
57580
|
+
});
|
|
57546
57581
|
}
|
|
57547
|
-
throw Object.assign(new Error("invalid refresh token"), { code: "unauthorized" });
|
|
57548
57582
|
}
|
|
57549
57583
|
if (row.revoked_at) throw Object.assign(new Error("client session revoked"), { code: "unauthorized" });
|
|
57550
57584
|
if (row.refresh_expires_at < now) {
|
|
@@ -57566,20 +57600,21 @@ var AuthService = class {
|
|
|
57566
57600
|
if (!Number.isFinite(proofTs) || Math.abs(now - proofTs) > 12e4) {
|
|
57567
57601
|
throw Object.assign(new Error("proof timestamp out of window"), { code: "unauthorized" });
|
|
57568
57602
|
}
|
|
57603
|
+
const session = row;
|
|
57569
57604
|
return this.db.transaction(() => {
|
|
57570
|
-
const scopes = parseScopes(
|
|
57605
|
+
const scopes = parseScopes(session.scopes_json);
|
|
57571
57606
|
const newRefresh = randomToken(32);
|
|
57572
57607
|
const newRefreshHash = this.hashSecret(newRefresh);
|
|
57573
57608
|
const refreshExpiresAt = now + AUTH_CREDENTIAL_LIFETIMES.refreshInactivityMs;
|
|
57574
57609
|
this.db.prepare(
|
|
57575
57610
|
`INSERT OR IGNORE INTO refresh_reuse_log (refresh_hash, client_session_id, seen_at)
|
|
57576
57611
|
VALUES (?, ?, ?)`
|
|
57577
|
-
).run(
|
|
57612
|
+
).run(session.refresh_hash, session.client_session_id, now);
|
|
57578
57613
|
const updated = this.db.prepare(
|
|
57579
57614
|
`UPDATE client_sessions
|
|
57580
57615
|
SET refresh_hash = ?, refresh_expires_at = ?, last_used_at = ?
|
|
57581
57616
|
WHERE client_session_id = ? AND refresh_hash = ? AND revoked_at IS NULL`
|
|
57582
|
-
).run(newRefreshHash, refreshExpiresAt, now,
|
|
57617
|
+
).run(newRefreshHash, refreshExpiresAt, now, session.client_session_id, session.refresh_hash);
|
|
57583
57618
|
if (updated.changes !== 1) {
|
|
57584
57619
|
throw Object.assign(new Error("refresh race; retry"), { code: "conflict" });
|
|
57585
57620
|
}
|
|
@@ -57589,15 +57624,15 @@ var AuthService = class {
|
|
|
57589
57624
|
aud: "superone",
|
|
57590
57625
|
exp: expiresAt,
|
|
57591
57626
|
iat: now,
|
|
57592
|
-
clientSessionId:
|
|
57627
|
+
clientSessionId: session.client_session_id,
|
|
57593
57628
|
scopes,
|
|
57594
|
-
proofKeyThumbprint:
|
|
57629
|
+
proofKeyThumbprint: session.device_public_key_fingerprint
|
|
57595
57630
|
});
|
|
57596
57631
|
return {
|
|
57597
57632
|
accessToken,
|
|
57598
57633
|
expiresAt,
|
|
57599
57634
|
scopes,
|
|
57600
|
-
clientSessionId:
|
|
57635
|
+
clientSessionId: session.client_session_id,
|
|
57601
57636
|
refreshToken: newRefresh
|
|
57602
57637
|
};
|
|
57603
57638
|
})();
|
|
@@ -61195,7 +61230,12 @@ function defaultProbeModels(ctx) {
|
|
|
61195
61230
|
return async (harnessId, cwd) => {
|
|
61196
61231
|
if (harnessId !== "claude") return [];
|
|
61197
61232
|
const binaryPath = resolveClaudeBinaryPath({ harnesses: ctx.harnesses });
|
|
61198
|
-
if (!binaryPath)
|
|
61233
|
+
if (!binaryPath) {
|
|
61234
|
+
console.warn(
|
|
61235
|
+
"[harness.resources] claude model probe skipped: no Agent SDK binary on this node (reinstall the optional platform package or set SUPERONE_CLAUDE_BINARY)"
|
|
61236
|
+
);
|
|
61237
|
+
return [];
|
|
61238
|
+
}
|
|
61199
61239
|
return getNodeClaudeModelCatalog({ cwd, binaryPath });
|
|
61200
61240
|
};
|
|
61201
61241
|
}
|
|
@@ -61233,6 +61273,9 @@ async function handleHarnessResources(payload, ctx) {
|
|
|
61233
61273
|
const probe = ctx.probeModels ?? defaultProbeModels(ctx);
|
|
61234
61274
|
const probed = await probe(hid, project.path);
|
|
61235
61275
|
if (probed.length > 0) return probed;
|
|
61276
|
+
console.warn(
|
|
61277
|
+
`[harness.resources] ${hid} probe returned no models; serving the built-in fallback table`
|
|
61278
|
+
);
|
|
61236
61279
|
return listHarnessModels(ctx.providers, hid, apiProviderId ?? null);
|
|
61237
61280
|
};
|
|
61238
61281
|
const bundle = await collectHarnessResources({
|
package/package.json
CHANGED