@open-tomato/rafa 0.32.0 → 0.33.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.
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  describeValue
4
- } from "./index-rs79dq9e.js";
4
+ } from "./index-fzhd3d4y.js";
5
5
 
6
6
  // src/cli/spends.ts
7
7
  var SPENDS_GLYPH = "\uD83E\uDE99";
@@ -31,7 +31,7 @@ function spendsProblem(value) {
31
31
  }
32
32
 
33
33
  // src/cli/command.ts
34
- var COMMAND_OUTPUTS = ["text", "json", "tui"];
34
+ var COMMAND_OUTPUTS = ["text", "json", "events", "tui"];
35
35
  var MAX_EXIT_CODE = 255;
36
36
 
37
37
  class CommandExit extends Error {
@@ -39,7 +39,7 @@ import {
39
39
  tierPin,
40
40
  tierSwitch,
41
41
  usdAmount
42
- } from "./index-rs79dq9e.js";
42
+ } from "./index-fzhd3d4y.js";
43
43
 
44
44
  // src/config-items.ts
45
45
  var itemText = text("a non-empty string");
@@ -172,6 +172,61 @@ var fragmentsDirectory = (raw, at) => {
172
172
  return { value: undefined, problems: [problem], extras: [] };
173
173
  };
174
174
 
175
+ // src/config-schema-hub.ts
176
+ var HUB_TIMEOUT_MIN_SECONDS = 1;
177
+ var HUB_TIMEOUT_MAX_SECONDS = 30;
178
+ var MS_PER_SECOND = 1000;
179
+ var HUB_TIMEOUT = /^(\d+)s$/;
180
+ var HUB_URL_PROTOCOLS = Object.freeze(["http:", "https:"]);
181
+ var HUB_DEFAULTS = Object.freeze({
182
+ hubUrl: null,
183
+ hubTokenSecret: null,
184
+ hubTimeout: "3s"
185
+ });
186
+ function hubTimeoutMs(raw) {
187
+ const match = typeof raw === "string" ? HUB_TIMEOUT.exec(raw) : null;
188
+ if (match === null)
189
+ return null;
190
+ const seconds = Number(match[1]);
191
+ return seconds >= HUB_TIMEOUT_MIN_SECONDS && seconds <= HUB_TIMEOUT_MAX_SECONDS ? seconds * MS_PER_SECOND : null;
192
+ }
193
+ var hubTimeout = (raw, at) => hubTimeoutMs(raw) === null ? refused(at, raw, `a duration of whole seconds from ${String(HUB_TIMEOUT_MIN_SECONDS)}s to ${String(HUB_TIMEOUT_MAX_SECONDS)}s, such as 3s`) : { value: raw, problems: [], extras: [] };
194
+ function isHubUrl(raw) {
195
+ if (typeof raw !== "string" || raw.trim() !== raw)
196
+ return false;
197
+ const url = URL.parse(raw);
198
+ return url !== null && HUB_URL_PROTOCOLS.includes(url.protocol) && url.username === "" && url.password === "";
199
+ }
200
+ var hubUrl = (raw, at) => isHubUrl(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, "an http or https URL with no user name or password, such as https://hub.example.org");
201
+ var HUB_SETTINGS = {
202
+ hubUrl: { key: "hub.url", read: hubUrl, cli: false },
203
+ hubTokenSecret: { key: "hub.tokenSecret", read: text("a secret store name"), cli: false },
204
+ hubTimeout: { key: "hub.timeout", read: hubTimeout, cli: false }
205
+ };
206
+ var HUB_STRATEGY = "service";
207
+ function labelOf(input) {
208
+ const path = input.effortSyncSource === "user" ? input.paths.user : input.paths.file;
209
+ return path ?? input.effortSyncSource;
210
+ }
211
+ function hubUrlProblems(input) {
212
+ if (input.effortSync !== HUB_STRATEGY || input.hubUrl !== null)
213
+ return [];
214
+ return [
215
+ `${labelOf(input)}: effort.sync is ${describeValue(HUB_STRATEGY)} and no config file names hub.url;` + " expected hub.url, the address of the hub, such as https://hub.example.org"
216
+ ];
217
+ }
218
+ function hubContextOf(config) {
219
+ const url = config.hubUrl ?? null;
220
+ if (url === null)
221
+ return;
222
+ const timeout = config.hubTimeout ?? HUB_DEFAULTS.hubTimeout;
223
+ const timeoutMs = hubTimeoutMs(timeout);
224
+ if (timeoutMs === null) {
225
+ throw new TypeError(`hub.timeout is ${describeValue(timeout)}, which no config accepts`);
226
+ }
227
+ return Object.freeze({ url, tokenSecret: config.hubTokenSecret ?? null, timeoutMs });
228
+ }
229
+
175
230
  // src/config-schema-release.ts
176
231
  var PR_DEFAULTS = Object.freeze({
177
232
  prProvider: null,
@@ -240,6 +295,49 @@ var DANGEROUS_RELEASE_SETTINGS = {
240
295
  }
241
296
  };
242
297
 
298
+ // src/config-schema-tests.ts
299
+ import { isAbsolute as isAbsolute2 } from "path";
300
+ var GLOB_PATTERN = "a glob pattern relative to the repository root";
301
+ var repoGlob = (raw, at) => typeof raw === "string" && isAbsolute2(raw) ? refused(at, raw, GLOB_PATTERN) : text(GLOB_PATTERN)(raw, at);
302
+ var globList = listOf(repoGlob, "glob patterns");
303
+ var TESTS_DEFAULTS = Object.freeze({
304
+ testsFullSuiteTriggers: Object.freeze([
305
+ "bunfig.toml",
306
+ "tsconfig*.json",
307
+ "package.json",
308
+ "bun.lock",
309
+ "bun.lockb"
310
+ ]),
311
+ testsIntegration: Object.freeze([
312
+ "**/*-integration.test.ts",
313
+ "**/*.integration.test.ts",
314
+ "**/*-spawned*.test.ts",
315
+ "**/*-cli.test.ts"
316
+ ])
317
+ });
318
+ var TESTS_SETTINGS = {
319
+ testsFullSuiteTriggers: {
320
+ key: "tests.fullSuiteTriggers",
321
+ read: globList,
322
+ cli: false
323
+ },
324
+ testsIntegration: { key: "tests.integration", read: globList, cli: false }
325
+ };
326
+
327
+ // src/config-schema-wrap-up.ts
328
+ var WRAP_UP_RETRIES_MIN = 1;
329
+ var WRAP_UP_RETRIES_MAX = 3;
330
+ function isRetryCount(raw) {
331
+ return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= WRAP_UP_RETRIES_MIN && raw <= WRAP_UP_RETRIES_MAX;
332
+ }
333
+ var wrapUpRetries = (raw, at) => raw === false || isRetryCount(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `false or a whole number from ${String(WRAP_UP_RETRIES_MIN)} to ${String(WRAP_UP_RETRIES_MAX)}`);
334
+ var WRAP_UP_DEFAULTS = Object.freeze({
335
+ loopWrapUpRetries: 1
336
+ });
337
+ var WRAP_UP_SETTINGS = {
338
+ loopWrapUpRetries: { key: "loop.wrapUp.retries", read: wrapUpRetries, cli: false }
339
+ };
340
+
243
341
  // src/tiers/resolve.ts
244
342
  import { readFileSync } from "fs";
245
343
  var VENDORED_HEADER = /^<!-- vendored by rafa from .* on \d{4}-\d{2}-\d{2} -->$/;
@@ -411,6 +509,7 @@ var CONFIG_DEFAULTS = Object.freeze({
411
509
  store: "sqlite",
412
510
  effortBusyTimeoutMs: 5000,
413
511
  effortSync: "local",
512
+ ...HUB_DEFAULTS,
414
513
  inject: "stage",
415
514
  planDir: join(".rafa", "plans"),
416
515
  specsDir: join(".rafa", "specs"),
@@ -430,6 +529,7 @@ var CONFIG_DEFAULTS = Object.freeze({
430
529
  allowList: Object.freeze([]),
431
530
  settingSources: Object.freeze(["project", "local"]),
432
531
  loopWorktreeDir: join(".rafa", "worktrees"),
532
+ ...WRAP_UP_DEFAULTS,
433
533
  ...PR_DEFAULTS,
434
534
  boardTrustedAuthors: Object.freeze([]),
435
535
  boardRelationships: "labels",
@@ -449,13 +549,15 @@ var CONFIG_DEFAULTS = Object.freeze({
449
549
  tiersAgents: new Map,
450
550
  routing: DEFAULT_ROUTING,
451
551
  taskSkills: "planner",
452
- taskLessons: "on"
552
+ taskLessons: "on",
553
+ ...TESTS_DEFAULTS
453
554
  });
454
555
  var SETTINGS = {
455
556
  version: { key: "version", read: oneOf(CONFIG_VERSIONS), cli: false },
456
557
  store: { key: "store", read: oneOf(STORE_BACKENDS), cli: true },
457
558
  effortBusyTimeoutMs: { key: "effort.busyTimeoutMs", read: busyTimeoutMs, cli: false },
458
559
  effortSync: { key: "effort.sync", read: oneOf(SYNC_STRATEGIES), cli: false },
560
+ ...HUB_SETTINGS,
459
561
  inject: { key: "plan.inject", read: oneOf(INJECT_MODES), cli: true },
460
562
  planDir: { key: "plan.dir", read: directory, cli: true },
461
563
  specsDir: { key: "specs.dir", read: directory, cli: true },
@@ -506,6 +608,7 @@ var SETTINGS = {
506
608
  cli: true
507
609
  },
508
610
  loopWorktreeDir: { key: "loop.worktreeDir", read: directory, cli: false },
611
+ ...WRAP_UP_SETTINGS,
509
612
  ...PR_SETTINGS,
510
613
  boardTrustedAuthors: {
511
614
  key: "board.trustedAuthors",
@@ -549,7 +652,8 @@ var SETTINGS = {
549
652
  tiersAgents: { key: "tiers.agents", read: tierPins, cli: false },
550
653
  routing: { key: "routing", read: routeTable, cli: false },
551
654
  taskSkills: { key: "task.skills", read: skillResolverName, cli: true },
552
- taskLessons: { key: "task.lessons", read: lessonSwitch, cli: false }
655
+ taskLessons: { key: "task.lessons", read: lessonSwitch, cli: false },
656
+ ...TESTS_SETTINGS
553
657
  };
554
658
  var SETTING_NAMES = Object.keys(SETTINGS);
555
659
  var SETTING_BY_KEY = new Map(SETTING_NAMES.map((setting) => [
@@ -621,6 +725,9 @@ function readLayer(rawOf, atOf) {
621
725
  store: read("store"),
622
726
  effortBusyTimeoutMs: read("effortBusyTimeoutMs"),
623
727
  effortSync: read("effortSync"),
728
+ hubUrl: read("hubUrl"),
729
+ hubTokenSecret: read("hubTokenSecret"),
730
+ hubTimeout: read("hubTimeout"),
624
731
  inject: read("inject"),
625
732
  planDir: read("planDir"),
626
733
  specsDir: read("specsDir"),
@@ -640,6 +747,7 @@ function readLayer(rawOf, atOf) {
640
747
  allowList: read("allowList"),
641
748
  settingSources: read("settingSources"),
642
749
  loopWorktreeDir: read("loopWorktreeDir"),
750
+ loopWrapUpRetries: read("loopWrapUpRetries"),
643
751
  prProvider: read("prProvider"),
644
752
  prMergeMethod: read("prMergeMethod"),
645
753
  prBase: read("prBase"),
@@ -671,7 +779,9 @@ function readLayer(rawOf, atOf) {
671
779
  tiersAgents: read("tiersAgents"),
672
780
  routing: read("routing"),
673
781
  taskSkills: read("taskSkills"),
674
- taskLessons: read("taskLessons")
782
+ taskLessons: read("taskLessons"),
783
+ testsFullSuiteTriggers: read("testsFullSuiteTriggers"),
784
+ testsIntegration: read("testsIntegration")
675
785
  };
676
786
  return { layer, problems, extras };
677
787
  }
@@ -793,6 +903,15 @@ function resolveConfig(layers = {}) {
793
903
  return { value: CONFIG_DEFAULTS[setting], source: "default" };
794
904
  };
795
905
  const ranked = SETTING_NAMES.map((setting) => [setting, rank(setting)]);
906
+ const effortSync = rank("effortSync");
907
+ const hubProblems = hubUrlProblems({
908
+ effortSync: effortSync.value,
909
+ hubUrl: rank("hubUrl").value,
910
+ effortSyncSource: effortSync.source,
911
+ paths: { file: file?.path ?? null, user: user?.path ?? null }
912
+ });
913
+ if (hubProblems.length > 0)
914
+ throw new ConfigError(hubProblems);
796
915
  const rafaLoaded = ranked.find(([setting]) => setting === "tiersRafa")?.[1].value !== "off";
797
916
  const warnings = [user, file].flatMap((layer) => layer === null ? [] : [
798
917
  ...layer.extras.map((extra) => unknownKeyWarning(extra.key, layer.path)),
@@ -1222,6 +1341,9 @@ function createTextOutput({ verbosity, stream }) {
1222
1341
  writeLine(resultLine(event));
1223
1342
  return;
1224
1343
  }
1344
+ case "event": {
1345
+ return;
1346
+ }
1225
1347
  }
1226
1348
  };
1227
1349
  return Object.freeze({ info, warn, error, debug, emit, result });
@@ -1238,4 +1360,4 @@ function activeOutputMode() {
1238
1360
  return activeMode;
1239
1361
  }
1240
1362
 
1241
- export { PREREQUISITE_KINDS, requiredPrerequisite, optionalPrerequisite, MODULE_SOURCE_KINDS, pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTES, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, isStampableStub, planStubFromPrompt, stampPrompt, planStubFromPath, createTextOutput, activeOutput, activeOutputMode, RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks, REPORT_STATUSES, FINDING_KINDS, FINDING_SIGNALS, FINDING_DOMAINS, CHANGE_LEVELS, parseReport };
1363
+ export { hubContextOf, PREREQUISITE_KINDS, requiredPrerequisite, optionalPrerequisite, MODULE_SOURCE_KINDS, pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTES, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, isStampableStub, planStubFromPrompt, stampPrompt, planStubFromPath, createTextOutput, activeOutput, activeOutputMode, RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks, REPORT_STATUSES, FINDING_KINDS, FINDING_SIGNALS, FINDING_DOMAINS, CHANGE_LEVELS, parseReport };
@@ -80,7 +80,8 @@ var DECLARATION_KEYS = [
80
80
  "effort",
81
81
  "budget",
82
82
  "tools",
83
- "skills"
83
+ "skills",
84
+ "tests"
84
85
  ];
85
86
  var GRANULAR_KEYS = ["model", "effort", "tools"];
86
87
  var AGENT_OWNED_KEYS = ["model", "tools"];
@@ -92,6 +93,8 @@ var EFFORT_LEVELS = [
92
93
  "xhigh",
93
94
  "max"
94
95
  ];
96
+ var TEST_SCOPES = ["affected", "module", "full"];
97
+ var DEFAULT_TEST_SCOPE = "affected";
95
98
  var DECLARATION_BLOCK = /\{([^{}]*)\}$/;
96
99
  var ENTRY_TOKEN = /^([A-Za-z_][A-Za-z0-9_-]*)=(.*)$/;
97
100
  var FULL_MODEL_NAME = /^claude-[a-z0-9][a-z0-9.-]*$/;
@@ -112,6 +115,12 @@ function parseBudgetUsd(value) {
112
115
  function isEffortLevel(value) {
113
116
  return EFFORT_LEVELS.includes(value);
114
117
  }
118
+ function isTestScope(value) {
119
+ return TEST_SCOPES.includes(value);
120
+ }
121
+ function readTestScope(declaration) {
122
+ return declaration?.tests ?? DEFAULT_TEST_SCOPE;
123
+ }
115
124
  function isModelValue(value) {
116
125
  if (MODEL_ALIASES.includes(value))
117
126
  return true;
@@ -166,6 +175,7 @@ function readBlock(raw, body) {
166
175
  let budget = null;
167
176
  let tools = null;
168
177
  let skills = null;
178
+ let tests = null;
169
179
  for (const token of tokenise(body)) {
170
180
  const match = token.match(ENTRY_TOKEN);
171
181
  const key = match?.[1];
@@ -222,6 +232,13 @@ function readBlock(raw, body) {
222
232
  tools = parsed;
223
233
  continue;
224
234
  }
235
+ if (key === "tests") {
236
+ if (isTestScope(value))
237
+ tests = value;
238
+ else
239
+ issues.push(unusableValue(key, token));
240
+ continue;
241
+ }
225
242
  const named = parseSkillList(value);
226
243
  if (named === null)
227
244
  issues.push(unusableValue(key, token));
@@ -240,7 +257,8 @@ function readBlock(raw, body) {
240
257
  effort,
241
258
  budget,
242
259
  tools,
243
- skills
260
+ skills,
261
+ tests
244
262
  };
245
263
  }
246
264
  function parseTaskDeclaration(taskText) {
@@ -315,7 +333,7 @@ var STORE_BACKENDS = ["sqlite", "ndjson"];
315
333
  var SYNC_STRATEGIES = ["local", "file", "git", "service", "p2p"];
316
334
  var BOARD_RELATIONSHIP_MODES = ["labels", "native"];
317
335
  var INJECT_MODES = ["full", "stage", "task"];
318
- var OUTPUT_MODES = ["text", "json"];
336
+ var OUTPUT_MODES = ["text", "json", "events"];
319
337
  var CLAUDE_SETTING_SOURCES = ["user", "project", "local"];
320
338
  var PR_PROVIDERS = ["gh", "none"];
321
339
  var RELEASE_AUTO = "auto";
@@ -425,4 +443,4 @@ function subsetOf(values) {
425
443
  };
426
444
  }
427
445
 
428
- export { MERGE_METHODS, isMergeMethod, SKILL_TIERS, RAFA_INSTINCTS_PATH, BUNDLED_SKILLS_DIR, isSkillTier, realEntry, bundledBinDirectory, skillTierDirectory, resolveSkillTiers, resolveInstinctScopes, tierExists, isAgentName, BUDGET_FLAG, parseBudgetUsd, parseTaskDeclaration, stripTaskDeclaration, resolveDeclarationFlags, isMapping, describeValue, messageOf, CONFIG_VERSIONS, STORE_BACKENDS, SYNC_STRATEGIES, BOARD_RELATIONSHIP_MODES, INJECT_MODES, OUTPUT_MODES, CLAUDE_SETTING_SOURCES, PR_PROVIDERS, RELEASE_AUTO, SKILL_RESOLVERS, CLAIMS_STALE_DISABLED, refused, refusedWith, mapReading, below, oneOf, text, flag, mergeMethod, usdAmount, issueNumber, dayCount, BUSY_TIMEOUT_MIN_MS, BUSY_TIMEOUT_MAX_MS, isBusyTimeoutMs, busyTimeoutMs, confidence, recurrenceCount, releaseEnabled, tierSwitch, tierPin, routeTarget, skillResolverName, lessonSwitch, claimDurationHours, claimsStaleAfter, claimsAhead, isGitHubLogin, githubLogin, listOf, subsetOf };
446
+ export { MERGE_METHODS, isMergeMethod, SKILL_TIERS, RAFA_INSTINCTS_PATH, BUNDLED_SKILLS_DIR, isSkillTier, realEntry, bundledBinDirectory, skillTierDirectory, resolveSkillTiers, resolveInstinctScopes, tierExists, TEST_SCOPES, isAgentName, BUDGET_FLAG, parseBudgetUsd, readTestScope, parseTaskDeclaration, stripTaskDeclaration, resolveDeclarationFlags, isMapping, describeValue, messageOf, CONFIG_VERSIONS, STORE_BACKENDS, SYNC_STRATEGIES, BOARD_RELATIONSHIP_MODES, INJECT_MODES, OUTPUT_MODES, CLAUDE_SETTING_SOURCES, PR_PROVIDERS, RELEASE_AUTO, SKILL_RESOLVERS, CLAIMS_STALE_DISABLED, refused, refusedWith, mapReading, below, oneOf, text, flag, mergeMethod, usdAmount, issueNumber, dayCount, BUSY_TIMEOUT_MIN_MS, BUSY_TIMEOUT_MAX_MS, isBusyTimeoutMs, busyTimeoutMs, confidence, recurrenceCount, releaseEnabled, tierSwitch, tierPin, routeTarget, skillResolverName, lessonSwitch, claimDurationHours, claimsStaleAfter, claimsAhead, isGitHubLogin, githubLogin, listOf, subsetOf };
@@ -4,10 +4,10 @@ import {
4
4
  commandSpelling,
5
5
  isRoutingWord,
6
6
  isTopLevel
7
- } from "./index-mt6hpsry.js";
7
+ } from "./index-3mzw3kzh.js";
8
8
  import {
9
9
  describeValue
10
- } from "./index-rs79dq9e.js";
10
+ } from "./index-fzhd3d4y.js";
11
11
 
12
12
  // src/cli/registry.ts
13
13
  var REFUSAL = "command registry";