@openape/apes 0.6.1 → 0.7.1
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 +68 -6
- package/dist/auth-lock-SRUFWJC3.js +41 -0
- package/dist/auth-lock-SRUFWJC3.js.map +1 -0
- package/dist/{chunk-G3Q2TMAI.js → chunk-B32ZQP5K.js} +139 -190
- package/dist/chunk-B32ZQP5K.js.map +1 -0
- package/dist/{chunk-KVBHBOED.js → chunk-ION3CWD5.js} +14 -2
- package/dist/chunk-ION3CWD5.js.map +1 -0
- package/dist/chunk-TBYYREL6.js +133 -0
- package/dist/chunk-TBYYREL6.js.map +1 -0
- package/dist/cli.js +349 -213
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +11 -9
- package/dist/orchestrator-JAMWD6DD.js +637 -0
- package/dist/orchestrator-JAMWD6DD.js.map +1 -0
- package/dist/{server-FR6GFS3S.js → server-UTCZSPCU.js} +8 -6
- package/dist/{server-FR6GFS3S.js.map → server-UTCZSPCU.js.map} +1 -1
- package/dist/ssh-key-YBNNG5K5.js +10 -0
- package/package.json +4 -2
- package/dist/chunk-G3Q2TMAI.js.map +0 -1
- package/dist/chunk-KVBHBOED.js.map +0 -1
- package/dist/ssh-key-Q7KG4K25.js +0 -8
- /package/dist/{ssh-key-Q7KG4K25.js.map → ssh-key-YBNNG5K5.js.map} +0 -0
|
@@ -1,116 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var CONFIG_FILE = join(CONFIG_DIR, "config.toml");
|
|
10
|
-
function ensureDir() {
|
|
11
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
12
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
function loadAuth() {
|
|
16
|
-
if (!existsSync(AUTH_FILE))
|
|
17
|
-
return null;
|
|
18
|
-
try {
|
|
19
|
-
return JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
|
|
20
|
-
} catch {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function saveAuth(data) {
|
|
25
|
-
ensureDir();
|
|
26
|
-
writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
27
|
-
}
|
|
28
|
-
function clearAuth() {
|
|
29
|
-
if (existsSync(AUTH_FILE)) {
|
|
30
|
-
writeFileSync(AUTH_FILE, "", { mode: 384 });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function loadConfig() {
|
|
34
|
-
if (!existsSync(CONFIG_FILE))
|
|
35
|
-
return {};
|
|
36
|
-
try {
|
|
37
|
-
return parseTOML(readFileSync(CONFIG_FILE, "utf-8"));
|
|
38
|
-
} catch {
|
|
39
|
-
return {};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function parseTOML(content) {
|
|
43
|
-
const config = {};
|
|
44
|
-
let section = "";
|
|
45
|
-
for (const line of content.split("\n")) {
|
|
46
|
-
const trimmed = line.trim();
|
|
47
|
-
if (!trimmed || trimmed.startsWith("#"))
|
|
48
|
-
continue;
|
|
49
|
-
const sectionMatch = trimmed.match(/^\[(.+)\]$/);
|
|
50
|
-
if (sectionMatch) {
|
|
51
|
-
section = sectionMatch[1];
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
const kvMatch = trimmed.match(/^(\w+)\s*=\s*"(.+)"$/);
|
|
55
|
-
if (kvMatch) {
|
|
56
|
-
const [, key, value] = kvMatch;
|
|
57
|
-
if (section === "defaults") {
|
|
58
|
-
config.defaults = config.defaults || {};
|
|
59
|
-
config.defaults[key] = value;
|
|
60
|
-
} else if (section === "agent") {
|
|
61
|
-
config.agent = config.agent || {};
|
|
62
|
-
config.agent[key] = value;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return config;
|
|
67
|
-
}
|
|
68
|
-
function saveConfig(config) {
|
|
69
|
-
ensureDir();
|
|
70
|
-
const lines = [];
|
|
71
|
-
if (config.defaults) {
|
|
72
|
-
lines.push("[defaults]");
|
|
73
|
-
for (const [key, value] of Object.entries(config.defaults)) {
|
|
74
|
-
if (value)
|
|
75
|
-
lines.push(`${key} = "${value}"`);
|
|
76
|
-
}
|
|
77
|
-
lines.push("");
|
|
78
|
-
}
|
|
79
|
-
if (config.agent) {
|
|
80
|
-
lines.push("[agent]");
|
|
81
|
-
for (const [key, value] of Object.entries(config.agent)) {
|
|
82
|
-
if (value)
|
|
83
|
-
lines.push(`${key} = "${value}"`);
|
|
84
|
-
}
|
|
85
|
-
lines.push("");
|
|
86
|
-
}
|
|
87
|
-
writeFileSync(CONFIG_FILE, lines.join("\n"), { mode: 384 });
|
|
88
|
-
}
|
|
89
|
-
function getIdpUrl(explicit) {
|
|
90
|
-
if (explicit)
|
|
91
|
-
return explicit;
|
|
92
|
-
if (process.env.APES_IDP)
|
|
93
|
-
return process.env.APES_IDP;
|
|
94
|
-
const auth = loadAuth();
|
|
95
|
-
if (auth?.idp)
|
|
96
|
-
return auth.idp;
|
|
97
|
-
const config = loadConfig();
|
|
98
|
-
if (config.defaults?.idp)
|
|
99
|
-
return config.defaults.idp;
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
function getAuthToken() {
|
|
103
|
-
const auth = loadAuth();
|
|
104
|
-
if (!auth)
|
|
105
|
-
return null;
|
|
106
|
-
if (auth.expires_at && Date.now() / 1e3 > auth.expires_at - 30) {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
return auth.access_token;
|
|
110
|
-
}
|
|
111
|
-
function getRequesterIdentity() {
|
|
112
|
-
return loadAuth()?.email ?? null;
|
|
113
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
getAuthToken,
|
|
4
|
+
getIdpUrl,
|
|
5
|
+
loadAuth,
|
|
6
|
+
loadConfig,
|
|
7
|
+
saveAuth
|
|
8
|
+
} from "./chunk-TBYYREL6.js";
|
|
114
9
|
|
|
115
10
|
// src/http.ts
|
|
116
11
|
import consola from "consola";
|
|
@@ -165,12 +60,12 @@ async function refreshAgentToken() {
|
|
|
165
60
|
if (!keyPath)
|
|
166
61
|
return null;
|
|
167
62
|
try {
|
|
168
|
-
const { readFileSync:
|
|
63
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
169
64
|
const { sign } = await import("crypto");
|
|
170
|
-
const { homedir:
|
|
171
|
-
const { loadEd25519PrivateKey } = await import("./ssh-key-
|
|
172
|
-
const resolved = keyPath.replace(/^~/,
|
|
173
|
-
const keyContent =
|
|
65
|
+
const { homedir: homedir6 } = await import("os");
|
|
66
|
+
const { loadEd25519PrivateKey } = await import("./ssh-key-YBNNG5K5.js");
|
|
67
|
+
const resolved = keyPath.replace(/^~/, homedir6());
|
|
68
|
+
const keyContent = readFileSync5(resolved, "utf-8");
|
|
174
69
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
175
70
|
const challengeUrl = await getAgentChallengeEndpoint(auth.idp);
|
|
176
71
|
const challengeResp = await fetch(challengeUrl, {
|
|
@@ -205,10 +100,61 @@ async function refreshAgentToken() {
|
|
|
205
100
|
return null;
|
|
206
101
|
}
|
|
207
102
|
}
|
|
103
|
+
async function refreshOAuthToken() {
|
|
104
|
+
const auth = loadAuth();
|
|
105
|
+
if (!auth?.refresh_token)
|
|
106
|
+
return null;
|
|
107
|
+
const { acquireAuthLock, releaseAuthLock } = await import("./auth-lock-SRUFWJC3.js");
|
|
108
|
+
const lock = await acquireAuthLock({ timeoutMs: 5e3 });
|
|
109
|
+
if (!lock) {
|
|
110
|
+
return getAuthToken();
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const latest = loadAuth();
|
|
114
|
+
if (latest?.expires_at && Date.now() / 1e3 < latest.expires_at - 30)
|
|
115
|
+
return latest.access_token;
|
|
116
|
+
const activeRefreshToken = latest?.refresh_token ?? auth.refresh_token;
|
|
117
|
+
if (!activeRefreshToken)
|
|
118
|
+
return null;
|
|
119
|
+
const disco = await discoverEndpoints(auth.idp);
|
|
120
|
+
const tokenEndpoint = disco.token_endpoint || `${auth.idp}/token`;
|
|
121
|
+
const body = new URLSearchParams({
|
|
122
|
+
grant_type: "refresh_token",
|
|
123
|
+
refresh_token: activeRefreshToken
|
|
124
|
+
});
|
|
125
|
+
const resp = await fetch(tokenEndpoint, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
128
|
+
body: body.toString()
|
|
129
|
+
});
|
|
130
|
+
if (!resp.ok) {
|
|
131
|
+
if (resp.status === 400 || resp.status === 401) {
|
|
132
|
+
const base2 = latest ?? auth;
|
|
133
|
+
saveAuth({ ...base2, refresh_token: void 0 });
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const tokens = await resp.json();
|
|
138
|
+
const base = latest ?? auth;
|
|
139
|
+
saveAuth({
|
|
140
|
+
...base,
|
|
141
|
+
access_token: tokens.access_token,
|
|
142
|
+
refresh_token: tokens.refresh_token ?? base.refresh_token,
|
|
143
|
+
expires_at: Math.floor(Date.now() / 1e3) + (tokens.expires_in || 300)
|
|
144
|
+
});
|
|
145
|
+
if (debug)
|
|
146
|
+
consola.debug("Token refreshed via OAuth refresh_token");
|
|
147
|
+
return tokens.access_token;
|
|
148
|
+
} finally {
|
|
149
|
+
await releaseAuthLock(lock);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
208
152
|
async function apiFetch(path, options = {}) {
|
|
209
153
|
let token = options.token || getAuthToken();
|
|
210
154
|
if (!token) {
|
|
211
155
|
token = await refreshAgentToken();
|
|
156
|
+
if (!token)
|
|
157
|
+
token = await refreshOAuthToken();
|
|
212
158
|
}
|
|
213
159
|
if (!token) {
|
|
214
160
|
throw new Error("Not authenticated (token expired). Run `apes login` first.");
|
|
@@ -260,9 +206,9 @@ async function apiFetch(path, options = {}) {
|
|
|
260
206
|
|
|
261
207
|
// src/shapes/adapters.ts
|
|
262
208
|
import { createHash } from "crypto";
|
|
263
|
-
import { existsSync
|
|
264
|
-
import { homedir
|
|
265
|
-
import { basename, join
|
|
209
|
+
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
210
|
+
import { homedir } from "os";
|
|
211
|
+
import { basename, join } from "path";
|
|
266
212
|
|
|
267
213
|
// src/shapes/toml.ts
|
|
268
214
|
function parseKeyValue(line) {
|
|
@@ -382,20 +328,20 @@ function digest(content) {
|
|
|
382
328
|
}
|
|
383
329
|
function adapterDirs() {
|
|
384
330
|
return [
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
331
|
+
join(process.cwd(), ".openape", "shapes", "adapters"),
|
|
332
|
+
join(homedir(), ".openape", "shapes", "adapters"),
|
|
333
|
+
join("/etc", "openape", "shapes", "adapters")
|
|
388
334
|
];
|
|
389
335
|
}
|
|
390
336
|
function findByExecutable(executable) {
|
|
391
337
|
for (const dir of adapterDirs()) {
|
|
392
|
-
if (!
|
|
338
|
+
if (!existsSync(dir))
|
|
393
339
|
continue;
|
|
394
340
|
try {
|
|
395
341
|
const files = readdirSync(dir).filter((f) => f.endsWith(".toml"));
|
|
396
342
|
for (const file of files) {
|
|
397
|
-
const path =
|
|
398
|
-
const content =
|
|
343
|
+
const path = join(dir, file);
|
|
344
|
+
const content = readFileSync(path, "utf-8");
|
|
399
345
|
const match = content.match(/^\s*executable\s*=\s*"([^"]+)"/m);
|
|
400
346
|
if (match && match[1] === executable)
|
|
401
347
|
return path;
|
|
@@ -407,12 +353,12 @@ function findByExecutable(executable) {
|
|
|
407
353
|
}
|
|
408
354
|
function resolveAdapterPath(cliId, explicitPath) {
|
|
409
355
|
if (explicitPath) {
|
|
410
|
-
if (
|
|
356
|
+
if (existsSync(explicitPath))
|
|
411
357
|
return explicitPath;
|
|
412
358
|
throw new Error(`Adapter file not found: ${explicitPath}`);
|
|
413
359
|
}
|
|
414
|
-
const candidates = adapterDirs().map((dir) =>
|
|
415
|
-
const match = candidates.find((path) =>
|
|
360
|
+
const candidates = adapterDirs().map((dir) => join(dir, `${cliId}.toml`));
|
|
361
|
+
const match = candidates.find((path) => existsSync(path));
|
|
416
362
|
if (match)
|
|
417
363
|
return match;
|
|
418
364
|
const byExec = findByExecutable(cliId);
|
|
@@ -422,7 +368,7 @@ function resolveAdapterPath(cliId, explicitPath) {
|
|
|
422
368
|
}
|
|
423
369
|
function loadAdapter(cliId, explicitPath) {
|
|
424
370
|
const source = resolveAdapterPath(cliId, explicitPath);
|
|
425
|
-
const content =
|
|
371
|
+
const content = readFileSync(source, "utf-8");
|
|
426
372
|
const adapter = parseAdapterToml(content);
|
|
427
373
|
const idMatch = adapter.cli.id === cliId;
|
|
428
374
|
const fileMatch = basename(source) === `${cliId}.toml`;
|
|
@@ -444,11 +390,11 @@ function tryLoadAdapter(cliId, explicitPath) {
|
|
|
444
390
|
}
|
|
445
391
|
|
|
446
392
|
// src/shapes/audit.ts
|
|
447
|
-
import { appendFileSync, existsSync as
|
|
448
|
-
import { homedir as
|
|
449
|
-
import { dirname, join as
|
|
393
|
+
import { appendFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
394
|
+
import { homedir as homedir2 } from "os";
|
|
395
|
+
import { dirname, join as join2 } from "path";
|
|
450
396
|
function auditPath() {
|
|
451
|
-
return
|
|
397
|
+
return join2(homedir2(), ".config", "apes", "audit.jsonl");
|
|
452
398
|
}
|
|
453
399
|
function appendAuditLog(entry) {
|
|
454
400
|
const full = {
|
|
@@ -459,7 +405,7 @@ function appendAuditLog(entry) {
|
|
|
459
405
|
const path = auditPath();
|
|
460
406
|
const dir = dirname(path);
|
|
461
407
|
try {
|
|
462
|
-
if (!
|
|
408
|
+
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
|
|
463
409
|
appendFileSync(path, `${JSON.stringify(full)}
|
|
464
410
|
`);
|
|
465
411
|
} catch {
|
|
@@ -468,15 +414,15 @@ function appendAuditLog(entry) {
|
|
|
468
414
|
|
|
469
415
|
// src/shapes/installer.ts
|
|
470
416
|
import { createHash as createHash2 } from "crypto";
|
|
471
|
-
import { existsSync as
|
|
472
|
-
import { homedir as
|
|
473
|
-
import { join as
|
|
417
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
|
|
418
|
+
import { homedir as homedir3 } from "os";
|
|
419
|
+
import { join as join3 } from "path";
|
|
474
420
|
function adapterDir(local) {
|
|
475
|
-
const base = local ? process.cwd() :
|
|
476
|
-
return
|
|
421
|
+
const base = local ? process.cwd() : homedir3();
|
|
422
|
+
return join3(base, ".openape", "shapes", "adapters");
|
|
477
423
|
}
|
|
478
424
|
function adapterPath(id, local) {
|
|
479
|
-
return
|
|
425
|
+
return join3(adapterDir(local), `${id}.toml`);
|
|
480
426
|
}
|
|
481
427
|
function sha256(content) {
|
|
482
428
|
return `SHA-256:${createHash2("sha256").update(content).digest("hex")}`;
|
|
@@ -492,25 +438,25 @@ async function installAdapter(entry, options = {}) {
|
|
|
492
438
|
const digest2 = sha256(content);
|
|
493
439
|
if (digest2 !== entry.digest)
|
|
494
440
|
throw new Error(`Digest mismatch for ${entry.id}: expected ${entry.digest}, got ${digest2}`);
|
|
495
|
-
const updated =
|
|
496
|
-
if (!
|
|
497
|
-
|
|
498
|
-
|
|
441
|
+
const updated = existsSync3(dest);
|
|
442
|
+
if (!existsSync3(dir))
|
|
443
|
+
mkdirSync2(dir, { recursive: true });
|
|
444
|
+
writeFileSync(dest, content);
|
|
499
445
|
return { id: entry.id, path: dest, digest: digest2, updated };
|
|
500
446
|
}
|
|
501
447
|
function getInstalledDigest(id, local) {
|
|
502
448
|
const path = adapterPath(id, local);
|
|
503
|
-
if (!
|
|
449
|
+
if (!existsSync3(path))
|
|
504
450
|
return null;
|
|
505
|
-
const content =
|
|
451
|
+
const content = readFileSync2(path, "utf-8");
|
|
506
452
|
return sha256(content);
|
|
507
453
|
}
|
|
508
454
|
function isInstalled(id, local) {
|
|
509
|
-
return
|
|
455
|
+
return existsSync3(adapterPath(id, local));
|
|
510
456
|
}
|
|
511
457
|
function removeAdapter(id, local) {
|
|
512
458
|
const path = adapterPath(id, local);
|
|
513
|
-
if (!
|
|
459
|
+
if (!existsSync3(path))
|
|
514
460
|
return false;
|
|
515
461
|
unlinkSync(path);
|
|
516
462
|
return true;
|
|
@@ -518,16 +464,16 @@ function removeAdapter(id, local) {
|
|
|
518
464
|
function findConflictingAdapters(executable, excludeId) {
|
|
519
465
|
const conflicts = [];
|
|
520
466
|
const dirs = [
|
|
521
|
-
|
|
522
|
-
|
|
467
|
+
join3(process.cwd(), ".openape", "shapes", "adapters"),
|
|
468
|
+
join3(homedir3(), ".openape", "shapes", "adapters")
|
|
523
469
|
];
|
|
524
470
|
for (const dir of dirs) {
|
|
525
|
-
if (!
|
|
471
|
+
if (!existsSync3(dir))
|
|
526
472
|
continue;
|
|
527
473
|
try {
|
|
528
474
|
for (const file of readdirSync2(dir).filter((f) => f.endsWith(".toml"))) {
|
|
529
|
-
const path =
|
|
530
|
-
const content =
|
|
475
|
+
const path = join3(dir, file);
|
|
476
|
+
const content = readFileSync2(path, "utf-8");
|
|
531
477
|
const execMatch = content.match(/^\s*executable\s*=\s*"([^"]+)"/m);
|
|
532
478
|
const idMatch = content.match(/^\s*id\s*=\s*"([^"]+)"/m);
|
|
533
479
|
if (execMatch?.[1] === executable && idMatch?.[1] !== excludeId) {
|
|
@@ -541,23 +487,23 @@ function findConflictingAdapters(executable, excludeId) {
|
|
|
541
487
|
}
|
|
542
488
|
|
|
543
489
|
// src/shapes/registry.ts
|
|
544
|
-
import { existsSync as
|
|
545
|
-
import { homedir as
|
|
546
|
-
import { join as
|
|
490
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
491
|
+
import { homedir as homedir4 } from "os";
|
|
492
|
+
import { join as join4 } from "path";
|
|
547
493
|
var REGISTRY_URL = process.env.SHAPES_REGISTRY_URL ?? "https://raw.githubusercontent.com/openape-ai/shapes-registry/main/registry.json";
|
|
548
494
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
549
495
|
function cacheDir() {
|
|
550
|
-
return
|
|
496
|
+
return join4(homedir4(), ".openape", "shapes", "cache");
|
|
551
497
|
}
|
|
552
498
|
function cachePath() {
|
|
553
|
-
return
|
|
499
|
+
return join4(cacheDir(), "registry.json");
|
|
554
500
|
}
|
|
555
501
|
function readCache() {
|
|
556
502
|
const path = cachePath();
|
|
557
|
-
if (!
|
|
503
|
+
if (!existsSync4(path))
|
|
558
504
|
return null;
|
|
559
505
|
try {
|
|
560
|
-
const raw =
|
|
506
|
+
const raw = readFileSync3(path, "utf-8");
|
|
561
507
|
const stat = JSON.parse(raw);
|
|
562
508
|
if (stat._cached_at && Date.now() - stat._cached_at > CACHE_TTL_MS)
|
|
563
509
|
return null;
|
|
@@ -568,9 +514,9 @@ function readCache() {
|
|
|
568
514
|
}
|
|
569
515
|
function writeCache(index) {
|
|
570
516
|
const dir = cacheDir();
|
|
571
|
-
if (!
|
|
572
|
-
|
|
573
|
-
|
|
517
|
+
if (!existsSync4(dir))
|
|
518
|
+
mkdirSync3(dir, { recursive: true });
|
|
519
|
+
writeFileSync2(cachePath(), JSON.stringify({ ...index, _cached_at: Date.now() }, null, 2));
|
|
574
520
|
}
|
|
575
521
|
async function fetchRegistry(forceRefresh = false) {
|
|
576
522
|
if (!forceRefresh) {
|
|
@@ -591,11 +537,14 @@ function searchAdapters(index, query) {
|
|
|
591
537
|
(a) => a.id.includes(q) || a.name.toLowerCase().includes(q) || a.description.toLowerCase().includes(q) || a.tags.some((t) => t.includes(q)) || a.category.includes(q)
|
|
592
538
|
);
|
|
593
539
|
}
|
|
594
|
-
function findAdapter(index,
|
|
595
|
-
return index.adapters.find(
|
|
540
|
+
function findAdapter(index, idOrExecutable) {
|
|
541
|
+
return index.adapters.find(
|
|
542
|
+
(a) => a.id === idOrExecutable || a.executable === idOrExecutable
|
|
543
|
+
);
|
|
596
544
|
}
|
|
597
545
|
|
|
598
546
|
// src/shapes/shell-parser.ts
|
|
547
|
+
import { basename as basename2 } from "path";
|
|
599
548
|
import consola2 from "consola";
|
|
600
549
|
import { parse as shellParse } from "shell-quote";
|
|
601
550
|
var COMPOUND_OPERATORS = /* @__PURE__ */ new Set(["&&", "||", ";", "|", "&", ">", ">>", "<"]);
|
|
@@ -634,23 +583,24 @@ function extractShellCommandString(command) {
|
|
|
634
583
|
return command.slice(2).join(" ");
|
|
635
584
|
}
|
|
636
585
|
async function loadOrInstallAdapter(cliId) {
|
|
637
|
-
const
|
|
586
|
+
const lookupId = basename2(cliId);
|
|
587
|
+
const local = tryLoadAdapter(lookupId);
|
|
638
588
|
if (local) return local;
|
|
639
589
|
try {
|
|
640
590
|
const index = await fetchRegistry();
|
|
641
|
-
const entry = findAdapter(index,
|
|
591
|
+
const entry = findAdapter(index, lookupId);
|
|
642
592
|
if (!entry) return null;
|
|
643
|
-
consola2.info(`Installing shapes adapter for ${
|
|
593
|
+
consola2.info(`Installing shapes adapter for ${entry.id} from registry...`);
|
|
644
594
|
await installAdapter(entry, { local: false });
|
|
645
595
|
appendAuditLog({
|
|
646
596
|
action: "adapter-auto-install",
|
|
647
|
-
cli_id:
|
|
597
|
+
cli_id: entry.id,
|
|
648
598
|
digest: entry.digest,
|
|
649
599
|
source: "ape-shell"
|
|
650
600
|
});
|
|
651
|
-
return tryLoadAdapter(
|
|
601
|
+
return tryLoadAdapter(entry.id);
|
|
652
602
|
} catch (err) {
|
|
653
|
-
consola2.debug(`ape-shell adapter auto-install failed for ${
|
|
603
|
+
consola2.debug(`ape-shell adapter auto-install failed for ${lookupId}:`, err);
|
|
654
604
|
return null;
|
|
655
605
|
}
|
|
656
606
|
}
|
|
@@ -1026,15 +976,15 @@ import { hostname } from "os";
|
|
|
1026
976
|
import consola3 from "consola";
|
|
1027
977
|
|
|
1028
978
|
// src/shapes/config.ts
|
|
1029
|
-
import { existsSync as
|
|
1030
|
-
import { homedir as
|
|
1031
|
-
import { join as
|
|
1032
|
-
var
|
|
979
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
980
|
+
import { homedir as homedir5 } from "os";
|
|
981
|
+
import { join as join5 } from "path";
|
|
982
|
+
var AUTH_FILE = join5(homedir5(), ".config", "apes", "auth.json");
|
|
1033
983
|
function loadAuth2() {
|
|
1034
|
-
if (!
|
|
984
|
+
if (!existsSync5(AUTH_FILE))
|
|
1035
985
|
return null;
|
|
1036
986
|
try {
|
|
1037
|
-
return JSON.parse(
|
|
987
|
+
return JSON.parse(readFileSync4(AUTH_FILE, "utf-8"));
|
|
1038
988
|
} catch {
|
|
1039
989
|
return null;
|
|
1040
990
|
}
|
|
@@ -1056,7 +1006,7 @@ function getAuthToken2() {
|
|
|
1056
1006
|
return null;
|
|
1057
1007
|
return auth.access_token;
|
|
1058
1008
|
}
|
|
1059
|
-
function
|
|
1009
|
+
function getRequesterIdentity() {
|
|
1060
1010
|
return loadAuth2()?.email ?? null;
|
|
1061
1011
|
}
|
|
1062
1012
|
|
|
@@ -1103,7 +1053,7 @@ function decodePayload(token) {
|
|
|
1103
1053
|
}
|
|
1104
1054
|
async function createShapesGrant(resolved, params) {
|
|
1105
1055
|
const grantsEndpoint = await getGrantsEndpoint2(params.idp);
|
|
1106
|
-
const requester =
|
|
1056
|
+
const requester = getRequesterIdentity();
|
|
1107
1057
|
if (!requester) {
|
|
1108
1058
|
throw new Error("No requester identity available. Run `apes login` first.");
|
|
1109
1059
|
}
|
|
@@ -1153,7 +1103,7 @@ function grantedCliDetails(claims) {
|
|
|
1153
1103
|
function hasStructuredCliGrant(claims) {
|
|
1154
1104
|
return grantedCliDetails(claims).length > 0;
|
|
1155
1105
|
}
|
|
1156
|
-
async function
|
|
1106
|
+
async function verifyAndConsume(token, resolved) {
|
|
1157
1107
|
const payload = decodePayload(token);
|
|
1158
1108
|
const issuer = String(payload.iss ?? "");
|
|
1159
1109
|
if (!issuer)
|
|
@@ -1215,9 +1165,15 @@ async function verifyAndExecute(token, resolved) {
|
|
|
1215
1165
|
if (consumeResult.error) {
|
|
1216
1166
|
throw new Error(`Grant rejected at consume step: ${consumeResult.error}`);
|
|
1217
1167
|
}
|
|
1168
|
+
}
|
|
1169
|
+
function executeResolvedViaExec(resolved) {
|
|
1218
1170
|
consola3.info(`Executing ${(resolved.executionContext.argv ?? [resolved.executable, ...resolved.commandArgv]).join(" ")}`);
|
|
1219
1171
|
execFileSync(resolved.executable, resolved.commandArgv, { stdio: "inherit" });
|
|
1220
1172
|
}
|
|
1173
|
+
async function verifyAndExecute(token, resolved) {
|
|
1174
|
+
await verifyAndConsume(token, resolved);
|
|
1175
|
+
executeResolvedViaExec(resolved);
|
|
1176
|
+
}
|
|
1221
1177
|
async function findExistingGrant(resolved, idp) {
|
|
1222
1178
|
const grantsEndpoint = await getGrantsEndpoint2(idp);
|
|
1223
1179
|
const response = await apiFetch2(
|
|
@@ -1286,14 +1242,6 @@ async function buildStructuredCliGrantRequest(resolved, options) {
|
|
|
1286
1242
|
}
|
|
1287
1243
|
|
|
1288
1244
|
export {
|
|
1289
|
-
loadAuth,
|
|
1290
|
-
saveAuth,
|
|
1291
|
-
clearAuth,
|
|
1292
|
-
loadConfig,
|
|
1293
|
-
saveConfig,
|
|
1294
|
-
getIdpUrl,
|
|
1295
|
-
getAuthToken,
|
|
1296
|
-
getRequesterIdentity,
|
|
1297
1245
|
ApiError,
|
|
1298
1246
|
discoverEndpoints,
|
|
1299
1247
|
getGrantsEndpoint,
|
|
@@ -1323,9 +1271,10 @@ export {
|
|
|
1323
1271
|
createShapesGrant,
|
|
1324
1272
|
waitForGrantStatus,
|
|
1325
1273
|
fetchGrantToken,
|
|
1274
|
+
verifyAndConsume,
|
|
1326
1275
|
verifyAndExecute,
|
|
1327
1276
|
findExistingGrant,
|
|
1328
1277
|
buildExactCommandGrantRequest,
|
|
1329
1278
|
buildStructuredCliGrantRequest
|
|
1330
1279
|
};
|
|
1331
|
-
//# sourceMappingURL=chunk-
|
|
1280
|
+
//# sourceMappingURL=chunk-B32ZQP5K.js.map
|