agentera 3.0.0-dev.14 → 3.0.0-dev.16

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 (221) hide show
  1. package/README.md +43 -22
  2. package/bundle/.codex-plugin/plugin.json +92 -0
  3. package/bundle/.cursor/agents/agentera.md +7 -0
  4. package/bundle/.cursor/hooks.json +32 -0
  5. package/bundle/.cursor-plugin/plugin.json +34 -0
  6. package/bundle/.github/hooks/postToolUse.json +9 -0
  7. package/bundle/.github/hooks/preToolUse.json +8 -0
  8. package/bundle/.github/hooks/sessionEnd.json +8 -0
  9. package/bundle/.github/hooks/sessionStart.json +8 -0
  10. package/bundle/.github/plugin/plugin.json +7 -0
  11. package/bundle/.opencode/agents/agentera.md +12 -0
  12. package/bundle/.opencode/commands/agentera.md +5 -0
  13. package/bundle/.opencode/package.json +31 -0
  14. package/bundle/.opencode/plugins/agentera.js +820 -0
  15. package/bundle/CHANGELOG.md +1075 -0
  16. package/bundle/DESIGN.md +233 -0
  17. package/bundle/LICENSE +201 -0
  18. package/bundle/README.md +137 -0
  19. package/bundle/UPGRADE.md +188 -0
  20. package/bundle/agents/openai.yaml +87 -0
  21. package/bundle/extract-corpus-parity.json +2 -4
  22. package/bundle/hooks/codex-hooks.json +31 -0
  23. package/bundle/hooks/codex-plugin-hooks.json +31 -0
  24. package/bundle/plugin.json +13 -0
  25. package/bundle/references/adapters/cursor.md +50 -40
  26. package/bundle/references/adapters/opencode.md +22 -23
  27. package/bundle/references/adapters/package-manifest-interface-model.yaml +36 -43
  28. package/bundle/references/adapters/package-registry.yaml +19 -52
  29. package/bundle/references/adapters/package-surface-characterization.md +61 -47
  30. package/bundle/references/adapters/runtime-adapter-characterization.md +44 -79
  31. package/bundle/references/adapters/runtime-adapter-registry.yaml +7 -169
  32. package/bundle/references/adapters/runtime-feature-parity.md +99 -167
  33. package/bundle/references/adapters/runtime-lifecycle-adapters.yaml +288 -0
  34. package/bundle/references/adapters/runtime-lifecycle-authority.yaml +73 -0
  35. package/bundle/references/adapters/runtime-lifecycle-operation-contract.yaml +83 -0
  36. package/bundle/references/adapters/runtime-retired-resources.yaml +33 -0
  37. package/bundle/references/analysis/benchmark.md +5 -5
  38. package/bundle/references/analysis/startup-measurement-contract.yaml +19 -8
  39. package/bundle/references/cli/bundle-skill-vocabulary.yaml +2 -2
  40. package/bundle/references/cli/vocabulary-index.yaml +1 -1
  41. package/bundle/references/cli/vocabulary.md +7 -7
  42. package/bundle/skills/agentera/SKILL.md +43 -2
  43. package/bundle/skills/agentera/references/contract.md +10 -3
  44. package/bundle/skills/agentera/schemas/artifacts/decisions.yaml +1 -1
  45. package/bundle/skills/agentera/schemas/artifacts/experiments.yaml +1 -1
  46. package/bundle/skills/agentera/schemas/artifacts/health.yaml +1 -1
  47. package/bundle/skills/agentera/schemas/artifacts/progress.yaml +1 -1
  48. package/dist/analytics/extractCorpus/cli.js +19 -5
  49. package/dist/analytics/extractCorpus/cli.js.map +1 -1
  50. package/dist/analytics/extractCorpus/copilotSessions.js +6 -3
  51. package/dist/analytics/extractCorpus/copilotSessions.js.map +1 -1
  52. package/dist/analytics/extractCorpus/core.js +40 -11
  53. package/dist/analytics/extractCorpus/core.js.map +1 -1
  54. package/dist/analytics/extractCorpus/corpus.js +39 -16
  55. package/dist/analytics/extractCorpus/corpus.js.map +1 -1
  56. package/dist/analytics/extractCorpus/coverageAudit.js +44 -44
  57. package/dist/analytics/extractCorpus/coverageAudit.js.map +1 -1
  58. package/dist/analytics/extractCorpus/cursorSessions.js +6 -3
  59. package/dist/analytics/extractCorpus/cursorSessions.js.map +1 -1
  60. package/dist/analytics/extractCorpus/extractCorpusParity.js +2 -2
  61. package/dist/analytics/extractCorpus/extractCorpusParity.js.map +1 -1
  62. package/dist/analytics/extractCorpus/filesystemSources.js +1 -4
  63. package/dist/analytics/extractCorpus/filesystemSources.js.map +1 -1
  64. package/dist/analytics/extractCorpus/jsonlSessions.js +24 -4
  65. package/dist/analytics/extractCorpus/jsonlSessions.js.map +1 -1
  66. package/dist/analytics/usageStats.js +51 -7
  67. package/dist/analytics/usageStats.js.map +1 -1
  68. package/dist/bin/agentera.js +3 -1
  69. package/dist/bin/agentera.js.map +1 -1
  70. package/dist/capabilities/audit/instructions.js +1 -1
  71. package/dist/capabilities/audit/instructions.js.map +1 -1
  72. package/dist/capabilities/build/instructions.js +1 -1
  73. package/dist/capabilities/build/instructions.js.map +1 -1
  74. package/dist/capabilities/discuss/instructions.js +1 -1
  75. package/dist/capabilities/discuss/instructions.js.map +1 -1
  76. package/dist/capabilities/orchestrate/instructions.js +1 -1
  77. package/dist/capabilities/orchestrate/instructions.js.map +1 -1
  78. package/dist/capabilities/plan/instructions.js +1 -1
  79. package/dist/capabilities/plan/instructions.js.map +1 -1
  80. package/dist/capabilities/profile/instructions.js +1 -1
  81. package/dist/capabilities/profile/instructions.js.map +1 -1
  82. package/dist/cli/capabilityContext/contract.js +2 -0
  83. package/dist/cli/capabilityContext/contract.js.map +1 -1
  84. package/dist/cli/capabilityContext/startup.js +2 -0
  85. package/dist/cli/capabilityContext/startup.js.map +1 -1
  86. package/dist/cli/commands/compact.js +1 -1
  87. package/dist/cli/commands/compact.js.map +1 -1
  88. package/dist/cli/commands/doctor.js +66 -4
  89. package/dist/cli/commands/doctor.js.map +1 -1
  90. package/dist/cli/commands/prime/collectOrientationState.js +15 -1
  91. package/dist/cli/commands/prime/collectOrientationState.js.map +1 -1
  92. package/dist/cli/commands/prime/orientationOutput.js +15 -1
  93. package/dist/cli/commands/prime/orientationOutput.js.map +1 -1
  94. package/dist/cli/commands/report.js +19 -4
  95. package/dist/cli/commands/report.js.map +1 -1
  96. package/dist/cli/commands/schema.js +79 -3
  97. package/dist/cli/commands/schema.js.map +1 -1
  98. package/dist/cli/commands/state/write.js +341 -0
  99. package/dist/cli/commands/state/write.js.map +1 -0
  100. package/dist/cli/commands/upgrade.js +18 -2
  101. package/dist/cli/commands/upgrade.js.map +1 -1
  102. package/dist/cli/commands/verify.js +6 -6
  103. package/dist/cli/commands/verify.js.map +1 -1
  104. package/dist/cli/dispatch/index.js +2 -1
  105. package/dist/cli/dispatch/index.js.map +1 -1
  106. package/dist/cli/dispatch/lifecycle.js +71 -3
  107. package/dist/cli/dispatch/lifecycle.js.map +1 -1
  108. package/dist/cli/dispatch/state.js +4 -0
  109. package/dist/cli/dispatch/state.js.map +1 -1
  110. package/dist/cli/errors.js +1 -0
  111. package/dist/cli/errors.js.map +1 -1
  112. package/dist/cli/help.js +34 -8
  113. package/dist/cli/help.js.map +1 -1
  114. package/dist/cli/prime-blob.js +68 -2
  115. package/dist/cli/prime-blob.js.map +1 -1
  116. package/dist/cli/startupCompletenessContract.js +1 -1
  117. package/dist/cli/startupCompletenessContract.js.map +1 -1
  118. package/dist/core/atomicWriter.js +21 -0
  119. package/dist/core/atomicWriter.js.map +1 -0
  120. package/dist/core/yaml.js +8 -0
  121. package/dist/core/yaml.js.map +1 -1
  122. package/dist/eval/evalSkills.js +13 -13
  123. package/dist/eval/evalSkills.js.map +1 -1
  124. package/dist/hooks/common.js +3 -3
  125. package/dist/hooks/common.js.map +1 -1
  126. package/dist/hooks/compaction/index.js +2 -2
  127. package/dist/hooks/compaction/index.js.map +1 -1
  128. package/dist/hooks/compaction/status.js +3 -3
  129. package/dist/hooks/compaction/status.js.map +1 -1
  130. package/dist/hooks/validateArtifact/runtime.js +4 -4
  131. package/dist/hooks/validateArtifact/schema.js +82 -6
  132. package/dist/hooks/validateArtifact/schema.js.map +1 -1
  133. package/dist/hooks/validateArtifact/violations.js +5 -2
  134. package/dist/hooks/validateArtifact/violations.js.map +1 -1
  135. package/dist/migrate/v2HandoffManifest.js +4 -0
  136. package/dist/migrate/v2HandoffManifest.js.map +1 -1
  137. package/dist/registries/artifactRegistry.js +39 -6
  138. package/dist/registries/artifactRegistry.js.map +1 -1
  139. package/dist/registries/packageRegistry.js +36 -3
  140. package/dist/registries/packageRegistry.js.map +1 -1
  141. package/dist/registries/runtimeAdapterRegistry.js +22 -16
  142. package/dist/registries/runtimeAdapterRegistry.js.map +1 -1
  143. package/dist/runtime/lifecycleAdapterContract.js +436 -0
  144. package/dist/runtime/lifecycleAdapterContract.js.map +1 -0
  145. package/dist/runtime/lifecycleAdapters.js +707 -0
  146. package/dist/runtime/lifecycleAdapters.js.map +1 -0
  147. package/dist/runtime/lifecycleAuthority.js +443 -0
  148. package/dist/runtime/lifecycleAuthority.js.map +1 -0
  149. package/dist/runtime/lifecycleOperationContract.js +109 -0
  150. package/dist/runtime/lifecycleOperationContract.js.map +1 -0
  151. package/dist/runtime/lifecycleOperations.js +627 -0
  152. package/dist/runtime/lifecycleOperations.js.map +1 -0
  153. package/dist/runtime/lifecycleOwnershipJournal.js +623 -0
  154. package/dist/runtime/lifecycleOwnershipJournal.js.map +1 -0
  155. package/dist/runtime/lifecyclePublication.js +395 -0
  156. package/dist/runtime/lifecyclePublication.js.map +1 -0
  157. package/dist/runtime/lifecycleSnapshot.js +174 -0
  158. package/dist/runtime/lifecycleSnapshot.js.map +1 -0
  159. package/dist/runtime/retiredRuntimeCleanup.js +232 -0
  160. package/dist/runtime/retiredRuntimeCleanup.js.map +1 -0
  161. package/dist/setup/codex/installRoot.js +1 -1
  162. package/dist/setup/codex/installRoot.js.map +1 -1
  163. package/dist/setup/copilot.js +1 -1
  164. package/dist/setup/copilot.js.map +1 -1
  165. package/dist/setup/cursor.js +1 -1
  166. package/dist/setup/cursor.js.map +1 -1
  167. package/dist/setup/doctor/core.js +3 -3
  168. package/dist/setup/doctor/core.js.map +1 -1
  169. package/dist/setup/doctor/diagnostics.js +0 -39
  170. package/dist/setup/doctor/diagnostics.js.map +1 -1
  171. package/dist/setup/smokeChecks.js +1 -3
  172. package/dist/setup/smokeChecks.js.map +1 -1
  173. package/dist/state/startupAnalysis/helpers.js +1 -1
  174. package/dist/state/startupAnalysis/helpers.js.map +1 -1
  175. package/dist/state/write/assign.js +21 -0
  176. package/dist/state/write/assign.js.map +1 -0
  177. package/dist/state/write/errors.js +12 -0
  178. package/dist/state/write/errors.js.map +1 -0
  179. package/dist/state/write/explain.js +151 -0
  180. package/dist/state/write/explain.js.map +1 -0
  181. package/dist/state/write/fields.js +62 -0
  182. package/dist/state/write/fields.js.map +1 -0
  183. package/dist/state/write/index.js +11 -0
  184. package/dist/state/write/index.js.map +1 -0
  185. package/dist/state/write/input.js +22 -0
  186. package/dist/state/write/input.js.map +1 -0
  187. package/dist/state/write/lock.js +108 -0
  188. package/dist/state/write/lock.js.map +1 -0
  189. package/dist/state/write/operations.js +181 -0
  190. package/dist/state/write/operations.js.map +1 -0
  191. package/dist/state/write/serialize.js +2 -0
  192. package/dist/state/write/serialize.js.map +1 -0
  193. package/dist/state/write/transaction.js +619 -0
  194. package/dist/state/write/transaction.js.map +1 -0
  195. package/dist/state/write/validate.js +8 -0
  196. package/dist/state/write/validate.js.map +1 -0
  197. package/dist/upgrade/appContentRefresh.js +8 -1
  198. package/dist/upgrade/appContentRefresh.js.map +1 -1
  199. package/dist/upgrade/atomicWriter.js +1 -22
  200. package/dist/upgrade/atomicWriter.js.map +1 -1
  201. package/dist/upgrade/doctor.js +4 -0
  202. package/dist/upgrade/doctor.js.map +1 -1
  203. package/dist/upgrade/lifecycleUpgrade.js +386 -0
  204. package/dist/upgrade/lifecycleUpgrade.js.map +1 -0
  205. package/dist/upgrade/migrateArtifactsV2ToV3.js.map +1 -1
  206. package/dist/upgrade/runtimeMigration.js +1 -8
  207. package/dist/upgrade/runtimeMigration.js.map +1 -1
  208. package/dist/upgrade/upgradeCommands.js +8 -0
  209. package/dist/upgrade/upgradeCommands.js.map +1 -1
  210. package/dist/upgrade/upgradeOrchestrator.js +148 -5
  211. package/dist/upgrade/upgradeOrchestrator.js.map +1 -1
  212. package/dist/validate/appHomeContract.js +1 -1
  213. package/dist/validate/appHomeContract.js.map +1 -1
  214. package/dist/validate/lifecycleAdapters/nodeFormChecks.js +2 -9
  215. package/dist/validate/lifecycleAdapters/nodeFormChecks.js.map +1 -1
  216. package/dist/validate/lifecycleAdapters/shared.js +1 -1
  217. package/dist/validate/lifecycleAdapters/shared.js.map +1 -1
  218. package/dist/validate/lifecycleAdapters.js +77 -2
  219. package/dist/validate/lifecycleAdapters.js.map +1 -1
  220. package/package.json +1 -1
  221. package/bundle/skills/agentera/.claude-plugin/plugin.json +0 -27
@@ -0,0 +1,707 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { buildRuntimeLifecycleState, loadLifecycleAuthority, } from "./lifecycleAuthority.js";
4
+ import { RUNTIME_ADAPTER_CATEGORIES, loadRuntimeLifecycleAdapterContract, } from "./lifecycleAdapterContract.js";
5
+ import { applyLifecycleOperations, createLifecycleOwnershipManifest, emptyLifecycleOwnershipLedger, planLifecycleOperations, } from "./lifecycleOperations.js";
6
+ const STATE_PRIORITY = {
7
+ blocked_unowned: 100,
8
+ action_required: 95,
9
+ denied: 90,
10
+ shadowed: 80,
11
+ drifted: 70,
12
+ absent: 60,
13
+ unknown: 40,
14
+ unsupported: 30,
15
+ confirmed: 20,
16
+ not_applicable: 10,
17
+ };
18
+ function aggregateState(states) {
19
+ if (states.length === 0)
20
+ return "unknown";
21
+ return [...states].sort((left, right) => STATE_PRIORITY[right] - STATE_PRIORITY[left])[0];
22
+ }
23
+ function opencodeConfig(home, env) {
24
+ const xdg = env.XDG_CONFIG_HOME;
25
+ return xdg ? path.resolve(xdg, "opencode") : path.resolve(home, ".config", "opencode");
26
+ }
27
+ function templateValues(context) {
28
+ const env = context.env ?? process.env;
29
+ return {
30
+ home: path.resolve(context.home),
31
+ project: path.resolve(context.project),
32
+ source_root: path.resolve(context.sourceRoot),
33
+ opencode_config: opencodeConfig(context.home, env),
34
+ };
35
+ }
36
+ function expandTemplate(template, values) {
37
+ const expanded = template.replace(/\{([a-z_]+)\}/g, (_match, key) => {
38
+ const value = values[key];
39
+ if (!value)
40
+ throw new Error(`unknown lifecycle adapter path template {${key}}`);
41
+ return value;
42
+ });
43
+ if (/[{}]/.test(expanded))
44
+ throw new Error(`unresolved lifecycle adapter path template ${template}`);
45
+ return path.resolve(expanded);
46
+ }
47
+ function expandResource(declaration, values) {
48
+ const sourcePath = expandTemplate(declaration.source, values);
49
+ const destinationPath = expandTemplate(declaration.destination, values);
50
+ if (declaration.kind === "directory_files") {
51
+ let entries;
52
+ try {
53
+ entries = fs.readdirSync(sourcePath)
54
+ .filter((name) => name.endsWith(declaration.extension))
55
+ .sort();
56
+ }
57
+ catch (error) {
58
+ return [{
59
+ declaration,
60
+ sourcePath,
61
+ destinationPath,
62
+ sourceError: `could not read declared source directory: ${error.message}`,
63
+ }];
64
+ }
65
+ if (entries.length === 0) {
66
+ return [{ declaration, sourcePath, destinationPath, sourceError: "declared source directory is empty" }];
67
+ }
68
+ return entries.map((name) => {
69
+ const source = path.join(sourcePath, name);
70
+ const destination = path.join(destinationPath, name);
71
+ if (source === destination) {
72
+ return { declaration, sourcePath: source, destinationPath: destination, alreadyInPlace: true };
73
+ }
74
+ try {
75
+ return {
76
+ declaration,
77
+ sourcePath: source,
78
+ destinationPath: destination,
79
+ operation: {
80
+ id: `${declaration.id}.${path.basename(name, declaration.extension)}`,
81
+ destination,
82
+ kind: "file",
83
+ intent: "ensure",
84
+ content: fs.readFileSync(source),
85
+ required: declaration.required,
86
+ },
87
+ };
88
+ }
89
+ catch (error) {
90
+ return {
91
+ declaration,
92
+ sourcePath: source,
93
+ destinationPath: destination,
94
+ sourceError: `could not read declared source: ${error.message}`,
95
+ };
96
+ }
97
+ });
98
+ }
99
+ if (sourcePath === destinationPath) {
100
+ return [{ declaration, sourcePath, destinationPath, alreadyInPlace: true }];
101
+ }
102
+ if (declaration.kind === "symlink") {
103
+ if (!fs.existsSync(sourcePath)) {
104
+ return [{ declaration, sourcePath, destinationPath, sourceError: "declared symlink source is missing" }];
105
+ }
106
+ return [{
107
+ declaration,
108
+ sourcePath,
109
+ destinationPath,
110
+ operation: {
111
+ id: declaration.id,
112
+ destination: destinationPath,
113
+ kind: "symlink",
114
+ intent: "ensure",
115
+ linkTarget: sourcePath,
116
+ required: declaration.required,
117
+ },
118
+ }];
119
+ }
120
+ try {
121
+ return [{
122
+ declaration,
123
+ sourcePath,
124
+ destinationPath,
125
+ operation: {
126
+ id: declaration.id,
127
+ destination: destinationPath,
128
+ kind: "file",
129
+ intent: "ensure",
130
+ content: fs.readFileSync(sourcePath),
131
+ required: declaration.required,
132
+ },
133
+ }];
134
+ }
135
+ catch (error) {
136
+ return [{
137
+ declaration,
138
+ sourcePath,
139
+ destinationPath,
140
+ sourceError: `could not read declared source: ${error.message}`,
141
+ }];
142
+ }
143
+ }
144
+ function nearestPlanState(operation) {
145
+ switch (operation.action) {
146
+ case "noop": return "confirmed";
147
+ case "create": return "absent";
148
+ case "update":
149
+ case "finalize_ownership": return "drifted";
150
+ case "blocked_unowned": return "blocked_unowned";
151
+ case "action_required": return operation.ownership === "unowned" ? "blocked_unowned" : "action_required";
152
+ case "remove": return "action_required";
153
+ }
154
+ }
155
+ function probeSkill(location, canonical, surfaces) {
156
+ const skillFile = path.join(location, "SKILL.md");
157
+ try {
158
+ const stat = fs.lstatSync(skillFile);
159
+ if (!stat.isFile()) {
160
+ return { location, canonical, surfaces, state: "drifted", detail: "SKILL.md is not a regular file" };
161
+ }
162
+ const handle = fs.openSync(skillFile, "r");
163
+ try {
164
+ const bytes = Buffer.alloc(Math.min(stat.size, 64 * 1024));
165
+ fs.readSync(handle, bytes, 0, bytes.length, 0);
166
+ const text = bytes.toString("utf8");
167
+ if (!/^name:\s*agentera\s*$/m.test(text)) {
168
+ return { location, canonical, surfaces, state: "drifted", detail: "SKILL.md does not declare name: agentera" };
169
+ }
170
+ return { location, canonical, surfaces, state: "confirmed", detail: "Agentera SKILL.md detected" };
171
+ }
172
+ finally {
173
+ fs.closeSync(handle);
174
+ }
175
+ }
176
+ catch (error) {
177
+ if (error.code === "ENOENT") {
178
+ return { location, canonical, surfaces, state: "absent", detail: "Agentera SKILL.md is absent" };
179
+ }
180
+ return {
181
+ location,
182
+ canonical,
183
+ surfaces,
184
+ state: "unknown",
185
+ detail: `Agentera skill detection failed: ${error.message}`,
186
+ };
187
+ }
188
+ }
189
+ function probeBinary(binaries, env) {
190
+ const searchPath = env.PATH;
191
+ if (searchPath === undefined)
192
+ return "unknown";
193
+ let unknown = false;
194
+ for (const directory of searchPath.split(path.delimiter).slice(0, 128)) {
195
+ if (!directory)
196
+ continue;
197
+ for (const binary of binaries) {
198
+ try {
199
+ fs.accessSync(path.join(directory, binary), fs.constants.X_OK);
200
+ return true;
201
+ }
202
+ catch (error) {
203
+ if (error.code !== "ENOENT" && error.code !== "EACCES") {
204
+ unknown = true;
205
+ }
206
+ }
207
+ }
208
+ }
209
+ return unknown ? "unknown" : false;
210
+ }
211
+ function evidenceState(value, category) {
212
+ if (value === true)
213
+ return "confirmed";
214
+ if (value === "denied" || (category === "trust" && value === false))
215
+ return "denied";
216
+ if (value === false)
217
+ return "absent";
218
+ if (value === "not_applicable")
219
+ return "not_applicable";
220
+ return "unknown";
221
+ }
222
+ function resourceReports(expanded, plan, category, surfaceId) {
223
+ const matching = expanded.filter((resource) => resource.declaration.category === category
224
+ && (resource.declaration.surfaceId === undefined || resource.declaration.surfaceId === surfaceId));
225
+ const evidence = [];
226
+ const states = [];
227
+ const operations = [];
228
+ for (const resource of matching) {
229
+ if (resource.sourceError) {
230
+ states.push("unknown");
231
+ evidence.push({
232
+ kind: "filesystem",
233
+ state: "unknown",
234
+ detail: resource.sourceError,
235
+ path: resource.sourcePath,
236
+ surfaceId,
237
+ });
238
+ continue;
239
+ }
240
+ if (resource.alreadyInPlace) {
241
+ states.push("confirmed");
242
+ evidence.push({
243
+ kind: "filesystem",
244
+ state: "confirmed",
245
+ detail: "declared source and destination are the same repository-owned path",
246
+ path: resource.destinationPath,
247
+ surfaceId,
248
+ });
249
+ continue;
250
+ }
251
+ const operation = resource.operation
252
+ ? plan.operations.find((candidate) => candidate.id === resource.operation?.id)
253
+ : undefined;
254
+ const state = operation ? nearestPlanState(operation) : "unknown";
255
+ states.push(state);
256
+ if (operation)
257
+ operations.push(operation);
258
+ evidence.push({
259
+ kind: "ownership",
260
+ state,
261
+ detail: operation?.reason ?? "declared resource has no operation plan",
262
+ path: resource.destinationPath,
263
+ surfaceId,
264
+ });
265
+ }
266
+ return {
267
+ state: matching.length === 0 ? "unknown" : aggregateState(states),
268
+ evidence,
269
+ operations,
270
+ };
271
+ }
272
+ function actionRequiredSummary(operations) {
273
+ const missingParentOperations = operations.filter((operation) => operation.reason === "allowed root is not an existing safe directory");
274
+ if (missingParentOperations.length === operations.length) {
275
+ const parents = [...new Set(missingParentOperations.map((operation) => path.dirname(operation.destination)))];
276
+ return `Create the destination parent ${parents.join(", ")} as a real, non-symlink directory you control, then rerun preview; Agentera will not create or replace it.`;
277
+ }
278
+ return `Resolve these lifecycle blockers manually, then rerun preview: ${operations
279
+ .map((operation) => `${operation.id}: ${operation.reason}`)
280
+ .join("; ")}.`;
281
+ }
282
+ function remediationFor(state, claim, operations, nativeActions, runtimeId, surfaceId, evidencePath, sourceRoot) {
283
+ const blockedOperations = operations.filter((operation) => operation.action === "blocked_unowned");
284
+ if (blockedOperations.length > 0) {
285
+ return {
286
+ kind: "action_required",
287
+ summary: "The destination is not ledger-owned; review the collision manually. Agentera will not adopt it by name or equality.",
288
+ operationIds: blockedOperations.map((operation) => operation.id),
289
+ nativeActions: [],
290
+ };
291
+ }
292
+ const actionRequiredOperations = operations.filter((operation) => operation.action === "action_required" || operation.action === "remove");
293
+ if (actionRequiredOperations.length > 0) {
294
+ return {
295
+ kind: "action_required",
296
+ summary: actionRequiredSummary(actionRequiredOperations),
297
+ operationIds: actionRequiredOperations.map((operation) => operation.id),
298
+ nativeActions: [],
299
+ };
300
+ }
301
+ if (nativeActions.length > 0) {
302
+ return {
303
+ kind: "action_required",
304
+ summary: "Host-native actions are user-owned and are reported for manual execution only.",
305
+ operationIds: [],
306
+ nativeActions: nativeActions.map((action) => ({
307
+ id: action.id,
308
+ kind: action.actionKind,
309
+ command: action.command,
310
+ instruction: action.instruction,
311
+ })),
312
+ };
313
+ }
314
+ const repairOperations = operations.filter((operation) => ["create", "update", "finalize_ownership"].includes(operation.action));
315
+ if (["absent", "drifted"].includes(state) && repairOperations.length > 0) {
316
+ return {
317
+ kind: "repair",
318
+ summary: "Preview and approve the declared Agentera-owned operations through the shared lifecycle engine.",
319
+ operationIds: repairOperations.map((operation) => operation.id),
320
+ nativeActions: [],
321
+ };
322
+ }
323
+ if (state === "action_required") {
324
+ return {
325
+ kind: "action_required",
326
+ summary: "Review the action-required evidence and complete the user-owned step, then rerun preview.",
327
+ operationIds: [],
328
+ nativeActions: [],
329
+ };
330
+ }
331
+ if (claim.remediation === "action_required") {
332
+ let summary = `Review ${runtimeId} ${surfaceId} ${claim.evidence} manually; Agentera will not mutate host-owned configuration or trust.`;
333
+ if (claim.evidence.startsWith("path:") && evidencePath) {
334
+ summary = `Edit ${evidencePath} and set AGENTERA_HOME to ${sourceRoot}; Agentera will not edit or trust this user-owned configuration.`;
335
+ }
336
+ else if (claim.evidence === "env:AGENTERA_HOME") {
337
+ summary = `Launch ${runtimeId} ${surfaceId} with AGENTERA_HOME=${sourceRoot} in its environment.`;
338
+ }
339
+ else if (claim.evidence === "external_observation") {
340
+ summary = `Review ${runtimeId} ${surfaceId} in the host trust or enablement UI and approve or deny it there; Agentera will only observe the result.`;
341
+ }
342
+ return { kind: "action_required", summary, operationIds: [], nativeActions: [] };
343
+ }
344
+ if (state === "confirmed" || state === "not_applicable") {
345
+ return { kind: "none", summary: "No remediation is required.", operationIds: [], nativeActions: [] };
346
+ }
347
+ return {
348
+ kind: "unavailable",
349
+ summary: claim.capability === "unsupported"
350
+ ? "The host surface is explicitly unsupported."
351
+ : "No verified safe remediation is declared for this host surface.",
352
+ operationIds: [],
353
+ nativeActions: [],
354
+ };
355
+ }
356
+ function assertSurfaceRemediationConsistency(category, state, operations, remediation) {
357
+ if (category !== "native_actions" && remediation.nativeActions.length > 0) {
358
+ throw new Error(`${category}: native actions may only remediate the native_actions category`);
359
+ }
360
+ const blocked = operations.some((operation) => operation.action === "blocked_unowned");
361
+ const actionRequired = operations.some((operation) => operation.action === "action_required" || operation.action === "remove");
362
+ if (blocked && (state !== "blocked_unowned" || remediation.kind !== "action_required")) {
363
+ throw new Error(`${category}: blocked operation must produce blocked_unowned action-required reporting`);
364
+ }
365
+ if (!blocked && actionRequired && (state !== "action_required" || remediation.kind !== "action_required")) {
366
+ throw new Error(`${category}: action-required operation must produce action_required reporting`);
367
+ }
368
+ if (remediation.kind === "repair") {
369
+ const repairableIds = new Set(operations
370
+ .filter((operation) => ["create", "update", "finalize_ownership"].includes(operation.action))
371
+ .map((operation) => operation.id));
372
+ if (remediation.operationIds.length === 0
373
+ || remediation.operationIds.some((operationId) => !repairableIds.has(operationId))) {
374
+ throw new Error(`${category}: repair remediation must reference only repairable plan operations`);
375
+ }
376
+ }
377
+ }
378
+ function categorySurface(runtimeId, surface, category, claim, expected, context, values, expanded, plan, skills, nativeActions) {
379
+ if (!expected) {
380
+ return {
381
+ surfaceId: surface.id,
382
+ expected: false,
383
+ state: "not_applicable",
384
+ capability: "not_applicable",
385
+ source: claim.evidence,
386
+ required: false,
387
+ diagnosisComplete: true,
388
+ evidence: [{
389
+ kind: "host_probe",
390
+ state: "not_applicable",
391
+ detail: "conditional host surface is absent",
392
+ surfaceId: surface.id,
393
+ }],
394
+ remediation: { kind: "none", summary: "No remediation is required.", operationIds: [], nativeActions: [] },
395
+ };
396
+ }
397
+ let state;
398
+ let evidence = [];
399
+ let operations = [];
400
+ let evidencePath;
401
+ if (category === "skills") {
402
+ const relevant = skills.filter((skill) => skill.surfaces.includes(surface.id));
403
+ const canonical = relevant.find((skill) => skill.canonical);
404
+ const nonCanonical = relevant.filter((skill) => !skill.canonical && skill.state === "confirmed");
405
+ state = canonical?.state ?? "unknown";
406
+ if (nonCanonical.length > 0)
407
+ state = "shadowed";
408
+ evidence = relevant.map((skill) => ({
409
+ kind: "filesystem",
410
+ state: skill.state,
411
+ detail: skill.canonical
412
+ ? `${skill.detail}; canonical shared location`
413
+ : `${skill.detail}; additional discovery location can shadow or collide with canonical Agentera`,
414
+ path: skill.location,
415
+ surfaceId: surface.id,
416
+ }));
417
+ const resources = resourceReports(expanded, plan, category, surface.id);
418
+ operations = resources.operations;
419
+ evidence.push(...resources.evidence);
420
+ state = aggregateState([state, resources.state]);
421
+ }
422
+ else if (claim.capability === "repairable" || claim.evidence.startsWith("managed_resource:")) {
423
+ const resourceCategory = claim.evidence.startsWith("managed_resource:")
424
+ ? expanded.find((resource) => resource.declaration.id === claim.evidence.slice("managed_resource:".length))?.declaration.category ?? category
425
+ : category;
426
+ const resources = resourceReports(expanded, plan, resourceCategory, surface.id);
427
+ state = resources.state;
428
+ evidence = resources.evidence;
429
+ operations = resources.operations;
430
+ }
431
+ else if (claim.capability === "not_applicable") {
432
+ state = "not_applicable";
433
+ evidence = [{ kind: "contract", state, detail: claim.evidence, surfaceId: surface.id }];
434
+ }
435
+ else if (claim.capability === "unsupported") {
436
+ state = "unsupported";
437
+ evidence = [{ kind: "contract", state, detail: claim.evidence, surfaceId: surface.id }];
438
+ }
439
+ else if (category === "native_actions" && nativeActions.length > 0) {
440
+ state = "action_required";
441
+ evidence = nativeActions.map((action) => ({
442
+ kind: "native_action",
443
+ state,
444
+ detail: action.instruction,
445
+ surfaceId: surface.id,
446
+ }));
447
+ }
448
+ else if (claim.evidence.startsWith("path:")) {
449
+ evidencePath = expandTemplate(claim.evidence.slice("path:".length), values);
450
+ try {
451
+ const present = fs.lstatSync(evidencePath).isFile();
452
+ state = present ? "confirmed" : "drifted";
453
+ }
454
+ catch (error) {
455
+ state = error.code === "ENOENT" ? "absent" : "unknown";
456
+ }
457
+ evidence = [{ kind: "filesystem", state, detail: claim.evidence, path: evidencePath, surfaceId: surface.id }];
458
+ }
459
+ else if (claim.evidence.startsWith("env:")) {
460
+ const key = claim.evidence.slice("env:".length);
461
+ const value = (context.env ?? process.env)[key];
462
+ state = value ? "confirmed" : "absent";
463
+ evidence = [{
464
+ kind: "environment",
465
+ state,
466
+ detail: value ? `${key} is present` : `${key} is absent`,
467
+ surfaceId: surface.id,
468
+ }];
469
+ }
470
+ else if (claim.evidence === "canonical_skill") {
471
+ const canonical = skills.find((skill) => skill.canonical && skill.surfaces.includes(surface.id));
472
+ state = canonical?.state ?? "unknown";
473
+ evidence = [{
474
+ kind: "filesystem",
475
+ state,
476
+ detail: canonical?.detail ?? "canonical skill was not diagnosed",
477
+ path: canonical?.location,
478
+ surfaceId: surface.id,
479
+ }];
480
+ const resources = resourceReports(expanded, plan, "skills", surface.id);
481
+ operations = resources.operations;
482
+ evidence.push(...resources.evidence);
483
+ state = aggregateState([state, resources.state]);
484
+ }
485
+ else {
486
+ const override = context.categoryEvidence?.[category]?.[surface.id]
487
+ ?? (category === "trust" ? context.surfaceEvidence?.[surface.id]?.trusted : undefined)
488
+ ?? (category === "enablement" ? context.surfaceEvidence?.[surface.id]?.enabled : undefined);
489
+ state = evidenceState(override ?? "unknown", category);
490
+ evidence = [{
491
+ kind: "contract",
492
+ state,
493
+ detail: override === undefined ? `${claim.evidence}; no verified host observation was supplied` : claim.evidence,
494
+ surfaceId: surface.id,
495
+ }];
496
+ }
497
+ const diagnosisComplete = claim.required
498
+ ? state !== "unknown" && claim.capability !== "unverified"
499
+ : true;
500
+ const remediation = remediationFor(state, claim, operations, nativeActions, runtimeId, surface.id, evidencePath, context.sourceRoot);
501
+ assertSurfaceRemediationConsistency(category, state, operations, remediation);
502
+ return {
503
+ surfaceId: surface.id,
504
+ expected,
505
+ state,
506
+ capability: claim.capability,
507
+ source: claim.evidence,
508
+ required: claim.required,
509
+ diagnosisComplete,
510
+ evidence,
511
+ remediation,
512
+ };
513
+ }
514
+ function canonicalDetection(skills) {
515
+ const canonical = skills.find((skill) => skill.canonical);
516
+ if (!canonical || canonical.state === "unknown")
517
+ return "unknown";
518
+ return canonical.state === "confirmed" ? true : false;
519
+ }
520
+ function lifecycleObservation(runtimeId, surfaces, hostPresence, categories, canonicalSkillDetected, diagnosisComplete, context) {
521
+ return {
522
+ runtimeId,
523
+ canonicalSkillDetected,
524
+ diagnosisComplete,
525
+ unmetMandatoryFields: [],
526
+ surfaces: surfaces.map((surface) => {
527
+ const host = hostPresence[surface.id] ?? "unknown";
528
+ const expected = surface.presence === "required" || host === true;
529
+ const skill = categories.skills.surfaces.find((item) => item.surfaceId === surface.id);
530
+ const trust = context.categoryEvidence?.trust?.[surface.id]
531
+ ?? context.surfaceEvidence?.[surface.id]?.trusted
532
+ ?? "unknown";
533
+ let enabled;
534
+ if (!expected)
535
+ enabled = "not_applicable";
536
+ else if (context.surfaceEvidence?.[surface.id]?.enabled !== undefined) {
537
+ enabled = context.surfaceEvidence[surface.id].enabled;
538
+ }
539
+ else if (skill?.state === "confirmed")
540
+ enabled = true;
541
+ else if (skill?.state === "absent")
542
+ enabled = false;
543
+ else
544
+ enabled = "unknown";
545
+ return {
546
+ id: surface.id,
547
+ evidence: {
548
+ host_present: host,
549
+ installed: !expected ? "not_applicable" : canonicalSkillDetected,
550
+ enabled,
551
+ trusted: !expected ? "not_applicable" : trust,
552
+ },
553
+ diagnosisComplete: expected ? skill?.diagnosisComplete === true : true,
554
+ };
555
+ }),
556
+ };
557
+ }
558
+ export class RuntimeLifecycleAdapter {
559
+ runtimeId;
560
+ contract;
561
+ authority;
562
+ runtime;
563
+ runtimeAuthority;
564
+ constructor(runtimeId, contract = loadRuntimeLifecycleAdapterContract(), authority = loadLifecycleAuthority()) {
565
+ this.runtimeId = runtimeId;
566
+ this.contract = contract;
567
+ this.authority = authority;
568
+ const runtime = contract.adapters.find((candidate) => candidate.runtimeId === runtimeId);
569
+ const runtimeAuthority = authority.runtimes.find((candidate) => candidate.id === runtimeId);
570
+ if (!runtime || !runtimeAuthority)
571
+ throw new Error(`unknown active runtime adapter ${runtimeId}`);
572
+ this.runtime = runtime;
573
+ this.runtimeAuthority = runtimeAuthority;
574
+ }
575
+ inspect(context) {
576
+ const env = context.env ?? process.env;
577
+ const values = templateValues(context);
578
+ const declarations = this.runtime.resourceRefs.map((id) => {
579
+ const declaration = this.contract.resources.find((candidate) => candidate.id === id);
580
+ if (!declaration)
581
+ throw new Error(`${this.runtimeId}: missing declared resource ${id}`);
582
+ return declaration;
583
+ });
584
+ const expanded = declarations.flatMap((declaration) => expandResource(declaration, values))
585
+ .map((resource) => {
586
+ if (resource.declaration.id !== "canonical_skill"
587
+ || resource.operation?.kind !== "symlink"
588
+ || !context.canonicalSkillTarget)
589
+ return resource;
590
+ const target = path.resolve(context.canonicalSkillTarget);
591
+ return {
592
+ ...resource,
593
+ sourcePath: target,
594
+ operation: { ...resource.operation, linkTarget: target },
595
+ };
596
+ });
597
+ const operations = expanded.flatMap((resource) => resource.operation ? [resource.operation] : []);
598
+ const allowedRoots = [...new Set([
599
+ path.resolve(context.sourceRoot),
600
+ ...(context.canonicalSkillTarget ? [path.resolve(context.canonicalSkillTarget, "..")] : []),
601
+ ...expanded.map((resource) => path.dirname(resource.destinationPath)),
602
+ ])];
603
+ const repairPlan = planLifecycleOperations({
604
+ allowedRoots,
605
+ operations,
606
+ manifest: createLifecycleOwnershipManifest(operations),
607
+ ledger: context.ledger ?? emptyLifecycleOwnershipLedger(),
608
+ });
609
+ const skills = this.runtime.skillLocations.map((location) => probeSkill(expandTemplate(location.path, values), location.canonical, location.surfaces));
610
+ const hostPresence = {};
611
+ for (const surface of this.runtimeAuthority.surfaces) {
612
+ hostPresence[surface.id] = context.surfaceEvidence?.[surface.id]?.host_present
613
+ ?? probeBinary(this.runtime.binaries[surface.id], env);
614
+ }
615
+ const categories = {};
616
+ for (const category of RUNTIME_ADAPTER_CATEGORIES) {
617
+ const surfaceReports = this.runtimeAuthority.surfaces.map((surface) => {
618
+ const host = hostPresence[surface.id];
619
+ const expected = surface.presence === "required" || host === true;
620
+ return categorySurface(this.runtimeId, surface, category, this.runtime.categories[category][surface.id], expected, context, values, expanded, repairPlan, skills, category === "native_actions"
621
+ ? this.runtime.nativeActions.filter((action) => action.surfaceId === surface.id)
622
+ : []);
623
+ });
624
+ categories[category] = {
625
+ category,
626
+ state: aggregateState(surfaceReports.map((surface) => surface.state)),
627
+ diagnosisComplete: surfaceReports.every((surface) => surface.diagnosisComplete),
628
+ capabilities: [...new Set(surfaceReports.map((surface) => surface.capability))],
629
+ surfaces: surfaceReports,
630
+ };
631
+ }
632
+ const detected = canonicalDetection(skills);
633
+ const requiredSkillReports = categories.skills.surfaces.filter((surface) => surface.required);
634
+ const diagnosisComplete = detected !== "unknown"
635
+ && requiredSkillReports.length > 0
636
+ && requiredSkillReports.every((surface) => surface.diagnosisComplete);
637
+ const observation = lifecycleObservation(this.runtimeId, this.runtimeAuthority.surfaces, hostPresence, categories, detected, diagnosisComplete, context);
638
+ const authoritativeState = buildRuntimeLifecycleState(this.authority, [observation])
639
+ .runtimes.find((runtime) => runtime.runtimeId === this.runtimeId);
640
+ if (!authoritativeState)
641
+ throw new Error(`${this.runtimeId}: lifecycle authority state is missing`);
642
+ const supportFloor = {
643
+ ...authoritativeState.supportFloor,
644
+ diagnosisComplete,
645
+ };
646
+ const expectedCategorySurfaces = RUNTIME_ADAPTER_CATEGORIES.flatMap((category) => categories[category].surfaces.filter((surface) => surface.expected));
647
+ const degraded = expectedCategorySurfaces.some((surface) => !["confirmed", "not_applicable"].includes(surface.state));
648
+ const caveats = [
649
+ ...this.contract.caveats,
650
+ ...expanded
651
+ .filter((resource) => resource.sourceError)
652
+ .map((resource) => `${resource.declaration.id}: ${resource.sourceError}`),
653
+ ];
654
+ return {
655
+ schemaVersion: "agentera.runtimeAdapterReport.v1",
656
+ runtimeId: this.runtimeId,
657
+ displayName: this.runtimeAuthority.displayName,
658
+ status: authoritativeState.status === "blocked" ? "blocked" : degraded ? "degraded" : "ready",
659
+ categories,
660
+ canonicalSkill: { path: this.authority.canonicalSkillPath, detected },
661
+ supportFloor,
662
+ lifecycleObservation: observation,
663
+ repairPlan,
664
+ caveats,
665
+ };
666
+ }
667
+ }
668
+ export class OpenCodeLifecycleAdapter extends RuntimeLifecycleAdapter {
669
+ constructor(contract, authority) {
670
+ super("opencode", contract, authority);
671
+ }
672
+ }
673
+ export class CodexLifecycleAdapter extends RuntimeLifecycleAdapter {
674
+ constructor(contract, authority) {
675
+ super("codex", contract, authority);
676
+ }
677
+ }
678
+ export class CursorLifecycleAdapter extends RuntimeLifecycleAdapter {
679
+ constructor(contract, authority) {
680
+ super("cursor", contract, authority);
681
+ }
682
+ }
683
+ export class CopilotLifecycleAdapter extends RuntimeLifecycleAdapter {
684
+ constructor(contract, authority) {
685
+ super("copilot", contract, authority);
686
+ }
687
+ }
688
+ export function runtimeLifecycleAdapters(contract = loadRuntimeLifecycleAdapterContract(), authority = loadLifecycleAuthority()) {
689
+ return [
690
+ new OpenCodeLifecycleAdapter(contract, authority),
691
+ new CodexLifecycleAdapter(contract, authority),
692
+ new CursorLifecycleAdapter(contract, authority),
693
+ new CopilotLifecycleAdapter(contract, authority),
694
+ ];
695
+ }
696
+ export function inspectRuntimeLifecycleAdapters(context, contract = loadRuntimeLifecycleAdapterContract(), authority = loadLifecycleAuthority()) {
697
+ const reports = runtimeLifecycleAdapters(contract, authority).map((adapter) => adapter.inspect(context));
698
+ return {
699
+ schemaVersion: "agentera.runtimeAdapterMatrix.v1",
700
+ reports,
701
+ lifecycleState: buildRuntimeLifecycleState(authority, reports.map((report) => report.lifecycleObservation)),
702
+ };
703
+ }
704
+ export function applyRuntimeAdapterRepair(report, options = {}) {
705
+ return applyLifecycleOperations(report.repairPlan, options);
706
+ }
707
+ //# sourceMappingURL=lifecycleAdapters.js.map