@openape/apes 0.15.1 → 0.16.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/dist/cli.js CHANGED
@@ -61,7 +61,7 @@ import {
61
61
  } from "./chunk-6GPSKAMU.js";
62
62
 
63
63
  // src/cli.ts
64
- import consola32 from "consola";
64
+ import consola33 from "consola";
65
65
 
66
66
  // src/ape-shell.ts
67
67
  import path from "path";
@@ -91,7 +91,7 @@ function rewriteApeShellArgs(argv, argv0) {
91
91
  }
92
92
 
93
93
  // src/cli.ts
94
- import { defineCommand as defineCommand39, runMain } from "citty";
94
+ import { defineCommand as defineCommand41, runMain } from "citty";
95
95
 
96
96
  // src/commands/auth/login.ts
97
97
  import { Buffer } from "buffer";
@@ -1820,7 +1820,7 @@ function buildDestroyTeardownScript(input) {
1820
1820
  return `#!/bin/bash
1821
1821
  # Best-effort teardown. set -u catches typos; we deliberately do NOT use -e
1822
1822
  # because pkill / launchctl are allowed to fail when the user has no live
1823
- # sessions, and dscl -delete is allowed to fail when the user is already gone.
1823
+ # sessions.
1824
1824
  set -u
1825
1825
 
1826
1826
  NAME=${shQuote(name)}
@@ -1837,7 +1837,32 @@ if [ -d "$HOME_DIR" ] && [ "$HOME_DIR" != "/" ] && [ "$HOME_DIR" != "" ]; then
1837
1837
  rm -rf "$HOME_DIR"
1838
1838
  fi
1839
1839
 
1840
- dscl . -delete "/Users/$NAME" 2>/dev/null || true
1840
+ # Delete the user record. \`sysadminctl -deleteUser\` is the canonical macOS
1841
+ # API and removes Open Directory metadata that \`dscl . -delete\` leaves
1842
+ # behind. Fall back to dscl if sysadminctl isn't available or rejects the
1843
+ # user. Surface a clear error if both fail \u2014 silent failure here is what
1844
+ # left orphaned dscl records on previous spawn/destroy round-trips.
1845
+ if command -v sysadminctl >/dev/null 2>&1; then
1846
+ if sysadminctl -deleteUser "$NAME" 2>/dev/null; then
1847
+ :
1848
+ elif dscl . -read "/Users/$NAME" >/dev/null 2>&1; then
1849
+ dscl . -delete "/Users/$NAME" || {
1850
+ echo "ERROR: failed to delete user record /Users/$NAME" >&2
1851
+ exit 1
1852
+ }
1853
+ fi
1854
+ elif dscl . -read "/Users/$NAME" >/dev/null 2>&1; then
1855
+ dscl . -delete "/Users/$NAME" || {
1856
+ echo "ERROR: failed to delete user record /Users/$NAME" >&2
1857
+ exit 1
1858
+ }
1859
+ fi
1860
+
1861
+ # Verify the record is actually gone.
1862
+ if dscl . -read "/Users/$NAME" >/dev/null 2>&1; then
1863
+ echo "ERROR: user record /Users/$NAME still exists after teardown" >&2
1864
+ exit 1
1865
+ fi
1841
1866
 
1842
1867
  echo "OK destroyed $NAME"
1843
1868
  `;
@@ -1998,6 +2023,18 @@ ${consequences.join("\n")}`);
1998
2023
  throw new CliExit(0);
1999
2024
  }
2000
2025
  }
2026
+ if (idpExists) {
2027
+ const id = encodeURIComponent(idpAgent.email);
2028
+ if (args.soft) {
2029
+ await apiFetch(`/api/my-agents/${id}`, { method: "PATCH", body: { isActive: false }, idp });
2030
+ consola18.success(`Deactivated IdP agent ${idpAgent.email}`);
2031
+ } else {
2032
+ await apiFetch(`/api/my-agents/${id}`, { method: "DELETE", idp });
2033
+ consola18.success(`Deleted IdP agent ${idpAgent.email}`);
2034
+ }
2035
+ } else {
2036
+ consola18.info("No IdP agent to remove (skipped).");
2037
+ }
2001
2038
  if (osUserExists) {
2002
2039
  const apes = whichBinary("apes");
2003
2040
  if (!apes) {
@@ -2021,18 +2058,6 @@ ${consequences.join("\n")}`);
2021
2058
  } else if (!args["keep-os-user"] && isDarwin()) {
2022
2059
  consola18.info("No macOS user to remove (skipped).");
2023
2060
  }
2024
- if (idpExists) {
2025
- const id = encodeURIComponent(idpAgent.email);
2026
- if (args.soft) {
2027
- await apiFetch(`/api/my-agents/${id}`, { method: "PATCH", body: { isActive: false }, idp });
2028
- consola18.success(`Deactivated IdP agent ${idpAgent.email}`);
2029
- } else {
2030
- await apiFetch(`/api/my-agents/${id}`, { method: "DELETE", idp });
2031
- consola18.success(`Deleted IdP agent ${idpAgent.email}`);
2032
- }
2033
- } else {
2034
- consola18.info("No IdP agent to remove (skipped).");
2035
- }
2036
2061
  consola18.success(`Destroyed ${name}.`);
2037
2062
  }
2038
2063
  });
@@ -3626,7 +3651,7 @@ var mcpCommand = defineCommand32({
3626
3651
  if (transport !== "stdio" && transport !== "sse") {
3627
3652
  throw new Error('Transport must be "stdio" or "sse"');
3628
3653
  }
3629
- const { startMcpServer } = await import("./server-VZ325IPS.js");
3654
+ const { startMcpServer } = await import("./server-NZMLYPN4.js");
3630
3655
  await startMcpServer(transport, port);
3631
3656
  }
3632
3657
  });
@@ -3977,11 +4002,131 @@ var registerUserCommand = defineCommand35({
3977
4002
  }
3978
4003
  });
3979
4004
 
3980
- // src/commands/dns-check.ts
4005
+ // src/commands/utils/index.ts
4006
+ import { defineCommand as defineCommand37 } from "citty";
4007
+
4008
+ // src/commands/utils/dig.ts
3981
4009
  import { defineCommand as defineCommand36 } from "citty";
3982
4010
  import consola30 from "consola";
3983
4011
  import { resolveDDISA as resolveDDISA2 } from "@openape/core";
3984
- var dnsCheckCommand = defineCommand36({
4012
+ var digCommand = defineCommand36({
4013
+ meta: {
4014
+ name: "dig",
4015
+ description: "Resolve DDISA IdP for a domain or email (admin/diag tool)"
4016
+ },
4017
+ args: {
4018
+ target: {
4019
+ type: "positional",
4020
+ description: "Domain (example.com) or email (alice@example.com)",
4021
+ required: true
4022
+ },
4023
+ json: {
4024
+ type: "boolean",
4025
+ description: "Machine-readable JSON output"
4026
+ }
4027
+ },
4028
+ async run({ args }) {
4029
+ const raw = String(args.target).trim();
4030
+ const at = raw.indexOf("@");
4031
+ const domain = at >= 0 ? raw.slice(at + 1) : raw;
4032
+ const localPart = at >= 0 ? raw.slice(0, at) : null;
4033
+ if (!domain || !/^[a-z0-9.-]+\.[a-z]{2,}$/i.test(domain)) {
4034
+ throw new CliError(`Invalid domain: ${domain}`);
4035
+ }
4036
+ const result = {
4037
+ input: raw,
4038
+ domain,
4039
+ localPart,
4040
+ ddisa: { found: false }
4041
+ };
4042
+ const ddisa = await resolveDDISA2(domain);
4043
+ if (ddisa) {
4044
+ result.ddisa = {
4045
+ found: true,
4046
+ idp: ddisa.idp,
4047
+ version: ddisa.version,
4048
+ mode: ddisa.mode,
4049
+ priority: ddisa.priority
4050
+ };
4051
+ try {
4052
+ const resp = await fetch(`${ddisa.idp}/.well-known/openid-configuration`);
4053
+ if (resp.ok) {
4054
+ const disco = await resp.json();
4055
+ result.idpDiscovery = {
4056
+ ok: true,
4057
+ status: resp.status,
4058
+ issuer: typeof disco.issuer === "string" ? disco.issuer : void 0,
4059
+ ddisaVersion: typeof disco.ddisa_version === "string" ? disco.ddisa_version : void 0,
4060
+ authMethods: Array.isArray(disco.ddisa_auth_methods_supported) ? disco.ddisa_auth_methods_supported : void 0,
4061
+ grantTypes: Array.isArray(disco.openape_grant_types_supported) ? disco.openape_grant_types_supported : void 0
4062
+ };
4063
+ } else {
4064
+ result.idpDiscovery = { ok: false, status: resp.status };
4065
+ }
4066
+ } catch (err) {
4067
+ result.idpDiscovery = { ok: false };
4068
+ result.hint = `IdP at ${ddisa.idp} unreachable: ${err instanceof Error ? err.message : String(err)}`;
4069
+ }
4070
+ } else {
4071
+ result.hint = `No DDISA record. Add a TXT record:
4072
+ _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}; mode=open"`;
4073
+ }
4074
+ if (args.json) {
4075
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
4076
+ `);
4077
+ if (!result.ddisa.found || result.idpDiscovery?.ok === false) process.exit(1);
4078
+ return;
4079
+ }
4080
+ console.log(`Target: ${raw}`);
4081
+ if (localPart) console.log(` user: ${localPart}`);
4082
+ console.log(` domain: ${domain}`);
4083
+ console.log("");
4084
+ if (!result.ddisa.found) {
4085
+ consola30.warn(`No DDISA record at _ddisa.${domain}`);
4086
+ if (result.hint) console.log(`
4087
+ ${result.hint}`);
4088
+ throw new CliError(`No DDISA record found for ${domain}`);
4089
+ }
4090
+ consola30.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
4091
+ console.log(` Version: ${result.ddisa.version || "ddisa1"}`);
4092
+ console.log(` IdP URL: ${result.ddisa.idp}`);
4093
+ if (result.ddisa.mode) console.log(` Mode: ${result.ddisa.mode}`);
4094
+ if (result.ddisa.priority !== void 0) console.log(` Priority: ${result.ddisa.priority}`);
4095
+ console.log("");
4096
+ if (!result.idpDiscovery) {
4097
+ return;
4098
+ }
4099
+ if (result.idpDiscovery.ok) {
4100
+ consola30.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
4101
+ if (result.idpDiscovery.issuer) console.log(` Issuer: ${result.idpDiscovery.issuer}`);
4102
+ if (result.idpDiscovery.ddisaVersion) console.log(` DDISA: v${result.idpDiscovery.ddisaVersion}`);
4103
+ if (result.idpDiscovery.authMethods?.length) console.log(` Auth: ${result.idpDiscovery.authMethods.join(", ")}`);
4104
+ if (result.idpDiscovery.grantTypes?.length) console.log(` Grants: ${result.idpDiscovery.grantTypes.join(", ")}`);
4105
+ } else {
4106
+ consola30.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
4107
+ if (result.hint) console.log(`
4108
+ ${result.hint}`);
4109
+ throw new CliError(`IdP at ${result.ddisa.idp} not reachable`);
4110
+ }
4111
+ }
4112
+ });
4113
+
4114
+ // src/commands/utils/index.ts
4115
+ var utilsCommand = defineCommand37({
4116
+ meta: {
4117
+ name: "utils",
4118
+ description: "Admin/diagnostic utilities (dig, \u2026)"
4119
+ },
4120
+ subCommands: {
4121
+ dig: digCommand
4122
+ }
4123
+ });
4124
+
4125
+ // src/commands/dns-check.ts
4126
+ import { defineCommand as defineCommand38 } from "citty";
4127
+ import consola31 from "consola";
4128
+ import { resolveDDISA as resolveDDISA3 } from "@openape/core";
4129
+ var dnsCheckCommand = defineCommand38({
3985
4130
  meta: {
3986
4131
  name: "dns-check",
3987
4132
  description: "Validate DDISA DNS TXT records for a domain"
@@ -3995,16 +4140,16 @@ var dnsCheckCommand = defineCommand36({
3995
4140
  },
3996
4141
  async run({ args }) {
3997
4142
  const domain = args.domain;
3998
- consola30.start(`Checking _ddisa.${domain}...`);
4143
+ consola31.start(`Checking _ddisa.${domain}...`);
3999
4144
  try {
4000
- const result = await resolveDDISA2(domain);
4145
+ const result = await resolveDDISA3(domain);
4001
4146
  if (!result) {
4002
4147
  console.log("");
4003
4148
  console.log("To set up DDISA, add a DNS TXT record:");
4004
4149
  console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
4005
4150
  throw new CliError(`No DDISA record found for ${domain}`);
4006
4151
  }
4007
- consola30.success(`_ddisa.${domain} \u2192 ${result.idp}`);
4152
+ consola31.success(`_ddisa.${domain} \u2192 ${result.idp}`);
4008
4153
  console.log("");
4009
4154
  console.log(` Version: ${result.version || "ddisa1"}`);
4010
4155
  console.log(` IdP URL: ${result.idp}`);
@@ -4013,14 +4158,14 @@ var dnsCheckCommand = defineCommand36({
4013
4158
  if (result.priority !== void 0)
4014
4159
  console.log(` Priority: ${result.priority}`);
4015
4160
  console.log("");
4016
- consola30.start(`Verifying IdP at ${result.idp}...`);
4161
+ consola31.start(`Verifying IdP at ${result.idp}...`);
4017
4162
  const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
4018
4163
  if (!discoResp.ok) {
4019
- consola30.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
4164
+ consola31.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
4020
4165
  return;
4021
4166
  }
4022
4167
  const disco = await discoResp.json();
4023
- consola30.success(`IdP is reachable`);
4168
+ consola31.success(`IdP is reachable`);
4024
4169
  console.log(` Issuer: ${disco.issuer}`);
4025
4170
  console.log(` DDISA: v${disco.ddisa_version || "?"}`);
4026
4171
  if (disco.ddisa_auth_methods_supported) {
@@ -4038,7 +4183,7 @@ var dnsCheckCommand = defineCommand36({
4038
4183
  // src/commands/health.ts
4039
4184
  import { exec } from "child_process";
4040
4185
  import { promisify } from "util";
4041
- import { defineCommand as defineCommand37 } from "citty";
4186
+ import { defineCommand as defineCommand39 } from "citty";
4042
4187
  var execAsync = promisify(exec);
4043
4188
  async function resolveApeShellPath() {
4044
4189
  try {
@@ -4074,7 +4219,7 @@ async function bestEffortGrantCount(idp) {
4074
4219
  }
4075
4220
  }
4076
4221
  async function runHealth(args) {
4077
- const version = true ? "0.15.1" : "0.0.0";
4222
+ const version = true ? "0.16.0" : "0.0.0";
4078
4223
  const auth = loadAuth();
4079
4224
  if (!auth) {
4080
4225
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -4137,7 +4282,7 @@ async function runHealth(args) {
4137
4282
  throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
4138
4283
  }
4139
4284
  }
4140
- var healthCommand = defineCommand37({
4285
+ var healthCommand = defineCommand39({
4141
4286
  meta: {
4142
4287
  name: "health",
4143
4288
  description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
@@ -4155,8 +4300,8 @@ var healthCommand = defineCommand37({
4155
4300
  });
4156
4301
 
4157
4302
  // src/commands/workflows.ts
4158
- import { defineCommand as defineCommand38 } from "citty";
4159
- import consola31 from "consola";
4303
+ import { defineCommand as defineCommand40 } from "citty";
4304
+ import consola32 from "consola";
4160
4305
 
4161
4306
  // src/guides/index.ts
4162
4307
  var guides = [
@@ -4206,7 +4351,7 @@ var guides = [
4206
4351
  ];
4207
4352
 
4208
4353
  // src/commands/workflows.ts
4209
- var workflowsCommand = defineCommand38({
4354
+ var workflowsCommand = defineCommand40({
4210
4355
  meta: {
4211
4356
  name: "workflows",
4212
4357
  description: "Discover workflow guides"
@@ -4227,7 +4372,7 @@ var workflowsCommand = defineCommand38({
4227
4372
  if (args.id) {
4228
4373
  const guide = guides.find((g) => g.id === String(args.id));
4229
4374
  if (!guide) {
4230
- consola31.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
4375
+ consola32.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
4231
4376
  throw new CliError(`Guide not found: ${args.id}`);
4232
4377
  }
4233
4378
  if (args.json) {
@@ -4276,10 +4421,10 @@ if (shellRewrite) {
4276
4421
  if (shellRewrite.action === "rewrite") {
4277
4422
  process.argv = shellRewrite.argv;
4278
4423
  } else if (shellRewrite.action === "version") {
4279
- console.log(`ape-shell ${"0.15.1"} (OpenApe DDISA shell wrapper)`);
4424
+ console.log(`ape-shell ${"0.16.0"} (OpenApe DDISA shell wrapper)`);
4280
4425
  process.exit(0);
4281
4426
  } else if (shellRewrite.action === "help") {
4282
- console.log(`ape-shell ${"0.15.1"} \u2014 OpenApe DDISA shell wrapper`);
4427
+ console.log(`ape-shell ${"0.16.0"} \u2014 OpenApe DDISA shell wrapper`);
4283
4428
  console.log("");
4284
4429
  console.log("Usage:");
4285
4430
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -4303,7 +4448,7 @@ if (shellRewrite) {
4303
4448
  }
4304
4449
  }
4305
4450
  var debug = process.argv.includes("--debug");
4306
- var grantsCommand = defineCommand39({
4451
+ var grantsCommand = defineCommand41({
4307
4452
  meta: {
4308
4453
  name: "grants",
4309
4454
  description: "Grant management"
@@ -4324,7 +4469,7 @@ var grantsCommand = defineCommand39({
4324
4469
  "delegation-revoke": delegationRevokeCommand
4325
4470
  }
4326
4471
  });
4327
- var configCommand = defineCommand39({
4472
+ var configCommand = defineCommand41({
4328
4473
  meta: {
4329
4474
  name: "config",
4330
4475
  description: "Configuration management"
@@ -4334,10 +4479,10 @@ var configCommand = defineCommand39({
4334
4479
  set: configSetCommand
4335
4480
  }
4336
4481
  });
4337
- var main = defineCommand39({
4482
+ var main = defineCommand41({
4338
4483
  meta: {
4339
4484
  name: "apes",
4340
- version: "0.15.1",
4485
+ version: "0.16.0",
4341
4486
  description: "Unified CLI for OpenApe"
4342
4487
  },
4343
4488
  subCommands: {
@@ -4345,6 +4490,7 @@ var main = defineCommand39({
4345
4490
  enroll: enrollCommand,
4346
4491
  "register-user": registerUserCommand,
4347
4492
  "dns-check": dnsCheckCommand,
4493
+ utils: utilsCommand,
4348
4494
  login: loginCommand,
4349
4495
  logout: logoutCommand,
4350
4496
  whoami: whoamiCommand,
@@ -4367,13 +4513,13 @@ runMain(main).catch((err) => {
4367
4513
  process.exit(err.exitCode);
4368
4514
  }
4369
4515
  if (err instanceof CliError) {
4370
- consola32.error(err.message);
4516
+ consola33.error(err.message);
4371
4517
  process.exit(err.exitCode);
4372
4518
  }
4373
4519
  if (debug) {
4374
- consola32.error(err);
4520
+ consola33.error(err);
4375
4521
  } else {
4376
- consola32.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
4522
+ consola33.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
4377
4523
  }
4378
4524
  process.exit(1);
4379
4525
  });