@harness-lab/cli 0.4.0 → 0.4.2
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/package.json
CHANGED
package/src/run-cli.js
CHANGED
|
@@ -305,18 +305,23 @@ async function handleSkillInstall(io, ui, deps, flags) {
|
|
|
305
305
|
ui.status("ok", "Installed the Harness Lab workshop skill bundle.");
|
|
306
306
|
}
|
|
307
307
|
ui.keyValue("Target", result.targetRoot);
|
|
308
|
-
ui.keyValue("
|
|
309
|
-
|
|
308
|
+
ui.keyValue("Codex/pi", result.installPath);
|
|
309
|
+
if (result.claudeCodePath) {
|
|
310
|
+
ui.keyValue("Claude Code", result.claudeCodePath);
|
|
311
|
+
}
|
|
310
312
|
ui.keyValue("Bundle source", result.sourceMode === "packaged_bundle" ? "packaged portable bundle" : "source checkout fallback");
|
|
311
313
|
ui.blank();
|
|
312
314
|
ui.section("Next steps");
|
|
313
|
-
|
|
314
|
-
"Open
|
|
315
|
-
"Start with the workshop command menu.",
|
|
315
|
+
const steps = [
|
|
316
|
+
"Open your coding agent in the target repo.",
|
|
316
317
|
"Codex: `$workshop commands`.",
|
|
317
318
|
"pi: `/skill:workshop`, then ask for the workshop commands.",
|
|
318
|
-
|
|
319
|
-
|
|
319
|
+
];
|
|
320
|
+
if (result.claudeCodePath) {
|
|
321
|
+
steps.push("Claude Code: the `workshop` skill is available as a slash command.");
|
|
322
|
+
}
|
|
323
|
+
steps.push("Next: `$workshop reference`, `$workshop brief`, and `$workshop resources`.");
|
|
324
|
+
ui.numberedList(steps);
|
|
320
325
|
return 0;
|
|
321
326
|
} catch (error) {
|
|
322
327
|
if (error instanceof SkillInstallError) {
|
|
@@ -879,11 +884,19 @@ async function handleWorkshopShowInstance(io, ui, env, positionals, flags, deps)
|
|
|
879
884
|
|
|
880
885
|
try {
|
|
881
886
|
const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
|
|
882
|
-
const result = await
|
|
887
|
+
const [result, agenda] = await Promise.all([
|
|
888
|
+
client.getWorkshopInstance(instanceId),
|
|
889
|
+
client.getWorkshopAgenda(instanceId).catch(() => null),
|
|
890
|
+
]);
|
|
883
891
|
ui.json("Workshop Instance", {
|
|
884
892
|
ok: true,
|
|
885
893
|
...summarizeWorkshopInstance(result.instance),
|
|
886
894
|
instance: result.instance,
|
|
895
|
+
contentSummary: agenda ? {
|
|
896
|
+
phases: Array.isArray(agenda.items) ? agenda.items.length : 0,
|
|
897
|
+
scenes: Array.isArray(agenda.items) ? agenda.items.reduce((sum, item) => sum + (item.presenterScenes?.length ?? 0), 0) : 0,
|
|
898
|
+
currentPhase: agenda.phase ?? null,
|
|
899
|
+
} : null,
|
|
887
900
|
});
|
|
888
901
|
return 0;
|
|
889
902
|
} catch (error) {
|
|
@@ -1118,6 +1131,10 @@ async function handleWorkshopResetInstance(io, ui, env, positionals, flags, deps
|
|
|
1118
1131
|
readStringFlag(flags, "template-id", "template"),
|
|
1119
1132
|
);
|
|
1120
1133
|
ui.json("Workshop Reset Instance", result);
|
|
1134
|
+
if (result.contentSummary) {
|
|
1135
|
+
const s = result.contentSummary;
|
|
1136
|
+
ui.status("ok", `Reset ${instanceId}: ${s.phases} phases, ${s.scenes} scenes, ${s.briefs} briefs, ${s.challenges} challenges`);
|
|
1137
|
+
}
|
|
1121
1138
|
return 0;
|
|
1122
1139
|
} catch (error) {
|
|
1123
1140
|
if (error instanceof HarnessApiError) {
|
|
@@ -1338,7 +1355,7 @@ export async function runCli(argv, io, deps = {}) {
|
|
|
1338
1355
|
|
|
1339
1356
|
if (scope === "skill") {
|
|
1340
1357
|
ui.heading("Harness CLI — Skill");
|
|
1341
|
-
ui.paragraph("Install the workshop skill into your project repo.");
|
|
1358
|
+
ui.paragraph("Install the workshop skill into your project repo for Codex, pi, and Claude Code.");
|
|
1342
1359
|
ui.blank();
|
|
1343
1360
|
ui.section("Commands");
|
|
1344
1361
|
ui.commandList([
|
|
@@ -1347,11 +1364,10 @@ export async function runCli(argv, io, deps = {}) {
|
|
|
1347
1364
|
ui.blank();
|
|
1348
1365
|
ui.section("After install");
|
|
1349
1366
|
ui.commandList([
|
|
1350
|
-
"Open Codex or
|
|
1351
|
-
"
|
|
1352
|
-
"
|
|
1353
|
-
"
|
|
1354
|
-
"Run: $workshop help",
|
|
1367
|
+
"Open your coding agent (Codex, pi, or Claude Code) in the same repo",
|
|
1368
|
+
"Codex: $workshop commands",
|
|
1369
|
+
"pi: /skill:workshop",
|
|
1370
|
+
"Claude Code: the workshop skill is available as a slash command",
|
|
1355
1371
|
]);
|
|
1356
1372
|
ui.blank();
|
|
1357
1373
|
ui.paragraph("The skill is the participant's primary workshop interface.");
|
package/src/skill-install.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
createWorkshopBundleManifestFromSource,
|
|
7
7
|
createWorkshopBundleFromSource,
|
|
8
8
|
getInstalledSkillPath,
|
|
9
|
+
getClaudeCodeSkillPath,
|
|
9
10
|
getPackagedWorkshopBundlePath,
|
|
10
11
|
getRepoWorkshopSourceRoot,
|
|
11
12
|
pathExists,
|
|
@@ -189,12 +190,15 @@ export async function installWorkshopSkill(startDir, options = {}) {
|
|
|
189
190
|
if (existingInstall && options.force !== true) {
|
|
190
191
|
const installedManifest = await createWorkshopBundleManifestFromDirectory(installPath);
|
|
191
192
|
if (installedManifest.contentHash === sourceManifest.contentHash) {
|
|
193
|
+
// Agents bundle is current but Claude Code target may be missing
|
|
194
|
+
const claudeInstalled = await installClaudeCodeSkill(installPath, targetRoot);
|
|
192
195
|
return {
|
|
193
196
|
installPath,
|
|
194
197
|
skillName: WORKSHOP_SKILL_NAME,
|
|
195
198
|
mode: "already_current",
|
|
196
199
|
sourceMode: resolvedBundle.mode,
|
|
197
200
|
targetRoot,
|
|
201
|
+
claudeCodePath: claudeInstalled,
|
|
198
202
|
};
|
|
199
203
|
}
|
|
200
204
|
|
|
@@ -234,11 +238,36 @@ async function installFreshBundle(resolvedBundle, installPath, targetRoot) {
|
|
|
234
238
|
);
|
|
235
239
|
await installFromResolvedBundle(resolvedBundle, installPath);
|
|
236
240
|
|
|
241
|
+
const claudeInstalled = await installClaudeCodeSkill(installPath, targetRoot);
|
|
242
|
+
|
|
237
243
|
return {
|
|
238
244
|
installPath,
|
|
239
245
|
skillName: WORKSHOP_SKILL_NAME,
|
|
240
246
|
mode: "installed",
|
|
241
247
|
sourceMode: resolvedBundle.mode,
|
|
242
248
|
targetRoot,
|
|
249
|
+
claudeCodePath: claudeInstalled,
|
|
243
250
|
};
|
|
244
251
|
}
|
|
252
|
+
|
|
253
|
+
async function installClaudeCodeSkill(agentsInstallPath, targetRoot) {
|
|
254
|
+
const claudePath = getClaudeCodeSkillPath(targetRoot);
|
|
255
|
+
try {
|
|
256
|
+
await fs.mkdir(claudePath, { recursive: true });
|
|
257
|
+
// Copy the participant SKILL.md as the Claude Code entry point
|
|
258
|
+
await fs.copyFile(
|
|
259
|
+
path.join(agentsInstallPath, "SKILL.md"),
|
|
260
|
+
path.join(claudePath, "SKILL.md"),
|
|
261
|
+
);
|
|
262
|
+
// Copy the workshop-skill support files that the skill references
|
|
263
|
+
const workshopSkillSource = path.join(agentsInstallPath, "workshop-skill");
|
|
264
|
+
const workshopSkillTarget = path.join(claudePath, "workshop-skill");
|
|
265
|
+
if (await pathExists(workshopSkillSource)) {
|
|
266
|
+
await fs.cp(workshopSkillSource, workshopSkillTarget, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
return claudePath;
|
|
269
|
+
} catch {
|
|
270
|
+
// Claude Code install is best-effort — don't fail the main install
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}
|
package/src/workshop-bundle.js
CHANGED
|
@@ -66,6 +66,10 @@ export function getInstalledSkillPath(targetRoot) {
|
|
|
66
66
|
return path.join(targetRoot, ".agents", "skills", WORKSHOP_SKILL_NAME);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
export function getClaudeCodeSkillPath(targetRoot) {
|
|
70
|
+
return path.join(targetRoot, ".claude", "skills", "workshop");
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
export function getBundleManifestPath(bundleRoot) {
|
|
70
74
|
return path.join(bundleRoot, WORKSHOP_BUNDLE_MANIFEST);
|
|
71
75
|
}
|