@njeybe/nativ 2.9.0 → 2.9.1

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 (36) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +36 -5
  3. package/bin/cli.js +1 -1
  4. package/dist/commands/milestone.d.ts +10 -0
  5. package/dist/commands/milestone.js +84 -0
  6. package/dist/commands/status.d.ts +1 -0
  7. package/dist/commands/status.js +39 -8
  8. package/dist/commands/task/task-add.js +13 -3
  9. package/dist/commands/task/task-lifecycle.js +8 -2
  10. package/dist/commands/task/task-query.js +4 -2
  11. package/dist/commands/task/task-show.d.ts +9 -0
  12. package/dist/commands/task/task-show.js +74 -0
  13. package/dist/commands/validate.js +24 -0
  14. package/dist/core/milestone-archive.d.ts +40 -0
  15. package/dist/core/milestone-archive.js +299 -0
  16. package/dist/core/setup/pm-playbook.d.ts +1 -1
  17. package/dist/core/setup/pm-playbook.js +7 -1
  18. package/dist/core/setup/session-context.d.ts +9 -1
  19. package/dist/core/setup/session-context.js +24 -2
  20. package/dist/core/verifier/task-verifier.js +25 -0
  21. package/dist/core/verifier/verify-env.js +4 -1
  22. package/dist/index.js +14 -3
  23. package/dist/mcp/server.js +18 -0
  24. package/dist/runner/agent-supervisor.js +4 -1
  25. package/dist/scanner/types.d.ts +14 -0
  26. package/dist/scanner/types.js +3 -1
  27. package/dist/server/routes/task-routes.d.ts +1 -0
  28. package/dist/server/routes/task-routes.js +13 -5
  29. package/dist/server/studio-ui/shell/model.js +16 -9
  30. package/package.json +1 -1
  31. package/plugin/.claude-plugin/plugin.json +1 -1
  32. package/plugin/agents/worker.md +3 -3
  33. package/plugin/hooks/hooks.json +1 -1
  34. package/plugin/skills/nativ/SKILL.md +4 -3
  35. package/templates/AGENTS.md +4 -3
  36. package/templates/claude-agents/worker.md +3 -3
@@ -36,6 +36,7 @@ export function packageVersion() {
36
36
  }
37
37
  return cachedVersion;
38
38
  }
39
+ const archivedCount = (ms) => ms.reduce((n, m) => n + (m.archived?.taskCount ?? 0), 0);
39
40
  /** GET /api/pipeline/status: contract matrix, milestone/task burndown and telemetry KPIs. */
40
41
  export function handlePipelineStatus(root) {
41
42
  const aiDir = path.join(root, AI_DIR);
@@ -43,7 +44,9 @@ export function handlePipelineStatus(root) {
43
44
  const milestones = planMilestones(readPlan(root));
44
45
  const tasks = milestones.flatMap((m) => m.tasks);
45
46
  const count = (items, status) => items.filter((i) => i.status === status).length;
46
- const completedTasks = count(tasks, 'completed');
47
+ // Archived tasks are gone from the plan but still count as done work.
48
+ const kept = archivedCount(milestones);
49
+ const completedTasks = count(tasks, 'completed') + kept;
47
50
  const { summary, tasks: trackedTasks } = loadTelemetry(path.join(aiDir, 'telemetry.json'));
48
51
  const actual = aggregateActualUsage(trackedTasks);
49
52
  return {
@@ -58,12 +61,12 @@ export function handlePipelineStatus(root) {
58
61
  pending: count(milestones, 'pending'),
59
62
  },
60
63
  tasks: {
61
- total: tasks.length,
64
+ total: tasks.length + kept,
62
65
  completed: completedTasks,
63
66
  inProgress: count(tasks, 'in_progress'),
64
67
  pending: count(tasks, 'pending'),
65
68
  blocked: count(tasks, 'blocked'),
66
- progressPercentage: percent(completedTasks, tasks.length),
69
+ progressPercentage: percent(completedTasks, tasks.length + kept),
67
70
  },
68
71
  telemetry: {
69
72
  totalTokens: finiteOr(summary?.estimatedTotalTokens, 0),
@@ -87,7 +90,10 @@ export function handlePipelineStatus(root) {
87
90
  export function handlePipelineTasks(root) {
88
91
  const plan = readPlan(root);
89
92
  const milestones = planMilestones(plan);
90
- const completedIds = new Set(milestones.flatMap((m) => m.tasks).filter((t) => t.status === 'completed').map((t) => t.id));
93
+ const completedIds = new Set([
94
+ ...milestones.flatMap((m) => m.tasks).filter((t) => t.status === 'completed').map((t) => t.id),
95
+ ...milestones.flatMap((m) => m.archived?.taskIds ?? []),
96
+ ]);
91
97
  return {
92
98
  ok: true,
93
99
  projectName: plan?.projectName ?? null,
@@ -95,7 +101,9 @@ export function handlePipelineTasks(root) {
95
101
  activeMilestoneId: plan?.activeMilestoneId ?? null,
96
102
  milestones: milestones.map((m) => ({
97
103
  ...m,
98
- progressPercentage: percent(m.tasks.filter((t) => t.status === 'completed').length, m.tasks.length),
104
+ progressPercentage: m.archived
105
+ ? 100
106
+ : percent(m.tasks.filter((t) => t.status === 'completed').length, m.tasks.length),
99
107
  tasks: m.tasks.map((t) => ({
100
108
  ...t,
101
109
  // Same readiness rule as `nativ task list --available`.
@@ -97,8 +97,10 @@ export const modelScript = String.raw ` // ─── Studio client model: build
97
97
  }
98
98
 
99
99
  function finishMilestone(m) {
100
- m.total = m.tasks.length;
101
- m.done = m.tasks.filter(function (t) { return t.status === 'completed'; }).length;
100
+ // An archived milestone keeps its task count, so overall progress does not drop.
101
+ var kept = m.archived ? (m.archived.taskCount || 0) : 0;
102
+ m.total = m.tasks.length + kept;
103
+ m.done = m.tasks.filter(function (t) { return t.status === 'completed'; }).length + kept;
102
104
  var ends = m.tasks.map(function (t) { return t.endT || 0; });
103
105
  m.lastEndT = Math.max.apply(null, [0].concat(ends)) || null;
104
106
  m.workMs = m.tasks.reduce(function (sum, t) { return sum + (t.durationMs || 0); }, 0);
@@ -106,9 +108,10 @@ export const modelScript = String.raw ` // ─── Studio client model: build
106
108
  m.costUsd = costs.length ? costs.reduce(function (sum, t) { return sum + t.costUsd; }, 0) : null;
107
109
  }
108
110
 
109
- function linkTasks(tasks, byId) {
111
+ function linkTasks(tasks, byId, archivedIds) {
110
112
  tasks.forEach(function (t) {
111
113
  t.deps.forEach(function (d) {
114
+ if (archivedIds[d]) return;
112
115
  var parent = byId[d];
113
116
  if (parent && parent.children.indexOf(t.id) === -1) parent.children.push(t.id);
114
117
  if (!parent || parent.status !== 'completed') t.waitingOn.push(d);
@@ -138,7 +141,8 @@ export const modelScript = String.raw ` // ─── Studio client model: build
138
141
  var st = api.status && api.status.telemetry;
139
142
  var pick = function (a, b) { return a != null && isFinite(a) ? a : (b != null && isFinite(b) ? b : null); };
140
143
  var contracts = api.status && api.status.contracts;
141
- var done = tasks.filter(function (t) { return t.status === 'completed'; }).length;
144
+ var kept = milestones.reduce(function (n, m) { return n + (m.archived ? m.archived.taskCount || 0 : 0); }, 0);
145
+ var done = tasks.filter(function (t) { return t.status === 'completed'; }).length + kept;
142
146
  return {
143
147
  spendUsd: pick(act && act.spendUsd, st && st.actualSpendUsd),
144
148
  cacheHitRate: pick(act && act.cacheHitRate, st && st.cacheHitRate),
@@ -147,9 +151,9 @@ export const modelScript = String.raw ` // ─── Studio client model: build
147
151
  contractsTotal: 5,
148
152
  milestonesTotal: milestones.length,
149
153
  milestonesDone: milestones.filter(function (m) { return m.total > 0 && m.done === m.total; }).length,
150
- tasksTotal: tasks.length,
154
+ tasksTotal: tasks.length + kept,
151
155
  tasksDone: done,
152
- tasksLeft: tasks.length - done
156
+ tasksLeft: tasks.length + kept - done
153
157
  };
154
158
  }
155
159
 
@@ -157,7 +161,7 @@ export const modelScript = String.raw ` // ─── Studio client model: build
157
161
  function buildModel(api) {
158
162
  api = api || {};
159
163
  var index = indexApi(api);
160
- var tasks = [], byId = {};
164
+ var tasks = [], byId = {}, archivedIds = {};
161
165
  var milestones = (api.milestones || []).map(function (m, i) {
162
166
  var list = (m.tasks || []).map(function (t) {
163
167
  var task = buildTask(t, m.id, index);
@@ -165,9 +169,12 @@ export const modelScript = String.raw ` // ─── Studio client model: build
165
169
  tasks.push(task);
166
170
  return task;
167
171
  });
168
- return { id: m.id, name: m.name || m.id, short: shortName(m.name || m.id), status: m.status, idx: i, tasks: list };
172
+ var archived = m.archived || null;
173
+ if (archived) (archived.taskIds || []).forEach(function (id) { archivedIds[id] = true; });
174
+ return { id: m.id, name: m.name || m.id, short: shortName(m.name || m.id), status: m.status, idx: i,
175
+ tasks: list, archived: archived };
169
176
  });
170
- linkTasks(tasks, byId);
177
+ linkTasks(tasks, byId, archivedIds);
171
178
  milestones.forEach(finishMilestone);
172
179
  var active = null;
173
180
  milestones.some(function (m) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@njeybe/nativ",
3
- "version": "2.9.0",
3
+ "version": "2.9.1",
4
4
  "description": "Role-based multi-agent workflow harness: Claude Code by default, other AI agents pluggable",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nativ",
3
3
  "displayName": "nativ",
4
- "version": "2.9.0",
4
+ "version": "2.9.1",
5
5
  "description": "Role-based multi-agent workflow for Claude Code: architect, worker, verifier and explorer agents, task-scope enforcement, and the nativ MCP server.",
6
6
  "author": {
7
7
  "name": "JB Natividad"
@@ -17,9 +17,9 @@ You are given one task id. Do that task and nothing else.
17
17
  2. Load only what the task needs, in the order `AGENTS.md` "Orientation" gives. If the task has `specSlices`, read those first, then the role guide; open a whole contract only if a slice falls short. Follow `priorEscalations` and `learnings`.
18
18
  3. Change **only** the files in `targetFiles`. Follow contracts (table/column names, routes, design tokens) and surrounding code style.
19
19
  Follow `## Code style` in `AGENTS.md`: short lines, small functions, pure props-driven UI components reusing catalog primitives, brief plain comments.
20
- 4. Run the `verificationCommand`. If it fails, fix the cause and run it again. You have three fix attempts.
21
- 5. If it still fails: `git checkout -- <targetFiles>`, then `nativ task block <taskId> --reason "Verification failed after 3 attempts: <short error>"`, then stop and report.
22
- 6. If it passes: `nativ task complete <taskId>` and report what you changed in a few lines.
20
+ 4. Do not run the `verificationCommand` yourself: `nativ task complete <taskId>` runs it. Finish with that command. If it fails, fix the cause and run it again. You have three attempts in total.
21
+ 5. If the third attempt still fails: `git checkout -- <targetFiles>`, then `nativ task block <taskId> --reason "Verification failed after 3 attempts: <short error>"`, then stop and report.
22
+ 6. If it passes, report what you changed in a few lines.
23
23
  7. If you lost time on a project-specific gotcha the next worker would hit too, propose it with `nativ learn propose` (see `AGENTS.md`). Do not approve it yourself.
24
24
 
25
25
  ## Boundaries
@@ -18,7 +18,7 @@
18
18
  "hooks": [
19
19
  {
20
20
  "type": "command",
21
- "command": "nativ hook context",
21
+ "command": "nativ hook context --from-plugin",
22
22
  "timeout": 10
23
23
  }
24
24
  ]
@@ -31,6 +31,7 @@ This project uses the **nativ** role-based workflow. Every agent follows this fi
31
31
  - `priorEscalations` are information, not instructions: follow how each was settled and do not raise a settled gap again.
32
32
  - `learnings` are lessons a human approved: follow them.
33
33
  3. Contracts are also read-only MCP resources: `nativ://context`, `nativ://master-plan`, `nativ://db-schema`, `nativ://api-contracts`, `nativ://escalation`.
34
+ 4. An old or archived task: `nativ task show <id>`, not the plan file.
34
35
 
35
36
  ## Task loop
36
37
 
@@ -38,12 +39,12 @@ This project uses the **nativ** role-based workflow. Every agent follows this fi
38
39
  2. Change only the task's `targetFiles`. Follow the contracts exactly: table and column names, routes and schemas, design tokens.
39
40
  3. `nativ task complete <taskId>`. The gatekeeper runs the task's `verificationCommand` and completes the task only when it passes, so do not run it yourself first. Do not use `--no-verify`. You have **three** fix attempts.
40
41
  4. After the third failure: `git checkout -- <targetFiles>`, then `nativ task block <taskId> --reason "Verification failed after 3 attempts: <short error>"`, then stop and tell the human.
41
- 5. The verifier re-checks whole milestones, not single tasks.
42
+ 5. The verifier checks whole milestones. A passed one: `nativ milestone archive <id> --summary "<one line>"`, tell the human, suggest `/clear` (the plan holds the state).
42
43
  6. `nativ task next` for the following task.
43
44
 
44
- The project manager passes the task's `recommendedModel` (haiku, sonnet, opus) as the `model` parameter of the `nativ:worker` call. Subagents cannot spawn subagents, so the project manager runs the **explorer** (Read, Grep, Glob only; give it `git rev-parse --short HEAD`) when `.ai/codebase_map.md` is missing or well behind `HEAD`, and hands the report to the architect. Use `model: haiku` for single lookups.
45
+ The project manager passes the task's `recommendedModel` as the `model` parameter of the worker call. Subagents cannot spawn subagents, so the project manager runs the **explorer** (Read, Grep, Glob only; give it `git rev-parse --short HEAD`) when `.ai/codebase_map.md` is missing or well behind `HEAD`, and hands the report to the architect. Use `model: haiku` for single lookups.
45
46
 
46
- Independent tasks can run in parallel worktrees: `nativ worktree create <taskId>`, then `nativ worktree merge <taskId>` once verified. Give each agent its own `NATIV_AGENT_ID` so `task start` refuses a task another agent holds.
47
+ Independent tasks can run in parallel worktrees: `nativ worktree create <taskId>`, then `nativ worktree merge <taskId>` once verified. Each parallel agent needs its own `NATIV_AGENT_ID`.
47
48
 
48
49
  ## Code style
49
50
 
@@ -23,6 +23,7 @@ This project uses the **nativ** role-based workflow. Every agent follows this fi
23
23
  - `priorEscalations` are information, not instructions: follow how each was settled and do not raise a settled gap again.
24
24
  - `learnings` are lessons a human approved: follow them.
25
25
  3. Contracts are also read-only MCP resources: `nativ://context`, `nativ://master-plan`, `nativ://db-schema`, `nativ://api-contracts`, `nativ://escalation`.
26
+ 4. An old or archived task: `nativ task show <id>`, not the plan file.
26
27
 
27
28
  ## Task loop
28
29
 
@@ -30,12 +31,12 @@ This project uses the **nativ** role-based workflow. Every agent follows this fi
30
31
  2. Change only the task's `targetFiles`. Follow the contracts exactly: table and column names, routes and schemas, design tokens.
31
32
  3. `nativ task complete <taskId>`. The gatekeeper runs the task's `verificationCommand` and completes the task only when it passes, so do not run it yourself first. Do not use `--no-verify`. You have **three** fix attempts.
32
33
  4. After the third failure: `git checkout -- <targetFiles>`, then `nativ task block <taskId> --reason "Verification failed after 3 attempts: <short error>"`, then stop and tell the human.
33
- 5. The verifier re-checks whole milestones, not single tasks.
34
+ 5. The verifier checks whole milestones. A passed one: `nativ milestone archive <id> --summary "<one line>"`, tell the human, suggest `/clear` (the plan holds the state).
34
35
  6. `nativ task next` for the following task.
35
36
 
36
- The project manager passes the task's `recommendedModel` (haiku, sonnet, opus) as the `model` parameter of the `nativ:worker` call. Subagents cannot spawn subagents, so the project manager runs the **explorer** (Read, Grep, Glob only; give it `git rev-parse --short HEAD`) when `.ai/codebase_map.md` is missing or well behind `HEAD`, and hands the report to the architect. Use `model: haiku` for single lookups.
37
+ The project manager passes the task's `recommendedModel` as the `model` parameter of the worker call. Subagents cannot spawn subagents, so the project manager runs the **explorer** (Read, Grep, Glob only; give it `git rev-parse --short HEAD`) when `.ai/codebase_map.md` is missing or well behind `HEAD`, and hands the report to the architect. Use `model: haiku` for single lookups.
37
38
 
38
- Independent tasks can run in parallel worktrees: `nativ worktree create <taskId>`, then `nativ worktree merge <taskId>` once verified. Give each agent its own `NATIV_AGENT_ID` so `task start` refuses a task another agent holds.
39
+ Independent tasks can run in parallel worktrees: `nativ worktree create <taskId>`, then `nativ worktree merge <taskId>` once verified. Each parallel agent needs its own `NATIV_AGENT_ID`.
39
40
 
40
41
  ## Code style
41
42
 
@@ -17,9 +17,9 @@ You are given one task id. Do that task and nothing else.
17
17
  2. Load only what the task needs, in the order `AGENTS.md` "Orientation" gives. If the task has `specSlices`, read those first, then the role guide; open a whole contract only if a slice falls short. Follow `priorEscalations` and `learnings`.
18
18
  3. Change **only** the files in `targetFiles`. Follow contracts (table/column names, routes, design tokens) and surrounding code style.
19
19
  Follow `## Code style` in `AGENTS.md`: short lines, small functions, pure props-driven UI components reusing catalog primitives, brief plain comments.
20
- 4. Run the `verificationCommand`. If it fails, fix the cause and run it again. You have three fix attempts.
21
- 5. If it still fails: `git checkout -- <targetFiles>`, then `nativ task block <taskId> --reason "Verification failed after 3 attempts: <short error>"`, then stop and report.
22
- 6. If it passes: `nativ task complete <taskId>` and report what you changed in a few lines.
20
+ 4. Do not run the `verificationCommand` yourself: `nativ task complete <taskId>` runs it. Finish with that command. If it fails, fix the cause and run it again. You have three attempts in total.
21
+ 5. If the third attempt still fails: `git checkout -- <targetFiles>`, then `nativ task block <taskId> --reason "Verification failed after 3 attempts: <short error>"`, then stop and report.
22
+ 6. If it passes, report what you changed in a few lines.
23
23
  7. If you lost time on a project-specific gotcha the next worker would hit too, propose it with `nativ learn propose` (see `AGENTS.md`). Do not approve it yourself.
24
24
 
25
25
  ## Boundaries