@ornncompute/cli 0.2.16 → 0.2.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornncompute/cli",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "Command-line interface for Ornn compute access workflows.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/update.mjs CHANGED
@@ -125,7 +125,7 @@ export function detectInstallContext(binPath, env = process.env) {
125
125
  if (isNpmGlobalInstall(lower, env)) {
126
126
  return { kind: "npm", binPath: resolved };
127
127
  }
128
- if (isProjectInstall(resolved, lower)) {
128
+ if (isProjectInstall(resolved)) {
129
129
  return { kind: "project", binPath: resolved };
130
130
  }
131
131
  if (has(".bun") || isUnderDir(lower, env.BUN_INSTALL)) {
@@ -140,14 +140,15 @@ export function detectInstallContext(binPath, env = process.env) {
140
140
  return { kind: "npm", binPath: resolved };
141
141
  }
142
142
 
143
- function isProjectInstall(resolvedPath, lower) {
143
+ function isProjectInstall(resolvedPath) {
144
144
  // Global layouts have no package.json above node_modules; projects do.
145
- const index = lower.indexOf("/node_modules/");
146
- if (index < 0) {
145
+ const parts = resolvedPath.replaceAll("\\", "/").split("/");
146
+ const index = parts.findIndex((segment) => segment.toLowerCase() === "node_modules");
147
+ if (index <= 0) {
147
148
  return false;
148
149
  }
149
150
  try {
150
- return existsSync(join(resolvedPath.slice(0, index), "package.json"));
151
+ return existsSync(join(parts.slice(0, index).join("/"), "package.json"));
151
152
  } catch {
152
153
  return false;
153
154
  }
@@ -212,9 +213,13 @@ function stableInstallRoot(binPath) {
212
213
  try {
213
214
  resolved = realpathSync(binPath);
214
215
  } catch {}
215
- const normalized = resolved.replaceAll("\\", "/");
216
- const markerIndex = normalized.toLowerCase().indexOf("/node_modules/");
217
- return markerIndex > 0 ? normalized.slice(0, markerIndex) : null;
216
+ const parts = resolved.replaceAll("\\", "/").split("/");
217
+ const index = parts.findIndex((segment) => segment.toLowerCase() === "node_modules");
218
+ if (index <= 0) {
219
+ return null;
220
+ }
221
+ const prefix = parts.slice(0, index).join("/");
222
+ return prefix.length > 0 ? prefix : null;
218
223
  }
219
224
 
220
225
  function pathIdentity(path) {
@@ -200,7 +200,21 @@ export const sshKeyAddCapability = defineStaffMcpCapability({
200
200
  // (gateway `add_reservation_key`), which this tool previously bypassed by
201
201
  // posting `public_key` into a body that only reads `sshKeyId`/`userId`.
202
202
  let sshKeyId = parsed.sshKeyId;
203
- if (!sshKeyId) {
203
+ if (sshKeyId) {
204
+ // Commerce stores the id as a soft key without checking authorization,
205
+ // so gate it here the way gateway `add_reservation_key` does.
206
+ const listed = (await ctx.fetch(`/v1/organizations/${seg(parsed.tenantId)}/ssh-keys`, {
207
+ method: "GET",
208
+ }));
209
+ const key = (listed.ssh_keys ?? []).find((candidate) => candidate.id === sshKeyId);
210
+ if (!key) {
211
+ throw new Error("SSH key not found.");
212
+ }
213
+ if (key.status !== "active" || key.revoked_at) {
214
+ throw new Error("SSH key is not active.");
215
+ }
216
+ }
217
+ else {
204
218
  const registered = (await ctx.fetch(`/v1/organizations/${seg(parsed.tenantId)}/ssh-keys`, {
205
219
  method: "POST",
206
220
  body: { public_key: parsed.publicKey, ...mapBody(parsed, { label: "label" }) },