@zerotal/arch 1.8.0 → 1.8.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/docs/changelog.md CHANGED
@@ -27,9 +27,42 @@ the section for every version you cross and apply its migration notes, not only
27
27
  majors. [Releases and versioning](/docs/support-policy#releases-and-versioning) explains
28
28
  when that carve-out ends.
29
29
 
30
+ ## 1.8.1 — 2026-08-26
31
+
32
+ DevTools showed you the wrong request, accurately.
33
+
34
+ ### Fixed
35
+
36
+ - **A page keeps the DevTools panel while its own assets load.** Opening `/login` selected
37
+ `/login`, then `/favicon.ico` a few milliseconds later, then `/css/app.css`. Live mode
38
+ selected every trace as it arrived and a page's sub-resources arrive right behind it, so the
39
+ bar named a request nobody asked about, the detail below described that request's headers
40
+ and its empty session, and the page you were inspecting had scrolled into the list. Nothing
41
+ shown was wrong; it was all about the wrong request.
42
+
43
+ Traces are now classified into three kinds rather than two, because "not the document" would
44
+ have suppressed the form post and the Inertia visit — the requests most worth watching. What
45
+ gets skipped over is narrower: a sub-resource the browser fetched on its own initiative. The
46
+ browser is asked rather than the URL, since an app may serve an API from a `.js` route and a
47
+ build that hashes its asset names has no extension to read; what was actually served is the
48
+ fallback, so a page fetched by `curl` still reads as a page. Anything unclassifiable counts
49
+ as app traffic, never as an asset — being wrong there decides whether a request is skipped,
50
+ and skipping the wrong one is how the panel stops showing what you came to see.
51
+
52
+ An asset still takes the selection when nothing else has it, so a panel opened mid-load
53
+ shows a request rather than an empty pane. A paused panel still counts assets toward its
54
+ pending badge.
55
+
56
+ ### Added
57
+
58
+ - **A `kind` facet on the DevTools All tab**, beside method and status. Assets were never the
59
+ problem, only their claim on the selection, so they are not hidden: pick `page` and `api`
60
+ for a list without fifty stylesheet fetches in it, or `asset` alone for what the browser
61
+ pulled in, what it cost and which of it 404'd — which was not visible anywhere before.
62
+
30
63
  ## 1.8.0 — 2026-08-24
31
64
 
32
- The first render mode, the codemod runner 2.0 depends on, and four failures that
65
+ The first render mode, the codemod runner 2.0 depends on, and five failures that
33
66
  each looked like something other than what they were.
34
67
 
35
68
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/arch",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "license": "MIT",
5
5
  "maturity": "stable",
6
6
  "private": false,
@@ -35,11 +35,11 @@
35
35
  "typecheck": "tsc --noEmit"
36
36
  },
37
37
  "dependencies": {
38
- "@zerotal/core": "1.8.0"
38
+ "@zerotal/core": "1.8.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "typescript": "^5.8.0",
42
- "@zerotal/orm": "1.8.0"
42
+ "@zerotal/orm": "1.8.1"
43
43
  },
44
44
  "description": "The Zerotal agent surface — an MCP server that hands coding agents the framework's machine-readable truth: exact API signatures, live routes and schema, version-matched docs, and `zt doctor`.",
45
45
  "keywords": [
@@ -16,7 +16,7 @@ import type { Application } from "@zerotal/core";
16
16
  import { ArchConfig } from "../config.ts";
17
17
  import type { ArchConfigShape } from "../config.ts";
18
18
  import { NoProjectRootError } from "../errors.ts";
19
- import { installedPackages } from "../probe/topics.ts";
19
+ import { declaredPackages } from "../probe/topics.ts";
20
20
  import { detectAgents } from "./detect.ts";
21
21
  import { agentsPreamble, buildGuidelines, claudeShim } from "./guidelines.ts";
22
22
  import { detectShape } from "./shape.ts";
@@ -54,7 +54,9 @@ export class ArchInstallCommand extends Command {
54
54
  const config = this._config();
55
55
 
56
56
  const detected = await detectAgents(root);
57
- const packages = (await installedPackages(root)).map((pkg) => pkg.name);
57
+ // Declared, not installed: what an install layout hoists into node_modules
58
+ // differs between machines, and the guidance must not.
59
+ const packages = (await declaredPackages(root)).map((pkg) => pkg.name);
58
60
  // Read off disk rather than from a booted app: a project that will not boot is
59
61
  // often exactly why someone is installing the agent surface.
60
62
  const shape = await detectShape(root);
@@ -304,3 +304,43 @@ export async function installedPackages(root = process.cwd()): Promise<Installed
304
304
  function controllerLabel(rawName: string): string {
305
305
  return rawName.startsWith("FileRoute<") ? "file" : rawName;
306
306
  }
307
+
308
+ /**
309
+ * The `@zerotal/*` packages this app *declares*, with their installed versions.
310
+ *
311
+ * {@link installedPackages} answers "what is on disk here", which is the right
312
+ * answer for a version report and the wrong one for guidance. Two things get into
313
+ * `node_modules/@zerotal` besides an app's own dependencies: transitive ones, and
314
+ * whatever an install layout decides to hoist — and layouts disagree. The same
315
+ * commit of one app resolved seventeen packages on a developer's machine and
316
+ * eleven on its server, because the server hoisted the shared ones to the
317
+ * workspace root instead.
318
+ *
319
+ * That is not a cosmetic difference when the list decides what an agent is told.
320
+ * `@zerotal/queue` arriving as a transitive dependency does not mean the app runs
321
+ * jobs, and a block explaining where jobs live is confidently wrong for an app
322
+ * that has none. It also made the generated file unstable between machines, so a
323
+ * check comparing it against the project could not tell drift from a difference
324
+ * of layout.
325
+ *
326
+ * Direct dependencies only, which is both deterministic and the honest reading of
327
+ * "what this app has": you import what you declare.
328
+ */
329
+ export async function declaredPackages(root = process.cwd()): Promise<InstalledPackage[]> {
330
+ let declared: Set<string>;
331
+ try {
332
+ const manifest = (await Bun.file(`${root}/package.json`).json()) as {
333
+ dependencies?: Record<string, string>;
334
+ devDependencies?: Record<string, string>;
335
+ };
336
+ declared = new Set([
337
+ ...Object.keys(manifest.dependencies ?? {}),
338
+ ...Object.keys(manifest.devDependencies ?? {}),
339
+ ]);
340
+ } catch {
341
+ // No manifest to read — every installed package is as good a guess as any.
342
+ return installedPackages(root);
343
+ }
344
+
345
+ return (await installedPackages(root)).filter((pkg) => declared.has(pkg.name));
346
+ }
@@ -142,7 +142,7 @@ export async function agentsFileCheck(
142
142
  };
143
143
  }
144
144
 
145
- const [{ buildGuidelines }, { detectShape }, { installedPackages }, markers] = await Promise.all([
145
+ const [{ buildGuidelines }, { detectShape }, { declaredPackages }, markers] = await Promise.all([
146
146
  import("../install/guidelines.ts"),
147
147
  import("../install/shape.ts"),
148
148
  import("../probe/topics.ts"),
@@ -160,7 +160,7 @@ export async function agentsFileCheck(
160
160
  };
161
161
  }
162
162
 
163
- const packages = (await installedPackages(root)).map((pkg) => pkg.name);
163
+ const packages = (await declaredPackages(root)).map((pkg) => pkg.name);
164
164
  const shape = await detectShape(root);
165
165
  const expected = buildGuidelines({
166
166
  packages,