@agentskit/doc-bridge 1.11.2 → 1.12.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/README.md +3 -2
  3. package/action.yml +1 -1
  4. package/dist/cli/program.js +582 -470
  5. package/dist/cli/program.js.map +1 -1
  6. package/dist/index.d.ts +7 -2
  7. package/dist/index.js +500 -388
  8. package/dist/index.js.map +1 -1
  9. package/docs/DESIGN.md +71 -0
  10. package/docs/MARKETPLACE-ECOSYSTEM-PLAN.md +1 -1
  11. package/docs/PRD-enterprise-hardening.md +5 -5
  12. package/docs/PRD-knowledge-retrieval-and-enrichment.md +1 -1
  13. package/docs/knowledge-engine-runbook.md +1 -1
  14. package/docs/loop-workflow.md +15 -15
  15. package/docs/spec/config-v1.md +29 -7
  16. package/docs/spec/documentation-standard-v1.md +5 -0
  17. package/docs/spec/mcp-knowledge-tools-v1.md +1 -1
  18. package/docs/validation-cycle-plan.md +13 -13
  19. package/ecosystem-claims.json +23 -14
  20. package/ecosystem-upstream.json +3 -3
  21. package/ecosystem.json +318 -99
  22. package/mcpb/manifest.json +1 -1
  23. package/package.json +2 -1
  24. package/skills/doc-bridge-handoff/SKILL.md +1 -1
  25. package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
  26. package/src/conformance/ecosystem-contract.ts +10 -24
  27. package/src/discovery/repository.ts +7 -1
  28. package/src/findings/report.ts +1 -1
  29. package/src/fixes/proposals.ts +4 -2
  30. package/src/gates/run-gates.ts +1 -1
  31. package/src/index-builder/human-adapters/core.ts +10 -4
  32. package/src/lib/ignore-filter.ts +151 -0
  33. package/src/lib/walk.ts +10 -2
  34. package/src/memory/ingest.ts +1 -1
  35. package/src/report/html.ts +1 -1
  36. package/src/safety/repository.ts +9 -0
  37. package/src/version.ts +1 -1
  38. package/docs/DOGFOOD-ROUND2.md +0 -147
  39. package/docs/DOGFOOD-ROUND3.md +0 -79
  40. package/docs/DOGFOOD-V1.md +0 -89
  41. package/docs/DOGFOOD.md +0 -97
package/ecosystem.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "$comment": "Canonical registry of AgentsKit ecosystem products. Stable identity lives in products[]. Numeric values live in the generated ecosystem-claims ledger. The deprecated properties array remains a v1 compatibility shim for sibling consumers; do not treat properties as the product catalog.",
3
+ "$comment": "Canonical seven-product AgentsKit catalog. The three-entry properties array is the legacy v1 compatibility projection; shared navigation is derived from products[].",
4
4
  "parentBrand": {
5
5
  "id": "agentskit",
6
6
  "name": "AgentsKit"
@@ -9,7 +9,15 @@
9
9
  "canonicalDescription": "AgentsKit is the open-source TypeScript ecosystem for building production AI agents without locking application architecture to a model provider, framework, database, or hosted platform.",
10
10
  "metaDescription": "Open-source TypeScript ecosystem for production AI agents. Swap models, providers, tools, memory, RAG, and interfaces without architectural lock-in.",
11
11
  "commercialBoundary": "The listed products are free and open source.",
12
- "openSourceProductIds": ["agentskit", "registry", "agentskit-chat", "playbook", "doc-bridge", "code-review"],
12
+ "openSourceProductIds": [
13
+ "agentskit",
14
+ "registry",
15
+ "agentskit-chat",
16
+ "doc-bridge",
17
+ "code-review",
18
+ "harness",
19
+ "playbook"
20
+ ],
13
21
  "managedProductIds": []
14
22
  },
15
23
  "products": [
@@ -26,7 +34,7 @@
26
34
  "repo": "AgentsKit-io/agentskit",
27
35
  "accent": "#2EA043",
28
36
  "metadata": {
29
- "alternateName": "AgentsKit.js",
37
+ "alternateName": "AgentsKit",
30
38
  "description": "A free, MIT-licensed TypeScript ecosystem for production AI agents with replaceable contracts for models, runtimes, tools, memory, RAG, observability, sandboxing, evaluation, and interfaces.",
31
39
  "dateCreated": "2026-04-02",
32
40
  "applicationCategory": "DeveloperApplication",
@@ -57,11 +65,21 @@
57
65
  "claimSource": {
58
66
  "url": "https://www.agentskit.io/api/stats.json",
59
67
  "claims": {
60
- "packages": { "path": "counts.packages" },
61
- "core-size-kb-gzip": { "path": "coreSizeKbGzip" },
62
- "catalog-providers": { "path": "counts.catalogProviders" },
63
- "native-adapters": { "path": "counts.nativeAdapters" },
64
- "integrations": { "path": "counts.integrations" }
68
+ "packages": {
69
+ "path": "counts.packages"
70
+ },
71
+ "core-size-kb-gzip": {
72
+ "path": "coreSizeKbGzip"
73
+ },
74
+ "catalog-providers": {
75
+ "path": "counts.catalogProviders"
76
+ },
77
+ "native-adapters": {
78
+ "path": "counts.nativeAdapters"
79
+ },
80
+ "integrations": {
81
+ "path": "counts.integrations"
82
+ }
65
83
  }
66
84
  },
67
85
  "stage": "Build",
@@ -72,12 +90,30 @@
72
90
  "kind": "integration-stack",
73
91
  "headline": "Swap the stack. Keep the agent.",
74
92
  "metrics": [
75
- { "value": "140+", "label": "providers" },
76
- { "value": "25", "label": "adapters" },
77
- { "value": "50", "label": "integrations" }
93
+ {
94
+ "value": "140+",
95
+ "label": "providers"
96
+ },
97
+ {
98
+ "value": "25",
99
+ "label": "adapters"
100
+ },
101
+ {
102
+ "value": "50",
103
+ "label": "integrations"
104
+ }
78
105
  ],
79
- "capabilities": ["Tools", "RAG", "Memory", "MCP"],
80
- "steps": ["Choose any adapter", "Add tools and memory", "Ship without rewrites"]
106
+ "capabilities": [
107
+ "Tools",
108
+ "RAG",
109
+ "Memory",
110
+ "MCP"
111
+ ],
112
+ "steps": [
113
+ "Choose any adapter",
114
+ "Add tools and memory",
115
+ "Ship without rewrites"
116
+ ]
81
117
  },
82
118
  "cta": "Build with AgentsKit"
83
119
  },
@@ -95,9 +131,10 @@
95
131
  "next": [
96
132
  "registry",
97
133
  "agentskit-chat",
98
- "playbook",
99
134
  "doc-bridge",
100
- "code-review"
135
+ "code-review",
136
+ "harness",
137
+ "playbook"
101
138
  ]
102
139
  }
103
140
  },
@@ -117,8 +154,16 @@
117
154
  "claimSource": {
118
155
  "url": "https://registry.agentskit.io/r/index.json",
119
156
  "claims": {
120
- "agents": { "path": "agents", "aggregate": "length" },
121
- "remaining-categories": { "path": "agents", "aggregate": "distinct", "field": "category", "subtract": 5 }
157
+ "agents": {
158
+ "path": "agents",
159
+ "aggregate": "length"
160
+ },
161
+ "remaining-categories": {
162
+ "path": "agents",
163
+ "aggregate": "distinct",
164
+ "field": "category",
165
+ "subtract": 5
166
+ }
122
167
  }
123
168
  },
124
169
  "stage": "Discover",
@@ -127,12 +172,20 @@
127
172
  "proof": "Ready-made · source-owned",
128
173
  "sales": {
129
174
  "kind": "registry-install",
130
- "headline": "Source-owned agents for your project.",
175
+ "headline": "Inspect every file before it ships.",
131
176
  "metric": "Source-owned",
132
177
  "metricLabel": "agent code",
133
- "capabilities": ["Ready-made agents", "Source ownership", "CLI installation"],
134
- "steps": ["Find the right agent", "Run npx agentskit add", "Own every line"],
135
- "command": "npx agentskit add research"
178
+ "capabilities": [
179
+ "Ready-made agents",
180
+ "Source ownership",
181
+ "CLI installation"
182
+ ],
183
+ "steps": [
184
+ "Find the right agent",
185
+ "Run npx @agentskit/cli add",
186
+ "Own every line"
187
+ ],
188
+ "command": "npx @agentskit/cli add research"
136
189
  },
137
190
  "cta": "Explore the Registry"
138
191
  },
@@ -150,9 +203,10 @@
150
203
  "next": [
151
204
  "agentskit",
152
205
  "agentskit-chat",
153
- "playbook",
154
206
  "doc-bridge",
155
- "code-review"
207
+ "code-review",
208
+ "harness",
209
+ "playbook"
156
210
  ]
157
211
  }
158
212
  },
@@ -179,12 +233,29 @@
179
233
  "metric": "One",
180
234
  "metricLabel": "agent experience",
181
235
  "logos": [
182
- { "id": "human", "label": "Human" },
183
- { "id": "agent", "label": "Agent" },
184
- { "id": "tools", "label": "Tools" }
236
+ {
237
+ "id": "human",
238
+ "label": "Human"
239
+ },
240
+ {
241
+ "id": "agent",
242
+ "label": "Agent"
243
+ },
244
+ {
245
+ "id": "tools",
246
+ "label": "Tools"
247
+ }
185
248
  ],
186
- "capabilities": ["Conversation", "Human control", "Tool results"],
187
- "steps": ["Define the agent experience", "Connect the conversation surface", "Keep the human in control"]
249
+ "capabilities": [
250
+ "Conversation",
251
+ "Human control",
252
+ "Tool results"
253
+ ],
254
+ "steps": [
255
+ "Define the agent experience",
256
+ "Connect the conversation surface",
257
+ "Keep the human in control"
258
+ ]
188
259
  },
189
260
  "cta": "Explore AgentsKit Chat"
190
261
  },
@@ -201,62 +272,10 @@
201
272
  "next": [
202
273
  "agentskit",
203
274
  "registry",
204
- "playbook",
205
- "doc-bridge",
206
- "code-review"
207
- ]
208
- }
209
- },
210
- {
211
- "id": "playbook",
212
- "public": true,
213
- "distributionClass": "open-source",
214
- "name": "Agents Playbook",
215
- "shortName": "Playbook",
216
- "kind": "methodology",
217
- "role": "discipline",
218
- "promise": "Make agents ship code a human would actually merge.",
219
- "maturity": "stable",
220
- "repo": "AgentsKit-io/agents-playbook",
221
- "accent": "#8B5CF6",
222
- "showcase": {
223
- "stage": "Standardize",
224
- "headline": "Engineering standards agents can execute.",
225
- "detail": "Turn repeatable practices into guidance that coding agents can follow in every repository.",
226
- "proof": "Convention → executable guidance",
227
- "sales": {
228
- "kind": "standards-flow",
229
- "headline": "Your standards. Every agent. Every repository.",
230
- "metric": "1×",
231
- "metricLabel": "define · reuse everywhere",
232
- "logos": [
233
- { "id": "architecture", "label": "Architecture" },
234
- { "id": "tests", "label": "Tests" },
235
- { "id": "security", "label": "Security" },
236
- { "id": "style", "label": "Style" }
237
- ],
238
- "capabilities": ["Repository rules", "Review criteria", "Agent guidance", "Team conventions"],
239
- "steps": ["Define the standard once", "Agents receive executable guidance", "Review consistent output"]
240
- },
241
- "cta": "Explore the Playbook"
242
- },
243
- "surfaces": {
244
- "home": "https://playbook.agentskit.io",
245
- "docs": "https://playbook.agentskit.io/docs",
246
- "llms": "https://playbook.agentskit.io/llms.txt",
247
- "stats": "https://playbook.agentskit.io/api/stats.json",
248
- "documentation": "fumadocs",
249
- "chat": "custom"
250
- },
251
- "navigation": {
252
- "showInBar": true,
253
- "order": 3,
254
- "next": [
255
- "agentskit",
256
- "registry",
257
- "agentskit-chat",
258
275
  "doc-bridge",
259
- "code-review"
276
+ "code-review",
277
+ "harness",
278
+ "playbook"
260
279
  ]
261
280
  }
262
281
  },
@@ -283,13 +302,34 @@
283
302
  "metric": "↔",
284
303
  "metricLabel": "humans and agents",
285
304
  "logos": [
286
- { "id": "human", "label": "Humans" },
287
- { "id": "markdown", "label": "Docs" },
288
- { "id": "code", "label": "Code" },
289
- { "id": "agent", "label": "Agents" }
305
+ {
306
+ "id": "human",
307
+ "label": "Humans"
308
+ },
309
+ {
310
+ "id": "markdown",
311
+ "label": "Docs"
312
+ },
313
+ {
314
+ "id": "code",
315
+ "label": "Code"
316
+ },
317
+ {
318
+ "id": "agent",
319
+ "label": "Agents"
320
+ }
321
+ ],
322
+ "capabilities": [
323
+ "ADRs",
324
+ "Handoffs",
325
+ "Agent findings",
326
+ "Human-readable docs"
290
327
  ],
291
- "capabilities": ["ADRs", "Handoffs", "Agent findings", "Human-readable docs"],
292
- "steps": ["Humans document decisions", "Agents receive precise context", "Agent findings return to humans"]
328
+ "steps": [
329
+ "Humans document decisions",
330
+ "Agents receive precise context",
331
+ "Agent findings return to humans"
332
+ ]
293
333
  },
294
334
  "cta": "Explore Doc Bridge"
295
335
  },
@@ -302,13 +342,14 @@
302
342
  },
303
343
  "navigation": {
304
344
  "showInBar": true,
305
- "order": 4,
345
+ "order": 3,
306
346
  "next": [
307
347
  "agentskit",
308
348
  "registry",
309
349
  "agentskit-chat",
310
- "playbook",
311
- "code-review"
350
+ "code-review",
351
+ "harness",
352
+ "playbook"
312
353
  ]
313
354
  }
314
355
  },
@@ -325,21 +366,196 @@
325
366
  "repo": "AgentsKit-io/code-review",
326
367
  "accent": "#F97316",
327
368
  "surfaces": {
328
- "home": "https://github.com/AgentsKit-io/code-review",
329
- "docs": "https://github.com/AgentsKit-io/code-review#readme",
330
- "llms": "https://raw.githubusercontent.com/AgentsKit-io/code-review/main/llms.txt",
331
- "documentation": "repository",
369
+ "home": "https://code-review.agentskit.io",
370
+ "docs": "https://code-review.agentskit.io/docs",
371
+ "llms": "https://code-review.agentskit.io/llms.txt",
372
+ "documentation": "fumadocs",
332
373
  "chat": "none"
333
374
  },
334
375
  "navigation": {
335
- "showInBar": false,
376
+ "showInBar": true,
377
+ "order": 4,
378
+ "next": [
379
+ "agentskit",
380
+ "registry",
381
+ "agentskit-chat",
382
+ "doc-bridge",
383
+ "harness",
384
+ "playbook"
385
+ ]
386
+ },
387
+ "showcase": {
388
+ "stage": "Review",
389
+ "headline": "A review you can tune. Findings you can act on.",
390
+ "detail": "Choose the concerns that matter and see the review comments adapt to the change.",
391
+ "proof": "Configurable · provider-neutral · open source",
392
+ "sales": {
393
+ "kind": "review-config",
394
+ "headline": "Set the standard for every review.",
395
+ "metric": "2",
396
+ "metricLabel": "review profiles",
397
+ "capabilities": [
398
+ "Security",
399
+ "Performance",
400
+ "Correctness",
401
+ "Actionable comments"
402
+ ],
403
+ "steps": [
404
+ "Choose security or performance",
405
+ "Apply your review configuration",
406
+ "Get focused, actionable comments"
407
+ ]
408
+ },
409
+ "cta": "Explore Code Review"
410
+ }
411
+ },
412
+ {
413
+ "id": "harness",
414
+ "public": true,
415
+ "distributionClass": "open-source",
416
+ "name": "AgentsKit Harness",
417
+ "shortName": "Harness",
418
+ "kind": "tool",
419
+ "role": "delivery",
420
+ "promise": "The keep-pushing loop for your SDLC.",
421
+ "maturity": "beta",
422
+ "repo": "AgentsKit-io/harness",
423
+ "accent": "#F778BA",
424
+ "showcase": {
425
+ "stage": "Ship",
426
+ "headline": "From a vague objective to production, unattended.",
427
+ "detail": "Interview, plan, vote, build, review, prove, merge, release — one state machine per stage, with humans only where the loop acts on the world.",
428
+ "proof": "Objective → released change",
429
+ "sales": {
430
+ "kind": "standards-flow",
431
+ "headline": "The loop keeps pushing while you sleep.",
432
+ "metric": "24/7",
433
+ "metricLabel": "unattended delivery",
434
+ "logos": [
435
+ {
436
+ "id": "issue",
437
+ "label": "Issues"
438
+ },
439
+ {
440
+ "id": "worktree",
441
+ "label": "Worktrees"
442
+ },
443
+ {
444
+ "id": "review",
445
+ "label": "Review"
446
+ },
447
+ {
448
+ "id": "release",
449
+ "label": "Release"
450
+ }
451
+ ],
452
+ "capabilities": [
453
+ "Frozen contracts",
454
+ "Plan with votes",
455
+ "Definition of done",
456
+ "Human gates"
457
+ ],
458
+ "steps": [
459
+ "An issue becomes a contract nobody can widen",
460
+ "A worker proves it in its own worktree",
461
+ "A human approves what reaches production"
462
+ ]
463
+ },
464
+ "cta": "Explore Harness"
465
+ },
466
+ "surfaces": {
467
+ "home": "https://harness.agentskit.io/",
468
+ "docs": "https://harness.agentskit.io/docs",
469
+ "llms": "https://harness.agentskit.io/llms.txt",
470
+ "stats": "https://harness.agentskit.io/api/stats.json",
471
+ "documentation": "fumadocs",
472
+ "chat": "none"
473
+ },
474
+ "navigation": {
475
+ "showInBar": true,
336
476
  "order": 5,
337
477
  "next": [
338
478
  "agentskit",
339
479
  "registry",
340
480
  "agentskit-chat",
341
- "playbook",
342
- "doc-bridge"
481
+ "doc-bridge",
482
+ "code-review",
483
+ "playbook"
484
+ ]
485
+ }
486
+ },
487
+ {
488
+ "id": "playbook",
489
+ "public": true,
490
+ "distributionClass": "open-source",
491
+ "name": "Agents Playbook",
492
+ "shortName": "Playbook",
493
+ "kind": "methodology",
494
+ "role": "discipline",
495
+ "promise": "Make agents ship code a human would actually merge.",
496
+ "maturity": "stable",
497
+ "repo": "AgentsKit-io/agents-playbook",
498
+ "accent": "#8B5CF6",
499
+ "showcase": {
500
+ "stage": "Standardize",
501
+ "headline": "Engineering standards agents can execute.",
502
+ "detail": "Turn repeatable practices into guidance that coding agents can follow in every repository.",
503
+ "proof": "Convention → executable guidance",
504
+ "sales": {
505
+ "kind": "standards-flow",
506
+ "headline": "Your standards. Every agent. Every repository.",
507
+ "metric": "1×",
508
+ "metricLabel": "define · reuse everywhere",
509
+ "logos": [
510
+ {
511
+ "id": "architecture",
512
+ "label": "Architecture"
513
+ },
514
+ {
515
+ "id": "tests",
516
+ "label": "Tests"
517
+ },
518
+ {
519
+ "id": "security",
520
+ "label": "Security"
521
+ },
522
+ {
523
+ "id": "style",
524
+ "label": "Style"
525
+ }
526
+ ],
527
+ "capabilities": [
528
+ "Repository rules",
529
+ "Review criteria",
530
+ "Agent guidance",
531
+ "Team conventions"
532
+ ],
533
+ "steps": [
534
+ "Define the standard once",
535
+ "Agents receive executable guidance",
536
+ "Review consistent output"
537
+ ]
538
+ },
539
+ "cta": "Explore the Playbook"
540
+ },
541
+ "surfaces": {
542
+ "home": "https://playbook.agentskit.io",
543
+ "docs": "https://playbook.agentskit.io/docs",
544
+ "llms": "https://playbook.agentskit.io/llms.txt",
545
+ "stats": "https://playbook.agentskit.io/api/stats.json",
546
+ "documentation": "fumadocs",
547
+ "chat": "custom"
548
+ },
549
+ "navigation": {
550
+ "showInBar": false,
551
+ "order": 6,
552
+ "next": [
553
+ "agentskit",
554
+ "registry",
555
+ "agentskit-chat",
556
+ "doc-bridge",
557
+ "code-review",
558
+ "harness"
343
559
  ]
344
560
  }
345
561
  }
@@ -355,6 +571,7 @@
355
571
  "tagline": "Build agents without gluing many libraries together.",
356
572
  "kind": "library",
357
573
  "accent": "#2EA043",
574
+ "showInBar": true,
358
575
  "llms": "https://www.agentskit.io/llms.txt",
359
576
  "stats": "https://www.agentskit.io/api/stats.json"
360
577
  },
@@ -368,6 +585,7 @@
368
585
  "tagline": "Make agents ship code a human would actually merge.",
369
586
  "kind": "methodology",
370
587
  "accent": "#8B5CF6",
588
+ "showInBar": false,
371
589
  "llms": "https://playbook.agentskit.io/llms.txt",
372
590
  "stats": "https://playbook.agentskit.io/api/stats.json"
373
591
  },
@@ -381,6 +599,7 @@
381
599
  "tagline": "Copy ready-made agents and own the source.",
382
600
  "kind": "registry",
383
601
  "accent": "#58A6FF",
602
+ "showInBar": true,
384
603
  "llms": "https://registry.agentskit.io/llms.txt",
385
604
  "stats": "https://registry.agentskit.io/r/index.json"
386
605
  }
@@ -2,7 +2,7 @@
2
2
  "manifest_version": "0.3",
3
3
  "name": "doc-bridge",
4
4
  "display_name": "Doc Bridge",
5
- "version": "1.11.2",
5
+ "version": "1.12.0",
6
6
  "description": "Deterministic repository handoffs for coding agents, running locally without an LLM or API key.",
7
7
  "long_description": "Doc Bridge turns a repository's own documentation and ownership metadata into deterministic handoffs: where an agent should start, which paths it may edit, which checks it must run, and when a human must take over. The local connector exposes the same read-only contract available through Doc Bridge CLI and CI.",
8
8
  "author": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentskit/doc-bridge",
3
- "version": "1.11.2",
3
+ "version": "1.12.0",
4
4
  "mcpName": "io.github.AgentsKit-io/doc-bridge",
5
5
  "description": "Human↔agent documentation bridge — deterministic handoffs, doc-site links, memory→docs, optional AgentsKit RAG/chat.",
6
6
  "type": "module",
@@ -80,6 +80,7 @@
80
80
  "graphology-dag": "~0.4.1",
81
81
  "graphology-metrics": "~2.4.2",
82
82
  "graphology-shortest-path": "~2.1.0",
83
+ "ignore": "^7.0.6",
83
84
  "knap": "~0.5.1",
84
85
  "mdast-util-to-string": "^4.0.0",
85
86
  "mermaid": "^11.17.2",
@@ -25,7 +25,7 @@ Use this skill before editing a repository that contains `doc-bridge.config.json
25
25
 
26
26
  If resolution fails, returns incomplete fields, or names an unknown target, stop. Do not infer edit permission from repository layout.
27
27
 
28
- The resolver and MCP tools are read-only. They resolve project guidance but never authorize edits, publish changes, execute returned checks, or replace repository instructions. The skill uses no credentials and has no provider, hosted service, or AKOS dependency.
28
+ The resolver and MCP tools are read-only. They resolve project guidance but never authorize edits, publish changes, execute returned checks, or replace repository instructions. The skill uses no credentials and has no provider, hosted service, or managed-service dependency.
29
29
 
30
30
  ## Portable runtimes
31
31
 
@@ -3,7 +3,7 @@
3
3
  import { spawnSync } from 'node:child_process'
4
4
  import { isAbsolute } from 'node:path'
5
5
 
6
- const VERSION = '1.11.2'
6
+ const VERSION = '1.12.0'
7
7
  const kinds = new Set(['package', 'ownership'])
8
8
  const args = process.argv.slice(2)
9
9
  const id = args[0]
@@ -50,12 +50,9 @@ const ManifestSchema = z.object({
50
50
  schemaVersion: z.literal(2),
51
51
  parentBrand: z.object({ id: NonEmptyStringSchema, name: NonEmptyStringSchema }).passthrough(),
52
52
  products: z.array(ProductSchema).min(1),
53
- // Legacy three-product shim or full public product projection of products[].
54
- properties: z
55
- .array(LegacyPropertySchema)
56
- .refine((value) => value.length === 3 || value.length === 6, {
57
- message: 'must project either the legacy three products or the full public product catalog',
58
- }),
53
+ // Deprecated compatibility shim: when present, every entry projects one products[] record.
54
+ // Membership is whatever the canonical manifest lists; no product is required by name.
55
+ properties: z.array(LegacyPropertySchema).optional(),
59
56
  builder: z.object({ id: NonEmptyStringSchema, name: NonEmptyStringSchema, url: HttpsUrlSchema }).passthrough().optional(),
60
57
  }).passthrough()
61
58
 
@@ -94,18 +91,6 @@ const ClaimsSchema = z.object({
94
91
  products: z.array(ClaimProductSchema),
95
92
  }).passthrough()
96
93
 
97
- /** Historical three-product shim order. */
98
- const LEGACY_PRODUCT_IDS = ['agentskit', 'playbook', 'registry'] as const
99
- /** Full public product projection order (matches products[]). */
100
- const PUBLIC_PRODUCT_IDS = [
101
- 'agentskit',
102
- 'registry',
103
- 'agentskit-chat',
104
- 'playbook',
105
- 'doc-bridge',
106
- 'code-review',
107
- ] as const
108
-
109
94
  export const parseCanonicalEcosystemContract = (
110
95
  manifestInput: unknown,
111
96
  claimsInput: unknown,
@@ -136,13 +121,14 @@ export const parseCanonicalEcosystemContract = (
136
121
  }
137
122
  }
138
123
 
139
- const propertyIds = manifest.properties.length === 6 ? PUBLIC_PRODUCT_IDS : LEGACY_PRODUCT_IDS
140
-
141
- for (const [index, id] of propertyIds.entries()) {
142
- const legacy = manifest.properties[index]
124
+ const propertyIds = new Set<string>()
125
+ for (const [index, legacy] of (manifest.properties ?? []).entries()) {
126
+ const id = legacy.id
143
127
  const product = products.get(id)
144
- if (!legacy || !product || legacy.id !== id || !product.surfaces.home) {
145
- throw new Error(`Legacy property ${index} must project product ${id}.`)
128
+ if (propertyIds.has(id)) throw new Error(`Legacy property ${id} is listed more than once.`)
129
+ propertyIds.add(id)
130
+ if (!product || !product.surfaces.home) {
131
+ throw new Error(`Legacy property ${index} (${id}) must project a manifest product with a home surface.`)
146
132
  }
147
133
  const expected = {
148
134
  name: product.name,
@@ -203,7 +203,13 @@ const discoverPackages = (
203
203
  const name = packageName(parsed.value, path)
204
204
  const id = entityId('package', name ?? path)
205
205
  const duplicate = packages.find((pkg) => pkg.id === id)
206
- if (duplicate && duplicate.absPath !== absPath) {
206
+ // Compare toPosix'd, not raw: the root package above is always registered with its raw, native-separator
207
+ // `absPath` (other code depends on that — e.g. `packageForModule`'s `startsWith` matching against
208
+ // `safeWalkFiles`' own native-style paths), while `expandWorkspaceGlobs` always returns toPosix'd absPaths.
209
+ // On Windows those are two different strings for the exact same directory whenever a workspace list
210
+ // includes "." explicitly (root resolves to itself both ways) — a false-positive collision on every such
211
+ // Windows checkout otherwise (reproduced live: harness's own `packages: [., apps/*]`).
212
+ if (duplicate && toPosix(duplicate.absPath) !== toPosix(absPath)) {
207
213
  throw new Error(`Package identity collision for "${id}": "${duplicate.path}" and "${path}".`)
208
214
  }
209
215
  if (!duplicate) packages.push({ id, ...(name ? { name } : {}), path, absPath, manifestPath, manifest: parsed.value })