@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 +6 -0
- package/dist/cli.js +21 -16
- package/library/global/skills/request/SKILL.md +11 -14
- package/library/global/skills/request/scripts/bedom.mjs +19 -71
- package/package.json +1 -1
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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`)
|
|
748
|
-
|
|
749
|
-
|
|
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`
|
|
755
|
-
reason and
|
|
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] [--
|
|
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/`,
|
|
2025
|
-
|
|
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 `
|
|
2032
|
-
(`priced`, `stopp`, `väntar på dom`), 1 on `ofärdig`, `pågår
|
|
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
|
|
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] [--
|
|
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),
|
|
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
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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)
|
|
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
|
-
* `
|
|
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
|
|
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}] [--
|
|
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,
|
|
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
|
-
//
|
|
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
|
-
/**
|
|
503
|
-
*
|
|
504
|
-
|
|
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
|
|
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(`
|
|
579
|
+
ut(`använt: ${anvant.toFixed(2)} USD`)
|
|
632
580
|
return rader.every((r) => RESULTAT.includes(r.status)) ? 0 : 1
|
|
633
581
|
}
|
|
634
582
|
|