harnessed 3.9.24 → 3.9.26
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/dist/cli.mjs +125 -17
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/workflows/plan/architecture/workflow.yaml +7 -6
package/dist/cli.mjs
CHANGED
|
@@ -1231,7 +1231,7 @@ var init_auto_install = __esm({
|
|
|
1231
1231
|
|
|
1232
1232
|
// package.json
|
|
1233
1233
|
var package_default = {
|
|
1234
|
-
version: "3.9.
|
|
1234
|
+
version: "3.9.26"};
|
|
1235
1235
|
|
|
1236
1236
|
// src/manifest/errors.ts
|
|
1237
1237
|
function instancePathToKeyPath(instancePath) {
|
|
@@ -4027,11 +4027,91 @@ async function loadRolePrompts(workflowsDir) {
|
|
|
4027
4027
|
const doc = parse(raw);
|
|
4028
4028
|
return doc?.prompts ?? {};
|
|
4029
4029
|
}
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4030
|
+
var INTERACTIVE_COMMANDS = /* @__PURE__ */ new Set([
|
|
4031
|
+
"discuss",
|
|
4032
|
+
"discuss-strategic",
|
|
4033
|
+
"discuss-phase",
|
|
4034
|
+
"discuss-subtask",
|
|
4035
|
+
"task-clarify"
|
|
4036
|
+
]);
|
|
4037
|
+
var HYBRID_COMMANDS = /* @__PURE__ */ new Set(["auto", "task"]);
|
|
4038
|
+
var MARKER = `<!-- harnessed-generated:v3.4.4 -->`;
|
|
4039
|
+
function buildInteractiveBody(name, prompt) {
|
|
4040
|
+
return [
|
|
4041
|
+
`# /${name}`,
|
|
4042
|
+
``,
|
|
4043
|
+
prompt.description,
|
|
4044
|
+
``,
|
|
4045
|
+
`## How to run (interactive \u2014 in THIS session)`,
|
|
4046
|
+
``,
|
|
4047
|
+
`Clarification requires real user dialogue. Spawned subagents cannot ask the user questions, so run this stage directly in this session \u2014 do NOT spawn \`harnessed run ${name}\`.`,
|
|
4048
|
+
``,
|
|
4049
|
+
`1. Evaluate the clarification criteria for "$ARGUMENTS":`,
|
|
4050
|
+
` - Strategic layer: new feature / new milestone / unclear business scope \u2192 run gstack \`/office-hours\` + \`/plan-ceo-review\``,
|
|
4051
|
+
` - Phase layer: \u22652 open implementation decisions / unclear cross-phase API contract \u2192 run GSD \`/gsd-discuss-phase\``,
|
|
4052
|
+
` - Subtask layer: \u22652 distinct approaches / core algorithm / API contract design / high error cost \u2192 run superpowers brainstorming`,
|
|
4053
|
+
`2. For each layer that fires, hold the dialogue with the user (use AskUserQuestion for option-style decisions). Lock every open decision.`,
|
|
4054
|
+
`3. Skip layers that don't fire \u2014 state which were skipped and why (transparent skip).`,
|
|
4055
|
+
`4. Persist locked decisions to \`.planning/\` via planning-with-files (\`findings.md\` / \`task_plan.md\`).`,
|
|
4056
|
+
``,
|
|
4057
|
+
`Output: a locked spec the execution stages can consume without further user input.`,
|
|
4058
|
+
``,
|
|
4059
|
+
`## Notes`,
|
|
4060
|
+
``,
|
|
4061
|
+
`- This file is generated by \`harnessed setup\`. Re-run \`harnessed setup\` after a harnessed upgrade to refresh.`,
|
|
4062
|
+
`- The downstream execution command (\`/plan\` \u2192 \`/task\` \u2192 \`/verify\`) embeds the locked spec in its task text.`,
|
|
4063
|
+
``,
|
|
4064
|
+
MARKER,
|
|
4065
|
+
``
|
|
4066
|
+
].join("\n");
|
|
4067
|
+
}
|
|
4068
|
+
function buildHybridBody(name, prompt) {
|
|
4069
|
+
const chain = name === "auto" ? [
|
|
4070
|
+
`3. Then run the execution stages in order via the Bash tool (each stage's output informs the next):`,
|
|
4071
|
+
``,
|
|
4072
|
+
"```bash",
|
|
4073
|
+
`echo "<locked spec + $ARGUMENTS>" | harnessed run plan --task-stdin`,
|
|
4074
|
+
`echo "<locked spec + plan output>" | harnessed run task --task-stdin --skip-sub clarify`,
|
|
4075
|
+
`echo "<locked spec + task output>" | harnessed run verify --task-stdin`,
|
|
4076
|
+
`echo "<summary of all stages>" | harnessed run retro --task-stdin`,
|
|
4077
|
+
"```",
|
|
4078
|
+
``,
|
|
4079
|
+
` Do NOT run \`harnessed run auto\` \u2014 that would re-spawn the discuss stage headlessly, defeating the interactive clarification you just did.`,
|
|
4080
|
+
` \`--skip-sub clarify\` tells the task master that clarification is already done.`
|
|
4081
|
+
] : [
|
|
4082
|
+
`3. Then spawn the execution subs via the Bash tool:`,
|
|
4083
|
+
``,
|
|
4084
|
+
"```bash",
|
|
4085
|
+
`echo "<locked spec + $ARGUMENTS>" | harnessed run task --task-stdin --skip-sub clarify`,
|
|
4086
|
+
"```",
|
|
4087
|
+
``,
|
|
4088
|
+
` \`--skip-sub clarify\` tells the task master that clarification is already done in this session.`
|
|
4089
|
+
];
|
|
4090
|
+
return [
|
|
4091
|
+
`# /${name}`,
|
|
4092
|
+
``,
|
|
4093
|
+
prompt.description,
|
|
4094
|
+
``,
|
|
4095
|
+
`## How to run (hybrid \u2014 clarify in THIS session, then spawn execution)`,
|
|
4096
|
+
``,
|
|
4097
|
+
`1. FIRST clarify interactively in this session (spawned subagents cannot ask the user questions):`,
|
|
4098
|
+
` - Evaluate the subtask clarification criteria for "$ARGUMENTS": \u22652 distinct approaches / core algorithm / API contract design / high error cost \u2192 brainstorm with the user (AskUserQuestion for option-style decisions) and lock every open decision.`,
|
|
4099
|
+
` - If criteria don't fire (CRUD / known pattern / single obvious implementation), skip with a one-line transparent declaration.`,
|
|
4100
|
+
`2. Embed the locked decisions into the task text passed downstream.`,
|
|
4101
|
+
...chain,
|
|
4102
|
+
``,
|
|
4103
|
+
`## Notes`,
|
|
4104
|
+
``,
|
|
4105
|
+
`- This file is generated by \`harnessed setup\`. Re-run \`harnessed setup\` after a harnessed upgrade to refresh.`,
|
|
4106
|
+
`- Execution stages (code / test / deliver / verify) spawn headless subagents \u2014 appropriate since they need no user dialogue.`,
|
|
4107
|
+
``,
|
|
4108
|
+
MARKER,
|
|
4109
|
+
``
|
|
4110
|
+
].join("\n");
|
|
4111
|
+
}
|
|
4112
|
+
function buildSpawnBody(name, prompt) {
|
|
4033
4113
|
const stagedNote = name === "auto" ? "\n- For stage-by-stage review, append `--staged` (pauses between stages for user review)." : "";
|
|
4034
|
-
|
|
4114
|
+
return [
|
|
4035
4115
|
`# /${name}`,
|
|
4036
4116
|
``,
|
|
4037
4117
|
prompt.description,
|
|
@@ -4054,9 +4134,21 @@ function generateCommandFile(name, prompt, _capabilities, _installedPlugins, _in
|
|
|
4054
4134
|
`- The sister \`~/.claude/skills/${name}/SKILL.md\` is the Skill-tool entry point (Claude loads it when triggers match \`trigger_phrases:\`). Both files invoke the same \`harnessed run ${name}\` Bash command.${stagedNote}`,
|
|
4055
4135
|
`- Workflow runtime: \`src/workflow/run.ts\` walks \`workflows/${nameToYamlHintPath(name)}\` with disciplines + judgments + master orchestration applied per the yaml \`delegates_to[]\` + \`gate\` clauses.`,
|
|
4056
4136
|
``,
|
|
4057
|
-
|
|
4137
|
+
MARKER,
|
|
4058
4138
|
``
|
|
4059
4139
|
].join("\n");
|
|
4140
|
+
}
|
|
4141
|
+
function generateCommandFile(name, prompt, _capabilities, _installedPlugins, _installedUserSkills) {
|
|
4142
|
+
const isMaster = prompt.is_master === true;
|
|
4143
|
+
const argHint = isMaster ? "[task description]" : "[requirement text or omit]";
|
|
4144
|
+
let body;
|
|
4145
|
+
if (INTERACTIVE_COMMANDS.has(name)) {
|
|
4146
|
+
body = buildInteractiveBody(name, prompt);
|
|
4147
|
+
} else if (HYBRID_COMMANDS.has(name)) {
|
|
4148
|
+
body = buildHybridBody(name, prompt);
|
|
4149
|
+
} else {
|
|
4150
|
+
body = buildSpawnBody(name, prompt);
|
|
4151
|
+
}
|
|
4060
4152
|
const warnings = [];
|
|
4061
4153
|
const frontmatter = [
|
|
4062
4154
|
"---",
|
|
@@ -5042,8 +5134,17 @@ async function runMasterOrchestrator(masterName, context, packageRoot, spawnDriv
|
|
|
5042
5134
|
}
|
|
5043
5135
|
effectiveOpts = pre.opts;
|
|
5044
5136
|
}
|
|
5137
|
+
const skipSubs = new Set(Array.isArray(context.skip_subs) ? context.skip_subs : []);
|
|
5045
5138
|
const gateEvalled = [];
|
|
5046
5139
|
for (const clause of master.delegates_to) {
|
|
5140
|
+
if (skipSubs.has(clause.sub)) {
|
|
5141
|
+
gateEvalled.push({
|
|
5142
|
+
clause,
|
|
5143
|
+
passes: false,
|
|
5144
|
+
reason: `skipped via skip_subs (done interactively in main session)`
|
|
5145
|
+
});
|
|
5146
|
+
continue;
|
|
5147
|
+
}
|
|
5047
5148
|
if (!clause.gate) {
|
|
5048
5149
|
gateEvalled.push({ clause, passes: true });
|
|
5049
5150
|
continue;
|
|
@@ -5449,7 +5550,10 @@ function registerRun(program2) {
|
|
|
5449
5550
|
).option("--model <model>", "subagent model: 'haiku' | 'sonnet' | 'opus'").option(
|
|
5450
5551
|
"--dry-run",
|
|
5451
5552
|
"validate yaml load + walk runtime without spawning (Phase 1 default for verification)"
|
|
5452
|
-
).option("--staged", "/auto super-master: pause between stages for user review").option(
|
|
5553
|
+
).option("--staged", "/auto super-master: pause between stages for user review").option(
|
|
5554
|
+
"--skip-sub <names>",
|
|
5555
|
+
"comma-separated sub names to skip (work already done interactively in main session, e.g. clarify)"
|
|
5556
|
+
).option("--list", "print all known workflow names and exit").action(async (name, raw) => {
|
|
5453
5557
|
if (raw.list) {
|
|
5454
5558
|
const names = await listWorkflowNames(WORKFLOWS_DIR);
|
|
5455
5559
|
for (const n of names) console.log(n);
|
|
@@ -5541,6 +5645,10 @@ function registerRun(program2) {
|
|
|
5541
5645
|
...raw.model ? { modelOverride: raw.model } : {},
|
|
5542
5646
|
...raw.maxIterations ? { maxIterations: raw.maxIterations } : {},
|
|
5543
5647
|
...raw.staged ? { staged: true } : {},
|
|
5648
|
+
// v3.9.26 Option A — skip subs done interactively in main session.
|
|
5649
|
+
...typeof raw.skipSub === "string" && raw.skipSub.length > 0 ? {
|
|
5650
|
+
skip_subs: raw.skipSub.split(",").map((s) => s.trim()).filter((s) => s.length > 0)
|
|
5651
|
+
} : {},
|
|
5544
5652
|
...matchedTriggers.length > 0 ? { user_overrides: matchedTriggers } : {}
|
|
5545
5653
|
};
|
|
5546
5654
|
if (raw.dryRun) {
|
|
@@ -6279,20 +6387,19 @@ function printGrouped(b, prefix = "") {
|
|
|
6279
6387
|
const GROUP_ORDER = ["mcp-tool", "command", "cli-binary", "other"];
|
|
6280
6388
|
const groupOf = (n) => b.componentTypes[n] ?? "other";
|
|
6281
6389
|
const buckets = {};
|
|
6390
|
+
const push = (group, entry) => {
|
|
6391
|
+
if (!buckets[group]) buckets[group] = [];
|
|
6392
|
+
buckets[group].push(entry);
|
|
6393
|
+
};
|
|
6282
6394
|
for (const n of b.failed) {
|
|
6283
6395
|
const m = n.match(/^([^:]+):/);
|
|
6284
6396
|
const baseName = m?.[1] ?? n;
|
|
6285
|
-
(
|
|
6397
|
+
push(groupOf(baseName), { status: "failed", name: n });
|
|
6286
6398
|
}
|
|
6287
|
-
for (const n of b.installed) (
|
|
6399
|
+
for (const n of b.installed) push(groupOf(n), { status: "installed", name: n });
|
|
6288
6400
|
for (const s of b.skipped)
|
|
6289
|
-
(
|
|
6290
|
-
|
|
6291
|
-
name: s.name,
|
|
6292
|
-
suffix: ` \u2014 ${s.reason}`
|
|
6293
|
-
});
|
|
6294
|
-
for (const n of b.alreadyInstalled)
|
|
6295
|
-
(buckets[groupOf(n)] ??= []).push({ status: "already-installed", name: n });
|
|
6401
|
+
push(groupOf(s.name), { status: "skipped", name: s.name, suffix: ` \u2014 ${s.reason}` });
|
|
6402
|
+
for (const n of b.alreadyInstalled) push(groupOf(n), { status: "already-installed", name: n });
|
|
6296
6403
|
for (const g of GROUP_ORDER) {
|
|
6297
6404
|
const entries = buckets[g];
|
|
6298
6405
|
if (!entries || entries.length === 0) continue;
|
|
@@ -6788,7 +6895,8 @@ async function removeSettingsEnv(settingsPath3) {
|
|
|
6788
6895
|
if (!changed) return false;
|
|
6789
6896
|
if (Object.keys(env).length === 0) delete data.env;
|
|
6790
6897
|
else data.env = env;
|
|
6791
|
-
await writeFile(settingsPath3, JSON.stringify(data, null, 2)
|
|
6898
|
+
await writeFile(settingsPath3, `${JSON.stringify(data, null, 2)}
|
|
6899
|
+
`, "utf8");
|
|
6792
6900
|
return true;
|
|
6793
6901
|
}
|
|
6794
6902
|
async function runUnifiedUninstall(home, dryRun) {
|