@pmelab/gtd 38.0.0 → 38.2.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 (39) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +36 -3
  3. package/dist/chunks/{Schema-DO5ttJaI.mjs → Schema-C6fLlQzx.mjs} +1 -1
  4. package/dist/chunks/{reserved-sfMdy7v7.mjs → reserved-C3PgP7XB.mjs} +56 -12
  5. package/dist/chunks/{tail-Cgca5Gp-.mjs → tail-Bkxki2nK.mjs} +1 -1
  6. package/dist/chunks/{wire-CSsa3Wxd.mjs → wire-BJuZWR3C.mjs} +1 -1
  7. package/dist/gtd.bundle.mjs +292 -53
  8. package/dist/testkit.mjs +257 -21
  9. package/dist/wire.mjs +1 -1
  10. package/dist/workflows/cleanup.mjs +2 -2
  11. package/dist/workflows/feature.mjs +158 -42
  12. package/dist/workflows/fix.mjs +2 -2
  13. package/dist/workflows/review.mjs +2 -2
  14. package/dist/workflows/rollout.mjs +1 -1
  15. package/dist/workflows.mjs +230 -70
  16. package/package.json +1 -1
  17. package/src/cli/Cli.test.ts +15 -3
  18. package/src/cli/Cli.ts +61 -28
  19. package/src/cli/History.ts +1 -19
  20. package/src/cli/Metrics.test.ts +224 -0
  21. package/src/cli/Metrics.ts +310 -0
  22. package/src/cli/Output.ts +13 -0
  23. package/src/cli/Program.test.ts +3 -1
  24. package/src/cli/Program.ts +4 -0
  25. package/src/testkit/steps.ts +4 -0
  26. package/src/wire/ContextLimit.ts +1 -1
  27. package/src/workflows/feature/continuation-cap.feature +65 -0
  28. package/src/workflows/feature/continuation-rebuild.feature +88 -0
  29. package/src/workflows/feature/continuation-slices.feature +64 -0
  30. package/src/workflows/feature/continuation.feature +205 -0
  31. package/src/workflows/feature/criteria.ts +11 -0
  32. package/src/workflows/feature/refactor.ts +64 -30
  33. package/src/workflows/feature/seam.ts +102 -30
  34. package/src/workflows/shared/continuation.ts +92 -0
  35. package/src/workflows/shared/options.ts +2 -0
  36. package/src/workflows/shared/steps.ts +1 -0
  37. package/src/workflows/shared/text.test.ts +6 -2
  38. package/src/workflows/shared/text.ts +104 -8
  39. package/src/workflows/shared/vars.ts +5 -0
@@ -2137,7 +2137,7 @@ var init_hashMap = __esmMin((() => {
2137
2137
  }));
2138
2138
  //#endregion
2139
2139
  //#region node_modules/effect/dist/esm/internal/hashSet.js
2140
- var HashSetSymbolKey, HashSetTypeId, HashSetProto, makeImpl, isHashSet, _empty$4, empty$23, fromIterable$3, make$44, has$2, size$6, beginMutation, endMutation, mutate, add$3, remove$3, difference$1, union$1, forEach$4, reduce$4;
2140
+ var HashSetSymbolKey, HashSetTypeId, HashSetProto, makeImpl, isHashSet, _empty$4, empty$23, fromIterable$3, make$44, has$2, size$6, beginMutation, endMutation, mutate, add$4, remove$3, difference$1, union$1, forEach$4, reduce$4;
2141
2141
  var init_hashSet = __esmMin((() => {
2142
2142
  init_Equal();
2143
2143
  init_Function();
@@ -2186,12 +2186,12 @@ var init_hashSet = __esmMin((() => {
2186
2186
  empty$23 = () => _empty$4;
2187
2187
  fromIterable$3 = (elements) => {
2188
2188
  const set = beginMutation(empty$23());
2189
- for (const value of elements) add$3(set, value);
2189
+ for (const value of elements) add$4(set, value);
2190
2190
  return endMutation(set);
2191
2191
  };
2192
2192
  make$44 = (...elements) => {
2193
2193
  const set = beginMutation(empty$23());
2194
- for (const value of elements) add$3(set, value);
2194
+ for (const value of elements) add$4(set, value);
2195
2195
  return endMutation(set);
2196
2196
  };
2197
2197
  has$2 = /*#__PURE__*/ dual(2, (self, value) => has$3(self._keyMap, value));
@@ -2206,21 +2206,21 @@ var init_hashSet = __esmMin((() => {
2206
2206
  f(transient);
2207
2207
  return endMutation(transient);
2208
2208
  });
2209
- add$3 = /*#__PURE__*/ dual(2, (self, value) => self._keyMap._editable ? (set$5(value, true)(self._keyMap), self) : makeImpl(set$5(value, true)(self._keyMap)));
2209
+ add$4 = /*#__PURE__*/ dual(2, (self, value) => self._keyMap._editable ? (set$5(value, true)(self._keyMap), self) : makeImpl(set$5(value, true)(self._keyMap)));
2210
2210
  remove$3 = /*#__PURE__*/ dual(2, (self, value) => self._keyMap._editable ? (remove$4(value)(self._keyMap), self) : makeImpl(remove$4(value)(self._keyMap)));
2211
2211
  difference$1 = /*#__PURE__*/ dual(2, (self, that) => mutate(self, (set) => {
2212
2212
  for (const value of that) remove$3(set, value);
2213
2213
  }));
2214
2214
  union$1 = /*#__PURE__*/ dual(2, (self, that) => mutate(empty$23(), (set) => {
2215
- forEach$4(self, (value) => add$3(set, value));
2216
- for (const value of that) add$3(set, value);
2215
+ forEach$4(self, (value) => add$4(set, value));
2216
+ for (const value of that) add$4(set, value);
2217
2217
  }));
2218
2218
  forEach$4 = /*#__PURE__*/ dual(2, (self, f) => forEach$5(self._keyMap, (_, k) => f(k)));
2219
2219
  reduce$4 = /*#__PURE__*/ dual(3, (self, zero, f) => reduce$5(self._keyMap, zero, (z, _, a) => f(z, a)));
2220
2220
  }));
2221
2221
  //#endregion
2222
2222
  //#region node_modules/effect/dist/esm/HashSet.js
2223
- var empty$22, fromIterable$2, make$43, has$1, size$5, add$2, remove$2, difference, union, reduce$3;
2223
+ var empty$22, fromIterable$2, make$43, has$1, size$5, add$3, remove$2, difference, union, reduce$3;
2224
2224
  var init_HashSet = __esmMin((() => {
2225
2225
  init_hashSet();
2226
2226
  empty$22 = empty$23;
@@ -2228,7 +2228,7 @@ var init_HashSet = __esmMin((() => {
2228
2228
  make$43 = make$44;
2229
2229
  has$1 = has$2;
2230
2230
  size$5 = size$6;
2231
- add$2 = add$3;
2231
+ add$3 = add$4;
2232
2232
  remove$2 = remove$3;
2233
2233
  difference = difference$1;
2234
2234
  union = union$1;
@@ -2369,7 +2369,7 @@ _E: (_) => _ };
2369
2369
  isInterruptedOnly$1 = (self) => reduceWithContext$1(void 0, IsInterruptedOnlyCauseReducer)(self);
2370
2370
  failures = (self) => reverse$1(reduce$2(self, empty$25(), (list, cause) => cause._tag === "Fail" ? some(pipe(list, prepend$1(cause.error))) : none$4()));
2371
2371
  defects = (self) => reverse$1(reduce$2(self, empty$25(), (list, cause) => cause._tag === "Die" ? some(pipe(list, prepend$1(cause.defect))) : none$4()));
2372
- interruptors$1 = (self) => reduce$2(self, empty$22(), (set, cause) => cause._tag === "Interrupt" ? some(pipe(set, add$2(cause.fiberId))) : none$4());
2372
+ interruptors$1 = (self) => reduce$2(self, empty$22(), (set, cause) => cause._tag === "Interrupt" ? some(pipe(set, add$3(cause.fiberId))) : none$4());
2373
2373
  failureOption = (self) => find(self, (cause) => cause._tag === "Fail" ? some(cause.error) : none$4());
2374
2374
  failureOrCause$1 = (self) => {
2375
2375
  const option = failureOption(self);
@@ -2485,17 +2485,17 @@ _E: (_) => _ };
2485
2485
  cause = stack.pop();
2486
2486
  break;
2487
2487
  case OP_FAIL$2:
2488
- _parallel = add$2(_parallel, make$46(cause._tag, cause.error));
2488
+ _parallel = add$3(_parallel, make$46(cause._tag, cause.error));
2489
2489
  if (stack.length === 0) return [_parallel, _sequential];
2490
2490
  cause = stack.pop();
2491
2491
  break;
2492
2492
  case "Die":
2493
- _parallel = add$2(_parallel, make$46(cause._tag, cause.defect));
2493
+ _parallel = add$3(_parallel, make$46(cause._tag, cause.defect));
2494
2494
  if (stack.length === 0) return [_parallel, _sequential];
2495
2495
  cause = stack.pop();
2496
2496
  break;
2497
2497
  case OP_INTERRUPT:
2498
- _parallel = add$2(_parallel, make$46(cause._tag, cause.fiberId));
2498
+ _parallel = add$3(_parallel, make$46(cause._tag, cause.fiberId));
2499
2499
  if (stack.length === 0) return [_parallel, _sequential];
2500
2500
  cause = stack.pop();
2501
2501
  break;
@@ -2721,7 +2721,7 @@ _E: (_) => _ };
2721
2721
  }));
2722
2722
  //#endregion
2723
2723
  //#region node_modules/effect/dist/esm/internal/context.js
2724
- var TagTypeId, ReferenceTypeId, STMSymbolKey, STMTypeId, TagProto, ReferenceProto, makeGenericTag, Tag$1, Reference$1, TypeId$21, ContextProto, makeContext, serviceNotFoundError, isContext$1, isTag$1, isReference, _empty$3, empty$20, make$42, add$1, defaultValueCache, getDefaultValue, unsafeGetReference, unsafeGet$1, get$9, getOption$1, merge$2, mergeAll$4, omit$2;
2724
+ var TagTypeId, ReferenceTypeId, STMSymbolKey, STMTypeId, TagProto, ReferenceProto, makeGenericTag, Tag$1, Reference$1, TypeId$21, ContextProto, makeContext, serviceNotFoundError, isContext$1, isTag$1, isReference, _empty$3, empty$20, make$42, add$2, defaultValueCache, getDefaultValue, unsafeGetReference, unsafeGet$1, get$9, getOption$1, merge$2, mergeAll$4, omit$2;
2725
2725
  var init_context = __esmMin((() => {
2726
2726
  init_Equal();
2727
2727
  init_Function();
@@ -2865,7 +2865,7 @@ var init_context = __esmMin((() => {
2865
2865
  _empty$3 = /*#__PURE__*/ makeContext(/*#__PURE__*/ new Map());
2866
2866
  empty$20 = () => _empty$3;
2867
2867
  make$42 = (tag, service) => makeContext(/* @__PURE__ */ new Map([[tag.key, service]]));
2868
- add$1 = /*#__PURE__*/ dual(3, (self, tag, service) => {
2868
+ add$2 = /*#__PURE__*/ dual(3, (self, tag, service) => {
2869
2869
  const map = new Map(self.unsafeMap);
2870
2870
  map.set(tag.key, service);
2871
2871
  return makeContext(map);
@@ -2912,7 +2912,7 @@ var init_context = __esmMin((() => {
2912
2912
  }));
2913
2913
  //#endregion
2914
2914
  //#region node_modules/effect/dist/esm/Context.js
2915
- var GenericTag, isContext, isTag, empty$19, make$41, add, get$8, unsafeGet, getOption, merge$1, mergeAll$3, omit$1, Tag, Reference;
2915
+ var GenericTag, isContext, isTag, empty$19, make$41, add$1, get$8, unsafeGet, getOption, merge$1, mergeAll$3, omit$1, Tag, Reference;
2916
2916
  var init_Context = __esmMin((() => {
2917
2917
  init_context();
2918
2918
  GenericTag = makeGenericTag;
@@ -2920,7 +2920,7 @@ var init_Context = __esmMin((() => {
2920
2920
  isTag = isTag$1;
2921
2921
  empty$19 = empty$20;
2922
2922
  make$41 = make$42;
2923
- add = add$1;
2923
+ add$1 = add$2;
2924
2924
  get$8 = get$9;
2925
2925
  unsafeGet = unsafeGet$1;
2926
2926
  getOption = getOption$1;
@@ -2932,7 +2932,7 @@ var init_Context = __esmMin((() => {
2932
2932
  }));
2933
2933
  //#endregion
2934
2934
  //#region node_modules/effect/dist/esm/Duration.js
2935
- var TypeId$20, bigint0$2, bigint24, bigint60, bigint1e3, bigint1e6, bigint1e9, DURATION_REGEX, decode$2, zeroValue, infinityValue, DurationProto, make$40, isDuration, isFinite, isZero$1, zero$1, infinity, nanos, micros, millis, seconds, minutes, hours, days, weeks, toMillis, toNanos, unsafeToNanos, toHrTime, match$6, matchWith, Equivalence$3, sum, lessThanOrEqualTo$1, greaterThanOrEqualTo$1, equals$1, parts, format$3;
2935
+ var TypeId$20, bigint0$2, bigint24, bigint60, bigint1e3, bigint1e6, bigint1e9, DURATION_REGEX, decode$2, zeroValue, infinityValue, DurationProto, make$40, isDuration, isFinite, isZero$1, zero$1, infinity, nanos, micros, millis, seconds, minutes, hours, days, weeks, toMillis, toNanos, unsafeToNanos, toHrTime, match$6, matchWith, Equivalence$3, sum$1, lessThanOrEqualTo$1, greaterThanOrEqualTo$1, equals$1, parts, format$3;
2936
2936
  var init_Duration = __esmMin((() => {
2937
2937
  init_Equal();
2938
2938
  init_Function();
@@ -3114,7 +3114,7 @@ var init_Duration = __esmMin((() => {
3114
3114
  onMillis: (self, that) => self === that,
3115
3115
  onNanos: (self, that) => self === that
3116
3116
  });
3117
- sum = /*#__PURE__*/ dual(2, (self, that) => matchWith(self, that, {
3117
+ sum$1 = /*#__PURE__*/ dual(2, (self, that) => matchWith(self, that, {
3118
3118
  onMillis: (self, that) => make$40(self + that),
3119
3119
  onNanos: (self, that) => make$40(self + that)
3120
3120
  }));
@@ -3718,7 +3718,7 @@ var init_hashSetPatch = __esmMin((() => {
3718
3718
  patches = prepend$1(head.first)(prepend$1(head.second)(tail));
3719
3719
  break;
3720
3720
  case "Add":
3721
- set = add$2(head.value)(set);
3721
+ set = add$3(head.value)(set);
3722
3722
  patches = tail;
3723
3723
  break;
3724
3724
  case "Remove":
@@ -5725,7 +5725,7 @@ var init_defaultServices = __esmMin((() => {
5725
5725
  init_console();
5726
5726
  init_random();
5727
5727
  init_tracer();
5728
- liveServices = /*#__PURE__*/ pipe(/*#__PURE__*/ empty$19(), /*#__PURE__*/ add(clockTag, /*#__PURE__*/ make$32()), /*#__PURE__*/ add(consoleTag, defaultConsole), /*#__PURE__*/ add(randomTag, /*#__PURE__*/ make$30(/*#__PURE__*/ Math.random())), /*#__PURE__*/ add(configProviderTag, /*#__PURE__*/ fromEnv()), /*#__PURE__*/ add(tracerTag, nativeTracer));
5728
+ liveServices = /*#__PURE__*/ pipe(/*#__PURE__*/ empty$19(), /*#__PURE__*/ add$1(clockTag, /*#__PURE__*/ make$32()), /*#__PURE__*/ add$1(consoleTag, defaultConsole), /*#__PURE__*/ add$1(randomTag, /*#__PURE__*/ make$30(/*#__PURE__*/ Math.random())), /*#__PURE__*/ add$1(configProviderTag, /*#__PURE__*/ fromEnv()), /*#__PURE__*/ add$1(tracerTag, nativeTracer));
5729
5729
  currentServices = /*#__PURE__*/ globalValue(/*#__PURE__*/ Symbol.for("effect/DefaultServices/currentServices"), () => fiberRefUnsafeMakeContext(liveServices));
5730
5730
  sleep$3 = (duration) => {
5731
5731
  const decodedDuration = decode$2(duration);
@@ -6934,8 +6934,8 @@ var init_core_effect = __esmMin((() => {
6934
6934
  resolve(die$3(e));
6935
6935
  }
6936
6936
  });
6937
- provideService$1 = /*#__PURE__*/ dual(3, (self, tag, service) => contextWithEffect((env) => provideContext$1(self, add(env, tag, service))));
6938
- provideServiceEffect = /*#__PURE__*/ dual(3, (self, tag, effect) => contextWithEffect((env) => flatMap$6(effect, (service) => provideContext$1(self, pipe(env, add(tag, service))))));
6937
+ provideService$1 = /*#__PURE__*/ dual(3, (self, tag, service) => contextWithEffect((env) => provideContext$1(self, add$1(env, tag, service))));
6938
+ provideServiceEffect = /*#__PURE__*/ dual(3, (self, tag, effect) => contextWithEffect((env) => flatMap$6(effect, (service) => provideContext$1(self, pipe(env, add$1(tag, service))))));
6939
6939
  sandbox$1 = (self) => matchCauseEffect$2(self, {
6940
6940
  onFailure: fail$12,
6941
6941
  onSuccess: succeed$8
@@ -11093,7 +11093,7 @@ var init_schedule = __esmMin((() => {
11093
11093
  };
11094
11094
  makeWithState = (initial, step) => new ScheduleImpl(initial, step);
11095
11095
  addDelay = /*#__PURE__*/ dual(2, (self, f) => addDelayEffect(self, (out) => sync$2(() => f(out))));
11096
- addDelayEffect = /*#__PURE__*/ dual(2, (self, f) => modifyDelayEffect(self, (out, duration) => map$8(f(out), (delay) => sum(duration, decode$2(delay)))));
11096
+ addDelayEffect = /*#__PURE__*/ dual(2, (self, f) => modifyDelayEffect(self, (out, duration) => map$8(f(out), (delay) => sum$1(duration, decode$2(delay)))));
11097
11097
  check$1 = /*#__PURE__*/ dual(2, (self, test) => checkEffect(self, (input, out) => sync$2(() => test(input, out))));
11098
11098
  checkEffect = /*#__PURE__*/ dual(2, (self, test) => makeWithState(self.initial, (now, input, state) => flatMap$6(self.step(now, input, state), ([state, out, decision]) => {
11099
11099
  if (isDone(decision)) return succeed$8([
@@ -13618,7 +13618,7 @@ var init_rcRef = __esmMin((() => {
13618
13618
  case "Acquired":
13619
13619
  self.state.refCount++;
13620
13620
  return self.state.fiber ? as$1(interruptFiber(self.state.fiber), self.state) : succeed$8(self.state);
13621
- case "Empty": return scopeMake().pipe(bindTo("scope"), bind("value", ({ scope }) => restore(fiberRefLocally(self.acquire, currentContext$1, add(self.context, scopeTag, scope)))), map$8(({ scope, value }) => {
13621
+ case "Empty": return scopeMake().pipe(bindTo("scope"), bind("value", ({ scope }) => restore(fiberRefLocally(self.acquire, currentContext$1, add$1(self.context, scopeTag, scope)))), map$8(({ scope, value }) => {
13622
13622
  const state = {
13623
13623
  _tag: "Acquired",
13624
13624
  value,
@@ -14288,7 +14288,7 @@ function getBrands(ast) {
14288
14288
  onSome: (brands) => brands.map((brand) => ` & Brand<${formatUnknown(brand)}>`).join("")
14289
14289
  });
14290
14290
  }
14291
- var TypeConstructorAnnotationId, BrandAnnotationId, SchemaIdAnnotationId, MessageAnnotationId, MissingMessageAnnotationId, IdentifierAnnotationId, TitleAnnotationId, AutoTitleAnnotationId, DescriptionAnnotationId, ExamplesAnnotationId, DefaultAnnotationId, JSONSchemaAnnotationId, ArbitraryAnnotationId, PrettyAnnotationId, EquivalenceAnnotationId, DocumentationAnnotationId, ConcurrencyAnnotationId, BatchingAnnotationId, ParseIssueTitleAnnotationId, ParseOptionsAnnotationId, DecodingFallbackAnnotationId, SurrogateAnnotationId, StableFilterAnnotationId, getAnnotation, getBrandAnnotation, getMessageAnnotation, getMissingMessageAnnotation, getTitleAnnotation, getAutoTitleAnnotation, getIdentifierAnnotation, getDescriptionAnnotation, getConcurrencyAnnotation, getBatchingAnnotation, getParseIssueTitleAnnotation$1, getParseOptionsAnnotation, getDecodingFallbackAnnotation, getSurrogateAnnotation, getStableFilterAnnotation, hasStableFilter, JSONIdentifierAnnotationId, getJSONIdentifierAnnotation, getJSONIdentifier, Declaration, createASTGuard, Literal$1, isLiteral, $null, UniqueSymbol, UndefinedKeyword, undefinedKeyword, NeverKeyword, neverKeyword, UnknownKeyword, unknownKeyword, AnyKeyword, anyKeyword, StringKeyword, stringKeyword, isStringKeyword, NumberKeyword, numberKeyword, isNumberKeyword, BooleanKeyword, booleanKeyword, isBooleanKeyword, BigIntKeyword, bigIntKeyword, SymbolKeyword, symbolKeyword, isSymbolKeyword, Type$1, OptionalType, getRestASTs, TupleType, formatTuple, PropertySignature, isParameter, IndexSignature, TypeLiteral, formatIndexSignatures, formatTypeLiteral, isTypeLiteral, sortCandidates, literalMap, flatten$2, unify, Union$1, mapMembers, isMembers, isUnion, toJSONMemoMap, Suspend, Refinement$1, isRefinement$1, defaultParseOption, Transformation$1, isTransformation$1, FinalTransformation, createTransformationGuard, ComposeTransformation, composeTransformation, PropertySignatureTransformation$1, TypeLiteralTransformation, isTypeLiteralTransformation, annotations, STRING_KEYWORD_PATTERN, NUMBER_KEYWORD_PATTERN, getTemplateLiteralSpanTypePattern, handleTemplateLiteralSpanTypeParens, getTemplateLiteralPattern, getTemplateLiteralRegExp, record$1, pickAnnotations, omitAnnotations, preserveTransformationAnnotations, typeAST, getTransformationFrom, encodedAST_, encodedAST, toJSONAnnotations, getEncodedParameter, formatKeyword, getOrElseExpected, getExpected;
14291
+ var TypeConstructorAnnotationId, BrandAnnotationId, SchemaIdAnnotationId, MessageAnnotationId, MissingMessageAnnotationId, IdentifierAnnotationId, TitleAnnotationId, AutoTitleAnnotationId, DescriptionAnnotationId, ExamplesAnnotationId, DefaultAnnotationId, JSONSchemaAnnotationId, ArbitraryAnnotationId, PrettyAnnotationId, EquivalenceAnnotationId, DocumentationAnnotationId, ConcurrencyAnnotationId, BatchingAnnotationId, ParseIssueTitleAnnotationId, ParseOptionsAnnotationId, DecodingFallbackAnnotationId, SurrogateAnnotationId, StableFilterAnnotationId, getAnnotation, getBrandAnnotation, getMessageAnnotation, getMissingMessageAnnotation, getTitleAnnotation, getAutoTitleAnnotation, getIdentifierAnnotation, getDescriptionAnnotation, getConcurrencyAnnotation, getBatchingAnnotation, getParseIssueTitleAnnotation$1, getParseOptionsAnnotation, getDecodingFallbackAnnotation, getSurrogateAnnotation, getStableFilterAnnotation, hasStableFilter, JSONIdentifierAnnotationId, getJSONIdentifierAnnotation, getJSONIdentifier, Declaration, createASTGuard, Literal$1, isLiteral, $null, UniqueSymbol, UndefinedKeyword, undefinedKeyword, NeverKeyword, neverKeyword, UnknownKeyword, unknownKeyword, AnyKeyword, anyKeyword, StringKeyword, stringKeyword, isStringKeyword, NumberKeyword, numberKeyword, isNumberKeyword, BooleanKeyword, booleanKeyword, isBooleanKeyword, BigIntKeyword, bigIntKeyword, SymbolKeyword, symbolKeyword, isSymbolKeyword, Type$1, OptionalType, getRestASTs, TupleType, formatTuple, PropertySignature, isParameter, IndexSignature, TypeLiteral, formatIndexSignatures, formatTypeLiteral, isTypeLiteral, sortCandidates, literalMap, flatten$2, unify, Union$1, mapMembers, isMembers, isUnion, toJSONMemoMap, Suspend, Refinement$1, isRefinement$1, defaultParseOption, Transformation$1, isTransformation$1, FinalTransformation, createTransformationGuard, ComposeTransformation, composeTransformation, PropertySignatureTransformation$1, TypeLiteralTransformation, isTypeLiteralTransformation, annotations, STRING_KEYWORD_PATTERN, NUMBER_KEYWORD_PATTERN, getTemplateLiteralSpanTypePattern, handleTemplateLiteralSpanTypeParens, getTemplateLiteralPattern, getTemplateLiteralRegExp, record$2, pickAnnotations, omitAnnotations, preserveTransformationAnnotations, typeAST, getTransformationFrom, encodedAST_, encodedAST, toJSONAnnotations, getEncodedParameter, formatKeyword, getOrElseExpected, getExpected;
14292
14292
  var init_SchemaAST = __esmMin((() => {
14293
14293
  init_Array();
14294
14294
  init_Function();
@@ -15252,7 +15252,7 @@ var init_SchemaAST = __esmMin((() => {
15252
15252
  return pattern;
15253
15253
  };
15254
15254
  getTemplateLiteralRegExp = (ast) => new RegExp(`^${getTemplateLiteralPattern(ast, false, true)}$`);
15255
- record$1 = (key, value) => {
15255
+ record$2 = (key, value) => {
15256
15256
  const propertySignatures = [];
15257
15257
  const indexSignatures = [];
15258
15258
  const go = (key) => {
@@ -16937,7 +16937,7 @@ var init_Schema = __esmMin((() => {
16937
16937
  const issFrom = [];
16938
16938
  const issTo = [];
16939
16939
  for (const r of records) {
16940
- const { indexSignatures, propertySignatures } = record$1(r.key.ast, r.value.ast);
16940
+ const { indexSignatures, propertySignatures } = record$2(r.key.ast, r.value.ast);
16941
16941
  propertySignatures.forEach((ps) => {
16942
16942
  from.push(ps);
16943
16943
  to.push(new PropertySignature(ps.name, typeAST(ps.type), ps.isOptional, ps.isReadonly, ps.annotations));
@@ -16952,7 +16952,7 @@ var init_Schema = __esmMin((() => {
16952
16952
  }
16953
16953
  const iss = [];
16954
16954
  for (const r of records) {
16955
- const { indexSignatures, propertySignatures } = record$1(r.key.ast, r.value.ast);
16955
+ const { indexSignatures, propertySignatures } = record$2(r.key.ast, r.value.ast);
16956
16956
  propertySignatures.forEach((ps) => pss.push(ps));
16957
16957
  indexSignatures.forEach((is) => iss.push(is));
16958
16958
  }
@@ -18875,7 +18875,7 @@ var init_Runtime = __esmMin((() => {
18875
18875
  return updateAs(refs, {
18876
18876
  fiberId,
18877
18877
  fiberRef: currentLoggers,
18878
- value: loggers.pipe(remove$2(defaultLogger), add$2(prettyLoggerDefault))
18878
+ value: loggers.pipe(remove$2(defaultLogger), add$3(prettyLoggerDefault))
18879
18879
  });
18880
18880
  };
18881
18881
  makeRunMain = (f) => dual((args) => isEffect(args[0]), (effect, options) => {
@@ -37767,7 +37767,7 @@ var init_Slices = __esmMin((() => {
37767
37767
  }));
37768
37768
  //#endregion
37769
37769
  //#region src/wire/ContextLimit.ts
37770
- var DEFAULT_CONTEXT_LIMIT, DEFAULT_WINDOW, LONG_WINDOW, contextWindowFor, parseContextWindow, CONTEXT_STOP_FILE_ENV, contextShapeFault, contextLimitFault, record, count, usageTokens, transcriptTokens, CONTEXT_LIMIT_MARKER, percent, contextHook, hookOutput;
37770
+ var DEFAULT_CONTEXT_LIMIT, DEFAULT_WINDOW, LONG_WINDOW, contextWindowFor, parseContextWindow, CONTEXT_STOP_FILE_ENV, contextShapeFault, contextLimitFault, record$1, count, usageTokens, transcriptTokens, CONTEXT_LIMIT_MARKER, percent, contextHook, hookOutput;
37771
37771
  var init_ContextLimit = __esmMin((() => {
37772
37772
  DEFAULT_CONTEXT_LIMIT = {
37773
37773
  soft: .6,
@@ -37800,10 +37800,10 @@ var init_ContextLimit = __esmMin((() => {
37800
37800
  const hard = shares.hard ?? DEFAULT_CONTEXT_LIMIT.hard;
37801
37801
  return soft < hard ? void 0 : `context.soft (${soft}) must be below context.hard (${hard})`;
37802
37802
  };
37803
- record = (value) => typeof value === "object" && value !== null ? value : void 0;
37803
+ record$1 = (value) => typeof value === "object" && value !== null ? value : void 0;
37804
37804
  count = (value) => typeof value === "number" && value > 0 ? value : 0;
37805
37805
  usageTokens = (usage) => {
37806
- const u = record(usage);
37806
+ const u = record$1(usage);
37807
37807
  if (u === void 0) return void 0;
37808
37808
  return count(u["input_tokens"]) + count(u["cache_read_input_tokens"]) + count(u["cache_creation_input_tokens"]);
37809
37809
  };
@@ -37818,8 +37818,8 @@ var init_ContextLimit = __esmMin((() => {
37818
37818
  } catch {
37819
37819
  continue;
37820
37820
  }
37821
- if (record(entry)?.["type"] !== "assistant") continue;
37822
- const tokens = usageTokens(record(record(entry)?.["message"])?.["usage"]);
37821
+ if (record$1(entry)?.["type"] !== "assistant") continue;
37822
+ const tokens = usageTokens(record$1(record$1(entry)?.["message"])?.["usage"]);
37823
37823
  if (tokens !== void 0) return tokens;
37824
37824
  }
37825
37825
  };
@@ -37839,7 +37839,7 @@ var init_ContextLimit = __esmMin((() => {
37839
37839
  };
37840
37840
  if (tokens >= limit.soft * window) return {
37841
37841
  kind: "soft",
37842
- reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next.`
37842
+ reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next. Where your instructions name a file for that note, write it there too.`
37843
37843
  };
37844
37844
  };
37845
37845
  hookOutput = (decision) => decision.kind === "soft" ? {
@@ -41263,6 +41263,13 @@ const writeSelection = (out, fields, path) => gen(function* () {
41263
41263
  if (selection.kind === "value") out.write(`${selection.text}\n`);
41264
41264
  else if (selection.kind === "unknown") return yield* fail$7(new SelectorUsageError(`gtd: unknown --json selector "${selection.path}" — see \`gtd --help\``));
41265
41265
  });
41266
+ /** Writes `document` per `json` (bare → whole, `=path` → one value); returns false for `off`. */
41267
+ const writeJson = (json, out, document) => gen(function* () {
41268
+ if (json.kind === "off") return false;
41269
+ if (json.kind === "document") out.write(`${JSON.stringify(document)}\n`);
41270
+ else yield* writeSelection(out, document, json.path);
41271
+ return true;
41272
+ });
41266
41273
  //#endregion
41267
41274
  //#region src/cli/Strays.ts
41268
41275
  init_esm();
@@ -41324,13 +41331,6 @@ const resolveHistoryRef = (arg, entries) => {
41324
41331
  return fail$7(/* @__PURE__ */ new Error(`gtd history: no history ref matches "${arg}"`));
41325
41332
  };
41326
41333
  const seven = (hash) => hash.slice(0, 7);
41327
- /** Writes `document` per `json` (bare → whole, `=path` → one value); returns false for `off`. */
41328
- const writeJson = (json, out, document) => gen(function* () {
41329
- if (json.kind === "off") return false;
41330
- if (json.kind === "document") out.write(`${JSON.stringify(document)}\n`);
41331
- else yield* writeSelection(out, document, json.path);
41332
- return true;
41333
- });
41334
41334
  const runHistoryListCommand = (json, out) => gen(function* () {
41335
41335
  const entries = yield* historyEntries;
41336
41336
  if (yield* writeJson(json, out, entries)) return;
@@ -41343,13 +41343,12 @@ const runHistoryListCommand = (json, out) => gen(function* () {
41343
41343
  const runHistoryShowCommand = (ref, json, out) => gen(function* () {
41344
41344
  const entry = yield* resolveHistoryRef(ref, yield* historyEntries);
41345
41345
  const trail = yield* historyTrail(entry.tip);
41346
- const document = {
41346
+ if (yield* writeJson(json, out, {
41347
41347
  ref: entry.ref,
41348
41348
  entry: entry.entry,
41349
41349
  branch: entry.branch,
41350
41350
  ...trail
41351
- };
41352
- if (yield* writeJson(json, out, document)) return;
41351
+ })) return;
41353
41352
  if (trail.versionWarning !== void 0) yield* (yield* Narrator).warn(trail.versionWarning);
41354
41353
  const lines = [`${entry.ref} (branch ${entry.branch ?? "-"}, tip ${seven(entry.tip)})`];
41355
41354
  for (const step of trail.steps) {
@@ -41365,6 +41364,203 @@ const runHistoryFetchCommand = (remote, out) => sync$1(() => {
41365
41364
  out.write(`${combinedScript(fetchHistoryRefs(remote), "")}\n`);
41366
41365
  });
41367
41366
  //#endregion
41367
+ //#region src/cli/Metrics.ts
41368
+ init_esm();
41369
+ init_wire();
41370
+ const QUALITY = ".gtd/QUALITY.md";
41371
+ const LENS = /^((?:.*\.)?quality\.[^.]+)\.reviewing$/;
41372
+ const CONTINUE = /(^|\.)continue\./;
41373
+ const inSeam = (step) => step.startsWith("seam.");
41374
+ const phaseOf = (step) => {
41375
+ const scope = step.split(".")[0];
41376
+ if (inSeam(step) && step.endsWith(".naive")) return "naive";
41377
+ if (step === "seam.note" || scope === "refactor") return "refactor";
41378
+ if (scope === "implement") return "implement";
41379
+ return "other";
41380
+ };
41381
+ const round = (n, places = 6) => {
41382
+ const f = 10 ** places;
41383
+ return Math.round(n * f) / f;
41384
+ };
41385
+ const record = () => Object.create(null);
41386
+ const add = (into, key, n) => {
41387
+ into[key] = (into[key] ?? 0) + n;
41388
+ };
41389
+ const roundAll = (record) => Object.fromEntries(Object.entries(record).map(([k, v]) => [k, round(v)]));
41390
+ const emptyTally = () => ({
41391
+ slices: {
41392
+ decided: 0,
41393
+ landed: 0,
41394
+ rebuilt: 0,
41395
+ refactored: 0
41396
+ },
41397
+ continuations: record(),
41398
+ byModel: record(),
41399
+ byPhase: {
41400
+ naive: 0,
41401
+ refactor: 0,
41402
+ implement: 0,
41403
+ other: 0
41404
+ },
41405
+ doubleWork: {
41406
+ naive: 0,
41407
+ rebuild: 0
41408
+ },
41409
+ byLens: record()
41410
+ });
41411
+ const sum = (record) => Object.values(record).reduce((a, b) => a + b, 0);
41412
+ const finish = (t) => ({
41413
+ slices: t.slices,
41414
+ refactorFirstRate: t.slices.decided === 0 ? null : round(t.slices.rebuilt / t.slices.decided, 3),
41415
+ continuations: t.continuations,
41416
+ cost: {
41417
+ total: round(sum(t.byModel)),
41418
+ byModel: roundAll(t.byModel),
41419
+ byPhase: roundAll(t.byPhase),
41420
+ doubleWork: {
41421
+ naive: round(t.doubleWork.naive),
41422
+ rebuild: round(t.doubleWork.rebuild),
41423
+ total: round(t.doubleWork.naive + t.doubleWork.rebuild)
41424
+ }
41425
+ },
41426
+ findings: {
41427
+ total: sum(t.byLens),
41428
+ byLens: t.byLens
41429
+ }
41430
+ });
41431
+ const tallyCost = (t, open, costs, phase) => {
41432
+ for (const { cost, model } of costs) {
41433
+ add(t.byModel, model ?? "unspecified", cost);
41434
+ t.byPhase[phase] += cost;
41435
+ if (phase === "naive") open.naive += cost;
41436
+ if (phase === "implement" && open.rebuilding) t.doubleWork.rebuild += cost;
41437
+ }
41438
+ };
41439
+ /** A slice is decided where its turns leave the seam: for `implement.applying` the naive pass landed — unless it fails to apply and is built afresh — anywhere else it is rebuilt. */
41440
+ const tallyDecision = (t, open, at, to) => {
41441
+ if (at === "implement.closing") open.rebuilding = false;
41442
+ if (open.applying !== void 0 && at === "implement.applying") {
41443
+ const naive = open.applying;
41444
+ open.applying = void 0;
41445
+ if (to !== "implement.building") return;
41446
+ t.slices.landed--;
41447
+ rebuild(t, open, naive);
41448
+ return;
41449
+ }
41450
+ if (!inSeam(at) || inSeam(to)) return;
41451
+ t.slices.decided++;
41452
+ const naive = open.naive;
41453
+ open.naive = 0;
41454
+ if (to === "implement.applying") {
41455
+ open.applying = naive;
41456
+ open.rebuilding = false;
41457
+ t.slices.landed++;
41458
+ return;
41459
+ }
41460
+ rebuild(t, open, naive);
41461
+ if (at === "seam.note") t.slices.refactored++;
41462
+ };
41463
+ const rebuild = (t, open, naive) => {
41464
+ open.rebuilding = true;
41465
+ t.slices.rebuilt++;
41466
+ t.doubleWork.naive += naive;
41467
+ };
41468
+ /** Oldest first; a commit gtd did not write is skipped. */
41469
+ const processMetrics = (commits) => {
41470
+ const t = emptyTally();
41471
+ const open = {
41472
+ naive: 0,
41473
+ rebuilding: false,
41474
+ applying: void 0
41475
+ };
41476
+ for (const commit of commits) {
41477
+ const message = parseCommitMessage(commit.message);
41478
+ const subject = message.parsed;
41479
+ if (subject === void 0) continue;
41480
+ const at = subject.from ?? subject.to;
41481
+ tallyCost(t, open, message.cost, phaseOf(at));
41482
+ if (subject.actor === "agent" && CONTINUE.test(at)) add(t.continuations, at.replace(CONTINUE, "$1"), 1);
41483
+ const lens = LENS.exec(at)?.[1];
41484
+ if (lens !== void 0 && commit.findings > 0) add(t.byLens, lens, commit.findings);
41485
+ tallyDecision(t, open, at, subject.to);
41486
+ }
41487
+ return finish(t);
41488
+ };
41489
+ const totalMetrics = (all) => {
41490
+ const t = emptyTally();
41491
+ for (const m of all) {
41492
+ for (const key of Object.keys(t.slices)) t.slices[key] += m.slices[key];
41493
+ for (const [k, v] of Object.entries(m.continuations)) add(t.continuations, k, v);
41494
+ for (const [k, v] of Object.entries(m.cost.byModel)) add(t.byModel, k, v);
41495
+ for (const key of Object.keys(t.byPhase)) t.byPhase[key] += m.cost.byPhase[key];
41496
+ t.doubleWork.naive += m.cost.doubleWork.naive;
41497
+ t.doubleWork.rebuild += m.cost.doubleWork.rebuild;
41498
+ for (const [k, v] of Object.entries(m.findings.byLens)) add(t.byLens, k, v);
41499
+ }
41500
+ return {
41501
+ processes: all.length,
41502
+ ...finish(t)
41503
+ };
41504
+ };
41505
+ const chunks = (content) => content === void 0 ? 0 : (content.match(/^## /gm) ?? []).length;
41506
+ const readProcessMetrics = (entry) => gen(function* () {
41507
+ const git = yield* GitService;
41508
+ const base = getOrUndefined(yield* git.readRefOption(`${entry.entry}^`));
41509
+ const commits = yield* git.commitHistory(base, entry.tip);
41510
+ const quality = (hash) => git.readFileAtRef(hash, QUALITY).pipe(map$4((content) => content), orElseSucceed(() => void 0));
41511
+ let count = chunks(base === void 0 ? void 0 : yield* quality(base));
41512
+ const read = [];
41513
+ for (const { hash, message, touched } of commits) {
41514
+ const before = count;
41515
+ if (touched.includes(QUALITY)) count = chunks(yield* quality(hash));
41516
+ read.push({
41517
+ message,
41518
+ findings: Math.max(0, count - before)
41519
+ });
41520
+ }
41521
+ return {
41522
+ workflow: (commits[0] === void 0 ? void 0 : parseCommitMessage(commits[0].message).workflow) ?? null,
41523
+ ...processMetrics(read)
41524
+ };
41525
+ });
41526
+ const printable = (s) => s.replace(/[\x00-\x1f\x7f-\x9f\u2028\u2029]/g, "?");
41527
+ const listed = (record) => Object.entries(record).map(([k, v]) => `${printable(k)} ${v}`).join(", ");
41528
+ const line = (label, m) => {
41529
+ const { slices, cost } = m;
41530
+ const percent = m.refactorFirstRate === null ? "-" : `${Math.round(m.refactorFirstRate * 100)}%`;
41531
+ const continued = sum(m.continuations);
41532
+ return [
41533
+ `${label}: ${slices.decided} slices, ${slices.rebuilt} rebuilt (refactor-first ${percent}), ${slices.refactored} refactored`,
41534
+ `${continued} continuations${continued > 0 ? ` (${listed(m.continuations)})` : ""}`,
41535
+ `cost ${cost.total} (${listed(cost.byPhase)}; by model ${listed(cost.byModel) || "-"}), double work ${cost.doubleWork.total}`,
41536
+ `${m.findings.total} findings${m.findings.total > 0 ? ` (${listed(m.findings.byLens)})` : ""}`
41537
+ ].join("; ");
41538
+ };
41539
+ const runHistoryMetricsCommand = (refs, json, out) => gen(function* () {
41540
+ const entries = yield* historyEntries;
41541
+ const chosen = refs.length === 0 ? entries : (yield* forEach$2(refs, (ref) => resolveHistoryRef(ref, entries).pipe(map$4((hit) => hit.branch === ref ? entries.filter((e) => e.branch === ref) : [hit])))).flat();
41542
+ const unique = chosen.filter((e, i) => chosen.findIndex((o) => o.ref === e.ref) === i);
41543
+ const processes = yield* forEach$2(unique, (e) => readProcessMetrics(e).pipe(map$4((metrics) => ({
41544
+ ref: e.ref,
41545
+ entry: e.entry,
41546
+ branch: e.branch,
41547
+ tip: e.tip,
41548
+ ...metrics
41549
+ }))), { concurrency: 4 });
41550
+ const document = {
41551
+ processes,
41552
+ total: totalMetrics(processes)
41553
+ };
41554
+ if (yield* writeJson(json, out, document)) return;
41555
+ if (processes.length === 0) {
41556
+ out.write("no history refs; run gtd history fetch | sh to pull them\n");
41557
+ return;
41558
+ }
41559
+ const lines = processes.map((p) => line(`${p.entry.slice(0, 7)} ${printable(p.branch ?? "-")}${p.workflow === null ? "" : ` (${printable(p.workflow)})`}`, p));
41560
+ lines.push(line(`total (${processes.length} processes)`, document.total));
41561
+ out.write(`${lines.join("\n")}\n`);
41562
+ });
41563
+ //#endregion
41368
41564
  //#region src/cli/Program.ts
41369
41565
  init_esm();
41370
41566
  init_wire();
@@ -42022,6 +42218,7 @@ const dispatchVoidCommand = (command, json, out) => {
42022
42218
  case "judgeRun": return runJudgeRunCommand(command, out);
42023
42219
  case "historyList": return runHistoryListCommand(json, out);
42024
42220
  case "historyShow": return runHistoryShowCommand(command.ref, json, out);
42221
+ case "historyMetrics": return runHistoryMetricsCommand(command.refs, json, out);
42025
42222
  case "historyFetch": return runHistoryFetchCommand(command.remote, out);
42026
42223
  }
42027
42224
  };
@@ -42062,18 +42259,30 @@ const share = (raw, flag) => {
42062
42259
  const n = Number(raw);
42063
42260
  return raw.trim() !== "" && n > 0 && n <= 1 ? right(n) : left(`gtd: ${flag} must be a share of the context window in (0, 1] — got "${raw}"`);
42064
42261
  };
42262
+ const JSON_KINDS = /* @__PURE__ */ new Set([
42263
+ "next",
42264
+ "land",
42265
+ "judge",
42266
+ "judgeAnswer",
42267
+ "doors",
42268
+ "slices",
42269
+ "historyList",
42270
+ "historyShow",
42271
+ "historyMetrics",
42272
+ "strays"
42273
+ ]);
42065
42274
  const FLAGS = [
42066
42275
  {
42067
42276
  name: "--json",
42068
42277
  arity: "optional",
42069
42278
  repeatable: false,
42070
- scope: (kind) => kind === "next" || kind === "land" || kind === "judge" || kind === "judgeAnswer" || kind === "doors" || kind === "slices" || kind === "historyList" || kind === "historyShow" || kind === "strays",
42279
+ scope: (kind) => JSON_KINDS.has(kind),
42071
42280
  decode: ([raw]) => right(raw ?? ""),
42072
- scopeError: "gtd: --json is only valid for `gtd next`/`gtd land`/`gtd judge`/`gtd judge answer`/`gtd doors`/`gtd slices`/`gtd history list`/`gtd history show`/`gtd strays` — every other command prints plain text; see `gtd install` for the driver protocol briefing",
42281
+ scopeError: "gtd: --json is only valid for `gtd next`/`gtd land`/`gtd judge`/`gtd judge answer`/`gtd doors`/`gtd slices`/`gtd history list`/`gtd history show`/`gtd history metrics`/`gtd strays` — every other command prints plain text; see `gtd install` for the driver protocol briefing",
42073
42282
  valueHint: "<path>",
42074
42283
  help: [
42075
42284
  "(gtd next/gtd land/gtd judge/gtd judge answer/gtd doors/gtd slices/gtd history",
42076
- "list/gtd history show/gtd strays only) output structured JSON. Bare --json prints the whole document;",
42285
+ "list/gtd history show/gtd history metrics/gtd strays only) output structured JSON. Bare --json prints the whole document;",
42077
42286
  "--json=<path> (a dotted key path into that document, e.g.",
42078
42287
  "kind, content, session.id) prints just that value: a",
42079
42288
  "scalar raw and unquoted, a boolean as true/false, a list",
@@ -42723,6 +42932,25 @@ const COMMAND_ROWS = [
42723
42932
  "prints the trail as one document; writes nothing"
42724
42933
  ]
42725
42934
  },
42935
+ {
42936
+ token: "history metrics",
42937
+ kind: "historyMetrics",
42938
+ arity: {
42939
+ name: "ref",
42940
+ many: true
42941
+ },
42942
+ details: [
42943
+ "Report how the kept processes went: slices whose naive pass",
42944
+ "landed or was rebuilt (the refactor-first rate), continuations",
42945
+ "per phase, Gtd-Cost by model and phase with the double work of",
42946
+ "a rebuild, and quality-lap findings per lens — per process and",
42947
+ "in total. Each <ref> is read as by history show, but a branch",
42948
+ "name means every process kept from it; none means every ref.",
42949
+ "Reads commit subjects and trailers, never replays, so a",
42950
+ "changed config is no refusal. --json prints { processes, total",
42951
+ "} as one document; writes nothing"
42952
+ ]
42953
+ },
42726
42954
  {
42727
42955
  token: "history fetch",
42728
42956
  kind: "historyFetch",
@@ -42754,7 +42982,7 @@ const flagHeader = (row) => {
42754
42982
  };
42755
42983
  const renderHelp = () => {
42756
42984
  const commandBlocks = COMMAND_ROWS.map((row) => {
42757
- const header = row.arity === "none" ? row.token : "names" in row.arity ? `${row.token} <${row.arity.names[0]}> <${row.arity.names[1]}>` : "variadic" in row.arity ? `${row.token} <${row.arity.name}> [${row.arity.variadic}...]` : "optional" in row.arity ? `${row.token} [${row.arity.name}]` : `${row.token} <${row.arity.name}>`;
42985
+ const header = row.arity === "none" ? row.token : "names" in row.arity ? `${row.token} <${row.arity.names[0]}> <${row.arity.names[1]}>` : "variadic" in row.arity ? `${row.token} <${row.arity.name}> [${row.arity.variadic}...]` : "optional" in row.arity ? `${row.token} [${row.arity.name}]` : "many" in row.arity ? `${row.token} [${row.arity.name}...]` : `${row.token} <${row.arity.name}>`;
42758
42986
  return renderBlock(header, row.details);
42759
42987
  });
42760
42988
  return `Usage: gtd [command] [options]\n\nCommands:\n${[
@@ -42862,12 +43090,14 @@ const conflictViolation = (present) => {
42862
43090
  for (const other of row.conflicts ?? []) if (present.has(other)) return `gtd: ${row.name} and ${other} are mutually exclusive`;
42863
43091
  }
42864
43092
  };
43093
+ const tooMany = (cmd, rest, expected, max) => rest.length > max ? `gtd ${cmd}: too many arguments — expected ${expected}, got: ${rest.join(", ")}` : void 0;
42865
43094
  const arityError = (cmd, rest, arity) => {
42866
- if (arity === "none") return rest.length > 0 ? `gtd ${cmd}: too many arguments — expected none, got: ${rest.join(", ")}` : void 0;
43095
+ if (arity === "none") return tooMany(cmd, rest, "none", 0);
42867
43096
  if ("names" in arity) return pairArityError(cmd, rest, arity.names);
42868
- if ("optional" in arity) return rest.length > 1 ? `gtd ${cmd}: too many arguments — expected at most one ${arity.name}, got: ${rest.join(", ")}` : void 0;
43097
+ if ("many" in arity) return void 0;
43098
+ if ("optional" in arity) return tooMany(cmd, rest, `at most one ${arity.name}`, 1);
42869
43099
  if (rest.length === 0) return `gtd ${cmd}: missing ${arity.name} argument`;
42870
- if (!("variadic" in arity) && rest.length > 1) return `gtd ${cmd}: too many arguments — expected one ${arity.name}, got: ${rest.join(", ")}`;
43100
+ return "variadic" in arity ? void 0 : tooMany(cmd, rest, `one ${arity.name}`, 1);
42871
43101
  };
42872
43102
  const pairArityError = (cmd, rest, [first, second]) => {
42873
43103
  if (rest.length === 0) return `gtd ${cmd}: missing ${first} and ${second} arguments`;
@@ -42918,7 +43148,7 @@ const parseArgv = (argv) => {
42918
43148
  };
42919
43149
  const isHistory = first === "history";
42920
43150
  const row = first === void 0 ? void 0 : commandByToken(isHistory ? `history ${positionals[1] ?? ""}` : first);
42921
- if (isHistory && row === void 0) return usagePlan("gtd history: expected a subcommand — list, show <ref> or fetch [remote]", jsonSeen);
43151
+ if (isHistory && row === void 0) return usagePlan("gtd history: expected a subcommand — list, show <ref>, metrics [ref...] or fetch [remote]", jsonSeen);
42922
43152
  const judgeAnswer = row?.kind === "judge" && positionals[1] === "answer";
42923
43153
  const selectsStart = workflowPresent && first === void 0;
42924
43154
  const judgeRun = row?.kind === "judge" && positionals[1] === "run";
@@ -43051,6 +43281,15 @@ const parseArgv = (argv) => {
43051
43281
  json,
43052
43282
  verbose
43053
43283
  };
43284
+ if (kind === "historyMetrics") return {
43285
+ kind: "command",
43286
+ command: {
43287
+ kind: "historyMetrics",
43288
+ refs: restPositionals
43289
+ },
43290
+ json,
43291
+ verbose
43292
+ };
43054
43293
  if (kind === "historyFetch") return {
43055
43294
  kind: "command",
43056
43295
  command: {