@agentworkforce/cli 2.1.0 → 2.1.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/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.1.2] - 2026-05-11
11
+
12
+ ### Changed
13
+
14
+ - Persona sources: keep cwd label as `cwd` (not `repo`)
15
+ - Persona sources: rename display labels (built-in / repo / personal)
16
+ - Persona-kit: add local skill source provider
17
+
10
18
  ## [2.1.0] - 2026-05-11
11
19
 
12
20
  ### Changed
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import { listBuiltInPersonas, personaCatalog, routingProfiles } from '@agentwork
10
10
  import { createMount, readAgentDotfiles } from '@relayfile/local-mount';
11
11
  import ora from 'ora';
12
12
  import { startLaunchMetadataRecording } from './launch-metadata.js';
13
- import { buildPersonaSourceDirectories, defaultCwdPersonaDir, loadLocalPersonas, loadPersonaSourceConfig, normalizePersonaDir, savePersonaSourceConfig } from './local-personas.js';
13
+ import { buildPersonaSourceDirectories, defaultCwdPersonaDir, formatPersonaSourceLabel, loadLocalPersonas, loadPersonaSourceConfig, normalizePersonaDir, savePersonaSourceConfig } from './local-personas.js';
14
14
  import { installPersonas } from './persona-install.js';
15
15
  import { pickPersona } from './persona-picker.js';
16
16
  import { recordRecent, loadRecents, runPersonaPickerTui } from './persona-tui.js';
@@ -18,7 +18,9 @@ const USAGE = `Usage: agentworkforce <command> [args...]
18
18
 
19
19
  Run with no arguments inside a TTY to open an interactive persona picker —
20
20
  the top 3 most recently used personas are shown first, and typing fuzzy-
21
- searches across persona names and descriptions.
21
+ searches across persona names and descriptions. Each row's SOURCE column
22
+ is one of: built-in (bundled), cwd (./.agentworkforce/workforce/personas),
23
+ personal (~/.agentworkforce/workforce/personas), or dir:N (configured).
22
24
 
23
25
  Commands:
24
26
  create [flags] Opens persona-maker@best for creating a new
@@ -424,7 +426,10 @@ async function runInstallOrThrow(command, label, cwd) {
424
426
  }
425
427
  }
426
428
  function buildInstallContext(selection, options = {}) {
427
- const plan = materializeSkills(selection.skills, selection.runtime.harness, options.installRoot !== undefined ? { installRoot: options.installRoot } : {});
429
+ const plan = materializeSkills(selection.skills, selection.runtime.harness, {
430
+ ...(options.installRoot !== undefined ? { installRoot: options.installRoot } : {}),
431
+ ...(options.repoRoot !== undefined ? { repoRoot: options.repoRoot } : {})
432
+ });
428
433
  const { installCommand, installCommandString } = buildInstallArtifacts(plan);
429
434
  const { cleanupCommand, cleanupCommandString } = buildCleanupArtifacts(plan);
430
435
  return {
@@ -852,7 +857,12 @@ function runDryRun(selection) {
852
857
  process.stderr.write(`warning: ${w}\n`);
853
858
  process.stderr.write(`✓ harness spec: ${spec.bin} (${spec.args.length} args)\n`);
854
859
  // Check 3: skill installs.
855
- const plan = materializeSkills(effectiveSelection.skills, runtime.harness);
860
+ // Dry-run runs each install inside a fresh tempDir (see `cwd: tempDir` on
861
+ // the spawnSync below). Pass repoRoot=process.cwd() so `local`-kind skills
862
+ // resolve their relative source paths against the real repo, not the tmp.
863
+ const plan = materializeSkills(effectiveSelection.skills, runtime.harness, {
864
+ repoRoot: process.cwd()
865
+ });
856
866
  if (plan.installs.length === 0) {
857
867
  process.stderr.write('✓ skills: (none declared)\n');
858
868
  process.stderr.write('✓ dry-run ok\n');
@@ -949,7 +959,15 @@ async function runInteractive(selection, options) {
949
959
  const installRoot = sessionRoot && runtime.harness === 'claude'
950
960
  ? sessionInstallRoot(sessionRoot)
951
961
  : undefined;
952
- const install = buildInstallContext(effectiveSelection, installRoot !== undefined ? { installRoot } : {});
962
+ // `repoRoot` lets the local skill provider (kind: 'local') resolve
963
+ // relative source paths like `.agentworkforce/workforce/skills/foo.md` to
964
+ // absolute paths before the install command runs. Critical for claude's
965
+ // installRoot mode, where the install runs `cd <installRoot> && cp ...`
966
+ // and a relative source would otherwise resolve against the wrong dir.
967
+ const install = buildInstallContext(effectiveSelection, {
968
+ ...(installRoot !== undefined ? { installRoot } : {}),
969
+ repoRoot: process.cwd()
970
+ });
953
971
  process.stderr.write(`→ ${personaId} [${tier}] via ${runtime.harness} (${runtime.model})\n`);
954
972
  const startLaunchMetadataForLaunch = (cwd = process.cwd()) => startLaunchMetadataRecording({
955
973
  selection: effectiveSelection,
@@ -1403,12 +1421,18 @@ function formatSourcesTable(rows, configPath, defaultCreateTarget) {
1403
1421
  dir: 'DIR'
1404
1422
  };
1405
1423
  const cols = ['cascade', 'config', 'source', 'exists', 'dir'];
1406
- const widths = Object.fromEntries(cols.map((c) => [c, Math.max(headers[c].length, ...rows.map((r) => r[c].length))]));
1424
+ // Display label only the underlying `source` literal flows through to
1425
+ // --json so tooling that pins on `'cwd'` / `'user'` / `'library'` is fine.
1426
+ const display = rows.map((r) => ({
1427
+ ...r,
1428
+ source: formatPersonaSourceLabel(r.source)
1429
+ }));
1430
+ const widths = Object.fromEntries(cols.map((c) => [c, Math.max(headers[c].length, ...display.map((r) => r[c].length))]));
1407
1431
  const line = (row) => cols.map((c) => row[c].padEnd(widths[c])).join(' ').trimEnd();
1408
1432
  return [
1409
1433
  `Config: ${configPath}`,
1410
1434
  `Default create target: ${defaultCreateTarget ?? '(auto)'}`,
1411
- [line(headers), ...rows.map(line)].join('\n'),
1435
+ [line(headers), ...display.map(line)].join('\n'),
1412
1436
  ''
1413
1437
  ].join('\n');
1414
1438
  }
@@ -1691,7 +1715,9 @@ function formatPersonaTable(rows, display) {
1691
1715
  };
1692
1716
  const rendered = rows.map((r) => ({
1693
1717
  persona: r.persona,
1694
- source: r.source,
1718
+ // Show the user-facing label (`built-in` / `repo` / `personal` / `dir:N`).
1719
+ // The internal cascade key is still in `--json` output for tooling.
1720
+ source: formatPersonaSourceLabel(r.source),
1695
1721
  harness: r.harness,
1696
1722
  model: r.model,
1697
1723
  rating: r.rating,
@@ -3064,13 +3090,17 @@ function applyPatchInPlace(root, patch) {
3064
3090
  export function buildTuiCandidates() {
3065
3091
  const byId = new Map();
3066
3092
  for (const spec of listBuiltInPersonas()) {
3067
- byId.set(spec.id, { id: spec.id, description: spec.description, source: 'library' });
3093
+ byId.set(spec.id, {
3094
+ id: spec.id,
3095
+ description: spec.description,
3096
+ source: formatPersonaSourceLabel('library')
3097
+ });
3068
3098
  }
3069
3099
  for (const [id, spec] of local.byId.entries()) {
3070
3100
  byId.set(id, {
3071
3101
  id,
3072
3102
  description: spec.description,
3073
- source: local.sources.get(id) ?? 'library'
3103
+ source: formatPersonaSourceLabel(local.sources.get(id) ?? 'library')
3074
3104
  });
3075
3105
  }
3076
3106
  return [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));