@aiwg/cli 2026.10.5 → 2026.10.6

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 (212) hide show
  1. package/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
  2. package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
  3. package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
  4. package/agentic/code/providers/model-capabilities.v1.json +74 -50
  5. package/bin/aiwg.mjs +3 -1
  6. package/dist/src/artifacts/browser-export.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +8 -1
  8. package/dist/src/artifacts/cli.js +57 -6
  9. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  10. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  11. package/dist/src/artifacts/graph-query.js +18 -8
  12. package/dist/src/artifacts/index-adapters.js +339 -0
  13. package/dist/src/artifacts/index-builder.js +143 -14
  14. package/dist/src/artifacts/index-files.js +15 -4
  15. package/dist/src/artifacts/index-reader.js +44 -0
  16. package/dist/src/artifacts/index-refresh.js +114 -55
  17. package/dist/src/artifacts/index-status.js +20 -5
  18. package/dist/src/artifacts/memory-maintenance.js +503 -0
  19. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  20. package/dist/src/artifacts/query-engine.js +263 -108
  21. package/dist/src/artifacts/relations-builder.js +2 -2
  22. package/dist/src/artifacts/source-graph.js +2 -2
  23. package/dist/src/artifacts/types.js +9 -1
  24. package/dist/src/cli/handlers/decision.js +19 -1
  25. package/dist/src/cli/handlers/guided-setup.js +470 -0
  26. package/dist/src/cli/handlers/help.js +2 -2
  27. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  28. package/dist/src/cli/handlers/index.js +4 -2
  29. package/dist/src/cli/handlers/init.js +41 -6
  30. package/dist/src/cli/handlers/local-executor.js +5 -3
  31. package/dist/src/cli/handlers/mc.js +509 -53
  32. package/dist/src/cli/handlers/models.js +32 -2
  33. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  34. package/dist/src/cli/handlers/rules.js +1 -1
  35. package/dist/src/cli/handlers/script-runner.js +73 -2
  36. package/dist/src/cli/handlers/serve.js +5 -3
  37. package/dist/src/cli/handlers/sessions.js +1 -0
  38. package/dist/src/cli/handlers/setup.js +428 -1
  39. package/dist/src/cli/handlers/skill-lint.js +1 -1
  40. package/dist/src/cli/handlers/subcommands.js +118 -8
  41. package/dist/src/cli/handlers/use.js +279 -93
  42. package/dist/src/cli/handlers/workspace.js +3 -1
  43. package/dist/src/cli/prompt-utils.js +8 -0
  44. package/dist/src/cli/router.js +16 -1
  45. package/dist/src/config/aiwg-config.js +42 -0
  46. package/dist/src/config/cli.js +7 -3
  47. package/dist/src/config/decision-config.js +14 -1
  48. package/dist/src/config/native-sandbox-warnings.js +25 -0
  49. package/dist/src/contributors/validation.js +6 -5
  50. package/dist/src/decision/admission.js +7 -3
  51. package/dist/src/decision/benchmark.js +469 -0
  52. package/dist/src/decision/ledger.js +22 -3
  53. package/dist/src/decision/pricing.js +147 -0
  54. package/dist/src/decision/qualification/gate-evidence.js +18 -15
  55. package/dist/src/decision/qualification/load-staged.js +539 -0
  56. package/dist/src/decision/qualification/load.js +109 -33
  57. package/dist/src/decision/qualification/runner.js +5 -2
  58. package/dist/src/decision/review/service.js +6 -4
  59. package/dist/src/decision/review/validate.js +23 -2
  60. package/dist/src/decision/savings.js +8 -3
  61. package/dist/src/discovery/index.js +492 -0
  62. package/dist/src/discovery/interview.js +233 -0
  63. package/dist/src/discovery/plan-apply.js +571 -0
  64. package/dist/src/discovery/plan-store.js +171 -0
  65. package/dist/src/discovery/plan-types.js +2 -0
  66. package/dist/src/discovery/plan-validation.js +139 -0
  67. package/dist/src/discovery/types.js +2 -0
  68. package/dist/src/extensions/commands/definitions.js +49 -9
  69. package/dist/src/extensions/manifest.js +71 -44
  70. package/dist/src/extensions/project-local-discovery.js +1 -1
  71. package/dist/src/extensions/project-quickref.js +18 -17
  72. package/dist/src/extensions/validation.js +32 -29
  73. package/dist/src/housekeeper/daemon-config.js +148 -0
  74. package/dist/src/housekeeper/ipc.js +84 -0
  75. package/dist/src/housekeeper/lifecycle.js +148 -0
  76. package/dist/src/housekeeper/platform.js +35 -0
  77. package/dist/src/housekeeper/status.js +70 -0
  78. package/dist/src/housekeeper/units.js +114 -0
  79. package/dist/src/jobs/flow.js +22 -21
  80. package/dist/src/lint/rule-activation.js +20 -5
  81. package/dist/src/lint/runner.js +1 -1
  82. package/dist/src/mcp/cli.mjs +5 -6
  83. package/dist/src/mcp/config-file.mjs +6 -2
  84. package/dist/src/mcp/config-layers.mjs +23 -7
  85. package/dist/src/mcp/profiles.js +18 -31
  86. package/dist/src/mcp/profiles.mjs +18 -32
  87. package/dist/src/mcp/registry.js +7 -27
  88. package/dist/src/mcp/registry.mjs +7 -28
  89. package/dist/src/mcp/server.mjs +34 -1
  90. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  91. package/dist/src/mcp/tools/command-run.mjs +3 -2
  92. package/dist/src/mcp/tools/decision.mjs +49 -48
  93. package/dist/src/mcp/tools/discovery.mjs +46 -21
  94. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  95. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  96. package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
  97. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  98. package/dist/src/memory/audit.js +719 -0
  99. package/dist/src/memory/canonical-context.js +392 -13
  100. package/dist/src/memory/canonical-maintenance.js +95 -0
  101. package/dist/src/memory/cli-result.js +22 -0
  102. package/dist/src/memory/cli.js +176 -0
  103. package/dist/src/memory/context-pack.js +57 -6
  104. package/dist/src/memory/cost.js +512 -0
  105. package/dist/src/memory/firewall-classification.d.mts +7 -0
  106. package/dist/src/memory/firewall-classification.mjs +32 -0
  107. package/dist/src/memory/index.js +8 -0
  108. package/dist/src/memory/line-maintenance.js +68 -0
  109. package/dist/src/memory/maintenance-cli.js +286 -0
  110. package/dist/src/memory/maintenance-contract.js +136 -0
  111. package/dist/src/memory/maintenance-index.js +18 -0
  112. package/dist/src/memory/maintenance-owner.js +2 -0
  113. package/dist/src/memory/maintenance-record.js +138 -0
  114. package/dist/src/memory/maintenance.js +254 -0
  115. package/dist/src/memory/provider-memory-adapter.js +154 -0
  116. package/dist/src/memory/recommend-cli.js +83 -0
  117. package/dist/src/memory/recommend.js +269 -0
  118. package/dist/src/memory/scheduled.js +81 -0
  119. package/dist/src/memory/taxonomy.js +44 -0
  120. package/dist/src/mission-protocol/codecs.js +19 -9
  121. package/dist/src/models/config-loader.js +11 -1
  122. package/dist/src/models/model-capabilities.v1.json +74 -50
  123. package/dist/src/models/provider-policy.js +125 -62
  124. package/dist/src/models/resolver.js +45 -8
  125. package/dist/src/models/worker-installation.d.mts +7 -0
  126. package/dist/src/models/worker-installation.mjs +169 -37
  127. package/dist/src/models/wrapper-route.js +1 -1
  128. package/dist/src/output-modes/registry.js +8 -7
  129. package/dist/src/plugin/metadata-validator.js +1 -1
  130. package/dist/src/providers/deploy-version.d.mts +1 -0
  131. package/dist/src/providers/deploy-version.mjs +17 -0
  132. package/dist/src/providers/provider-definitions.js +19 -16
  133. package/dist/src/providers/skill-ownership.d.mts +11 -2
  134. package/dist/src/providers/skill-ownership.mjs +35 -17
  135. package/dist/src/rules/activation.d.mts +11 -2
  136. package/dist/src/rules/activation.mjs +82 -6
  137. package/dist/src/rules/inventory.js +1 -1
  138. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  139. package/dist/src/schema/zod-validation.d.mts +6 -0
  140. package/dist/src/schema/zod-validation.mjs +50 -0
  141. package/dist/src/serve/executor-registry.js +297 -20
  142. package/dist/src/serve/executor-token.d.mts +1 -0
  143. package/dist/src/serve/executor-token.mjs +8 -0
  144. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  145. package/dist/src/serve/worker-invocation.js +114 -15
  146. package/dist/src/sessions/adapters/claude.js +19 -18
  147. package/dist/src/sessions/adapters/codex.js +10 -9
  148. package/dist/src/sessions/adapters/copilot.js +14 -13
  149. package/dist/src/sessions/adapters/cursor.js +19 -18
  150. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  151. package/dist/src/sessions/adapters/factory.js +11 -10
  152. package/dist/src/sessions/adapters/generic.js +32 -23
  153. package/dist/src/sessions/adapters/grokbot.js +35 -35
  154. package/dist/src/sessions/adapters/hermes.js +20 -19
  155. package/dist/src/sessions/adapters/muse.js +50 -49
  156. package/dist/src/sessions/adapters/omp.js +5 -4
  157. package/dist/src/sessions/adapters/openclaw.js +30 -29
  158. package/dist/src/sessions/adapters/opencode.js +26 -26
  159. package/dist/src/sessions/adapters/openhuman.js +24 -23
  160. package/dist/src/sessions/adapters/pi.js +5 -4
  161. package/dist/src/sessions/adapters/windsurf.js +8 -8
  162. package/dist/src/sessions/analytics.js +10 -9
  163. package/dist/src/sessions/candidates.js +7 -6
  164. package/dist/src/sessions/contracts.js +63 -53
  165. package/dist/src/sessions/output-registration.js +11 -10
  166. package/dist/src/sessions/workspace-discovery.js +3 -4
  167. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  168. package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
  169. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  170. package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
  171. package/dist/src/update/checker.d.mts +4 -0
  172. package/dist/src/update/checker.mjs +14 -0
  173. package/dist/src/writing/exemplar-selection.js +6 -6
  174. package/dist/src/writing/voice-evaluation.js +24 -23
  175. package/dist/src/writing/writer-migration.js +14 -13
  176. package/dist/src/writing/writer-profile.js +19 -18
  177. package/dist/src/writing/writing-brief.js +18 -17
  178. package/dist/src/writing/writing-receipt.js +47 -46
  179. package/package.json +5 -2
  180. package/schemas/decision/DecisionReview.schema.json +78 -1
  181. package/schemas/mission-v1.schema.json +3 -0
  182. package/tools/agents/deploy-agents.mjs +67 -39
  183. package/tools/agents/providers/antigravity.mjs +6 -1
  184. package/tools/agents/providers/base.mjs +19 -13
  185. package/tools/agents/providers/claude.mjs +1 -1
  186. package/tools/agents/providers/codex.mjs +50 -56
  187. package/tools/agents/providers/copilot.mjs +8 -2
  188. package/tools/agents/providers/cursor.mjs +1 -1
  189. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  190. package/tools/agents/providers/factory.mjs +7 -1
  191. package/tools/agents/providers/grok-build.mjs +18 -2
  192. package/tools/agents/providers/grokbot.mjs +1 -1
  193. package/tools/agents/providers/hermes.mjs +7 -13
  194. package/tools/agents/providers/muse-hooks.mjs +21 -14
  195. package/tools/agents/providers/muse.mjs +7 -2
  196. package/tools/agents/providers/omp.mjs +28 -4
  197. package/tools/agents/providers/opencode.mjs +14 -5
  198. package/tools/agents/providers/openhuman.mjs +1 -1
  199. package/tools/agents/providers/pi.mjs +1 -1
  200. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  201. package/tools/agents/providers/rule-delivery.mjs +263 -71
  202. package/tools/agents/providers/windsurf.mjs +7 -0
  203. package/tools/cli/workspace-status.mjs +5 -0
  204. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  205. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  206. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  207. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  208. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  209. package/tools/ralph-external/process-monitor.mjs +7 -4
  210. package/tools/ralph-external/session-launcher.mjs +280 -32
  211. package/tools/skills/deploy-skills-codex.mjs +11 -7
  212. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -13,6 +13,7 @@
13
13
  * @architecture .aiwg/architecture/design-manifest-schema.md
14
14
  */
15
15
  import { z } from 'zod';
16
+ import { integer, dateTime, url } from '../schema/zod-validation.mjs';
16
17
  import { PlatformCompatibilitySchema, DeploymentConfigSchema, MemoryFootprintSchema, DeprecationSchema, } from './validation.js';
17
18
  // ============================================
18
19
  // Limits (from #1042 threat model + #1044 design)
@@ -58,7 +59,7 @@ const ArtifactListsSchema = z.object({
58
59
  behaviors: z.array(z.string()).max(50).optional(),
59
60
  gatePacks: z.array(z.string().min(1).max(128)).max(50).optional(),
60
61
  });
61
- const EntryPathsSchema = z.object({
62
+ const EntryPathsSchema = z.strictObject({
62
63
  agents: safeRelativePath.optional(),
63
64
  skills: safeRelativePath.optional(),
64
65
  rules: safeRelativePath.optional(),
@@ -68,37 +69,37 @@ const EntryPathsSchema = z.object({
68
69
  commands: safeRelativePath.optional(),
69
70
  behaviors: safeRelativePath.optional(),
70
71
  gatePacks: safeRelativePath.optional(),
71
- }).strict();
72
- export const AddonConfigSchema = z.object({
72
+ });
73
+ export const AddonConfigSchema = z.strictObject({
73
74
  entry: EntryPathsSchema.optional(),
74
75
  ...ArtifactListsSchema.shape,
75
76
  core: z.boolean().optional(),
76
77
  autoInstall: z.boolean().optional(),
77
- }).strict();
78
- export const FrameworkConfigSchema = z.object({
78
+ });
79
+ export const FrameworkConfigSchema = z.strictObject({
79
80
  path: safeRelativePath.optional(),
80
81
  files: z.array(safeRelativePath).max(100).optional(),
81
82
  ignore: z.array(safeRelativePath).max(100).optional(),
82
83
  gatePacks: z.array(z.string().min(1).max(128)).max(50).optional(),
83
- entry: z.object({
84
+ entry: z.strictObject({
84
85
  gatePacks: safeRelativePath.optional(),
85
- }).strict().optional(),
86
- contextContributions: z.object({
86
+ }).optional(),
87
+ contextContributions: z.strictObject({
87
88
  hookFragment: safeRelativePath.optional(),
88
89
  sectionsDir: safeRelativePath.optional(),
89
90
  sectionsManifest: safeRelativePath.optional(),
90
- priority: z.number().int().min(0).max(100).optional(),
91
+ priority: integer().min(0).max(100).optional(),
91
92
  description: z.string().max(512).optional(),
92
- }).strict().optional(),
93
- }).strict();
94
- export const ExtensionConfigSchema = z.object({
93
+ }).optional(),
94
+ });
95
+ export const ExtensionConfigSchema = z.strictObject({
95
96
  entry: EntryPathsSchema.optional(),
96
97
  ...ArtifactListsSchema.shape,
97
- }).strict();
98
- export const PluginConfigSchema = z.object({
98
+ });
99
+ export const PluginConfigSchema = z.strictObject({
99
100
  payloadType: z.enum(['addon', 'framework', 'extension']),
100
101
  payloadPath: safeRelativePath,
101
- }).strict();
102
+ });
102
103
  const ProviderCapabilityFeatureSchema = z.enum([
103
104
  'cron',
104
105
  'agent_teams',
@@ -116,11 +117,11 @@ const ProviderCapabilityEmulationSchema = z.enum([
116
117
  'aiwg-daemon',
117
118
  'external-trigger',
118
119
  ]).nullable();
119
- const ProviderCapabilityOverridesSchema = z.object({
120
- nativeFeatures: z.record(ProviderCapabilityFeatureSchema, z.boolean()).optional(),
121
- emulation: z.record(ProviderCapabilityFeatureSchema, ProviderCapabilityEmulationSchema).optional(),
122
- }).strict();
123
- export const ProviderConfigSchema = z.object({
120
+ const ProviderCapabilityOverridesSchema = z.strictObject({
121
+ nativeFeatures: z.partialRecord(ProviderCapabilityFeatureSchema, z.boolean()).optional(),
122
+ emulation: z.partialRecord(ProviderCapabilityFeatureSchema, ProviderCapabilityEmulationSchema).optional(),
123
+ });
124
+ export const ProviderConfigSchema = z.strictObject({
124
125
  extends: z.enum([
125
126
  'claude',
126
127
  'codex',
@@ -142,7 +143,7 @@ export const ProviderConfigSchema = z.object({
142
143
  displayName: z.string().min(1).max(128).optional(),
143
144
  aliases: z.array(z.string().min(1).max(64)).max(20).optional(),
144
145
  capabilities: ProviderCapabilityOverridesSchema.optional(),
145
- }).strict();
146
+ });
146
147
  /**
147
148
  * Review attestation for one gate metric provider (#2831).
148
149
  *
@@ -152,11 +153,11 @@ export const ProviderConfigSchema = z.object({
152
153
  * registration refuses absent attestations and digest mismatches. Null or
153
154
  * unknown digests never verify: they fail closed.
154
155
  */
155
- export const GateProviderReviewSchema = z.object({
156
+ export const GateProviderReviewSchema = z.strictObject({
156
157
  reviewer: z.string().min(1).max(128),
157
- reviewedAt: z.string().datetime(),
158
+ reviewedAt: dateTime(),
158
159
  codeDigest: z.string().regex(/^sha256:[0-9a-f]{64}$/, 'must be a sha256 digest'),
159
- }).strict();
160
+ });
160
161
  /**
161
162
  * One addon/extension gate metric provider declared by a bundle manifest
162
163
  * (#2831). The module is loaded ONLY through the gates registry from this
@@ -165,16 +166,16 @@ export const GateProviderReviewSchema = z.object({
165
166
  * providers remain the default; this field is optional and disabled unless
166
167
  * the caller explicitly enables bundle providers.
167
168
  */
168
- export const GateProviderEntrySchema = z.object({
169
+ export const GateProviderEntrySchema = z.strictObject({
169
170
  id: z.string().min(1).max(128).regex(/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/, 'must be a namespaced provider id <scope>/<name> (alphanumeric plus . _ -)'),
170
171
  version: z.string().regex(/^\d+\.\d+\.\d+/, 'CalVer or SemVer (X.Y.Z[...])'),
171
172
  module: safeModuleFile,
172
173
  description: z.string().min(1).max(512),
173
174
  review: GateProviderReviewSchema.optional(),
174
175
  reviewFile: safeJsonFile.optional(),
175
- }).strict().refine((entry) => (entry.review !== undefined) !== (entry.reviewFile !== undefined), { message: 'exactly one of review or reviewFile is required' });
176
- export const GateProvidersSchema = z.array(GateProviderEntrySchema).max(20).refine((entries) => new Set(entries.map((entry) => entry.id)).size === entries.length, { message: 'gate provider ids must be unique within a bundle' }).refine((entries) => new Set(entries.map((entry) => entry.module)).size === entries.length, { message: 'gate provider modules must be unique within a bundle' });
177
- export const CliCommandsSchema = z.object({
176
+ }).refine((entry) => (entry.review !== undefined) !== (entry.reviewFile !== undefined), { error: 'exactly one of review or reviewFile is required' });
177
+ export const GateProvidersSchema = z.array(GateProviderEntrySchema).max(20).refine((entries) => new Set(entries.map((entry) => entry.id)).size === entries.length, { error: 'gate provider ids must be unique within a bundle' }).refine((entries) => new Set(entries.map((entry) => entry.module)).size === entries.length, { error: 'gate provider modules must be unique within a bundle' });
178
+ export const CliCommandsSchema = z.strictObject({
178
179
  namespace: z.string()
179
180
  .min(1)
180
181
  .max(64)
@@ -184,7 +185,7 @@ export const CliCommandsSchema = z.object({
184
185
  subcommands: z.record(z.string()
185
186
  .min(1)
186
187
  .max(64)
187
- .regex(bundleNamePattern, 'kebab-case alphanumeric, no leading/trailing hyphen'), z.object({
188
+ .regex(bundleNamePattern, 'kebab-case alphanumeric, no leading/trailing hyphen'), z.strictObject({
188
189
  file: safeModuleFile,
189
190
  description: z.string().min(1).max(512),
190
191
  hook_event: z.enum([
@@ -195,14 +196,14 @@ export const CliCommandsSchema = z.object({
195
196
  'PostToolUse',
196
197
  'FeatureComplete',
197
198
  ]).optional(),
198
- }).strict()).refine((commands) => Object.keys(commands).length > 0, {
199
- message: 'at least one CLI subcommand is required',
199
+ })).refine((commands) => Object.keys(commands).length > 0, {
200
+ error: 'at least one CLI subcommand is required',
200
201
  }),
201
- }).strict();
202
+ });
202
203
  // ============================================
203
204
  // Top-level BundleManifestSchema
204
205
  // ============================================
205
- export const BundleManifestSchema = z.object({
206
+ export const BundleManifestSchema = z.strictObject({
206
207
  // Required core fields
207
208
  id: z.string()
208
209
  .min(1)
@@ -219,7 +220,7 @@ export const BundleManifestSchema = z.object({
219
220
  // Optional standard metadata
220
221
  author: z.string().max(128).optional(),
221
222
  license: z.string().max(64).optional(),
222
- repository: z.string().url().max(512).optional(),
223
+ repository: url().max(512).optional(),
223
224
  // Type-discriminated nested config (exactly one matches `type`)
224
225
  addonConfig: AddonConfigSchema.optional(),
225
226
  frameworkConfig: FrameworkConfigSchema.optional(),
@@ -242,7 +243,6 @@ export const BundleManifestSchema = z.object({
242
243
  // providers remain the default when this field is absent.
243
244
  gateProviders: GateProvidersSchema.optional(),
244
245
  })
245
- .strict()
246
246
  .refine((m) => {
247
247
  // Discriminator alignment: type must match the present *Config block(s)
248
248
  const present = {
@@ -258,18 +258,45 @@ export const BundleManifestSchema = z.object({
258
258
  return presentCount === 0 || (presentCount === 1 && present.extension);
259
259
  }
260
260
  return presentCount === 1 && present[m.type];
261
- }, { message: 'type must match its corresponding *Config block (addon→addonConfig, framework→frameworkConfig, plugin→pluginConfig, provider→providerConfig; extension may omit extensionConfig)' });
261
+ }, { error: 'type must match its corresponding *Config block (addon→addonConfig, framework→frameworkConfig, plugin→pluginConfig, provider→providerConfig; extension may omit extensionConfig)' });
262
262
  /**
263
263
  * Convert a Zod error into the structured ManifestValidationError shape used
264
264
  * by discovery and `aiwg validate-metadata`.
265
265
  */
266
- export function zodErrorToValidationErrors(err, manifestPath) {
267
- return err.errors.map((issue) => ({
268
- path: manifestPath,
269
- field: issue.path.join('.') || '(root)',
270
- expected: issue.message,
271
- actual: 'received' in issue ? String(issue.received) : 'invalid',
272
- severity: 'error',
273
- }));
266
+ export function zodErrorToValidationErrors(err, manifestPath, input) {
267
+ const hasInput = arguments.length >= 3;
268
+ const issues = err.issues.flatMap(issue => {
269
+ // Partial enum maps report unknown keys at the map in v4; discovery's
270
+ // existing field contract identifies each rejected capability key.
271
+ if (issue.code === 'unrecognized_keys'
272
+ && issue.path.length === 3 && issue.path[0] === 'providerConfig'
273
+ && issue.path[1] === 'capabilities'
274
+ && ['nativeFeatures', 'emulation'].includes(String(issue.path[2]))) {
275
+ return issue.keys.map(key => ({ ...issue, path: [...issue.path, key] }));
276
+ }
277
+ return [issue];
278
+ });
279
+ return issues.map((issue) => {
280
+ let actual = 'invalid';
281
+ if (issue.code === 'invalid_type' && hasInput) {
282
+ let value = input;
283
+ for (const segment of issue.path) {
284
+ value = value !== null && typeof value === 'object' && Object.hasOwn(value, segment)
285
+ ? value[segment] : undefined;
286
+ }
287
+ // Emit only the former type classification, never rejected values.
288
+ actual = value === null ? 'null' : Array.isArray(value) ? 'array'
289
+ : typeof value === 'number' && Number.isNaN(value) ? 'nan'
290
+ : issue.expected === 'int' && typeof value === 'number' ? 'float'
291
+ : typeof value;
292
+ }
293
+ return {
294
+ path: manifestPath,
295
+ field: issue.path.join('.') || '(root)',
296
+ expected: issue.message,
297
+ actual,
298
+ severity: 'error',
299
+ };
300
+ });
274
301
  }
275
302
  //# sourceMappingURL=manifest.js.map
@@ -228,7 +228,7 @@ export async function loadAndValidateManifest(manifestPath, expectedType, projec
228
228
  }
229
229
  const result = BundleManifestSchema.safeParse(parsed);
230
230
  if (!result.success) {
231
- return { errors: zodErrorToValidationErrors(result.error, manifestPath) };
231
+ return { errors: zodErrorToValidationErrors(result.error, manifestPath, parsed) };
232
232
  }
233
233
  const manifest = result.data;
234
234
  // Cross-check: manifest declared type must match the directory it lives in.
@@ -10,6 +10,7 @@ import { access, mkdir, readFile, readdir, rm, writeFile } from 'fs/promises';
10
10
  import { basename, dirname, isAbsolute, join, resolve } from 'path';
11
11
  import { homedir } from 'os';
12
12
  import { z } from 'zod';
13
+ import { integer } from '../schema/zod-validation.mjs';
13
14
  import { getProviderDefinition, normalizeProviderDefinitionId, } from '../providers/provider-definitions.js';
14
15
  import { resolveHermesHome } from '../providers/hermes-home.js';
15
16
  import { OPERATIONAL_SHOW_TYPES } from '../artifacts/types.js';
@@ -18,45 +19,45 @@ import { appendAiwgSourceTrackBlock } from './project-local-gitignore.js';
18
19
  import { discoverProjectLocalBundles } from './project-local-discovery.js';
19
20
  import { enumerateBundleArtifacts } from './shadow-resolver.js';
20
21
  const OWNERSHIP_MARKER = '.aiwg-project-quickref.json';
21
- const ShowHintSchema = z.object({
22
+ const ShowHintSchema = z.strictObject({
22
23
  type: z.enum(OPERATIONAL_SHOW_TYPES),
23
24
  name: z.string().min(1).max(128),
24
- }).strict();
25
- const QuickrefEntrySchema = z.object({
25
+ });
26
+ const QuickrefEntrySchema = z.strictObject({
26
27
  title: z.string().min(1).max(128),
27
28
  summary: z.string().min(1).max(512),
28
29
  discover: z.array(z.string().min(1).max(256)).max(10).default([]),
29
30
  show: z.array(ShowHintSchema).max(20).default([]),
30
- }).strict().refine(entry => entry.discover.length > 0 || entry.show.length > 0, { message: 'each entry must provide at least one discover or show hint' });
31
- export const ProjectQuickrefSchema = z.object({
31
+ }).refine(entry => entry.discover.length > 0 || entry.show.length > 0, { error: 'each entry must provide at least one discover or show hint' });
32
+ export const ProjectQuickrefSchema = z.strictObject({
32
33
  version: z.literal('1'),
33
- project: z.object({
34
+ project: z.strictObject({
34
35
  id: z.string().regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, 'must be kebab-case'),
35
36
  name: z.string().min(1).max(128),
36
37
  description: z.string().min(1).max(512),
37
- }).strict(),
38
+ }),
38
39
  precedence: z.string().min(1).max(1024),
39
40
  entries: z.array(QuickrefEntrySchema).min(1).max(50),
40
- }).strict();
41
- const QuickrefOverrideSchema = z.object({
41
+ });
42
+ const QuickrefOverrideSchema = z.strictObject({
42
43
  title: z.string().min(1).max(128).optional(),
43
44
  summary: z.string().min(1).max(512).optional(),
44
45
  discover: z.array(z.string().min(1).max(256)).max(10).optional(),
45
46
  show: z.array(ShowHintSchema).max(20).optional(),
46
47
  hidden: z.boolean().optional(),
47
- order: z.number().int().optional(),
48
- }).strict();
49
- export const ProjectQuickrefConfigSchema = z.object({
48
+ order: integer().optional(),
49
+ });
50
+ export const ProjectQuickrefConfigSchema = z.strictObject({
50
51
  version: z.literal('1'),
51
52
  project: ProjectQuickrefSchema.shape.project.optional(),
52
53
  precedence: z.string().min(1).max(1024).optional(),
53
54
  entries: z.array(QuickrefEntrySchema).max(50).default([]),
54
- discovery: z.object({
55
+ discovery: z.strictObject({
55
56
  enabled: z.boolean().default(true),
56
57
  excludeBundles: z.array(z.string().min(1)).max(200).default([]),
57
- overrides: z.record(z.string(), QuickrefOverrideSchema).default({}),
58
- }).strict().default({ enabled: true, excludeBundles: [], overrides: {} }),
59
- }).strict();
58
+ overrides: z.record(z.string(), QuickrefOverrideSchema).prefault({}),
59
+ }).prefault({ enabled: true, excludeBundles: [], overrides: {} }),
60
+ });
60
61
  function sha256(content) {
61
62
  return createHash('sha256').update(content).digest('hex');
62
63
  }
@@ -281,7 +282,7 @@ export function renderProjectQuickref(definition) {
281
282
  lines.push(`- Discover: \`aiwg discover ${JSON.stringify(phrase)}\``);
282
283
  }
283
284
  for (const hint of entry.show) {
284
- lines.push(`- Fetch: \`aiwg show ${hint.type} ${hint.name}\``);
285
+ lines.push(`- Fetch: \`aiwg show ${hint.type} ${hint.name} --body\``);
285
286
  }
286
287
  lines.push('');
287
288
  }
@@ -10,6 +10,7 @@
10
10
  * @version 1.0.0
11
11
  */
12
12
  import { z } from 'zod';
13
+ import { integer, dateTime, url, number } from '../schema/zod-validation.mjs';
13
14
  // ============================================
14
15
  // Core Enums & Primitives
15
16
  // ============================================
@@ -77,13 +78,13 @@ export const PlatformCompatibilitySchema = z.object({
77
78
  codex: PlatformSupportSchema.optional(),
78
79
  opencode: PlatformSupportSchema.optional(),
79
80
  generic: PlatformSupportSchema.optional(),
80
- }).refine((data) => Object.values(data).some((val) => val !== undefined), { message: 'At least one platform must be specified' });
81
+ }).refine((data) => Object.values(data).some((val) => val !== undefined), { error: 'At least one platform must be specified' });
81
82
  /**
82
83
  * Deployment configuration
83
84
  */
84
85
  export const DeploymentConfigSchema = z.object({
85
86
  pathTemplate: z.string().min(1, 'Path template is required'),
86
- pathOverrides: z.record(z.string()).optional(),
87
+ pathOverrides: z.record(z.string(), z.string()).optional(),
87
88
  additionalFiles: z.array(z.string()).optional(),
88
89
  autoInstall: z.boolean().optional().default(false),
89
90
  core: z.boolean().optional().default(false),
@@ -106,7 +107,7 @@ export const MemoryFootprintSchema = z.object({
106
107
  * Deprecation information
107
108
  */
108
109
  export const DeprecationSchema = z.object({
109
- date: z.string().datetime({ message: 'Date must be ISO 8601 format' }),
110
+ date: dateTime({ error: 'Date must be ISO 8601 format' }),
110
111
  successor: z.string().optional(),
111
112
  reason: z.string().min(1, 'Deprecation reason is required'),
112
113
  });
@@ -114,7 +115,7 @@ export const DeprecationSchema = z.object({
114
115
  * Installation state
115
116
  */
116
117
  export const InstallationSchema = z.object({
117
- installedAt: z.string().datetime({ message: 'Install timestamp must be ISO 8601 format' }),
118
+ installedAt: dateTime({ error: 'Install timestamp must be ISO 8601 format' }),
118
119
  installedFrom: z.enum(['builtin', 'registry', 'local', 'git']),
119
120
  installedPath: z.string().min(1),
120
121
  enabled: z.boolean(),
@@ -142,7 +143,7 @@ export const AgentMetadataSchema = z.object({
142
143
  }),
143
144
  tools: z.array(z.string()).min(1, 'At least one tool is required'),
144
145
  template: z.string().optional(),
145
- maxTools: z.number().int().positive().optional(),
146
+ maxTools: integer().positive().optional(),
146
147
  canDelegate: z.boolean().optional(),
147
148
  readOnly: z.boolean().optional(),
148
149
  workflow: z.array(z.string()).optional(),
@@ -157,8 +158,8 @@ export const CommandArgumentSchema = z.object({
157
158
  description: z.string().min(1),
158
159
  required: z.boolean(),
159
160
  type: z.enum(['string', 'number', 'boolean']),
160
- default: z.union([z.string(), z.number(), z.boolean()]).optional(),
161
- position: z.number().int().nonnegative().optional(),
161
+ default: z.union([z.string(), number(), z.boolean()]).optional(),
162
+ position: integer().nonnegative().optional(),
162
163
  });
163
164
  /**
164
165
  * Command option definition
@@ -167,7 +168,7 @@ export const CommandOptionSchema = z.object({
167
168
  name: z.string().min(1),
168
169
  description: z.string().min(1),
169
170
  type: z.enum(['string', 'boolean', 'number', 'array']),
170
- default: z.union([z.string(), z.boolean(), z.number()]).optional(),
171
+ default: z.union([z.string(), z.boolean(), number()]).optional(),
171
172
  short: z.string().length(1).optional(),
172
173
  long: z.string().min(2).optional(),
173
174
  });
@@ -229,11 +230,13 @@ export const SkillReferenceSchema = z.object({
229
230
  * natural-language invocation. Do NOT relax this rule — a blank description
230
231
  * is what caused the 107-file regression we are guarding against.
231
232
  */
232
- export const SkillFrontmatterSchema = z.object({
233
+ export const SkillFrontmatterSchema = z.looseObject({
233
234
  name: z.string().min(1, 'Skill name is required'),
234
235
  description: z
235
236
  .string({
236
- required_error: 'Description is required (Codex rejects SKILL.md without it)',
237
+ error: issue => issue.input === undefined
238
+ ? 'Description is required (Codex rejects SKILL.md without it)'
239
+ : undefined,
237
240
  })
238
241
  .min(1, 'Description is required and must be non-empty'),
239
242
  version: z.string().regex(/^\d+\.\d+\.\d+/, 'Version must be semver or CalVer format (e.g., 1.0.0)').optional(),
@@ -247,7 +250,7 @@ export const SkillFrontmatterSchema = z.object({
247
250
  triggers: z
248
251
  .array(z
249
252
  .string()
250
- .refine((s) => s.trim().length > 0, { message: 'trigger phrases must be non-empty' }))
253
+ .refine((s) => s.trim().length > 0, { error: 'trigger phrases must be non-empty' }))
251
254
  .min(1, 'triggers is declared but empty — add at least one phrase or remove the field (empty-triggers anti-pattern, #1623)')
252
255
  .optional(),
253
256
  aliases: z.array(z.string()).optional(),
@@ -263,8 +266,8 @@ export const SkillFrontmatterSchema = z.object({
263
266
  context: z.enum(['fork', 'inherit']).optional(),
264
267
  author: z.string().optional(),
265
268
  license: z.string().optional(),
266
- metadata: z.record(z.unknown()).optional(),
267
- }).passthrough();
269
+ metadata: z.record(z.string(), z.unknown()).optional(),
270
+ });
268
271
  /**
269
272
  * Validate SKILL.md frontmatter.
270
273
  *
@@ -313,10 +316,10 @@ export const SkillMetadataSchema = z.object({
313
316
  export const HookMetadataSchema = z.object({
314
317
  type: z.literal('hook'),
315
318
  event: HookEventSchema,
316
- priority: z.number().int().optional().default(100),
319
+ priority: integer().optional().default(100),
317
320
  canModify: z.boolean().optional().default(false),
318
321
  canBlock: z.boolean().optional().default(false),
319
- configSchema: z.record(z.unknown()).optional(),
322
+ configSchema: z.record(z.string(), z.unknown()).optional(),
320
323
  });
321
324
  /**
322
325
  * Tool-specific metadata
@@ -326,11 +329,11 @@ export const ToolMetadataSchema = z.object({
326
329
  category: z.enum(['core', 'languages', 'utilities', 'custom']),
327
330
  executable: z.string().min(1, 'Executable path is required'),
328
331
  verificationStatus: z.enum(['verified', 'unverified']).optional(),
329
- lastVerified: z.string().datetime().optional(),
332
+ lastVerified: dateTime().optional(),
330
333
  manPage: z.string().optional(),
331
334
  aliases: z.array(z.string()).optional(),
332
335
  relatedTools: z.array(z.string()).optional(),
333
- platformNotes: z.record(z.string()).optional(),
336
+ platformNotes: z.record(z.string(), z.string()).optional(),
334
337
  installHint: z.string().optional(),
335
338
  });
336
339
  /**
@@ -348,7 +351,7 @@ export const MCPServerMetadataSchema = z.object({
348
351
  type: z.literal('mcp-server'),
349
352
  mcpVersion: z.string().min(1, 'MCP version is required'),
350
353
  transport: z.enum(['stdio', 'http']),
351
- port: z.number().int().positive().optional(),
354
+ port: integer().positive().optional(),
352
355
  capabilities: z.object({
353
356
  tools: z.boolean(),
354
357
  resources: z.boolean(),
@@ -358,9 +361,9 @@ export const MCPServerMetadataSchema = z.object({
358
361
  }),
359
362
  sourceType: z.enum(['cli', 'api', 'catalog', 'nl', 'extension']),
360
363
  sourceCommand: z.string().optional(),
361
- sourceBaseUrl: z.string().url().optional(),
364
+ sourceBaseUrl: url().optional(),
362
365
  workingDirectory: z.string().optional(),
363
- environment: z.record(z.string()).optional(),
366
+ environment: z.record(z.string(), z.string()).optional(),
364
367
  tools: z.array(MCPToolSummarySchema).optional(),
365
368
  resources: z.array(z.string()).optional(),
366
369
  prompts: z.array(z.string()).optional(),
@@ -379,8 +382,8 @@ export const FrameworkMetadataSchema = z.object({
379
382
  templates: z.array(z.string()).optional(),
380
383
  prompts: z.array(z.string()).optional(),
381
384
  }),
382
- configSchema: z.record(z.unknown()).optional(),
383
- defaultConfig: z.record(z.unknown()).optional(),
385
+ configSchema: z.record(z.string(), z.unknown()).optional(),
386
+ defaultConfig: z.record(z.string(), z.unknown()).optional(),
384
387
  });
385
388
  /**
386
389
  * Addon-specific metadata
@@ -476,15 +479,15 @@ export const ExtensionSchema = z.object({
476
479
  requires: z.array(z.string()).optional(),
477
480
  recommends: z.array(z.string()).optional(),
478
481
  conflicts: z.array(z.string()).optional(),
479
- systemDependencies: z.record(z.string()).optional(),
482
+ systemDependencies: z.record(z.string(), z.string()).optional(),
480
483
  // Metadata & Documentation
481
484
  author: z.string().optional(),
482
485
  license: z.string().optional(),
483
- repository: z.string().url().optional(),
484
- homepage: z.string().url().optional(),
485
- bugs: z.string().url().optional(),
486
- documentation: z.record(z.string()).optional(),
487
- researchCompliance: z.record(z.array(z.string())).optional(),
486
+ repository: url().optional(),
487
+ homepage: url().optional(),
488
+ bugs: url().optional(),
489
+ documentation: z.record(z.string(), z.string()).optional(),
490
+ researchCompliance: z.record(z.string(), z.array(z.string())).optional(),
488
491
  memory: MemoryFootprintSchema.optional(),
489
492
  // Type-Specific Data
490
493
  metadata: ExtensionMetadataSchema,
@@ -495,7 +498,7 @@ export const ExtensionSchema = z.object({
495
498
  // Validation & Quality
496
499
  checksum: z.string().optional(),
497
500
  signature: SignatureSchema.optional(),
498
- }).refine((data) => data.type === data.metadata.type, { message: 'Extension type must match metadata type' });
501
+ }).refine((data) => data.type === data.metadata.type, { error: 'Extension type must match metadata type' });
499
502
  /**
500
503
  * Validate an extension manifest
501
504
  *
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Daemon config access for `aiwg housekeeper` (epic #3353 slice B5).
3
+ *
4
+ * Mirrors the file precedence of `tools/daemon/config.mjs` (YAML, then YML,
5
+ * then JSON) without importing `tools/` — `src/` must never import `tools/`
6
+ * (tools import compiled src via `importImpl`). Only the `schedule.jobs`
7
+ * and `watch.paths` sections plus `daemon.profile` are read or written;
8
+ * every other key is preserved byte-for-byte through a YAML round-trip.
9
+ */
10
+ import fs from 'node:fs';
11
+ import path from 'node:path';
12
+ import YAML from 'yaml';
13
+ import { parseMemoryAuditOptions } from '../memory/cli.js';
14
+ export const HOUSEKEEPER_PROFILE = 'housekeeper';
15
+ /**
16
+ * Deterministic maintenance kinds. Mirrors `MAINTENANCE_KINDS` in
17
+ * `tools/daemon/scheduled-task-runner.mjs` — that module owns execution;
18
+ * this list only validates `job register` input on the CLI side.
19
+ */
20
+ export const MAINTENANCE_KINDS = Object.freeze([
21
+ 'index.verify',
22
+ 'index.reconcile',
23
+ 'cache.retention',
24
+ 'update.check',
25
+ 'update.install',
26
+ 'index.freshness',
27
+ 'index.refresh',
28
+ 'cache.prune',
29
+ 'memory.audit',
30
+ 'memory.recommend',
31
+ 'memory.apply',
32
+ ]);
33
+ /** Same argument contract for registration, daemon configuration and dispatch. */
34
+ export function validateMemoryJobArgs(kind, args = {}) {
35
+ if (!kind.startsWith('memory.'))
36
+ return;
37
+ if (!['memory.audit', 'memory.recommend', 'memory.apply'].includes(kind))
38
+ throw new Error(`Unsupported memory kind: ${kind}`);
39
+ if (!args || typeof args !== 'object' || Array.isArray(args))
40
+ throw new Error('Memory job args must be an object');
41
+ const values = args;
42
+ const allowed = kind === 'memory.apply' ? ['plan', 'confirmedDigest', 'windows']
43
+ : ['scope', 'provider', ...(kind === 'memory.recommend' ? ['evidence', 'usage'] : [])];
44
+ for (const [key, value] of Object.entries(values)) {
45
+ if (!allowed.includes(key))
46
+ throw new Error(`Unsupported ${kind} argument: ${key}`);
47
+ if (key !== 'windows' && (typeof value !== 'string' || !value.trim()))
48
+ throw new Error(`${key} must be a non-empty string`);
49
+ }
50
+ if (kind === 'memory.apply') {
51
+ if (!values.plan || !values.confirmedDigest)
52
+ throw new Error('memory.apply requires args.plan and args.confirmedDigest for the named reviewed plan');
53
+ }
54
+ else {
55
+ parseMemoryAuditOptions(['scope', 'provider'].flatMap(key => values[key] === undefined ? [] : [`--${key}`, String(values[key])]));
56
+ }
57
+ }
58
+ /** Resolve the daemon config file with the same precedence as Config.load. */
59
+ export function resolveDaemonConfigPath(cwd) {
60
+ const candidates = [
61
+ path.join(cwd, '.aiwg', 'daemon.yaml'),
62
+ path.join(cwd, '.aiwg', 'daemon.yml'),
63
+ path.join(cwd, '.aiwg', 'daemon.json'),
64
+ ];
65
+ for (const candidate of candidates) {
66
+ if (fs.existsSync(candidate))
67
+ return { path: candidate, existed: true };
68
+ }
69
+ return { path: candidates[0], existed: false };
70
+ }
71
+ function parseConfigFile(file) {
72
+ const raw = fs.readFileSync(file, 'utf8');
73
+ if (file.endsWith('.json')) {
74
+ const parsed = JSON.parse(raw);
75
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
76
+ throw new Error(`Daemon config ${file} must contain a JSON object`);
77
+ }
78
+ return parsed;
79
+ }
80
+ const parsed = YAML.parse(raw);
81
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
82
+ throw new Error(`Daemon config ${file} must contain a mapping`);
83
+ }
84
+ return parsed;
85
+ }
86
+ export function loadDaemonConfig(cwd) {
87
+ const { path: file, existed } = resolveDaemonConfigPath(cwd);
88
+ if (!existed)
89
+ return { path: file, existed, config: {} };
90
+ return { path: file, existed, config: parseConfigFile(file) };
91
+ }
92
+ export function saveDaemonConfig(file, config) {
93
+ fs.mkdirSync(path.dirname(file), { recursive: true });
94
+ const body = file.endsWith('.json')
95
+ ? `${JSON.stringify(config, null, 2)}\n`
96
+ : YAML.stringify(config);
97
+ const tmp = `${file}.tmp.${process.pid}`;
98
+ fs.writeFileSync(tmp, body);
99
+ fs.renameSync(tmp, file);
100
+ }
101
+ export function getDaemonProfile(config) {
102
+ const daemon = config['daemon'];
103
+ if (!daemon || typeof daemon !== 'object' || Array.isArray(daemon))
104
+ return undefined;
105
+ const profile = daemon['profile'];
106
+ return typeof profile === 'string' ? profile : undefined;
107
+ }
108
+ export function setDaemonProfile(config, profile) {
109
+ const daemon = (config['daemon'] ??= {});
110
+ daemon['profile'] = profile;
111
+ }
112
+ export function getScheduleJobs(config) {
113
+ const schedule = config['schedule'];
114
+ if (!schedule || typeof schedule !== 'object' || Array.isArray(schedule))
115
+ return [];
116
+ const jobs = schedule['jobs'];
117
+ return Array.isArray(jobs) ? jobs : [];
118
+ }
119
+ export function setScheduleJobs(config, jobs) {
120
+ const schedule = (config['schedule'] ??= {});
121
+ schedule['jobs'] = jobs;
122
+ }
123
+ export function scheduleEnabled(config) {
124
+ const schedule = config['schedule'];
125
+ if (!schedule || typeof schedule !== 'object' || Array.isArray(schedule))
126
+ return false;
127
+ return schedule['enabled'] !== false;
128
+ }
129
+ export function getWatchPaths(config) {
130
+ const watch = config['watch'];
131
+ if (!watch || typeof watch !== 'object' || Array.isArray(watch))
132
+ return [];
133
+ const paths = watch['paths'];
134
+ return Array.isArray(paths) ? paths : [];
135
+ }
136
+ export function setWatchPaths(config, entries) {
137
+ const watch = (config['watch'] ??= {});
138
+ watch['paths'] = entries;
139
+ }
140
+ /** Minimal housekeeper seed written when no daemon config exists yet. */
141
+ export function seedHousekeeperConfig() {
142
+ return {
143
+ daemon: { profile: HOUSEKEEPER_PROFILE, heartbeat_interval_seconds: 30 },
144
+ watch: { enabled: false, paths: [] },
145
+ schedule: { enabled: true, jobs: [] },
146
+ };
147
+ }
148
+ //# sourceMappingURL=daemon-config.js.map