vgxness 0.1.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 (121) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +110 -0
  3. package/dist/agents/agent-activation-service.js +144 -0
  4. package/dist/agents/agent-registry-service.js +46 -0
  5. package/dist/agents/agent-resolver.js +249 -0
  6. package/dist/agents/agent-seed-service.js +146 -0
  7. package/dist/agents/manager-profile-overlay-service.js +34 -0
  8. package/dist/agents/profile-model-routing.js +26 -0
  9. package/dist/agents/renderers/claude-renderer.js +98 -0
  10. package/dist/agents/renderers/index.js +16 -0
  11. package/dist/agents/renderers/json-renderer.js +87 -0
  12. package/dist/agents/renderers/opencode-renderer.js +100 -0
  13. package/dist/agents/renderers/provider-adapter.js +6 -0
  14. package/dist/agents/repositories/agents.js +185 -0
  15. package/dist/agents/repositories/manager-profile-overlays.js +81 -0
  16. package/dist/agents/schema.js +1 -0
  17. package/dist/cli/dashboard-operational-read-models.js +153 -0
  18. package/dist/cli/dashboard-renderer.js +109 -0
  19. package/dist/cli/dashboard-screen-renderers.js +332 -0
  20. package/dist/cli/dashboard-tui-read-model.js +71 -0
  21. package/dist/cli/dashboard-tui-state.js +218 -0
  22. package/dist/cli/dispatcher.js +2880 -0
  23. package/dist/cli/index.js +27 -0
  24. package/dist/cli/interactive-dashboard.js +29 -0
  25. package/dist/cli/mcp-start-path.js +21 -0
  26. package/dist/cli/setup-status-renderer.js +29 -0
  27. package/dist/cli/setup-wizard-read-model.js +56 -0
  28. package/dist/cli/setup-wizard-renderer.js +148 -0
  29. package/dist/cli/setup-wizard-state.js +82 -0
  30. package/dist/cli/tui-render-helpers.js +192 -0
  31. package/dist/export/redaction.js +71 -0
  32. package/dist/harness/tools/agents.js +245 -0
  33. package/dist/harness/tools/memory.js +29 -0
  34. package/dist/mcp/client-install-opencode-contract.js +227 -0
  35. package/dist/mcp/client-install-opencode.js +194 -0
  36. package/dist/mcp/client-setup-preview.js +38 -0
  37. package/dist/mcp/control-plane.js +175 -0
  38. package/dist/mcp/doctor.js +193 -0
  39. package/dist/mcp/index.js +10 -0
  40. package/dist/mcp/opencode-default-agent-config.js +156 -0
  41. package/dist/mcp/opencode-visibility.js +102 -0
  42. package/dist/mcp/schema.js +234 -0
  43. package/dist/mcp/stdio-server.js +56 -0
  44. package/dist/mcp/validation.js +761 -0
  45. package/dist/memory/import/dry-run-planner.js +58 -0
  46. package/dist/memory/import/index.js +3 -0
  47. package/dist/memory/import/observation-writer.js +220 -0
  48. package/dist/memory/import/package.js +178 -0
  49. package/dist/memory/memory-service.js +126 -0
  50. package/dist/memory/repositories/artifacts.js +41 -0
  51. package/dist/memory/repositories/observations.js +133 -0
  52. package/dist/memory/repositories/sessions.js +105 -0
  53. package/dist/memory/repositories/traces.js +58 -0
  54. package/dist/memory/schema.js +1 -0
  55. package/dist/memory/search.js +11 -0
  56. package/dist/memory/sqlite/database.js +97 -0
  57. package/dist/memory/sqlite/migrations/001_initial.sql +128 -0
  58. package/dist/memory/sqlite/migrations/002_observation_revisions.sql +14 -0
  59. package/dist/memory/sqlite/migrations/003_agent_registry.sql +26 -0
  60. package/dist/memory/sqlite/migrations/004_run_runtime.sql +62 -0
  61. package/dist/memory/sqlite/migrations/005_run_approvals.sql +20 -0
  62. package/dist/memory/sqlite/migrations/006_run_operation_attempts.sql +32 -0
  63. package/dist/memory/sqlite/migrations/007_abandoned_operation_attempts.sql +46 -0
  64. package/dist/memory/sqlite/migrations/008_run_execution_plan_events.sql +105 -0
  65. package/dist/memory/sqlite/migrations/009_multiple_operation_attempts.sql +73 -0
  66. package/dist/memory/sqlite/migrations/010_skill_registry.sql +66 -0
  67. package/dist/memory/sqlite/migrations/011_skill_usage_resolution_outcomes.sql +21 -0
  68. package/dist/memory/sqlite/migrations/012_skill_improvement_proposals.sql +37 -0
  69. package/dist/memory/sqlite/migrations/013_skill_evaluation_scenarios.sql +43 -0
  70. package/dist/memory/sqlite/migrations/014_manager_profile_overlays.sql +14 -0
  71. package/dist/memory/storage-paths.js +72 -0
  72. package/dist/orchestrator/natural-language-planner.js +191 -0
  73. package/dist/orchestrator/schema.js +1 -0
  74. package/dist/permissions/index.js +2 -0
  75. package/dist/permissions/policy-evaluator.js +109 -0
  76. package/dist/permissions/schema.js +1 -0
  77. package/dist/providers/opencode/injection-preview.js +134 -0
  78. package/dist/providers/opencode/manager-payload.js +129 -0
  79. package/dist/runs/execution-planning.js +117 -0
  80. package/dist/runs/operation-execution.js +1 -0
  81. package/dist/runs/operation-retry.js +124 -0
  82. package/dist/runs/repositories/runs.js +611 -0
  83. package/dist/runs/run-insights.js +145 -0
  84. package/dist/runs/run-service.js +713 -0
  85. package/dist/runs/run-snapshot-export-service.js +31 -0
  86. package/dist/runs/sandbox-process-execution.js +218 -0
  87. package/dist/runs/sandbox-worktree-planning.js +59 -0
  88. package/dist/runs/schema.js +1 -0
  89. package/dist/sdd/artifact-portability-service.js +118 -0
  90. package/dist/sdd/schema.js +17 -0
  91. package/dist/sdd/sdd-workflow-service.js +217 -0
  92. package/dist/setup/backup-rollback-service.js +76 -0
  93. package/dist/setup/index.js +3 -0
  94. package/dist/setup/providers/antigravity-setup-adapter.js +18 -0
  95. package/dist/setup/providers/claude-setup-adapter.js +30 -0
  96. package/dist/setup/providers/custom-setup-adapter.js +18 -0
  97. package/dist/setup/providers/index.js +6 -0
  98. package/dist/setup/providers/opencode-setup-adapter.js +104 -0
  99. package/dist/setup/providers/provider-setup-adapter.js +15 -0
  100. package/dist/setup/providers/provider-setup-registry.js +11 -0
  101. package/dist/setup/schema.js +1 -0
  102. package/dist/setup/setup-defaults.js +11 -0
  103. package/dist/setup/setup-lifecycle-service.js +175 -0
  104. package/dist/setup/setup-plan.js +105 -0
  105. package/dist/skills/repositories/skill-evaluation-scenarios.js +289 -0
  106. package/dist/skills/repositories/skill-improvement-proposals.js +288 -0
  107. package/dist/skills/repositories/skills.js +430 -0
  108. package/dist/skills/schema.js +1 -0
  109. package/dist/skills/skill-payload.js +94 -0
  110. package/dist/skills/skill-registry-service.js +92 -0
  111. package/dist/skills/skill-resolver.js +191 -0
  112. package/dist/workflows/command-allowlist-adapter.js +70 -0
  113. package/dist/workflows/schema.js +4 -0
  114. package/dist/workflows/workflow-executor.js +345 -0
  115. package/dist/workflows/workflow-registry.js +66 -0
  116. package/docs/architecture.md +698 -0
  117. package/docs/cli.md +741 -0
  118. package/docs/funcionamiento-del-sistema.md +868 -0
  119. package/docs/harness-gap-analysis.md +229 -0
  120. package/docs/prd.md +372 -0
  121. package/package.json +57 -0
@@ -0,0 +1,146 @@
1
+ import { AgentRepository } from './repositories/agents.js';
2
+ const requiredManagerName = 'vgxness-manager';
3
+ export class AgentSeedService {
4
+ database;
5
+ agents;
6
+ constructor(database) {
7
+ this.database = database;
8
+ this.agents = new AgentRepository(database);
9
+ }
10
+ loadManifest(manifest) {
11
+ const validation = this.validateManifest(manifest);
12
+ if (!validation.ok)
13
+ return validation;
14
+ const existingNames = new Map();
15
+ for (const definition of [...manifest.agents, ...manifest.subagents]) {
16
+ const existing = this.agents.getByName(manifest.project, manifest.scope, definition.name);
17
+ if (existing.ok)
18
+ existingNames.set(definition.name, true);
19
+ else
20
+ existingNames.set(definition.name, false);
21
+ }
22
+ const transaction = this.database.transaction(() => {
23
+ const agents = [];
24
+ const subagents = [];
25
+ const nameToId = new Map();
26
+ const created = [];
27
+ const updated = [];
28
+ for (const definition of manifest.agents) {
29
+ const registered = this.agents.register(toRegisterInput(manifest, definition, 'agent'));
30
+ if (!registered.ok)
31
+ throw new SeedLoadError(registered.error);
32
+ agents.push(registered.value);
33
+ nameToId.set(registered.value.name, registered.value.id);
34
+ (existingNames.get(definition.name) ? updated : created).push(definition.name);
35
+ }
36
+ for (const definition of manifest.subagents) {
37
+ const parentAgentId = nameToId.get(definition.parentAgentName) ?? this.resolveExistingParentId(manifest, definition.parentAgentName);
38
+ if (parentAgentId === undefined) {
39
+ throw new SeedLoadError({ code: 'validation_failed', message: `Unresolved parentAgentName: ${definition.parentAgentName}` });
40
+ }
41
+ const registered = this.agents.register(toRegisterInput(manifest, definition, 'subagent', parentAgentId));
42
+ if (!registered.ok)
43
+ throw new SeedLoadError(registered.error);
44
+ subagents.push(registered.value);
45
+ (existingNames.get(definition.name) ? updated : created).push(definition.name);
46
+ }
47
+ return { created, updated, agents, subagents, warnings: [] };
48
+ });
49
+ if (!transaction.ok) {
50
+ if (transaction.error.cause instanceof SeedLoadError)
51
+ return { ok: false, error: transaction.error.cause.failure };
52
+ return transaction;
53
+ }
54
+ return transaction;
55
+ }
56
+ validateManifest(manifest) {
57
+ if (manifest.version !== 1)
58
+ return validationFailure('Agent seed manifest version must be 1');
59
+ if (!manifest.project?.trim())
60
+ return validationFailure('Agent seed manifest project is required');
61
+ if (manifest.scope !== 'project' && manifest.scope !== 'personal')
62
+ return validationFailure('Agent seed manifest scope must be project or personal');
63
+ if (!Array.isArray(manifest.agents))
64
+ return validationFailure('Agent seed manifest agents must be an array');
65
+ if (!Array.isArray(manifest.subagents))
66
+ return validationFailure('Agent seed manifest subagents must be an array');
67
+ const managerCount = manifest.agents.filter((agent) => agent.name === requiredManagerName).length;
68
+ if (managerCount !== 1)
69
+ return validationFailure(`Agent seed manifest must declare exactly one ${requiredManagerName} agent`);
70
+ const seenNames = new Set();
71
+ for (const definition of manifest.agents) {
72
+ const validation = validateDefinition(definition, 'agent');
73
+ if (!validation.ok)
74
+ return validation;
75
+ if (seenNames.has(definition.name))
76
+ return validationFailure(`Duplicate seed agent name: ${definition.name}`);
77
+ seenNames.add(definition.name);
78
+ }
79
+ for (const definition of manifest.subagents) {
80
+ const validation = validateDefinition(definition, 'subagent');
81
+ if (!validation.ok)
82
+ return validation;
83
+ if (seenNames.has(definition.name))
84
+ return validationFailure(`Duplicate seed agent name: ${definition.name}`);
85
+ seenNames.add(definition.name);
86
+ if (!definition.parentAgentName.trim())
87
+ return validationFailure(`Subagent ${definition.name} parentAgentName is required`);
88
+ if (!manifest.agents.some((agent) => agent.name === definition.parentAgentName) && this.resolveExistingParentId(manifest, definition.parentAgentName) === undefined) {
89
+ return validationFailure(`Unresolved parentAgentName: ${definition.parentAgentName}`);
90
+ }
91
+ }
92
+ return { ok: true, value: undefined };
93
+ }
94
+ resolveExistingParentId(manifest, parentAgentName) {
95
+ const parent = this.agents.getByName(manifest.project, manifest.scope, parentAgentName);
96
+ if (!parent.ok || parent.value.mode !== 'agent')
97
+ return undefined;
98
+ return parent.value.id;
99
+ }
100
+ }
101
+ function validateDefinition(definition, mode) {
102
+ if (!definition.name?.trim())
103
+ return validationFailure(`Seed ${mode} name is required`);
104
+ if (!definition.description?.trim())
105
+ return validationFailure(`Seed ${mode} ${definition.name} description is required`);
106
+ if (definition.instructions?.kind !== 'inline' && definition.instructions?.kind !== 'path')
107
+ return validationFailure(`Seed ${mode} ${definition.name} instructions kind is invalid`);
108
+ if (!definition.instructions.value.trim())
109
+ return validationFailure(`Seed ${mode} ${definition.name} instructions are required`);
110
+ return { ok: true, value: undefined };
111
+ }
112
+ function toRegisterInput(manifest, definition, mode, parentAgentId) {
113
+ const input = {
114
+ project: manifest.project,
115
+ scope: manifest.scope,
116
+ mode,
117
+ name: definition.name,
118
+ description: definition.description,
119
+ instructions: definition.instructions,
120
+ };
121
+ if (definition.capabilities !== undefined)
122
+ input.capabilities = definition.capabilities;
123
+ if (definition.permissions !== undefined)
124
+ input.permissions = definition.permissions;
125
+ if (definition.memory !== undefined)
126
+ input.memory = definition.memory;
127
+ if (definition.workflows !== undefined)
128
+ input.workflows = definition.workflows;
129
+ if (definition.skills !== undefined)
130
+ input.skills = definition.skills;
131
+ if (definition.adapters !== undefined)
132
+ input.adapters = definition.adapters;
133
+ if (parentAgentId !== undefined)
134
+ input.parentAgentId = parentAgentId;
135
+ return input;
136
+ }
137
+ function validationFailure(message) {
138
+ return { ok: false, error: { code: 'validation_failed', message } };
139
+ }
140
+ class SeedLoadError extends Error {
141
+ failure;
142
+ constructor(failure) {
143
+ super(failure.message);
144
+ this.failure = failure;
145
+ }
146
+ }
@@ -0,0 +1,34 @@
1
+ export class ManagerProfileOverlayService {
2
+ dependencies;
3
+ constructor(dependencies) {
4
+ this.dependencies = dependencies;
5
+ }
6
+ save(input) {
7
+ return this.dependencies.overlays.save(input);
8
+ }
9
+ get(project, scope, managerName) {
10
+ return this.dependencies.overlays.get(project, scope, managerName);
11
+ }
12
+ resolveEffectiveManager(input) {
13
+ const manager = this.dependencies.agents.getAgentByName(input.project, input.scope, input.managerName);
14
+ if (!manager.ok)
15
+ return manager;
16
+ if (manager.value.mode !== 'agent')
17
+ return validationFailure('Effective manager requires a top-level agent');
18
+ const overlay = this.dependencies.overlays.get(input.project, input.scope, input.managerName);
19
+ if (!overlay.ok) {
20
+ if (overlay.error.code === 'not_found')
21
+ return ok({ manager: manager.value });
22
+ return overlay;
23
+ }
24
+ return ok({
25
+ manager: {
26
+ ...manager.value,
27
+ instructions: { kind: 'inline', value: overlay.value.instructions },
28
+ },
29
+ overlay: overlay.value,
30
+ });
31
+ }
32
+ }
33
+ function ok(value) { return { ok: true, value }; }
34
+ function validationFailure(message) { return { ok: false, error: { code: 'validation_failed', message } }; }
@@ -0,0 +1,26 @@
1
+ export function resolveAgentProfileModel(input) {
2
+ const providerAdapter = input.providerAdapter?.trim() || 'opencode';
3
+ const adapters = input.agent.adapters;
4
+ const adapterNames = Object.keys(adapters);
5
+ const adapter = adapters[providerAdapter];
6
+ if (adapterNames.length > 0 && adapter === undefined) {
7
+ return validationFailure(`Agent ${input.agent.name} does not declare provider adapter: ${providerAdapter}`);
8
+ }
9
+ const model = adapter?.model?.trim();
10
+ if (model !== undefined && model.length > 0) {
11
+ const profile = profileFromAdapter(adapter?.config);
12
+ return ok({ providerAdapter, model, ...(profile === undefined ? {} : { profile }), source: 'agent-adapter-model', warnings: [] });
13
+ }
14
+ const previewModel = `${providerAdapter}-preview`;
15
+ const warnings = adapter === undefined
16
+ ? [`Agent does not declare adapters; using provider-neutral preview model ${previewModel}.`]
17
+ : [`Adapter ${providerAdapter} does not declare a model; using ${previewModel}.`];
18
+ const profile = profileFromAdapter(adapter?.config);
19
+ return ok({ providerAdapter, model: previewModel, ...(profile === undefined ? {} : { profile }), source: 'provider-preview-default', warnings });
20
+ }
21
+ function profileFromAdapter(config) {
22
+ const profile = config?.profile;
23
+ return typeof profile === 'string' && profile.trim().length > 0 ? profile.trim() : undefined;
24
+ }
25
+ function ok(value) { return { ok: true, value }; }
26
+ function validationFailure(message) { return { ok: false, error: { code: 'validation_failed', message } }; }
@@ -0,0 +1,98 @@
1
+ import { ok, validationFailure } from './provider-adapter.js';
2
+ const previewWarnings = [
3
+ 'Claude rendering returns preview artifacts only; it does not install or write provider configuration.',
4
+ 'VGX does not execute Claude or run Claude Code from this preview.',
5
+ 'VGX does not install Claude Code, does not write .claude/, does not write CLAUDE.md, and does not write provider configuration.',
6
+ 'VGX does not guarantee exact Claude Code configuration compatibility; this output is a neutral preview only.',
7
+ ];
8
+ const previewSafety = {
9
+ executesProvider: false,
10
+ writesProviderConfig: false,
11
+ installable: false,
12
+ previewOnly: true,
13
+ };
14
+ const claudeCapabilities = {
15
+ supportedAgentFields: ['name', 'description', 'instructions', 'mode', 'adapter model', 'adapter profile', 'permissions', 'memory', 'skills'],
16
+ skillInjectionModes: ['included as neutral skill identifiers in preview output'],
17
+ permissionCategories: ['included as registry permission metadata in preview output'],
18
+ memoryInjectionModes: ['included as registry memory metadata in preview output'],
19
+ delegationModel: 'registry agents and subagents are represented in preview output without executing Claude delegation',
20
+ lifecycleHooks: ['preview render/export only'],
21
+ configFileLocations: ['rendered/claude/.../claude-preview.json'],
22
+ limitations: [
23
+ 'Preview artifacts only; does not execute Claude or Claude Code.',
24
+ 'Does not install Claude Code or provider tooling.',
25
+ 'Does not write .claude/, CLAUDE.md, or provider configuration.',
26
+ 'Does not guarantee exact Claude Code configuration compatibility.',
27
+ ],
28
+ render: {
29
+ format: 'claude-json-preview',
30
+ artifactContentTypes: ['application/json'],
31
+ installable: false,
32
+ previewOnly: true,
33
+ },
34
+ };
35
+ export class ClaudeAgentRenderer {
36
+ provider = 'claude';
37
+ capabilities = claudeCapabilities;
38
+ render(input) {
39
+ const agents = [input.agent, ...(input.subagents ?? [])];
40
+ const renderedAgents = {};
41
+ for (const agent of agents) {
42
+ const key = claudeAgentKey(agent.name);
43
+ if (renderedAgents[key] !== undefined)
44
+ return validationFailure(`Rendered Claude agent key collision: ${key}`);
45
+ renderedAgents[key] = claudePreviewAgent(agent);
46
+ }
47
+ const preview = {
48
+ version: 1,
49
+ provider: 'claude',
50
+ installable: false,
51
+ compatibility: 'preview-only',
52
+ agents: renderedAgents,
53
+ safety: {
54
+ ...previewSafety,
55
+ writesClaudeDirectory: false,
56
+ compatibilityGuaranteed: false,
57
+ },
58
+ warnings: previewWarnings,
59
+ };
60
+ const artifact = {
61
+ relativePath: `rendered/claude/${pathSegment(input.agent.project)}/${input.agent.scope}/${pathSegment(input.agent.name)}/claude-preview.json`,
62
+ contentType: 'application/json',
63
+ contents: `${JSON.stringify(preview, null, 2)}\n`,
64
+ };
65
+ return ok({
66
+ provider: this.provider,
67
+ installable: false,
68
+ artifacts: [artifact],
69
+ warnings: previewWarnings,
70
+ });
71
+ }
72
+ }
73
+ function claudePreviewAgent(agent) {
74
+ const adapter = claudeAdapter(agent);
75
+ const rendered = {
76
+ name: agent.name,
77
+ description: agent.description,
78
+ instructions: agent.instructions.value,
79
+ mode: agent.mode === 'subagent' ? 'subagent' : 'primary',
80
+ ...(adapter?.model !== undefined ? { model: adapter.model } : {}),
81
+ permissions: agent.permissions,
82
+ memory: agent.memory,
83
+ skills: agent.skills,
84
+ };
85
+ const profile = adapter?.config?.profile;
86
+ if (typeof profile === 'string')
87
+ rendered.profile = profile;
88
+ return rendered;
89
+ }
90
+ function claudeAdapter(agent) {
91
+ return agent.adapters.claude ?? agent.adapters['claude-code'];
92
+ }
93
+ function claudeAgentKey(value) {
94
+ return pathSegment(value);
95
+ }
96
+ function pathSegment(value) {
97
+ return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'unnamed';
98
+ }
@@ -0,0 +1,16 @@
1
+ import { ClaudeAgentRenderer } from './claude-renderer.js';
2
+ import { JsonAgentRenderer } from './json-renderer.js';
3
+ import { OpenCodeAgentRenderer } from './opencode-renderer.js';
4
+ import { ok, validationFailure } from './provider-adapter.js';
5
+ const renderers = {
6
+ json: new JsonAgentRenderer(),
7
+ opencode: new OpenCodeAgentRenderer(),
8
+ claude: new ClaudeAgentRenderer(),
9
+ };
10
+ export function getProviderRenderer(provider) {
11
+ const normalized = provider.trim().toLowerCase();
12
+ const renderer = renderers[normalized];
13
+ return renderer === undefined
14
+ ? validationFailure(`Unknown provider renderer: ${provider}`)
15
+ : ok(renderer);
16
+ }
@@ -0,0 +1,87 @@
1
+ import { ok, validationFailure } from './provider-adapter.js';
2
+ const previewSafety = {
3
+ executesProvider: false,
4
+ writesProviderConfig: false,
5
+ installable: false,
6
+ previewOnly: true,
7
+ };
8
+ const jsonCapabilities = {
9
+ supportedAgentFields: ['id', 'project', 'scope', 'mode', 'name', 'description', 'instructions', 'capabilities', 'permissions', 'memory', 'workflows', 'skills', 'adapters', 'timestamps', 'parentAgentId'],
10
+ skillInjectionModes: ['preserved as registry metadata in neutral export'],
11
+ permissionCategories: ['preserved registry permission policy metadata'],
12
+ memoryInjectionModes: ['preserved registry memory scope metadata'],
13
+ delegationModel: 'preserves registry agent/subagent relationships without provider delegation execution',
14
+ lifecycleHooks: ['preview render/export only'],
15
+ configFileLocations: [],
16
+ limitations: [
17
+ 'Generic debug/export output; it is not executable provider configuration.',
18
+ 'Does not execute providers or run lifecycle hooks.',
19
+ 'Does not install provider tooling.',
20
+ 'Does not write provider configuration files.',
21
+ ],
22
+ render: {
23
+ format: 'neutral-json-export',
24
+ artifactContentTypes: ['application/json'],
25
+ installable: false,
26
+ previewOnly: true,
27
+ },
28
+ };
29
+ export class JsonAgentRenderer {
30
+ provider = 'json';
31
+ capabilities = jsonCapabilities;
32
+ render(input) {
33
+ const subagents = input.subagents ?? [];
34
+ const basePath = `rendered/json/${pathSegment(input.agent.project)}/${input.agent.scope}/${pathSegment(input.agent.name)}`;
35
+ const artifacts = [
36
+ jsonArtifact(`${basePath}.agent.json`, renderedDefinition(input.agent, this.provider)),
37
+ jsonArtifact(`${basePath}.manifest.json`, {
38
+ provider: this.provider,
39
+ installable: false,
40
+ safety: previewSafety,
41
+ rootAgentId: input.agent.id,
42
+ rootAgentName: input.agent.name,
43
+ subagentIds: subagents.map((subagent) => subagent.id),
44
+ artifacts: [
45
+ `${basePath}.agent.json`,
46
+ ...subagents.map((subagent) => `${basePath}.subagents/${pathSegment(subagent.name)}.json`),
47
+ ],
48
+ }),
49
+ ...subagents.map((subagent) => jsonArtifact(`${basePath}.subagents/${pathSegment(subagent.name)}.json`, renderedDefinition(subagent, this.provider))),
50
+ ];
51
+ const duplicatePath = firstDuplicate(artifacts.map((artifact) => artifact.relativePath));
52
+ if (duplicatePath !== undefined)
53
+ return validationFailure(`Rendered artifact path collision: ${duplicatePath}`);
54
+ return ok({
55
+ provider: this.provider,
56
+ installable: false,
57
+ artifacts,
58
+ warnings: ['Rendering returns preview artifacts only; it does not install or write provider configuration.'],
59
+ });
60
+ }
61
+ }
62
+ function renderedDefinition(agent, provider) {
63
+ const rendered = { agent, safety: previewSafety };
64
+ const selectedAdapter = agent.adapters[provider];
65
+ if (selectedAdapter !== undefined)
66
+ rendered.selectedAdapter = selectedAdapter;
67
+ return rendered;
68
+ }
69
+ function jsonArtifact(relativePath, value) {
70
+ return {
71
+ relativePath,
72
+ contentType: 'application/json',
73
+ contents: `${JSON.stringify(value, null, 2)}\n`,
74
+ };
75
+ }
76
+ function pathSegment(value) {
77
+ return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'unnamed';
78
+ }
79
+ function firstDuplicate(values) {
80
+ const seen = new Set();
81
+ for (const value of values) {
82
+ if (seen.has(value))
83
+ return value;
84
+ seen.add(value);
85
+ }
86
+ return undefined;
87
+ }
@@ -0,0 +1,100 @@
1
+ import { ok, validationFailure } from './provider-adapter.js';
2
+ const openCodeSchema = 'https://opencode.ai/config.json';
3
+ const previewWarning = 'Rendering returns preview artifacts only; it does not install or write .opencode/, .claude/, or provider configuration.';
4
+ const previewSafety = {
5
+ executesProvider: false,
6
+ writesProviderConfig: false,
7
+ installable: false,
8
+ previewOnly: true,
9
+ };
10
+ const openCodeCapabilities = {
11
+ supportedAgentFields: ['name', 'description', 'instructions', 'mode', 'adapter model', 'adapter config keys: variant, temperature, top_p, hidden, options, color, steps, permission'],
12
+ skillInjectionModes: ['external preview services may inject skill payloads before rendering; renderer does not resolve skills'],
13
+ permissionCategories: ['registry permission metadata mapped from adapter permission config'],
14
+ memoryInjectionModes: ['external preview services may inject memory payloads before rendering; renderer does not load memory'],
15
+ delegationModel: 'registry agents render as primary agents and registry subagents render as subagents without executing delegation',
16
+ lifecycleHooks: ['preview render/export only'],
17
+ configFileLocations: ['rendered/opencode/.../opencode.json'],
18
+ limitations: [
19
+ 'Preview artifacts only; does not execute OpenCode or provider commands.',
20
+ 'Does not install OpenCode or global tooling.',
21
+ 'Does not write .opencode/, .claude/, or provider configuration.',
22
+ 'Does not provide TUI support or sandbox/worktree enforcement.',
23
+ ],
24
+ render: {
25
+ format: 'opencode-json-preview',
26
+ artifactContentTypes: ['application/json'],
27
+ installable: false,
28
+ previewOnly: true,
29
+ },
30
+ };
31
+ export class OpenCodeAgentRenderer {
32
+ provider = 'opencode';
33
+ capabilities = openCodeCapabilities;
34
+ render(input) {
35
+ const agents = [input.agent, ...(input.subagents ?? [])];
36
+ const renderedAgents = {};
37
+ for (const agent of agents) {
38
+ const key = openCodeAgentKey(agent.name);
39
+ if (renderedAgents[key] !== undefined)
40
+ return validationFailure(`Rendered OpenCode agent key collision: ${key}`);
41
+ renderedAgents[key] = openCodeAgentConfig(agent);
42
+ }
43
+ const artifact = {
44
+ relativePath: `rendered/opencode/${pathSegment(input.agent.project)}/${input.agent.scope}/${pathSegment(input.agent.name)}/opencode.json`,
45
+ contentType: 'application/json',
46
+ contents: `${JSON.stringify({ '$schema': openCodeSchema, agent: renderedAgents, safety: previewSafety }, null, 2)}\n`,
47
+ };
48
+ return ok({
49
+ provider: this.provider,
50
+ installable: false,
51
+ artifacts: [artifact],
52
+ warnings: [previewWarning, 'Top-level registry agents render as OpenCode primary agents by default; registry subagents render as OpenCode subagents.'],
53
+ });
54
+ }
55
+ }
56
+ function openCodeAgentConfig(agent) {
57
+ const adapter = agent.adapters.opencode;
58
+ const config = adapter?.config ?? {};
59
+ const rendered = {
60
+ ...(adapter?.model !== undefined ? { model: adapter.model } : {}),
61
+ description: agent.description,
62
+ prompt: agent.instructions.value,
63
+ mode: agent.mode === 'subagent' ? 'subagent' : 'primary',
64
+ };
65
+ copyString(config, rendered, 'variant');
66
+ copyNumber(config, rendered, 'temperature');
67
+ copyNumber(config, rendered, 'top_p');
68
+ copyBoolean(config, rendered, 'hidden');
69
+ copyJson(config, rendered, 'options');
70
+ copyString(config, rendered, 'color');
71
+ copyNumber(config, rendered, 'steps');
72
+ copyJson(config, rendered, 'permission');
73
+ return rendered;
74
+ }
75
+ function copyString(source, target, key) {
76
+ const value = source[key];
77
+ if (typeof value === 'string')
78
+ target[key] = value;
79
+ }
80
+ function copyNumber(source, target, key) {
81
+ const value = source[key];
82
+ if (typeof value === 'number')
83
+ target[key] = value;
84
+ }
85
+ function copyBoolean(source, target, key) {
86
+ const value = source[key];
87
+ if (typeof value === 'boolean')
88
+ target[key] = value;
89
+ }
90
+ function copyJson(source, target, key) {
91
+ const value = source[key];
92
+ if (value !== undefined)
93
+ target[key] = value;
94
+ }
95
+ function openCodeAgentKey(value) {
96
+ return pathSegment(value);
97
+ }
98
+ function pathSegment(value) {
99
+ return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'unnamed';
100
+ }
@@ -0,0 +1,6 @@
1
+ export function validationFailure(message) {
2
+ return { ok: false, error: { code: 'validation_failed', message } };
3
+ }
4
+ export function ok(value) {
5
+ return { ok: true, value };
6
+ }