supipowers 2.0.2 → 2.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.
Files changed (84) hide show
  1. package/README.md +5 -6
  2. package/package.json +4 -2
  3. package/skills/harness/SKILL.md +1 -0
  4. package/src/bootstrap.ts +8 -133
  5. package/src/commands/optimize-context.ts +153 -16
  6. package/src/commands/runbook.ts +511 -0
  7. package/src/config/defaults.ts +5 -5
  8. package/src/config/loader.ts +1 -0
  9. package/src/config/schema.ts +2 -6
  10. package/src/context/rule-renderer.ts +274 -2
  11. package/src/context/runbook-extension-template.ts +193 -0
  12. package/src/context/startup-check.ts +197 -2
  13. package/src/context/startup-optimizer.ts +133 -10
  14. package/src/context-mode/knowledge/store.ts +381 -43
  15. package/src/context-mode/tools.ts +41 -3
  16. package/src/deps/registry.ts +1 -12
  17. package/src/fix-pr/assessment.ts +1 -0
  18. package/src/fix-pr/prompt-builder.ts +1 -0
  19. package/src/git/commit.ts +76 -18
  20. package/src/harness/command.ts +201 -12
  21. package/src/harness/default-agents/docs.md +39 -0
  22. package/src/harness/docs/config.ts +29 -0
  23. package/src/harness/docs/glob-match.ts +27 -0
  24. package/src/harness/docs/index-renderer.ts +82 -0
  25. package/src/harness/docs/provenance.ts +125 -0
  26. package/src/harness/docs/regen-decision.ts +167 -0
  27. package/src/harness/docs/representative-files.ts +175 -0
  28. package/src/harness/docs/source-hash.ts +106 -0
  29. package/src/harness/docs/validator.ts +233 -0
  30. package/src/harness/git-verification.ts +515 -0
  31. package/src/harness/git-verify-qa.ts +406 -0
  32. package/src/harness/hooks/layer-context-inject.ts +35 -1
  33. package/src/harness/hooks/register.ts +24 -3
  34. package/src/harness/pipeline.ts +37 -13
  35. package/src/harness/pr-comment/baseline.ts +105 -0
  36. package/src/harness/pr-comment/ci-env.ts +120 -0
  37. package/src/harness/pr-comment/gh-poster.ts +227 -0
  38. package/src/harness/pr-comment/handler.ts +198 -0
  39. package/src/harness/pr-comment/render.ts +297 -0
  40. package/src/harness/pr-comment/status.ts +95 -0
  41. package/src/harness/pr-comment/types.ts +73 -0
  42. package/src/harness/pr-comment/workflow-summary.ts +47 -0
  43. package/src/harness/project-paths.ts +95 -0
  44. package/src/harness/stages/design.ts +1 -0
  45. package/src/harness/stages/discover.ts +1 -13
  46. package/src/harness/stages/docs.ts +708 -0
  47. package/src/harness/stages/implement-apply.ts +934 -0
  48. package/src/harness/stages/implement.ts +64 -51
  49. package/src/harness/stages/plan.ts +25 -16
  50. package/src/harness/stages/validate.ts +478 -0
  51. package/src/harness/storage.ts +142 -0
  52. package/src/harness/tools.ts +130 -0
  53. package/src/mempalace/bridge.ts +207 -41
  54. package/src/mempalace/config.ts +10 -4
  55. package/src/mempalace/format.ts +122 -6
  56. package/src/mempalace/hooks.ts +204 -56
  57. package/src/mempalace/installer-helper.ts +18 -4
  58. package/src/mempalace/python/mempalace_bridge.py +128 -3
  59. package/src/mempalace/runtime.ts +53 -16
  60. package/src/mempalace/schema.ts +151 -30
  61. package/src/mempalace/session-summary.ts +5 -0
  62. package/src/mempalace/tool.ts +17 -4
  63. package/src/mempalace/upstream-limits.ts +69 -0
  64. package/src/planning/approval-flow.ts +25 -2
  65. package/src/planning/planning-ask-tool.ts +34 -4
  66. package/src/planning/system-prompt.ts +1 -1
  67. package/src/tool-catalog/active-tool-controller.ts +0 -22
  68. package/src/tool-catalog/active-tool-planner.ts +0 -26
  69. package/src/tool-catalog/tool-groups.ts +1 -9
  70. package/src/types.ts +127 -8
  71. package/src/ui-design/session.ts +114 -8
  72. package/src/utils/executable.ts +10 -1
  73. package/src/workspace/state-paths.ts +1 -1
  74. package/src/commands/mcp.ts +0 -814
  75. package/src/mcp/activation.ts +0 -77
  76. package/src/mcp/config.ts +0 -223
  77. package/src/mcp/docs.ts +0 -154
  78. package/src/mcp/gateway.ts +0 -103
  79. package/src/mcp/lifecycle.ts +0 -79
  80. package/src/mcp/manager-tool.ts +0 -104
  81. package/src/mcp/mcpc.ts +0 -113
  82. package/src/mcp/registry.ts +0 -98
  83. package/src/mcp/triggers.ts +0 -62
  84. package/src/mcp/types.ts +0 -95
@@ -1,20 +1,20 @@
1
1
  /**
2
2
  * IMPLEMENT stage runner.
3
3
  *
4
- * Counts the tasks in the approved plan and decides whether to run them in-session (steer
5
- * loop, mirrors `/supi:plan`) or to hand off to `/supi:ultraplan` batch / worktree
6
- * runtime. The threshold is configurable via `harness.implement_in_session_threshold`
7
- * (default 10).
4
+ * Programmatic apply of every Tier 1 artifact defined by the design spec. Mirrors the
5
+ * `/supi:checks` pattern: the stage runs deterministically inside the harness command,
6
+ * with no handoff to the user's active agent. After this stage completes, the pipeline
7
+ * naturally continues to docs (per-layer subagent dispatch) and validate (mechanical
8
+ * checks) inside the same `/supi:harness` invocation.
8
9
  *
9
- * The actual execution loop lives in the command handler the stage runner records the
10
- * routing decision and validates pre-conditions (clean git tree, plan readable, etc.).
10
+ * `decideImplementRouting` is retained as an exported helper for tests + future tooling;
11
+ * the in-session-vs-batch heuristic is no longer used by the stage runner itself because
12
+ * the apply path no longer needs the active agent.
11
13
  */
12
14
 
13
15
  import * as fs from "node:fs";
14
- import * as path from "node:path";
15
16
 
16
17
  import type { Plan } from "../../types.js";
17
- import { parsePlan } from "../../storage/plans.js";
18
18
  import {
19
19
  type HarnessStageRunResult,
20
20
  type HarnessStageRunner,
@@ -23,7 +23,10 @@ import {
23
23
  } from "../stage-runner.js";
24
24
  import {
25
25
  appendImplementLog,
26
+ hasSuccessfulImplementApply,
27
+ loadHarnessDesignSpecJson,
26
28
  } from "../storage.js";
29
+ import { applyHarnessPlan } from "./implement-apply.js";
27
30
 
28
31
  const DEFAULT_IN_SESSION_THRESHOLD = 10;
29
32
 
@@ -81,20 +84,15 @@ export class HarnessImplementStage implements HarnessStageRunner {
81
84
  return fs.existsSync(this.input.planPath);
82
85
  }
83
86
 
87
+ /**
88
+ * Implement is driven by the programmatic apply, so `isComplete` returns true once a
89
+ * successful apply has been recorded in `implement-log.jsonl`. This keeps reruns
90
+ * idempotent without re-walking every applier (the appliers themselves are also
91
+ * idempotent — this is a fast-skip for the common case). A subsequent failed apply in
92
+ * the same session resets the result via the scan-from-end logic in storage.
93
+ */
84
94
  async isComplete(ctx: HarnessStageRunnerContext): Promise<boolean> {
85
- // Implement is complete when the post-implement self-check has been recorded in
86
- // implement-log.jsonl with `kind: "self-check-passed"`. The command handler appends
87
- // that record after running typecheck/test/scan.
88
- const logPath = path.join(
89
- path.dirname(this.input.planPath),
90
- "..",
91
- "harness",
92
- "sessions",
93
- ctx.sessionId,
94
- "implement-log.jsonl",
95
- );
96
- void logPath; // tracked but the stage runner does not introspect it directly.
97
- return false;
95
+ return hasSuccessfulImplementApply(ctx.paths, ctx.cwd, ctx.sessionId);
98
96
  }
99
97
 
100
98
  async run(ctx: HarnessStageRunnerContext): Promise<HarnessStageRunResult> {
@@ -111,51 +109,66 @@ export class HarnessImplementStage implements HarnessStageRunner {
111
109
  blocker: { code: "implement-preflight-failed", message: errors.join("; ") },
112
110
  };
113
111
  }
114
- let raw: string;
115
- try {
116
- raw = fs.readFileSync(this.input.planPath, "utf8");
117
- } catch (error) {
112
+ const designResult = loadHarnessDesignSpecJson(ctx.paths, ctx.cwd, ctx.sessionId);
113
+ if (!designResult.ok) {
118
114
  return {
119
- status: "failed",
120
- stage: this.stage,
121
- artifactPaths: [],
122
- error: `unable to read plan: ${error instanceof Error ? error.message : String(error)}`,
123
- };
124
- }
125
- let plan: Plan;
126
- try {
127
- plan = parsePlan(raw, this.input.planPath);
128
- } catch (error) {
129
- return {
130
- status: "failed",
115
+ status: "blocked",
131
116
  stage: this.stage,
132
117
  artifactPaths: [],
133
- error: `unable to parse plan: ${error instanceof Error ? error.message : String(error)}`,
118
+ blocker: {
119
+ code: "design-spec-missing",
120
+ message: "implement stage requires <session>/design-spec.json. Run /supi:harness design first.",
121
+ },
134
122
  };
135
123
  }
136
124
 
137
- const decision = decideImplementRouting({
138
- plan,
139
- threshold: this.input.threshold ?? DEFAULT_IN_SESSION_THRESHOLD,
125
+ const recordedAt = nowIso(ctx);
126
+ const outcome = await applyHarnessPlan({
127
+ platform: ctx.platform,
128
+ paths: ctx.paths,
129
+ cwd: ctx.cwd,
130
+ spec: designResult.value,
131
+ apply: true,
140
132
  });
141
133
 
142
134
  appendImplementLog(ctx.paths, ctx.cwd, ctx.sessionId, {
143
- recordedAt: nowIso(ctx),
144
- kind: "routing-decision",
145
- routing: decision.routing,
146
- taskCount: decision.taskCount,
147
- reason: decision.reason,
135
+ recordedAt,
136
+ kind: "applied",
148
137
  planPath: this.input.planPath,
138
+ applied: outcome.applied,
139
+ warnings: outcome.warnings,
140
+ errors: outcome.errors,
149
141
  });
150
142
 
143
+ const artifactPaths = outcome.applied
144
+ .filter((entry) => entry.action === "wrote" || entry.action === "patched")
145
+ .map((entry) => entry.path);
146
+
147
+ if (outcome.errors.length > 0) {
148
+ const summary = outcome.errors
149
+ .map((err) => `${err.step}: ${err.message}`)
150
+ .join("; ");
151
+ return {
152
+ status: "blocked",
153
+ stage: this.stage,
154
+ artifactPaths,
155
+ blocker: { code: "implement-apply-failed", message: summary },
156
+ details: {
157
+ applied: outcome.applied.length,
158
+ errors: outcome.errors.length,
159
+ warnings: outcome.warnings.length,
160
+ },
161
+ };
162
+ }
163
+
151
164
  return {
152
- status: "awaiting-user",
165
+ status: "completed",
153
166
  stage: this.stage,
154
- artifactPaths: ["implement-log.jsonl"],
167
+ artifactPaths,
155
168
  details: {
156
- routing: decision.routing,
157
- taskCount: decision.taskCount,
158
- reason: decision.reason,
169
+ applied: outcome.applied.length,
170
+ warnings: outcome.warnings.length,
171
+ wrote: artifactPaths.length,
159
172
  },
160
173
  };
161
174
  }
@@ -24,6 +24,7 @@ import {
24
24
  } from "../stage-runner.js";
25
25
  import {
26
26
  loadHarnessDesignSpecJson,
27
+ loadHarnessSession,
27
28
  } from "../storage.js";
28
29
 
29
30
  export interface HarnessPlanTask {
@@ -36,22 +37,14 @@ export interface HarnessPlanTask {
36
37
  }
37
38
 
38
39
  /**
39
- * Build the canonical task list from a design spec. Always emits the "harden" tasks
40
- * (AGENTS.md, docs/architecture.md, docs/golden-principles.md, lint/structural/eval
41
- * configs); appends the conditional anti-slop tasks per Design's backend choice.
40
+ * Build the canonical task list from a design spec. Always emits the source
41
+ * harness artifacts first (docs, tooling, CI, queue, review wiring), then ends
42
+ * with AGENTS.md so the agent-facing summary can reference completed artifacts.
42
43
  */
43
44
  export function buildHarnessPlanTasks(spec: HarnessDesignSpec): HarnessPlanTask[] {
44
45
  const tasks: HarnessPlanTask[] = [];
45
46
  let id = 1;
46
47
 
47
- tasks.push({
48
- id: id++,
49
- name: "Generate AGENTS.md",
50
- description: "Write a ≤120-line AGENTS.md at the repo root summarizing the harness contract for any agent.",
51
- files: ["AGENTS.md"],
52
- criteria: "AGENTS.md exists, references docs/architecture.md and docs/golden-principles.md, and ends with a 'When in doubt' section.",
53
- complexity: "small",
54
- });
55
48
 
56
49
  tasks.push({
57
50
  id: id++,
@@ -159,10 +152,10 @@ export function buildHarnessPlanTasks(spec: HarnessDesignSpec): HarnessPlanTask[
159
152
 
160
153
  tasks.push({
161
154
  id: id++,
162
- name: "Register anti-slop hooks",
163
- description: "Ensure src/harness/hooks/register.ts wires pre-edit dupe probe, post-session sweep, and layer-context-inject only when the harness marker exists.",
164
- files: ["src/harness/hooks/register.ts"],
165
- criteria: "Hooks are registered idempotently and gated by the marker file.",
155
+ name: "Enable repo-local anti-slop hooks",
156
+ description: "Create the repo-local harness marker. The installed Supipowers extension already registers the runtime hooks; the marker gates them for this repository.",
157
+ files: [".omp/supipowers/harness/marker.json"],
158
+ criteria: `Marker JSON exists with backend ${spec.antiSlop.backend}; no supipowers extension source files are modified.`,
166
159
  complexity: "small",
167
160
  });
168
161
 
@@ -206,9 +199,20 @@ export function buildHarnessPlanTasks(spec: HarnessDesignSpec): HarnessPlanTask[
206
199
  });
207
200
  }
208
201
 
202
+ tasks.push({
203
+ id: id++,
204
+ name: "Generate AGENTS.md",
205
+ description: "Write a ≤120-line AGENTS.md at the repo root summarizing the harness contract for any agent.",
206
+ files: ["AGENTS.md"],
207
+ criteria: "AGENTS.md exists, references docs/architecture.md and docs/golden-principles.md, and ends with a 'When in doubt' section.",
208
+ complexity: "small",
209
+ });
210
+
209
211
  return tasks;
210
212
  }
211
213
 
214
+
215
+
212
216
  /** Render the plan markdown that lands in the canonical plans directory. */
213
217
  export function renderHarnessPlanMarkdown(input: {
214
218
  spec: HarnessDesignSpec;
@@ -321,7 +325,12 @@ export function emitHarnessPlanFromSpec(input: {
321
325
  const recordedAt = input.recordedAt ?? new Date().toISOString();
322
326
  const planName = input.planName ?? `harness-${input.spec.sessionId}`;
323
327
  const tasks = buildHarnessPlanTasks(input.spec);
324
- const planMarkdown = renderHarnessPlanMarkdown({ spec: input.spec, tasks, recordedAt, planName });
328
+ const planMarkdown = renderHarnessPlanMarkdown({
329
+ spec: input.spec,
330
+ tasks,
331
+ recordedAt,
332
+ planName,
333
+ });
325
334
  const filename = `${planName}.md`;
326
335
  const planPath = savePlan(input.ctx.paths, input.ctx.cwd, filename, planMarkdown);
327
336
  return { planPath, planMarkdown, tasks };