autonomous-sdlc-harness 0.1.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/LICENSE +201 -0
- package/NOTICE +7 -0
- package/README.md +24 -0
- package/dist/cli.js +194 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.js +561 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/daemon.js +791 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/doctor.js +336 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.js +2023 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/registry.js +42 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/config/check.js +505 -0
- package/dist/config/check.js.map +1 -0
- package/dist/config/io.js +177 -0
- package/dist/config/io.js.map +1 -0
- package/dist/config/model.js +406 -0
- package/dist/config/model.js.map +1 -0
- package/dist/core/errors.js +71 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/git.js +537 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/json.js +125 -0
- package/dist/core/json.js.map +1 -0
- package/dist/core/layerCoverage.js +141 -0
- package/dist/core/layerCoverage.js.map +1 -0
- package/dist/core/layerGapRemedy.js +62 -0
- package/dist/core/layerGapRemedy.js.map +1 -0
- package/dist/core/nameList.js +23 -0
- package/dist/core/nameList.js.map +1 -0
- package/dist/core/paths.js +153 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/prompt.js +206 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/repoPaths.js +55 -0
- package/dist/core/repoPaths.js.map +1 -0
- package/dist/core/report.js +150 -0
- package/dist/core/report.js.map +1 -0
- package/dist/core/templating.js +88 -0
- package/dist/core/templating.js.map +1 -0
- package/dist/core/writer.js +479 -0
- package/dist/core/writer.js.map +1 -0
- package/dist/daemon/backend.js +180 -0
- package/dist/daemon/backend.js.map +1 -0
- package/dist/daemon/units.js +380 -0
- package/dist/daemon/units.js.map +1 -0
- package/dist/detect/nestedApplication.js +79 -0
- package/dist/detect/nestedApplication.js.map +1 -0
- package/dist/detect/presets.js +2033 -0
- package/dist/detect/presets.js.map +1 -0
- package/dist/detect/signals.js +1368 -0
- package/dist/detect/signals.js.map +1 -0
- package/dist/doctor/checks.js +3530 -0
- package/dist/doctor/checks.js.map +1 -0
- package/dist/generators/claudeContext.js +588 -0
- package/dist/generators/claudeContext.js.map +1 -0
- package/dist/generators/githooks.js +446 -0
- package/dist/generators/githooks.js.map +1 -0
- package/dist/generators/harnessConfig.js +632 -0
- package/dist/generators/harnessConfig.js.map +1 -0
- package/dist/generators/notifications.js +191 -0
- package/dist/generators/notifications.js.map +1 -0
- package/dist/generators/outerLoopScripts.js +165 -0
- package/dist/generators/outerLoopScripts.js.map +1 -0
- package/dist/generators/permissionProfile.js +1172 -0
- package/dist/generators/permissionProfile.js.map +1 -0
- package/dist/generators/projectSettings.js +322 -0
- package/dist/generators/projectSettings.js.map +1 -0
- package/dist/generators/repoRoot.js +417 -0
- package/dist/generators/repoRoot.js.map +1 -0
- package/dist/generators/scripts.js +557 -0
- package/dist/generators/scripts.js.map +1 -0
- package/dist/generators/stateDir.js +221 -0
- package/dist/generators/stateDir.js.map +1 -0
- package/dist/machine/paths.js +111 -0
- package/dist/machine/paths.js.map +1 -0
- package/dist/machine/plugins.js +224 -0
- package/dist/machine/plugins.js.map +1 -0
- package/dist/machine/registry.js +330 -0
- package/dist/machine/registry.js.map +1 -0
- package/package.json +23 -0
- package/scripts/README.md +13 -0
- package/scripts/daemon/launchd.plist.template +59 -0
- package/scripts/daemon/systemd.service.template +58 -0
- package/templates/README.md +15 -0
- package/templates/claude/CLAUDE.md +54 -0
- package/templates/claude/README.md +5 -0
- package/templates/claude/context/api.md +29 -0
- package/templates/claude/context/conventions.md +23 -0
- package/templates/claude/context/data-layer.md +28 -0
- package/templates/claude/context/data-storage.md +29 -0
- package/templates/claude/context/docs-catalog.md +29 -0
- package/templates/claude/context/domain.md +28 -0
- package/templates/claude/context/layer.md +20 -0
- package/templates/claude/context/module.md +30 -0
- package/templates/claude/context/package.md +29 -0
- package/templates/claude/context/presentation.md +32 -0
- package/templates/claude/context/state-slices.md +28 -0
- package/templates/claude/context/tests.md +28 -0
- package/templates/claude/harness-task-offer.md +58 -0
- package/templates/claude/push-notify.env.example +21 -0
- package/templates/claude/qa-accounts.env.example +38 -0
- package/templates/claude/qa_test_scenarios.md +110 -0
- package/templates/claude/settings.autonomous.json +93 -0
- package/templates/claude/settings.autonomous.qa.json +36 -0
- package/templates/githooks/README.md +3 -0
- package/templates/githooks/pre-push +72 -0
- package/templates/repo/README.md +3 -0
- package/templates/repo/gitattributes +16 -0
- package/templates/repo/gitignore +61 -0
- package/templates/repo/gitignore.qa +25 -0
- package/templates/repo/mcp.json +17 -0
- package/templates/scripts/README.md +5 -0
- package/templates/scripts/autonomous-format-stream.sh +95 -0
- package/templates/scripts/autonomous-notify.sh +337 -0
- package/templates/scripts/autonomous-watcher.sh +3087 -0
- package/templates/scripts/cleanup-merged-worktrees.sh +327 -0
- package/templates/scripts/commit-on-branch.sh +288 -0
- package/templates/scripts/create-worktree.sh +360 -0
- package/templates/scripts/deploy.sh +47 -0
- package/templates/scripts/lib/harness-run-lib.sh +1481 -0
- package/templates/scripts/push-branch.sh +140 -0
- package/templates/scripts/refresh-branch.sh +244 -0
- package/templates/scripts/restart-watcher.sh +401 -0
- package/templates/scripts/scratch-run.sh +302 -0
- package/templates/scripts/setup-worktree.sh +262 -0
- package/templates/scripts/start-dev-server.sh +99 -0
- package/templates/scripts/test.sh +50 -0
- package/templates/scripts/typecheck.sh +50 -0
- package/templates/state-dir/README-root.md +13 -0
- package/templates/state-dir/README.md +9 -0
- package/templates/state-dir/architecture_branch_review_point_reviews/README.md +9 -0
- package/templates/state-dir/architecture_branch_reviews/README.md +9 -0
- package/templates/state-dir/architecture_reviews/README.md +9 -0
- package/templates/state-dir/architecture_user_review_reviews/README.md +9 -0
- package/templates/state-dir/autonomous_inbox/README.md +9 -0
- package/templates/state-dir/autonomous_logs/README.md +9 -0
- package/templates/state-dir/branch_statistics/README.md +9 -0
- package/templates/state-dir/business_parity_branch_review_point_reviews/README.md +9 -0
- package/templates/state-dir/business_parity_branch_reviews/README.md +9 -0
- package/templates/state-dir/business_parity_reviews/README.md +9 -0
- package/templates/state-dir/business_parity_user_review_reviews/README.md +9 -0
- package/templates/state-dir/clarification_digests/README.md +9 -0
- package/templates/state-dir/clarifications/README.md +9 -0
- package/templates/state-dir/code_reviews/README.md +9 -0
- package/templates/state-dir/dispatch_additions/README.md +19 -0
- package/templates/state-dir/docs_catalog/README.md +9 -0
- package/templates/state-dir/flow_progress/README.md +9 -0
- package/templates/state-dir/improvement_observations/README.md +19 -0
- package/templates/state-dir/improvement_suggestions.md +29 -0
- package/templates/state-dir/lessons.md +23 -0
- package/templates/state-dir/qa_review_point_reviews/README.md +9 -0
- package/templates/state-dir/qa_reviews/README.md +9 -0
- package/templates/state-dir/review_plan_point_reviews/README.md +9 -0
- package/templates/state-dir/review_plan_reviews/README.md +9 -0
- package/templates/state-dir/scratch/README.md +11 -0
- package/templates/state-dir/skeptic_review_plan_reviews/README.md +9 -0
- package/templates/state-dir/skeptic_review_point_reviews/README.md +9 -0
- package/templates/state-dir/skeptic_reviews/README.md +9 -0
- package/templates/state-dir/story_plans/README.md +9 -0
- package/templates/state-dir/task_plan_point_reviews/README.md +9 -0
- package/templates/state-dir/task_plan_reviews/README.md +9 -0
- package/templates/state-dir/task_plans/README.md +9 -0
- package/templates/state-dir/task_prompts/README.md +9 -0
- package/templates/state-dir/ui_test_plan_reviews/README.md +9 -0
- package/templates/state-dir/ui_test_plans/README.md +9 -0
- package/templates/state-dir/user_review_fix_plan_point_reviews/README.md +9 -0
- package/templates/state-dir/user_reviews/README.md +9 -0
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command: `config` — read and update `harness.config.json`.
|
|
3
|
+
*
|
|
4
|
+
* **The rule this module exists to enforce: this command is exactly as wide as the one line the
|
|
5
|
+
* shipped documentation promises for it — read and update — and no wider.** It addresses one value
|
|
6
|
+
* at a time by a dotted key path, prints it or replaces it, and hands every judgement about whether
|
|
7
|
+
* the result is a legal config to `config/check.ts`. It is **not** a validator: the gate that checks
|
|
8
|
+
* a file against `schemas/harness.config.schema.json` is `npm run validate:config`, whose validator
|
|
9
|
+
* is a workspace development dependency this package does not ship and this command does not read.
|
|
10
|
+
* The structural check that does run here runs on the **result of the edit**, and exists for exactly
|
|
11
|
+
* one reason — to stop this command corrupting the file it was asked to change. It also runs on the
|
|
12
|
+
* **input**: `get` and `set` refuse a `harness.config.json` that already carries an `error` problem,
|
|
13
|
+
* before a value is read or a mutator applied. `list` does not — see below.
|
|
14
|
+
*
|
|
15
|
+
* ## Three non-obvious choices, and where each comes from
|
|
16
|
+
*
|
|
17
|
+
* 1. **There is no key table in this file.** A typo (`commands.tset`), an unknown section and a
|
|
18
|
+
* value whose type contradicts the one its key holds are all refused by the same mechanism: the
|
|
19
|
+
* edit is applied to a private copy and `config/check.ts` is run over the whole result, which
|
|
20
|
+
* already reports an unknown key at *every* level and the declared type of every declared key. A
|
|
21
|
+
* second table here would be a third copy of the key set — after the declared contract and
|
|
22
|
+
* `config/model.ts` — and the day it drifted, this command would refuse a legal key or write an
|
|
23
|
+
* illegal one.
|
|
24
|
+
* 2. **`set` applies its write plan with `force: true`, always, and never with `--force`.**
|
|
25
|
+
* `config/io.ts` enqueues the update as `create-if-absent`, which is the write engine's only
|
|
26
|
+
* content-replacing policy; applied without force, the engine would record `kept` and the edit
|
|
27
|
+
* would silently not land. Forcing is therefore not an escalation here, it is the ordinary path —
|
|
28
|
+
* and it carries a safety property worth having for the one command whose job is to change a file
|
|
29
|
+
* the adopter owns: the engine copies the previous file to a `.bak` sibling before replacing it,
|
|
30
|
+
* so the values that were there stay one file away. The global `--force` flag is not consulted:
|
|
31
|
+
* there is nothing about this command for it to escalate.
|
|
32
|
+
* 3. **A value is read as JSON first and as a plain string second.** `set phases.qa true` has to set
|
|
33
|
+
* the boolean rather than the four-letter word, and `set commands.test "bash scripts/test.sh"`
|
|
34
|
+
* has to set the string rather than fail to parse. Trying JSON and falling back gives both
|
|
35
|
+
* without a type flag, and a caller who wants the *string* `3` writes it as `'"3"'`.
|
|
36
|
+
*
|
|
37
|
+
* ## What this command deliberately does not do
|
|
38
|
+
*
|
|
39
|
+
* - **It does not fill in defaults.** `list` prints the file as it stands, because `get` reports an
|
|
40
|
+
* unset key as absent and exits non-zero; a `list` that merged declared defaults in would answer a
|
|
41
|
+
* question `get` answers differently, and the two views would disagree about the same file.
|
|
42
|
+
* - **It does not refuse to `list` a broken config.** `list` is the one verb that prints a file
|
|
43
|
+
* carrying shape errors, reporting each as a warning on stderr, so the configuration most in need
|
|
44
|
+
* of repair is the one an adopter can still read. `get` and `set` refuse it: both act on a single
|
|
45
|
+
* value, and a value read out of a file whose shape is wrong is not one to act on.
|
|
46
|
+
* - **It does not address a list element by element.** `layers` and `protectedBranches` are set and
|
|
47
|
+
* printed whole. Order matters in both, and a flat string path is a poor way to express an
|
|
48
|
+
* insertion, a removal or a reorder.
|
|
49
|
+
* - **It does not remove a key.** A value can be replaced; deleting an optional key is a hand edit,
|
|
50
|
+
* which keeps the number of ways this command can shrink an adopter's config at zero.
|
|
51
|
+
* - **It writes nothing but `harness.config.json`** (plus that file's `.bak` sibling, written by the
|
|
52
|
+
* engine), and it runs no external command. It does *read* one other file: a `set` of a branch-guard
|
|
53
|
+
* key opens the generated pre-push hook to grade its `case` label against the set the result
|
|
54
|
+
* resolves, because the alternative is asserting that state unread ({@link guardState}).
|
|
55
|
+
*/
|
|
56
|
+
import { readFileSync } from 'node:fs';
|
|
57
|
+
import { join } from 'node:path';
|
|
58
|
+
import { formatProblem } from '../config/check.js';
|
|
59
|
+
import { readParsedConfig, requireConfig, updateConfig } from '../config/io.js';
|
|
60
|
+
import { COMMAND_NONE_SENTINEL, CONFIG_FILENAME, DEFAULTS, NONE_SENTINEL_KEY, } from '../config/model.js';
|
|
61
|
+
import { EXIT, HarnessError } from '../core/errors.js';
|
|
62
|
+
import { resolveRepoRoot } from '../core/git.js';
|
|
63
|
+
import { formatJson, isJsonObject } from '../core/json.js';
|
|
64
|
+
import { WritePlan } from '../core/writer.js';
|
|
65
|
+
import { caseLabelMatches, PRE_PUSH_HOOK, readProtectedCaseLabel, resolveGithooksDir, resolveProtectedBranches, } from '../generators/githooks.js';
|
|
66
|
+
import { configKeyPath, wrappedKeyMismatch, wrappedKeyMismatchMessage, WRAPPER_SCRIPTS, } from '../generators/scripts.js';
|
|
67
|
+
/**
|
|
68
|
+
* The command's one-line summary, in the usage block and at the head of its own `--help`.
|
|
69
|
+
*
|
|
70
|
+
* It is the string the registry has carried since the skeleton, and `cli/README.md` repeats it. This
|
|
71
|
+
* command implements that promise; it does not restate it more widely.
|
|
72
|
+
*/
|
|
73
|
+
const SUMMARY = 'Read and update harness.config.json';
|
|
74
|
+
/** The roadmap item this command belongs to, as the registry reports it. */
|
|
75
|
+
const ROADMAP_ITEM = 13;
|
|
76
|
+
/** How the CLI is typed, for the messages that tell an operator what to run next. The `npx` prefix is not decoration: the rule for which occurrences carry it is stated once in `commands/init.ts`, beside its own `CLI`. */
|
|
77
|
+
const CLI = 'npx autonomous-sdlc-harness';
|
|
78
|
+
/** The three verbs, in the order `--help` lists them. */
|
|
79
|
+
const VERBS = ['list', 'get', 'set'];
|
|
80
|
+
/** What each verb takes after itself, named as `--help` names it. The arity check reads this. */
|
|
81
|
+
const OPERANDS = {
|
|
82
|
+
list: [],
|
|
83
|
+
get: ['<key>'],
|
|
84
|
+
set: ['<key>', '<value>'],
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* How the command is invoked, written once: the registry's generic `config [options]` synopsis line
|
|
88
|
+
* cannot show a required verb, and a refusal quotes the same form back at whoever typed it wrong.
|
|
89
|
+
*/
|
|
90
|
+
const INVOCATION_FORM = `${CLI} config list | get <key> | set <key> <value>`;
|
|
91
|
+
/** The lines the registry renders under this command's synopsis. */
|
|
92
|
+
const CONFIG_USAGE = Object.freeze([
|
|
93
|
+
`The verb is required: ${INVOCATION_FORM}`,
|
|
94
|
+
'',
|
|
95
|
+
'Verbs:',
|
|
96
|
+
` list Print ${CONFIG_FILENAME} as it stands, formatted, problems and all`,
|
|
97
|
+
' get <key> Print one value, addressed by a dotted key path',
|
|
98
|
+
' set <key> <value> Replace one value and write the file back',
|
|
99
|
+
'',
|
|
100
|
+
'<key> is a dotted path into the file: defaultBranch, commands.test, phases.qa, qa.portSeed,',
|
|
101
|
+
'layers. A list is addressed as a whole — get layers prints it and set layers <json> replaces',
|
|
102
|
+
'it — never element by element.',
|
|
103
|
+
'',
|
|
104
|
+
'<value> is read as JSON when it parses as JSON, and as a plain string when it does not:',
|
|
105
|
+
' set phases.qa true the boolean true',
|
|
106
|
+
' set qa.portSeed 3001 the number 3001',
|
|
107
|
+
' set commands.test "bash scripts/test.sh" that string',
|
|
108
|
+
` ${`set commands.${NONE_SENTINEL_KEY} "${COMMAND_NONE_SENTINEL}"`.padEnd(40)} the answer that this repository has no type check`,
|
|
109
|
+
' set projectName \'"3"\' the string 3 rather than the number',
|
|
110
|
+
'',
|
|
111
|
+
'A <value> that would be read as one of the global options above is separated with --, which',
|
|
112
|
+
'stops flag parsing: set commands.build -- --version.',
|
|
113
|
+
'',
|
|
114
|
+
'get prints a string raw and anything else as JSON, so a shell can consume it directly, and it',
|
|
115
|
+
'exits non-zero when the key is not set. An optional key with no value is absent from the file',
|
|
116
|
+
'rather than written as null, and no declared default is filled in for it.',
|
|
117
|
+
'',
|
|
118
|
+
'set refuses and writes nothing when the key is not one the file may carry — a typo is an error,',
|
|
119
|
+
'not a new setting — when the value contradicts the type that key holds, or when the result would',
|
|
120
|
+
'fail the structural check; every problem found is reported, not only the first. A dot-named',
|
|
121
|
+
'stateDir is refused there, because the run-artifact tree has to be writable by an unattended run.',
|
|
122
|
+
'',
|
|
123
|
+
'set accepts a raw command line at commands.typecheck, commands.test, commands.devServer or',
|
|
124
|
+
'deploy.command and reports it, because the next init writes the wrapper script from that line and',
|
|
125
|
+
'the value the permission profile allow-lists is bash <scriptsDir>/<name>.sh.',
|
|
126
|
+
'',
|
|
127
|
+
`set commands.${NONE_SENTINEL_KEY} "${COMMAND_NONE_SENTINEL}" is the answer that this repository has no type check: exactly`,
|
|
128
|
+
'that, unquoted and lower-case. It is an answer rather than an unfilled key, so it is accepted',
|
|
129
|
+
`without a warning, no ${NONE_SENTINEL_KEY}.sh is written for it and no permission entry is implied. It is`,
|
|
130
|
+
'recognised on that one key — written into any other commands.* key it is stored and run as a',
|
|
131
|
+
'command line, and set says so — and a near miss such as none or <None> is a command line too,',
|
|
132
|
+
'reported by name.',
|
|
133
|
+
'',
|
|
134
|
+
'set defaultBranch or protectedBranches reports what the edit leaves behind: the guards resolve the',
|
|
135
|
+
'two keys into one protected set, so setting one alone leaves the other in it, and the committed',
|
|
136
|
+
'<githooksDir>/pre-push hook keeps the branch set it was rendered with until init re-renders it.',
|
|
137
|
+
'',
|
|
138
|
+
`get and set refuse a ${CONFIG_FILENAME} that already fails the structural check, before the key is`,
|
|
139
|
+
'read or the edit applied; every problem in it is named. list does not — it prints what parsed and',
|
|
140
|
+
'reports the problems as warnings, so a config with a typo can still be read here and repaired by',
|
|
141
|
+
'hand. Nothing that did not parse is printed: an absent or unparsable file is refused by all three.',
|
|
142
|
+
'',
|
|
143
|
+
`set writes a ${CONFIG_FILENAME}.bak sibling before replacing the file, every time, so the previous`,
|
|
144
|
+
'values stay one file away. Key order and formatting are preserved, so the diff is the changed',
|
|
145
|
+
'value and nothing else.',
|
|
146
|
+
'',
|
|
147
|
+
'--dry-run prints the before and after values and writes nothing. Every refusal still applies',
|
|
148
|
+
'under it, so a dry run cannot report a success a real run would not have.',
|
|
149
|
+
'',
|
|
150
|
+
'This command reads and updates the file; it does not validate it against the contract published',
|
|
151
|
+
'for editors and CI. `npm run validate:config` at the workspace root is that gate.',
|
|
152
|
+
]);
|
|
153
|
+
/** `list, get or set` — the verb list as a sentence, for a refusal. */
|
|
154
|
+
function verbList() {
|
|
155
|
+
return `${VERBS.slice(0, -1).join(', ')} or ${VERBS[VERBS.length - 1]}`;
|
|
156
|
+
}
|
|
157
|
+
/** The usage a bad invocation is refused with: the form, and where the rest of it is. */
|
|
158
|
+
function usageHint() {
|
|
159
|
+
return `usage: \`${INVOCATION_FORM}\` — run \`${CLI} config --help\` for the full usage`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Parse the verb and its operands, positionally.
|
|
163
|
+
*
|
|
164
|
+
* The operands are taken by position rather than by pattern, so a value that begins with `-` is
|
|
165
|
+
* still a value: `set commands.build "-x"` is a legal thing to want, and a parser that treated it as
|
|
166
|
+
* a flag would refuse it. The one exception is a value spelled exactly like one of the six global
|
|
167
|
+
* options, which the entry point consumes before this command is reached; `--` stops that parsing,
|
|
168
|
+
* which is why the usage names it. A token in the *verb* or *key* position that begins with `-` is
|
|
169
|
+
* refused, since neither can legally start that way and a mistyped flag is the likely cause.
|
|
170
|
+
*
|
|
171
|
+
* A missing verb, an unknown verb and a wrong operand count are refusals rather than defaults: `set`
|
|
172
|
+
* changes a file the adopter owns, and there is no verb harmless enough to be the default.
|
|
173
|
+
*/
|
|
174
|
+
function parseInvocation(argv) {
|
|
175
|
+
const [verbToken, ...rest] = argv;
|
|
176
|
+
if (verbToken === undefined) {
|
|
177
|
+
throw new HarnessError(`config: no verb given — expected ${verbList()}; ${usageHint()}`);
|
|
178
|
+
}
|
|
179
|
+
if (verbToken.startsWith('-')) {
|
|
180
|
+
throw new HarnessError(`config: unknown option ${JSON.stringify(verbToken)} — ${usageHint()}`);
|
|
181
|
+
}
|
|
182
|
+
if (!VERBS.includes(verbToken)) {
|
|
183
|
+
throw new HarnessError(`config: unknown verb ${JSON.stringify(verbToken)} — expected ${verbList()}; ${usageHint()}`);
|
|
184
|
+
}
|
|
185
|
+
const verb = verbToken;
|
|
186
|
+
const expected = OPERANDS[verb];
|
|
187
|
+
if (rest.length < expected.length) {
|
|
188
|
+
throw new HarnessError(`config ${verb}: expected \`config ${verb} ${expected.join(' ')}\` — ${usageHint()}`);
|
|
189
|
+
}
|
|
190
|
+
if (rest.length > expected.length) {
|
|
191
|
+
const takes = expected.length === 0 ? 'takes no arguments' : `takes exactly ${expected.join(' ')}`;
|
|
192
|
+
throw new HarnessError(`config ${verb}: unexpected argument ${JSON.stringify(rest[expected.length])} — config ${verb} ${takes}; ${usageHint()}`);
|
|
193
|
+
}
|
|
194
|
+
if (verb === 'list')
|
|
195
|
+
return { verb };
|
|
196
|
+
// Present by the arity check above.
|
|
197
|
+
const key = rest[0];
|
|
198
|
+
if (key.startsWith('-')) {
|
|
199
|
+
throw new HarnessError(`config ${verb}: unknown option ${JSON.stringify(key)} — ${usageHint()}`);
|
|
200
|
+
}
|
|
201
|
+
return verb === 'get' ? { verb, key } : { verb, key, value: rest[1] };
|
|
202
|
+
}
|
|
203
|
+
/** A key path split into its segments, refusing anything that cannot address a key. */
|
|
204
|
+
function parseKeyPath(key) {
|
|
205
|
+
if (key === '')
|
|
206
|
+
throw new HarnessError(`config: the key is empty — ${usageHint()}`);
|
|
207
|
+
const segments = key.split('.');
|
|
208
|
+
if (segments.some((segment) => segment === '')) {
|
|
209
|
+
throw new HarnessError(`config: ${JSON.stringify(key)} is not a key path: one of its segments is empty`);
|
|
210
|
+
}
|
|
211
|
+
return segments;
|
|
212
|
+
}
|
|
213
|
+
/** What a value is, for a message: `a list`, `a string`, `null`. */
|
|
214
|
+
function describe(value) {
|
|
215
|
+
if (value === null)
|
|
216
|
+
return 'null';
|
|
217
|
+
if (Array.isArray(value))
|
|
218
|
+
return 'a list';
|
|
219
|
+
return `a ${typeof value}`;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The refusal for a key path that tries to descend through something with no keys beneath it.
|
|
223
|
+
*
|
|
224
|
+
* The list case gets its own sentence because it has a different answer: the value is reachable, it
|
|
225
|
+
* is simply addressed whole.
|
|
226
|
+
*/
|
|
227
|
+
function notAContainer(key, walked, value) {
|
|
228
|
+
if (Array.isArray(value)) {
|
|
229
|
+
return new HarnessError(`config: ${key} reaches into ${walked}, which is a list — a list is addressed as a whole: \`${CLI} config get ${walked}\` prints it, and \`${CLI} config set ${walked} '<json>'\` replaces it`);
|
|
230
|
+
}
|
|
231
|
+
return new HarnessError(`config: ${key} reaches into ${walked}, which holds ${describe(value)}, so it has no keys beneath it`);
|
|
232
|
+
}
|
|
233
|
+
/** The value at a key path, or `undefined` when nothing is set there. */
|
|
234
|
+
function readValue(config, key, segments) {
|
|
235
|
+
let current = config;
|
|
236
|
+
let walked = '';
|
|
237
|
+
for (const segment of segments) {
|
|
238
|
+
if (!isJsonObject(current))
|
|
239
|
+
throw notAContainer(key, walked, current);
|
|
240
|
+
if (!Object.hasOwn(current, segment))
|
|
241
|
+
return undefined;
|
|
242
|
+
current = current[segment];
|
|
243
|
+
walked = walked === '' ? segment : `${walked}.${segment}`;
|
|
244
|
+
}
|
|
245
|
+
return current;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Set the value at a key path on a config object, in place, and report what was there.
|
|
249
|
+
*
|
|
250
|
+
* A **missing** intermediate section is created rather than refused, because that is the ordinary
|
|
251
|
+
* case: `set qa.credentialsPath …` on a config with no `qa` section has to work. Creating it is safe
|
|
252
|
+
* precisely because nothing here decides whether the section is a legal one — a mistyped section
|
|
253
|
+
* name is created too, and is then reported by the structural check over the result, which names it
|
|
254
|
+
* as an unknown key and refuses the write.
|
|
255
|
+
*/
|
|
256
|
+
function assignValue(config, key, segments, value) {
|
|
257
|
+
const last = segments[segments.length - 1];
|
|
258
|
+
let current = config;
|
|
259
|
+
let walked = '';
|
|
260
|
+
for (const segment of segments.slice(0, -1)) {
|
|
261
|
+
walked = walked === '' ? segment : `${walked}.${segment}`;
|
|
262
|
+
const existing = Object.hasOwn(current, segment) ? current[segment] : undefined;
|
|
263
|
+
if (existing === undefined) {
|
|
264
|
+
const created = {};
|
|
265
|
+
current[segment] = created;
|
|
266
|
+
current = created;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (!isJsonObject(existing))
|
|
270
|
+
throw notAContainer(key, walked, existing);
|
|
271
|
+
current = existing;
|
|
272
|
+
}
|
|
273
|
+
const existed = Object.hasOwn(current, last);
|
|
274
|
+
const previous = existed ? current[last] : undefined;
|
|
275
|
+
current[last] = value;
|
|
276
|
+
return { existed, previous };
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* A `<value>` operand as the JSON it parses as, or as itself when it does not parse.
|
|
280
|
+
*
|
|
281
|
+
* Falling back rather than refusing is what makes the common case typeable: almost every command
|
|
282
|
+
* line, branch name and path an adopter sets here is not valid JSON, and requiring them to be
|
|
283
|
+
* quoted twice would make the string case the awkward one.
|
|
284
|
+
*/
|
|
285
|
+
function parseValue(raw) {
|
|
286
|
+
try {
|
|
287
|
+
return JSON.parse(raw);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return raw;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* One value as a line of output: a string raw, anything else as the same JSON the file is written
|
|
295
|
+
* in, minus the trailing newline the reporter adds itself.
|
|
296
|
+
*
|
|
297
|
+
* Raw for a string so `commands.test` can be substituted straight into a shell; JSON for everything
|
|
298
|
+
* else so a list or an object round-trips back through `set`.
|
|
299
|
+
*/
|
|
300
|
+
function render(value) {
|
|
301
|
+
return typeof value === 'string' ? value : formatJson(value).trimEnd();
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* `config list`: the file as it stands, in the CLI's single JSON format.
|
|
305
|
+
*
|
|
306
|
+
* It prints a config **carrying shape errors**, reporting each as a warning, where `get` and `set`
|
|
307
|
+
* refuse one. That is what "as it stands" has to mean: an unknown-key typo or an out-of-range value
|
|
308
|
+
* is exactly the state an adopter needs to see printed to repair it, and a `list` that refused it
|
|
309
|
+
* would leave them with no way to read the file through this command at all. Nothing that did not
|
|
310
|
+
* parse is printed — absent, unparsable or not a JSON object is still a refusal.
|
|
311
|
+
*/
|
|
312
|
+
function list(ctx) {
|
|
313
|
+
const repoRoot = resolveRepoRoot(ctx.cwd);
|
|
314
|
+
const loaded = readParsedConfig(repoRoot);
|
|
315
|
+
ctx.report.result(render(loaded.config));
|
|
316
|
+
// After the result, and on stderr, so the printed file stays a parsable document on stdout.
|
|
317
|
+
for (const problem of loaded.problems)
|
|
318
|
+
ctx.report.warn(formatProblem(problem));
|
|
319
|
+
return EXIT.OK;
|
|
320
|
+
}
|
|
321
|
+
/** `config get <key>`: one value, or a non-zero refusal naming the key that is not set. */
|
|
322
|
+
function get(ctx, key) {
|
|
323
|
+
const repoRoot = resolveRepoRoot(ctx.cwd);
|
|
324
|
+
const config = requireConfig(repoRoot);
|
|
325
|
+
const value = readValue(config, key, parseKeyPath(key));
|
|
326
|
+
if (value === undefined) {
|
|
327
|
+
throw new HarnessError(`config get: ${key} is not set in ${CONFIG_FILENAME} — run \`${CLI} config list\` for every key the file carries. An optional key with no value is absent from the file rather than written as null, and no declared default is filled in for it`);
|
|
328
|
+
}
|
|
329
|
+
ctx.report.result(render(value));
|
|
330
|
+
return EXIT.OK;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* The wrapper keys a dotted `<key>` can have changed: the one it names, or **every** wrapper key
|
|
334
|
+
* beneath it when the value set was the enclosing object. `set commands '<json>'` writes the same
|
|
335
|
+
* values a per-key `set` would, so the boundary report has to see it too (`docs/cli.md` §5).
|
|
336
|
+
*
|
|
337
|
+
* Matched against {@link configKeyPath} over {@link WRAPPER_SCRIPTS} rather than against four path
|
|
338
|
+
* literals here: `deploy`'s command lives at `deploy.command` rather than under `commands`, and a
|
|
339
|
+
* second copy of that mapping is the key table choice 1 of the module header refuses to keep.
|
|
340
|
+
*/
|
|
341
|
+
function wrapperKeysFor(key) {
|
|
342
|
+
return WRAPPER_SCRIPTS.filter((entry) => {
|
|
343
|
+
const path = configKeyPath(entry.key);
|
|
344
|
+
return path === key || path.startsWith(`${key}.`);
|
|
345
|
+
}).map((entry) => entry.key);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* The two keys the branch guards read **together**: the protected set every guard enforces is
|
|
349
|
+
* `protectedBranches` unioned with `defaultBranch` (`generators/githooks.ts` →
|
|
350
|
+
* `resolveProtectedBranches`), so an edit to either one moves the set and neither moves it alone.
|
|
351
|
+
*
|
|
352
|
+
* Typed as key names of {@link HarnessConfig} rather than written as path literals, so a release
|
|
353
|
+
* that renames either key stops compiling here instead of leaving a report addressing a key the
|
|
354
|
+
* file no longer carries — the second key table choice 1 of the module header refuses to keep.
|
|
355
|
+
*/
|
|
356
|
+
const BRANCH_GUARD_KEYS = ['defaultBranch', 'protectedBranches'];
|
|
357
|
+
/**
|
|
358
|
+
* The branch-guard keys a dotted `<key>` can have changed, on {@link wrapperKeysFor}'s shape: the
|
|
359
|
+
* one it names, or **every** guard key beneath it when the value set was an enclosing object.
|
|
360
|
+
*
|
|
361
|
+
* Both keys sit at the top level today, so `set protectedBranches '<json>'` — the whole list at
|
|
362
|
+
* once — is reached by the **equality** arm, and the prefix arm has no subject in this release. It
|
|
363
|
+
* is carried rather than dropped because it is what makes the helper survive either key moving
|
|
364
|
+
* under a section, which is the one shape {@link wrapperKeysFor} already has and this one does not:
|
|
365
|
+
* there, `test`'s command line is nested at `commands.test`, and the prefix arm is what
|
|
366
|
+
* `set commands '<json>'` is matched by. A `<key>` addressing the document itself is refused by
|
|
367
|
+
* {@link parseKeyPath} as an empty key path.
|
|
368
|
+
*/
|
|
369
|
+
function branchGuardKeysFor(key) {
|
|
370
|
+
return BRANCH_GUARD_KEYS.filter((path) => path === key || path.startsWith(`${key}.`));
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Where the guard git runs lives, resolved through the generator that writes it.
|
|
374
|
+
*
|
|
375
|
+
* Caught rather than propagated: a `githooksDir` naming the repository root is refused by `init` and
|
|
376
|
+
* graded by `doctor` (`generators/githooks.ts` → `resolveGithooksDir`), and a `set` that has already
|
|
377
|
+
* written the file it was asked to change may not turn into that refusal on a key that has nothing to
|
|
378
|
+
* do with it. Where the directory does not resolve, the hook is named by its filename alone.
|
|
379
|
+
*/
|
|
380
|
+
function guardHookPath(config) {
|
|
381
|
+
try {
|
|
382
|
+
return `${resolveGithooksDir(config)}/${PRE_PUSH_HOOK}`;
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return PRE_PUSH_HOOK;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* What the guard on disk enforces, against the set the config now resolves.
|
|
390
|
+
*
|
|
391
|
+
* The label is **read** through the generator's own reader rather than asserted, which is the
|
|
392
|
+
* discipline `doctor`'s `pre-push-guard` check and `writeGitHooks`' re-render arm already apply to
|
|
393
|
+
* the same file: a `set` that told an adopter to run `init --force` over a guard that was already
|
|
394
|
+
* right would spend the write engine's one `.bak` generation for nothing, on every generated
|
|
395
|
+
* `create-if-absent` artifact in the repository.
|
|
396
|
+
*
|
|
397
|
+
* Both catches answer with a state rather than propagating, for {@link guardHookPath}'s reason — a
|
|
398
|
+
* `set` that has already written the file it was asked to change may not turn into a refusal. An
|
|
399
|
+
* unresolvable set is answered `'behind'`: it is the sentence this report carried before anything
|
|
400
|
+
* was read, and a value no hook can be rendered from is not one the hook on disk carries.
|
|
401
|
+
*/
|
|
402
|
+
function guardState(repoRoot, config, hookPath) {
|
|
403
|
+
let hookText;
|
|
404
|
+
try {
|
|
405
|
+
hookText = readFileSync(join(repoRoot, hookPath), 'utf8');
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
return 'absent';
|
|
409
|
+
}
|
|
410
|
+
const label = readProtectedCaseLabel(hookText);
|
|
411
|
+
if (label === undefined)
|
|
412
|
+
return 'unreadable';
|
|
413
|
+
try {
|
|
414
|
+
return caseLabelMatches(label, resolveProtectedBranches(config, () => { })) ? 'in-step' : 'behind';
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
return 'behind';
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/** Branch patterns as a sentence: `"main", "release/*"` — a list rendered inline rather than as the multi-line JSON {@link render} produces for one. */
|
|
421
|
+
function patternList(patterns) {
|
|
422
|
+
return patterns.map((pattern) => JSON.stringify(pattern)).join(', ');
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* What the sibling key holds while `defaultBranch` is being set, in the three states it can be in:
|
|
426
|
+
* unset, and therefore standing at the schema default the guards are rendered from; listing nothing,
|
|
427
|
+
* which resolves to the default branch and nothing else; or listing the names it lists.
|
|
428
|
+
*/
|
|
429
|
+
function siblingKeyState(listed) {
|
|
430
|
+
if (listed === undefined) {
|
|
431
|
+
return `protectedBranches is not set here, so it stands at its schema default (${patternList(DEFAULTS.protectedBranches)})`;
|
|
432
|
+
}
|
|
433
|
+
if (listed.length === 0)
|
|
434
|
+
return 'protectedBranches lists no branch, so the set is defaultBranch and nothing else';
|
|
435
|
+
return `protectedBranches still lists ${patternList(listed)}`;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* What an edit to one half of the guard pair leaves behind, in one line.
|
|
439
|
+
*
|
|
440
|
+
* The sibling half is written only for `defaultBranch`, because that is the direction with a value
|
|
441
|
+
* to name: the key the adopter did **not** set still lists what it listed, and it is reported rather
|
|
442
|
+
* than offered as a change — narrowing a protected set is the one direction that fails unsafely, and
|
|
443
|
+
* this command does not remove a key at all (module header). The hook half is written for both, from
|
|
444
|
+
* `writeGitHooks`' own note, so the two re-render routes are named here in the words that note and
|
|
445
|
+
* `doctor`'s `pre-push-guard` check name them in — but only in the one state that is owed them:
|
|
446
|
+
* {@link guardState} grades the file first, so a hook already carrying this set, a hook that is not
|
|
447
|
+
* there and a hook nothing can read out of are each reported as themselves.
|
|
448
|
+
*/
|
|
449
|
+
function branchGuardMessage(repoRoot, config, matched) {
|
|
450
|
+
const hookPath = guardHookPath(config);
|
|
451
|
+
const sibling = !matched.includes('defaultBranch')
|
|
452
|
+
? ''
|
|
453
|
+
: ` ${siblingKeyState(config.protectedBranches)}, and \`${CLI} config set protectedBranches '<json>'\` is what changes it: nothing removes an entry automatically and nothing will, because narrowing a protected set is the one direction that fails unsafely, so the edit is yours.`;
|
|
454
|
+
const state = guardState(repoRoot, config, hookPath);
|
|
455
|
+
const hook = state === 'behind'
|
|
456
|
+
? ` The committed ${hookPath} hook carries the branch set it was rendered with rather than the set the configuration resolves, and a push is judged by that file: re-render it with \`${CLI} init --force\`, which copies ${hookPath} to ${hookPath}.bak and re-renders it from the config in effect; without --force, delete ${hookPath} and re-run \`${CLI} init\`, which re-renders the hook because it is create-if-absent`
|
|
457
|
+
: state === 'in-step'
|
|
458
|
+
? ` The committed ${hookPath} hook already carries the set this configuration resolves, so nothing is owed to it by this edit.`
|
|
459
|
+
: state === 'absent'
|
|
460
|
+
? ` There is no readable ${hookPath}, so nothing in this checkout judges a push against this set: re-run \`${CLI} init\`, which writes the hook because it is create-if-absent.`
|
|
461
|
+
: ` ${hookPath} carries no case label in the generated shape, so what it protects cannot be read out of it and cannot be compared with this set — \`${CLI} doctor\`'s pre-push-guard check reports that state on every run.`;
|
|
462
|
+
return (`the protected set every guard resolves is protectedBranches unioned with defaultBranch, so setting one of those two keys alone leaves the other in the set.${sibling}` +
|
|
463
|
+
hook);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* `config set <key> <value>`: replace one value, guarded, and write the file back.
|
|
467
|
+
*
|
|
468
|
+
* The edit goes through `config/io.ts`'s update path, which re-reads the file, applies the mutator
|
|
469
|
+
* to a private copy, re-runs the structural check and refuses on any `error` — so a refusal here
|
|
470
|
+
* leaves the file exactly as it was, whichever of the guards produced it. Key order and formatting
|
|
471
|
+
* survive because the mutated object *is* the parsed file, written back through the one serializer.
|
|
472
|
+
*
|
|
473
|
+
* **The boundary.** This is the command an adopter fills a wrapped `commands.*` key in with, and the
|
|
474
|
+
* last point at which the raw command line they typed and the wrapper invocation the permission
|
|
475
|
+
* profile allow-lists are still distinguishable — by the time an agent is refused on the raw line,
|
|
476
|
+
* neither `init` nor `doctor` can tell which of the two the adopter meant. So the value is reported
|
|
477
|
+
* here, through {@link wrappedKeyMismatch}, whose sentence and condition this command shares with
|
|
478
|
+
* those two rather than restating.
|
|
479
|
+
*
|
|
480
|
+
* It is a **warning, not a refusal**, and the value is stored exactly as typed: the schema accepts it,
|
|
481
|
+
* the wrapper the next `init` writes runs it, and the documented repair for an undetected command is
|
|
482
|
+
* a two-step that passes through this state (set the raw line, re-run `init`, set the wrapper form).
|
|
483
|
+
* Normalising the value here — writing the invocation and putting the raw line in the wrapper —
|
|
484
|
+
* would make `get` answer something other than what was `set`, and would break the module header's
|
|
485
|
+
* *"It writes nothing but `harness.config.json`"*.
|
|
486
|
+
*/
|
|
487
|
+
function set(ctx, key, raw) {
|
|
488
|
+
const repoRoot = resolveRepoRoot(ctx.cwd);
|
|
489
|
+
const segments = parseKeyPath(key);
|
|
490
|
+
const value = parseValue(raw);
|
|
491
|
+
const plan = new WritePlan();
|
|
492
|
+
let assignment;
|
|
493
|
+
const updated = updateConfig(repoRoot, (config) => {
|
|
494
|
+
assignment = assignValue(config, key, segments, value);
|
|
495
|
+
}, plan);
|
|
496
|
+
if (assignment === undefined) {
|
|
497
|
+
throw new HarnessError('config set: the update was enqueued without the edit having been applied', EXIT.INTERNAL);
|
|
498
|
+
}
|
|
499
|
+
ctx.report.step(ctx.flags.dryRun ? `config set ${key} (dry run — nothing is written)` : `config set ${key}`);
|
|
500
|
+
ctx.report.result(assignment.existed ? `${key} was ${render(assignment.previous)}` : `${key} was not set`);
|
|
501
|
+
// Nothing to write is reported rather than performed: replacing a file with its own bytes would
|
|
502
|
+
// still make a .bak sibling and still log a replacement, which reads as a change that was not one.
|
|
503
|
+
const unchanged = assignment.existed && formatJson(assignment.previous) === formatJson(value);
|
|
504
|
+
if (unchanged) {
|
|
505
|
+
ctx.report.result(`${key} already holds that value, so ${CONFIG_FILENAME} was not rewritten`);
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
ctx.report.result(ctx.flags.dryRun ? `${key} would become ${render(value)}` : `${key} is now ${render(value)}`);
|
|
509
|
+
// `force: true` unconditionally, and never `ctx.flags.force` — see choice 2 in the module header:
|
|
510
|
+
// the update is enqueued as create-if-absent, so an unforced apply would keep the file and the
|
|
511
|
+
// edit would silently not land. The engine writes the `.bak` sibling before replacing.
|
|
512
|
+
plan.apply({ repoRoot, report: ctx.report, dryRun: ctx.flags.dryRun, force: true });
|
|
513
|
+
}
|
|
514
|
+
// Asked of `updated.config` — the value that is landing, not the one that was there — and outside
|
|
515
|
+
// the arms above, so all three reach it: a `--dry-run` that withheld the line would report a
|
|
516
|
+
// success a real run would not have, and a `set` that changed nothing still leaves a repository
|
|
517
|
+
// carrying the defect.
|
|
518
|
+
for (const wrapperKey of wrapperKeysFor(key)) {
|
|
519
|
+
const mismatch = wrappedKeyMismatch(updated.config, wrapperKey);
|
|
520
|
+
if (mismatch !== undefined)
|
|
521
|
+
ctx.report.warn(wrappedKeyMismatchMessage(wrapperKey, mismatch));
|
|
522
|
+
}
|
|
523
|
+
// Beside the wrapper report, asked of the same object and outside the same arms, for the same
|
|
524
|
+
// reason: an edit to one half of the guard pair leaves the sibling key behind on every path, and a
|
|
525
|
+
// preview that withheld the line would report a success a real run would not have. What it says
|
|
526
|
+
// about the hook is graded against the file rather than assumed — including on a --dry-run, where
|
|
527
|
+
// the hook on disk is the one a real run would have left behind. One warning, whichever half was
|
|
528
|
+
// matched.
|
|
529
|
+
const branchGuardKeys = branchGuardKeysFor(key);
|
|
530
|
+
if (branchGuardKeys.length > 0)
|
|
531
|
+
ctx.report.warn(branchGuardMessage(repoRoot, updated.config, branchGuardKeys));
|
|
532
|
+
// Warnings only — an error would have been refused above. Reported because a `set` is often the
|
|
533
|
+
// fix for one of them, and the ones still outstanding are worth naming while the adopter is here.
|
|
534
|
+
for (const problem of updated.problems)
|
|
535
|
+
ctx.report.warn(formatProblem(problem));
|
|
536
|
+
return EXIT.OK;
|
|
537
|
+
}
|
|
538
|
+
/** Parse the verb and hand off. Every verb returns its own exit code and throws to refuse. */
|
|
539
|
+
async function run(ctx) {
|
|
540
|
+
const invocation = parseInvocation(ctx.argv);
|
|
541
|
+
if (invocation.verb === 'list')
|
|
542
|
+
return list(ctx);
|
|
543
|
+
if (invocation.verb === 'get')
|
|
544
|
+
return get(ctx, invocation.key);
|
|
545
|
+
return set(ctx, invocation.key, invocation.value);
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* The registry row for this command.
|
|
549
|
+
*
|
|
550
|
+
* Exported as the row itself rather than as a `run` the table wraps, so the summary, the usage lines
|
|
551
|
+
* and the behaviour stay in the file that owns them. The import back to `commands/registry.ts` is
|
|
552
|
+
* type-only and therefore erased, so the table can list this row without a runtime cycle.
|
|
553
|
+
*/
|
|
554
|
+
export const CONFIG_COMMAND = {
|
|
555
|
+
name: 'config',
|
|
556
|
+
summary: SUMMARY,
|
|
557
|
+
roadmapItem: ROADMAP_ITEM,
|
|
558
|
+
usage: CONFIG_USAGE,
|
|
559
|
+
run,
|
|
560
|
+
};
|
|
561
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|