@ionivetech/mugiwara 0.6.1 → 0.6.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.
Files changed (37) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.cursor-plugin/plugin.json +1 -1
  5. package/.kimi-plugin/plugin.json +1 -1
  6. package/.opencode/commands/mugiwara-onboard.md +15 -0
  7. package/.opencode/plugins/mugiwara.mjs +6 -5
  8. package/README.md +15 -13
  9. package/content/agents/luffy-orchestrator.md +14 -4
  10. package/content/agents/onboarding-guide.md +24 -45
  11. package/content/agents/zoro-execution.md +4 -0
  12. package/content/skills/mugiwara-backend/SKILL.md +1 -1
  13. package/content/skills/mugiwara-checkpoint/SKILL.md +1 -1
  14. package/content/skills/mugiwara-claim-audit/SKILL.md +1 -1
  15. package/content/skills/mugiwara-execution/SKILL.md +20 -20
  16. package/content/skills/mugiwara-execution/references/dispatch.md +4 -3
  17. package/content/skills/mugiwara-frontend/SKILL.md +1 -1
  18. package/content/skills/mugiwara-healing/SKILL.md +1 -1
  19. package/content/skills/mugiwara-orchestration/SKILL.md +28 -31
  20. package/content/skills/mugiwara-orchestration/references/check-ins.md +34 -0
  21. package/content/skills/mugiwara-orchestration/references/closure.md +1 -1
  22. package/content/skills/mugiwara-pr/SKILL.md +11 -8
  23. package/content/skills/mugiwara-ship/SKILL.md +1 -1
  24. package/content/skills/mugiwara-sunset/SKILL.md +1 -1
  25. package/content/skills/mugiwara-workflow/SKILL.md +3 -1
  26. package/content/skills/mugiwara-workflow/references/workspace-layout.md +7 -6
  27. package/content/skills/using-mugiwara/SKILL.md +4 -0
  28. package/dist/mugiwara.js +5 -12
  29. package/gemini-extension.json +1 -1
  30. package/package.json +1 -1
  31. package/plugin.json +1 -1
  32. package/scripts/onboard.ts +3 -29
  33. package/scripts/release-notes.ts +152 -75
  34. package/scripts/savepoint.sh +10 -2
  35. package/src/mission.ts +3 -6
  36. package/src/targets/claude.ts +5 -3
  37. package/src/targets/opencode.ts +12 -8
@@ -7,6 +7,14 @@ die() { echo "savepoint: $*" >&2; exit 1; }
7
7
 
8
8
  MUGIWARA_DIR="${MUGIWARA_DIR:-.mugiwara}"
9
9
 
10
+ # --- git identity for actor attribution ---
11
+ # Resolve once from repo git config; used when no actor is passed explicitly.
12
+ # GIT_AUTHOR_NAME is an env var usually unset — falling through to $USER
13
+ # attributes the savepoint to the OS user instead of the git identity.
14
+ GIT_NAME="$(git config user.name 2>/dev/null || true)"
15
+ GIT_EMAIL="$(git config user.email 2>/dev/null || true)"
16
+ if [ -n "$GIT_NAME" ] && [ -n "$GIT_EMAIL" ]; then GIT_ID="$GIT_NAME <$GIT_EMAIL>"; else GIT_ID="$GIT_NAME"; fi
17
+
10
18
  # --- parse mission args ---
11
19
  # --branch flag must parse FIRST — it shifts positionals
12
20
  BRANCH_MODE=0
@@ -14,13 +22,13 @@ if [ "${1:-}" = "--branch" ]; then
14
22
  BRANCH_MODE=1
15
23
  shift
16
24
  MISSION="${1:-${STATE_MISSION:-}}"
17
- ACTOR="${2:-${STATE_ACTOR:-${GIT_AUTHOR_NAME:-${USER:-}}}}"
25
+ ACTOR="${2:-${STATE_ACTOR:-${GIT_AUTHOR_NAME:-${GIT_ID:-${USER:-}}}}}"
18
26
  BRANCH="${3:-$(git branch --show-current 2>/dev/null || echo 'unknown')}"
19
27
  WAVE="${4:-${STATE_WAVE:-1}}"
20
28
  MODE="${5:-${STATE_MODE:-guided}}"
21
29
  else
22
30
  MISSION="${1:-${STATE_MISSION:-}}"
23
- ACTOR="${2:-${STATE_ACTOR:-${GIT_AUTHOR_NAME:-${USER:-}}}}"
31
+ ACTOR="${2:-${STATE_ACTOR:-${GIT_AUTHOR_NAME:-${GIT_ID:-${USER:-}}}}}"
24
32
  BRANCH="${3:-$(git branch --show-current 2>/dev/null || echo 'unknown')}"
25
33
  WAVE="${4:-${STATE_WAVE:-1}}"
26
34
  MODE="${5:-${STATE_MODE:-guided}}"
package/src/mission.ts CHANGED
@@ -80,15 +80,12 @@ export function archiveMission(projectDir: string, mission: string, opts: { dryR
80
80
  if (f) report = join('reports', f);
81
81
  }
82
82
 
83
- // remove per-mission wave intermediates from results/<mission>/, EXCEPT
84
- // 06-closure.md and 07-pr-verdict.md (PR material + closure stay)
83
+ // step results 01..05 + todos.md are evidence — kept; archive removes
84
+ // only spec/review/issues/logs/continue.md
85
85
  const resultsDir = join(root, 'results', mission);
86
86
  if (existsSync(resultsDir)) {
87
87
  for (const f of readdirSync(resultsDir)) {
88
- if (f === '06-closure.md' || f === '07-pr-verdict.md') { kept.push(join('results', mission, f)); continue; }
89
- const p = join(resultsDir, f);
90
- if (!dryRun) rmSync(p, { recursive: true, force: true });
91
- removed.push(join('results', mission, f));
88
+ kept.push(join('results', mission, f));
92
89
  }
93
90
  }
94
91
 
@@ -10,8 +10,10 @@ const HOOKS_SRC = join(here, '..', '..', 'hooks');
10
10
  const COMMANDS_SRC = join(here, '..', '..', '.claude', 'commands');
11
11
 
12
12
  // Claude Code has no path-scoped permission. write-scope maps to a partial
13
- // `tools:` list: artifacts agents lose Edit (cannot modify existing source)
14
- // but keep Write (must create .mugiwara/**); source agents get the default set.
13
+ // `tools:` list applied to internal subagent-only agents only: artifacts
14
+ // agents lose Edit (cannot modify existing source) but keep Write (must create
15
+ // .mugiwara/**). User-facing crew run inline in the main thread and keep the
16
+ // default toolset (incl. Edit); discipline is enforced by rules, not tools.
15
17
  function toolsFromScope(scope?: string): string | undefined {
16
18
  if (scope === 'artifacts') return 'Read, Grep, Glob, Write, Bash, WebFetch, WebSearch';
17
19
  return undefined;
@@ -35,7 +37,7 @@ export const target: Target = {
35
37
  transformAgent(data: FrontmatterData, body: string) {
36
38
  const fm: FrontmatterData = { name: data.name, description: data.description };
37
39
  if (data.tools) fm.tools = data.tools;
38
- else {
40
+ else if (data['internal-agent'] === 'true') {
39
41
  const generated = toolsFromScope(data['write-scope']);
40
42
  if (generated) fm.tools = generated;
41
43
  }
@@ -32,23 +32,27 @@ const CREW: Record<string, CrewConfig> = {
32
32
  'memory-keeper': { color: '#d946ef', temperature: 0.2, steps: 8 },
33
33
  };
34
34
 
35
- // write-scope is the single source of truth (content/agents/*.md frontmatter).
36
- // The path boundary (artifacts vs source) IS expressible in opencode:
37
- // permission.edit accepts glob/pattern -> action, last match wins. Artifacts
38
- // agents get deny-all-edit except .mugiwara/**; source agents (zoro, brook)
39
- // get full edit allow. Derived at install time from the frontmatter field.
35
+ // write-scope is the single source of truth (content/agents/*.md frontmatter),
36
+ // but it is a RULE for user-facing crew agents: they run inline in the main
37
+ // thread, so a runtime permission bound to the active-agent identity would
38
+ // force tab-switching per wave and break auto mode + resume. Runtime
39
+ // enforcement stays for internal subagent-only agents (internal: true) the
40
+ // path boundary IS expressible in opencode: permission.edit accepts
41
+ // glob/pattern -> action, last match wins. Artifacts internal agents get
42
+ // deny-all-edit except .mugiwara/**; source internal agents get full edit
43
+ // allow. Derived at install time from the frontmatter field.
40
44
  function permissionFromScope(scope: string | undefined): Record<string, string | Record<string, string>> | undefined {
41
45
  if (scope === 'source') return { edit: 'allow' };
42
46
  if (scope === 'artifacts') return { edit: { '*': 'deny', '.mugiwara/**': 'allow' } };
43
47
  return undefined;
44
48
  }
45
49
 
46
- function agentFrontmatter(name: string, description: string, writeScope?: string) {
50
+ function agentFrontmatter(name: string, description: string, internal: boolean, writeScope?: string) {
47
51
  const crew = CREW[name];
48
52
  const lines = [`description: ${description}`, `mode: all`];
49
53
  if (crew) {
50
54
  lines.push(`color: '${crew.color}'`, `temperature: ${crew.temperature}`, `steps: ${crew.steps}`);
51
- const perm = permissionFromScope(writeScope);
55
+ const perm = internal ? permissionFromScope(writeScope) : undefined;
52
56
  if (perm) {
53
57
  lines.push('permission:');
54
58
  for (const [k, v] of Object.entries(perm)) {
@@ -81,7 +85,7 @@ export const target: Target = {
81
85
  },
82
86
  transformAgent(data: FrontmatterData, body: string) {
83
87
  const desc = data['internal-agent'] === 'true' ? `[INTERNAL] ${data.description}` : data.description;
84
- const fm = agentFrontmatter(data.name, desc, data['write-scope']);
88
+ const fm = agentFrontmatter(data.name, desc, data['internal-agent'] === 'true', data['write-scope']);
85
89
  return { relPath: `${data.name}.md`, text: `---\n${fm}\n---\n${body}` };
86
90
  },
87
91
  refsDir({ scope, projectDir, home }, skillName: string) {