@pmelab/gtd 36.0.0 → 38.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +30 -9
  3. package/claude/hooks/context.ts +66 -0
  4. package/claude/hooks/drive.ts +3 -0
  5. package/claude/hooks/register.tsx +69 -6
  6. package/dist/chunks/{reserved-BAv71I4i.mjs → reserved-sfMdy7v7.mjs} +83 -22
  7. package/dist/chunks/{tail-kar1zhOb.mjs → tail-Cgca5Gp-.mjs} +1 -1
  8. package/dist/chunks/{wire-D3Rc5r22.mjs → wire-CSsa3Wxd.mjs} +117 -2
  9. package/dist/gtd.bundle.mjs +498 -56
  10. package/dist/testkit.mjs +115 -3
  11. package/dist/wire.mjs +2 -2
  12. package/dist/workflows/cleanup.mjs +2 -2
  13. package/dist/workflows/feature.mjs +277 -58
  14. package/dist/workflows/fix.mjs +2 -2
  15. package/dist/workflows/review.mjs +2 -2
  16. package/dist/workflows/rollout.mjs +1 -1
  17. package/dist/workflows.mjs +355 -75
  18. package/package.json +1 -1
  19. package/src/cli/Cli.test.ts +10 -3
  20. package/src/cli/Cli.ts +76 -1
  21. package/src/cli/Program.test.ts +1 -0
  22. package/src/cli/Program.ts +28 -0
  23. package/src/cli/ToolCommands.ts +3 -0
  24. package/src/edge/Edge.ts +11 -0
  25. package/src/flows/runtime.ts +11 -0
  26. package/src/replay/Replay.ts +51 -2
  27. package/src/testkit/Layers.ts +1 -0
  28. package/src/testkit/steps.ts +35 -0
  29. package/src/wire/BeatDocument.ts +12 -2
  30. package/src/wire/BeatStatus.ts +3 -0
  31. package/src/wire/ContextLimit.fixture.ts +30 -0
  32. package/src/wire/ContextLimit.test.ts +96 -0
  33. package/src/wire/ContextLimit.ts +169 -0
  34. package/src/wire/index.ts +1 -0
  35. package/src/wire/types.ts +7 -0
  36. package/src/workflow/Workflow.ts +9 -1
  37. package/src/workflows/feature/context-limit.feature +37 -0
  38. package/src/workflows/feature/coverage.ts +22 -8
  39. package/src/workflows/feature/criteria.test.ts +17 -1
  40. package/src/workflows/feature/criteria.ts +26 -3
  41. package/src/workflows/feature/feature.ts +69 -16
  42. package/src/workflows/feature/index.ts +1 -0
  43. package/src/workflows/feature/refactor-absorbs.feature +12 -5
  44. package/src/workflows/feature/refactor-first.feature +11 -2
  45. package/src/workflows/feature/refactor-lens-models.feature +4 -0
  46. package/src/workflows/feature/refactor-rebuild.feature +269 -0
  47. package/src/workflows/feature/refactor-review.feature +45 -1
  48. package/src/workflows/feature/refactor.ts +9 -3
  49. package/src/workflows/feature/seam.test.ts +108 -3
  50. package/src/workflows/feature/seam.ts +169 -31
  51. package/src/workflows/feature/slicing-cap.feature +14 -0
  52. package/src/workflows/feature/slicing.feature +225 -0
  53. package/src/workflows/feature/slicing.test.ts +49 -0
  54. package/src/workflows/feature/slicing.ts +105 -0
  55. package/src/workflows/index.ts +1 -0
  56. package/src/workflows/shared/fences.ts +5 -0
  57. package/src/workflows/shared/options.test.ts +11 -2
  58. package/src/workflows/shared/options.ts +19 -4
  59. package/src/workflows/shared/steps.ts +2 -0
  60. package/src/workflows/shared/text.ts +129 -28
  61. package/src/workflows/shared/vars.ts +1 -0
  62. package/src/workflows/shared/workflows.steps.ts +13 -0
@@ -170,7 +170,7 @@ var init_GlobalValue = __esmMin((() => {
170
170
  }));
171
171
  //#endregion
172
172
  //#region node_modules/effect/dist/esm/Predicate.js
173
- var isTruthy, isString, isNumber, isBoolean, isBigInt, isSymbol, isFunction$1, isUndefined, isNever, isRecordOrArray, isObject$3, hasProperty, isTagged, isNullable, isNotNullable, isUint8Array, isDate, isIterable, isRecord$2, isPromiseLike;
173
+ var isTruthy, isString, isNumber, isBoolean, isBigInt, isSymbol, isFunction$1, isUndefined, isNotUndefined, isNotNull, isNever, isRecordOrArray, isObject$3, hasProperty, isTagged, isNullable, isNotNullable, isUint8Array, isDate, isIterable, isRecord$2, isPromiseLike;
174
174
  var init_Predicate = __esmMin((() => {
175
175
  init_Function();
176
176
  isTruthy = (input) => !!input;
@@ -181,6 +181,8 @@ var init_Predicate = __esmMin((() => {
181
181
  isSymbol = (input) => typeof input === "symbol";
182
182
  isFunction$1 = isFunction$2;
183
183
  isUndefined = (input) => input === void 0;
184
+ isNotUndefined = (input) => input !== void 0;
185
+ isNotNull = (input) => input !== null;
184
186
  isNever = (_) => false;
185
187
  isRecordOrArray = (input) => typeof input === "object" && input !== null;
186
188
  isObject$3 = (input) => isRecordOrArray(input) || isFunction$1(input);
@@ -6826,7 +6828,7 @@ var init_label = __esmMin((() => {
6826
6828
  }));
6827
6829
  //#endregion
6828
6830
  //#region node_modules/effect/dist/esm/internal/core-effect.js
6829
- var annotateLogs$1, asSome, try_$1, catchTag$1, diffFiberRefs, bind, bindTo, match$4, fiberRefs, ignore$1, logWithLevel, logWarning$1, logError$1, mapErrorCause, negate$1, orElseSucceed$1, patchFiberRefs, promise$1, provideService$1, provideServiceEffect, sandbox$1, sleep$1, succeedNone, summarized, tapErrorCause$1, tryPromise$1, tryMap$1, updateFiberRefs, when$1, serviceOption$1;
6831
+ var annotateLogs$1, asSome, try_$1, catchAllDefect$1, catchTag$1, diffFiberRefs, bind, bindTo, match$4, fiberRefs, ignore$1, logWithLevel, logWarning$1, logError$1, mapErrorCause, negate$1, orElseSucceed$1, patchFiberRefs, promise$1, provideService$1, provideServiceEffect, sandbox$1, sleep$1, succeedNone, summarized, tapErrorCause$1, tryPromise$1, tryMap$1, updateFiberRefs, when$1, serviceOption$1;
6830
6832
  var init_core_effect = __esmMin((() => {
6831
6833
  init_Clock();
6832
6834
  init_Context();
@@ -6861,6 +6863,13 @@ var init_core_effect = __esmMin((() => {
6861
6863
  }
6862
6864
  });
6863
6865
  };
6866
+ catchAllDefect$1 = /*#__PURE__*/ dual(2, (self, f) => catchAllCause$1(self, (cause) => {
6867
+ const option = find(cause, (_) => isDieType$1(_) ? some(_) : none$4());
6868
+ switch (option._tag) {
6869
+ case "None": return failCause$6(cause);
6870
+ case "Some": return f(option.value.defect);
6871
+ }
6872
+ }));
6864
6873
  catchTag$1 = /*#__PURE__*/ dual((args) => isEffect$1(args[0]), (self, ...args) => {
6865
6874
  const f = args[args.length - 1];
6866
6875
  let predicate;
@@ -11435,7 +11444,7 @@ var init_MutableQueue = __esmMin((() => {
11435
11444
  }));
11436
11445
  //#endregion
11437
11446
  //#region node_modules/effect/dist/esm/Effect.js
11438
- var isEffect, all$1, forEach$2, async, withFiberRuntime, fail$7, failCause$2, die, dieMessage, gen, promise, succeed$3, suspend$5, sync$1, _void, catchAll, catchAllCause, catchIf, catchTag, ignore, sandbox, retry, try_, tryMap, tryPromise, interrupt, interruptible, uninterruptible, uninterruptibleMask, as, asVoid, map$4, mapBoth$1, mapError$1, negate, acquireRelease, acquireUseRelease$2, addFinalizer, ensuring$2, onError, scope$1, scopeWith, scopedWith$1, scoped$3, fiberIdWith, forkDaemon, forkIn, forkScoped, timeout, provide$1, provideService, serviceOption, either, exit$1, intoDeferred, when, flatMap$4, andThen, flatten$5, race, raceWith, tap, tapErrorCause, repeat, match$2, matchCause, matchCauseEffect, matchEffect, logWarning, logError, annotateLogs, orDie, orElse$1, orElseSucceed, runtime, unsafeMakeSemaphore, makeSemaphore, unsafeMakeLatch, runFork$1, runPromise, runSync, zip$1, zipLeft, zipRight$1, zipWith, fnUntraced;
11447
+ var isEffect, all$1, forEach$2, async, withFiberRuntime, fail$7, failCause$2, die, dieMessage, gen, promise, succeed$3, suspend$5, sync$1, _void, catchAll, catchAllCause, catchAllDefect, catchIf, catchTag, ignore, sandbox, retry, try_, tryMap, tryPromise, interrupt, interruptible, uninterruptible, uninterruptibleMask, as, asVoid, map$4, mapBoth$1, mapError$1, negate, acquireRelease, acquireUseRelease$2, addFinalizer, ensuring$2, onError, scope$1, scopeWith, scopedWith$1, scoped$3, fiberIdWith, forkDaemon, forkIn, forkScoped, timeout, provide$1, provideService, serviceOption, either, exit$1, intoDeferred, when, flatMap$4, andThen, flatten$5, race, raceWith, tap, tapErrorCause, repeat, match$2, matchCause, matchCauseEffect, matchEffect, logWarning, logError, annotateLogs, orDie, orElse$1, orElseSucceed, runtime, unsafeMakeSemaphore, makeSemaphore, unsafeMakeLatch, runFork$1, runPromise, runSync, zip$1, zipLeft, zipRight$1, zipWith, fnUntraced;
11439
11448
  var init_Effect = __esmMin((() => {
11440
11449
  init_core_effect();
11441
11450
  init_core();
@@ -11461,6 +11470,7 @@ var init_Effect = __esmMin((() => {
11461
11470
  _void = void_$4;
11462
11471
  catchAll = catchAll$1;
11463
11472
  catchAllCause = catchAllCause$1;
11473
+ catchAllDefect = catchAllDefect$1;
11464
11474
  catchIf = catchIf$1;
11465
11475
  catchTag = catchTag$1;
11466
11476
  ignore = ignore$1;
@@ -14278,7 +14288,7 @@ function getBrands(ast) {
14278
14288
  onSome: (brands) => brands.map((brand) => ` & Brand<${formatUnknown(brand)}>`).join("")
14279
14289
  });
14280
14290
  }
14281
- 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, 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$1, pickAnnotations, omitAnnotations, preserveTransformationAnnotations, typeAST, getTransformationFrom, encodedAST_, encodedAST, toJSONAnnotations, getEncodedParameter, formatKeyword, getOrElseExpected, getExpected;
14282
14292
  var init_SchemaAST = __esmMin((() => {
14283
14293
  init_Array();
14284
14294
  init_Function();
@@ -15242,7 +15252,7 @@ var init_SchemaAST = __esmMin((() => {
15242
15252
  return pattern;
15243
15253
  };
15244
15254
  getTemplateLiteralRegExp = (ast) => new RegExp(`^${getTemplateLiteralPattern(ast, false, true)}$`);
15245
- record = (key, value) => {
15255
+ record$1 = (key, value) => {
15246
15256
  const propertySignatures = [];
15247
15257
  const indexSignatures = [];
15248
15258
  const go = (key) => {
@@ -16549,7 +16559,7 @@ function causeEncode(cause) {
16549
16559
  };
16550
16560
  }
16551
16561
  }
16552
- var TypeId$7, variance, builtInAnnotations, toASTAnnotations, mergeSchemaAnnotations, format, encodedSchema, typeSchema, decodeUnknown, decodeUnknownEither, isSchema, declareConstructor, declarePrimitive, declare, InstanceOfSchemaId, instanceOf, Undefined, Null, Never, Unknown, BigIntFromSelf, SymbolFromSelf, String$, Number$, Boolean$, getDefaultUnionAST, NullOr, UndefinedOr, element, ElementImpl, getDefaultTupleTypeAST, Array$, formatPropertySignatureToken, PropertySignatureDeclaration, ToPropertySignature, formatPropertyKey, PropertySignatureTransformation, mergeSignatureAnnotations, PropertySignatureTypeId, isPropertySignature, PropertySignatureImpl, makePropertySignature, PropertySignatureWithFromImpl, propertySignature, withConstructorDefault, optional$2, preserveMissingMessageAnnotation, getDefaultTypeLiteralAST, lazilyMergeDefaults, tag$2, TaggedStruct, Record, intersectTypeLiterals, preserveRefinementAnnotations, addRefinementToMembers, extendAST, getTypes, intersectUnionMembers, extend, suspend, RefineSchemaId, fromFilterPredicateReturnTypeItem, toFilterParseIssue, transformOrFail, transform$1, TrimmedSchemaId, trimmed, MinLengthSchemaId, minLength, LengthSchemaId, length, PatternSchemaId, pattern, LowercasedSchemaId, lowercased, Lowercased, UppercasedSchemaId, uppercased, Uppercased, CapitalizedSchemaId, capitalized, Capitalized, UncapitalizedSchemaId, uncapitalized, Uncapitalized, nonEmptyString, Trimmed, NonEmptyTrimmedString, getErrorMessage, UUIDSchemaId, uuidRegexp, ULIDSchemaId, ulidRegexp, URLFromSelf, FiniteSchemaId, finite, GreaterThanSchemaId, greaterThan, GreaterThanOrEqualToSchemaId, greaterThanOrEqualTo, IntSchemaId, int, LessThanSchemaId, lessThan, LessThanOrEqualToSchemaId, lessThanOrEqualTo, BetweenSchemaId, between, NonNaNSchemaId, nonNaN, positive, negative, nonPositive, nonNegative, Int, NonNegative, JsonNumberSchemaId, encodeSymbol, decodeSymbol, GreaterThanOrEqualToBigIntSchemaId, greaterThanOrEqualToBigInt, BetweenBigIntSchemaId, betweenBigInt, nonNegativeBigInt, BigInt$, NonNegativeBigIntFromSelf, toComposite, DurationFromSelf, NonNegativeInt, DurationValueMillis, DurationValueNanos, DurationValueInfinity, durationValueInfinity, DurationValue, HRTime, isDurationValue, Uint8ArrayFromSelf, Uint8, ValidDateSchemaId, validDate, DateFromSelfSchemaId, DateFromSelf, DateFromString, DateTimeUtcFromSelf, decodeDateTimeUtc, timeZoneOffsetArbitrary, TimeZoneOffsetFromSelf, timeZoneNamedArbitrary, TimeZoneNamedFromSelf, TimeZoneFromSelf, timeZoneArbitrary, DateTimeZonedFromSelf, optionDecode, optionArbitrary, optionPretty, optionParse, OptionFromSelf_, OptionFromSelf, bigDecimalPretty, bigDecimalArbitrary, BigDecimalFromSelf, isField, isFields, getFields, getSchemaFromFieldsOr, getFieldsFromFieldsOr, getClassTag, TaggedError, extendFields, astCache, getClassAnnotations, makeClass, FiberIdEncoded, fiberIdArbitrary, fiberIdPretty, FiberIdFromSelf, fiberIdDecode, fiberIdEncode, causeDieEncoded, CauseEmptyEncoded, causeFailEncoded, CauseInterruptEncoded, causeEncodedId, causeEncoded, causeArbitrary, causePretty, causeParse, CauseFromSelf, Cause, Defect, SymbolStruct, SymbolFromStruct, PropertyKey$;
16562
+ var TypeId$7, variance, builtInAnnotations, toASTAnnotations, mergeSchemaAnnotations, format, encodedSchema, typeSchema, decodeUnknown, decodeUnknownEither, isSchema, declareConstructor, declarePrimitive, declare, InstanceOfSchemaId, instanceOf, Undefined, Null, Never, Unknown, BigIntFromSelf, SymbolFromSelf, String$, Number$, Boolean$, getDefaultUnionAST, NullOr, UndefinedOr, NullishOr, element, ElementImpl, getDefaultTupleTypeAST, Array$, formatPropertySignatureToken, PropertySignatureDeclaration, FromPropertySignature, ToPropertySignature, formatPropertyKey, PropertySignatureTransformation, mergeSignatureAnnotations, PropertySignatureTypeId, isPropertySignature, PropertySignatureImpl, makePropertySignature, PropertySignatureWithFromImpl, propertySignature, withConstructorDefault, optionalToRequired, optionalToOptional, optionalPropertySignatureAST, optional$2, optionalWith, preserveMissingMessageAnnotation, getDefaultTypeLiteralAST, lazilyMergeDefaults, tag$2, TaggedStruct, Record, intersectTypeLiterals, preserveRefinementAnnotations, addRefinementToMembers, extendAST, getTypes, intersectUnionMembers, extend, suspend, RefineSchemaId, fromFilterPredicateReturnTypeItem, toFilterParseIssue, transformOrFail, transform$1, TrimmedSchemaId, trimmed, MinLengthSchemaId, minLength, LengthSchemaId, length, PatternSchemaId, pattern, LowercasedSchemaId, lowercased, Lowercased, UppercasedSchemaId, uppercased, Uppercased, CapitalizedSchemaId, capitalized, Capitalized, UncapitalizedSchemaId, uncapitalized, Uncapitalized, nonEmptyString, Trimmed, NonEmptyTrimmedString, getErrorMessage, UUIDSchemaId, uuidRegexp, ULIDSchemaId, ulidRegexp, URLFromSelf, FiniteSchemaId, finite, GreaterThanSchemaId, greaterThan, GreaterThanOrEqualToSchemaId, greaterThanOrEqualTo, IntSchemaId, int, LessThanSchemaId, lessThan, LessThanOrEqualToSchemaId, lessThanOrEqualTo, BetweenSchemaId, between, NonNaNSchemaId, nonNaN, positive, negative, nonPositive, nonNegative, Int, NonNegative, JsonNumberSchemaId, encodeSymbol, decodeSymbol, GreaterThanOrEqualToBigIntSchemaId, greaterThanOrEqualToBigInt, BetweenBigIntSchemaId, betweenBigInt, nonNegativeBigInt, BigInt$, NonNegativeBigIntFromSelf, toComposite, DurationFromSelf, NonNegativeInt, DurationValueMillis, DurationValueNanos, DurationValueInfinity, durationValueInfinity, DurationValue, HRTime, isDurationValue, Uint8ArrayFromSelf, Uint8, ValidDateSchemaId, validDate, DateFromSelfSchemaId, DateFromSelf, DateFromString, DateTimeUtcFromSelf, decodeDateTimeUtc, timeZoneOffsetArbitrary, TimeZoneOffsetFromSelf, timeZoneNamedArbitrary, TimeZoneNamedFromSelf, TimeZoneFromSelf, timeZoneArbitrary, DateTimeZonedFromSelf, optionDecode, optionArbitrary, optionPretty, optionParse, OptionFromSelf_, OptionFromSelf, bigDecimalPretty, bigDecimalArbitrary, BigDecimalFromSelf, isField, isFields, getFields, getSchemaFromFieldsOr, getFieldsFromFieldsOr, getClassTag, TaggedError, extendFields, astCache, getClassAnnotations, makeClass, FiberIdEncoded, fiberIdArbitrary, fiberIdPretty, FiberIdFromSelf, fiberIdDecode, fiberIdEncode, causeDieEncoded, CauseEmptyEncoded, causeFailEncoded, CauseInterruptEncoded, causeEncodedId, causeEncoded, causeArbitrary, causePretty, causeParse, CauseFromSelf, Cause, Defect, SymbolStruct, SymbolFromStruct, PropertyKey$;
16553
16563
  var init_Schema = __esmMin((() => {
16554
16564
  init_Array();
16555
16565
  init_BigDecimal();
@@ -16668,6 +16678,7 @@ var init_Schema = __esmMin((() => {
16668
16678
  getDefaultUnionAST = (members) => Union$1.make(members.map((m) => m.ast));
16669
16679
  NullOr = (self) => Union(self, Null);
16670
16680
  UndefinedOr = (self) => Union(self, Undefined);
16681
+ NullishOr = (self) => Union(self, Null, Undefined);
16671
16682
  element = (self) => new ElementImpl(new OptionalType(self.ast, false), self);
16672
16683
  ElementImpl = class ElementImpl {
16673
16684
  ast;
@@ -16712,6 +16723,15 @@ var init_Schema = __esmMin((() => {
16712
16723
  return `PropertySignature<${token}, ${type}, never, ${token}, ${type}>`;
16713
16724
  }
16714
16725
  };
16726
+ FromPropertySignature = class extends OptionalType {
16727
+ isReadonly;
16728
+ fromKey;
16729
+ constructor(type, isOptional, isReadonly, annotations, fromKey) {
16730
+ super(type, isOptional, annotations);
16731
+ this.isReadonly = isReadonly;
16732
+ this.fromKey = fromKey;
16733
+ }
16734
+ };
16715
16735
  ToPropertySignature = class extends OptionalType {
16716
16736
  isReadonly;
16717
16737
  defaultValue;
@@ -16802,10 +16822,80 @@ var init_Schema = __esmMin((() => {
16802
16822
  case "PropertySignatureTransformation": return makePropertySignature(new PropertySignatureTransformation(ast.from, new ToPropertySignature(ast.to.type, ast.to.isOptional, ast.to.isReadonly, ast.to.annotations, defaultValue), ast.decode, ast.encode));
16803
16823
  }
16804
16824
  });
16825
+ optionalToRequired = (from, to, options) => makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(from.ast, true, true, {}, void 0), new ToPropertySignature(to.ast, false, true, {}, void 0), (o) => some(options.decode(o)), flatMap$9(options.encode)));
16826
+ optionalToOptional = (from, to, options) => makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(from.ast, true, true, {}, void 0), new ToPropertySignature(to.ast, true, true, {}, void 0), options.decode, options.encode));
16827
+ optionalPropertySignatureAST = (self, options) => {
16828
+ const isExact = options?.exact;
16829
+ const defaultValue = options?.default;
16830
+ const isNullable = options?.nullable;
16831
+ const asOption = options?.as == "Option";
16832
+ const asOptionEncode = options?.onNoneEncoding ? orElse$3(options.onNoneEncoding) : identity$1;
16833
+ if (isExact) if (defaultValue) if (isNullable) return withConstructorDefault(optionalToRequired(NullOr(self), typeSchema(self), {
16834
+ decode: match$8({
16835
+ onNone: defaultValue,
16836
+ onSome: (a) => a === null ? defaultValue() : a
16837
+ }),
16838
+ encode: some
16839
+ }), defaultValue).ast;
16840
+ else return withConstructorDefault(optionalToRequired(self, typeSchema(self), {
16841
+ decode: match$8({
16842
+ onNone: defaultValue,
16843
+ onSome: identity$1
16844
+ }),
16845
+ encode: some
16846
+ }), defaultValue).ast;
16847
+ else if (asOption) {
16848
+ const to = OptionFromSelf_(typeSchema(self));
16849
+ if (isNullable) return optionalToRequired(NullOr(self), to, {
16850
+ decode: filter$3(isNotNull),
16851
+ encode: asOptionEncode
16852
+ }).ast;
16853
+ else return optionalToRequired(self, to, {
16854
+ decode: identity$1,
16855
+ encode: identity$1
16856
+ }).ast;
16857
+ } else if (isNullable) return optionalToOptional(NullOr(self), typeSchema(self), {
16858
+ decode: filter$3(isNotNull),
16859
+ encode: identity$1
16860
+ }).ast;
16861
+ else return new PropertySignatureDeclaration(self.ast, true, true, {}, void 0);
16862
+ else if (defaultValue) if (isNullable) return withConstructorDefault(optionalToRequired(NullishOr(self), typeSchema(self), {
16863
+ decode: match$8({
16864
+ onNone: defaultValue,
16865
+ onSome: (a) => a == null ? defaultValue() : a
16866
+ }),
16867
+ encode: some
16868
+ }), defaultValue).ast;
16869
+ else return withConstructorDefault(optionalToRequired(UndefinedOr(self), typeSchema(self), {
16870
+ decode: match$8({
16871
+ onNone: defaultValue,
16872
+ onSome: (a) => a === void 0 ? defaultValue() : a
16873
+ }),
16874
+ encode: some
16875
+ }), defaultValue).ast;
16876
+ else if (asOption) {
16877
+ const to = OptionFromSelf_(typeSchema(self));
16878
+ if (isNullable) return optionalToRequired(NullishOr(self), to, {
16879
+ decode: filter$3((a) => a != null),
16880
+ encode: asOptionEncode
16881
+ }).ast;
16882
+ else return optionalToRequired(UndefinedOr(self), to, {
16883
+ decode: filter$3(isNotUndefined),
16884
+ encode: asOptionEncode
16885
+ }).ast;
16886
+ } else if (isNullable) return optionalToOptional(NullishOr(self), UndefinedOr(typeSchema(self)), {
16887
+ decode: filter$3(isNotNull),
16888
+ encode: identity$1
16889
+ }).ast;
16890
+ else return new PropertySignatureDeclaration(UndefinedOr(self).ast, true, true, {}, void 0);
16891
+ };
16805
16892
  optional$2 = (self) => {
16806
16893
  const ast = self.ast === undefinedKeyword || self.ast === neverKeyword ? undefinedKeyword : UndefinedOr(self).ast;
16807
16894
  return new PropertySignatureWithFromImpl(new PropertySignatureDeclaration(ast, true, true, {}, void 0), self);
16808
16895
  };
16896
+ optionalWith = /*#__PURE__*/ dual((args) => isSchema(args[0]), (self, options) => {
16897
+ return new PropertySignatureWithFromImpl(optionalPropertySignatureAST(self, options), self);
16898
+ });
16809
16899
  preserveMissingMessageAnnotation = /*#__PURE__*/ pickAnnotations([MissingMessageAnnotationId]);
16810
16900
  getDefaultTypeLiteralAST = (fields, records) => {
16811
16901
  const ownKeys = Reflect.ownKeys(fields);
@@ -16847,7 +16937,7 @@ var init_Schema = __esmMin((() => {
16847
16937
  const issFrom = [];
16848
16938
  const issTo = [];
16849
16939
  for (const r of records) {
16850
- const { indexSignatures, propertySignatures } = record(r.key.ast, r.value.ast);
16940
+ const { indexSignatures, propertySignatures } = record$1(r.key.ast, r.value.ast);
16851
16941
  propertySignatures.forEach((ps) => {
16852
16942
  from.push(ps);
16853
16943
  to.push(new PropertySignature(ps.name, typeAST(ps.type), ps.isOptional, ps.isReadonly, ps.annotations));
@@ -16862,7 +16952,7 @@ var init_Schema = __esmMin((() => {
16862
16952
  }
16863
16953
  const iss = [];
16864
16954
  for (const r of records) {
16865
- const { indexSignatures, propertySignatures } = record(r.key.ast, r.value.ast);
16955
+ const { indexSignatures, propertySignatures } = record$1(r.key.ast, r.value.ast);
16866
16956
  propertySignatures.forEach((ps) => pss.push(ps));
16867
16957
  indexSignatures.forEach((is) => iss.push(is));
16868
16958
  }
@@ -21831,15 +21921,15 @@ const openQuestions = (text) => ctx().openQuestions(text);
21831
21921
  //#endregion
21832
21922
  //#region src/flows/scripts.ts
21833
21923
  /** POSIX single-quoting: `value` survives the shell as one word, verbatim. */
21834
- const quote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
21835
- const removal = (paths) => paths.length === 0 ? [] : [`rm -rf -- ${paths.map(quote).join(" ")}`];
21924
+ const quote$1 = (value) => `'${value.replace(/'/g, "'\\''")}'`;
21925
+ const removal = (paths) => paths.length === 0 ? [] : [`rm -rf -- ${paths.map(quote$1).join(" ")}`];
21836
21926
  /**
21837
21927
  * Run `command` and keep its outcome in the tree: on failure its output (or
21838
21928
  * a note that there was none) lands in `report`, on success `report` goes.
21839
21929
  */
21840
21930
  const checkScript = (command, options) => {
21841
- const report = quote(options.report);
21842
- const output = quote(`${options.report}.output`);
21931
+ const report = quote$1(options.report);
21932
+ const output = quote$1(`${options.report}.output`);
21843
21933
  return [
21844
21934
  "#!/usr/bin/env sh",
21845
21935
  "set +e",
@@ -21857,7 +21947,7 @@ const checkScript = (command, options) => {
21857
21947
  ` rm -f ${output}`,
21858
21948
  ` printf 'the test command failed with exit code %s and produced no output.' "$code" > ${report}`,
21859
21949
  " fi",
21860
- ` printf '\\n<!-- gtd check %s -->\\n' ${quote(options.stamp)} >> ${report}`,
21950
+ ` printf '\\n<!-- gtd check %s -->\\n' ${quote$1(options.stamp)} >> ${report}`,
21861
21951
  "else",
21862
21952
  ` rm -f ${output} ${report}`,
21863
21953
  ...removal(options.sweepOnGreen ?? []).map((line) => ` ${line}`),
@@ -21866,21 +21956,21 @@ const checkScript = (command, options) => {
21866
21956
  ].join("\n");
21867
21957
  };
21868
21958
  const patchScript = (commit, report, failure, reverse, exclude = []) => {
21869
- const paths = exclude.length === 0 ? "" : ` . ${exclude.map((p) => quote(`:(exclude,literal)${p}`)).join(" ")}`;
21870
- const range = `${quote(`${commit}^`)} ${quote(commit)}`;
21871
- const error = quote(`${report}.output`);
21959
+ const paths = exclude.length === 0 ? "" : ` . ${exclude.map((p) => quote$1(`:(exclude,literal)${p}`)).join(" ")}`;
21960
+ const range = `${quote$1(`${commit}^`)} ${quote$1(commit)}`;
21961
+ const error = quote$1(`${report}.output`);
21872
21962
  return [
21873
21963
  "#!/usr/bin/env sh",
21874
21964
  "set +e",
21875
21965
  `if ! git diff --quiet ${range} --${paths}; then`,
21876
- ` mkdir -p "$(dirname ${quote(report)})"`,
21966
+ ` mkdir -p "$(dirname ${quote$1(report)})"`,
21877
21967
  ` git diff --binary --no-color --no-ext-diff --no-textconv --src-prefix=a/ --dst-prefix=b/ ${range} --${paths} | git apply --whitespace=nowarn${reverse ? " -R" : ""} 2> ${error}`,
21878
21968
  " code=$?",
21879
21969
  " if [ \"$code\" -ne 0 ]; then",
21880
21970
  " {",
21881
- ` printf '%s\\n\\n' ${quote(failure)}`,
21971
+ ` printf '%s\\n\\n' ${quote$1(failure)}`,
21882
21972
  ` if [ -s ${error} ]; then cat ${error}; else printf '${reverse ? "Reverting" : "Applying"} it exited %s and produced no output.\\n' "$code"; fi`,
21883
- ` } > ${quote(report)}`,
21973
+ ` } > ${quote$1(report)}`,
21884
21974
  " fi",
21885
21975
  ` rm -f ${error}`,
21886
21976
  "fi",
@@ -21901,12 +21991,12 @@ const applyScript = (commit, report, failure, exclude = []) => patchScript(commi
21901
21991
  * still exactly as `commit` left it. A path changed since is left alone.
21902
21992
  */
21903
21993
  const restoreScript = (commit, paths, source) => {
21904
- const unchanged = (path) => `git diff --quiet ${quote(commit)} -- ${quote(path)}`;
21994
+ const unchanged = (path) => `git diff --quiet ${quote$1(commit)} -- ${quote$1(path)}`;
21905
21995
  return [
21906
21996
  "#!/usr/bin/env sh",
21907
21997
  "set +e",
21908
- ...paths.restore.map((path) => `${unchanged(path)} && git restore --source=${quote(source ?? `${commit}~1`)} --worktree -- ${quote(path)}`),
21909
- ...paths.remove.map((path) => `${unchanged(path)} && rm -f -- ${quote(path)}`),
21998
+ ...paths.restore.map((path) => `${unchanged(path)} && git restore --source=${quote$1(source ?? `${commit}~1`)} --worktree -- ${quote$1(path)}`),
21999
+ ...paths.remove.map((path) => `${unchanged(path)} && rm -f -- ${quote$1(path)}`),
21910
22000
  ""
21911
22001
  ].join("\n");
21912
22002
  };
@@ -21920,15 +22010,15 @@ const removeScript = (paths) => [
21920
22010
  const moveScript = (from, to) => [
21921
22011
  "#!/usr/bin/env sh",
21922
22012
  "set -e",
21923
- `mkdir -p "$(dirname ${quote(to)})"`,
21924
- `mv -- ${quote(from)} ${quote(to)}`,
22013
+ `mkdir -p "$(dirname ${quote$1(to)})"`,
22014
+ `mv -- ${quote$1(from)} ${quote$1(to)}`,
21925
22015
  ""
21926
22016
  ].join("\n");
21927
22017
  /** Write `path` as committed at `ref` to `to`. */
21928
22018
  const showScript = (ref, path, to) => [
21929
22019
  "#!/usr/bin/env sh",
21930
22020
  "set -e",
21931
- `git show ${quote(`${ref}:${path}`)} > ${quote(to)}`,
22021
+ `git show ${quote$1(`${ref}:${path}`)} > ${quote$1(to)}`,
21932
22022
  ""
21933
22023
  ].join("\n");
21934
22024
  //#endregion
@@ -22291,7 +22381,7 @@ var flows_exports = /* @__PURE__ */ __exportAll({
22291
22381
  numeric: () => numeric,
22292
22382
  openQuestions: () => openQuestions,
22293
22383
  protocolMismatch: () => protocolMismatch,
22294
- quote: () => quote,
22384
+ quote: () => quote$1,
22295
22385
  read: () => read,
22296
22386
  refuse: () => refuse,
22297
22387
  removeScript: () => removeScript,
@@ -37375,6 +37465,7 @@ var init_BeatStatus = __esmMin((() => {
37375
37465
  initial,
37376
37466
  model: rendered.model,
37377
37467
  system: rendered.system !== void 0 && rendered.system !== "" ? rendered.system : void 0,
37468
+ context: rendered.context,
37378
37469
  log,
37379
37470
  state: rendered.state,
37380
37471
  actor: rendered.actor,
@@ -37433,6 +37524,7 @@ var init_BeatDocument = __esmMin((() => {
37433
37524
  session,
37434
37525
  model: status.model,
37435
37526
  system: status.system,
37527
+ context: status.context,
37436
37528
  validate,
37437
37529
  log: status.log,
37438
37530
  state: status.state,
@@ -37674,6 +37766,91 @@ var init_Slices = __esmMin((() => {
37674
37766
  renderSlicesJson = (document) => JSON.stringify(document) + "\n";
37675
37767
  }));
37676
37768
  //#endregion
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;
37771
+ var init_ContextLimit = __esmMin((() => {
37772
+ DEFAULT_CONTEXT_LIMIT = {
37773
+ soft: .6,
37774
+ hard: .7
37775
+ };
37776
+ DEFAULT_WINDOW = 2e5;
37777
+ LONG_WINDOW = 1e6;
37778
+ contextWindowFor = (model) => model !== void 0 && /\[1m\]/i.test(model) ? LONG_WINDOW : DEFAULT_WINDOW;
37779
+ parseContextWindow = (raw) => {
37780
+ const n = Number(raw);
37781
+ return raw !== void 0 && raw.trim() !== "" && Number.isInteger(n) && n > 0 ? n : void 0;
37782
+ };
37783
+ CONTEXT_STOP_FILE_ENV = "GTD_LOOP_CONTEXT_STOP_FILE";
37784
+ contextShapeFault = (limit) => {
37785
+ if (typeof limit !== "object" || limit === null || Array.isArray(limit)) return `context must be an object { soft, hard }, got ${JSON.stringify(limit)}`;
37786
+ const unknown = Object.keys(limit).filter((key) => key !== "soft" && key !== "hard");
37787
+ if (unknown.length > 0) return `unknown key(s) ${unknown.join(", ")} in context`;
37788
+ const shares = limit;
37789
+ for (const key of ["soft", "hard"]) {
37790
+ const value = shares[key];
37791
+ if (value === void 0) continue;
37792
+ if (typeof value !== "number" || !(value > 0 && value <= 1)) return `context.${key} must be a share of the context window in (0, 1], got ${JSON.stringify(value)}`;
37793
+ }
37794
+ };
37795
+ contextLimitFault = (limit) => {
37796
+ const shape = contextShapeFault(limit);
37797
+ if (shape !== void 0) return shape;
37798
+ const shares = limit;
37799
+ const soft = shares.soft ?? DEFAULT_CONTEXT_LIMIT.soft;
37800
+ const hard = shares.hard ?? DEFAULT_CONTEXT_LIMIT.hard;
37801
+ return soft < hard ? void 0 : `context.soft (${soft}) must be below context.hard (${hard})`;
37802
+ };
37803
+ record = (value) => typeof value === "object" && value !== null ? value : void 0;
37804
+ count = (value) => typeof value === "number" && value > 0 ? value : 0;
37805
+ usageTokens = (usage) => {
37806
+ const u = record(usage);
37807
+ if (u === void 0) return void 0;
37808
+ return count(u["input_tokens"]) + count(u["cache_read_input_tokens"]) + count(u["cache_creation_input_tokens"]);
37809
+ };
37810
+ transcriptTokens = (transcript) => {
37811
+ const lines = transcript.split("\n");
37812
+ for (let i = lines.length - 1; i >= 0; i--) {
37813
+ const line = lines[i].trim();
37814
+ if (line === "") continue;
37815
+ let entry;
37816
+ try {
37817
+ entry = JSON.parse(line);
37818
+ } catch {
37819
+ continue;
37820
+ }
37821
+ if (record(entry)?.["type"] !== "assistant") continue;
37822
+ const tokens = usageTokens(record(record(entry)?.["message"])?.["usage"]);
37823
+ if (tokens !== void 0) return tokens;
37824
+ }
37825
+ };
37826
+ CONTEXT_LIMIT_MARKER = "gtd: context limit";
37827
+ percent = (share) => `${Math.round(share * 100)}%`;
37828
+ contextHook = (input) => {
37829
+ const { event, tokens, window, limit } = input;
37830
+ if (event === "PreCompact") return {
37831
+ kind: "hard",
37832
+ stopReason: `${CONTEXT_LIMIT_MARKER}: the context is about to be compacted — the run is too big for one turn`
37833
+ };
37834
+ if (tokens === void 0) return void 0;
37835
+ const used = `${tokens} of ${window} tokens`;
37836
+ if (tokens >= limit.hard * window) return {
37837
+ kind: "hard",
37838
+ stopReason: `${CONTEXT_LIMIT_MARKER}: ${used}, past the ${percent(limit.hard)} hard limit`
37839
+ };
37840
+ if (tokens >= limit.soft * window) return {
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.`
37843
+ };
37844
+ };
37845
+ hookOutput = (decision) => decision.kind === "soft" ? {
37846
+ decision: "block",
37847
+ reason: decision.reason
37848
+ } : {
37849
+ continue: false,
37850
+ stopReason: decision.stopReason
37851
+ };
37852
+ }));
37853
+ //#endregion
37677
37854
  //#region src/wire/index.ts
37678
37855
  var init_wire = __esmMin((() => {
37679
37856
  init_constants();
@@ -37689,6 +37866,7 @@ var init_wire = __esmMin((() => {
37689
37866
  init_Sessions();
37690
37867
  init_Glob();
37691
37868
  init_Slices();
37869
+ init_ContextLimit();
37692
37870
  }));
37693
37871
  //#endregion
37694
37872
  //#region src/replay/RefName.ts
@@ -38018,6 +38196,15 @@ const budgeted = (evidence, budgetBytes) => {
38018
38196
  truncated
38019
38197
  };
38020
38198
  };
38199
+ const scopeLabel = (chain) => {
38200
+ const path = chain.flatMap((o) => o.name === void 0 ? [] : [o.name]).join(".");
38201
+ if (chain.at(-1)?.name !== void 0) return `scope "${path}"`;
38202
+ return path === "" ? "an unnamed scope" : `an unnamed scope inside "${path}"`;
38203
+ };
38204
+ const inheritedContext = (layers) => layers.reduce((merged, layer) => layer === void 0 ? merged : {
38205
+ ...merged,
38206
+ ...Object.fromEntries(Object.entries(layer).filter(([, value]) => value !== void 0))
38207
+ }, void 0);
38021
38208
  const sameSkills = (a, b) => (a?.length ?? 0) === (b?.length ?? 0) && (a ?? []).every((skill, i) => skill === b?.[i]);
38022
38209
  const samePersona = (a, b) => a.model === b.model && a.system === b.system && sameSkills(a.skills, b.skills) && sameAccess(a.access, b.access);
38023
38210
  /**
@@ -38037,6 +38224,7 @@ const KNOWN_OPTIONS = {
38037
38224
  ...STEERING_OPTIONS,
38038
38225
  "model",
38039
38226
  "system",
38227
+ "context",
38040
38228
  "allowEmpty",
38041
38229
  "keep"
38042
38230
  ]),
@@ -38151,11 +38339,13 @@ const replay = async (input) => {
38151
38339
  if (s.model !== void 0) persona.model = s.model;
38152
38340
  if (s.system !== void 0) persona.system = s.system;
38153
38341
  }
38342
+ const context = inheritedContext([...scopes.map((s) => s.context), request.options.context]);
38154
38343
  return {
38155
38344
  ...request,
38156
38345
  options: {
38157
38346
  ...persona,
38158
- ...request.options
38347
+ ...request.options,
38348
+ ...context === void 0 ? {} : { context }
38159
38349
  }
38160
38350
  };
38161
38351
  }
@@ -38293,10 +38483,26 @@ const replay = async (input) => {
38293
38483
  });
38294
38484
  return landPending(step, input.pending);
38295
38485
  };
38486
+ const scopeContextFault = () => {
38487
+ for (const [i, s] of scopes.entries()) {
38488
+ const fault = s.context === void 0 ? void 0 : contextShapeFault(s.context);
38489
+ if (fault !== void 0) return `the context of ${scopeLabel(scopes.slice(0, i + 1))}: ${fault}`;
38490
+ }
38491
+ };
38492
+ const resolvedContextFault = (request) => {
38493
+ const own = request.options.context;
38494
+ const layered = scopeContextFault() ?? (own === void 0 ? void 0 : contextShapeFault(own));
38495
+ if (layered !== void 0) return layered;
38496
+ const resolved = resolve(request);
38497
+ const context = resolved.kind === "agent" ? resolved.options.context : void 0;
38498
+ return context === void 0 ? void 0 : contextLimitFault(context);
38499
+ };
38296
38500
  const requestFault = (request) => {
38297
38501
  if (request.kind === "run" && typeof request.body !== "string") return `gtd: step "${scoped(request.name)}": a run() body is a shell script string — decide in flow code, then render the script (see checkScript and friends)`;
38298
38502
  if (request.kind !== "agent") return void 0;
38299
38503
  const name = scoped(request.name);
38504
+ const contextFault = resolvedContextFault(request);
38505
+ if (contextFault !== void 0) return `gtd: step "${name}": ${contextFault}`;
38300
38506
  if (request.options.keep === true) {
38301
38507
  if (request.options.allowEmpty === true) return `gtd: step "${name}": keep: true cannot be combined with allowEmpty — a turn that changes nothing has nothing to keep`;
38302
38508
  const refFault = name.includes("/") ? "it contains \"/\"" : refNameFault(name);
@@ -39917,6 +40123,10 @@ const commonOf = (step) => {
39917
40123
  ...optional$1("mode", options.mode)
39918
40124
  };
39919
40125
  };
40126
+ const stepContext = (context) => context === void 0 ? void 0 : {
40127
+ ...optional$1("soft", context.soft),
40128
+ ...optional$1("hard", context.hard)
40129
+ };
39920
40130
  const promptDef = (common, request, skills, access) => ({
39921
40131
  ...common,
39922
40132
  kind: "prompt",
@@ -39925,6 +40135,7 @@ const promptDef = (common, request, skills, access) => ({
39925
40135
  ...optional$1("system", request.options.system),
39926
40136
  ...optional$1("allowEmpty", request.options.allowEmpty),
39927
40137
  ...optional$1("keep", request.options.keep),
40138
+ ...optional$1("context", stepContext(request.options.context)),
39928
40139
  ...optional$1("skills", skills),
39929
40140
  ...optional$1("access", access)
39930
40141
  });
@@ -40010,7 +40221,8 @@ const hintsOf = (def) => ({
40010
40221
  ...optional$1("system", def.system),
40011
40222
  ...optional$1("mode", def.mode),
40012
40223
  ...optional$1("skills", def.skills),
40013
- ...optional$1("access", def.access)
40224
+ ...optional$1("access", def.access),
40225
+ ...optional$1("context", def.context)
40014
40226
  });
40015
40227
  const normalizeStatus = (raw) => raw === "A" ? "A" : raw === "D" ? "D" : "M";
40016
40228
  /** Per-model token totals, highest-cost first (ties broken by model name). */
@@ -41292,6 +41504,17 @@ const readStdin = () => tryPromise({
41292
41504
  },
41293
41505
  catch: (e) => e instanceof Error ? e : new Error(String(e))
41294
41506
  });
41507
+ /** Stdout is written once: a hook reads one JSON document, or none. */
41508
+ const runContextHookCommand = (command, out) => gen(function* () {
41509
+ const tools = yield* ToolCommands;
41510
+ const input = yield* readStdin();
41511
+ out.write(yield* tools.contextHook({
41512
+ input,
41513
+ ...command.soft !== void 0 ? { soft: command.soft } : {},
41514
+ ...command.hard !== void 0 ? { hard: command.hard } : {},
41515
+ ...command.window !== void 0 ? { window: command.window } : {}
41516
+ }));
41517
+ });
41295
41518
  /** Stdout is written once, after the answerer resolves — a rejection leaves it empty. */
41296
41519
  const runJudgeRunCommand = (command, out) => gen(function* () {
41297
41520
  const host = yield* Host;
@@ -41751,6 +41974,7 @@ const needsOf = (kind) => {
41751
41974
  case "lsp":
41752
41975
  case "install":
41753
41976
  case "loop":
41977
+ case "contextHook":
41754
41978
  case "judgeRun":
41755
41979
  case "strays": return "none";
41756
41980
  case "check":
@@ -41790,6 +42014,7 @@ const dispatchVoidCommand = (command, json, out) => {
41790
42014
  case "uncheck": return runUncheckCommand(command.file);
41791
42015
  case "install": return runInstallCommand(out);
41792
42016
  case "loop": return runLoopCommand();
42017
+ case "contextHook": return runContextHookCommand(command, out);
41793
42018
  case "summary": return runSummaryCommand(out, command.slice);
41794
42019
  case "base": return runBaseCommand(out);
41795
42020
  case "judge": return runJudgeCommand(json, out);
@@ -41833,6 +42058,10 @@ const nonNegativeNumber = (raw, flag) => {
41833
42058
  if (raw.trim() === "" || !Number.isFinite(n) || n < 0) return left(`gtd: ${flag} must be a non-negative number — got "${raw}"`);
41834
42059
  return right(n);
41835
42060
  };
42061
+ const share = (raw, flag) => {
42062
+ const n = Number(raw);
42063
+ 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
+ };
41836
42065
  const FLAGS = [
41837
42066
  {
41838
42067
  name: "--json",
@@ -41960,6 +42189,39 @@ const FLAGS = [
41960
42189
  "GTD_JUDGE_MODEL, then judge.json, then sonnet"
41961
42190
  ]
41962
42191
  },
42192
+ {
42193
+ name: "--soft",
42194
+ arity: 1,
42195
+ repeatable: false,
42196
+ scope: (kind) => kind === "contextHook",
42197
+ decode: ([raw]) => share(raw ?? "", "--soft"),
42198
+ scopeError: "gtd: --soft is only valid for `gtd context-hook`",
42199
+ valueHint: "<share>",
42200
+ help: ["(gtd context-hook only) the soft limit; default 0.6"]
42201
+ },
42202
+ {
42203
+ name: "--hard",
42204
+ arity: 1,
42205
+ repeatable: false,
42206
+ scope: (kind) => kind === "contextHook",
42207
+ decode: ([raw]) => share(raw ?? "", "--hard"),
42208
+ scopeError: "gtd: --hard is only valid for `gtd context-hook`",
42209
+ valueHint: "<share>",
42210
+ help: ["(gtd context-hook only) the hard limit; default 0.7"]
42211
+ },
42212
+ {
42213
+ name: "--window",
42214
+ arity: 1,
42215
+ repeatable: false,
42216
+ scope: (kind) => kind === "contextHook",
42217
+ decode: ([raw]) => {
42218
+ const window = parseContextWindow(raw);
42219
+ return window !== void 0 ? right(window) : left(`gtd: --window must be a positive integer — got "${raw ?? ""}"`);
42220
+ },
42221
+ scopeError: "gtd: --window is only valid for `gtd context-hook`",
42222
+ valueHint: "<tokens>",
42223
+ help: ["(gtd context-hook only) the model's context window in", "tokens; default 200000"]
42224
+ },
41963
42225
  {
41964
42226
  name: "--slice",
41965
42227
  arity: 1,
@@ -42266,6 +42528,22 @@ const COMMAND_ROWS = [
42266
42528
  "~/.config/gtd/loop.json); see docs/driver.md"
42267
42529
  ]
42268
42530
  },
42531
+ {
42532
+ token: "context-hook",
42533
+ kind: "contextHook",
42534
+ arity: "none",
42535
+ details: [
42536
+ "A Claude Code PostToolUse and PreCompact hook that stops an",
42537
+ "agent turn at a share of its context window. Reads the",
42538
+ "hook's input on stdin and the context the transcript's",
42539
+ "latest assistant message used. Past --soft it blocks with a",
42540
+ "request to end the turn with a handoff note; past --hard,",
42541
+ "or at PreCompact, it stops the turn with a stopReason",
42542
+ "starting \"gtd: context limit\". Prints nothing otherwise,",
42543
+ "and for a subagent's tool call. Always exits 0 on valid",
42544
+ "input; see docs/driver.md"
42545
+ ]
42546
+ },
42269
42547
  {
42270
42548
  token: "summary",
42271
42549
  kind: "summary",
@@ -42744,6 +43022,17 @@ const parseArgv = (argv) => {
42744
43022
  verbose
42745
43023
  };
42746
43024
  }
43025
+ if (kind === "contextHook") return {
43026
+ kind: "command",
43027
+ command: {
43028
+ kind: "contextHook",
43029
+ ...bag["--soft"] !== void 0 ? { soft: bag["--soft"] } : {},
43030
+ ...bag["--hard"] !== void 0 ? { hard: bag["--hard"] } : {},
43031
+ ...bag["--window"] !== void 0 ? { window: bag["--window"] } : {}
43032
+ },
43033
+ json,
43034
+ verbose
43035
+ };
42747
43036
  if (kind === "summary") return {
42748
43037
  kind: "command",
42749
43038
  command: {
@@ -58422,8 +58711,9 @@ var init_lsp = __esmMin((() => {
58422
58711
  }));
58423
58712
  //#endregion
58424
58713
  //#region src/loop/Agent.ts
58425
- var optional, parseJson, field, costOf, claude, pi, agentCli;
58714
+ var optional, parseJson, field$1, costOf, claude, hookSettings, pi, agentCli;
58426
58715
  var init_Agent = __esmMin((() => {
58716
+ init_wire();
58427
58717
  optional = (flag, value) => value === void 0 || value === "" ? [] : [flag, value];
58428
58718
  parseJson = (text) => {
58429
58719
  try {
@@ -58432,7 +58722,7 @@ var init_Agent = __esmMin((() => {
58432
58722
  return;
58433
58723
  }
58434
58724
  };
58435
- field = (value, key) => typeof value === "object" && value !== null ? value[key] : void 0;
58725
+ field$1 = (value, key) => typeof value === "object" && value !== null ? value[key] : void 0;
58436
58726
  costOf = (value) => typeof value === "number" && value > 0 ? value : 0;
58437
58727
  claude = {
58438
58728
  command: "claude",
@@ -58442,19 +58732,45 @@ var init_Agent = __esmMin((() => {
58442
58732
  turn.sessionId,
58443
58733
  ...optional("--model", turn.model),
58444
58734
  ...optional("--system-prompt", turn.system),
58735
+ "--settings",
58736
+ JSON.stringify(hookSettings(turn.hook)),
58445
58737
  "--output-format",
58446
- "json",
58738
+ "stream-json",
58739
+ "--verbose",
58447
58740
  "--dangerously-skip-permissions"
58448
58741
  ],
58449
58742
  read: (exit) => {
58450
- const envelope = parseJson(exit.stdout);
58451
- const result = field(envelope, "result");
58743
+ const lines = exit.stdout.split("\n");
58744
+ let envelope;
58745
+ for (let i = lines.length - 1; i >= 0 && envelope === void 0; i--) {
58746
+ const event = parseJson(lines[i]);
58747
+ if (field$1(event, "type") === "result" || field$1(event, "result") !== void 0) envelope = event;
58748
+ }
58749
+ const result = field$1(envelope, "result");
58750
+ const hookStopped = field$1(envelope, "terminal_reason") === "hook_stopped";
58452
58751
  return {
58453
- ok: exit.code === 0 && field(envelope, "is_error") !== true,
58454
- text: typeof result === "string" ? result : exit.stdout,
58455
- cost: costOf(field(envelope, "total_cost_usd"))
58752
+ ok: exit.code === 0 && field$1(envelope, "is_error") !== true && !hookStopped,
58753
+ text: typeof result === "string" ? result : lines.slice(-5).join("\n"),
58754
+ cost: costOf(field$1(envelope, "total_cost_usd")),
58755
+ hookStopped
58456
58756
  };
58457
- }
58757
+ },
58758
+ contextTokens: (line) => {
58759
+ const event = parseJson(line);
58760
+ if (field$1(event, "type") !== "assistant") return void 0;
58761
+ if (field$1(event, "parent_tool_use_id") != null) return void 0;
58762
+ return usageTokens(field$1(field$1(event, "message"), "usage"));
58763
+ }
58764
+ };
58765
+ hookSettings = (command) => {
58766
+ const hook = [{ hooks: [{
58767
+ type: "command",
58768
+ command
58769
+ }] }];
58770
+ return { hooks: {
58771
+ PostToolUse: hook,
58772
+ PreCompact: hook
58773
+ } };
58458
58774
  };
58459
58775
  pi = {
58460
58776
  command: "pi",
@@ -58470,13 +58786,14 @@ var init_Agent = __esmMin((() => {
58470
58786
  ],
58471
58787
  read: (exit) => {
58472
58788
  const events = exit.stdout.split("\n").map(parseJson).filter((event) => event !== void 0);
58473
- const message = field(events.findLast((event) => field(event, "type") === "message_end" && field(field(event, "message"), "role") === "assistant"), "message");
58474
- const content = field(message, "content");
58475
- const text = (Array.isArray(content) ? content : []).filter((part) => field(part, "type") === "text").map((part) => String(field(part, "text"))).join("\n");
58789
+ const message = field$1(events.findLast((event) => field$1(event, "type") === "message_end" && field$1(field$1(event, "message"), "role") === "assistant"), "message");
58790
+ const content = field$1(message, "content");
58791
+ const text = (Array.isArray(content) ? content : []).filter((part) => field$1(part, "type") === "text").map((part) => String(field$1(part, "text"))).join("\n");
58476
58792
  return {
58477
- ok: exit.code === 0 && !events.some((event) => field(event, "type") === "error"),
58793
+ ok: exit.code === 0 && !events.some((event) => field$1(event, "type") === "error"),
58478
58794
  text: text === "" ? exit.stdout : text,
58479
- cost: costOf(field(field(field(message, "usage"), "cost"), "total"))
58795
+ cost: costOf(field$1(field$1(field$1(message, "usage"), "cost"), "total")),
58796
+ hookStopped: false
58480
58797
  };
58481
58798
  }
58482
58799
  };
@@ -58501,6 +58818,10 @@ var init_Documents = __esmMin((() => {
58501
58818
  })),
58502
58819
  model: optional$2(String$),
58503
58820
  system: optional$2(String$),
58821
+ context: optional$2(Struct({
58822
+ soft: optionalWith(Number$, { exact: true }),
58823
+ hard: optionalWith(Number$, { exact: true })
58824
+ })),
58504
58825
  validate: optional$2(String$),
58505
58826
  label: optional$2(String$),
58506
58827
  judge: optional$2(String$)
@@ -58548,9 +58869,30 @@ var init_Host = __esmMin((() => {
58548
58869
  ],
58549
58870
  detached: true
58550
58871
  });
58872
+ const killGroup = (signal) => {
58873
+ try {
58874
+ if (child.pid !== void 0) process.kill(-child.pid, signal);
58875
+ } catch {}
58876
+ };
58551
58877
  let stdout = "";
58552
58878
  let stderr = "";
58553
- child.stdout?.setEncoding("utf-8").on("data", (chunk) => stdout += chunk);
58879
+ let stopped = false;
58880
+ let stopForce;
58881
+ let scanned = 0;
58882
+ child.stdout?.setEncoding("utf-8").on("data", (chunk) => {
58883
+ stdout += chunk;
58884
+ if (request.stopAt === void 0 || stopped) return;
58885
+ for (let end = stdout.indexOf("\n", scanned); end !== -1; end = stdout.indexOf("\n", scanned)) {
58886
+ const line = stdout.slice(scanned, end);
58887
+ scanned = end + 1;
58888
+ if (request.stopAt(line)) {
58889
+ stopped = true;
58890
+ killGroup("SIGTERM");
58891
+ stopForce = setTimeout(() => killGroup("SIGKILL"), KILL_GRACE_MS);
58892
+ return;
58893
+ }
58894
+ }
58895
+ });
58554
58896
  child.stderr?.setEncoding("utf-8").on("data", (chunk) => stderr += chunk);
58555
58897
  child.stdin?.on("error", () => {});
58556
58898
  child.stdin?.end(request.stdin);
@@ -58563,18 +58905,15 @@ var init_Host = __esmMin((() => {
58563
58905
  };
58564
58906
  child.on("error", (error) => settle(fail$7(/* @__PURE__ */ new Error(`could not run ${request.command}: ${error.message}`))));
58565
58907
  child.on("close", (code, signal) => {
58908
+ clearTimeout(stopForce);
58566
58909
  const exit = code ?? 128 + (signal === null ? 0 : constants.signals[signal] ?? 0);
58567
58910
  settle(succeed$3({
58568
58911
  code: exit,
58569
58912
  stdout,
58570
- stderr
58913
+ stderr,
58914
+ ...stopped ? { stopped: true } : {}
58571
58915
  }));
58572
58916
  });
58573
- const killGroup = (signal) => {
58574
- try {
58575
- if (child.pid !== void 0) process.kill(-child.pid, signal);
58576
- } catch {}
58577
- };
58578
58917
  return async((done) => {
58579
58918
  if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
58580
58919
  killGroup("SIGTERM");
@@ -58618,9 +58957,10 @@ var init_Host = __esmMin((() => {
58618
58957
  }));
58619
58958
  //#endregion
58620
58959
  //#region src/loop/Settings.ts
58621
- var Agent, CLAUDE_MODELS, BUNDLED_HINTS, SettingsFile, settingsPath, MODEL_ENV_PREFIX, modelEnvName, decodeFile, decodeAgent, resolveSettings, resolveModel;
58960
+ var Agent, CLAUDE_MODELS, BUNDLED_HINTS, SettingsFile, settingsPath, MODEL_ENV_PREFIX, modelEnvName, decodeFile, decodeAgent, decodeWindow, resolveSettings, resolveModel;
58622
58961
  var init_Settings = __esmMin((() => {
58623
58962
  init_esm();
58963
+ init_wire();
58624
58964
  Agent = Literal("claude", "pi");
58625
58965
  CLAUDE_MODELS = {
58626
58966
  smart: "opus",
@@ -58632,7 +58972,8 @@ var init_Settings = __esmMin((() => {
58632
58972
  models: optional$2(Record({
58633
58973
  key: String$,
58634
58974
  value: String$
58635
- }))
58975
+ })),
58976
+ contextWindow: optional$2(Int.pipe(positive()))
58636
58977
  });
58637
58978
  settingsPath = (env) => {
58638
58979
  const explicit = env["GTD_LOOP_CONFIG"];
@@ -58654,9 +58995,15 @@ var init_Settings = __esmMin((() => {
58654
58995
  return decodeUnknownEither(SettingsFile, { onExcessProperty: "error" })(json).pipe(mapLeft((error) => `${path}: ${error.message}`));
58655
58996
  };
58656
58997
  decodeAgent = (value) => value === void 0 || value === "" ? right(void 0) : decodeUnknownEither(Agent)(value).pipe(mapLeft(() => `GTD_LOOP_AGENT must be "claude" or "pi" — got "${value}"`));
58998
+ decodeWindow = (value) => {
58999
+ if (value === void 0 || value === "") return right(void 0);
59000
+ const window = parseContextWindow(value);
59001
+ return window !== void 0 ? right(window) : left(`GTD_LOOP_CONTEXT_WINDOW must be a positive integer — got "${value}"`);
59002
+ };
58657
59003
  resolveSettings = (env, file) => gen$2(function* () {
58658
59004
  const fromFile = file === void 0 ? {} : yield* decodeFile(file.path, file.text);
58659
59005
  const envAgent = yield* decodeAgent(env["GTD_LOOP_AGENT"]);
59006
+ const envWindow = yield* decodeWindow(env["GTD_LOOP_CONTEXT_WINDOW"]);
58660
59007
  const envModels = Object.fromEntries(Object.entries(env).filter((entry) => entry[0].startsWith(MODEL_ENV_PREFIX) && entry[1] !== void 0 && entry[1] !== ""));
58661
59008
  const agent = envAgent ?? fromFile.agent ?? "claude";
58662
59009
  return {
@@ -58665,7 +59012,8 @@ var init_Settings = __esmMin((() => {
58665
59012
  ...agent === "claude" ? CLAUDE_MODELS : {},
58666
59013
  ...fromFile.models
58667
59014
  },
58668
- envModels
59015
+ envModels,
59016
+ contextWindow: envWindow ?? fromFile.contextWindow
58669
59017
  };
58670
59018
  });
58671
59019
  resolveModel = (settings, hint) => {
@@ -58675,9 +59023,10 @@ var init_Settings = __esmMin((() => {
58675
59023
  }));
58676
59024
  //#endregion
58677
59025
  //#region src/loop/Loop.ts
58678
- var MAX_VALIDATION_FIXES, FAILURE_LINES, LAND, fromEither, paint, firstLines, loadSettings, gitRoot, gtd, readBeat, clock, header, rest, agentFailed, agentTurn, sessionFlags, validateOnce, promptBeat, runScript, stop, judgeGate, messageBeat, kindBeat, runBeat, costFlags, land, runLoop;
59026
+ var MAX_VALIDATION_FIXES, FAILURE_LINES, LAND, fromEither, paint, firstLines, loadSettings, gitRoot, gtd, readBeat, clock, header, rest, agentFailed, quote, contextGuard, contextStop, agentTurn, sessionFlags, validateOnce, promptBeat, runScript, stop, judgeGate, messageBeat, kindBeat, runBeat, costFlags, land, runLoop;
58679
59027
  var init_Loop = __esmMin((() => {
58680
59028
  init_esm();
59029
+ init_wire();
58681
59030
  init_Agent();
58682
59031
  init_Documents();
58683
59032
  init_Host();
@@ -58730,23 +59079,61 @@ var init_Loop = __esmMin((() => {
58730
59079
  ...exit.stderr.trim() === "" ? [] : [firstLines(exit.stderr)],
58731
59080
  ...result.text.trim() === "" ? [] : [firstLines(result.text)]
58732
59081
  ].join("\n") + "\n");
59082
+ quote = (arg) => `'${arg.replaceAll("'", "'\\''")}'`;
59083
+ contextGuard = (ctx, doc, model) => {
59084
+ const limit = {
59085
+ ...DEFAULT_CONTEXT_LIMIT,
59086
+ ...doc.context
59087
+ };
59088
+ const window = ctx.settings.contextWindow ?? contextWindowFor(model);
59089
+ return {
59090
+ limit,
59091
+ window,
59092
+ hook: [...ctx.gtd, "context-hook"].concat([
59093
+ "--soft",
59094
+ String(limit.soft),
59095
+ "--hard",
59096
+ String(limit.hard),
59097
+ "--window",
59098
+ String(window)
59099
+ ]).map(quote).join(" "),
59100
+ kill: (limit.hard + 1) / 2
59101
+ };
59102
+ };
59103
+ contextStop = (ctx, exit, guard, stopFile) => map$4(ctx.host.readFile(stopFile), (recorded) => {
59104
+ const reason = recorded?.trim().split("\n")[0];
59105
+ if (reason !== void 0 && reason !== "") return reason;
59106
+ if (exit.stopped !== true) return void 0;
59107
+ return `${CONTEXT_LIMIT_MARKER}: the stream passed ${Math.round(guard.kill * 100)}% of ${guard.window} tokens with no hook stopping it`;
59108
+ });
58733
59109
  agentTurn = (ctx, doc, model) => (prompt, sessionFlag) => gen(function* () {
58734
59110
  const cli = agentCli(ctx.settings.agent);
59111
+ const guard = contextGuard(ctx, doc, model);
59112
+ const tokensOf = cli.contextTokens;
59113
+ const stopFile = `${ctx.log}.context-stop`;
59114
+ yield* ctx.host.resetLog(stopFile);
58735
59115
  const exit = yield* ctx.host.spawn({
58736
59116
  command: cli.command,
58737
59117
  args: cli.args({
58738
59118
  sessionFlag,
58739
59119
  sessionId: doc.session?.id ?? "",
58740
59120
  model,
58741
- system: doc.system
59121
+ system: doc.system,
59122
+ hook: guard.hook
58742
59123
  }),
58743
59124
  cwd: ctx.root,
58744
59125
  stdin: prompt,
58745
- env: { CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" },
58746
- output: "capture"
59126
+ env: {
59127
+ CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1",
59128
+ [CONTEXT_STOP_FILE_ENV]: stopFile
59129
+ },
59130
+ output: "capture",
59131
+ ...tokensOf === void 0 ? {} : { stopAt: (line) => (tokensOf(line) ?? 0) >= guard.kill * guard.window }
58747
59132
  });
58748
59133
  const result = cli.read(exit);
58749
59134
  yield* ctx.host.appendLog(ctx.log, `${exit.stderr}${result.text}\n`);
59135
+ const why = yield* contextStop(ctx, exit, guard, stopFile);
59136
+ if (why !== void 0) return yield* fail$7(/* @__PURE__ */ new Error(`${why} — the turn at "${doc.state}" was stopped and nothing landed; see ${ctx.log}`));
58750
59137
  if (!result.ok) yield* agentFailed(ctx, exit, result);
58751
59138
  return result;
58752
59139
  });
@@ -58876,15 +59263,66 @@ var init_Loop = __esmMin((() => {
58876
59263
  });
58877
59264
  }));
58878
59265
  //#endregion
59266
+ //#region src/loop/ContextHook.ts
59267
+ var field, limitOf, parseInput, tokensOf, recordStop, runContextHook;
59268
+ var init_ContextHook = __esmMin((() => {
59269
+ init_esm();
59270
+ init_wire();
59271
+ init_Host();
59272
+ field = (value, key) => typeof value === "object" && value !== null ? value[key] : void 0;
59273
+ limitOf = (request) => {
59274
+ const limit = {
59275
+ soft: request.soft ?? DEFAULT_CONTEXT_LIMIT.soft,
59276
+ hard: request.hard ?? DEFAULT_CONTEXT_LIMIT.hard
59277
+ };
59278
+ const fault = contextLimitFault(limit);
59279
+ return fault === void 0 ? succeed$3(limit) : fail$7(/* @__PURE__ */ new Error(`gtd context-hook: ${fault}`));
59280
+ };
59281
+ parseInput = (text) => try_({
59282
+ try: () => JSON.parse(text),
59283
+ catch: () => /* @__PURE__ */ new Error("gtd context-hook: stdin is not a hook's JSON input")
59284
+ }).pipe(map$4((input) => {
59285
+ const event = field(input, "hook_event_name");
59286
+ if (event !== "PostToolUse" && event !== "PreCompact") return void 0;
59287
+ if (field(input, "agent_id") !== void 0) return void 0;
59288
+ const path = field(input, "transcript_path");
59289
+ return {
59290
+ event,
59291
+ transcript: typeof path === "string" && path !== "" ? path : void 0
59292
+ };
59293
+ }));
59294
+ tokensOf = (input) => input.event === "PostToolUse" && input.transcript !== void 0 ? flatMap$4(LoopHost, (host) => host.readFile(input.transcript)).pipe(map$4((text) => text === void 0 ? void 0 : transcriptTokens(text))) : succeed$3(void 0);
59295
+ recordStop = (stopReason) => flatMap$4(LoopHost, (host) => {
59296
+ const file = host.env[CONTEXT_STOP_FILE_ENV];
59297
+ return file === void 0 || file === "" ? _void : host.appendLog(file, `${stopReason}\n`).pipe(catchAllDefect(() => _void));
59298
+ });
59299
+ runContextHook = (request) => gen(function* () {
59300
+ const limit = yield* limitOf(request);
59301
+ const input = yield* parseInput(request.input);
59302
+ if (input === void 0) return "";
59303
+ const decision = contextHook({
59304
+ event: input.event,
59305
+ tokens: yield* tokensOf(input),
59306
+ window: request.window ?? contextWindowFor(void 0),
59307
+ limit
59308
+ });
59309
+ if (decision === void 0) return "";
59310
+ if (decision.kind === "hard") yield* recordStop(decision.stopReason);
59311
+ return `${JSON.stringify(hookOutput(decision))}\n`;
59312
+ });
59313
+ }));
59314
+ //#endregion
58879
59315
  //#region src/loop/index.ts
58880
59316
  var loop_exports = /* @__PURE__ */ __exportAll({
58881
59317
  LoopHost: () => LoopHost,
58882
59318
  liveLoopHost: () => liveLoopHost,
59319
+ runContextHook: () => runContextHook,
58883
59320
  runLoop: () => runLoop
58884
59321
  });
58885
59322
  var init_loop = __esmMin((() => {
58886
59323
  init_Loop();
58887
59324
  init_Host();
59325
+ init_ContextHook();
58888
59326
  }));
58889
59327
  //#endregion
58890
59328
  //#region src/judges/providers/io.ts
@@ -59373,6 +59811,10 @@ const liveToolCommands = effect$1(ToolCommands, gen(function* () {
59373
59811
  const { runLoop, liveLoopHost } = await Promise.resolve().then(() => (init_loop(), loop_exports));
59374
59812
  return () => runLoop({ gtd }).pipe(provide$1(liveLoopHost));
59375
59813
  }),
59814
+ contextHook: (request) => lazy("loop", async () => {
59815
+ const { runContextHook, liveLoopHost } = await Promise.resolve().then(() => (init_loop(), loop_exports));
59816
+ return () => runContextHook(request).pipe(provide$1(liveLoopHost));
59817
+ }),
59376
59818
  judge: async (request) => {
59377
59819
  const { runJudge } = await Promise.resolve().then(() => (init_judges(), judges_exports)).catch((error) => {
59378
59820
  throw loadFailure("judge")(error);