@haus-tech/haus-workflow 6.0.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 +17 -0
- package/dist/cli.js +1910 -834
- package/library/global/skills/haus-workflow/SKILL.md +5 -2
- package/library/global/skills/haus-workflow/references/new.md +1 -1
- package/library/global/skills/request/SKILL.md +19 -19
- package/library/global/skills/request/scripts/archive.mjs +48 -17
- package/library/global/skills/request/scripts/bedom.mjs +19 -71
- package/package.json +4 -3
|
@@ -117,8 +117,11 @@ After the command completes, follow the relevant post-run steps below.
|
|
|
117
117
|
first; user content preserved), then re-runs setup from scratch. Say what it keeps:
|
|
118
118
|
an item the user edited and its lock row, and a `.claude/rules/haus.md` haus did not
|
|
119
119
|
write. `haus undo --force` removes those too, after a backup, except a
|
|
120
|
-
`.claude/rules/haus.md` that is a link or a folder, which stays either way
|
|
121
|
-
it
|
|
120
|
+
`.claude/rules/haus.md` that is a link or a folder, which stays either way. In workspace
|
|
121
|
+
scope it also keeps a linked copy edited at the workspace root and a
|
|
122
|
+
`.haus-workflow/WORKSPACE.md` haus does not own; `haus workspace undo --force` removes
|
|
123
|
+
those too, with what each member keeps, after a backup, a link or a folder again
|
|
124
|
+
excepted. Mention it, but never add `--force` yourself. On confirm run
|
|
122
125
|
`haus undo --yes` (project) or `haus workspace undo --yes` (workspace), then
|
|
123
126
|
continue by the scope already detected in Step 1.5 — workspace: step 1 below
|
|
124
127
|
(deep-docs ask, `haus workspace setup --write`, per-member documentation pass,
|
|
@@ -222,7 +222,7 @@ stay there.
|
|
|
222
222
|
finds no tests at all. The skeleton below fills in the real body once the runner
|
|
223
223
|
config is decided; what matters here is that the key exists first.
|
|
224
224
|
4. Write: `haus apply --write`. It reads the profile: `.haus-workflow/WORKFLOW.md` now
|
|
225
|
-
starts with `# PoC Workflow Standard`, and there is no
|
|
225
|
+
starts with `# PoC Workflow Standard`, and there is no haus gate (`lefthook.yml`).
|
|
226
226
|
|
|
227
227
|
Fast path: the chained init already ran `haus apply --write` inside Phase 3, before this
|
|
228
228
|
phase's `"manus"` script exists, so `.haus-workflow/workflow-config.md`'s "Run the manus"
|
|
@@ -236,11 +236,14 @@ its stop (`designa` step 5), with no runs row, since the design is no dispatch.
|
|
|
236
236
|
later): an item never goes a third spec round on the same choice. Older archives
|
|
237
237
|
lack the field and are read as `0`.
|
|
238
238
|
- `coverage_post` mirrors the score envelope's optional `coverage_post: { yta, omfattning }`
|
|
239
|
-
(ADR-0119)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
(ADR-0119) from the score pricing file that counts, the same file `bluf` reads the score
|
|
240
|
+
from: the round's main file, or the file a ruling's `galler_fil` names (ADR-0159).
|
|
241
|
+
`archive.mjs` recomputes it on `add-run` of a score pricing file, on `utslag` on the
|
|
242
|
+
score axis and on `set-status priced`, and sets it to `null` when that file has no
|
|
243
|
+
post or is not written yet; `respec` clears it. A `-run2` file sets it exactly when a
|
|
244
|
+
ruling makes it the counting file. Never write the field by hand. The skeleton
|
|
245
|
+
(`ny-korning`/`ny-del`) sets it to `null`. `bluf` shows `täckningspost: <yta>` in the
|
|
246
|
+
`anm` column when the field is set.
|
|
244
247
|
- `design` is written ONLY by `archive.mjs add-design` and reset ONLY by
|
|
245
248
|
`archive.mjs respec`: `{ "path": "<absolute path to the canonical file in the repo>",
|
|
246
249
|
"file": "design.md", "sha256": "<marker-stripped hash of design.md, identical to the canonical file>",
|
|
@@ -741,15 +744,14 @@ dispatches no agent and runs no check in this leg. `--repo-rot` is the checkout
|
|
|
741
744
|
code the assessor reads (the session's cwd; a worktree is fine) and `--arkiv` is
|
|
742
745
|
`ARKIVROT:` from `rot`. The starter writes the running receipt (`archive.mjs korning-start`,
|
|
743
746
|
`state.korning`) before the process starts and clears it after
|
|
744
|
-
(`korning-slut`), skips an item whose receipt carries a living pid (`pågår`)
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
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
|
|
748
750
|
final table (`| post | status | poäng | utfall | wall | USD |`), paste it under the BLUF
|
|
749
751
|
in step 8, and route every row by its status: `priced` goes on to step 8, `stopp` and
|
|
750
752
|
`väntar på dom` take the stop and OLIKA routing below, `ofärdig` shows the reason from
|
|
751
|
-
the table and `<post>/korningar/<körning>/stderr.log`, `grind`
|
|
752
|
-
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.
|
|
753
755
|
`bedom.mjs` passes the board's design mode on to `korning.mjs` as `--design-mode`
|
|
754
756
|
(`design_mode` in `.haus-workflow/request.json`; `interview` and an absent key read as
|
|
755
757
|
`intervju`; the flag overrides one run). In draft mode the process drafts a missing design
|
|
@@ -2012,22 +2014,20 @@ reference files whose rules it mirrors and WARNS when a catalog bump has changed
|
|
|
2012
2014
|
and skipped. `--arkiv` is the archive root; omitted, it is derived from
|
|
2013
2015
|
`--repo-rot`'s git common dir (ADR-0154). Exit 0 when no run became
|
|
2014
2016
|
`ofärdig`, 1 otherwise, 2 on a usage error.
|
|
2015
|
-
- `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>]`:
|
|
2016
2018
|
production's starter (see `bedöm`), one `korning.mjs --post` process per item, two at a
|
|
2017
2019
|
time. `--post` is relative to the archive root (`--arkiv`, or derived from `--repo-rot`'s
|
|
2018
2020
|
git common dir as in `svep.mjs`); an absolute `--post` is a usage error. Per item: the
|
|
2019
2021
|
receipt via `archive.mjs korning-start`/`korning-slut` (the latter always, also when the
|
|
2020
2022
|
run fails), the run directory `<post>/korningar/<stämpel>/` with `stderr.log`,
|
|
2021
|
-
`matning.json` and the raw replies under `steg/`,
|
|
2022
|
-
|
|
2023
|
-
USD, plus each item in flight at the average of the finished ones, reaches it no further
|
|
2024
|
-
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
|
|
2025
2025
|
every `korning.mjs` it starts, SIGINT and SIGTERM both killing the running items and
|
|
2026
2026
|
clearing their receipts (exit 130),
|
|
2027
2027
|
and the final table `| post | status | poäng | utfall | wall | USD |` in argument order
|
|
2028
|
-
with the line `
|
|
2029
|
-
(`priced`, `stopp`, `väntar på dom`), 1 on `ofärdig`, `pågår
|
|
2030
|
-
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).
|
|
2031
2031
|
`bedom.mjs` takes `--design-mode draft|intervju` and passes it to every `korning.mjs` it
|
|
2032
2032
|
starts; without the flag the value is `request.json`'s `design_mode` (`interview` is read
|
|
2033
2033
|
as `intervju`), and without that key `intervju` (ADR-0156).
|
|
@@ -998,23 +998,21 @@ if (cmd === 'add-run') {
|
|
|
998
998
|
const rubrik = forstaRubrik(readFileSync(path.join(katalog, 'spec.md'), 'utf8'))
|
|
999
999
|
if (rubrik) titelFalt = { title: rubrik, slug: slugAv(rubrik) }
|
|
1000
1000
|
}
|
|
1001
|
-
// Täckningspost (ADR-0119, #
|
|
1002
|
-
//
|
|
1003
|
-
//
|
|
1004
|
-
//
|
|
1005
|
-
//
|
|
1006
|
-
//
|
|
1007
|
-
//
|
|
1008
|
-
//
|
|
1009
|
-
//
|
|
1010
|
-
//
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
if (data.coverage_post !== null && typeof data.coverage_post === 'object')
|
|
1017
|
-
titelFalt = { ...titelFalt, coverage_post: data.coverage_post }
|
|
1001
|
+
// Täckningspost (ADR-0159, ändrar ADR-0119 beslut 4; #763, #687): fältet
|
|
1002
|
+
// härleds ur den poängfil som GÄLLER efter den här raden, aldrig ur filen
|
|
1003
|
+
// som råkar stämplas. Bara en poängprisfil (huvudfil, -run2 eller
|
|
1004
|
+
// -avvisad) räknar om: en guardfil har en egen N-sekvens och synkas
|
|
1005
|
+
// aldrig (SKILL.md, arkivträdet), och spec.md/impact.md får inte väcka en
|
|
1006
|
+
// post som respec redan rensat. En -run2 eller -avvisad från en NYARE
|
|
1007
|
+
// runda än den gällande (huvudfilen är inte stämplad än) räknar inte om
|
|
1008
|
+
// heller: den rundan pågår och dess gällande fil finns inte än, så fältet
|
|
1009
|
+
// behåller sitt värde (null efter en respec) tills rundans huvudfil
|
|
1010
|
+
// stämplas. Se gallandeTackning för regeln.
|
|
1011
|
+
const poangfil = /^score-pricing-v(\d+)(-[a-z0-9-]+)?\.json$/.exec(file)
|
|
1012
|
+
if (poangfil) {
|
|
1013
|
+
const efter = { ...state, runs: [...runs, row] }
|
|
1014
|
+
if (Number(poangfil[1]) <= maxN(efter.runs, 'score'))
|
|
1015
|
+
titelFalt = { ...titelFalt, coverage_post: gallandeTackning(efter) }
|
|
1018
1016
|
}
|
|
1019
1017
|
// ADR-0153 beslut 3: brädkvittot betyder att den gällande prisrundan
|
|
1020
1018
|
// ligger på brädan. En ny rundas huvudfil gör ett tidigare kvitto
|
|
@@ -1239,6 +1237,13 @@ if (cmd === 'add-run') {
|
|
|
1239
1237
|
}
|
|
1240
1238
|
}
|
|
1241
1239
|
state.granskarutslag = [...(state.granskarutslag ?? []), row]
|
|
1240
|
+
// ADR-0159: en dom på poängaxeln kan byta den gällande filen, så
|
|
1241
|
+
// täckningsposten räknas om ur den. En trasig gällande fil fäller domen
|
|
1242
|
+
// (exit 2) innan något skrivs.
|
|
1243
|
+
// En dom om ett äldre varv byter aldrig den gällande filen (liftingUtslag
|
|
1244
|
+
// kräver n === maxN) och räknar därför inte om.
|
|
1245
|
+
if (row.typ === 'viktning' && row.axel === 'score' && row.n === maxN(state.runs ?? [], 'score'))
|
|
1246
|
+
state.coverage_post = gallandeTackning(state)
|
|
1242
1247
|
writeStateOrThrow(state)
|
|
1243
1248
|
rowCount = state.granskarutslag.length
|
|
1244
1249
|
} catch (e) {
|
|
@@ -1273,6 +1278,10 @@ if (cmd === 'add-run') {
|
|
|
1273
1278
|
}
|
|
1274
1279
|
if (stopp.length === 0) {
|
|
1275
1280
|
state.status = status
|
|
1281
|
+
// ADR-0159: priced är steget före synken, så täckningsposten räknas om
|
|
1282
|
+
// här också. En huvudfil som stämplades innan den skrevs får då sin
|
|
1283
|
+
// post även när ingen senare stämpling kom.
|
|
1284
|
+
if (status === 'priced') state.coverage_post = gallandeTackning(state)
|
|
1276
1285
|
writeStateOrThrow(state)
|
|
1277
1286
|
}
|
|
1278
1287
|
} catch (e) {
|
|
@@ -1989,6 +1998,12 @@ if (cmd === 'add-run') {
|
|
|
1989
1998
|
nytt.board = null
|
|
1990
1999
|
antal++
|
|
1991
2000
|
}
|
|
2001
|
+
// ADR-0159: täckningsposten hörde till en prisrunda som inte längre
|
|
2002
|
+
// gäller; nästa poängrunda räknar fram den på nytt.
|
|
2003
|
+
if (nytt.coverage_post !== null && nytt.coverage_post !== undefined) {
|
|
2004
|
+
nytt.coverage_post = null
|
|
2005
|
+
antal++
|
|
2006
|
+
}
|
|
1992
2007
|
// Ett dött kvitto (levande vägrades ovan) hör till en körning som inte
|
|
1993
2008
|
// finns; en ny spec nollar det.
|
|
1994
2009
|
if (nytt.korning !== null && nytt.korning !== undefined) {
|
|
@@ -3238,6 +3253,22 @@ function gallandeDokumentFil(state, typ, n) {
|
|
|
3238
3253
|
return liftingUtslag(state, typ, n)?.galler_fil ?? `${typ}-pricing-v${n}.json`
|
|
3239
3254
|
}
|
|
3240
3255
|
|
|
3256
|
+
/** Täckningsposten (ADR-0159, ändrar ADR-0119 beslut 4): `coverage_post` ur
|
|
3257
|
+
* den poängfil som gäller, `gallandeDokumentFil(state, 'score', maxN)`, så
|
|
3258
|
+
* att granskarens `galler_fil` styr på samma sätt som för poäng och utfall.
|
|
3259
|
+
* null när ingen poängrunda finns, när den gällande filen ännu inte skrivits
|
|
3260
|
+
* (den stämplas ofta före agentens fil; nästa omräkning fyller i den) och
|
|
3261
|
+
* när filen saknar ett objekt i fältet. Finns filen men är trasig kastar
|
|
3262
|
+
* readPricingFileOrThrow ArkivFel, samma arkivfel som andra läsare i filen. */
|
|
3263
|
+
function gallandeTackning(state, d = katalog) {
|
|
3264
|
+
const n = maxN(state.runs ?? [], 'score')
|
|
3265
|
+
if (n === 0) return null
|
|
3266
|
+
const fil = gallandeDokumentFil(state, 'score', n)
|
|
3267
|
+
if (!existsSync(path.join(d, fil))) return null
|
|
3268
|
+
const cp = readPricingFileOrThrow(fil, d).coverage_post
|
|
3269
|
+
return cp !== null && typeof cp === 'object' && !Array.isArray(cp) ? cp : null
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3241
3272
|
/** Läser en gällande pricing-fil (classification eller score) ur katalogen
|
|
3242
3273
|
* och returnerar den PARSADE, validerade datan. Arkivet PÅSTÅR via sin
|
|
3243
3274
|
* runs-rad (eller ett viktningsutslags `galler_fil`) att filen finns och är
|
|
@@ -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
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haus-tech/haus-workflow",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0",
|
|
4
4
|
"description": "Haus AI workflow CLI for Claude Code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,11 +34,12 @@
|
|
|
34
34
|
"format": "prettier --write --cache --cache-location .prettiercache .",
|
|
35
35
|
"typecheck": "tsc --noEmit",
|
|
36
36
|
"pack:local": "yarn pack",
|
|
37
|
-
"release": "GITHUB_TOKEN=$(gh auth token) LEFTHOOK_EXCLUDE=branch-guard release-it",
|
|
38
|
-
"release:dry": "GITHUB_TOKEN=$(gh auth token) LEFTHOOK_EXCLUDE=branch-guard release-it --dry-run",
|
|
37
|
+
"release": "GITHUB_TOKEN=$(gh auth token) LEFTHOOK_EXCLUDE=branch-guard,ci-local release-it",
|
|
38
|
+
"release:dry": "GITHUB_TOKEN=$(gh auth token) LEFTHOOK_EXCLUDE=branch-guard,ci-local release-it --dry-run",
|
|
39
39
|
"prepack": "yarn build",
|
|
40
40
|
"verify": "node scripts/verify.mjs",
|
|
41
41
|
"verify:full": "node scripts/verify.mjs --coverage",
|
|
42
|
+
"ci:local": "node scripts/ci-local.mjs --force",
|
|
42
43
|
"check:contract-behavior": "node --import tsx scripts/contract-behavior-check.mjs",
|
|
43
44
|
"check:mutation-table": "node scripts/check-mutation-table.mjs",
|
|
44
45
|
"check:docs-site": "node scripts/check-docs-site.mjs",
|