@haus-tech/haus-workflow 6.1.0 → 6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [6.2.0](https://github.com/WeAreHausTech/haus-workflow/compare/v6.1.0...v6.2.0) (2026-10-15)
4
+
5
+ ### Features
6
+
7
+ - **request:** remove the per-batch USD cap from bedöm ([#782](https://github.com/WeAreHausTech/haus-workflow/issues/782)) ([5ff7cc0](https://github.com/WeAreHausTech/haus-workflow/commit/5ff7cc0e132545ccf68d6e4a7bc9aa58976da0ee))
8
+
3
9
  ## [6.1.0](https://github.com/WeAreHausTech/haus-workflow/compare/v6.0.0...v6.1.0) (2026-10-15)
4
10
 
5
11
  ### Features
package/dist/cli.js CHANGED
@@ -3170,7 +3170,7 @@ function outcomeLine(o, opts) {
3170
3170
  (p) => `${lead}${word} ${subject(p)}: haus does not own this file. Keep it, replace it with ${opts.force} (backed up first), or delete it by hand.`
3171
3171
  ).join("\n");
3172
3172
  case "kept":
3173
- return `${lead}${word} ${subject(posixPaths.join(", "))}: your edit stays. ${opts.force} replaces it after a backup.`;
3173
+ return `${lead}${word} ${subject(posixPaths.join(", "))}: your edit stays. ${opts.force} ${opts.forceVerb ?? "replaces"} it after a backup.`;
3174
3174
  case "replaced": {
3175
3175
  const where = o.backupDir ? `: previous copy in .haus-workflow/backups/${o.backupDir}/` : "";
3176
3176
  return `${lead}${word} ${subject(posixPaths.join(", "))}${where}`;
@@ -3224,6 +3224,7 @@ function backupFailedLine(paths, id, message2, opts = {}) {
3224
3224
  const subject = (opts.onDisk === true ? [...new Set(paths)] : posixPathsOnce(paths)).join(", ");
3225
3225
  return `backup failed for ${id === void 0 ? subject : `${subject} ${bracketedId(id)}`}: ${message2}. Left as it was.`;
3226
3226
  }
3227
+ var WHAT_HAUS_WOULD_WRITE = "what haus would write";
3227
3228
  function couldNotCompareLine(file, message2, against = "the catalog") {
3228
3229
  return `could not compare ${file} with ${against}: ${message2}`;
3229
3230
  }
@@ -7639,7 +7640,7 @@ ${opts.body}`;
7639
7640
  };
7640
7641
  if (onDisk.kind === "unreadable") {
7641
7642
  if (opts.force) return replaceAfterBackup("kept");
7642
- warn(`could not compare ${relPath} with the catalog: ${onDisk.message}`);
7643
+ warn(couldNotCompareLine(relPath, onDisk.message, WHAT_HAUS_WOULD_WRITE));
7643
7644
  return report("kept");
7644
7645
  }
7645
7646
  const current = verdictText(onDisk);
@@ -7651,10 +7652,12 @@ ${opts.body}`;
7651
7652
  case "refused": {
7652
7653
  const refusal = verdict.refusal;
7653
7654
  if (refusal?.kind === "another-id") {
7654
- warn(`${printable}: HAUS-MANAGED id mismatch (expected ${opts.id}), skipping`);
7655
+ warn(
7656
+ `refused ${recordedRel(relPath)} (${opts.id}): its HAUS-MANAGED header names another id. haus left the file as it was; fix the header or delete the file by hand.`
7657
+ );
7655
7658
  } else if (refusal?.kind === "newer-format") {
7656
7659
  warn(
7657
- `${printable}: written by a newer haus (template v${refusal.v}), upgrade the CLI to manage it`
7660
+ `refused ${recordedRel(relPath)} (${opts.id}): written by a newer haus (template v${refusal.v}). haus left the file as it was; upgrade the haus CLI to manage it.`
7658
7661
  );
7659
7662
  } else {
7660
7663
  return report("refused");
@@ -8349,7 +8352,7 @@ async function writeClaudeFilesReport(root, dryRun, selectedIds, opts = {}) {
8349
8352
  const lockRecord = lockWrite === "unchanged" ? { file: LOCK_FILE, outcome: "unchanged", added: [], removed: [], reRecorded: [] } : {
8350
8353
  file: LOCK_FILE,
8351
8354
  outcome: "changed",
8352
- ...recordDelta(prevLock, carried.rows, ["catalogRef"])
8355
+ ...recordDelta(namedRows(prevLock), namedRows(carried.rows), ["catalogRef"])
8353
8356
  };
8354
8357
  for (const outcome of carried.dropped) printOutcome(outcome);
8355
8358
  if (!opts.callerPrintsRecords) say(recordLine(lockRecord, dryRun));
@@ -8515,7 +8518,7 @@ async function ownershipGate({
8515
8518
  if (force) {
8516
8519
  return stands && prevRow !== void 0 ? await replaceAfterBackup([...recorded, ...target], prevRow) : await replaceAfterBackup(target);
8517
8520
  }
8518
- warn(`could not compare ${item.id} with the catalog: ${messageOf(err)}`);
8521
+ warn(couldNotCompareLine(item.id, messageOf(err)));
8519
8522
  return stands && prevRow !== void 0 ? { action: "skip", outcome: "kept", row: prevRow } : { action: "skip", outcome: "refused" };
8520
8523
  }
8521
8524
  }
@@ -14338,7 +14341,7 @@ async function scaffoldConfigItems(projectRoot, catalogRoot, items, opts = {}) {
14338
14341
  entries.forEach((entry, i) => {
14339
14342
  const state = states[i];
14340
14343
  if (state.kind === "unreadable") {
14341
- warn(`could not compare ${entry.name} with the catalog: ${state.message}`);
14344
+ warn(couldNotCompareLine(entry.name, state.message));
14342
14345
  }
14343
14346
  });
14344
14347
  refused.push(item.id);
@@ -18479,7 +18482,7 @@ async function runRemove(ids, options = {}) {
18479
18482
  const gate = await hashGateEntry(root, { hash }, existing);
18480
18483
  if (!gate.ok && !force) {
18481
18484
  const kept = { id, paths: existing.map((e) => e.rel), outcome: "kept" };
18482
- warn(outcomeLine(kept, { dryRun, force: `haus remove ${id} --force` }));
18485
+ warn(outcomeLine(kept, { dryRun, force: `haus remove ${id} --force`, forceVerb: "removes" }));
18483
18486
  report.skipped.push({ id, reason: gate.reason });
18484
18487
  continue;
18485
18488
  }
@@ -18747,6 +18750,7 @@ init_fs();
18747
18750
  init_logger();
18748
18751
  init_paths();
18749
18752
  var FORCE_COMMAND = "haus undo --force";
18753
+ var FORCE_LINE = { force: FORCE_COMMAND, forceVerb: "removes" };
18750
18754
  var REFUSED_REASON = {
18751
18755
  symlink: "recorded path is a symlink or reaches through one",
18752
18756
  "escapes-root": "recorded path is outside the project root"
@@ -18962,11 +18966,11 @@ async function runUndo(options) {
18962
18966
  );
18963
18967
  for (const plan of keptCore) {
18964
18968
  if (plan.unreadable !== void 0) {
18965
- warn(couldNotCompareLine(relOf(plan.abs), plan.unreadable));
18969
+ warn(couldNotCompareLine(relOf(plan.abs), plan.unreadable, WHAT_HAUS_WOULD_WRITE));
18966
18970
  continue;
18967
18971
  }
18968
18972
  const kept = { id: RULES_HAUS_ID, paths: [relOf(plan.abs)], outcome: "kept" };
18969
- warn(outcomeLine(kept, { dryRun, force: FORCE_COMMAND }));
18973
+ warn(outcomeLine(kept, { dryRun, ...FORCE_LINE }));
18970
18974
  }
18971
18975
  for (const plan of leftCore) warn(notRegularLine(relOf(plan.abs)));
18972
18976
  for (const { item } of keptItems) {
@@ -18975,7 +18979,7 @@ async function runUndo(options) {
18975
18979
  paths: item.existing.map((e) => e.rel),
18976
18980
  outcome: "kept"
18977
18981
  };
18978
- warn(outcomeLine(kept, { dryRun, force: FORCE_COMMAND }));
18982
+ warn(outcomeLine(kept, { dryRun, ...FORCE_LINE }));
18979
18983
  }
18980
18984
  const removedRels = new Map(
18981
18985
  toDelete.map(({ item, paths }) => [item, new Set(paths.map((p) => p.rel))])
@@ -19026,7 +19030,7 @@ async function runUndo(options) {
19026
19030
  }
19027
19031
  }
19028
19032
  const settleLock = async () => {
19029
- for (const outcome of gone) log(outcomeLine(outcome, { dryRun, force: FORCE_COMMAND }));
19033
+ for (const outcome of gone) log(outcomeLine(outcome, { dryRun, ...FORCE_LINE }));
19030
19034
  if (!lockExisted) return;
19031
19035
  if (carried.length === 0) {
19032
19036
  if (dryRun) return;
@@ -22055,7 +22059,8 @@ async function removeLinkedCopies(workspaceRoot, entries, opts, say) {
22055
22059
  result.outcomes.push(outcome);
22056
22060
  const line2 = outcomeLine(outcome, {
22057
22061
  dryRun: opts.dryRun,
22058
- force: opts.forceCommand ?? LINK_CONTEXT_FORCE
22062
+ force: opts.forceCommand ?? LINK_CONTEXT_FORCE,
22063
+ forceVerb: "removes"
22059
22064
  });
22060
22065
  if (outcomeStream(outcome.outcome) === "warn") stderr(line2);
22061
22066
  else say(line2);
@@ -23031,7 +23036,7 @@ async function runWorkspaceLinkContext(workspaceRoot, opts = {}) {
23031
23036
  `Linked ${result.linked.length} skill/agent/command copy(ies) into .claude/ (${result.added.length} new, ${result.removed.length} removed${left}).`
23032
23037
  );
23033
23038
  log(
23034
- "Source of truth for each copy stays in its own member repo: edit the source, not the copy, and re-run `haus workspace link-context --write` after editing a source, or when `haus workspace doctor` flags one stale. A copy edited here is kept until `haus workspace link-context --write --force` replaces it after a backup."
23039
+ "Source of truth for each copy stays in its own member repo: edit the source, not the copy, and re-run `haus workspace link-context --write` after editing a source, or when `haus workspace doctor` flags one stale. A copy edited here is kept until `haus workspace link-context --write --force` replaces it after a backup, or removes it when its source is gone."
23035
23040
  );
23036
23041
  }
23037
23042
  function leftAsTheyAre(kept, refused) {
@@ -23457,9 +23462,9 @@ function reportRootRefusals(plan, opts) {
23457
23462
  const doc = plan.doc;
23458
23463
  if (doc.kind === "kept" && !opts.force) {
23459
23464
  warn(
23460
- doc.unreadable !== void 0 ? couldNotCompareLine(WORKSPACE_DOC_FILE, doc.unreadable) : outcomeLine(
23465
+ doc.unreadable !== void 0 ? couldNotCompareLine(WORKSPACE_DOC_FILE, doc.unreadable, WHAT_HAUS_WOULD_WRITE) : outcomeLine(
23461
23466
  { id: WORKSPACE_DOC_ID, paths: [WORKSPACE_DOC_FILE], outcome: "kept" },
23462
- { dryRun: opts.dryRun, force: WORKSPACE_UNDO_FORCE }
23467
+ { dryRun: opts.dryRun, force: WORKSPACE_UNDO_FORCE, forceVerb: "removes" }
23463
23468
  )
23464
23469
  );
23465
23470
  }
@@ -744,15 +744,14 @@ dispatches no agent and runs no check in this leg. `--repo-rot` is the checkout
744
744
  code the assessor reads (the session's cwd; a worktree is fine) and `--arkiv` is
745
745
  `ARKIVROT:` from `rot`. The starter writes the running receipt (`archive.mjs korning-start`,
746
746
  `state.korning`) before the process starts and clears it after
747
- (`korning-slut`), skips an item whose receipt carries a living pid (`pågår`), and stops
748
- starting items when the batch's cost reaches `max_usd_per_batch` in
749
- `.haus-workflow/request.json` (default 100 USD; `--max-usd` overrides one run), counting an
750
- item in flight at the average of the finished ones. Read its
747
+ (`korning-slut`), and skips an item whose receipt carries a living pid (`pågår`). There is
748
+ no spend cap: every item that passes the gate starts, and the cost shows instead, as the
749
+ USD per item in the table and the total spent on the line under it (ADR-0162). Read its
751
750
  final table (`| post | status | poäng | utfall | wall | USD |`), paste it under the BLUF
752
751
  in step 8, and route every row by its status: `priced` goes on to step 8, `stopp` and
753
752
  `väntar på dom` take the stop and OLIKA routing below, `ofärdig` shows the reason from
754
- the table and `<post>/korningar/<körning>/stderr.log`, `grind` and `tak nått` show the
755
- reason and stop, and a `pågår` row is left alone.
753
+ the table and `<post>/korningar/<körning>/stderr.log`, `grind` shows the
754
+ reason and stops, and a `pågår` row is left alone.
756
755
  `bedom.mjs` passes the board's design mode on to `korning.mjs` as `--design-mode`
757
756
  (`design_mode` in `.haus-workflow/request.json`; `interview` and an absent key read as
758
757
  `intervju`; the flag overrides one run). In draft mode the process drafts a missing design
@@ -2015,22 +2014,20 @@ reference files whose rules it mirrors and WARNS when a catalog bump has changed
2015
2014
  and skipped. `--arkiv` is the archive root; omitted, it is derived from
2016
2015
  `--repo-rot`'s git common dir (ADR-0154). Exit 0 when no run became
2017
2016
  `ofärdig`, 1 otherwise, 2 on a usage error.
2018
- - `scripts/bedom.mjs --repo-rot <abs> [--arkiv <abs>] --post <gid|gid/del-N>... [--parallellt 2] [--max-usd <n>] [--claude <kommando>] [--om] [--sprak <svenska|engelska>]`:
2017
+ - `scripts/bedom.mjs --repo-rot <abs> [--arkiv <abs>] --post <gid|gid/del-N>... [--parallellt 2] [--claude <kommando>] [--om] [--sprak <svenska|engelska>]`:
2019
2018
  production's starter (see `bedöm`), one `korning.mjs --post` process per item, two at a
2020
2019
  time. `--post` is relative to the archive root (`--arkiv`, or derived from `--repo-rot`'s
2021
2020
  git common dir as in `svep.mjs`); an absolute `--post` is a usage error. Per item: the
2022
2021
  receipt via `archive.mjs korning-start`/`korning-slut` (the latter always, also when the
2023
2022
  run fails), the run directory `<post>/korningar/<stämpel>/` with `stderr.log`,
2024
- `matning.json` and the raw replies under `steg/`, the cap from `request.json`
2025
- (`max_usd_per_batch`, default 100 USD, `--max-usd` overrides; once the finished items'
2026
- USD, plus each item in flight at the average of the finished ones, reaches it no further
2027
- item starts, `tak nått`, and a running item is never killed), `--startare <its own pid>` on
2023
+ `matning.json` and the raw replies under `steg/`, no spend cap (every item that passes
2024
+ the gate starts, ADR-0162), `--startare <its own pid>` on
2028
2025
  every `korning.mjs` it starts, SIGINT and SIGTERM both killing the running items and
2029
2026
  clearing their receipts (exit 130),
2030
2027
  and the final table `| post | status | poäng | utfall | wall | USD |` in argument order
2031
- with the line `tak: <n> USD, använt: <m> USD`. Exit 0 when every item ended in a result
2032
- (`priced`, `stopp`, `väntar på dom`), 1 on `ofärdig`, `pågår`, `grind` or `tak nått`, 2
2033
- on a usage error (ADR-0155).
2028
+ with the line `använt: <m> USD`. Exit 0 when every item ended in a result
2029
+ (`priced`, `stopp`, `väntar på dom`), 1 on `ofärdig`, `pågår` or `grind`, 2
2030
+ on a usage error (ADR-0155, ADR-0162).
2034
2031
  `bedom.mjs` takes `--design-mode draft|intervju` and passes it to every `korning.mjs` it
2035
2032
  starts; without the flag the value is `request.json`'s `design_mode` (`interview` is read
2036
2033
  as `intervju`), and without that key `intervju` (ADR-0156).
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Startaren för produktionens prisning (ADR-0155 beslut 1, 3, 4 och 5):
3
+ * Startaren för produktionens prisning (ADR-0155 beslut 1, 3 och 5; beslut 4
4
+ * ersatt av ADR-0162):
4
5
  * `bedöm`:s steg 3 till 7 körs som EN `korning.mjs`-process per post i
5
6
  * produktionsläget (`--post`), startad härifrån, så huvudkonversationen
6
7
  * dispatchar ingen agent för prisbenet. Huvudkonversationen behåller grinden,
@@ -9,7 +10,7 @@
9
10
  *
10
11
  * Användning:
11
12
  * node bedom.mjs --repo-rot <abs> [--arkiv <abs>] --post <gid|gid/del-N> [--post ...]...
12
- * [--parallellt 2] [--max-usd <n>] [--claude <kommando>] [--om]
13
+ * [--parallellt 2] [--claude <kommando>] [--om]
13
14
  * [--sprak <svenska|engelska>] [--design-mode <draft|intervju>]
14
15
  *
15
16
  * `--post` är relativ arkivroten: `--arkiv` när den ges (ARKIVROT: från
@@ -20,7 +21,7 @@
20
21
  * Per post, i ordning: förkontroll (state.json läsbar, ingen experimentkatalog,
21
22
  * ingen splitrot med `del-N/` under sig, `approval` satt, inget stående
22
23
  * `stopp`, inte redan `priced`/`guard_run` utan `--om`; annars raden `grind`
23
- * och inget startas), taket, körningskatalogen
24
+ * och inget startas), körningskatalogen
24
25
  * `<post>/korningar/<YYYYMMDDTHHMMSS>/`, kvittot `archive.mjs korning-start`
25
26
  * (en levande pid ger raden `pågår` och den tomma katalogen tas bort),
26
27
  * `korning.mjs` med `stderr.log` och `matning.json` i körningskatalogen och
@@ -28,22 +29,17 @@
28
29
  * `korning.json`:s `total_cost_usd`, `archive.mjs sparr` och statusen. Kvittot
29
30
  * rensas alltid med `archive.mjs korning-slut` i en finally.
30
31
  *
31
- * Taket (beslut 4): `max_usd_per_batch` i `.haus-workflow/request.json`
32
- * (`<arkiv>/../request.json`), 100 USD när nyckeln saknas, `--max-usd` vinner
33
- * för en körning. Före varje poststart jämförs summan mot taket: de klara
34
- * posterna med sin USD plus varje post i flykt till de klaras snittkostnad
35
- * (0 så länge ingen är klar). När summan nått taket startas inga fler poster
36
- * (raden `tak nått`), och ingen pågående körning dödas. Två poster som startar
37
- * samtidigt innan någon är klar passerar båda kontrollen: det är accepterat,
38
- * taket stoppar nästa start och aldrig en körning som pågår.
32
+ * Inget tak (ADR-0162 ersätter ADR-0155 beslut 4): varje post som klarar
33
+ * förkontrollen startas, oavsett vad batchen kostat. Kostnaden syns i stället:
34
+ * USD per post i tabellen och summan på sista raden.
39
35
  *
40
36
  * stdout under körningen: `START <post>`, `KLAR <post> <status>`,
41
- * `GRIND <post>: <orsak>`, `PÅGÅR <post> (pid N)`, `TAK <post>`; till sist
37
+ * `GRIND <post>: <orsak>`, `PÅGÅR <post> (pid N)`; till sist
42
38
  * tabellen `| post | status | poäng | utfall | wall | USD |` och raden
43
- * `tak: <n> USD, använt: <m.mm> USD`.
39
+ * `använt: <m.mm> USD`.
44
40
  *
45
41
  * Exit 0 = varje rad är `priced`, `stopp` eller `väntar på dom`; 1 = minst en
46
- * rad är `ofärdig`, `pågår`, `grind` eller `tak nått`; 2 = användningsfel.
42
+ * rad är `ofärdig`, `pågår` eller `grind`; 2 = användningsfel.
47
43
  * SIGINT och SIGTERM skickar SIGTERM till varje pågående körning, skriver
48
44
  * matning.json med signalen, rensar varje kvitto med korning-slut och avslutar
49
45
  * med 130. Ett oväntat kast i huvudloopen skrivs på stderr och ger exit 2.
@@ -58,30 +54,20 @@ const HAR = path.dirname(fileURLToPath(import.meta.url))
58
54
  const ARCHIVE = path.join(HAR, 'archive.mjs')
59
55
  const KORNING = path.join(HAR, 'korning.mjs')
60
56
 
61
- export const STANDARD_TAK_USD = 100
62
57
  const STANDARD_PARALLELLT = 2
63
58
  const SIGNAL_EXIT = 130
64
59
  /** Signalerna som avbryter batchen; samma hanterare för båda. */
65
60
  export const AVBROTTSSIGNALER = ['SIGINT', 'SIGTERM']
66
61
  const SPRAKEN = ['svenska', 'engelska']
67
62
  const DESIGNLAGEN = ['draft', 'intervju']
68
- const VARDEFLAGGOR = [
69
- 'repo-rot',
70
- 'arkiv',
71
- 'post',
72
- 'parallellt',
73
- 'max-usd',
74
- 'claude',
75
- 'sprak',
76
- 'design-mode',
77
- ]
63
+ const VARDEFLAGGOR = ['repo-rot', 'arkiv', 'post', 'parallellt', 'claude', 'sprak', 'design-mode']
78
64
  const BOOLFLAGGOR = ['om']
79
65
  /** Statusar som är ett resultat: exit 0 när varje rad bär en av dem. */
80
66
  const RESULTAT = ['priced', 'stopp', 'väntar på dom']
81
67
 
82
68
  export const ANVANDNING = [
83
69
  'användning: bedom.mjs --repo-rot <abs> [--arkiv <abs>] --post <gid|gid/del-N> [--post ...]...',
84
- ` [--parallellt ${STANDARD_PARALLELLT}] [--max-usd <n>] [--claude <kommando>] [--om]`,
70
+ ` [--parallellt ${STANDARD_PARALLELLT}] [--claude <kommando>] [--om]`,
85
71
  ` [--sprak <${SPRAKEN.join('|')}>] [--design-mode <${DESIGNLAGEN.join('|')}>]`,
86
72
  ].join('\n')
87
73
 
@@ -127,12 +113,6 @@ export function tolkaArgv(argv) {
127
113
  const parText = enkla.parallellt ?? String(STANDARD_PARALLELLT)
128
114
  if (!/^\d+$/.test(parText) || Number(parText) < 1)
129
115
  return { fel: `--parallellt måste vara ett heltal >= 1 (fick "${parText}")` }
130
- let maxUsd = null
131
- if (enkla['max-usd'] !== undefined) {
132
- maxUsd = Number(enkla['max-usd'])
133
- if (enkla['max-usd'].trim() === '' || !Number.isFinite(maxUsd) || maxUsd < 0)
134
- return { fel: `--max-usd måste vara ett tal >= 0 (fick "${enkla['max-usd']}")` }
135
- }
136
116
  if (enkla.sprak !== undefined && !SPRAKEN.includes(enkla.sprak))
137
117
  return { fel: `--sprak måste vara ${SPRAKEN.join(' eller ')} (fick "${enkla.sprak}")` }
138
118
  if (enkla['design-mode'] !== undefined && !DESIGNLAGEN.includes(enkla['design-mode']))
@@ -144,7 +124,6 @@ export function tolkaArgv(argv) {
144
124
  arkiv: enkla.arkiv ?? null,
145
125
  poster: normerade,
146
126
  parallellt: Number(parText),
147
- maxUsd,
148
127
  claude: enkla.claude ?? 'claude',
149
128
  om,
150
129
  sprak: enkla.sprak ?? null,
@@ -164,16 +143,6 @@ export function losPost(post, arkiv) {
164
143
  return { dir }
165
144
  }
166
145
 
167
- /** Taket för körningen: flaggan vinner, sedan `max_usd_per_batch` i
168
- * `<arkiv>/../request.json` (`.haus-workflow/request.json`), sedan 100. En
169
- * saknad eller trasig fil är defaulten, aldrig ett fel. */
170
- export function lasTak({ arkiv, maxUsd = null }) {
171
- if (maxUsd !== null && maxUsd !== undefined) return maxUsd
172
- const v = lasRequestJson(arkiv)?.max_usd_per_batch
173
- if (typeof v === 'number' && Number.isFinite(v) && v >= 0) return v
174
- return STANDARD_TAK_USD
175
- }
176
-
177
146
  /** `<arkiv>/../request.json` som objekt, eller null när den saknas eller är
178
147
  * trasig (defaulten gäller då, aldrig ett fel). */
179
148
  function lasRequestJson(arkiv) {
@@ -294,9 +263,6 @@ export function avgorStatus({ exitCode, signal = null, state, sparrExit }) {
294
263
  return { status: 'ofärdig', orsak: `status ${state?.status ?? 'okänd'} utan stopp eller spärr` }
295
264
  }
296
265
 
297
- /** Har summan (de klara posterna plus de i flykt till snittet) nått taket? */
298
- export const kapNatt = (summaUsd, tak) => summaUsd >= tak
299
-
300
266
  /** Standardlöparen för archive.mjs: synkron, cwd i posten. */
301
267
  export const arkivStandard = (args, cwd) =>
302
268
  spawnSync(process.execPath, [ARCHIVE, ...args], { cwd, encoding: 'utf8' })
@@ -421,7 +387,7 @@ const lasUsd = (runDir) => {
421
387
  /** En post, hela ordningen ur ADR-0155. Kastar aldrig medvetet; ett kast
422
388
  * blir en `ofärdig`-rad i korBatch. */
423
389
  async function korPost(post, ctx) {
424
- const { ut, arkivKor, korKorning, kvitton, summa, tak, konto } = ctx
390
+ const { ut, arkivKor, korKorning, kvitton, konto } = ctx
425
391
  const rad = (status, extra = {}) => ({ post, status, ...extra })
426
392
  const los = losPost(post, ctx.arkiv)
427
393
  if (los.fel) {
@@ -439,10 +405,6 @@ async function korPost(post, ctx) {
439
405
  ut(`GRIND ${post}: ${grind}`)
440
406
  return rad('grind', { orsak: grind, ...lasPoang(dir) })
441
407
  }
442
- if (kapNatt(summa(), tak)) {
443
- ut(`TAK ${post}`)
444
- return rad('tak nått')
445
- }
446
408
  const runDir = korningsKatalog(dir, ctx.now ? ctx.now() : new Date())
447
409
  const start = startaKorning(dir, ctx.pid ?? process.pid, runDir, { arkivKor })
448
410
  if (start.pagar) {
@@ -457,7 +419,6 @@ async function korPost(post, ctx) {
457
419
  }
458
420
  if (start.varning) console.error(`${post}: ${start.varning}`)
459
421
  kvitton.add(dir)
460
- konto.iFlykt++
461
422
  let belopp = null
462
423
  try {
463
424
  ut(`START ${post}`)
@@ -488,10 +449,7 @@ async function korPost(post, ctx) {
488
449
  usd: belopp,
489
450
  })
490
451
  } finally {
491
- // Posten är klar för taket: ur flykten, in bland de klara med sin USD
492
- // (en post utan korning.json räknas som 0).
493
- konto.iFlykt--
494
- konto.klara++
452
+ // Postens USD in i summan (en post utan korning.json räknas som 0).
495
453
  if (Number.isFinite(belopp)) konto.anvant += belopp
496
454
  const slut = avslutaKorning(dir, { arkivKor })
497
455
  if (!slut.ok) console.error(`VARNING ${post}: ${slut.fel}`)
@@ -499,20 +457,14 @@ async function korPost(post, ctx) {
499
457
  }
500
458
  }
501
459
 
502
- /** Summan taket prövas mot: de klara posternas USD plus varje post i flykt
503
- * till de klaras snittkostnad (0 så länge ingen är klar). */
504
- export const taksumma = ({ anvant, klara, iFlykt }) =>
505
- anvant + (klara > 0 ? iFlykt * (anvant / klara) : 0)
506
-
507
- /** Kör posterna med högst `parallellt` i flykt. Taket prövas vid varje
508
- * poststart mot `taksumma` (en post utan korning.json räknas som 0).
509
- * Returnerar raderna i argv-ordning och de klara posternas summa. */
460
+ /** Kör posterna med högst `parallellt` i flykt. Returnerar raderna i
461
+ * argv-ordning och de klara posternas summa (en post utan korning.json
462
+ * räknas som 0). */
510
463
  export async function korBatch({
511
464
  poster,
512
465
  arkiv,
513
466
  repoRot,
514
467
  parallellt,
515
- tak,
516
468
  om,
517
469
  claude,
518
470
  sprak,
@@ -525,7 +477,7 @@ export async function korBatch({
525
477
  pid = process.pid,
526
478
  now,
527
479
  }) {
528
- const konto = { anvant: 0, klara: 0, iFlykt: 0 }
480
+ const konto = { anvant: 0 }
529
481
  const ctx = {
530
482
  arkiv,
531
483
  repoRot,
@@ -533,7 +485,6 @@ export async function korBatch({
533
485
  claude,
534
486
  sprak,
535
487
  designMode,
536
- tak,
537
488
  ut,
538
489
  arkivKor,
539
490
  korKorning,
@@ -542,7 +493,6 @@ export async function korBatch({
542
493
  pid,
543
494
  now,
544
495
  konto,
545
- summa: () => taksumma(konto),
546
496
  }
547
497
  const resultat = await schemalagg(poster, parallellt, (post) => korPost(post, ctx))
548
498
  const rader = resultat.map((r, i) =>
@@ -604,7 +554,6 @@ async function main(argv) {
604
554
  console.error(ANVANDNING)
605
555
  return 2
606
556
  }
607
- const tak = lasTak({ arkiv, maxUsd: val.maxUsd })
608
557
  const designMode = lasDesignlage({ arkiv, designMode: val.designMode })
609
558
  const ut = (rad) => process.stdout.write(rad + '\n')
610
559
  const pagaende = new Map()
@@ -617,7 +566,6 @@ async function main(argv) {
617
566
  arkiv,
618
567
  repoRot: val.repoRot,
619
568
  parallellt: val.parallellt,
620
- tak,
621
569
  om: val.om,
622
570
  claude: val.claude,
623
571
  sprak: val.sprak,
@@ -628,7 +576,7 @@ async function main(argv) {
628
576
  })
629
577
  ut('')
630
578
  ut(renderaTabell(rader))
631
- ut(`tak: ${tak} USD, använt: ${anvant.toFixed(2)} USD`)
579
+ ut(`använt: ${anvant.toFixed(2)} USD`)
632
580
  return rader.every((r) => RESULTAT.includes(r.status)) ? 0 : 1
633
581
  }
634
582
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haus-tech/haus-workflow",
3
- "version": "6.1.0",
3
+ "version": "6.2.0",
4
4
  "description": "Haus AI workflow CLI for Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {