akm-cli 0.9.0-beta.47 → 0.9.0-beta.48

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.
@@ -22,8 +22,14 @@
22
22
  * - Two exceptions (hard-rejected): openviking source type and legacy
23
23
  * `stashes[]` key. Both have explicit migration paths; silently dropping
24
24
  * would mask user data loss.
25
- * - `.strict()` walls still gate `registries[]`, `sources[]`, `profiles.*`
26
- * sub-shapes so typos in those structured records are caught (#462).
25
+ * - UNKNOWN-KEY POLICY: object schemas use passthrough (unknown keys are
26
+ * preserved and ignored, NOT rejected). akm runs across multiple installed
27
+ * versions sharing one config.json; a newer version writes keys an older
28
+ * version's schema doesn't know yet, so hard-rejecting unknown keys turned
29
+ * benign version skew into `INVALID_CONFIG_FILE` failures. Known keys are
30
+ * still type-checked; passthrough preserves unknown keys across a
31
+ * load→save round trip so an older reader never strips a newer writer's
32
+ * settings. (Replaced the prior strict-mode object walls.)
27
33
  * - `defaultWriteTarget` resolution and similar cross-field invariants are
28
34
  * enforced at save time via `superRefine` on the top-level schema.
29
35
  */
@@ -50,7 +56,7 @@ const LlmCapabilitiesSchema = z
50
56
  .object({
51
57
  structuredOutput: z.boolean().optional(),
52
58
  })
53
- .strict();
59
+ .passthrough();
54
60
  /**
55
61
  * Connection config used for both top-level `llm` (after migration) and
56
62
  * `profiles.llm[*]`. `model` is required at schema level — partial entries
@@ -75,15 +81,15 @@ export const LlmConnectionConfigSchema = z
75
81
  judgeModel: z.string().min(1).optional(),
76
82
  enableThinking: z.boolean().optional(),
77
83
  })
78
- .strict();
84
+ .passthrough();
79
85
  export const LlmProfileConfigSchema = LlmConnectionConfigSchema.extend({
80
86
  supportsJsonSchema: z.boolean().optional(),
81
- }).strict();
87
+ }).passthrough();
82
88
  const EmbeddingOllamaOptionsSchema = z
83
89
  .object({
84
90
  num_ctx: positiveInt.optional(),
85
91
  })
86
- .strict();
92
+ .passthrough();
87
93
  /**
88
94
  * Embedding connection config. Both `endpoint` and `model` are optional:
89
95
  * - Remote: provide `endpoint` (http/https URL) + `model`.
@@ -107,7 +113,7 @@ export const EmbeddingConnectionConfigSchema = z
107
113
  contextLength: positiveInt.optional(),
108
114
  ollamaOptions: EmbeddingOllamaOptionsSchema.optional(),
109
115
  })
110
- .strict();
116
+ .passthrough();
111
117
  // ── Agent profiles ──────────────────────────────────────────────────────────
112
118
  // Derives from the canonical VALID_HARNESS_IDS (#565) so the Zod gate cannot
113
119
  // drift from the TS union / parse check / setup detection.
@@ -120,7 +126,7 @@ export const AgentProfileConfigSchema = z
120
126
  workspace: z.string().min(1).optional(),
121
127
  model: z.string().min(1).optional(),
122
128
  })
123
- .strict();
129
+ .passthrough();
124
130
  // ── Improve profile / process ──────────────────────────────────────────────
125
131
  export const ImproveProcessConfigSchema = z
126
132
  .object({
@@ -151,7 +157,7 @@ export const ImproveProcessConfigSchema = z
151
157
  // with care — cost is O(n²).
152
158
  cosineCandidateLimit: z.number().int().positive().optional(),
153
159
  })
154
- .strict()
160
+ .passthrough()
155
161
  .optional(),
156
162
  // Consolidate process: judged-state cache (#581). When enabled, a memory
157
163
  // whose current content hash equals its cached judged hash is SKIPPED from
@@ -160,9 +166,9 @@ export const ImproveProcessConfigSchema = z
160
166
  // time-window slice. Default OFF — when absent the consolidate pass behaves
161
167
  // byte-identically to today (the incrementalSince path is unaffected). Only
162
168
  // meaningful on the `consolidate` process.
163
- judgedCache: z.object({ enabled: z.boolean().optional() }).strict().optional(),
164
- qualityGate: z.object({ enabled: z.boolean().optional() }).strict().optional(),
165
- contradictionDetection: z.object({ enabled: z.boolean().optional() }).strict().optional(),
169
+ judgedCache: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
170
+ qualityGate: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
171
+ contradictionDetection: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
166
172
  // Extract process config (only meaningful for extract process)
167
173
  defaultSince: z.string().min(1).optional(),
168
174
  maxTotalChars: positiveInt.optional(),
@@ -236,7 +242,7 @@ export const ImproveProcessConfigSchema = z
236
242
  // Demotion factor: multiply retrievalSalience by this when stale (default 0.5).
237
243
  demotionFactor: z.number().min(0).max(1).optional(),
238
244
  })
239
- .strict()
245
+ .passthrough()
240
246
  .optional(),
241
247
  // WS-3b: Schema-similarity gate (step 0b). At intake, if a new candidate's
242
248
  // body embedding is within epsilon of an existing derived-layer lesson/knowledge
@@ -253,7 +259,7 @@ export const ImproveProcessConfigSchema = z
253
259
  // to pass the quality gate and create redundant stash entries.
254
260
  confidencePenalty: z.number().min(0).max(1).optional(),
255
261
  })
256
- .strict()
262
+ .passthrough()
257
263
  .optional(),
258
264
  // WS-3b: Hot-probation intake buffer (step 0c, #604). New system-generated
259
265
  // extractions enter captureMode: hot-probation and spend ONE consolidation
@@ -263,7 +269,7 @@ export const ImproveProcessConfigSchema = z
263
269
  .object({
264
270
  enabled: z.boolean().optional(),
265
271
  })
266
- .strict()
272
+ .passthrough()
267
273
  .optional(),
268
274
  // WS-3b: Anti-collapse guards (step 8). Prevents the consolidation pipeline
269
275
  // from collapsing too aggressively and losing diversity.
@@ -278,7 +284,7 @@ export const ImproveProcessConfigSchema = z
278
284
  lexicalDiversityCheck: z.boolean().optional(),
279
285
  randomClusterFraction: z.number().min(0).max(1).optional(),
280
286
  })
281
- .strict()
287
+ .passthrough()
282
288
  .optional(),
283
289
  // WS-3b: CLS (Complementary Learning System) interleaving (step 9).
284
290
  // distill/memoryInference prompts include embedding-retrieved existing adjacent
@@ -290,7 +296,7 @@ export const ImproveProcessConfigSchema = z
290
296
  // Number of adjacent lessons/knowledge to include in prompts (default 3).
291
297
  adjacentCount: z.number().int().min(1).optional(),
292
298
  })
293
- .strict()
299
+ .passthrough()
294
300
  .optional(),
295
301
  // WS-3b: Distill→source fidelity check (step 10). After a distill proposal,
296
302
  // check it against its cited source memories; a contradiction flag forces
@@ -299,7 +305,7 @@ export const ImproveProcessConfigSchema = z
299
305
  .object({
300
306
  enabled: z.boolean().optional(),
301
307
  })
302
- .strict()
308
+ .passthrough()
303
309
  .optional(),
304
310
  // #609 — recombine process: minimum related-memory cluster size before an
305
311
  // LLM generalization call. Default 3. Only meaningful on `recombine`.
@@ -342,7 +348,7 @@ export const ImproveProcessConfigSchema = z
342
348
  // enabled, proposals classified as "low-value" by the deterministic noise
343
349
  // gate are deferred. DEFAULT OFF (absent / { enabled: false } = pre-#639
344
350
  // byte-identical behaviour). Only meaningful on the `reflect` process.
345
- lowValueFilter: z.object({ enabled: z.boolean().optional() }).strict().optional(),
351
+ lowValueFilter: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
346
352
  // #641 — procedural-aware floor for the `extract` process triage gate.
347
353
  // When true, a session must have markers>=1 OR editCommit>=0.5 to pass, even
348
354
  // if score>=minScore. DEFAULT OFF (absent/false = pre-#641 byte-identical).
@@ -360,10 +366,10 @@ export const ImproveProcessConfigSchema = z
360
366
  profile: z.string().min(1).optional(),
361
367
  timeoutMs: z.union([positiveInt, z.null()]).optional(),
362
368
  })
363
- .strict()
369
+ .passthrough()
364
370
  .optional(),
365
371
  })
366
- .strict();
372
+ .passthrough();
367
373
  const ImproveProfileProcessesSchema = z
368
374
  .object({
369
375
  reflect: ImproveProcessConfigSchema.optional(),
@@ -380,37 +386,17 @@ const ImproveProfileProcessesSchema = z
380
386
  .passthrough()
381
387
  .superRefine((val, ctx) => {
382
388
  // 0.8.0 removed the duplicated `feedbackDistillation` process key — it was
383
- // a thin wrapper around `processes.distill.enabled`. Single source of truth.
384
- const raw = val;
385
- if ("feedbackDistillation" in raw) {
389
+ // a thin wrapper around `processes.distill.enabled`. Keep the migration
390
+ // hint so a stale config gets an actionable message rather than silently
391
+ // doing nothing. All OTHER unknown process keys are tolerated (passthrough)
392
+ // — see the unknown-key policy in this file's header. Hard-rejecting them
393
+ // turned benign cross-version skew into INVALID_CONFIG_FILE failures.
394
+ if ("feedbackDistillation" in val) {
386
395
  ctx.addIssue({
387
396
  code: z.ZodIssueCode.custom,
388
397
  message: "feedbackDistillation was removed in 0.8.0 — use processes.distill.enabled instead. " +
389
398
  "It now controls both the orchestration gate and the LLM-call gate.",
390
399
  });
391
- return;
392
- }
393
- const allowed = new Set([
394
- "reflect",
395
- "distill",
396
- "consolidate",
397
- "memoryInference",
398
- "graphExtraction",
399
- "validation",
400
- "extract",
401
- "triage",
402
- "proactiveMaintenance",
403
- "recombine",
404
- "procedural",
405
- ]);
406
- for (const k of Object.keys(raw)) {
407
- if (!allowed.has(k)) {
408
- ctx.addIssue({
409
- code: z.ZodIssueCode.unrecognized_keys,
410
- keys: [k],
411
- message: `Unrecognized improve process key: "${k}".`,
412
- });
413
- }
414
400
  }
415
401
  });
416
402
  export const ImproveProfileConfigSchema = z
@@ -435,10 +421,10 @@ export const ImproveProfileConfigSchema = z
435
421
  push: z.boolean().optional(),
436
422
  message: z.string().min(1).optional(),
437
423
  })
438
- .strict()
424
+ .passthrough()
439
425
  .optional(),
440
426
  })
441
- .strict();
427
+ .passthrough();
442
428
  // ── Profiles / defaults ────────────────────────────────────────────────────
443
429
  export const ProfilesSchema = z
444
430
  .object({
@@ -446,14 +432,14 @@ export const ProfilesSchema = z
446
432
  agent: z.record(z.string(), AgentProfileConfigSchema).optional(),
447
433
  improve: z.record(z.string(), ImproveProfileConfigSchema).optional(),
448
434
  })
449
- .strict();
435
+ .passthrough();
450
436
  export const DefaultsSchema = z
451
437
  .object({
452
438
  llm: z.string().min(1).optional(),
453
439
  agent: z.string().min(1).optional(),
454
440
  improve: z.string().min(1).optional(),
455
441
  })
456
- .strict();
442
+ .passthrough();
457
443
  // ── Sources / registries / installed ────────────────────────────────────────
458
444
  const SourceConfigEntryOptionsSchema = z
459
445
  .object({
@@ -477,7 +463,7 @@ export const SourceConfigEntrySchema = z
477
463
  options: SourceConfigEntryOptionsSchema.optional(),
478
464
  wikiName: z.string().min(1).optional(),
479
465
  })
480
- .strict()
466
+ .passthrough()
481
467
  .superRefine((entry, ctx) => {
482
468
  if (entry.writable === true && (entry.type === "website" || entry.type === "npm")) {
483
469
  ctx.addIssue({
@@ -496,7 +482,7 @@ export const RegistryConfigEntrySchema = z
496
482
  provider: z.string().min(1).optional(),
497
483
  options: z.record(z.unknown()).optional(),
498
484
  })
499
- .strict();
485
+ .passthrough();
500
486
  const KitSourceSchema = z.enum(["filesystem", "git", "npm", "github", "website", "local"]);
501
487
  export const InstalledStashEntrySchema = z
502
488
  .object({
@@ -512,7 +498,7 @@ export const InstalledStashEntrySchema = z
512
498
  resolvedRevision: z.string().min(1).optional(),
513
499
  wikiName: z.string().min(1).optional(),
514
500
  })
515
- .strict()
501
+ .passthrough()
516
502
  .superRefine((entry, ctx) => {
517
503
  if (entry.writable === true && entry.source !== "git" && entry.source !== "filesystem") {
518
504
  ctx.addIssue({
@@ -527,7 +513,7 @@ export const OutputConfigSchema = z
527
513
  format: z.enum(["json", "yaml", "text"]).optional(),
528
514
  detail: z.enum(["brief", "normal", "full"]).optional(),
529
515
  })
530
- .strict();
516
+ .passthrough();
531
517
  // ── Search ──────────────────────────────────────────────────────────────────
532
518
  const SearchGraphBoostSchema = z
533
519
  .object({
@@ -541,29 +527,29 @@ const SearchGraphBoostSchema = z
541
527
  /** Range [0, 1]; values > 1 hard-error (no silent clamp). */
542
528
  confidenceWeight: z.number().finite().min(0).max(1).default(0.2).optional(),
543
529
  })
544
- .strict();
530
+ .passthrough();
545
531
  export const SearchConfigSchema = z
546
532
  .object({
547
533
  minScore: nonNegativeNumber.optional(),
548
534
  defaultExcludeTypes: z.array(nonEmptyString).optional(),
549
- curateRerank: z.object({ enabled: z.boolean().optional() }).strict().optional(),
535
+ curateRerank: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
550
536
  graphBoost: SearchGraphBoostSchema.optional(),
551
537
  })
552
- .strict();
538
+ .passthrough();
553
539
  // ── Feedback ────────────────────────────────────────────────────────────────
554
540
  export const FeedbackConfigSchema = z
555
541
  .object({
556
542
  requireReason: z.boolean().optional(),
557
543
  allowedFailureModes: z.array(nonEmptyString).optional(),
558
544
  })
559
- .strict();
545
+ .passthrough();
560
546
  // ── Improve top-level (utility decay, event retention) ─────────────────────
561
547
  const ImproveUtilityDecaySchema = z
562
548
  .object({
563
549
  halfLifeDays: z.number().finite().min(0.1).optional(),
564
550
  feedbackStabilityBoost: z.number().finite().min(1).optional(),
565
551
  })
566
- .strict();
552
+ .passthrough();
567
553
  // #612 / WS-4 — auto-accept gate calibration + bounded, opt-in per-phase
568
554
  // threshold auto-tune. DEFAULT OFF: when absent (or `autoTune: false`) no
569
555
  // tuning occurs, so the gate behaves byte-identically to today.
@@ -586,7 +572,7 @@ const ImproveCalibrationSchema = z
586
572
  /** Target realized accept rate in [0, 1]. Default 0.9. */
587
573
  targetAcceptRate: z.number().finite().min(0).max(1).optional(),
588
574
  })
589
- .strict();
575
+ .passthrough();
590
576
  // WS-4 — exploration budget: a fixed fraction of proposals accepted per run
591
577
  // regardless of confidence. DEFAULT OFF.
592
578
  const ImproveExplorationSchema = z
@@ -602,7 +588,7 @@ const ImproveExplorationSchema = z
602
588
  */
603
589
  budgetFraction: z.number().finite().min(0).max(1).optional(),
604
590
  })
605
- .strict();
591
+ .passthrough();
606
592
  const ImproveSalienceSchema = z
607
593
  .object({
608
594
  /**
@@ -624,7 +610,7 @@ const ImproveSalienceSchema = z
624
610
  */
625
611
  replayBudget: z.number().int().min(0).optional(),
626
612
  })
627
- .strict();
613
+ .passthrough();
628
614
  export const ImproveConfigSchema = z
629
615
  .object({
630
616
  utilityDecay: ImproveUtilityDecaySchema.optional(),
@@ -633,7 +619,7 @@ export const ImproveConfigSchema = z
633
619
  exploration: ImproveExplorationSchema.optional(),
634
620
  salience: ImproveSalienceSchema.optional(),
635
621
  })
636
- .strict();
622
+ .passthrough();
637
623
  // ── Index / per-pass ────────────────────────────────────────────────────────
638
624
  const GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED = [
639
625
  "memory",
@@ -712,13 +698,13 @@ export const IndexPassConfigSchema = z.preprocess((raw, ctx) => {
712
698
  lazyGraphExtraction: z.boolean().optional(),
713
699
  })
714
700
  .passthrough());
715
- const MetadataEnhanceSchema = z.object({ enabled: z.boolean().optional() }).strict();
701
+ const MetadataEnhanceSchema = z.object({ enabled: z.boolean().optional() }).passthrough();
716
702
  const StalenessDetectionSchema = z
717
703
  .object({
718
704
  enabled: z.boolean().optional(),
719
705
  thresholdDays: positiveInt.optional(),
720
706
  })
721
- .strict();
707
+ .passthrough();
722
708
  /**
723
709
  * Index config is a union of reserved feature sections and per-pass entries.
724
710
  * Passthrough so per-pass entries (keyed by arbitrary pass names like `graph`,
@@ -791,12 +777,12 @@ export const SetupTaskSchedulesSchema = z
791
777
  improve: z.string().min(1).optional(),
792
778
  index: z.string().min(1).optional(),
793
779
  })
794
- .strict();
780
+ .passthrough();
795
781
  export const SetupConfigSchema = z
796
782
  .object({
797
783
  taskSchedules: SetupTaskSchedulesSchema.optional(),
798
784
  })
799
- .strict();
785
+ .passthrough();
800
786
  // ── Top-level AkmConfig ────────────────────────────────────────────────────
801
787
  /**
802
788
  * Base object schema used both as the top-level shape and as the source of
@@ -828,7 +814,7 @@ export const AkmConfigShape = {
828
814
  improve: ImproveConfigSchema.optional(),
829
815
  setup: SetupConfigSchema.optional(),
830
816
  };
831
- export const AkmConfigBaseSchema = z.object(AkmConfigShape).strict();
817
+ export const AkmConfigBaseSchema = z.object(AkmConfigShape).passthrough();
832
818
  export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
833
819
  // #464.a: defaultWriteTarget must name a configured source when sources
834
820
  // are present. With no sources configured, error out instead of silently
@@ -15785,7 +15785,7 @@ var init_config_schema = __esm(() => {
15785
15785
  });
15786
15786
  LlmCapabilitiesSchema = exports_external.object({
15787
15787
  structuredOutput: exports_external.boolean().optional()
15788
- }).strict();
15788
+ }).passthrough();
15789
15789
  LlmConnectionConfigSchema = exports_external.object({
15790
15790
  provider: exports_external.string().optional(),
15791
15791
  endpoint: exports_external.string(),
@@ -15800,13 +15800,13 @@ var init_config_schema = __esm(() => {
15800
15800
  contextLength: positiveInt.optional(),
15801
15801
  judgeModel: exports_external.string().min(1).optional(),
15802
15802
  enableThinking: exports_external.boolean().optional()
15803
- }).strict();
15803
+ }).passthrough();
15804
15804
  LlmProfileConfigSchema = LlmConnectionConfigSchema.extend({
15805
15805
  supportsJsonSchema: exports_external.boolean().optional()
15806
- }).strict();
15806
+ }).passthrough();
15807
15807
  EmbeddingOllamaOptionsSchema = exports_external.object({
15808
15808
  num_ctx: positiveInt.optional()
15809
- }).strict();
15809
+ }).passthrough();
15810
15810
  EmbeddingConnectionConfigSchema = exports_external.object({
15811
15811
  provider: exports_external.string().optional(),
15812
15812
  endpoint: exports_external.string().optional(),
@@ -15819,7 +15819,7 @@ var init_config_schema = __esm(() => {
15819
15819
  chunkSize: positiveInt.optional(),
15820
15820
  contextLength: positiveInt.optional(),
15821
15821
  ollamaOptions: EmbeddingOllamaOptionsSchema.optional()
15822
- }).strict();
15822
+ }).passthrough();
15823
15823
  AgentPlatformSchema = exports_external.enum(VALID_HARNESS_IDS);
15824
15824
  AgentProfileConfigSchema = exports_external.object({
15825
15825
  platform: AgentPlatformSchema,
@@ -15827,7 +15827,7 @@ var init_config_schema = __esm(() => {
15827
15827
  args: exports_external.array(exports_external.string()).optional(),
15828
15828
  workspace: exports_external.string().min(1).optional(),
15829
15829
  model: exports_external.string().min(1).optional()
15830
- }).strict();
15830
+ }).passthrough();
15831
15831
  ImproveProcessConfigSchema = exports_external.object({
15832
15832
  enabled: exports_external.boolean().optional(),
15833
15833
  mode: exports_external.enum(["llm", "agent", "sdk"]).optional(),
@@ -15839,10 +15839,10 @@ var init_config_schema = __esm(() => {
15839
15839
  enabled: exports_external.boolean().optional(),
15840
15840
  cosineThreshold: exports_external.number().min(0).max(1).optional(),
15841
15841
  cosineCandidateLimit: exports_external.number().int().positive().optional()
15842
- }).strict().optional(),
15843
- judgedCache: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
15844
- qualityGate: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
15845
- contradictionDetection: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
15842
+ }).passthrough().optional(),
15843
+ judgedCache: exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional(),
15844
+ qualityGate: exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional(),
15845
+ contradictionDetection: exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional(),
15846
15846
  defaultSince: exports_external.string().min(1).optional(),
15847
15847
  maxTotalChars: positiveInt.optional(),
15848
15848
  minContentChars: exports_external.number().int().min(0).optional(),
@@ -15864,28 +15864,28 @@ var init_config_schema = __esm(() => {
15864
15864
  enabled: exports_external.boolean().optional(),
15865
15865
  staleDays: exports_external.number().int().min(0).optional(),
15866
15866
  demotionFactor: exports_external.number().min(0).max(1).optional()
15867
- }).strict().optional(),
15867
+ }).passthrough().optional(),
15868
15868
  schemaSimilarity: exports_external.object({
15869
15869
  enabled: exports_external.boolean().optional(),
15870
15870
  epsilon: exports_external.number().min(0).max(1).optional(),
15871
15871
  confidencePenalty: exports_external.number().min(0).max(1).optional()
15872
- }).strict().optional(),
15872
+ }).passthrough().optional(),
15873
15873
  hotProbation: exports_external.object({
15874
15874
  enabled: exports_external.boolean().optional()
15875
- }).strict().optional(),
15875
+ }).passthrough().optional(),
15876
15876
  antiCollapse: exports_external.object({
15877
15877
  enabled: exports_external.boolean().optional(),
15878
15878
  maxGeneration: exports_external.number().int().min(1).optional(),
15879
15879
  lexicalDiversityCheck: exports_external.boolean().optional(),
15880
15880
  randomClusterFraction: exports_external.number().min(0).max(1).optional()
15881
- }).strict().optional(),
15881
+ }).passthrough().optional(),
15882
15882
  cls: exports_external.object({
15883
15883
  enabled: exports_external.boolean().optional(),
15884
15884
  adjacentCount: exports_external.number().int().min(1).optional()
15885
- }).strict().optional(),
15885
+ }).passthrough().optional(),
15886
15886
  fidelityCheck: exports_external.object({
15887
15887
  enabled: exports_external.boolean().optional()
15888
- }).strict().optional(),
15888
+ }).passthrough().optional(),
15889
15889
  minClusterSize: exports_external.number().int().min(2).optional(),
15890
15890
  maxClustersPerRun: positiveInt.optional(),
15891
15891
  maxClusterSize: positiveInt.optional(),
@@ -15896,7 +15896,7 @@ var init_config_schema = __esm(() => {
15896
15896
  minRecurrence: exports_external.number().int().min(2).optional(),
15897
15897
  maxProposalsPerRun: positiveInt.optional(),
15898
15898
  emitAs: exports_external.enum(["workflow", "skill"]).optional(),
15899
- lowValueFilter: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
15899
+ lowValueFilter: exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional(),
15900
15900
  proceduralAwareFloor: exports_external.boolean().optional(),
15901
15901
  applyMode: exports_external.enum(["queue", "promote"]).optional(),
15902
15902
  policy: exports_external.string().min(1).optional(),
@@ -15907,8 +15907,8 @@ var init_config_schema = __esm(() => {
15907
15907
  mode: exports_external.enum(["llm", "agent", "sdk"]).optional(),
15908
15908
  profile: exports_external.string().min(1).optional(),
15909
15909
  timeoutMs: exports_external.union([positiveInt, exports_external.null()]).optional()
15910
- }).strict().optional()
15911
- }).strict();
15910
+ }).passthrough().optional()
15911
+ }).passthrough();
15912
15912
  ImproveProfileProcessesSchema = exports_external.object({
15913
15913
  reflect: ImproveProcessConfigSchema.optional(),
15914
15914
  distill: ImproveProcessConfigSchema.optional(),
@@ -15921,35 +15921,11 @@ var init_config_schema = __esm(() => {
15921
15921
  recombine: ImproveProcessConfigSchema.optional(),
15922
15922
  procedural: ImproveProcessConfigSchema.optional()
15923
15923
  }).passthrough().superRefine((val, ctx) => {
15924
- const raw = val;
15925
- if ("feedbackDistillation" in raw) {
15924
+ if ("feedbackDistillation" in val) {
15926
15925
  ctx.addIssue({
15927
15926
  code: exports_external.ZodIssueCode.custom,
15928
15927
  message: "feedbackDistillation was removed in 0.8.0 \u2014 use processes.distill.enabled instead. " + "It now controls both the orchestration gate and the LLM-call gate."
15929
15928
  });
15930
- return;
15931
- }
15932
- const allowed = new Set([
15933
- "reflect",
15934
- "distill",
15935
- "consolidate",
15936
- "memoryInference",
15937
- "graphExtraction",
15938
- "validation",
15939
- "extract",
15940
- "triage",
15941
- "proactiveMaintenance",
15942
- "recombine",
15943
- "procedural"
15944
- ]);
15945
- for (const k of Object.keys(raw)) {
15946
- if (!allowed.has(k)) {
15947
- ctx.addIssue({
15948
- code: exports_external.ZodIssueCode.unrecognized_keys,
15949
- keys: [k],
15950
- message: `Unrecognized improve process key: "${k}".`
15951
- });
15952
- }
15953
15929
  }
15954
15930
  });
15955
15931
  ImproveProfileConfigSchema = exports_external.object({
@@ -15963,18 +15939,18 @@ var init_config_schema = __esm(() => {
15963
15939
  enabled: exports_external.boolean().optional(),
15964
15940
  push: exports_external.boolean().optional(),
15965
15941
  message: exports_external.string().min(1).optional()
15966
- }).strict().optional()
15967
- }).strict();
15942
+ }).passthrough().optional()
15943
+ }).passthrough();
15968
15944
  ProfilesSchema = exports_external.object({
15969
15945
  llm: exports_external.record(exports_external.string(), LlmProfileConfigSchema).optional(),
15970
15946
  agent: exports_external.record(exports_external.string(), AgentProfileConfigSchema).optional(),
15971
15947
  improve: exports_external.record(exports_external.string(), ImproveProfileConfigSchema).optional()
15972
- }).strict();
15948
+ }).passthrough();
15973
15949
  DefaultsSchema = exports_external.object({
15974
15950
  llm: exports_external.string().min(1).optional(),
15975
15951
  agent: exports_external.string().min(1).optional(),
15976
15952
  improve: exports_external.string().min(1).optional()
15977
- }).strict();
15953
+ }).passthrough();
15978
15954
  SourceConfigEntryOptionsSchema = exports_external.object({
15979
15955
  pushOnCommit: exports_external.boolean().optional()
15980
15956
  }).passthrough();
@@ -15988,7 +15964,7 @@ var init_config_schema = __esm(() => {
15988
15964
  primary: exports_external.boolean().optional(),
15989
15965
  options: SourceConfigEntryOptionsSchema.optional(),
15990
15966
  wikiName: exports_external.string().min(1).optional()
15991
- }).strict().superRefine((entry, ctx) => {
15967
+ }).passthrough().superRefine((entry, ctx) => {
15992
15968
  if (entry.writable === true && (entry.type === "website" || entry.type === "npm")) {
15993
15969
  ctx.addIssue({
15994
15970
  code: exports_external.ZodIssueCode.custom,
@@ -16002,7 +15978,7 @@ var init_config_schema = __esm(() => {
16002
15978
  enabled: exports_external.boolean().optional(),
16003
15979
  provider: exports_external.string().min(1).optional(),
16004
15980
  options: exports_external.record(exports_external.unknown()).optional()
16005
- }).strict();
15981
+ }).passthrough();
16006
15982
  KitSourceSchema = exports_external.enum(["filesystem", "git", "npm", "github", "website", "local"]);
16007
15983
  InstalledStashEntrySchema = exports_external.object({
16008
15984
  id: nonEmptyString,
@@ -16016,7 +15992,7 @@ var init_config_schema = __esm(() => {
16016
15992
  resolvedVersion: exports_external.string().min(1).optional(),
16017
15993
  resolvedRevision: exports_external.string().min(1).optional(),
16018
15994
  wikiName: exports_external.string().min(1).optional()
16019
- }).strict().superRefine((entry, ctx) => {
15995
+ }).passthrough().superRefine((entry, ctx) => {
16020
15996
  if (entry.writable === true && entry.source !== "git" && entry.source !== "filesystem") {
16021
15997
  ctx.addIssue({
16022
15998
  code: exports_external.ZodIssueCode.custom,
@@ -16027,7 +16003,7 @@ var init_config_schema = __esm(() => {
16027
16003
  OutputConfigSchema = exports_external.object({
16028
16004
  format: exports_external.enum(["json", "yaml", "text"]).optional(),
16029
16005
  detail: exports_external.enum(["brief", "normal", "full"]).optional()
16030
- }).strict();
16006
+ }).passthrough();
16031
16007
  SearchGraphBoostSchema = exports_external.object({
16032
16008
  directBoostPerEntity: nonNegativeNumber.optional(),
16033
16009
  directBoostCap: nonNegativeNumber.optional(),
@@ -16036,21 +16012,21 @@ var init_config_schema = __esm(() => {
16036
16012
  maxHops: positiveInt.max(3).optional(),
16037
16013
  confidenceMode: exports_external.enum(["off", "blend", "multiply"]).default("blend").optional(),
16038
16014
  confidenceWeight: exports_external.number().finite().min(0).max(1).default(0.2).optional()
16039
- }).strict();
16015
+ }).passthrough();
16040
16016
  SearchConfigSchema = exports_external.object({
16041
16017
  minScore: nonNegativeNumber.optional(),
16042
16018
  defaultExcludeTypes: exports_external.array(nonEmptyString).optional(),
16043
- curateRerank: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
16019
+ curateRerank: exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional(),
16044
16020
  graphBoost: SearchGraphBoostSchema.optional()
16045
- }).strict();
16021
+ }).passthrough();
16046
16022
  FeedbackConfigSchema = exports_external.object({
16047
16023
  requireReason: exports_external.boolean().optional(),
16048
16024
  allowedFailureModes: exports_external.array(nonEmptyString).optional()
16049
- }).strict();
16025
+ }).passthrough();
16050
16026
  ImproveUtilityDecaySchema = exports_external.object({
16051
16027
  halfLifeDays: exports_external.number().finite().min(0.1).optional(),
16052
16028
  feedbackStabilityBoost: exports_external.number().finite().min(1).optional()
16053
- }).strict();
16029
+ }).passthrough();
16054
16030
  ImproveCalibrationSchema = exports_external.object({
16055
16031
  autoTune: exports_external.boolean().optional(),
16056
16032
  minThreshold: exports_external.number().int().min(0).max(100).optional(),
@@ -16058,23 +16034,23 @@ var init_config_schema = __esm(() => {
16058
16034
  maxStep: positiveInt.optional(),
16059
16035
  minSamples: nonNegativeNumber.optional(),
16060
16036
  targetAcceptRate: exports_external.number().finite().min(0).max(1).optional()
16061
- }).strict();
16037
+ }).passthrough();
16062
16038
  ImproveExplorationSchema = exports_external.object({
16063
16039
  enabled: exports_external.boolean().optional(),
16064
16040
  budgetFraction: exports_external.number().finite().min(0).max(1).optional()
16065
- }).strict();
16041
+ }).passthrough();
16066
16042
  ImproveSalienceSchema = exports_external.object({
16067
16043
  outcomeWeightEnabled: exports_external.boolean().optional(),
16068
16044
  salienceThreshold: exports_external.number().min(0).max(1).optional(),
16069
16045
  replayBudget: exports_external.number().int().min(0).optional()
16070
- }).strict();
16046
+ }).passthrough();
16071
16047
  ImproveConfigSchema = exports_external.object({
16072
16048
  utilityDecay: ImproveUtilityDecaySchema.optional(),
16073
16049
  eventRetentionDays: nonNegativeNumber.optional(),
16074
16050
  calibration: ImproveCalibrationSchema.optional(),
16075
16051
  exploration: ImproveExplorationSchema.optional(),
16076
16052
  salience: ImproveSalienceSchema.optional()
16077
- }).strict();
16053
+ }).passthrough();
16078
16054
  GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED = [
16079
16055
  "memory",
16080
16056
  "knowledge",
@@ -16140,11 +16116,11 @@ var init_config_schema = __esm(() => {
16140
16116
  memoryInferenceBatchSize: positiveInt.optional(),
16141
16117
  lazyGraphExtraction: exports_external.boolean().optional()
16142
16118
  }).passthrough());
16143
- MetadataEnhanceSchema = exports_external.object({ enabled: exports_external.boolean().optional() }).strict();
16119
+ MetadataEnhanceSchema = exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough();
16144
16120
  StalenessDetectionSchema = exports_external.object({
16145
16121
  enabled: exports_external.boolean().optional(),
16146
16122
  thresholdDays: positiveInt.optional()
16147
- }).strict();
16123
+ }).passthrough();
16148
16124
  IndexConfigSchema = exports_external.preprocess((raw, ctx) => {
16149
16125
  if (raw === undefined || raw === null)
16150
16126
  return raw;
@@ -16190,10 +16166,10 @@ var init_config_schema = __esm(() => {
16190
16166
  SetupTaskSchedulesSchema = exports_external.object({
16191
16167
  improve: exports_external.string().min(1).optional(),
16192
16168
  index: exports_external.string().min(1).optional()
16193
- }).strict();
16169
+ }).passthrough();
16194
16170
  SetupConfigSchema = exports_external.object({
16195
16171
  taskSchedules: SetupTaskSchedulesSchema.optional()
16196
- }).strict();
16172
+ }).passthrough();
16197
16173
  AkmConfigShape = {
16198
16174
  configVersion: exports_external.union([exports_external.string().min(1), exports_external.number()]).optional(),
16199
16175
  profiles: ProfilesSchema.optional(),
@@ -16214,7 +16190,7 @@ var init_config_schema = __esm(() => {
16214
16190
  improve: ImproveConfigSchema.optional(),
16215
16191
  setup: SetupConfigSchema.optional()
16216
16192
  };
16217
- AkmConfigBaseSchema = exports_external.object(AkmConfigShape).strict();
16193
+ AkmConfigBaseSchema = exports_external.object(AkmConfigShape).passthrough();
16218
16194
  AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
16219
16195
  if (config.defaultWriteTarget !== undefined) {
16220
16196
  const knownNames = (config.sources ?? []).map((s) => s.name).filter((n) => typeof n === "string" && n.length > 0);
@@ -4,6 +4,21 @@
4
4
  import { fetchWithRetry } from "../../core/common.js";
5
5
  const YOUTUBE_HOSTS = new Set(["www.youtube.com", "youtube.com", "m.youtube.com", "youtu.be"]);
6
6
  const WATCH_HOST = "https://www.youtube.com/watch?v=";
7
+ // Captions: the WEB watch-page caption baseUrls are now Proof-of-Origin-Token
8
+ // gated (they carry `exp=xpe` and return an empty body without a `pot` token).
9
+ // The ANDROID InnerTube `player` client still returns UNGATED caption baseUrls
10
+ // that serve the transcript, so captions are sourced from there. See
11
+ // https://github.com/yt-dlp/yt-dlp/issues/13075.
12
+ const INNERTUBE_PLAYER_URL = "https://www.youtube.com/youtubei/v1/player";
13
+ // Long-stable public InnerTube key; only authorizes the player call (not auth).
14
+ const DEFAULT_INNERTUBE_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8";
15
+ const ANDROID_INNERTUBE_CLIENT = {
16
+ clientName: "ANDROID",
17
+ clientVersion: "20.10.38",
18
+ androidSdkVersion: 34,
19
+ hl: "en",
20
+ gl: "US",
21
+ };
7
22
  function extractVideoId(url) {
8
23
  if (!YOUTUBE_HOSTS.has(url.hostname))
9
24
  return null;
@@ -129,13 +144,45 @@ async function fetchText(url, timeoutMs, signal) {
129
144
  return response.text();
130
145
  }
131
146
  function parseTranscript(xml) {
132
- const texts = [...xml.matchAll(/<text\b[^>]*>([\s\S]*?)<\/text>/g)]
133
- .map((match) => decodeEntities(stripTags(match[1] ?? "")).trim())
134
- .filter(Boolean);
147
+ // Two timedtext shapes: legacy srv1 `<text>` cues, and the format-3
148
+ // `<timedtext format="3">` `<p>` cues that the ANDROID InnerTube caption
149
+ // URLs return. Strip any nested `<s>` word tags via stripTags.
150
+ const matches = [...xml.matchAll(/<text\b[^>]*>([\s\S]*?)<\/text>/g), ...xml.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p>/g)];
151
+ const texts = matches.map((match) => decodeEntities(stripTags(match[1] ?? "")).trim()).filter(Boolean);
135
152
  if (texts.length === 0)
136
153
  return null;
137
154
  return texts.join("\n");
138
155
  }
156
+ /**
157
+ * Fetch caption tracks via the ANDROID InnerTube `player` endpoint, whose
158
+ * caption baseUrls are not POT-gated. Returns [] on any failure so the caller
159
+ * can fall back to the (usually empty) watch-page tracks and degrade to a
160
+ * description-only snapshot.
161
+ */
162
+ async function fetchInnertubeCaptionTracks(videoId, apiKey, timeoutMs, signal) {
163
+ try {
164
+ const response = await fetchWithRetry(`${INNERTUBE_PLAYER_URL}?key=${encodeURIComponent(apiKey)}`, {
165
+ method: "POST",
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ "User-Agent": "com.google.android.youtube/20.10.38 (Linux; U; Android 14) gzip",
169
+ },
170
+ body: JSON.stringify({ context: { client: ANDROID_INNERTUBE_CLIENT }, videoId }),
171
+ signal,
172
+ }, { timeout: timeoutMs, retries: 1 });
173
+ if (!response.ok)
174
+ return [];
175
+ const json = (await response.json());
176
+ return json.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? [];
177
+ }
178
+ catch {
179
+ return [];
180
+ }
181
+ }
182
+ /** Extract the page's InnerTube API key, falling back to the stable default. */
183
+ function extractInnertubeKey(html) {
184
+ return html.match(/"INNERTUBE_API_KEY":"([^"]+)"/)?.[1] ?? DEFAULT_INNERTUBE_KEY;
185
+ }
139
186
  const youtubeFetcher = {
140
187
  name: "youtube-transcript",
141
188
  matches(url) {
@@ -161,7 +208,14 @@ const youtubeFetcher = {
161
208
  if (description) {
162
209
  sections.push("## Description", "", description);
163
210
  }
164
- const tracks = playerResponse.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? [];
211
+ // Prefer ungated ANDROID InnerTube caption tracks; fall back to the
212
+ // (now usually empty) watch-page tracks so a description-only snapshot
213
+ // still works when InnerTube is unavailable.
214
+ const apiKey = extractInnertubeKey(watchHtml);
215
+ let tracks = await fetchInnertubeCaptionTracks(videoId, apiKey, context.timeoutMs, context.signal);
216
+ if (tracks.length === 0) {
217
+ tracks = playerResponse.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? [];
218
+ }
165
219
  const captionUrl = chooseCaptionTrack(tracks);
166
220
  if (captionUrl) {
167
221
  const transcriptXml = await fetchText(captionUrl, context.timeoutMs, context.signal);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.0-beta.47",
3
+ "version": "0.9.0-beta.48",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [