@microck/canonfig 2.0.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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +263 -0
  3. package/dist/agent/agent-resolution.errors.js +42 -0
  4. package/dist/agent/agent-resolution.layer.js +204 -0
  5. package/dist/agent/agent-resolution.service.js +2259 -0
  6. package/dist/agent/agent-resolution.types.js +1 -0
  7. package/dist/agent/controlled-executor.js +704 -0
  8. package/dist/agent/harness-adapters.js +85 -0
  9. package/dist/cli/cli.js +618 -0
  10. package/dist/cli/exit-codes.js +28 -0
  11. package/dist/cli/follower-commands.js +3 -0
  12. package/dist/cli/render.js +56 -0
  13. package/dist/cli/source-commands.js +5 -0
  14. package/dist/domain/brand.js +29 -0
  15. package/dist/domain/identity.js +31 -0
  16. package/dist/domain/npm-package-spec.js +186 -0
  17. package/dist/domain/profile.js +950 -0
  18. package/dist/domain/recipe-versions.js +297 -0
  19. package/dist/domain/resource.js +259 -0
  20. package/dist/domain/synchronization.js +346 -0
  21. package/dist/enrollment/enrollment.errors.js +43 -0
  22. package/dist/enrollment/enrollment.layer.js +724 -0
  23. package/dist/enrollment/enrollment.service.js +3 -0
  24. package/dist/enrollment/enrollment.types.js +59 -0
  25. package/dist/enrollment/follower-client.js +585 -0
  26. package/dist/enrollment/source-server.js +313 -0
  27. package/dist/machine/linux.layer.js +1183 -0
  28. package/dist/machine/machine-state.errors.js +52 -0
  29. package/dist/machine/machine-state.service.js +3 -0
  30. package/dist/machine/machine-state.types.js +1 -0
  31. package/dist/machine/macos.layer.js +470 -0
  32. package/dist/machine/windows.layer.js +879 -0
  33. package/dist/profile/discovery.js +740 -0
  34. package/dist/profile/profile-catalog.errors.js +50 -0
  35. package/dist/profile/profile-catalog.layer.js +20 -0
  36. package/dist/profile/profile-catalog.service.js +7 -0
  37. package/dist/profile/profile-codec.js +153 -0
  38. package/dist/profile/publication.js +298 -0
  39. package/dist/profile/tool-catalog.js +384 -0
  40. package/dist/runtime/doctor.js +306 -0
  41. package/dist/runtime/layers.js +706 -0
  42. package/dist/runtime/main.js +38 -0
  43. package/dist/schedule/linux-schedule.js +24 -0
  44. package/dist/schedule/macos-schedule.js +25 -0
  45. package/dist/schedule/schedule-manager.errors.js +17 -0
  46. package/dist/schedule/schedule-manager.layer.js +205 -0
  47. package/dist/schedule/schedule-manager.service.js +3 -0
  48. package/dist/schedule/schedule-manager.types.js +114 -0
  49. package/dist/schedule/windows-schedule.js +25 -0
  50. package/dist/state/state-repository.errors.js +55 -0
  51. package/dist/state/state-repository.layer.js +1507 -0
  52. package/dist/state/state-repository.service.js +3 -0
  53. package/dist/state/state-repository.types.js +1 -0
  54. package/dist/state/state-schema.js +298 -0
  55. package/dist/synchronization/config-codec.js +97 -0
  56. package/dist/synchronization/executor.js +700 -0
  57. package/dist/synchronization/follower-orchestration.js +939 -0
  58. package/dist/synchronization/follower-sync-config.js +81 -0
  59. package/dist/synchronization/npm-artifact.js +670 -0
  60. package/dist/synchronization/planner.js +378 -0
  61. package/dist/synchronization/recovery.js +397 -0
  62. package/dist/synchronization/resource-executors.js +1198 -0
  63. package/dist/synchronization/resource-plans.js +645 -0
  64. package/dist/synchronization/synchronization.errors.js +102 -0
  65. package/dist/synchronization/synchronization.layer.js +97 -0
  66. package/dist/synchronization/synchronization.service.js +11 -0
  67. package/dist/synchronization/synchronization.types.js +1 -0
  68. package/package.json +66 -0
@@ -0,0 +1,346 @@
1
+ import { Schema } from "effect";
2
+ import { ActionId, AgentTaskId, BlobId, ContentDigest, FollowerId, ProfileRevisionId, ResourceId as ResourceIdSchema, RunId, Timestamp, } from "./brand.js";
3
+ import { SyncScheduleSchema, } from "../schedule/schedule-manager.types.js";
4
+ import { AutomaticRecipeMethod, BuildPolicy as BuildPolicySchema, RecipeIndexPolicy, } from "./resource.js";
5
+ import { isMissingAutomaticRecipeVersion, RecipeSourceMetadata, recipeValidationError, } from "./recipe-versions.js";
6
+ /** Observed state of one resource target on the follower. */
7
+ export const ObservedObjectKind = Schema.Literals([
8
+ "regular",
9
+ "directory",
10
+ "symlink",
11
+ "reparse-point",
12
+ "special",
13
+ ]);
14
+ export const PlannedActionKindSchema = Schema.Literals([
15
+ "no-op",
16
+ "transfer-blob",
17
+ "write-file",
18
+ "write-config",
19
+ "mirror-directory",
20
+ "remove-resource",
21
+ "schedule-default",
22
+ "install-tool",
23
+ "verify-only",
24
+ "human-action",
25
+ "agent-task",
26
+ "drift-conflict",
27
+ ]);
28
+ const InstallToolActionDetailSchema = Schema.Struct({
29
+ kind: Schema.Literal("install-tool"),
30
+ toolId: Schema.NonEmptyString,
31
+ method: AutomaticRecipeMethod,
32
+ package: Schema.NonEmptyString,
33
+ version: Schema.optional(Schema.NonEmptyString),
34
+ indexPolicy: Schema.optional(RecipeIndexPolicy),
35
+ source: Schema.optional(Schema.Union([
36
+ Schema.NonEmptyString,
37
+ RecipeSourceMetadata,
38
+ ])),
39
+ buildPolicy: Schema.optional(BuildPolicySchema),
40
+ }).check(Schema.makeFilter((detail) => {
41
+ const reason = recipeValidationError(detail);
42
+ return reason === undefined && !isMissingAutomaticRecipeVersion(detail)
43
+ ? undefined
44
+ : {
45
+ path: ["version"],
46
+ issue: reason ?? `automatic installer ${detail.method} requires an exact version`,
47
+ };
48
+ }));
49
+ export const ActionDetailSchema = Schema.Union([
50
+ Schema.Struct({ kind: Schema.Literal("no-op") }),
51
+ Schema.Struct({
52
+ kind: Schema.Literal("transfer-blob"),
53
+ blob: BlobId,
54
+ bytes: Schema.Natural,
55
+ }),
56
+ Schema.Struct({
57
+ kind: Schema.Literal("write-file"),
58
+ target: Schema.NonEmptyString,
59
+ digest: ContentDigest,
60
+ executable: Schema.optional(Schema.Boolean),
61
+ }),
62
+ Schema.Struct({
63
+ kind: Schema.Literal("write-config"),
64
+ target: Schema.NonEmptyString,
65
+ keys: Schema.Array(Schema.NonEmptyString),
66
+ }),
67
+ Schema.Struct({
68
+ kind: Schema.Literal("mirror-directory"),
69
+ target: Schema.NonEmptyString,
70
+ adds: Schema.Array(Schema.NonEmptyString),
71
+ removes: Schema.Array(Schema.NonEmptyString),
72
+ }),
73
+ Schema.Struct({
74
+ kind: Schema.Literal("remove-resource"),
75
+ target: Schema.NonEmptyString,
76
+ paths: Schema.Array(Schema.NonEmptyString),
77
+ keys: Schema.Array(Schema.NonEmptyString),
78
+ schedule: Schema.optional(SyncScheduleSchema),
79
+ }),
80
+ Schema.Struct({
81
+ kind: Schema.Literal("schedule-default"),
82
+ operation: Schema.Literals(["upsert", "remove"]),
83
+ schedule: SyncScheduleSchema,
84
+ previousSchedule: Schema.optional(SyncScheduleSchema),
85
+ }),
86
+ InstallToolActionDetailSchema,
87
+ Schema.Struct({
88
+ kind: Schema.Literal("verify-only"),
89
+ method: Schema.NonEmptyString,
90
+ }),
91
+ Schema.Struct({
92
+ kind: Schema.Literal("human-action"),
93
+ reason: Schema.NonEmptyString,
94
+ instructions: Schema.NonEmptyString,
95
+ }),
96
+ Schema.Struct({
97
+ kind: Schema.Literal("agent-task"),
98
+ taskId: AgentTaskId,
99
+ summary: Schema.NonEmptyString,
100
+ }),
101
+ Schema.Struct({
102
+ kind: Schema.Literal("drift-conflict"),
103
+ target: Schema.NonEmptyString,
104
+ desiredDigest: ContentDigest,
105
+ observedDigest: ContentDigest,
106
+ desiredExecutable: Schema.optional(Schema.Boolean),
107
+ observedExecutable: Schema.optional(Schema.Boolean),
108
+ }),
109
+ ]);
110
+ export const PlannedActionSchema = Schema.Struct({
111
+ id: ActionId,
112
+ resource: ResourceIdSchema,
113
+ kind: PlannedActionKindSchema,
114
+ detail: ActionDetailSchema,
115
+ before: Schema.Array(ActionId),
116
+ });
117
+ export const SynchronizationPlanSchema = Schema.Struct({
118
+ revision: ProfileRevisionId,
119
+ follower: FollowerId,
120
+ actions: Schema.Array(PlannedActionSchema),
121
+ encoded: Schema.String,
122
+ digest: Schema.optional(ContentDigest),
123
+ });
124
+ export const ForbiddenAgentCapabilitySchema = Schema.Literals([
125
+ "elevation",
126
+ "login",
127
+ "restart",
128
+ "reboot",
129
+ ]);
130
+ export const ExecutableAuthorizationSchema = Schema.Struct({
131
+ executable: Schema.NonEmptyString,
132
+ behavior: Schema.Literals(["leaf", "script-interpreter"]),
133
+ });
134
+ export const AgentTaskSchema = Schema.Struct({
135
+ id: AgentTaskId,
136
+ summary: Schema.NonEmptyString,
137
+ desiredOutcome: Schema.NonEmptyString,
138
+ observedEvidence: Schema.Array(Schema.String),
139
+ allowedPaths: Schema.Array(Schema.NonEmptyString),
140
+ allowedExecutables: Schema.Array(Schema.NonEmptyString),
141
+ executableAuthorizations: Schema.optional(Schema.Array(ExecutableAuthorizationSchema)),
142
+ allowedOrigins: Schema.Array(Schema.NonEmptyString),
143
+ forbidden: Schema.Array(ForbiddenAgentCapabilitySchema),
144
+ timeLimitSeconds: Schema.Int.check(Schema.isGreaterThan(0)),
145
+ outputLimitBytes: Schema.Int.check(Schema.isGreaterThan(0)),
146
+ verification: Schema.Struct({
147
+ command: Schema.Array(Schema.NonEmptyString),
148
+ expectContains: Schema.optional(Schema.String),
149
+ }),
150
+ });
151
+ export const HumanActionSchema = Schema.Struct({
152
+ reason: Schema.NonEmptyString,
153
+ instructions: Schema.NonEmptyString,
154
+ resource: Schema.optional(ResourceIdSchema),
155
+ });
156
+ export const HumanActionRequiredSchema = Schema.Struct({
157
+ outcome: Schema.Literal("HumanActionRequired"),
158
+ run: RunId,
159
+ actions: Schema.Array(HumanActionSchema),
160
+ });
161
+ export const DriftConflictSchema = Schema.Struct({
162
+ resource: ResourceIdSchema,
163
+ target: Schema.NonEmptyString,
164
+ desiredDigest: ContentDigest,
165
+ observedDigest: ContentDigest,
166
+ lastAppliedDigest: ContentDigest,
167
+ desiredExecutable: Schema.optional(Schema.Boolean),
168
+ observedExecutable: Schema.optional(Schema.Boolean),
169
+ });
170
+ export const SynchronizationOutcomeSchema = Schema.Union([
171
+ Schema.Struct({
172
+ outcome: Schema.Literal("Converged"),
173
+ run: RunId,
174
+ verified: Schema.Array(ResourceIdSchema),
175
+ }),
176
+ HumanActionRequiredSchema,
177
+ Schema.Struct({
178
+ outcome: Schema.Literal("FollowerDrift"),
179
+ run: RunId,
180
+ conflicts: Schema.Array(DriftConflictSchema),
181
+ }),
182
+ Schema.Struct({
183
+ outcome: Schema.Literal("Failed"),
184
+ run: RunId,
185
+ reason: Schema.NonEmptyString,
186
+ }),
187
+ Schema.Struct({
188
+ outcome: Schema.Literal("Interrupted"),
189
+ run: RunId,
190
+ completedActions: Schema.Array(ActionId),
191
+ }),
192
+ ]);
193
+ export const ObservedResourceStateSchema = Schema.Union([
194
+ Schema.Struct({ state: Schema.Literal("absent") }),
195
+ Schema.Struct({
196
+ state: Schema.Literal("present"),
197
+ digest: ContentDigest,
198
+ executable: Schema.Boolean,
199
+ objectKind: Schema.optional(ObservedObjectKind),
200
+ symlinkTo: Schema.optional(Schema.NonEmptyString),
201
+ }),
202
+ Schema.Struct({
203
+ state: Schema.Literal("directory"),
204
+ objectKind: Schema.optional(ObservedObjectKind),
205
+ files: Schema.Array(Schema.Union([
206
+ Schema.Struct({
207
+ path: Schema.NonEmptyString,
208
+ state: Schema.Literal("absent"),
209
+ }),
210
+ Schema.Struct({
211
+ path: Schema.NonEmptyString,
212
+ digest: ContentDigest,
213
+ executable: Schema.optional(Schema.Boolean),
214
+ objectKind: Schema.optional(ObservedObjectKind),
215
+ }),
216
+ ])),
217
+ }),
218
+ Schema.Struct({
219
+ state: Schema.Literal("unverifiable"),
220
+ reason: Schema.NonEmptyString,
221
+ }),
222
+ ]);
223
+ export const AppliedResourceRecordSchema = Schema.Struct({
224
+ resource: ResourceIdSchema,
225
+ revision: ProfileRevisionId,
226
+ digest: ContentDigest,
227
+ appliedAt: Timestamp,
228
+ kind: Schema.optional(Schema.Literals([
229
+ "file",
230
+ "directory",
231
+ "config",
232
+ "skill",
233
+ "tool",
234
+ "credential",
235
+ "schedule",
236
+ ])),
237
+ policy: Schema.optional(Schema.Literals([
238
+ "replace",
239
+ "mirror-owned",
240
+ "merge",
241
+ "replace-if-unmodified",
242
+ "ensure",
243
+ "require-local",
244
+ ])),
245
+ target: Schema.optional(Schema.NonEmptyString),
246
+ executable: Schema.optional(Schema.Boolean),
247
+ symlinkTo: Schema.optional(Schema.NonEmptyString),
248
+ ownedFiles: Schema.optional(Schema.Array(Schema.Struct({
249
+ path: Schema.NonEmptyString,
250
+ digest: ContentDigest,
251
+ executable: Schema.optional(Schema.Boolean),
252
+ }))),
253
+ ownedKeys: Schema.optional(Schema.Array(Schema.NonEmptyString)),
254
+ configFormat: Schema.optional(Schema.Literals(["toml", "json", "yaml"])),
255
+ schedule: Schema.optional(SyncScheduleSchema),
256
+ });
257
+ /** Runtime schema aliases share names with their corresponding domain types. */
258
+ export const PlannedActionKind = PlannedActionKindSchema;
259
+ export const ActionDetail = ActionDetailSchema;
260
+ export const PlannedAction = PlannedActionSchema;
261
+ export const SynchronizationPlan = SynchronizationPlanSchema;
262
+ export const AgentTask = AgentTaskSchema;
263
+ export const HumanAction = HumanActionSchema;
264
+ export const HumanActionRequired = HumanActionRequiredSchema;
265
+ export const DriftConflict = DriftConflictSchema;
266
+ export const SynchronizationOutcome = SynchronizationOutcomeSchema;
267
+ export const ObservedResourceState = ObservedResourceStateSchema;
268
+ export const AppliedResourceRecord = AppliedResourceRecordSchema;
269
+ export class DuplicateActionError extends Schema.TaggedError()("DuplicateActionError", { id: Schema.String }) {
270
+ }
271
+ export class MissingActionReferenceError extends Schema.TaggedError()("MissingActionReferenceError", { id: Schema.String, before: Schema.String }) {
272
+ }
273
+ export class ActionCycleError extends Schema.TaggedError()("ActionCycleError", { cycle: Schema.Array(Schema.String) }) {
274
+ }
275
+ export class ActionKindMismatchError extends Schema.TaggedError()("ActionKindMismatchError", { id: Schema.String, kind: Schema.String, detailKind: Schema.String }) {
276
+ }
277
+ /** Validate action references, detail compatibility, and action graph acyclicity. */
278
+ export const validateSynchronizationPlan = (plan) => {
279
+ const errors = [];
280
+ const actionIds = new Set();
281
+ for (const action of plan.actions) {
282
+ if (actionIds.has(action.id))
283
+ errors.push(new DuplicateActionError({ id: action.id }));
284
+ actionIds.add(action.id);
285
+ if (action.kind !== action.detail.kind) {
286
+ errors.push(new ActionKindMismatchError({
287
+ id: action.id,
288
+ kind: action.kind,
289
+ detailKind: action.detail.kind,
290
+ }));
291
+ }
292
+ }
293
+ for (const action of plan.actions) {
294
+ for (const before of action.before) {
295
+ if (!actionIds.has(before)) {
296
+ errors.push(new MissingActionReferenceError({ id: action.id, before }));
297
+ }
298
+ }
299
+ }
300
+ const cycle = findActionCycle(plan.actions);
301
+ if (cycle !== null)
302
+ errors.push(new ActionCycleError({ cycle }));
303
+ return errors;
304
+ };
305
+ export const findActionCycle = (actions) => {
306
+ const graph = new Map();
307
+ for (const action of actions)
308
+ graph.set(action.id, action.before);
309
+ const active = [];
310
+ const complete = new Set();
311
+ const visit = (id) => {
312
+ if (complete.has(id))
313
+ return null;
314
+ const index = active.indexOf(id);
315
+ if (index >= 0)
316
+ return [...active.slice(index), id];
317
+ active.push(id);
318
+ for (const next of graph.get(id) ?? []) {
319
+ if (!graph.has(next))
320
+ continue;
321
+ const cycle = visit(next);
322
+ if (cycle !== null)
323
+ return cycle;
324
+ }
325
+ active.pop();
326
+ complete.add(id);
327
+ return null;
328
+ };
329
+ for (const action of actions) {
330
+ const cycle = visit(action.id);
331
+ if (cycle !== null)
332
+ return cycle;
333
+ }
334
+ return null;
335
+ };
336
+ /** Exit codes for the CLI, mapped from outcomes. */
337
+ export const ExitCode = {
338
+ success: 0,
339
+ invalidInput: 2,
340
+ drift: 3,
341
+ humanAction: 4,
342
+ interrupted: 5,
343
+ operationalFailure: 1,
344
+ };
345
+ /** Agent policy schema re-exported for the profile authoring boundary. */
346
+ export { AgentPolicy } from "./identity.js";
@@ -0,0 +1,43 @@
1
+ import { Schema } from "effect";
2
+ export class SourceNotInitializedError extends Schema.TaggedError()("SourceNotInitializedError", { operation: Schema.String }) {
3
+ }
4
+ export class EnrollmentConfigurationError extends Schema.TaggedError()("EnrollmentConfigurationError", {
5
+ operation: Schema.String,
6
+ message: Schema.String,
7
+ }) {
8
+ }
9
+ export class InvitationNotFoundError extends Schema.TaggedError()("InvitationNotFoundError", { message: Schema.String }) {
10
+ }
11
+ export class InvitationExpiredError extends Schema.TaggedError()("InvitationExpiredError", { message: Schema.String }) {
12
+ }
13
+ export class InvitationReplayError extends Schema.TaggedError()("InvitationReplayError", { message: Schema.String }) {
14
+ }
15
+ export class EnrollmentSourceMismatchError extends Schema.TaggedError()("EnrollmentSourceMismatchError", { message: Schema.String }) {
16
+ }
17
+ export class EnrollmentFingerprintMismatchError extends Schema.TaggedError()("EnrollmentFingerprintMismatchError", { message: Schema.String }) {
18
+ }
19
+ export class MalformedEnrollmentRequestError extends Schema.TaggedError()("MalformedEnrollmentRequestError", { message: Schema.String }) {
20
+ }
21
+ export class DuplicateFollowerIdentityError extends Schema.TaggedError()("DuplicateFollowerIdentityError", { message: Schema.String }) {
22
+ }
23
+ export class InvalidFollowerCredentialError extends Schema.TaggedError()("InvalidFollowerCredentialError", { message: Schema.String }) {
24
+ }
25
+ export class RevokedFollowerCredentialError extends Schema.TaggedError()("RevokedFollowerCredentialError", { message: Schema.String }) {
26
+ }
27
+ export class EnrollmentTransportError extends Schema.TaggedError()("EnrollmentTransportError", {
28
+ operation: Schema.String,
29
+ message: Schema.String,
30
+ }) {
31
+ }
32
+ export class TransportResourceNotFoundError extends Schema.TaggedError()("TransportResourceNotFoundError", { resource: Schema.String }) {
33
+ }
34
+ export class TransportUnauthorizedError extends Schema.TaggedError()("TransportUnauthorizedError", { resource: Schema.String }) {
35
+ }
36
+ export class TransportMalformedResponseError extends Schema.TaggedError()("TransportMalformedResponseError", { operation: Schema.String, message: Schema.String }) {
37
+ }
38
+ export class TransportIntegrityError extends Schema.TaggedError()("TransportIntegrityError", { artifact: Schema.String, message: Schema.String }) {
39
+ }
40
+ export class TransportSizeLimitError extends Schema.TaggedError()("TransportSizeLimitError", { artifact: Schema.String, limit: Schema.Number }) {
41
+ }
42
+ export class TransportInterruptedError extends Schema.TaggedError()("TransportInterruptedError", { operation: Schema.String }) {
43
+ }