prjct-cli 1.21.0 → 1.22.0

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.
@@ -10968,7 +10968,7 @@ var init_shipped = __esm({
10968
10968
 
10969
10969
  // core/schemas/state.ts
10970
10970
  import { z as z14 } from "zod";
10971
- var PrioritySchema, TaskTypeSchema, TaskSectionSchema, TaskStatusSchema, ActivityTypeSchema, SubtaskSummarySchema, SubtaskCompletionDataSchema, SubtaskSchema, SubtaskProgressSchema, CurrentTaskSchema, PreviousTaskSchema, StateJsonSchema, QueueTaskSchema, QueueJsonSchema, StatsSchema, RecentActivitySchema, StateSchemaFull;
10971
+ var PrioritySchema, TaskTypeSchema, TaskSectionSchema, TaskStatusSchema, ActivityTypeSchema, SubtaskSummarySchema, SubtaskCompletionDataSchema, SubtaskSchema, SubtaskProgressSchema, CurrentTaskSchema, PreviousTaskSchema, TaskFeedbackSchema, TaskHistoryEntrySchema, StateJsonSchema, QueueTaskSchema, QueueJsonSchema, StatsSchema, RecentActivitySchema, StateSchemaFull;
10972
10972
  var init_state = __esm({
10973
10973
  "core/schemas/state.ts"() {
10974
10974
  "use strict";
@@ -11079,12 +11079,63 @@ var init_state = __esm({
11079
11079
  // ISO8601
11080
11080
  pauseReason: z14.string().optional()
11081
11081
  });
11082
+ TaskFeedbackSchema = z14.object({
11083
+ // Stack confirmations - tech confirmed/used during the task
11084
+ stackConfirmed: z14.array(z14.string()).optional(),
11085
+ // ["React 18", "TypeScript strict mode"]
11086
+ // Patterns discovered during the task
11087
+ patternsDiscovered: z14.array(z14.string()).optional(),
11088
+ // ["API routes follow /api/v1/{resource}"]
11089
+ // Agent accuracy - how well domain agents performed
11090
+ agentAccuracy: z14.array(
11091
+ z14.object({
11092
+ agent: z14.string(),
11093
+ // "backend.md"
11094
+ rating: z14.enum(["helpful", "neutral", "inaccurate"]),
11095
+ note: z14.string().optional()
11096
+ // "Missing Tailwind context"
11097
+ })
11098
+ ).optional(),
11099
+ // Issues encountered during the task
11100
+ issuesEncountered: z14.array(z14.string()).optional()
11101
+ // ["ESLint conflicts with Prettier"]
11102
+ });
11103
+ TaskHistoryEntrySchema = z14.object({
11104
+ taskId: z14.string(),
11105
+ // task UUID
11106
+ title: z14.string(),
11107
+ // parent task description
11108
+ classification: TaskTypeSchema,
11109
+ // feature, bug, improvement, chore
11110
+ startedAt: z14.string(),
11111
+ // ISO8601
11112
+ completedAt: z14.string(),
11113
+ // ISO8601
11114
+ subtaskCount: z14.number(),
11115
+ // total number of subtasks
11116
+ subtaskSummaries: z14.array(SubtaskSummarySchema),
11117
+ // summary of each subtask
11118
+ outcome: z14.string(),
11119
+ // brief description of what was accomplished
11120
+ branchName: z14.string(),
11121
+ // git branch used
11122
+ linearId: z14.string().optional(),
11123
+ // Linear issue ID if linked
11124
+ linearUuid: z14.string().optional(),
11125
+ // Linear internal UUID
11126
+ prUrl: z14.string().optional(),
11127
+ // PR URL if shipped
11128
+ feedback: TaskFeedbackSchema.optional()
11129
+ // Task-to-analysis feedback (PRJ-272)
11130
+ });
11082
11131
  StateJsonSchema = z14.object({
11083
11132
  currentTask: CurrentTaskSchema.nullable(),
11084
11133
  previousTask: PreviousTaskSchema.nullable().optional(),
11085
11134
  // deprecated: use pausedTasks
11086
11135
  pausedTasks: z14.array(PreviousTaskSchema).optional(),
11087
11136
  // replaces previousTask
11137
+ taskHistory: z14.array(TaskHistoryEntrySchema).optional(),
11138
+ // completed tasks history (max 20)
11088
11139
  lastUpdated: z14.string()
11089
11140
  });
11090
11141
  QueueTaskSchema = z14.object({
@@ -15187,6 +15238,8 @@ var init_state_storage = __esm({
15187
15238
  return {
15188
15239
  currentTask: null,
15189
15240
  previousTask: null,
15241
+ pausedTasks: [],
15242
+ taskHistory: [],
15190
15243
  lastUpdated: ""
15191
15244
  };
15192
15245
  }
@@ -15245,6 +15298,28 @@ var init_state_storage = __esm({
15245
15298
  if (prev.pauseReason) m.raw(` Reason: ${prev.pauseReason}`);
15246
15299
  });
15247
15300
  m.blank().italic("Use /p:resume to continue");
15301
+ }).when((data.taskHistory?.length || 0) > 0, (m) => {
15302
+ const history2 = this.getTaskHistoryFromState(data);
15303
+ if (history2.length === 0) return;
15304
+ const currentTaskType = data.currentTask?.type;
15305
+ const relevantHistory = currentTaskType ? history2.filter((h) => h.classification === currentTaskType).slice(0, 3) : history2.slice(0, 5);
15306
+ if (relevantHistory.length === 0) return;
15307
+ m.hr().h2(
15308
+ currentTaskType ? `Recent ${currentTaskType} tasks (${relevantHistory.length})` : `Recent tasks (${relevantHistory.length})`
15309
+ );
15310
+ relevantHistory.forEach((entry, i) => {
15311
+ m.raw(`${i + 1}. **${entry.title}** (${entry.classification})`).raw(
15312
+ ` Completed: ${toRelative(entry.completedAt)} | ${entry.subtaskCount} subtask${entry.subtaskCount > 1 ? "s" : ""}`
15313
+ ).raw(` Outcome: ${entry.outcome}`);
15314
+ if (entry.linearId) m.raw(` Linear: ${entry.linearId}`);
15315
+ if (entry.feedback?.patternsDiscovered?.length) {
15316
+ m.raw(` Patterns: ${entry.feedback.patternsDiscovered.join(", ")}`);
15317
+ }
15318
+ if (entry.feedback?.issuesEncountered?.length) {
15319
+ m.raw(` Gotchas: ${entry.feedback.issuesEncountered.join(", ")}`);
15320
+ }
15321
+ });
15322
+ m.blank().italic("Task history helps identify patterns and improve decisions");
15248
15323
  }).blank().build();
15249
15324
  }
15250
15325
  // =========== Transition Validation ===========
@@ -15306,29 +15381,65 @@ var init_state_storage = __esm({
15306
15381
  }
15307
15382
  /**
15308
15383
  * Complete current task
15384
+ * Creates a TaskHistoryEntry and adds it to taskHistory with FIFO eviction
15385
+ * Optionally accepts structured feedback for the task-to-analysis feedback loop (PRJ-272)
15309
15386
  */
15310
- async completeTask(projectId) {
15387
+ async completeTask(projectId, feedback) {
15311
15388
  const state = await this.read(projectId);
15312
15389
  const completedTask = state.currentTask;
15313
15390
  if (!completedTask) {
15314
15391
  return null;
15315
15392
  }
15316
15393
  this.validateTransition(state, "done");
15394
+ const completedAt = getTimestamp();
15395
+ const historyEntry = this.createTaskHistoryEntry(completedTask, completedAt, feedback);
15396
+ const existingHistory = this.getTaskHistoryFromState(state);
15397
+ const taskHistory = [historyEntry, ...existingHistory].slice(0, this.maxTaskHistory);
15317
15398
  await this.update(projectId, () => ({
15318
15399
  currentTask: null,
15319
15400
  previousTask: null,
15320
- lastUpdated: getTimestamp()
15401
+ taskHistory,
15402
+ lastUpdated: completedAt
15321
15403
  }));
15322
15404
  await this.publishEvent(projectId, "task.completed", {
15323
15405
  taskId: completedTask.id,
15324
15406
  description: completedTask.description,
15325
15407
  startedAt: completedTask.startedAt,
15326
- completedAt: getTimestamp()
15408
+ completedAt
15327
15409
  });
15328
15410
  return completedTask;
15329
15411
  }
15412
+ /**
15413
+ * Create a TaskHistoryEntry from a completed task
15414
+ * Optionally includes structured feedback for the feedback loop (PRJ-272)
15415
+ */
15416
+ createTaskHistoryEntry(task, completedAt, feedback) {
15417
+ const taskAny = task;
15418
+ const subtaskSummaries = (task.subtasks || []).filter((st) => st.status === "completed" && st.summary).map((st) => st.summary);
15419
+ const outcome = subtaskSummaries.length > 0 ? subtaskSummaries.map((s) => s.title).join(", ") : "Task completed";
15420
+ const entry = {
15421
+ taskId: task.id,
15422
+ title: taskAny.parentDescription || task.description,
15423
+ classification: taskAny.type || "improvement",
15424
+ startedAt: task.startedAt,
15425
+ completedAt,
15426
+ subtaskCount: task.subtasks?.length || 0,
15427
+ subtaskSummaries,
15428
+ outcome,
15429
+ branchName: taskAny.branch || "unknown",
15430
+ linearId: task.linearId,
15431
+ linearUuid: task.linearUuid,
15432
+ prUrl: taskAny.prUrl
15433
+ };
15434
+ if (feedback) {
15435
+ entry.feedback = feedback;
15436
+ }
15437
+ return entry;
15438
+ }
15330
15439
  /** Max number of paused tasks (configurable) */
15331
15440
  maxPausedTasks = 5;
15441
+ /** Max number of task history entries (configurable) */
15442
+ maxTaskHistory = 20;
15332
15443
  /** Staleness threshold in days */
15333
15444
  stalenessThresholdDays = 30;
15334
15445
  /**
@@ -15417,6 +15528,13 @@ var init_state_storage = __esm({
15417
15528
  }
15418
15529
  return paused;
15419
15530
  }
15531
+ /**
15532
+ * Get task history from state with backward compatibility
15533
+ * Ensures taskHistory is always an array (never undefined)
15534
+ */
15535
+ getTaskHistoryFromState(state) {
15536
+ return state.taskHistory || [];
15537
+ }
15420
15538
  /**
15421
15539
  * Get stale paused tasks (older than threshold)
15422
15540
  */
@@ -15498,6 +15616,63 @@ var init_state_storage = __esm({
15498
15616
  const state = await this.read(projectId);
15499
15617
  return this.getPausedTasksFromState(state);
15500
15618
  }
15619
+ /**
15620
+ * Get full task history (completed tasks)
15621
+ */
15622
+ async getTaskHistory(projectId) {
15623
+ const state = await this.read(projectId);
15624
+ return this.getTaskHistoryFromState(state);
15625
+ }
15626
+ /**
15627
+ * Get most recent task from history
15628
+ */
15629
+ async getMostRecentTask(projectId) {
15630
+ const state = await this.read(projectId);
15631
+ const history2 = this.getTaskHistoryFromState(state);
15632
+ return history2[0] || null;
15633
+ }
15634
+ /**
15635
+ * Get task history filtered by classification
15636
+ */
15637
+ async getTaskHistoryByType(projectId, classification) {
15638
+ const state = await this.read(projectId);
15639
+ const history2 = this.getTaskHistoryFromState(state);
15640
+ return history2.filter((t) => t.classification === classification);
15641
+ }
15642
+ /**
15643
+ * Aggregate feedback from all task history entries (PRJ-272)
15644
+ * Used by sync to feed task discoveries back into analysis and agent generation.
15645
+ * Returns consolidated patterns, stack confirmations, issues, and agent accuracy.
15646
+ */
15647
+ async getAggregatedFeedback(projectId) {
15648
+ const history2 = await this.getTaskHistory(projectId);
15649
+ const entriesWithFeedback = history2.filter((h) => h.feedback);
15650
+ const stackConfirmed = [];
15651
+ const patternsDiscovered = [];
15652
+ const agentAccuracy = [];
15653
+ const allIssues = [];
15654
+ for (const entry of entriesWithFeedback) {
15655
+ const fb = entry.feedback;
15656
+ if (fb.stackConfirmed) stackConfirmed.push(...fb.stackConfirmed);
15657
+ if (fb.patternsDiscovered) patternsDiscovered.push(...fb.patternsDiscovered);
15658
+ if (fb.agentAccuracy) agentAccuracy.push(...fb.agentAccuracy);
15659
+ if (fb.issuesEncountered) allIssues.push(...fb.issuesEncountered);
15660
+ }
15661
+ const uniqueStack = [...new Set(stackConfirmed)];
15662
+ const uniquePatterns = [...new Set(patternsDiscovered)];
15663
+ const issueCounts = /* @__PURE__ */ new Map();
15664
+ for (const issue of allIssues) {
15665
+ issueCounts.set(issue, (issueCounts.get(issue) || 0) + 1);
15666
+ }
15667
+ const knownGotchas = [...issueCounts.entries()].filter(([_, count]) => count >= 2).map(([issue]) => issue);
15668
+ return {
15669
+ stackConfirmed: uniqueStack,
15670
+ patternsDiscovered: uniquePatterns,
15671
+ agentAccuracy,
15672
+ issuesEncountered: [...new Set(allIssues)],
15673
+ knownGotchas
15674
+ };
15675
+ }
15501
15676
  // =========== Subtask Methods ===========
15502
15677
  /**
15503
15678
  * Create subtasks when fragmenting a task
@@ -27970,6 +28145,8 @@ var init_sync_service = __esm({
27970
28145
  projectId = null;
27971
28146
  globalPath = "";
27972
28147
  cliVersion = "0.0.0";
28148
+ /** Task feedback context for agent generation (PRJ-272) */
28149
+ taskFeedbackContext;
27973
28150
  constructor() {
27974
28151
  this.projectPath = process.cwd();
27975
28152
  }
@@ -28094,7 +28271,17 @@ var init_sync_service = __esm({
28094
28271
  });
28095
28272
  }
28096
28273
  }
28097
- const agents = shouldRegenerateAgents ? await this.generateAgents(stack, stats) : await this.loadExistingAgents();
28274
+ let taskFeedbackContext;
28275
+ if (shouldRegenerateAgents) {
28276
+ try {
28277
+ const feedback = await stateStorage.getAggregatedFeedback(this.projectId);
28278
+ if (feedback.patternsDiscovered.length > 0 || feedback.knownGotchas.length > 0 || feedback.agentAccuracy.length > 0) {
28279
+ taskFeedbackContext = feedback;
28280
+ }
28281
+ } catch {
28282
+ }
28283
+ }
28284
+ const agents = shouldRegenerateAgents ? await this.generateAgents(stack, stats, taskFeedbackContext) : await this.loadExistingAgents();
28098
28285
  const skills = this.configureSkills(agents);
28099
28286
  const skillsInstalled = shouldRegenerateAgents ? await this.autoInstallSkills(agents) : [];
28100
28287
  const sources = this.buildSources(stats, commands);
@@ -28424,7 +28611,8 @@ var init_sync_service = __esm({
28424
28611
  // ==========================================================================
28425
28612
  // AGENT GENERATION
28426
28613
  // ==========================================================================
28427
- async generateAgents(stack, stats) {
28614
+ async generateAgents(stack, stats, feedbackContext) {
28615
+ this.taskFeedbackContext = feedbackContext;
28428
28616
  const agents = [];
28429
28617
  const agentsPath = path59.join(this.globalPath, "agents");
28430
28618
  try {
@@ -28565,8 +28753,45 @@ var init_sync_service = __esm({
28565
28753
  });
28566
28754
  content = this.generateMinimalDomainAgent(name, stats, stack);
28567
28755
  }
28756
+ content = this.injectFeedbackSection(content, name);
28568
28757
  await fs56.writeFile(path59.join(agentsPath, `${name}.md`), content, "utf-8");
28569
28758
  }
28759
+ /**
28760
+ * Inject a "Recent Learnings" section into agent content from task feedback (PRJ-272)
28761
+ */
28762
+ injectFeedbackSection(content, agentName) {
28763
+ if (!this.taskFeedbackContext) return content;
28764
+ const { patternsDiscovered, knownGotchas, agentAccuracy } = this.taskFeedbackContext;
28765
+ const agentNotes = agentAccuracy.filter(
28766
+ (a) => a.agent === `${agentName}.md` || a.agent === agentName
28767
+ );
28768
+ const hasContent = patternsDiscovered.length > 0 || knownGotchas.length > 0 || agentNotes.length > 0;
28769
+ if (!hasContent) return content;
28770
+ const lines = ["\n## Recent Learnings (from completed tasks)\n"];
28771
+ if (patternsDiscovered.length > 0) {
28772
+ lines.push("### Discovered Patterns");
28773
+ for (const pattern of patternsDiscovered) {
28774
+ lines.push(`- ${pattern}`);
28775
+ }
28776
+ lines.push("");
28777
+ }
28778
+ if (knownGotchas.length > 0) {
28779
+ lines.push("### Known Gotchas");
28780
+ for (const gotcha of knownGotchas) {
28781
+ lines.push(`- ${gotcha}`);
28782
+ }
28783
+ lines.push("");
28784
+ }
28785
+ if (agentNotes.length > 0) {
28786
+ lines.push("### Agent Accuracy Notes");
28787
+ for (const note of agentNotes) {
28788
+ const desc = note.note ? ` \u2014 ${note.note}` : "";
28789
+ lines.push(`- ${note.rating}${desc}`);
28790
+ }
28791
+ lines.push("");
28792
+ }
28793
+ return content + lines.join("\n");
28794
+ }
28570
28795
  generateMinimalWorkflowAgent(name) {
28571
28796
  const descriptions = {
28572
28797
  "prjct-workflow": "Task lifecycle: now, done, pause, resume",
@@ -28892,18 +29117,38 @@ You are the ${name} expert for this project. Apply best practices for the detect
28892
29117
  /**
28893
29118
  * Save sync results as a draft analysis.
28894
29119
  * Preserves existing sealed analysis — only the draft is overwritten.
29120
+ * Incorporates task feedback from completed tasks (PRJ-272).
28895
29121
  */
28896
29122
  async saveDraftAnalysis(git, stats, _stack) {
28897
29123
  try {
28898
29124
  const commitHash = git.recentCommits[0]?.hash || null;
29125
+ let patterns = [];
29126
+ let antiPatterns = [];
29127
+ try {
29128
+ const feedback = await stateStorage.getAggregatedFeedback(this.projectId);
29129
+ if (feedback.patternsDiscovered.length > 0) {
29130
+ patterns = feedback.patternsDiscovered.map((p) => ({
29131
+ name: p,
29132
+ description: `Discovered during task execution: ${p}`
29133
+ }));
29134
+ }
29135
+ if (feedback.knownGotchas.length > 0) {
29136
+ antiPatterns = feedback.knownGotchas.map((g) => ({
29137
+ issue: g,
29138
+ file: "multiple",
29139
+ suggestion: `Recurring issue reported across tasks: ${g}`
29140
+ }));
29141
+ }
29142
+ } catch {
29143
+ }
28899
29144
  await analysisStorage.saveDraft(this.projectId, {
28900
29145
  projectId: this.projectId,
28901
29146
  languages: stats.languages,
28902
29147
  frameworks: stats.frameworks,
28903
29148
  configFiles: [],
28904
29149
  fileCount: stats.fileCount,
28905
- patterns: [],
28906
- antiPatterns: [],
29150
+ patterns,
29151
+ antiPatterns,
28907
29152
  analyzedAt: getTimestamp(),
28908
29153
  status: "draft",
28909
29154
  commitHash: commitHash ?? void 0
@@ -34388,6 +34633,7 @@ var init_workflow = __esm({
34388
34633
  }
34389
34634
  /**
34390
34635
  * /p:done - Complete current task
34636
+ * Optionally accepts structured feedback for the task-to-analysis feedback loop (PRJ-272)
34391
34637
  */
34392
34638
  async done(projectPath = process.cwd(), options = {}) {
34393
34639
  try {
@@ -34443,7 +34689,7 @@ var init_workflow = __esm({
34443
34689
  const sign = diff >= 0 ? "+" : "";
34444
34690
  varianceDisplay = ` | est: ${estimatedPoints}pt (${formatMinutesToDuration(estimatedMinutes)}) \u2192 ${sign}${pct}%`;
34445
34691
  }
34446
- await stateStorage.completeTask(projectId);
34692
+ await stateStorage.completeTask(projectId, options.feedback);
34447
34693
  const linearId = currentTask.linearId;
34448
34694
  if (linearId) {
34449
34695
  try {
@@ -34890,7 +35136,7 @@ var require_package = __commonJS({
34890
35136
  "package.json"(exports, module) {
34891
35137
  module.exports = {
34892
35138
  name: "prjct-cli",
34893
- version: "1.21.0",
35139
+ version: "1.22.0",
34894
35140
  description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
34895
35141
  main: "core/index.ts",
34896
35142
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "1.21.0",
3
+ "version": "1.22.0",
4
4
  "description": "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
5
5
  "main": "core/index.ts",
6
6
  "bin": {