@open-mercato/cli 0.7.1-develop.7203.1.9396450b78 → 0.8.1-develop.7204.1.83330e271e

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 (91) hide show
  1. package/dist/agentic/guides/module-facts.json +142 -142
  2. package/dist/agentic/guides/module-facts.v2.json +142 -142
  3. package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
  4. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  5. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  6. package/dist/agentic/guides/modules/api_keys/index.md +1 -1
  7. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  8. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  9. package/dist/agentic/guides/modules/auth/index.md +1 -1
  10. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  11. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  12. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  13. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  14. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  15. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  16. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  17. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  18. package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
  19. package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
  20. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  21. package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
  22. package/dist/agentic/guides/modules/configs/index.md +1 -1
  23. package/dist/agentic/guides/modules/content/index.md +1 -1
  24. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  25. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  26. package/dist/agentic/guides/modules/customers/index.md +1 -1
  27. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  28. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  29. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  30. package/dist/agentic/guides/modules/devices/index.md +1 -1
  31. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  32. package/dist/agentic/guides/modules/directory/index.md +1 -1
  33. package/dist/agentic/guides/modules/documents/index.md +1 -1
  34. package/dist/agentic/guides/modules/entities/index.md +1 -1
  35. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  36. package/dist/agentic/guides/modules/events/index.md +1 -1
  37. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  38. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  39. package/dist/agentic/guides/modules/generators/index.md +1 -1
  40. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  41. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  42. package/dist/agentic/guides/modules/messages/index.md +1 -1
  43. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  44. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  45. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  46. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  47. package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
  48. package/dist/agentic/guides/modules/planner/index.md +1 -1
  49. package/dist/agentic/guides/modules/portal/index.md +1 -1
  50. package/dist/agentic/guides/modules/progress/index.md +1 -1
  51. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  52. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  53. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  54. package/dist/agentic/guides/modules/resources/index.md +1 -1
  55. package/dist/agentic/guides/modules/sales/index.md +1 -1
  56. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  57. package/dist/agentic/guides/modules/search/index.md +1 -1
  58. package/dist/agentic/guides/modules/security/index.md +1 -1
  59. package/dist/agentic/guides/modules/seeds/index.md +1 -1
  60. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  61. package/dist/agentic/guides/modules/sso/index.md +1 -1
  62. package/dist/agentic/guides/modules/staff/index.md +1 -1
  63. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  64. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  65. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  66. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  67. package/dist/agentic/guides/modules/tillio/index.md +1 -1
  68. package/dist/agentic/guides/modules/translations/index.md +1 -1
  69. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  70. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  71. package/dist/agentic/guides/modules/wms/index.md +1 -1
  72. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  73. package/dist/agentic/guides/reference-module-facts.json +2 -2
  74. package/dist/agentic/guides/reference-modules/example/index.md +1 -1
  75. package/dist/agentic/guides/upstream/manifest.json +1 -1
  76. package/dist/agentic/shared/ai/harness/cases.json +1 -1
  77. package/dist/agentic/shared/ai/harness/design-system-inventory.json +3309 -967
  78. package/dist/agentic/shared/ai/harness/source-link-inventory.json +249 -29
  79. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.7.0-to-0.8.0/SKILL.md +93 -0
  80. package/dist/agentic/shared/ai/skills/tiers.json +2 -1
  81. package/dist/lib/generators/extensions/agent-files.js +37 -16
  82. package/dist/lib/generators/extensions/agent-files.js.map +2 -2
  83. package/dist/lib/generators/extensions/index.js +2 -2
  84. package/dist/lib/generators/extensions/index.js.map +2 -2
  85. package/dist/lib/generators/module-registry.js +1 -1
  86. package/dist/lib/generators/module-registry.js.map +2 -2
  87. package/package.json +7 -7
  88. package/src/lib/generators/__tests__/agent-files-extension.test.ts +118 -0
  89. package/src/lib/generators/extensions/agent-files.ts +85 -15
  90. package/src/lib/generators/extensions/index.ts +8 -3
  91. package/src/lib/generators/module-registry.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.7.1-develop.7203.1.9396450b78",
3
+ "version": "0.8.1-develop.7204.1.83330e271e",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,9 +60,9 @@
60
60
  "@mikro-orm/decorators": "^7.1.14",
61
61
  "@mikro-orm/migrations": "^7.1.14",
62
62
  "@mikro-orm/postgresql": "^7.1.14",
63
- "@open-mercato/queue": "0.7.1-develop.7203.1.9396450b78",
64
- "@open-mercato/shared": "0.7.1-develop.7203.1.9396450b78",
65
- "@open-mercato/telemetry": "0.7.1-develop.7203.1.9396450b78",
63
+ "@open-mercato/queue": "0.8.1-develop.7204.1.83330e271e",
64
+ "@open-mercato/shared": "0.8.1-develop.7204.1.83330e271e",
65
+ "@open-mercato/telemetry": "0.8.1-develop.7204.1.83330e271e",
66
66
  "cross-spawn": "^7.0.6",
67
67
  "pg": "8.23.0",
68
68
  "semver": "^7.8.5",
@@ -73,10 +73,10 @@
73
73
  "typescript-js": "npm:typescript@6.0.3"
74
74
  },
75
75
  "peerDependencies": {
76
- "@open-mercato/shared": "0.7.1-develop.7203.1.9396450b78"
76
+ "@open-mercato/shared": "0.8.1-develop.7204.1.83330e271e"
77
77
  },
78
78
  "devDependencies": {
79
- "@open-mercato/shared": "0.7.1-develop.7203.1.9396450b78",
79
+ "@open-mercato/shared": "0.8.1-develop.7204.1.83330e271e",
80
80
  "@types/jest": "^30.0.0",
81
81
  "jest": "^30.4.2",
82
82
  "ts-jest": "^29.4.12"
@@ -89,5 +89,5 @@
89
89
  "url": "https://github.com/open-mercato/open-mercato",
90
90
  "directory": "packages/cli"
91
91
  },
92
- "stableVersion": "0.7.0"
92
+ "stableVersion": "0.8.0"
93
93
  }
@@ -474,4 +474,122 @@ describe('createAgentFilesExtension', () => {
474
474
  )
475
475
  expect(manifest).toContain('export const fileAgentDescriptors: FileAgentDescriptor[] = []')
476
476
  })
477
+
478
+ describe('standalone app layout', () => {
479
+ /**
480
+ * A scaffolded app has no `packages/` tree and no `docker/opencode/` before
481
+ * the first generate, so the legacy `findRepoRoot` walk-up could never
482
+ * resolve and the extension silently emitted nothing. With a resolver
483
+ * reporting `isMonorepo() === false` the artifacts land in the app instead.
484
+ */
485
+ function makeStandaloneFixture(): { appDir: string; appBase: string; pkgBase: string } {
486
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-files-standalone-'))
487
+ const appBase = path.join(appDir, 'src', 'modules', 'agent_examples')
488
+ const pkgBase = path.join(
489
+ appDir,
490
+ 'node_modules',
491
+ '@open-mercato',
492
+ 'enterprise',
493
+ 'dist',
494
+ 'modules',
495
+ 'agent_examples',
496
+ )
497
+ const agentDir = path.join(appBase, 'agents', 'deals_health_check')
498
+ fs.mkdirSync(agentDir, { recursive: true })
499
+ fs.writeFileSync(
500
+ path.join(agentDir, 'AGENT.md'),
501
+ [
502
+ '---',
503
+ 'id: deals.health_check',
504
+ 'label: Deal health check',
505
+ 'description: Assess a deal.',
506
+ '---',
507
+ 'You assess a deal.',
508
+ ].join('\n'),
509
+ 'utf8',
510
+ )
511
+ fs.writeFileSync(
512
+ path.join(agentDir, 'OUTCOME.md'),
513
+ [
514
+ '---',
515
+ 'kind: proposal',
516
+ '---',
517
+ '```json',
518
+ JSON.stringify({
519
+ type: 'object',
520
+ required: ['confidence'],
521
+ properties: { confidence: { type: 'number' } },
522
+ }),
523
+ '```',
524
+ ].join('\n'),
525
+ 'utf8',
526
+ )
527
+ return { appDir, appBase, pkgBase }
528
+ }
529
+
530
+ function standaloneResolver(appDir: string) {
531
+ return {
532
+ isMonorepo: () => false,
533
+ getRootDir: () => appDir,
534
+ getAppDir: () => appDir,
535
+ getOutputDir: () => path.join(appDir, '.mercato', 'generated'),
536
+ }
537
+ }
538
+
539
+ let appDir = ''
540
+ afterEach(() => {
541
+ if (appDir) fs.rmSync(appDir, { recursive: true, force: true })
542
+ appDir = ''
543
+ })
544
+
545
+ it('writes the manifest to .mercato/generated and agents under the app docker/ dir', () => {
546
+ const fixture = makeStandaloneFixture()
547
+ appDir = fixture.appDir
548
+
549
+ const extension = createAgentFilesExtension(standaloneResolver(fixture.appDir))
550
+ extension.scanModule(createScanContext('agent_examples', fixture.appBase, fixture.pkgBase))
551
+ extension.generateOutput()
552
+
553
+ // The manifest lands in the generated output dir that
554
+ // `findGeneratedFile()` probes as `<cwd>/.mercato/generated/<file>`.
555
+ const manifestPath = path.join(
556
+ fixture.appDir,
557
+ '.mercato',
558
+ 'generated',
559
+ 'file-agents.generated.ts',
560
+ )
561
+ expect(fs.existsSync(manifestPath)).toBe(true)
562
+ expect(fs.readFileSync(manifestPath, 'utf8')).toContain('id: "deals.health_check"')
563
+
564
+ // It must NOT write into node_modules, which yarn install rewrites.
565
+ expect(
566
+ fs.existsSync(path.join(fixture.appDir, 'node_modules', '@open-mercato', 'enterprise', 'src')),
567
+ ).toBe(false)
568
+
569
+ const dockerFile = path.join(
570
+ fixture.appDir,
571
+ 'docker',
572
+ 'opencode',
573
+ 'agents',
574
+ 'deals_health_check.md',
575
+ )
576
+ expect(fs.existsSync(dockerFile)).toBe(true)
577
+ expect(fs.readFileSync(dockerFile, 'utf8')).toContain('mode: primary')
578
+ })
579
+
580
+ it('warns instead of silently dropping agents when no output root resolves', () => {
581
+ const fixture = makeStandaloneFixture()
582
+ appDir = fixture.appDir
583
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {})
584
+
585
+ // No resolver AND no in-repo markers: the legacy walk-up returns null.
586
+ const extension = createAgentFilesExtension()
587
+ extension.scanModule(createScanContext('agent_examples', fixture.appBase, fixture.pkgBase))
588
+ const output = extension.generateOutput()
589
+
590
+ expect(output.size).toBe(0)
591
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining('Could not resolve an output root'))
592
+ warn.mockRestore()
593
+ })
594
+ })
477
595
  })
@@ -4,6 +4,18 @@ import { countTokens } from '@open-mercato/shared/lib/ai/token-count'
4
4
  import type { GeneratorExtension, ModuleScanContext } from '../extension'
5
5
  import { resolveStandaloneSourceMirrorBase } from '../scanner'
6
6
 
7
+ /**
8
+ * The slice of `PackageResolver` this extension needs. Kept structural (rather
9
+ * than importing the full interface) so the extension stays testable with a
10
+ * literal and carries no dependency on the resolver module.
11
+ */
12
+ export type AgentFilesResolver = {
13
+ isMonorepo(): boolean
14
+ getRootDir(): string
15
+ getAppDir(): string
16
+ getOutputDir(): string
17
+ }
18
+
7
19
  /**
8
20
  * Generator extension for the `agents/<id>/` file-defined-agent convention
9
21
  * (AGENT.md + OUTCOME.md). For every enabled module it scans the module's
@@ -839,6 +851,62 @@ function findRepoRoot(start: string): string | null {
839
851
  return null
840
852
  }
841
853
 
854
+ /**
855
+ * Where this extension's three artifacts land. The two layouts differ because a
856
+ * standalone app has no `packages/` tree to host the manifest: the enterprise
857
+ * module lives under `node_modules/`, which `yarn install` rewrites.
858
+ *
859
+ * | Artifact | Monorepo | Standalone |
860
+ * |-----------|------------------------------------------------------------|-------------------------------------------|
861
+ * | manifest | `packages/enterprise/src/modules/agent_orchestrator/generated/` | `<app>/.mercato/generated/` |
862
+ * | agents/ | `<repo>/docker/opencode/agents/` | `<app>/docker/opencode/agents/` |
863
+ * | skills/ | `<repo>/docker/opencode/skills/` | `<app>/docker/opencode/skills/` |
864
+ *
865
+ * The standalone manifest sits in the generated output dir that
866
+ * `findGeneratedFile()` already probes (`generated-registry-loader.ts` resolves
867
+ * `<cwd>/.mercato/generated/<file>` for exactly this case), so the runtime
868
+ * loader reaches it with no new resolution logic. It is regenerated on every
869
+ * `yarn generate`, which both `scripts/dev.mjs` setup and
870
+ * `docker/scripts/init-or-migrate.sh` run before the app boots.
871
+ */
872
+ type AgentFilesTargets = {
873
+ manifestPath: string
874
+ dockerAgentsDir: string
875
+ dockerSkillsDir: string
876
+ }
877
+
878
+ function resolveAgentFilesTargets(
879
+ resolver: AgentFilesResolver | undefined,
880
+ fallbackRepoRoot: string | null,
881
+ ): AgentFilesTargets | null {
882
+ if (resolver && !resolver.isMonorepo()) {
883
+ const appDir = resolver.getAppDir()
884
+ return {
885
+ manifestPath: path.join(resolver.getOutputDir(), 'file-agents.generated.ts'),
886
+ dockerAgentsDir: path.join(appDir, 'docker', 'opencode', 'agents'),
887
+ dockerSkillsDir: path.join(appDir, 'docker', 'opencode', 'skills'),
888
+ }
889
+ }
890
+ // Monorepo. Prefer the resolver's root, falling back to the walk-up probe so
891
+ // unit tests that construct the extension without a resolver keep working.
892
+ const repoRoot = resolver?.getRootDir() ?? fallbackRepoRoot
893
+ if (!repoRoot) return null
894
+ return {
895
+ manifestPath: path.join(
896
+ repoRoot,
897
+ 'packages',
898
+ 'enterprise',
899
+ 'src',
900
+ 'modules',
901
+ 'agent_orchestrator',
902
+ 'generated',
903
+ 'file-agents.generated.ts',
904
+ ),
905
+ dockerAgentsDir: path.join(repoRoot, 'docker', 'opencode', 'agents'),
906
+ dockerSkillsDir: path.join(repoRoot, 'docker', 'opencode', 'skills'),
907
+ }
908
+ }
909
+
842
910
  function listAgentDirs(agentsBase: string): string[] {
843
911
  if (!fs.existsSync(agentsBase)) return []
844
912
  return fs
@@ -1125,7 +1193,7 @@ export const fileAgentDescriptors: FileAgentDescriptor[] = [${
1125
1193
  `
1126
1194
  }
1127
1195
 
1128
- export function createAgentFilesExtension(): GeneratorExtension {
1196
+ export function createAgentFilesExtension(resolver?: AgentFilesResolver): GeneratorExtension {
1129
1197
  const discovered: DiscoveredAgent[] = []
1130
1198
  const seenIds = new Set<string>()
1131
1199
  let repoRoot: string | null = null
@@ -1238,9 +1306,22 @@ export function createAgentFilesExtension(): GeneratorExtension {
1238
1306
  generateOutput() {
1239
1307
  const sorted = [...discovered].sort((a, b) => a.id.localeCompare(b.id))
1240
1308
 
1241
- if (!repoRoot) {
1242
- // No module roots resolved to a repo (e.g. an isolated unit test). Skip
1309
+ const targets = resolveAgentFilesTargets(resolver, repoRoot)
1310
+
1311
+ if (!targets) {
1312
+ // No layout resolved (e.g. an isolated unit test constructing the
1313
+ // extension without a resolver and without in-repo module roots). Skip
1243
1314
  // the fs side effect; the empty-Map return keeps the contract intact.
1315
+ // Stay silent only when there is nothing to emit — otherwise the run
1316
+ // would drop real agents without saying so (the pre-2026-09 behaviour).
1317
+ if (sawOrchestratorModule || sorted.length > 0) {
1318
+ console.warn(
1319
+ '[agent-files] Could not resolve an output root, so the file-agent manifest and ' +
1320
+ 'docker/opencode/{agents,skills} were NOT written. ' +
1321
+ `Discovered ${sorted.length} file agent(s). ` +
1322
+ 'In a standalone app this means the generator ran without a package resolver.',
1323
+ )
1324
+ }
1244
1325
  return new Map<string, string>()
1245
1326
  }
1246
1327
 
@@ -1253,20 +1334,10 @@ export function createAgentFilesExtension(): GeneratorExtension {
1253
1334
  return new Map<string, string>()
1254
1335
  }
1255
1336
 
1256
- const manifestPath = path.join(
1257
- repoRoot,
1258
- 'packages',
1259
- 'enterprise',
1260
- 'src',
1261
- 'modules',
1262
- 'agent_orchestrator',
1263
- 'generated',
1264
- 'file-agents.generated.ts',
1265
- )
1337
+ const { manifestPath, dockerAgentsDir, dockerSkillsDir } = targets
1266
1338
  fs.mkdirSync(path.dirname(manifestPath), { recursive: true })
1267
1339
  fs.writeFileSync(manifestPath, renderManifest(sorted), 'utf8')
1268
1340
 
1269
- const dockerAgentsDir = path.join(repoRoot, 'docker', 'opencode', 'agents')
1270
1341
  fs.mkdirSync(dockerAgentsDir, { recursive: true })
1271
1342
  const desiredFiles = new Map<string, string>()
1272
1343
  for (const agent of sorted) {
@@ -1292,7 +1363,6 @@ export function createAgentFilesExtension(): GeneratorExtension {
1292
1363
  // remove stale skill dirs not in the current desired set. Sub-agents
1293
1364
  // (Phase 4) may carry their own skills too, so flatten them in.
1294
1365
  const allAgents = sorted.flatMap((agent) => [agent, ...agent.subAgentsContent])
1295
- const dockerSkillsDir = path.join(repoRoot, 'docker', 'opencode', 'skills')
1296
1366
  // The synthetic `__agent_tools__` skill only carries an agent's local
1297
1367
  // `tools/*.ts` sources (run via `run_skill_script`); it has no instructions
1298
1368
  // and MUST NOT be emitted as a native OpenCode skill (OpenCode requires a
@@ -1,5 +1,5 @@
1
1
  import type { GeneratorExtension } from '../extension'
2
- import { createAgentFilesExtension } from './agent-files'
2
+ import { createAgentFilesExtension, type AgentFilesResolver } from './agent-files'
3
3
  import { createAiAgentsExtension } from './ai-agents'
4
4
  import { createAiToolsExtension } from './ai-tools'
5
5
  import { createAnalyticsExtension } from './analytics'
@@ -19,14 +19,19 @@ import { createSearchExtension } from './search'
19
19
  import { createTranslatableFieldsExtension } from './translatable-fields'
20
20
  import { createWorkflowsExtension } from './workflows'
21
21
 
22
- export function loadGeneratorExtensions(): GeneratorExtension[] {
22
+ /**
23
+ * `resolver` is optional so existing callers and unit tests keep working; the
24
+ * agent-files extension uses it to tell a monorepo checkout from a standalone
25
+ * app when choosing where to write its artifacts.
26
+ */
27
+ export function loadGeneratorExtensions(resolver?: AgentFilesResolver): GeneratorExtension[] {
23
28
  return [
24
29
  createSearchExtension(),
25
30
  createNotificationsExtension(),
26
31
  createMessagesExtension(),
27
32
  createAiToolsExtension(),
28
33
  createAiAgentsExtension(),
29
- createAgentFilesExtension(),
34
+ createAgentFilesExtension(resolver),
30
35
  createEventsExtension(),
31
36
  createAnalyticsExtension(),
32
37
  createTranslatableFieldsExtension(),
@@ -3591,7 +3591,7 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
3591
3591
  const commandLoadersChecksumFile = path.join(outputDir, 'command-loaders.generated.checksum')
3592
3592
 
3593
3593
  const enabled = discovery.enabled
3594
- const extensions = loadGeneratorExtensions()
3594
+ const extensions = loadGeneratorExtensions(resolver)
3595
3595
 
3596
3596
  // Pre-pass: collect generator plugins from each enabled module's generators.ts
3597
3597
  const pluginRegistry = new Map<string, import('@open-mercato/shared/modules/generators').GeneratorPlugin>()