@ory/argus 0.1.0 → 0.1.2

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.
@@ -7,7 +7,7 @@ preserving data volumes so you can restart later without losing state.
7
7
  Run:
8
8
 
9
9
  ```bash
10
- npx {{BIN}} local down
10
+ {{NPX}} local down
11
11
  ```
12
12
 
13
13
  To restart later, use {{REF_LOCAL_UP}}.
@@ -15,5 +15,5 @@ To restart later, use {{REF_LOCAL_UP}}.
15
15
  To stop **and** remove all data (full reset), run:
16
16
 
17
17
  ```bash
18
- npx {{BIN}} local reset
18
+ {{NPX}} local reset
19
19
  ```
@@ -7,7 +7,7 @@ and an Nginx gateway on port 4000.
7
7
  Run:
8
8
 
9
9
  ```bash
10
- npx {{BIN}} local up
10
+ {{NPX}} local up
11
11
  ```
12
12
 
13
13
  This will:
@@ -20,8 +20,8 @@ This will:
20
20
  After it completes, set the printed environment variables in your shell:
21
21
 
22
22
  ```bash
23
- eval "$(npx {{BIN}} local env)"
23
+ eval "$({{NPX}} local env)"
24
24
  ```
25
25
 
26
26
  If services are already running, stop them first with {{REF_LOCAL_DOWN}}
27
- or use `npx {{BIN}} local status` to check the current state.
27
+ or use `{{NPX}} local status` to check the current state.
@@ -14,7 +14,7 @@ manage the lifecycle:
14
14
  then seed a test identity, session, and permission tuples.
15
15
  - {{REF_LOCAL_DOWN}} — stop all services while preserving data volumes.
16
16
 
17
- Both delegate to `npx {{BIN}} local <subcommand>`, so the same
17
+ Both delegate to `{{NPX}} local <subcommand>`, so the same
18
18
  workflow runs from the shell when the command shortcuts are not available.
19
19
 
20
20
  ## When to use this skill
@@ -69,7 +69,7 @@ docker engine) and retry. Do not try to install Docker for them.
69
69
  Tell the user to run {{REF_LOCAL_UP}}, or the equivalent shell command:
70
70
 
71
71
  ```bash
72
- npx {{BIN}} local up
72
+ {{NPX}} local up
73
73
  ```
74
74
 
75
75
  Wait for the command to print "All services are running!" and the seed
@@ -79,7 +79,7 @@ output. Capture two values from the output:
79
79
  - `ORY_SESSION_TOKEN` (the seeded session token)
80
80
 
81
81
  If the user wants to skip seeding (to bring their own data), use
82
- `npx {{BIN}} local up --no-seed` instead.
82
+ `{{NPX}} local up --no-seed` instead.
83
83
 
84
84
  ## Step 3: Point the app at the local gateway
85
85
 
@@ -102,7 +102,7 @@ same value as `basePath` in the Ory `Configuration`.
102
102
  machine target the local stack):
103
103
 
104
104
  ```bash
105
- npx {{BIN}} local configure
105
+ {{NPX}} local configure
106
106
  ```
107
107
 
108
108
  This writes the URL to the shared plugin config so future agent runs
@@ -148,10 +148,10 @@ Common day-to-day commands:
148
148
 
149
149
  | Need | Command |
150
150
  |--------------------------------|------------------------------------------|
151
- | Re-seed (after `local reset`) | `npx {{BIN}} local seed` |
152
- | Tail Kratos logs | `npx {{BIN}} local logs kratos -f` |
153
- | Check what's running | `npx {{BIN}} local status` |
154
- | Print env vars to copy/paste | `npx {{BIN}} local env` |
151
+ | Re-seed (after `local reset`) | `{{NPX}} local seed` |
152
+ | Tail Kratos logs | `{{NPX}} local logs kratos -f` |
153
+ | Check what's running | `{{NPX}} local status` |
154
+ | Print env vars to copy/paste | `{{NPX}} local env` |
155
155
 
156
156
  If the user reports flaky behavior, run `local status` first to confirm
157
157
  each service is `healthy`. If a container is unhealthy, `local logs
@@ -161,14 +161,14 @@ have looked at logs.
161
161
  ## Step 7: Stop or reset
162
162
 
163
163
  When the user is done for the session, use {{REF_LOCAL_DOWN}} (equivalent:
164
- `npx {{BIN}} local down`). Containers stop but volumes
164
+ `{{NPX}} local down`). Containers stop but volumes
165
165
  remain, so the next {{REF_LOCAL_UP}} reuses the same identities,
166
166
  sessions, and tuples.
167
167
 
168
168
  For a full wipe (e.g., after schema changes or to clear test data):
169
169
 
170
170
  ```bash
171
- npx {{BIN}} local reset
171
+ {{NPX}} local reset
172
172
  ```
173
173
 
174
174
  `reset` removes data volumes and the generated `.ory-dev/ory/` directory.
@@ -179,8 +179,8 @@ plugin updates the bundled service configs.
179
179
 
180
180
  - **"Docker is not running"** — start Docker Desktop, then re-run
181
181
  {{REF_LOCAL_UP}}.
182
- - **Gateway never becomes healthy** — `npx {{BIN}} local logs
183
- gateway` and `npx {{BIN}} local logs kratos` to see which service
182
+ - **Gateway never becomes healthy** — `{{NPX}} local logs
183
+ gateway` and `{{NPX}} local logs kratos` to see which service
184
184
  failed. Port conflicts on `4000`, `4433`, `4444`, or `4466` are the
185
185
  usual culprit.
186
186
  - **Login works but `whoami` returns 401** — the cookie domain is
package/dist/dev.js CHANGED
@@ -127,8 +127,19 @@ function npmEnv() {
127
127
  // the local registry through an isolated pacote cache, with the user's
128
128
  // supply-chain freshness gate disabled (otherwise just-published tarballs
129
129
  // get filtered out as `ENOVERSIONS — No versions available`).
130
+ //
131
+ // `npm_config_userconfig` swaps the userconfig file from `~/.npmrc` to a
132
+ // launcher-managed npmrc that pins `@ory:registry` to the local Verdaccio.
133
+ // Without this, a developer-level `@ory:registry=…` line in their own
134
+ // `~/.npmrc` (left over from `npm login --scope=@ory` or similar) wins
135
+ // against `--registry` for scoped packages and routes the launcher's
136
+ // `npm install @ory/<harness>` — and the harness's own runtime `npx`
137
+ // calls — back to npmjs.org. The symptoms are ENOVERSIONS or tarball
138
+ // sha512 corruption depending on which side of the manifest/tarball
139
+ // split each subprocess hits.
130
140
  return {
131
141
  ...process.env,
142
+ npm_config_userconfig: (0, manager_js_1.ensureLauncherNpmrc)(),
132
143
  npm_config_registry: config_js_1.REGISTRY_URL,
133
144
  npm_config_cache: (0, manager_js_1.getLocalRegistryNpmCacheDir)(),
134
145
  npm_config_min_release_age: "0",
@@ -21,3 +21,20 @@ export declare const REGISTRY_CONTAINER_STORAGE = "/verdaccio/storage";
21
21
  export declare const REGISTRY_CONTAINER_CONFIG = "/verdaccio/conf/config.yaml";
22
22
  export declare function verdaccioConfigYaml(): string;
23
23
  export declare function npmrcContent(): string;
24
+ /**
25
+ * Userconfig file used by the dev launcher's npm/npx subprocesses.
26
+ *
27
+ * The scope-specific `@ory:registry=…` line is the critical bit. If a
28
+ * developer has ever run `npm login --scope=@ory` (or otherwise pinned
29
+ * `@ory:registry` in their `~/.npmrc`) to publish or fetch from npmjs.org,
30
+ * that pin takes precedence over `--registry` / `npm_config_registry` for
31
+ * scoped packages — so the launcher's `npm install @ory/<harness>` and the
32
+ * harness's own runtime `npx -y -p @ory/<harness>` calls silently hit
33
+ * npmjs.org instead of localhost, producing either `ENOVERSIONS` (because
34
+ * npmjs's manifest doesn't list the just-bumped local version) or a tarball
35
+ * sha512 mismatch (when the local manifest is consulted but npmjs serves
36
+ * the bytes). We expose this file as `npm_config_userconfig` so it
37
+ * displaces `~/.npmrc` entirely for subprocesses the launcher spawns,
38
+ * without modifying any global config or polluting the sandbox.
39
+ */
40
+ export declare function launcherNpmrcContent(): string;
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.REGISTRY_CONTAINER_CONFIG = exports.REGISTRY_CONTAINER_STORAGE = exports.REGISTRY_CONTAINER = exports.REGISTRY_IMAGE = exports.REGISTRY_DIR_NAME = exports.REGISTRY_URL = exports.REGISTRY_PORT = void 0;
14
14
  exports.verdaccioConfigYaml = verdaccioConfigYaml;
15
15
  exports.npmrcContent = npmrcContent;
16
+ exports.launcherNpmrcContent = launcherNpmrcContent;
16
17
  exports.REGISTRY_PORT = 4873;
17
18
  exports.REGISTRY_URL = `http://localhost:${exports.REGISTRY_PORT}`;
18
19
  exports.REGISTRY_DIR_NAME = ".ory-dev/registry";
@@ -44,15 +45,22 @@ uplinks:
44
45
  cache: false
45
46
 
46
47
  packages:
48
+ # @ory/client is a transitive Ory SDK dep that lives on npmjs.org — proxy
49
+ # it so installs can resolve it from upstream.
50
+ "@ory/client":
51
+ access: $all
52
+ publish: $all
53
+ proxy: npmjs
54
+
55
+ # All other @ory/* packages are workspace packages we publish locally.
56
+ # No proxy: if upstream were consulted, Verdaccio would merge npmjs.org's
57
+ # already-published versions into the manifest and reject every republish
58
+ # at the same version with "cannot publish over previously published
59
+ # versions: X.Y.Z".
47
60
  "@ory/*":
48
61
  access: $all
49
62
  publish: $all
50
63
  unpublish: $all
51
- # Locally-published workspace packages (e.g. @ory/argus) are served from
52
- # storage; everything else under @ory/* (notably @ory/client, a transitive
53
- # dep) falls through to npmjs. Without this, transitive @ory/client
54
- # resolution fails with E404 against the local registry.
55
- proxy: npmjs
56
64
 
57
65
  "**":
58
66
  access: $all
@@ -78,3 +86,26 @@ function npmrcContent() {
78
86
  //localhost:${exports.REGISTRY_PORT}/:_authToken=local-dev-token
79
87
  `;
80
88
  }
89
+ /**
90
+ * Userconfig file used by the dev launcher's npm/npx subprocesses.
91
+ *
92
+ * The scope-specific `@ory:registry=…` line is the critical bit. If a
93
+ * developer has ever run `npm login --scope=@ory` (or otherwise pinned
94
+ * `@ory:registry` in their `~/.npmrc`) to publish or fetch from npmjs.org,
95
+ * that pin takes precedence over `--registry` / `npm_config_registry` for
96
+ * scoped packages — so the launcher's `npm install @ory/<harness>` and the
97
+ * harness's own runtime `npx -y -p @ory/<harness>` calls silently hit
98
+ * npmjs.org instead of localhost, producing either `ENOVERSIONS` (because
99
+ * npmjs's manifest doesn't list the just-bumped local version) or a tarball
100
+ * sha512 mismatch (when the local manifest is consulted but npmjs serves
101
+ * the bytes). We expose this file as `npm_config_userconfig` so it
102
+ * displaces `~/.npmrc` entirely for subprocesses the launcher spawns,
103
+ * without modifying any global config or polluting the sandbox.
104
+ */
105
+ function launcherNpmrcContent() {
106
+ return `registry=${exports.REGISTRY_URL}/
107
+ @ory:registry=${exports.REGISTRY_URL}/
108
+ //localhost:${exports.REGISTRY_PORT}/:_authToken=local-dev-token
109
+ min-release-age=0
110
+ `;
111
+ }
@@ -19,6 +19,17 @@
19
19
  * pnpm publish/npm install even after we drop the version from Verdaccio.
20
20
  */
21
21
  export declare function getLocalRegistryNpmCacheDir(): string;
22
+ /**
23
+ * Path to the userconfig npmrc the dev launcher hands to its subprocesses.
24
+ * See `launcherNpmrcContent` in `./config.ts` for why this exists.
25
+ */
26
+ export declare function getLauncherNpmrcPath(): string;
27
+ /**
28
+ * Materialize the launcher userconfig npmrc on disk and return its path.
29
+ * Idempotent: rewrites the file every call so any drift in the rendered
30
+ * content (e.g. registry URL change) lands without a clean-and-restart.
31
+ */
32
+ export declare function ensureLauncherNpmrc(): string;
22
33
  /**
23
34
  * Start the local registry if it isn't already running.
24
35
  */
@@ -46,6 +46,8 @@ var __importStar = (this && this.__importStar) || (function () {
46
46
  })();
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.getLocalRegistryNpmCacheDir = getLocalRegistryNpmCacheDir;
49
+ exports.getLauncherNpmrcPath = getLauncherNpmrcPath;
50
+ exports.ensureLauncherNpmrc = ensureLauncherNpmrc;
49
51
  exports.ensureRegistryRunning = ensureRegistryRunning;
50
52
  exports.publishHarnessToLocal = publishHarnessToLocal;
51
53
  exports.registryStart = registryStart;
@@ -84,6 +86,24 @@ function getRegistryDir() {
84
86
  function getLocalRegistryNpmCacheDir() {
85
87
  return path.join(getRegistryDir(), "npm-cache");
86
88
  }
89
+ /**
90
+ * Path to the userconfig npmrc the dev launcher hands to its subprocesses.
91
+ * See `launcherNpmrcContent` in `./config.ts` for why this exists.
92
+ */
93
+ function getLauncherNpmrcPath() {
94
+ return path.join(getRegistryDir(), "launcher.npmrc");
95
+ }
96
+ /**
97
+ * Materialize the launcher userconfig npmrc on disk and return its path.
98
+ * Idempotent: rewrites the file every call so any drift in the rendered
99
+ * content (e.g. registry URL change) lands without a clean-and-restart.
100
+ */
101
+ function ensureLauncherNpmrc() {
102
+ const npmrcPath = getLauncherNpmrcPath();
103
+ ensureDir(path.dirname(npmrcPath));
104
+ fs.writeFileSync(npmrcPath, (0, config_js_1.launcherNpmrcContent)());
105
+ return npmrcPath;
106
+ }
87
107
  function ensureDir(dir) {
88
108
  if (!fs.existsSync(dir)) {
89
109
  fs.mkdirSync(dir, { recursive: true });
@@ -176,15 +196,28 @@ async function withLocalPublishConfig(workspaceRoot, fn) {
176
196
  async function cleanScopeStorage() {
177
197
  // Verdaccio caches package metadata in memory; deleting on-disk storage
178
198
  // alone leaves stale manifests served and causes publish to report
179
- // "already exists". Issue an HTTP DELETE for every known scoped package
180
- // first (Verdaccio drops both memory + disk state), then remove any
181
- // residual scope dir for completeness.
199
+ // "already exists". Issue an authenticated HTTP DELETE for every known
200
+ // scoped package first (Verdaccio drops both memory + disk state), then
201
+ // remove any residual scope dir for completeness.
202
+ //
203
+ // The Authorization header is required: Verdaccio silently rejects
204
+ // unauthenticated DELETEs, leaves its in-memory manifest intact, and then
205
+ // rewrites the on-disk `package.json` from that cache on the next publish
206
+ // — so the second publish sees the stale versions and fails with
207
+ // "cannot publish over previously published versions".
182
208
  const root = findProjectRoot(process.cwd());
183
209
  const names = listWorkspaceScopedPackages(root);
210
+ const token = readToken(getRegistryDir());
211
+ const headers = token
212
+ ? { Authorization: `Bearer ${token}` }
213
+ : {};
184
214
  await Promise.all(names.map(async (name) => {
185
215
  const encoded = name.replace("/", "%2f");
186
216
  try {
187
- await fetch(`${config_js_1.REGISTRY_URL}/${encoded}/-rev/0`, { method: "DELETE" });
217
+ await fetch(`${config_js_1.REGISTRY_URL}/${encoded}/-rev/0`, {
218
+ method: "DELETE",
219
+ headers,
220
+ });
188
221
  }
189
222
  catch {
190
223
  // Best-effort.
@@ -292,6 +325,48 @@ async function registerDevUser(registryDir) {
292
325
  fs.writeFileSync(getTokenFile(registryDir), token);
293
326
  return token;
294
327
  }
328
+ /**
329
+ * Restart the registry container if the rendered Verdaccio config has
330
+ * drifted from what's on disk. Verdaccio 6 does not hot-reload `config.yaml`,
331
+ * so a config change in the codebase has no effect on a running container
332
+ * until it restarts — and a stale config can silently keep mis-routing
333
+ * publishes through the upstream proxy. Called from `publishAllOryToLocal`
334
+ * so any code-bundled policy fix lands without an explicit `registry:clean`.
335
+ */
336
+ async function ensureConfigInSync(quiet) {
337
+ const registryDir = getRegistryDir();
338
+ // If the registry dir doesn't exist here, the running container was
339
+ // started from a different cwd (e.g. main repo while we're in a worktree,
340
+ // or vice versa). We don't own the on-disk state and writing a config
341
+ // file at this path wouldn't reach the container's bind mount anyway.
342
+ // Skip silently — the downstream auth-token check will surface a clear
343
+ // error if the caller actually needs local registry state.
344
+ if (!fs.existsSync(registryDir))
345
+ return;
346
+ const configPath = path.join(registryDir, "config.yaml");
347
+ const expected = (0, config_js_1.verdaccioConfigYaml)();
348
+ const current = fs.existsSync(configPath)
349
+ ? fs.readFileSync(configPath, "utf-8")
350
+ : "";
351
+ if (current === expected)
352
+ return;
353
+ if (!quiet) {
354
+ console.log("Verdaccio config out of date — restarting registry...");
355
+ }
356
+ fs.writeFileSync(configPath, expected);
357
+ const restart = (0, node_child_process_1.spawnSync)("docker", ["restart", config_js_1.REGISTRY_CONTAINER], {
358
+ stdio: ["ignore", "ignore", "pipe"],
359
+ encoding: "utf-8",
360
+ });
361
+ if (restart.status !== 0) {
362
+ const stderr = (restart.stderr ?? "").toString().trim();
363
+ throw new Error(`Failed to restart registry container after config change (exit ${restart.status}): ${stderr}`);
364
+ }
365
+ const ready = await waitForRegistry();
366
+ if (!ready) {
367
+ throw new Error("Registry did not come back online after config restart within 30 seconds.");
368
+ }
369
+ }
295
370
  // ─── Public lifecycle ──────────────────────────────────────────────
296
371
  /**
297
372
  * Start the local registry if it isn't already running.
@@ -362,6 +437,7 @@ async function publishAllOryToLocal(opts = {}) {
362
437
  if (!isRegistryRunning()) {
363
438
  throw new Error("Local registry is not running. Call ensureRegistryRunning() first.");
364
439
  }
440
+ await ensureConfigInSync(opts.quiet);
365
441
  const registryDir = getRegistryDir();
366
442
  const token = readToken(registryDir);
367
443
  if (!token) {
@@ -401,7 +477,25 @@ async function publishAllOryToLocal(opts = {}) {
401
477
  if (!fs.existsSync(tarball)) {
402
478
  throw new Error(`Packed ${pkgName} but expected tarball not found at ${tarball}.`);
403
479
  }
404
- const publishResult = (0, node_child_process_1.spawnSync)("npm", ["publish", tarball, "--registry", config_js_1.REGISTRY_URL, "--access=public"], {
480
+ // Scope-specific registry override. A developer who has run
481
+ // `npm login --scope=@ory` (or otherwise set `@ory:registry=…` in
482
+ // `~/.npmrc`) has a scope-pinned registry that takes precedence
483
+ // over `--registry` / `npm_config_registry` for scoped publishes.
484
+ // Without this flag, `npm publish` of an `@ory/*` tarball would
485
+ // silently target npmjs.org instead of localhost even though we
486
+ // strip `publishConfig.registry` and pass `--registry`.
487
+ const scope = packageScope(pkgName);
488
+ const scopeRegistryArg = scope
489
+ ? [`--${scope}:registry=${config_js_1.REGISTRY_URL}`]
490
+ : [];
491
+ const publishResult = (0, node_child_process_1.spawnSync)("npm", [
492
+ "publish",
493
+ tarball,
494
+ "--registry",
495
+ config_js_1.REGISTRY_URL,
496
+ ...scopeRegistryArg,
497
+ "--access=public",
498
+ ], {
405
499
  cwd: pkgDir,
406
500
  stdio: opts.quiet ? "pipe" : "inherit",
407
501
  encoding: "utf-8",
@@ -434,6 +528,14 @@ function readPackageNameVersion(pkgJsonPath) {
434
528
  function tarballFilename(pkgName, version) {
435
529
  return `${pkgName.replace(/^@/, "").replace("/", "-")}-${version}.tgz`;
436
530
  }
531
+ function packageScope(pkgName) {
532
+ if (!pkgName.startsWith("@"))
533
+ return null;
534
+ const slash = pkgName.indexOf("/");
535
+ if (slash < 0)
536
+ return null;
537
+ return pkgName.slice(0, slash);
538
+ }
437
539
  function emitCapturedOutput(quiet, label, result) {
438
540
  if (!quiet)
439
541
  return;
package/dist/skills.js CHANGED
@@ -126,6 +126,7 @@ function buildProfile(harness, opts) {
126
126
  tokens: {
127
127
  "{{BIN}}": opts.binName,
128
128
  "{{PKG}}": opts.packageName,
129
+ "{{NPX}}": `npx -y -p ${opts.packageName} ${opts.binName}`,
129
130
  "{{REF_AUTH_SETUP}}": skillRef("ory-auth-setup"),
130
131
  "{{REF_LOGIN_FLOW}}": skillRef("ory-login-flow"),
131
132
  "{{REF_SOCIAL_LOGIN}}": skillRef("ory-social-login"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ory/argus",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Ory Argus: the core API for building authentication, authorization, and audit into AI agent harness plugins, extensions, and custom integrations",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ory.com",
@@ -44,7 +44,9 @@
44
44
  "hydra"
45
45
  ],
46
46
  "publishConfig": {
47
- "access": "public"
47
+ "access": "public",
48
+ "registry": "https://registry.npmjs.org/",
49
+ "provenance": true
48
50
  },
49
51
  "main": "dist/index.js",
50
52
  "types": "dist/index.d.ts",