autonomous-sdlc-harness 0.5.0 → 0.6.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.
Files changed (35) hide show
  1. package/dist/commands/init.js +17 -8
  2. package/dist/commands/init.js.map +1 -1
  3. package/dist/config/check.js +27 -5
  4. package/dist/config/check.js.map +1 -1
  5. package/dist/config/model.js +54 -11
  6. package/dist/config/model.js.map +1 -1
  7. package/dist/core/pluginIdentity.js +2 -0
  8. package/dist/core/pluginIdentity.js.map +1 -1
  9. package/dist/core/writer.js +1 -0
  10. package/dist/core/writer.js.map +1 -1
  11. package/dist/doctor/checks.js +317 -40
  12. package/dist/doctor/checks.js.map +1 -1
  13. package/dist/generators/githubWorkflows.js +21 -11
  14. package/dist/generators/githubWorkflows.js.map +1 -1
  15. package/dist/remote/githubActions.js +63 -4
  16. package/dist/remote/githubActions.js.map +1 -1
  17. package/dist/retrieval/pythonBackend.js +114 -0
  18. package/dist/retrieval/pythonBackend.js.map +1 -0
  19. package/dist/retrieval/setup.js +8 -0
  20. package/dist/retrieval/setup.js.map +1 -1
  21. package/package.json +1 -1
  22. package/templates/README.md +1 -1
  23. package/templates/github/workflows/harness-control.yml +184 -0
  24. package/templates/github/workflows/harness-resume.yml +7 -0
  25. package/templates/github/workflows/harness-run.yml +100 -1
  26. package/templates/github/workflows/harness-trigger.yml +5 -4
  27. package/templates/scripts/README.md +1 -1
  28. package/templates/scripts/autonomous-watcher.sh +29 -2
  29. package/templates/scripts/docs-search-server.sh +88 -17
  30. package/templates/scripts/lib/harness-run-lib.sh +205 -26
  31. package/templates/scripts/remote-run.sh +2617 -150
  32. package/templates/scripts/scratch-run.sh +54 -73
  33. package/templates/state-dir/README-root.md +1 -1
  34. package/templates/state-dir/scratch/README.md +4 -2
  35. package/templates/state-dir/user_reviews/README.md +2 -2
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Generator: the GitHub Actions workflows remote execution runs on — `harness-run.yml`, the job
3
- * the watcher dispatches a run to, `harness-resume.yml`, the self-disabling resume poller, and
4
- * `harness-trigger.yml`, the issue-label and `repository_dispatch` trigger — written into the
5
- * adopter's `.github/workflows/`.
3
+ * the watcher dispatches a run to, `harness-resume.yml`, the self-disabling resume poller,
4
+ * `harness-trigger.yml`, the issue-label and `repository_dispatch` trigger, and `harness-control.yml`,
5
+ * the comment-command and review handler — written into the adopter's `.github/workflows/`.
6
6
  *
7
7
  * **The rule this module exists to enforce: the first two workflows are written exactly when
8
- * `config/model.ts` → `remoteExecutionApplies(config)` holds, the trigger exactly when
9
- * `config/model.ts` → `forgeTriggerApplies(config)` also holds, and all three from the templates under
8
+ * `config/model.ts` → `remoteExecutionApplies(config)` holds, the two forge workflows — the trigger
9
+ * and the control workflow — exactly when `config/model.ts` → `forgeTriggerApplies(config)` also
10
+ * holds, and all four from the templates under
10
11
  * `cli/templates/` → {@link WORKFLOW_TEMPLATE_DIR} only.** With the key absent or `local` this module
11
12
  * enqueues nothing, so such a repository receives exactly what `init` wrote before remote execution
12
13
  * existed. Every name — the directory, the file names, the template directory — is imported from
@@ -34,9 +35,10 @@
34
35
  * carried into its re-render because the schedule is the one thing an adopter tunes inside that
35
36
  * file; every other edit to either file survives only in its `.bak`. The runner and the timeouts
36
37
  * are repository variables, which the re-render does not touch.
37
- * 5. **The trigger workflow is gated on `forgeTriggerApplies`, carries no pin and is not upgraded,**
38
- * because it calls the scripts on the default branch and shares their re-run contract. It is
39
- * copied verbatim like `harness-resume.yml` (choice 3) and never carries a `forceOverride`.
38
+ * 5. **The two forge workflows — the trigger and the control workflow — are gated on
39
+ * `forgeTriggerApplies`, carry no pin and are not upgraded,** because each calls the scripts on the
40
+ * default branch and shares their re-run contract. Both are copied verbatim like
41
+ * `harness-resume.yml` (choice 3) and never carry a `forceOverride`, upgrade mode included.
40
42
  *
41
43
  * **Declared mirror.** `cli/templates/github/workflows/harness-run.yml`'s `Install the pinned plugin`
42
44
  * step spells the route {@link upgradeWorkflowsCommand} produces,
@@ -56,7 +58,7 @@ import { forgeTriggerApplies, remoteExecutionApplies } from '../config/model.js'
56
58
  import { ownManifestString, readTemplate } from '../core/paths.js';
57
59
  import { renderTemplate } from '../core/templating.js';
58
60
  import { unquoteYamlScalar } from '../core/yamlScalar.js';
59
- import { WORKFLOW_RESUME_FILE, WORKFLOW_RESUME_PATH, WORKFLOW_RUN_FILE, WORKFLOW_RUN_PATH, WORKFLOW_TEMPLATE_DIR, WORKFLOW_TRIGGER_FILE, WORKFLOW_TRIGGER_PATH, renderedCliVersions, } from '../remote/githubActions.js';
61
+ import { WORKFLOW_RESUME_FILE, WORKFLOW_RESUME_PATH, WORKFLOW_CONTROL_FILE, WORKFLOW_CONTROL_PATH, WORKFLOW_RUN_FILE, WORKFLOW_RUN_PATH, WORKFLOW_TEMPLATE_DIR, WORKFLOW_TRIGGER_FILE, WORKFLOW_TRIGGER_PATH, renderedCliVersions, } from '../remote/githubActions.js';
60
62
  /** The `init` flag that runs {@link writeGithubWorkflows} with {@link GithubWorkflowsOptions.upgrade}. */
61
63
  export const UPGRADE_WORKFLOWS_FLAG = '--upgrade-workflows';
62
64
  /** The one producer of the `npx <package>@<version>` prefix a version-pinned remedy command starts with. */
@@ -91,8 +93,8 @@ function carryCron(template, cron) {
91
93
  .join('\n');
92
94
  }
93
95
  /**
94
- * Enqueue the workflows when remote execution is on — the trigger only when `forgeTriggerApplies` also
95
- * holds — and nothing otherwise.
96
+ * Enqueue the workflows when remote execution is on — the trigger and control workflows only when
97
+ * `forgeTriggerApplies` also holds — and nothing otherwise.
96
98
  *
97
99
  * Nothing here writes the filesystem: the generator plans, and `init` applies the plan once. The
98
100
  * upgrade mode reads the two existing workflows to decide.
@@ -150,6 +152,14 @@ export function writeGithubWorkflows({ repoRoot, config, plan, upgrade = false,
150
152
  label: `workflow ${WORKFLOW_TRIGGER_FILE}`,
151
153
  });
152
154
  workflows.push({ absolute: triggerPath, repoPath: WORKFLOW_TRIGGER_PATH });
155
+ const controlPath = join(repoRoot, ...WORKFLOW_CONTROL_PATH.split('/'));
156
+ plan.add({
157
+ path: controlPath,
158
+ policy: 'create-if-absent',
159
+ content: readTemplate(`${WORKFLOW_TEMPLATE_DIR}/${WORKFLOW_CONTROL_FILE}`),
160
+ label: `workflow ${WORKFLOW_CONTROL_FILE}`,
161
+ });
162
+ workflows.push({ absolute: controlPath, repoPath: WORKFLOW_CONTROL_PATH });
153
163
  }
154
164
  return {
155
165
  written: true,
@@ -1 +1 @@
1
- {"version":3,"file":"githubWorkflows.js","sourceRoot":"","sources":["../../src/generators/githubWorkflows.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"githubWorkflows.js","sourceRoot":"","sources":["../../src/generators/githubWorkflows.ts"],"names":[],"mappings":"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"}
@@ -11,14 +11,19 @@
11
11
  * Except in `generators/repoRoot.ts`, nothing here is consulted unless `config/model.ts` →
12
12
  * `remoteExecutionApplies(config)` is true: every other consumer tests that switch first. That one
13
13
  * is ungated because a gated rule would change `.gitignore` in the same run that turns remote
14
- * execution on. The issue-trigger names (`WORKFLOW_TRIGGER_*`, `TRIGGER_*`, `DEFAULT_TRIGGER_LABEL`)
15
- * are gated tighter still: they are consulted only where `forgeTriggerApplies(config)` is true.
14
+ * execution on. The issue-trigger names (`WORKFLOW_TRIGGER_*`, `TRIGGER_*`, `DEFAULT_TRIGGER_LABEL`,
15
+ * `LEGACY_TRIGGER_LABEL`)
16
+ * and the run-control names (`WORKFLOW_CONTROL_*`, `COMMAND_*`, `COMMENT_MARKER`,
17
+ * `REVIEW_ROUND_STATE`, `STATE_LABEL_PREFIX`, `RUN_STATES`, `STATE_LABELS`, `PR_CREATE_SETTING`,
18
+ * `PR_CREATE_SETTING_PATH`) are gated tighter
19
+ * still: they are consulted only where `forgeTriggerApplies(config)` is true.
16
20
  *
17
21
  * **Shell and YAML mirrors that must agree byte for byte.** The compiler cannot reach them, so each
18
22
  * declares the mirror in its own header, and a rename here is an edit to each of them:
19
23
  * `cli/templates/scripts/remote-run.sh`, `cli/templates/github/workflows/harness-run.yml`,
20
24
  * `cli/templates/github/workflows/harness-resume.yml`,
21
- * `cli/templates/github/workflows/harness-trigger.yml` and
25
+ * `cli/templates/github/workflows/harness-trigger.yml`,
26
+ * `cli/templates/github/workflows/harness-control.yml` and
22
27
  * `cli/templates/scripts/lib/harness-run-lib.sh`, which mirrors {@link WORKFLOW_RUN_FILE} and
23
28
  * {@link STATE_ARTIFACT_NAME} for the GitHub route its notification producers print.
24
29
  * `cli/templates/scripts/autonomous-watcher.sh` is not one: it reaches GitHub only through
@@ -43,6 +48,34 @@ export const WORKFLOW_RESUME_PATH = `${WORKFLOWS_DIR}/${WORKFLOW_RESUME_FILE}`;
43
48
  /** The workflow that turns a labelled issue or a `repository_dispatch` event into a remote run. */
44
49
  export const WORKFLOW_TRIGGER_FILE = 'harness-trigger.yml';
45
50
  export const WORKFLOW_TRIGGER_PATH = `${WORKFLOWS_DIR}/${WORKFLOW_TRIGGER_FILE}`;
51
+ /** The workflow that turns a comment command or a review into a harness action. */
52
+ export const WORKFLOW_CONTROL_FILE = 'harness-control.yml';
53
+ export const WORKFLOW_CONTROL_PATH = `${WORKFLOWS_DIR}/${WORKFLOW_CONTROL_FILE}`;
54
+ /** The first word of a command comment, matched case-insensitively. */
55
+ export const COMMAND_HANDLE = '@sdlc-harness';
56
+ /** The verbs a command comment may carry after {@link COMMAND_HANDLE}. */
57
+ export const COMMAND_VERBS = ['answer', 'pause', 'resume', 'stop', 'clear'];
58
+ /**
59
+ * The prefix of the hidden line every harness comment carries; the whole line is
60
+ * `<!-- sdlc-harness event=<event> branch=<branch>[ question=<n>] -->`. A comment containing the
61
+ * prefix anywhere is never a command.
62
+ */
63
+ export const COMMENT_MARKER = '<!-- sdlc-harness';
64
+ /** The `review.state` that starts a review round, lowercase as the webhook payload carries it. */
65
+ export const REVIEW_ROUND_STATE = 'changes_requested';
66
+ /** The prefix every run-state label's name starts with. */
67
+ export const STATE_LABEL_PREFIX = 'sdlc-harness: ';
68
+ /** The states a run's pull request is labelled with, one label each. */
69
+ export const RUN_STATES = ['running', 'parked', 'paused', 'done', 'failed', 'stopped'];
70
+ /** The label name for each {@link RunState}; total, so a new state fails to compile until it has one. */
71
+ export const STATE_LABELS = {
72
+ running: `${STATE_LABEL_PREFIX}running`,
73
+ parked: `${STATE_LABEL_PREFIX}parked`,
74
+ paused: `${STATE_LABEL_PREFIX}paused`,
75
+ done: `${STATE_LABEL_PREFIX}done`,
76
+ failed: `${STATE_LABEL_PREFIX}failed`,
77
+ stopped: `${STATE_LABEL_PREFIX}stopped`,
78
+ };
46
79
  /** Under `cli/templates/`; stored without the dot, which `init` adds (`cli/templates/README.md`). */
47
80
  export const WORKFLOW_TEMPLATE_DIR = 'github/workflows';
48
81
  /** The Actions artifact every job uploads its state bundle as. */
@@ -56,7 +89,29 @@ export const REMOTE_STOP_VARIABLE = 'HARNESS_REMOTE_STOP';
56
89
  /** Repository variable naming the issue label that starts a run; unset or empty means {@link DEFAULT_TRIGGER_LABEL}. */
57
90
  export const TRIGGER_LABEL_VARIABLE = 'HARNESS_TRIGGER_LABEL';
58
91
  /** The issue label that starts a run when {@link TRIGGER_LABEL_VARIABLE} is unset or empty. */
59
- export const DEFAULT_TRIGGER_LABEL = 'harness';
92
+ export const DEFAULT_TRIGGER_LABEL = 'sdlc-harness';
93
+ /**
94
+ * The previous release's {@link DEFAULT_TRIGGER_LABEL}. The trigger still accepts it when its
95
+ * workflow passes no label, which only that release's `harness-trigger.yml` does: it is never
96
+ * re-rendered by `init --upgrade-workflows`, and its own `if:` already ran the job for this label.
97
+ */
98
+ export const LEGACY_TRIGGER_LABEL = 'harness';
99
+ const TRIGGER_FALLBACK_PATTERN = new RegExp(`\\(\\s*vars\\.${TRIGGER_LABEL_VARIABLE}\\s*\\|\\|\\s*'([^']+)'\\s*\\)`);
100
+ /**
101
+ * The label a trigger workflow's text falls back to when {@link TRIGGER_LABEL_VARIABLE} is unset: the
102
+ * single-quoted literal of the first `(vars.HARNESS_TRIGGER_LABEL || '<label>')`, or `undefined` when
103
+ * no line carries one. Pure — the caller reads the file. It exists because the committed
104
+ * `harness-trigger.yml` carries no version pin and is never upgraded, so its own fallback, not
105
+ * {@link DEFAULT_TRIGGER_LABEL}, is what starts a run in a repository wired by an earlier release.
106
+ */
107
+ export function triggerFallbackLabel(text) {
108
+ for (const line of text.split(/\r?\n/)) {
109
+ const match = TRIGGER_FALLBACK_PATTERN.exec(line);
110
+ if (match !== null)
111
+ return match[1];
112
+ }
113
+ return undefined;
114
+ }
60
115
  /** Repository variable: comma-separated bot logins that may start a run; unset or empty admits none. */
61
116
  export const TRIGGER_ALLOWED_BOTS_VARIABLE = 'HARNESS_TRIGGER_ALLOWED_BOTS';
62
117
  /** The `repository_dispatch` `event_type` the trigger workflow listens to. */
@@ -67,6 +122,10 @@ export const OAUTH_TOKEN_SECRET = 'CLAUDE_CODE_OAUTH_TOKEN';
67
122
  export const API_KEY_SECRET = 'ANTHROPIC_API_KEY';
68
123
  export const PUSH_URL_SECRET = 'HARNESS_PUSH_URL';
69
124
  export const GIT_TOKEN_SECRET = 'HARNESS_GIT_TOKEN';
125
+ /** GitHub's repository setting that lets a workflow's own token open a pull request; off by default. */
126
+ export const PR_CREATE_SETTING = 'Allow GitHub Actions to create and approve pull requests';
127
+ /** Where an adopter finds {@link PR_CREATE_SETTING} in the repository's settings. */
128
+ export const PR_CREATE_SETTING_PATH = 'Settings -> Actions -> General -> Workflow permissions';
70
129
  /** The environment variable naming the binary run as `gh`: `${HARNESS_GH_CLI:-gh}`. */
71
130
  export const GH_CLI_VARIABLE = 'HARNESS_GH_CLI';
72
131
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"githubActions.js","sourceRoot":"","sources":["../../src/remote/githubActions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"githubActions.js","sourceRoot":"","sources":["../../src/remote/githubActions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Every fact about the Python docs-retrieval backend that both the launcher and `doctor` need: the
3
+ * console script's name, its sub-commands, the database variable, the default connection string, the
4
+ * launcher's unavailable-backend exit code, the `self-check` line contract and the launcher's `PATH`
5
+ * fallback list.
6
+ *
7
+ * **The rule this module exists to enforce: every name the Python backend is reached by is spelled
8
+ * here once, and each copy outside the compiler is a declared mirror.**
9
+ *
10
+ * Pure data and pure functions: this module spawns nothing, reads no file and imports no retrieval
11
+ * peer, so `cli/test/retrieval-loading.test.mjs`'s guarantees do not reach it.
12
+ *
13
+ * **MIRRORS.** Each copy outside the compiler, and what it holds:
14
+ * - `cli/templates/scripts/docs-search-server.sh` — {@link PYTHON_RETRIEVAL_COMMAND},
15
+ * {@link PYTHON_SERVE_SUB_COMMAND}, {@link PYTHON_DATABASE_URL_VARIABLE},
16
+ * {@link PYTHON_DEFAULT_DATABASE_URL} and {@link PYTHON_BACKEND_UNAVAILABLE_EXIT}.
17
+ * - `docs-retrieval-service/compose.yaml` → `postgres` — the user, password, database and port inside
18
+ * {@link PYTHON_DEFAULT_DATABASE_URL}.
19
+ * - `docs-retrieval-service/src/harness_docs_retrieval/self_check.py` — `SELF_CHECK_QUESTIONS`
20
+ * ({@link SELF_CHECK_QUESTIONS}), `CheckLine.render` (the line shape {@link parseSelfCheck} reads)
21
+ * and `_check_index`'s not-attempted detail ({@link SELF_CHECK_INDEX_NOT_ATTEMPTED}).
22
+ * - `docs-retrieval-service/src/harness_docs_retrieval/store.py` — `DATABASE_URL_ENV`
23
+ * ({@link PYTHON_DATABASE_URL_VARIABLE}).
24
+ * - `cli/templates/scripts/lib/harness-run-lib.sh` → `hr_path_with_fallbacks` —
25
+ * {@link LAUNCHER_PATH_FALLBACKS} and the policy {@link launcherSearchPath} reproduces.
26
+ * - `docs-retrieval-service/tests/test_launcher_e2e.py` — `_BACKEND_UNAVAILABLE_EXIT`
27
+ * ({@link PYTHON_BACKEND_UNAVAILABLE_EXIT}).
28
+ *
29
+ * A change to a mirrored literal is an edit to every file that mirrors it, in the same change; a
30
+ * mirror this header does not declare is a defect (`.claude/context/conventions.md` →
31
+ * `## Configuration is the source of truth…`, the persisted-key bullet).
32
+ */
33
+ /** The Python package's console script. */
34
+ export const PYTHON_RETRIEVAL_COMMAND = 'harness-docs-retrieval';
35
+ /** The sub-command the launcher runs as its child to serve MCP over stdio, never `exec`ed. */
36
+ export const PYTHON_SERVE_SUB_COMMAND = 'serve-mcp';
37
+ /** The sub-command whose stdout {@link parseSelfCheck} reads. */
38
+ export const PYTHON_SELF_CHECK_SUB_COMMAND = 'self-check';
39
+ /** The sub-command `doctor`'s missing-weights remedy names. */
40
+ export const PYTHON_FETCH_MODELS_SUB_COMMAND = 'fetch-models';
41
+ /** The variable the Python backend reads its Postgres connection string from. */
42
+ export const PYTHON_DATABASE_URL_VARIABLE = 'HARNESS_DOCS_RETRIEVAL_DATABASE_URL';
43
+ /**
44
+ * The connection string used when {@link PYTHON_DATABASE_URL_VARIABLE} is unset. The credentials are
45
+ * the compose file's throwaway values for a loopback-only container, never a real secret.
46
+ */
47
+ export const PYTHON_DEFAULT_DATABASE_URL = 'postgresql://harness:harness@127.0.0.1:5432/docs_retrieval';
48
+ /** The launcher's exit code when the Python backend is selected but cannot be started. */
49
+ export const PYTHON_BACKEND_UNAVAILABLE_EXIT = 3;
50
+ /** The questions `self-check` answers, one line each, in this order. */
51
+ export const SELF_CHECK_QUESTIONS = ['packages', 'weights', 'index'];
52
+ /** `CheckLine.render`'s two prefixes; the `ok` one is padded to the width of `FAIL `. */
53
+ const SELF_CHECK_LINE = /^(ok {3}|FAIL )([a-z]+): (.*)$/;
54
+ /**
55
+ * The `index` line's detail when an earlier question failed, naming that question — `_check_index`'s
56
+ * `not attempted, because … failed`.
57
+ */
58
+ export const SELF_CHECK_INDEX_NOT_ATTEMPTED = /^not attempted, because (packages|weights) failed$/;
59
+ /**
60
+ * Parse `self-check`'s stdout. Answers `undefined` unless the non-empty lines are exactly one per
61
+ * {@link SELF_CHECK_QUESTIONS} entry, in that order, each in `CheckLine.render`'s shape — a shape this
62
+ * cannot read is the caller's to report, never guessed at.
63
+ */
64
+ export function parseSelfCheck(stdout) {
65
+ const lines = stdout.split(/\r?\n/).filter((line) => line.length > 0);
66
+ if (lines.length !== SELF_CHECK_QUESTIONS.length)
67
+ return undefined;
68
+ const parsed = new Map();
69
+ for (const [index, question] of SELF_CHECK_QUESTIONS.entries()) {
70
+ const match = SELF_CHECK_LINE.exec(lines[index] ?? '');
71
+ if (match === null || match[2] !== question)
72
+ return undefined;
73
+ parsed.set(question, { question, ok: match[1] !== 'FAIL ', detail: match[3] ?? '' });
74
+ }
75
+ return parsed;
76
+ }
77
+ /**
78
+ * The connection string the server will use: `serverEnv[PYTHON_DATABASE_URL_VARIABLE]` when
79
+ * `serverEnv` (the `harness-docs` server's `env` object in `.mcp.json`) is an object holding a
80
+ * non-empty string there, else {@link PYTHON_DEFAULT_DATABASE_URL}. A shell export is deliberately not
81
+ * consulted: the agent runner never passes one to the server (`docs/retrieval.md` → **How the variable
82
+ * reaches the server, since an export does not.**).
83
+ */
84
+ export function pythonDatabaseUrl(serverEnv) {
85
+ if (typeof serverEnv === 'object' && serverEnv !== null && !Array.isArray(serverEnv)) {
86
+ const value = serverEnv[PYTHON_DATABASE_URL_VARIABLE];
87
+ if (typeof value === 'string' && value.length > 0)
88
+ return value;
89
+ }
90
+ return PYTHON_DEFAULT_DATABASE_URL;
91
+ }
92
+ /** The fixed directories `hr_path_with_fallbacks` appends, in its order. */
93
+ export const LAUNCHER_PATH_FALLBACKS = ['/opt/homebrew/bin', '/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin'];
94
+ /**
95
+ * The `PATH` the launcher resolves {@link PYTHON_RETRIEVAL_COMMAND} on, as `hr_path_with_fallbacks`
96
+ * builds it: the inherited non-empty entries kept in order, each {@link LAUNCHER_PATH_FALLBACKS} entry
97
+ * not already present appended, then `<home>/.local/bin` (one trailing `/` stripped from `home`) when
98
+ * `home` is non-empty and that entry is not among the inherited ones.
99
+ */
100
+ export function launcherSearchPath(inherited, home) {
101
+ const kept = inherited.split(':').filter((entry) => entry.length > 0);
102
+ const suffix = [];
103
+ for (const dir of LAUNCHER_PATH_FALLBACKS) {
104
+ if (!kept.includes(dir) && !suffix.includes(dir))
105
+ suffix.push(dir);
106
+ }
107
+ if (home !== undefined && home.length > 0) {
108
+ const local = `${home.endsWith('/') ? home.slice(0, -1) : home}/.local/bin`;
109
+ if (!kept.includes(local))
110
+ suffix.push(local);
111
+ }
112
+ return [...kept, ...suffix].join(':');
113
+ }
114
+ //# sourceMappingURL=pythonBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pythonBackend.js","sourceRoot":"","sources":["../../src/retrieval/pythonBackend.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,10 @@
14
14
  * runtime is a warning rather than an `npm` call, so a test that forgets to plant one stays offline.
15
15
  * - **A failed step is a warning.** The wiring the plan wrote stays valid; `doctor` fails until a
16
16
  * re-run completes the step.
17
+ * - **The Python backend gets no install and no download here, and the TypeScript setup still runs.**
18
+ * Its package, weights and Postgres are provisioned by hand; the TypeScript runtime and models are
19
+ * kept so switching `docs.retrievalBackend` back costs nothing. With `python` selected, one note
20
+ * says both.
17
21
  *
18
22
  * Both steps put machine state outside the repository, not through the write engine
19
23
  * (`cli/src/core/writer.ts` header). `setUpRuntime` writes the runtime itself, through `npm`;
@@ -25,6 +29,7 @@ import { mkdirSync } from 'node:fs';
25
29
  import { join } from 'node:path';
26
30
  import { ownManifestString } from '../core/paths.js';
27
31
  import { modelFilesPresent, RETRIEVAL_STUB_ENV, stubModelsSelected } from './models.js';
32
+ import { PYTHON_RETRIEVAL_COMMAND } from './pythonBackend.js';
28
33
  import { retrievalCliEntry, retrievalModelCacheDir, retrievalPeers, retrievalRuntimeDir, retrievalRuntimeState, RUNTIME_CLI_RELATIVE, } from './runtime.js';
29
34
  /** Both child processes may take minutes on a cold cache. */
30
35
  const STEP_TIMEOUT_MS = 900000;
@@ -116,6 +121,9 @@ export function setUpRetrieval(options) {
116
121
  const warnings = [];
117
122
  setUpRuntime(options.dryRun, notes, warnings);
118
123
  setUpModels(options.dryRun, notes, warnings);
124
+ if (options.backend === 'python') {
125
+ notes.push(`docs.retrievalBackend is python: init installed and downloaded nothing for it — the \`${PYTHON_RETRIEVAL_COMMAND}\` package, its weights and its Postgres are set up by hand (docs/retrieval.md → Turning on the Python backend); the TypeScript runtime and models above are kept so switching back costs nothing`);
126
+ }
119
127
  return { notes, warnings };
120
128
  }
121
129
  //# sourceMappingURL=setup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/retrieval/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/retrieval/setup.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autonomous-sdlc-harness",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "The outer loop of the autonomous SDLC harness: init, doctor, config and daemon management for the harness Claude Code plugin, plus opt-in local docs retrieval.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "firu-daniel",
@@ -9,7 +9,7 @@ The generator templates `init` copies into an adopted repository. Nothing here i
9
9
  | `githooks/` | the configured `githooksDir` |
10
10
  | `scripts/` | the configured `scriptsDir` |
11
11
  | `state-dir/` | the configured `stateDir` |
12
- | `github/` | `.github/` in the adopter's repo — `workflows/harness-run.yml` and `workflows/harness-resume.yml`, written only when `execution.target` is `github-actions`, and `workflows/harness-trigger.yml`, written only when `forge` is also `github` |
12
+ | `github/` | `.github/` in the adopter's repo — `workflows/harness-run.yml` and `workflows/harness-resume.yml`, written only when `execution.target` is `github-actions`, and `workflows/harness-trigger.yml` and `workflows/harness-control.yml`, written only when `forge` is also `github` |
13
13
 
14
14
  **Naming rule for the whole tree: a template whose adopter-side name begins with a dot is stored here without the dot.** `repo/gitignore` is written as `.gitignore`, `repo/mcp.json` as `.mcp.json`, and the `claude/` subtree lands at `.claude/` and the `github/` subtree at `.github/`; `init` adds the dot when it writes. The rule is load-bearing twice over — a real `.gitignore` inside this repository would be honoured by git and could silently exclude files that are meant to ship, and npm rewrites a packaged `.gitignore` to `.npmignore` on publish, so a dot-named template does not survive the wire.
15
15
 
@@ -0,0 +1,184 @@
1
+ # harness-control.yml — acts on an autonomous-sdlc-harness command comment
2
+ # (`@sdlc-harness answer|pause|resume|stop|clear`) on an issue or pull request,
3
+ # and turns a pull-request review requesting changes into the next user-review
4
+ # round.
5
+ #
6
+ # WHO WRITES IT. `autonomous-sdlc-harness init`, only when harness.config.json's
7
+ # `forge` is `github` and its `execution.target` is `github-actions`. Written
8
+ # create-if-absent: from then on it is yours to tune, and a re-run of `init`
9
+ # keeps your copy. `init --upgrade-workflows` does NOT re-render it: it carries
10
+ # no version pin and calls the scripts on the default branch, so it shares
11
+ # their re-run contract — `init --force` replaces it after a `.bak`. It is a
12
+ # file of its own, apart from harness-trigger.yml, so you can disable comment
13
+ # control alone: disabling a workflow disables every event in it.
14
+ #
15
+ # WHAT IT DOES. One job runs `remote-run.sh control`, which does everything
16
+ # else: it authorises the actor, finds the run's branch, carries out the
17
+ # command or places the review round, and replies. Every decision lives in that
18
+ # script; this file carries only the events, the permissions, a prefilter and
19
+ # the concurrency group.
20
+ # The `run-name` below is not harness-run.yml's `harness <action> <branch>`
21
+ # title, so no run lookup `remote-run.sh` makes by that title can match it.
22
+ #
23
+ # THE EVENTS.
24
+ # issue_comment, type `created` only: a command is a new comment. GitHub
25
+ # raises it for a comment on an issue and on a pull request alike.
26
+ # pull_request_review, type `submitted` only: the round is built from the
27
+ # review event, which carries the review body and identifies its inline
28
+ # comments (docs/github-integration-research.md, C1).
29
+ # Never pull_request_review_comment: one review raises one such event per
30
+ # inline comment, so listening to it would start one job per comment for a
31
+ # round the review event already covers (C1).
32
+ #
33
+ # THE PREFILTER. The job's `if:` runs it only for a comment that contains
34
+ # `@sdlc-harness` and not `<!-- sdlc-harness` (the hidden line every harness
35
+ # reply carries, so a reply quoting a command is never one), or for a review
36
+ # whose state is `changes_requested` on a pull request from this repository.
37
+ # Every other comment or review yields a skipped job, which runs no runner and
38
+ # bills nothing (docs/remote-execution.md, `### Verified in Gate 12 round 2`).
39
+ # It is a saving, not the authority: `control` re-checks every rule, so an
40
+ # edited copy of this filter cannot bypass one. That `contains()` compares
41
+ # case-insensitively is GitHub's documented behaviour, not verified here; a
42
+ # mixed-case handle the filter missed would only go unanswered, never obeyed.
43
+ #
44
+ # THE PERMISSIONS, declared because the default token may be read-only
45
+ # (docs/github-integration-research.md, T2):
46
+ # contents: write push a review round
47
+ # actions: write dispatch, pause, stop and cancel runs, and read
48
+ # runs and their artifacts
49
+ # issues: write reply on the issue or pull request, and label it
50
+ # pull-requests: write read the pull request, its reviews and comments,
51
+ # and label it
52
+ # The job reads no repository secret: it needs only its own token, so the
53
+ # credential secrets never reach the job that reads untrusted comment text.
54
+ # Every reply is posted as github-actions[bot] and starts no workflow (S3).
55
+ #
56
+ # FORK PULL REQUESTS. Never `pull_request_target`, which would run with this
57
+ # repository's write token on a fork's event (C2).
58
+ # A `pull_request_review` job runs this file as the pull request's merge
59
+ # commit carries it (docs/github-integration-research.md, C2), so the `if:`
60
+ # that skips a fork's review is the fork's own copy: a fork that edits it is
61
+ # not skipped, and can name any `runs-on:` label, a self-hosted runner's
62
+ # included. Such a job gets a read-only token and no secret (C2), and fork
63
+ # approval policies apply to it.
64
+ # A comment on a fork's pull request runs with a write token, and `control`
65
+ # refuses it.
66
+ # The checkout is always the default branch, never the pull request's merge
67
+ # commit a `pull_request_review` job checks out by default, so the script that
68
+ # decides is always the default branch's; what a pull request's head can change
69
+ # is this file's own definition for its own review events.
70
+ #
71
+ # THE CONCURRENCY GROUP SERIALIZES REVIEW JOBS PER BRANCH, NEVER COMMENT JOBS.
72
+ # * A comment job's group is its own run id, so it never waits and is never
73
+ # replaced: a group keeps at most one pending job and cancels an earlier
74
+ # pending one, which would drop a command.
75
+ # * Review jobs on one head branch share `harness-review-<branch>` and run one
76
+ # at a time, so two reviews submitted together give one round, not two
77
+ # pushes racing for the same round number.
78
+ # * A pending review job replaced by a newer one loses nothing: every job in
79
+ # the group collects cumulatively, every review requesting changes, every
80
+ # other review carrying a summary and every inline comment no earlier round
81
+ # recorded, and the round's comment names
82
+ # every reviewer it took.
83
+ # * The name `harness-review-<branch>` is reserved for every job that places a
84
+ # review round on that branch; any other workflow's job that does so joins
85
+ # the group under exactly that name, and both files' headers declare it.
86
+ # harness-run.yml's `collect` job is the one such job today (DECLARED
87
+ # MIRRORS below).
88
+ #
89
+
90
+ # TWO RULES EVERY EDIT KEEPS.
91
+ # * Event text and variables reach a shell line only through `env:` and the
92
+ # event file, never through a GitHub expression inside `run:` — a comment
93
+ # body is written by whoever posted it (script injection).
94
+ # * Every GitHub expression has a space after its opening braces. `init`
95
+ # renders its workflows with the CLI's double-brace token renderer, which
96
+ # reads a letter straight after the braces as a token; this file carries
97
+ # no token.
98
+ #
99
+ # DECLARED MIRRORS — a rename on either side is an edit to both:
100
+ # cli/src/remote/githubActions.ts WORKFLOW_CONTROL_FILE, COMMAND_HANDLE
101
+ # (`@sdlc-harness`), COMMENT_MARKER
102
+ # (`<!-- sdlc-harness`), REVIEW_ROUND_STATE
103
+ # (`changes_requested`), HARNESS_RUNNER,
104
+ # HARNESS_REMOTE_STOP,
105
+ # HARNESS_TRIGGER_ALLOWED_BOTS
106
+ # cli/src/config/model.ts DEFAULTS.scriptsDir
107
+ # harness-run.yml the concurrency group
108
+ # `harness-review-<branch>`, held by its
109
+ # `collect` job
110
+ #
111
+ # ACTION PINS.
112
+ # actions/checkout@v5
113
+ # The lowest major whose own action.yml declares `runs.using: node24`, per a
114
+ # maintainer's lookups of its action.yml and release notes on
115
+ # 2026-09-29T08:21Z (UTC). That major's release notes require Actions Runner
116
+ # 2.327.1 or newer; a GitHub-hosted runner already has it, and a self-hosted
117
+ # one must run it (docs/remote-execution.md, section 8). A major tag, not a
118
+ # commit sha: it is GitHub's own `actions/` organisation, the owner of the
119
+ # runner and GITHUB_TOKEN this job already trusts, and a major tag takes the
120
+ # action's own patch and security releases where a sha would freeze your copy.
121
+ # Pin a sha in your copy if you want one.
122
+
123
+ name: harness-control
124
+ run-name: harness control ${{ github.event.issue.number || github.event.pull_request.number }}
125
+
126
+ on:
127
+ issue_comment:
128
+ types: [created]
129
+ pull_request_review:
130
+ types: [submitted]
131
+
132
+ permissions:
133
+ contents: write
134
+ actions: write
135
+ issues: write
136
+ pull-requests: write
137
+
138
+ defaults:
139
+ run:
140
+ shell: bash
141
+
142
+ jobs:
143
+ control:
144
+ if: (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@sdlc-harness') && !contains(github.event.comment.body, '<!-- sdlc-harness')) || (github.event_name == 'pull_request_review' && github.event.review.state == 'changes_requested' && github.event.pull_request.head.repo.full_name == github.repository)
145
+ runs-on: ${{ vars.HARNESS_RUNNER || 'ubuntu-latest' }}
146
+ concurrency:
147
+ group: ${{ github.event_name == 'pull_request_review' && format('harness-review-{0}', github.event.pull_request.head.ref) || format('harness-control-{0}', github.run_id) }}
148
+ cancel-in-progress: false
149
+ env:
150
+ GH_TOKEN: ${{ github.token }}
151
+ HARNESS_REMOTE_STOP: ${{ vars.HARNESS_REMOTE_STOP }}
152
+ HARNESS_REMOTE_SLUG: ${{ github.repository }}
153
+ HARNESS_TRIGGER_ALLOWED_BOTS: ${{ vars.HARNESS_TRIGGER_ALLOWED_BOTS }}
154
+ steps:
155
+ - name: Check out the default branch
156
+ uses: actions/checkout@v5
157
+ with:
158
+ ref: ${{ github.event.repository.default_branch }}
159
+ token: ${{ github.token }}
160
+ fetch-depth: 0
161
+
162
+ - name: Check for jq and gh
163
+ run: |
164
+ missing=""
165
+ for tool in jq gh; do
166
+ command -v "$tool" >/dev/null 2>&1 || missing="$missing $tool"
167
+ done
168
+ if [ -n "$missing" ]; then
169
+ echo "::error::this runner lacks:$missing. Install them on the self-hosted runner, or use a GitHub-hosted one."
170
+ exit 1
171
+ fi
172
+
173
+ - name: Read the configuration
174
+ run: |
175
+ scripts_dir=$(jq -r '.scriptsDir // "scripts"' harness.config.json)
176
+ echo "SCRIPTS_DIR=${scripts_dir%/}" >> "$GITHUB_ENV"
177
+
178
+ - name: Set the git identity
179
+ run: |
180
+ git config user.name "github-actions[bot]"
181
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
182
+
183
+ - name: Act on the comment or review
184
+ run: bash "$SCRIPTS_DIR/remote-run.sh" control
@@ -48,6 +48,11 @@
48
48
  # The job's `actions: write` covers listing and downloading its own
49
49
  # workflow's artifacts.
50
50
  #
51
+ # THE PERMISSIONS. `issues: write` and `pull-requests: write` serve `poll`'s
52
+ # reports, which comment on the waiting run's issue or pull request; a
53
+ # workflow-level `permissions:` block sets every permission it does not list to
54
+ # `none`.
55
+ #
51
56
  # WHAT IT WRITES. The `harness-poll-state` artifact: the failed-dispatch count
52
57
  # `poll` carries to the next tick, kept 7 days.
53
58
  #
@@ -85,6 +90,8 @@ on:
85
90
  permissions:
86
91
  contents: read
87
92
  actions: write
93
+ issues: write
94
+ pull-requests: write
88
95
 
89
96
  defaults:
90
97
  run: