prjct-cli 1.12.0 → 1.14.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.
@@ -10383,6 +10383,76 @@ var init_state = __esm({
10383
10383
  }
10384
10384
  });
10385
10385
 
10386
+ // core/schemas/velocity.ts
10387
+ import { z as z15 } from "zod";
10388
+ var VelocityTrendSchema, SprintVelocitySchema, EstimationPatternSchema, CompletionProjectionSchema, VelocityMetricsSchema, VelocityConfigSchema, DEFAULT_VELOCITY_CONFIG, DEFAULT_VELOCITY_METRICS;
10389
+ var init_velocity = __esm({
10390
+ "core/schemas/velocity.ts"() {
10391
+ "use strict";
10392
+ VelocityTrendSchema = z15.enum(["improving", "stable", "declining"]);
10393
+ SprintVelocitySchema = z15.object({
10394
+ sprintNumber: z15.number(),
10395
+ startDate: z15.string(),
10396
+ // ISO8601
10397
+ endDate: z15.string(),
10398
+ // ISO8601
10399
+ pointsCompleted: z15.number(),
10400
+ tasksCompleted: z15.number(),
10401
+ avgVariance: z15.number(),
10402
+ // Average estimation variance (%)
10403
+ estimationAccuracy: z15.number()
10404
+ // % of tasks within tolerance
10405
+ });
10406
+ EstimationPatternSchema = z15.object({
10407
+ category: z15.string(),
10408
+ // task type or domain
10409
+ avgVariance: z15.number(),
10410
+ // positive = over, negative = under
10411
+ taskCount: z15.number()
10412
+ });
10413
+ CompletionProjectionSchema = z15.object({
10414
+ totalPoints: z15.number(),
10415
+ sprints: z15.number(),
10416
+ estimatedDate: z15.string()
10417
+ // ISO8601
10418
+ });
10419
+ VelocityMetricsSchema = z15.object({
10420
+ sprints: z15.array(SprintVelocitySchema),
10421
+ averageVelocity: z15.number(),
10422
+ velocityTrend: VelocityTrendSchema,
10423
+ estimationAccuracy: z15.number(),
10424
+ // 0-100%
10425
+ overEstimated: z15.array(EstimationPatternSchema),
10426
+ underEstimated: z15.array(EstimationPatternSchema),
10427
+ lastUpdated: z15.string()
10428
+ // ISO8601
10429
+ });
10430
+ VelocityConfigSchema = z15.object({
10431
+ sprintLengthDays: z15.number().min(1).max(90).default(7),
10432
+ startDay: z15.enum(["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]).default("monday"),
10433
+ windowSize: z15.number().min(1).max(52).default(6),
10434
+ // number of sprints for rolling average
10435
+ accuracyTolerance: z15.number().min(0).max(100).default(20)
10436
+ // ±% for "accurate" estimate
10437
+ });
10438
+ DEFAULT_VELOCITY_CONFIG = {
10439
+ sprintLengthDays: 7,
10440
+ startDay: "monday",
10441
+ windowSize: 6,
10442
+ accuracyTolerance: 20
10443
+ };
10444
+ DEFAULT_VELOCITY_METRICS = {
10445
+ sprints: [],
10446
+ averageVelocity: 0,
10447
+ velocityTrend: "stable",
10448
+ estimationAccuracy: 0,
10449
+ overEstimated: [],
10450
+ underEstimated: [],
10451
+ lastUpdated: ""
10452
+ };
10453
+ }
10454
+ });
10455
+
10386
10456
  // core/schemas/index.ts
10387
10457
  var init_schemas2 = __esm({
10388
10458
  "core/schemas/index.ts"() {
@@ -10401,6 +10471,7 @@ var init_schemas2 = __esm({
10401
10471
  init_schemas();
10402
10472
  init_shipped();
10403
10473
  init_state();
10474
+ init_velocity();
10404
10475
  }
10405
10476
  });
10406
10477
 
@@ -11374,6 +11445,457 @@ Context: ${context2}` : ""}`,
11374
11445
  }
11375
11446
  });
11376
11447
 
11448
+ // core/domain/velocity.ts
11449
+ function getSprintStart(date, config) {
11450
+ const resolved = resolveConfig(config);
11451
+ const startDayIdx = DAY_INDEX[resolved.startDay];
11452
+ const d = new Date(date);
11453
+ d.setHours(0, 0, 0, 0);
11454
+ const currentDay = d.getDay();
11455
+ const diff = (currentDay - startDayIdx + 7) % 7;
11456
+ d.setDate(d.getDate() - diff);
11457
+ return d;
11458
+ }
11459
+ function getSprintEnd(sprintStart, config) {
11460
+ const resolved = resolveConfig(config);
11461
+ const end = new Date(sprintStart);
11462
+ end.setDate(end.getDate() + resolved.sprintLengthDays - 1);
11463
+ end.setHours(23, 59, 59, 999);
11464
+ return end;
11465
+ }
11466
+ function getSprintNumber(date, earliestDate, config) {
11467
+ const resolved = resolveConfig(config);
11468
+ const sprintStart = getSprintStart(date, config);
11469
+ const firstSprintStart = getSprintStart(earliestDate, config);
11470
+ const diffMs = sprintStart.getTime() - firstSprintStart.getTime();
11471
+ const diffDays = Math.round(diffMs / (1e3 * 60 * 60 * 24));
11472
+ return Math.floor(diffDays / resolved.sprintLengthDays) + 1;
11473
+ }
11474
+ function calculateVelocity(outcomes, config = DEFAULT_VELOCITY_CONFIG) {
11475
+ const resolved = resolveConfig(config);
11476
+ if (outcomes.length === 0) {
11477
+ return {
11478
+ sprints: [],
11479
+ averageVelocity: 0,
11480
+ velocityTrend: "stable",
11481
+ estimationAccuracy: 0,
11482
+ overEstimated: [],
11483
+ underEstimated: [],
11484
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
11485
+ };
11486
+ }
11487
+ const sprintBuckets = bucketBySprint(outcomes, config);
11488
+ const sprints = buildSprintVelocities(sprintBuckets, resolved.accuracyTolerance);
11489
+ const windowSprints = sprints.slice(-resolved.windowSize);
11490
+ const averageVelocity = calculateAverageVelocity(windowSprints);
11491
+ const velocityTrend = detectTrend(windowSprints);
11492
+ const estimationAccuracy = calculateOverallAccuracy(outcomes, resolved.accuracyTolerance);
11493
+ const { overEstimated, underEstimated } = detectEstimationPatterns(outcomes);
11494
+ return {
11495
+ sprints,
11496
+ averageVelocity,
11497
+ velocityTrend,
11498
+ estimationAccuracy,
11499
+ overEstimated,
11500
+ underEstimated,
11501
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
11502
+ };
11503
+ }
11504
+ function projectCompletion(totalPoints, averageVelocity, config = DEFAULT_VELOCITY_CONFIG) {
11505
+ const resolved = resolveConfig(config);
11506
+ if (averageVelocity <= 0) {
11507
+ return {
11508
+ totalPoints,
11509
+ sprints: 0,
11510
+ estimatedDate: ""
11511
+ };
11512
+ }
11513
+ const sprints = Math.ceil(totalPoints / averageVelocity);
11514
+ const daysRemaining = sprints * resolved.sprintLengthDays;
11515
+ const estimatedDate = /* @__PURE__ */ new Date();
11516
+ estimatedDate.setDate(estimatedDate.getDate() + daysRemaining);
11517
+ return {
11518
+ totalPoints,
11519
+ sprints,
11520
+ estimatedDate: estimatedDate.toISOString()
11521
+ };
11522
+ }
11523
+ function bucketBySprint(outcomes, config) {
11524
+ const buckets = /* @__PURE__ */ new Map();
11525
+ const dates = outcomes.map((o) => new Date(o.completedAt));
11526
+ const earliest = new Date(Math.min(...dates.map((d) => d.getTime())));
11527
+ for (const outcome of outcomes) {
11528
+ const completedDate = new Date(outcome.completedAt);
11529
+ const sprintNum = getSprintNumber(completedDate, earliest, config);
11530
+ if (!buckets.has(sprintNum)) {
11531
+ const start = getSprintStart(completedDate, config);
11532
+ const end = getSprintEnd(start, config);
11533
+ buckets.set(sprintNum, {
11534
+ sprintNumber: sprintNum,
11535
+ startDate: start,
11536
+ endDate: end,
11537
+ outcomes: []
11538
+ });
11539
+ }
11540
+ buckets.get(sprintNum).outcomes.push(outcome);
11541
+ }
11542
+ return buckets;
11543
+ }
11544
+ function buildSprintVelocities(buckets, accuracyTolerance) {
11545
+ const sprints = [];
11546
+ for (const [, bucket] of buckets) {
11547
+ const points = bucket.outcomes.reduce((sum, o) => {
11548
+ return sum + derivePoints(o);
11549
+ }, 0);
11550
+ const variances = bucket.outcomes.filter((o) => o.variance).map((o) => parseVariancePercent(o));
11551
+ const avgVariance = variances.length > 0 ? Math.round(variances.reduce((a, b) => a + b, 0) / variances.length) : 0;
11552
+ const accurateCount = variances.filter((v) => Math.abs(v) <= accuracyTolerance).length;
11553
+ const estimationAccuracy = variances.length > 0 ? Math.round(accurateCount / variances.length * 100) : 0;
11554
+ sprints.push({
11555
+ sprintNumber: bucket.sprintNumber,
11556
+ startDate: bucket.startDate.toISOString(),
11557
+ endDate: bucket.endDate.toISOString(),
11558
+ pointsCompleted: points,
11559
+ tasksCompleted: bucket.outcomes.length,
11560
+ avgVariance,
11561
+ estimationAccuracy
11562
+ });
11563
+ }
11564
+ return sprints.sort((a, b) => a.sprintNumber - b.sprintNumber);
11565
+ }
11566
+ function detectTrend(sprints) {
11567
+ if (sprints.length < 3) return "stable";
11568
+ const points = sprints.map((s) => s.pointsCompleted);
11569
+ const n = points.length;
11570
+ let sumX = 0;
11571
+ let sumY = 0;
11572
+ let sumXY = 0;
11573
+ let sumX2 = 0;
11574
+ for (let i = 0; i < n; i++) {
11575
+ sumX += i;
11576
+ sumY += points[i];
11577
+ sumXY += i * points[i];
11578
+ sumX2 += i * i;
11579
+ }
11580
+ const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
11581
+ const avgVelocity = sumY / n;
11582
+ if (avgVelocity === 0) return "stable";
11583
+ const normalizedSlope = slope / avgVelocity;
11584
+ if (normalizedSlope > 0.1) return "improving";
11585
+ if (normalizedSlope < -0.1) return "declining";
11586
+ return "stable";
11587
+ }
11588
+ function calculateOverallAccuracy(outcomes, tolerance) {
11589
+ const withEstimates = outcomes.filter((o) => o.variance);
11590
+ if (withEstimates.length === 0) return 0;
11591
+ const accurate = withEstimates.filter((o) => {
11592
+ const variancePct = parseVariancePercent(o);
11593
+ return Math.abs(variancePct) <= tolerance;
11594
+ });
11595
+ return Math.round(accurate.length / withEstimates.length * 100);
11596
+ }
11597
+ function calculateAverageVelocity(sprints) {
11598
+ if (sprints.length === 0) return 0;
11599
+ const total = sprints.reduce((sum, s) => sum + s.pointsCompleted, 0);
11600
+ return Math.round(total / sprints.length * 10) / 10;
11601
+ }
11602
+ function detectEstimationPatterns(outcomes) {
11603
+ const byCategory = /* @__PURE__ */ new Map();
11604
+ for (const outcome of outcomes) {
11605
+ if (!outcome.variance) continue;
11606
+ const variancePct = parseVariancePercent(outcome);
11607
+ const categories = outcome.tags && outcome.tags.length > 0 ? outcome.tags : ["uncategorized"];
11608
+ for (const category of categories) {
11609
+ if (!byCategory.has(category)) {
11610
+ byCategory.set(category, { variances: [], count: 0 });
11611
+ }
11612
+ const entry = byCategory.get(category);
11613
+ entry.variances.push(variancePct);
11614
+ entry.count++;
11615
+ }
11616
+ }
11617
+ const overEstimated = [];
11618
+ const underEstimated = [];
11619
+ for (const [category, data] of byCategory) {
11620
+ if (data.count < 2) continue;
11621
+ const avg = Math.round(data.variances.reduce((a, b) => a + b, 0) / data.variances.length);
11622
+ if (avg > 10) {
11623
+ underEstimated.push({ category, avgVariance: avg, taskCount: data.count });
11624
+ } else if (avg < -10) {
11625
+ overEstimated.push({ category, avgVariance: Math.abs(avg), taskCount: data.count });
11626
+ }
11627
+ }
11628
+ overEstimated.sort((a, b) => b.avgVariance - a.avgVariance);
11629
+ underEstimated.sort((a, b) => b.avgVariance - a.avgVariance);
11630
+ return { overEstimated, underEstimated };
11631
+ }
11632
+ function parseVariancePercent(outcome) {
11633
+ if (!outcome.variance) return 0;
11634
+ const estimated = parseDurationMinutes(outcome.estimatedDuration);
11635
+ const actual = parseDurationMinutes(outcome.actualDuration);
11636
+ if (estimated <= 0) return 0;
11637
+ return Math.round((actual - estimated) / estimated * 100);
11638
+ }
11639
+ function parseDurationMinutes(duration) {
11640
+ let minutes = 0;
11641
+ const hourMatch = duration.match(/(\d+)h/);
11642
+ if (hourMatch) {
11643
+ minutes += Number.parseInt(hourMatch[1], 10) * 60;
11644
+ }
11645
+ const minMatch = duration.match(/(\d+)m/);
11646
+ if (minMatch) {
11647
+ minutes += Number.parseInt(minMatch[1], 10);
11648
+ }
11649
+ const secMatch = duration.match(/(\d+)s/);
11650
+ if (secMatch && minutes === 0) {
11651
+ minutes = 1;
11652
+ }
11653
+ return minutes;
11654
+ }
11655
+ function formatVelocityContext(metrics) {
11656
+ if (metrics.sprints.length === 0) {
11657
+ return "No velocity data available yet.";
11658
+ }
11659
+ const lines = [];
11660
+ lines.push(
11661
+ `Project velocity: ${metrics.averageVelocity} pts/sprint (trend: ${metrics.velocityTrend})`
11662
+ );
11663
+ lines.push(`Estimation accuracy: ${metrics.estimationAccuracy}%`);
11664
+ for (const pattern of metrics.underEstimated) {
11665
+ lines.push(
11666
+ `\u26A0 "${pattern.category}" tasks historically take ${pattern.avgVariance}% longer than estimated`
11667
+ );
11668
+ }
11669
+ for (const pattern of metrics.overEstimated) {
11670
+ lines.push(
11671
+ `"${pattern.category}" tasks typically finish ${pattern.avgVariance}% faster than estimated`
11672
+ );
11673
+ }
11674
+ return lines.join("\n");
11675
+ }
11676
+ function derivePoints(outcome) {
11677
+ if (!outcome.estimatedDuration) return 0;
11678
+ const minutes = parseDurationMinutes(outcome.estimatedDuration);
11679
+ if (minutes <= 0) return 0;
11680
+ let closest = FIBONACCI_MINUTES[0];
11681
+ let smallestDiff = Number.POSITIVE_INFINITY;
11682
+ for (const entry of FIBONACCI_MINUTES) {
11683
+ const diff = Math.abs(entry.typical - minutes);
11684
+ if (diff < smallestDiff) {
11685
+ smallestDiff = diff;
11686
+ closest = entry;
11687
+ }
11688
+ }
11689
+ return closest.points;
11690
+ }
11691
+ function resolveConfig(config) {
11692
+ return {
11693
+ sprintLengthDays: config.sprintLengthDays ?? 7,
11694
+ startDay: config.startDay ?? "monday",
11695
+ windowSize: config.windowSize ?? 6,
11696
+ accuracyTolerance: config.accuracyTolerance ?? 20
11697
+ };
11698
+ }
11699
+ var DAY_INDEX, FIBONACCI_MINUTES;
11700
+ var init_velocity2 = __esm({
11701
+ "core/domain/velocity.ts"() {
11702
+ "use strict";
11703
+ init_velocity();
11704
+ DAY_INDEX = {
11705
+ sunday: 0,
11706
+ monday: 1,
11707
+ tuesday: 2,
11708
+ wednesday: 3,
11709
+ thursday: 4,
11710
+ friday: 5,
11711
+ saturday: 6
11712
+ };
11713
+ __name(getSprintStart, "getSprintStart");
11714
+ __name(getSprintEnd, "getSprintEnd");
11715
+ __name(getSprintNumber, "getSprintNumber");
11716
+ __name(calculateVelocity, "calculateVelocity");
11717
+ __name(projectCompletion, "projectCompletion");
11718
+ __name(bucketBySprint, "bucketBySprint");
11719
+ __name(buildSprintVelocities, "buildSprintVelocities");
11720
+ __name(detectTrend, "detectTrend");
11721
+ __name(calculateOverallAccuracy, "calculateOverallAccuracy");
11722
+ __name(calculateAverageVelocity, "calculateAverageVelocity");
11723
+ __name(detectEstimationPatterns, "detectEstimationPatterns");
11724
+ __name(parseVariancePercent, "parseVariancePercent");
11725
+ __name(parseDurationMinutes, "parseDurationMinutes");
11726
+ __name(formatVelocityContext, "formatVelocityContext");
11727
+ FIBONACCI_MINUTES = [
11728
+ { points: 1, typical: 10 },
11729
+ { points: 2, typical: 20 },
11730
+ { points: 3, typical: 45 },
11731
+ { points: 5, typical: 90 },
11732
+ { points: 8, typical: 180 },
11733
+ { points: 13, typical: 360 },
11734
+ { points: 21, typical: 720 }
11735
+ ];
11736
+ __name(derivePoints, "derivePoints");
11737
+ __name(resolveConfig, "resolveConfig");
11738
+ }
11739
+ });
11740
+
11741
+ // core/outcomes/recorder.ts
11742
+ import path24 from "node:path";
11743
+ var OUTCOMES_DIR, OUTCOMES_FILE, OutcomeRecorder, outcomeRecorder, recorder_default;
11744
+ var init_recorder = __esm({
11745
+ "core/outcomes/recorder.ts"() {
11746
+ "use strict";
11747
+ init_path_manager();
11748
+ init_schemas2();
11749
+ init_file_helper();
11750
+ OUTCOMES_DIR = "outcomes";
11751
+ OUTCOMES_FILE = "outcomes.jsonl";
11752
+ OutcomeRecorder = class {
11753
+ static {
11754
+ __name(this, "OutcomeRecorder");
11755
+ }
11756
+ /**
11757
+ * Get outcomes directory path for a project.
11758
+ */
11759
+ getOutcomesDir(projectId) {
11760
+ const globalPath = path_manager_default.getGlobalProjectPath(projectId);
11761
+ return path24.join(globalPath, OUTCOMES_DIR);
11762
+ }
11763
+ /**
11764
+ * Get outcomes file path for a project.
11765
+ */
11766
+ getOutcomesPath(projectId) {
11767
+ return path24.join(this.getOutcomesDir(projectId), OUTCOMES_FILE);
11768
+ }
11769
+ /**
11770
+ * Record an outcome.
11771
+ */
11772
+ async record(projectId, input) {
11773
+ const outcome = {
11774
+ ...input,
11775
+ id: generateUUID()
11776
+ };
11777
+ const outcomesPath = this.getOutcomesPath(projectId);
11778
+ await ensureDir(path24.dirname(outcomesPath));
11779
+ await appendLine(outcomesPath, JSON.stringify(outcome));
11780
+ return outcome;
11781
+ }
11782
+ /**
11783
+ * Get all outcomes for a project.
11784
+ */
11785
+ async getAll(projectId) {
11786
+ const outcomesPath = this.getOutcomesPath(projectId);
11787
+ if (!await fileExists2(outcomesPath)) {
11788
+ return [];
11789
+ }
11790
+ const content = await readFile(outcomesPath);
11791
+ if (!content.trim()) {
11792
+ return [];
11793
+ }
11794
+ return content.trim().split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
11795
+ }
11796
+ /**
11797
+ * Get outcomes matching a filter.
11798
+ */
11799
+ async filter(projectId, filter) {
11800
+ const all = await this.getAll(projectId);
11801
+ return all.filter((outcome) => {
11802
+ if (filter.sessionId && outcome.sessionId !== filter.sessionId) {
11803
+ return false;
11804
+ }
11805
+ if (filter.command && outcome.command !== filter.command) {
11806
+ return false;
11807
+ }
11808
+ if (filter.agent && outcome.agentUsed !== filter.agent) {
11809
+ return false;
11810
+ }
11811
+ if (filter.fromDate && outcome.startedAt < filter.fromDate) {
11812
+ return false;
11813
+ }
11814
+ if (filter.toDate && outcome.completedAt > filter.toDate) {
11815
+ return false;
11816
+ }
11817
+ if (filter.minQuality && outcome.qualityScore < filter.minQuality) {
11818
+ return false;
11819
+ }
11820
+ if (filter.tags && filter.tags.length > 0) {
11821
+ const outcomeTags = outcome.tags || [];
11822
+ if (!filter.tags.some((tag) => outcomeTags.includes(tag))) {
11823
+ return false;
11824
+ }
11825
+ }
11826
+ return true;
11827
+ });
11828
+ }
11829
+ /**
11830
+ * Get recent outcomes (last N).
11831
+ */
11832
+ async getRecent(projectId, count = 10) {
11833
+ const all = await this.getAll(projectId);
11834
+ return all.slice(-count);
11835
+ }
11836
+ /**
11837
+ * Get outcomes for a specific command.
11838
+ */
11839
+ async getByCommand(projectId, command) {
11840
+ return this.filter(projectId, { command });
11841
+ }
11842
+ /**
11843
+ * Get outcomes for a specific agent.
11844
+ */
11845
+ async getByAgent(projectId, agent) {
11846
+ return this.filter(projectId, { agent });
11847
+ }
11848
+ /**
11849
+ * Calculate estimate accuracy.
11850
+ */
11851
+ async getEstimateAccuracy(projectId) {
11852
+ const outcomes = await this.getAll(projectId);
11853
+ if (outcomes.length === 0) {
11854
+ return 0;
11855
+ }
11856
+ const accurate = outcomes.filter((o) => {
11857
+ if (!o.variance) return false;
11858
+ const variance = this.parseVariance(o.variance);
11859
+ const estimated = this.parseDuration(o.estimatedDuration);
11860
+ if (estimated === 0) return false;
11861
+ return Math.abs(variance) / estimated <= 0.2;
11862
+ });
11863
+ return Math.round(accurate.length / outcomes.length * 100);
11864
+ }
11865
+ /**
11866
+ * Parse variance string to minutes.
11867
+ * "+30m" → 30, "-15m" → -15
11868
+ */
11869
+ parseVariance(variance) {
11870
+ const match = variance.match(/^([+-])(\d+)([mh])$/);
11871
+ if (!match) return 0;
11872
+ const sign = match[1] === "-" ? -1 : 1;
11873
+ const value = parseInt(match[2], 10);
11874
+ const unit = match[3];
11875
+ return sign * (unit === "h" ? value * 60 : value);
11876
+ }
11877
+ /**
11878
+ * Parse duration string to minutes.
11879
+ * "2h" → 120, "30m" → 30, "1h 30m" → 90
11880
+ */
11881
+ parseDuration(duration) {
11882
+ let minutes = 0;
11883
+ const hourMatch = duration.match(/(\d+)h/);
11884
+ if (hourMatch) {
11885
+ minutes += parseInt(hourMatch[1], 10) * 60;
11886
+ }
11887
+ const minMatch = duration.match(/(\d+)m/);
11888
+ if (minMatch) {
11889
+ minutes += parseInt(minMatch[1], 10);
11890
+ }
11891
+ return minutes;
11892
+ }
11893
+ };
11894
+ outcomeRecorder = new OutcomeRecorder();
11895
+ recorder_default = outcomeRecorder;
11896
+ }
11897
+ });
11898
+
11377
11899
  // core/storage/analysis-storage.ts
11378
11900
  import { createHash } from "node:crypto";
11379
11901
  var AnalysisStorage, analysisStorage;
@@ -11826,7 +12348,7 @@ var init_ideas_storage = __esm({
11826
12348
  // core/storage/index-storage.ts
11827
12349
  import crypto4 from "node:crypto";
11828
12350
  import fs26 from "node:fs/promises";
11829
- import path24 from "node:path";
12351
+ import path25 from "node:path";
11830
12352
  function getDefaultChecksums() {
11831
12353
  return {
11832
12354
  version: INDEX_VERSION,
@@ -11851,7 +12373,7 @@ var init_index_storage = __esm({
11851
12373
  * Get the index directory path for a project
11852
12374
  */
11853
12375
  getIndexPath(projectId) {
11854
- return path24.join(path_manager_default.getGlobalProjectPath(projectId), "index");
12376
+ return path25.join(path_manager_default.getGlobalProjectPath(projectId), "index");
11855
12377
  }
11856
12378
  /**
11857
12379
  * Ensure index directory exists
@@ -11868,7 +12390,7 @@ var init_index_storage = __esm({
11868
12390
  * Read the project index
11869
12391
  */
11870
12392
  async readIndex(projectId) {
11871
- const filePath = path24.join(this.getIndexPath(projectId), "project-index.json");
12393
+ const filePath = path25.join(this.getIndexPath(projectId), "project-index.json");
11872
12394
  try {
11873
12395
  const content = await fs26.readFile(filePath, "utf-8");
11874
12396
  const index = JSON.parse(content);
@@ -11888,7 +12410,7 @@ var init_index_storage = __esm({
11888
12410
  */
11889
12411
  async writeIndex(projectId, index) {
11890
12412
  await this.ensureIndexDir(projectId);
11891
- const filePath = path24.join(this.getIndexPath(projectId), "project-index.json");
12413
+ const filePath = path25.join(this.getIndexPath(projectId), "project-index.json");
11892
12414
  await fs26.writeFile(filePath, JSON.stringify(index, null, 2), "utf-8");
11893
12415
  }
11894
12416
  /**
@@ -11905,7 +12427,7 @@ var init_index_storage = __esm({
11905
12427
  * Read file checksums
11906
12428
  */
11907
12429
  async readChecksums(projectId) {
11908
- const filePath = path24.join(this.getIndexPath(projectId), "checksums.json");
12430
+ const filePath = path25.join(this.getIndexPath(projectId), "checksums.json");
11909
12431
  try {
11910
12432
  const content = await fs26.readFile(filePath, "utf-8");
11911
12433
  return JSON.parse(content);
@@ -11921,7 +12443,7 @@ var init_index_storage = __esm({
11921
12443
  */
11922
12444
  async writeChecksums(projectId, checksums) {
11923
12445
  await this.ensureIndexDir(projectId);
11924
- const filePath = path24.join(this.getIndexPath(projectId), "checksums.json");
12446
+ const filePath = path25.join(this.getIndexPath(projectId), "checksums.json");
11925
12447
  await fs26.writeFile(filePath, JSON.stringify(checksums, null, 2), "utf-8");
11926
12448
  }
11927
12449
  /**
@@ -11965,7 +12487,7 @@ var init_index_storage = __esm({
11965
12487
  * Read file scores
11966
12488
  */
11967
12489
  async readScores(projectId) {
11968
- const filePath = path24.join(this.getIndexPath(projectId), "file-scores.json");
12490
+ const filePath = path25.join(this.getIndexPath(projectId), "file-scores.json");
11969
12491
  try {
11970
12492
  const content = await fs26.readFile(filePath, "utf-8");
11971
12493
  const data = JSON.parse(content);
@@ -11982,7 +12504,7 @@ var init_index_storage = __esm({
11982
12504
  */
11983
12505
  async writeScores(projectId, scores) {
11984
12506
  await this.ensureIndexDir(projectId);
11985
- const filePath = path24.join(this.getIndexPath(projectId), "file-scores.json");
12507
+ const filePath = path25.join(this.getIndexPath(projectId), "file-scores.json");
11986
12508
  const data = {
11987
12509
  version: INDEX_VERSION,
11988
12510
  lastUpdated: getTimestamp(),
@@ -12000,7 +12522,7 @@ var init_index_storage = __esm({
12000
12522
  const indexPath = this.getIndexPath(projectId);
12001
12523
  try {
12002
12524
  const files = await fs26.readdir(indexPath);
12003
- await Promise.all(files.map((file) => fs26.unlink(path24.join(indexPath, file))));
12525
+ await Promise.all(files.map((file) => fs26.unlink(path25.join(indexPath, file))));
12004
12526
  } catch (error) {
12005
12527
  if (!isNotFoundError(error)) {
12006
12528
  throw error;
@@ -12026,7 +12548,7 @@ var init_index_storage = __esm({
12026
12548
  * Read discovered domains for a project
12027
12549
  */
12028
12550
  async readDomains(projectId) {
12029
- const filePath = path24.join(this.getIndexPath(projectId), "domains.json");
12551
+ const filePath = path25.join(this.getIndexPath(projectId), "domains.json");
12030
12552
  try {
12031
12553
  const content = await fs26.readFile(filePath, "utf-8");
12032
12554
  const domains = JSON.parse(content);
@@ -12046,7 +12568,7 @@ var init_index_storage = __esm({
12046
12568
  */
12047
12569
  async writeDomains(projectId, domains) {
12048
12570
  await this.ensureIndexDir(projectId);
12049
- const filePath = path24.join(this.getIndexPath(projectId), "domains.json");
12571
+ const filePath = path25.join(this.getIndexPath(projectId), "domains.json");
12050
12572
  await fs26.writeFile(filePath, JSON.stringify(domains, null, 2), "utf-8");
12051
12573
  }
12052
12574
  // ==========================================================================
@@ -12056,7 +12578,7 @@ var init_index_storage = __esm({
12056
12578
  * Read categories cache
12057
12579
  */
12058
12580
  async readCategories(projectId) {
12059
- const filePath = path24.join(this.getIndexPath(projectId), "categories-cache.json");
12581
+ const filePath = path25.join(this.getIndexPath(projectId), "categories-cache.json");
12060
12582
  try {
12061
12583
  const content = await fs26.readFile(filePath, "utf-8");
12062
12584
  const cache2 = JSON.parse(content);
@@ -12076,7 +12598,7 @@ var init_index_storage = __esm({
12076
12598
  */
12077
12599
  async writeCategories(projectId, cache2) {
12078
12600
  await this.ensureIndexDir(projectId);
12079
- const filePath = path24.join(this.getIndexPath(projectId), "categories-cache.json");
12601
+ const filePath = path25.join(this.getIndexPath(projectId), "categories-cache.json");
12080
12602
  await fs26.writeFile(filePath, JSON.stringify(cache2, null, 2), "utf-8");
12081
12603
  }
12082
12604
  /**
@@ -13542,7 +14064,7 @@ ${errors.join("\n")}`);
13542
14064
  // core/storage/storage.ts
13543
14065
  import fs27 from "node:fs/promises";
13544
14066
  import os8 from "node:os";
13545
- import path25 from "node:path";
14067
+ import path26 from "node:path";
13546
14068
  function getStorage(projectId) {
13547
14069
  return new FileStorage(projectId);
13548
14070
  }
@@ -13560,7 +14082,7 @@ var init_storage = __esm({
13560
14082
  basePath;
13561
14083
  constructor(projectId) {
13562
14084
  this.projectId = projectId;
13563
- this.basePath = path25.join(os8.homedir(), ".prjct-cli/projects", projectId, "data");
14085
+ this.basePath = path26.join(os8.homedir(), ".prjct-cli/projects", projectId, "data");
13564
14086
  }
13565
14087
  /**
13566
14088
  * Convert path array to file path
@@ -13569,16 +14091,16 @@ var init_storage = __esm({
13569
14091
  */
13570
14092
  pathToFile(pathArray) {
13571
14093
  if (pathArray.length === 1) {
13572
- return path25.join(this.basePath, `${pathArray[0]}.json`);
14094
+ return path26.join(this.basePath, `${pathArray[0]}.json`);
13573
14095
  }
13574
14096
  const dir = `${pathArray[0]}s`;
13575
14097
  const rest = pathArray.slice(1);
13576
14098
  const filename = `${rest.join("/")}.json`;
13577
- return path25.join(this.basePath, dir, filename);
14099
+ return path26.join(this.basePath, dir, filename);
13578
14100
  }
13579
14101
  async write(pathArray, data) {
13580
14102
  const filePath = this.pathToFile(pathArray);
13581
- await fs27.mkdir(path25.dirname(filePath), { recursive: true });
14103
+ await fs27.mkdir(path26.dirname(filePath), { recursive: true });
13582
14104
  await fs27.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
13583
14105
  eventBus.publish({
13584
14106
  type: inferEventType(pathArray, "write"),
@@ -13604,7 +14126,7 @@ var init_storage = __esm({
13604
14126
  }
13605
14127
  }
13606
14128
  async list(prefix) {
13607
- const dir = path25.join(this.basePath, `${prefix[0]}s`);
14129
+ const dir = path26.join(this.basePath, `${prefix[0]}s`);
13608
14130
  try {
13609
14131
  const files = await fs27.readdir(dir);
13610
14132
  return files.filter((f) => f.endsWith(".json") && f !== "index.json").map((f) => [...prefix, f.replace(".json", "")]);
@@ -13651,7 +14173,7 @@ var init_storage = __esm({
13651
14173
  * Update collection index
13652
14174
  */
13653
14175
  async updateIndex(collection, id, action) {
13654
- const indexPath = path25.join(this.basePath, `${collection}s`, "index.json");
14176
+ const indexPath = path26.join(this.basePath, `${collection}s`, "index.json");
13655
14177
  let index = { ids: [], updatedAt: "" };
13656
14178
  try {
13657
14179
  const content = await fs27.readFile(indexPath, "utf-8");
@@ -13667,7 +14189,7 @@ var init_storage = __esm({
13667
14189
  index.ids = index.ids.filter((i) => i !== id);
13668
14190
  }
13669
14191
  index.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
13670
- await fs27.mkdir(path25.dirname(indexPath), { recursive: true });
14192
+ await fs27.mkdir(path26.dirname(indexPath), { recursive: true });
13671
14193
  await fs27.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
13672
14194
  }
13673
14195
  };
@@ -13675,6 +14197,115 @@ var init_storage = __esm({
13675
14197
  }
13676
14198
  });
13677
14199
 
14200
+ // core/storage/velocity-storage.ts
14201
+ function formatTrendIcon(trend) {
14202
+ switch (trend) {
14203
+ case "improving":
14204
+ return "\u2191";
14205
+ case "declining":
14206
+ return "\u2193";
14207
+ default:
14208
+ return "\u2192";
14209
+ }
14210
+ }
14211
+ var VelocityStorage, velocityStorage;
14212
+ var init_velocity_storage = __esm({
14213
+ "core/storage/velocity-storage.ts"() {
14214
+ "use strict";
14215
+ init_velocity();
14216
+ init_storage_manager();
14217
+ VelocityStorage = class extends StorageManager {
14218
+ static {
14219
+ __name(this, "VelocityStorage");
14220
+ }
14221
+ constructor() {
14222
+ super("velocity.json");
14223
+ }
14224
+ getDefault() {
14225
+ return {
14226
+ metrics: DEFAULT_VELOCITY_METRICS,
14227
+ lastUpdated: ""
14228
+ };
14229
+ }
14230
+ getMdFilename() {
14231
+ return "velocity.md";
14232
+ }
14233
+ getLayer() {
14234
+ return "progress";
14235
+ }
14236
+ getEventType(action) {
14237
+ return `velocity.${action}d`;
14238
+ }
14239
+ toMarkdown(data) {
14240
+ const { metrics } = data;
14241
+ const lines = ["# Velocity", ""];
14242
+ if (metrics.sprints.length === 0) {
14243
+ lines.push("_No velocity data yet. Complete tasks with estimates to build velocity history._");
14244
+ lines.push("");
14245
+ return lines.join("\n");
14246
+ }
14247
+ lines.push(`**Average**: ${metrics.averageVelocity} pts/sprint`);
14248
+ lines.push(`**Trend**: ${formatTrendIcon(metrics.velocityTrend)} ${metrics.velocityTrend}`);
14249
+ lines.push(`**Estimation Accuracy**: ${metrics.estimationAccuracy}%`);
14250
+ lines.push("");
14251
+ lines.push("## Sprint History");
14252
+ lines.push("");
14253
+ lines.push("| Sprint | Points | Tasks | Accuracy | Variance |");
14254
+ lines.push("|--------|--------|-------|----------|----------|");
14255
+ const recentSprints = metrics.sprints.slice(-6);
14256
+ for (const sprint of recentSprints) {
14257
+ lines.push(
14258
+ `| ${sprint.sprintNumber} | ${sprint.pointsCompleted} | ${sprint.tasksCompleted} | ${sprint.estimationAccuracy}% | ${sprint.avgVariance > 0 ? "+" : ""}${sprint.avgVariance}% |`
14259
+ );
14260
+ }
14261
+ lines.push("");
14262
+ if (metrics.underEstimated.length > 0 || metrics.overEstimated.length > 0) {
14263
+ lines.push("## Estimation Patterns");
14264
+ lines.push("");
14265
+ for (const p of metrics.underEstimated) {
14266
+ lines.push(
14267
+ `- \u26A0 **${p.category}**: underestimated by avg ${p.avgVariance}% (${p.taskCount} tasks)`
14268
+ );
14269
+ }
14270
+ for (const p of metrics.overEstimated) {
14271
+ lines.push(
14272
+ `- \u2713 **${p.category}**: overestimated by avg ${p.avgVariance}% (${p.taskCount} tasks)`
14273
+ );
14274
+ }
14275
+ lines.push("");
14276
+ }
14277
+ return lines.join("\n");
14278
+ }
14279
+ // ===========================================================================
14280
+ // Domain Methods
14281
+ // ===========================================================================
14282
+ /**
14283
+ * Save computed velocity metrics.
14284
+ */
14285
+ async saveMetrics(projectId, metrics) {
14286
+ await this.write(projectId, {
14287
+ metrics,
14288
+ lastUpdated: metrics.lastUpdated
14289
+ });
14290
+ await this.publishEntityEvent(projectId, "velocity", "updated", {
14291
+ averageVelocity: metrics.averageVelocity,
14292
+ trend: metrics.velocityTrend,
14293
+ sprintCount: metrics.sprints.length
14294
+ });
14295
+ }
14296
+ /**
14297
+ * Get current velocity metrics.
14298
+ */
14299
+ async getMetrics(projectId) {
14300
+ const data = await this.read(projectId);
14301
+ return data.metrics;
14302
+ }
14303
+ };
14304
+ __name(formatTrendIcon, "formatTrendIcon");
14305
+ velocityStorage = new VelocityStorage();
14306
+ }
14307
+ });
14308
+
13678
14309
  // core/storage/index.ts
13679
14310
  var init_storage2 = __esm({
13680
14311
  "core/storage/index.ts"() {
@@ -13688,19 +14319,20 @@ var init_storage2 = __esm({
13688
14319
  init_state_storage();
13689
14320
  init_storage();
13690
14321
  init_storage_manager();
14322
+ init_velocity_storage();
13691
14323
  }
13692
14324
  });
13693
14325
 
13694
14326
  // core/agentic/domain-classifier.ts
13695
14327
  import { createHash as createHash2 } from "node:crypto";
13696
14328
  import fs28 from "node:fs/promises";
13697
- import path26 from "node:path";
14329
+ import path27 from "node:path";
13698
14330
  function hashDescription(description) {
13699
14331
  return createHash2("sha256").update(description.toLowerCase().trim()).digest("hex").slice(0, 16);
13700
14332
  }
13701
14333
  async function loadCache(globalPath) {
13702
14334
  try {
13703
- const cachePath = path26.join(globalPath, "storage", "classification-cache.json");
14335
+ const cachePath = path27.join(globalPath, "storage", "classification-cache.json");
13704
14336
  const content = await fs28.readFile(cachePath, "utf-8");
13705
14337
  return JSON.parse(content);
13706
14338
  } catch (error) {
@@ -13711,7 +14343,7 @@ async function loadCache(globalPath) {
13711
14343
  }
13712
14344
  async function saveCache(globalPath, cache2) {
13713
14345
  try {
13714
- const cachePath = path26.join(globalPath, "storage", "classification-cache.json");
14346
+ const cachePath = path27.join(globalPath, "storage", "classification-cache.json");
13715
14347
  await fs28.writeFile(cachePath, JSON.stringify(cache2, null, 2));
13716
14348
  } catch (error) {
13717
14349
  console.warn("[classifier] Failed to save cache:", getErrorMessage2(error));
@@ -14085,7 +14717,7 @@ var init_domain_classifier = __esm({
14085
14717
 
14086
14718
  // core/agentic/template-loader.ts
14087
14719
  import fs29 from "node:fs/promises";
14088
- import path27 from "node:path";
14720
+ import path28 from "node:path";
14089
14721
  function updateLruOrder(key) {
14090
14722
  const index = cacheOrder.indexOf(key);
14091
14723
  if (index > -1) cacheOrder.splice(index, 1);
@@ -14123,7 +14755,7 @@ async function load(commandName) {
14123
14755
  updateLruOrder(commandName);
14124
14756
  return cache.get(commandName);
14125
14757
  }
14126
- const templatePath = path27.join(TEMPLATES_DIR, `${commandName}.md`);
14758
+ const templatePath = path28.join(TEMPLATES_DIR, `${commandName}.md`);
14127
14759
  try {
14128
14760
  const rawContent = await fs29.readFile(templatePath, "utf-8");
14129
14761
  const parsed = parseFrontmatter(rawContent);
@@ -14148,7 +14780,7 @@ var init_template_loader = __esm({
14148
14780
  "core/agentic/template-loader.ts"() {
14149
14781
  "use strict";
14150
14782
  init_errors();
14151
- TEMPLATES_DIR = path27.join(__dirname, "..", "..", "templates", "commands");
14783
+ TEMPLATES_DIR = path28.join(__dirname, "..", "..", "templates", "commands");
14152
14784
  MAX_CACHE_SIZE = 50;
14153
14785
  cache = /* @__PURE__ */ new Map();
14154
14786
  cacheOrder = [];
@@ -14167,7 +14799,7 @@ var init_template_loader = __esm({
14167
14799
  import { exec as execCallback5 } from "node:child_process";
14168
14800
  import fs30 from "node:fs/promises";
14169
14801
  import os9 from "node:os";
14170
- import path28 from "node:path";
14802
+ import path29 from "node:path";
14171
14803
  import { promisify as promisify7 } from "node:util";
14172
14804
  var execAsync3, DOMAIN_DEPENDENCY_ORDER, OrchestratorExecutor, orchestratorExecutor, orchestrator_executor_default;
14173
14805
  var init_orchestrator_executor = __esm({
@@ -14176,8 +14808,11 @@ var init_orchestrator_executor = __esm({
14176
14808
  init_files_tool();
14177
14809
  init_recent_tool();
14178
14810
  init_signatures_tool();
14811
+ init_velocity2();
14179
14812
  init_config_manager();
14180
14813
  init_path_manager();
14814
+ init_recorder();
14815
+ init_velocity();
14181
14816
  init_storage2();
14182
14817
  init_fs();
14183
14818
  init_domain_classifier();
@@ -14203,7 +14838,11 @@ var init_orchestrator_executor = __esm({
14203
14838
  const { domains, primary } = await this.detectDomains(taskDescription, projectId, repoAnalysis);
14204
14839
  const agents = await this.loadAgents(domains, projectId);
14205
14840
  const skills = await this.loadSkills(agents);
14206
- const realContext = await this.gatherRealContext(taskDescription, projectPath);
14841
+ const [realContext, sealedAnalysis, velocityContext] = await Promise.all([
14842
+ this.gatherRealContext(taskDescription, projectPath),
14843
+ this.loadSealedAnalysis(projectId),
14844
+ this.loadVelocityContext(projectId)
14845
+ ]);
14207
14846
  const requiresFragmentation = this.shouldFragment(domains, taskDescription);
14208
14847
  let subtasks = null;
14209
14848
  if (requiresFragmentation && command === "task") {
@@ -14221,7 +14860,9 @@ var init_orchestrator_executor = __esm({
14221
14860
  ecosystem: repoAnalysis?.ecosystem || "unknown",
14222
14861
  conventions: repoAnalysis?.conventions || []
14223
14862
  },
14224
- realContext
14863
+ realContext,
14864
+ sealedAnalysis,
14865
+ velocityContext
14225
14866
  };
14226
14867
  }
14227
14868
  /**
@@ -14301,12 +14942,52 @@ var init_orchestrator_executor = __esm({
14301
14942
  return { branch: "unknown", status: "git unavailable" };
14302
14943
  }
14303
14944
  }
14945
+ /**
14946
+ * Load sealed/active analysis from analysis storage (PRJ-260).
14947
+ * Returns sealed if available, otherwise draft as fallback.
14948
+ * Returns null if no analysis exists (graceful degradation).
14949
+ */
14950
+ async loadSealedAnalysis(projectId) {
14951
+ try {
14952
+ const analysis2 = await analysisStorage.getActive(projectId);
14953
+ if (!analysis2) return null;
14954
+ return {
14955
+ languages: analysis2.languages,
14956
+ frameworks: analysis2.frameworks,
14957
+ packageManager: analysis2.packageManager,
14958
+ sourceDir: analysis2.sourceDir,
14959
+ testDir: analysis2.testDir,
14960
+ fileCount: analysis2.fileCount,
14961
+ patterns: analysis2.patterns,
14962
+ antiPatterns: analysis2.antiPatterns,
14963
+ status: analysis2.status ?? "draft",
14964
+ commitHash: analysis2.commitHash
14965
+ };
14966
+ } catch {
14967
+ return null;
14968
+ }
14969
+ }
14970
+ /**
14971
+ * Load velocity context for estimation guidance (PRJ-296).
14972
+ * Returns formatted string for prompt injection, or null if no data.
14973
+ */
14974
+ async loadVelocityContext(projectId) {
14975
+ try {
14976
+ const outcomes = await recorder_default.getAll(projectId);
14977
+ if (outcomes.length === 0) return null;
14978
+ const metrics = calculateVelocity(outcomes, DEFAULT_VELOCITY_CONFIG);
14979
+ if (metrics.sprints.length === 0) return null;
14980
+ return formatVelocityContext(metrics);
14981
+ } catch {
14982
+ return null;
14983
+ }
14984
+ }
14304
14985
  /**
14305
14986
  * Load repo-analysis.json for project context
14306
14987
  */
14307
14988
  async loadRepoAnalysis(globalPath) {
14308
14989
  try {
14309
- const analysisPath = path28.join(globalPath, "analysis", "repo-analysis.json");
14990
+ const analysisPath = path29.join(globalPath, "analysis", "repo-analysis.json");
14310
14991
  const content = await fs30.readFile(analysisPath, "utf-8");
14311
14992
  return JSON.parse(content);
14312
14993
  } catch (error) {
@@ -14332,7 +15013,7 @@ var init_orchestrator_executor = __esm({
14332
15013
  hasDocker: false
14333
15014
  };
14334
15015
  try {
14335
- const statePath = path28.join(globalPath, "storage", "state.json");
15016
+ const statePath = path29.join(globalPath, "storage", "state.json");
14336
15017
  const stateContent = await fs30.readFile(statePath, "utf-8");
14337
15018
  const state = JSON.parse(stateContent);
14338
15019
  if (state.domains) {
@@ -14367,7 +15048,7 @@ var init_orchestrator_executor = __esm({
14367
15048
  */
14368
15049
  async getAvailableAgentNames(globalPath) {
14369
15050
  try {
14370
- const agentsDir = path28.join(globalPath, "agents");
15051
+ const agentsDir = path29.join(globalPath, "agents");
14371
15052
  const files = await fs30.readdir(agentsDir);
14372
15053
  return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
14373
15054
  } catch {
@@ -14384,11 +15065,11 @@ var init_orchestrator_executor = __esm({
14384
15065
  */
14385
15066
  async loadAgents(domains, projectId) {
14386
15067
  const globalPath = path_manager_default.getGlobalProjectPath(projectId);
14387
- const agentsDir = path28.join(globalPath, "agents");
15068
+ const agentsDir = path29.join(globalPath, "agents");
14388
15069
  const agentPromises = domains.map(async (domain) => {
14389
15070
  const possibleNames = [`${domain}.md`, `${domain}-agent.md`, `prjct-${domain}.md`];
14390
15071
  for (const fileName of possibleNames) {
14391
- const filePath = path28.join(agentsDir, fileName);
15072
+ const filePath = path29.join(agentsDir, fileName);
14392
15073
  try {
14393
15074
  const content = await fs30.readFile(filePath, "utf-8");
14394
15075
  const { frontmatter, body } = this.parseAgentFile(content);
@@ -14431,7 +15112,7 @@ var init_orchestrator_executor = __esm({
14431
15112
  * Uses parallel file reads for performance (PRJ-110).
14432
15113
  */
14433
15114
  async loadSkills(agents) {
14434
- const skillsDir = path28.join(os9.homedir(), ".claude", "skills");
15115
+ const skillsDir = path29.join(os9.homedir(), ".claude", "skills");
14435
15116
  const skillToAgents = /* @__PURE__ */ new Map();
14436
15117
  for (const agent of agents) {
14437
15118
  for (const skillName of agent.skills) {
@@ -14442,8 +15123,8 @@ var init_orchestrator_executor = __esm({
14442
15123
  }
14443
15124
  const skillPromises = Array.from(skillToAgents.keys()).map(
14444
15125
  async (skillName) => {
14445
- const flatPath = path28.join(skillsDir, `${skillName}.md`);
14446
- const subdirPath = path28.join(skillsDir, skillName, "SKILL.md");
15126
+ const flatPath = path29.join(skillsDir, `${skillName}.md`);
15127
+ const subdirPath = path29.join(skillsDir, skillName, "SKILL.md");
14447
15128
  try {
14448
15129
  const content = await fs30.readFile(subdirPath, "utf-8");
14449
15130
  return { name: skillName, content, filePath: subdirPath };
@@ -14885,262 +15566,104 @@ var init_plan_mode = __esm({
14885
15566
  aborted: true,
14886
15567
  planId: plan.id,
14887
15568
  reason: reason2,
14888
- completedSteps: plan.steps.filter((s) => s.status === "completed").length,
14889
- totalSteps: plan.steps.length
14890
- };
14891
- this.activePlans.delete(projectId);
14892
- return summary;
14893
- }
14894
- /**
14895
- * Generate approval prompt for destructive commands (class method wrapper)
14896
- */
14897
- generateApprovalPrompt(commandName, context2) {
14898
- return generateApprovalPrompt(commandName, context2);
14899
- }
14900
- /**
14901
- * Format plan status for display
14902
- */
14903
- formatStatus(projectId) {
14904
- const plan = this.getActivePlan(projectId);
14905
- if (!plan) return "No active plan";
14906
- const statusEmoji = {
14907
- [PLAN_STATUS.GATHERING]: "\u{1F50D}",
14908
- [PLAN_STATUS.ANALYZING]: "\u{1F9E0}",
14909
- [PLAN_STATUS.PROPOSING]: "\u{1F4DD}",
14910
- [PLAN_STATUS.PENDING_APPROVAL]: "\u23F3",
14911
- [PLAN_STATUS.APPROVED]: "\u2705",
14912
- [PLAN_STATUS.EXECUTING]: "\u26A1",
14913
- [PLAN_STATUS.COMPLETED]: "\u{1F389}",
14914
- [PLAN_STATUS.REJECTED]: "\u274C",
14915
- [PLAN_STATUS.ABORTED]: "\u{1F6D1}"
14916
- };
14917
- const lines = [
14918
- `${statusEmoji[plan.status] || "\u{1F4CB}"} Plan: ${plan.command}`,
14919
- `Status: ${plan.status}`
14920
- ];
14921
- if (plan.status === PLAN_STATUS.EXECUTING) {
14922
- const progress = Math.round(plan.currentStep / plan.steps.length * 100);
14923
- lines.push(`Progress: ${plan.currentStep}/${plan.steps.length} (${progress}%)`);
14924
- }
14925
- return lines.join("\n");
14926
- }
14927
- /**
14928
- * Calculate duration between two timestamps
14929
- */
14930
- _calculateDuration(start, end) {
14931
- if (!start || !end) return null;
14932
- const ms = new Date(end).getTime() - new Date(start).getTime();
14933
- const seconds = Math.floor(ms / 1e3);
14934
- const minutes = Math.floor(seconds / 60);
14935
- const hours = Math.floor(minutes / 60);
14936
- if (hours > 0) return `${hours}h ${minutes % 60}m`;
14937
- if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
14938
- return `${seconds}s`;
14939
- }
14940
- };
14941
- planMode = new PlanMode();
14942
- plan_mode_default = planMode;
14943
- }
14944
- });
14945
-
14946
- // core/types/agentic.ts
14947
- var init_agentic = __esm({
14948
- "core/types/agentic.ts"() {
14949
- "use strict";
14950
- }
14951
- });
14952
-
14953
- // core/types/bus.ts
14954
- var init_bus = __esm({
14955
- "core/types/bus.ts"() {
14956
- "use strict";
14957
- }
14958
- });
14959
-
14960
- // core/integrations/issue-tracker/types.ts
14961
- var init_types2 = __esm({
14962
- "core/integrations/issue-tracker/types.ts"() {
14963
- "use strict";
14964
- }
14965
- });
14966
-
14967
- // core/types/integrations.ts
14968
- var init_integrations = __esm({
14969
- "core/types/integrations.ts"() {
14970
- "use strict";
14971
- init_types2();
14972
- }
14973
- });
14974
-
14975
- // core/types/index.ts
14976
- var init_types3 = __esm({
14977
- "core/types/index.ts"() {
14978
- "use strict";
14979
- init_agentic();
14980
- init_bus();
14981
- init_errors2();
14982
- init_fs();
14983
- init_integrations();
14984
- init_memory();
14985
- init_server();
14986
- }
14987
- });
14988
-
14989
- // core/outcomes/recorder.ts
14990
- import path29 from "node:path";
14991
- var OUTCOMES_DIR, OUTCOMES_FILE, OutcomeRecorder, outcomeRecorder, recorder_default;
14992
- var init_recorder = __esm({
14993
- "core/outcomes/recorder.ts"() {
14994
- "use strict";
14995
- init_path_manager();
14996
- init_schemas2();
14997
- init_file_helper();
14998
- OUTCOMES_DIR = "outcomes";
14999
- OUTCOMES_FILE = "outcomes.jsonl";
15000
- OutcomeRecorder = class {
15001
- static {
15002
- __name(this, "OutcomeRecorder");
15003
- }
15004
- /**
15005
- * Get outcomes directory path for a project.
15006
- */
15007
- getOutcomesDir(projectId) {
15008
- const globalPath = path_manager_default.getGlobalProjectPath(projectId);
15009
- return path29.join(globalPath, OUTCOMES_DIR);
15010
- }
15011
- /**
15012
- * Get outcomes file path for a project.
15013
- */
15014
- getOutcomesPath(projectId) {
15015
- return path29.join(this.getOutcomesDir(projectId), OUTCOMES_FILE);
15016
- }
15017
- /**
15018
- * Record an outcome.
15019
- */
15020
- async record(projectId, input) {
15021
- const outcome = {
15022
- ...input,
15023
- id: generateUUID()
15024
- };
15025
- const outcomesPath = this.getOutcomesPath(projectId);
15026
- await ensureDir(path29.dirname(outcomesPath));
15027
- await appendLine(outcomesPath, JSON.stringify(outcome));
15028
- return outcome;
15029
- }
15030
- /**
15031
- * Get all outcomes for a project.
15032
- */
15033
- async getAll(projectId) {
15034
- const outcomesPath = this.getOutcomesPath(projectId);
15035
- if (!await fileExists2(outcomesPath)) {
15036
- return [];
15037
- }
15038
- const content = await readFile(outcomesPath);
15039
- if (!content.trim()) {
15040
- return [];
15041
- }
15042
- return content.trim().split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
15043
- }
15044
- /**
15045
- * Get outcomes matching a filter.
15046
- */
15047
- async filter(projectId, filter) {
15048
- const all = await this.getAll(projectId);
15049
- return all.filter((outcome) => {
15050
- if (filter.sessionId && outcome.sessionId !== filter.sessionId) {
15051
- return false;
15052
- }
15053
- if (filter.command && outcome.command !== filter.command) {
15054
- return false;
15055
- }
15056
- if (filter.agent && outcome.agentUsed !== filter.agent) {
15057
- return false;
15058
- }
15059
- if (filter.fromDate && outcome.startedAt < filter.fromDate) {
15060
- return false;
15061
- }
15062
- if (filter.toDate && outcome.completedAt > filter.toDate) {
15063
- return false;
15064
- }
15065
- if (filter.minQuality && outcome.qualityScore < filter.minQuality) {
15066
- return false;
15067
- }
15068
- if (filter.tags && filter.tags.length > 0) {
15069
- const outcomeTags = outcome.tags || [];
15070
- if (!filter.tags.some((tag) => outcomeTags.includes(tag))) {
15071
- return false;
15072
- }
15073
- }
15074
- return true;
15075
- });
15076
- }
15077
- /**
15078
- * Get recent outcomes (last N).
15079
- */
15080
- async getRecent(projectId, count = 10) {
15081
- const all = await this.getAll(projectId);
15082
- return all.slice(-count);
15083
- }
15084
- /**
15085
- * Get outcomes for a specific command.
15086
- */
15087
- async getByCommand(projectId, command) {
15088
- return this.filter(projectId, { command });
15569
+ completedSteps: plan.steps.filter((s) => s.status === "completed").length,
15570
+ totalSteps: plan.steps.length
15571
+ };
15572
+ this.activePlans.delete(projectId);
15573
+ return summary;
15089
15574
  }
15090
15575
  /**
15091
- * Get outcomes for a specific agent.
15576
+ * Generate approval prompt for destructive commands (class method wrapper)
15092
15577
  */
15093
- async getByAgent(projectId, agent) {
15094
- return this.filter(projectId, { agent });
15578
+ generateApprovalPrompt(commandName, context2) {
15579
+ return generateApprovalPrompt(commandName, context2);
15095
15580
  }
15096
15581
  /**
15097
- * Calculate estimate accuracy.
15582
+ * Format plan status for display
15098
15583
  */
15099
- async getEstimateAccuracy(projectId) {
15100
- const outcomes = await this.getAll(projectId);
15101
- if (outcomes.length === 0) {
15102
- return 0;
15584
+ formatStatus(projectId) {
15585
+ const plan = this.getActivePlan(projectId);
15586
+ if (!plan) return "No active plan";
15587
+ const statusEmoji = {
15588
+ [PLAN_STATUS.GATHERING]: "\u{1F50D}",
15589
+ [PLAN_STATUS.ANALYZING]: "\u{1F9E0}",
15590
+ [PLAN_STATUS.PROPOSING]: "\u{1F4DD}",
15591
+ [PLAN_STATUS.PENDING_APPROVAL]: "\u23F3",
15592
+ [PLAN_STATUS.APPROVED]: "\u2705",
15593
+ [PLAN_STATUS.EXECUTING]: "\u26A1",
15594
+ [PLAN_STATUS.COMPLETED]: "\u{1F389}",
15595
+ [PLAN_STATUS.REJECTED]: "\u274C",
15596
+ [PLAN_STATUS.ABORTED]: "\u{1F6D1}"
15597
+ };
15598
+ const lines = [
15599
+ `${statusEmoji[plan.status] || "\u{1F4CB}"} Plan: ${plan.command}`,
15600
+ `Status: ${plan.status}`
15601
+ ];
15602
+ if (plan.status === PLAN_STATUS.EXECUTING) {
15603
+ const progress = Math.round(plan.currentStep / plan.steps.length * 100);
15604
+ lines.push(`Progress: ${plan.currentStep}/${plan.steps.length} (${progress}%)`);
15103
15605
  }
15104
- const accurate = outcomes.filter((o) => {
15105
- if (!o.variance) return false;
15106
- const variance = this.parseVariance(o.variance);
15107
- const estimated = this.parseDuration(o.estimatedDuration);
15108
- if (estimated === 0) return false;
15109
- return Math.abs(variance) / estimated <= 0.2;
15110
- });
15111
- return Math.round(accurate.length / outcomes.length * 100);
15112
- }
15113
- /**
15114
- * Parse variance string to minutes.
15115
- * "+30m" → 30, "-15m" → -15
15116
- */
15117
- parseVariance(variance) {
15118
- const match = variance.match(/^([+-])(\d+)([mh])$/);
15119
- if (!match) return 0;
15120
- const sign = match[1] === "-" ? -1 : 1;
15121
- const value = parseInt(match[2], 10);
15122
- const unit = match[3];
15123
- return sign * (unit === "h" ? value * 60 : value);
15606
+ return lines.join("\n");
15124
15607
  }
15125
15608
  /**
15126
- * Parse duration string to minutes.
15127
- * "2h" → 120, "30m" → 30, "1h 30m" → 90
15609
+ * Calculate duration between two timestamps
15128
15610
  */
15129
- parseDuration(duration) {
15130
- let minutes = 0;
15131
- const hourMatch = duration.match(/(\d+)h/);
15132
- if (hourMatch) {
15133
- minutes += parseInt(hourMatch[1], 10) * 60;
15134
- }
15135
- const minMatch = duration.match(/(\d+)m/);
15136
- if (minMatch) {
15137
- minutes += parseInt(minMatch[1], 10);
15138
- }
15139
- return minutes;
15611
+ _calculateDuration(start, end) {
15612
+ if (!start || !end) return null;
15613
+ const ms = new Date(end).getTime() - new Date(start).getTime();
15614
+ const seconds = Math.floor(ms / 1e3);
15615
+ const minutes = Math.floor(seconds / 60);
15616
+ const hours = Math.floor(minutes / 60);
15617
+ if (hours > 0) return `${hours}h ${minutes % 60}m`;
15618
+ if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
15619
+ return `${seconds}s`;
15140
15620
  }
15141
15621
  };
15142
- outcomeRecorder = new OutcomeRecorder();
15143
- recorder_default = outcomeRecorder;
15622
+ planMode = new PlanMode();
15623
+ plan_mode_default = planMode;
15624
+ }
15625
+ });
15626
+
15627
+ // core/types/agentic.ts
15628
+ var init_agentic = __esm({
15629
+ "core/types/agentic.ts"() {
15630
+ "use strict";
15631
+ }
15632
+ });
15633
+
15634
+ // core/types/bus.ts
15635
+ var init_bus = __esm({
15636
+ "core/types/bus.ts"() {
15637
+ "use strict";
15638
+ }
15639
+ });
15640
+
15641
+ // core/integrations/issue-tracker/types.ts
15642
+ var init_types2 = __esm({
15643
+ "core/integrations/issue-tracker/types.ts"() {
15644
+ "use strict";
15645
+ }
15646
+ });
15647
+
15648
+ // core/types/integrations.ts
15649
+ var init_integrations = __esm({
15650
+ "core/types/integrations.ts"() {
15651
+ "use strict";
15652
+ init_types2();
15653
+ }
15654
+ });
15655
+
15656
+ // core/types/index.ts
15657
+ var init_types3 = __esm({
15658
+ "core/types/index.ts"() {
15659
+ "use strict";
15660
+ init_agentic();
15661
+ init_bus();
15662
+ init_errors2();
15663
+ init_fs();
15664
+ init_integrations();
15665
+ init_memory();
15666
+ init_server();
15144
15667
  }
15145
15668
  });
15146
15669
 
@@ -15372,7 +15895,7 @@ var init_outcomes2 = __esm({
15372
15895
  });
15373
15896
 
15374
15897
  // core/agentic/anti-hallucination.ts
15375
- import { z as z15 } from "zod";
15898
+ import { z as z16 } from "zod";
15376
15899
  function buildAntiHallucinationBlock(truth) {
15377
15900
  const parts = [];
15378
15901
  parts.push("## CONSTRAINTS (Read Before Acting)\n");
@@ -15381,9 +15904,24 @@ function buildAntiHallucinationBlock(truth) {
15381
15904
  if (truth.framework) available.push(truth.framework);
15382
15905
  const techStack = truth.techStack ?? [];
15383
15906
  available.push(...techStack.filter((t) => t !== truth.framework));
15907
+ const analysisLangs = truth.analysisLanguages ?? [];
15908
+ const analysisFrameworks = truth.analysisFrameworks ?? [];
15909
+ for (const lang of analysisLangs) {
15910
+ if (!available.some((a) => a.toLowerCase() === lang.toLowerCase())) {
15911
+ available.push(lang);
15912
+ }
15913
+ }
15914
+ for (const fw of analysisFrameworks) {
15915
+ if (!available.some((a) => a.toLowerCase() === fw.toLowerCase())) {
15916
+ available.push(fw);
15917
+ }
15918
+ }
15384
15919
  if (available.length > 0) {
15385
15920
  parts.push(`AVAILABLE in this project: ${available.join(", ")}`);
15386
15921
  }
15922
+ if (truth.analysisPackageManager) {
15923
+ parts.push(`PACKAGE MANAGER: ${truth.analysisPackageManager}`);
15924
+ }
15387
15925
  if (truth.domains) {
15388
15926
  const absent = Object.entries(truth.domains).filter(([, hasIt]) => !hasIt).map(([key]) => DOMAIN_LABELS[key]).filter(Boolean);
15389
15927
  if (absent.length > 0) {
@@ -15410,27 +15948,33 @@ var ProjectGroundTruthSchema, DOMAIN_LABELS;
15410
15948
  var init_anti_hallucination = __esm({
15411
15949
  "core/agentic/anti-hallucination.ts"() {
15412
15950
  "use strict";
15413
- ProjectGroundTruthSchema = z15.object({
15951
+ ProjectGroundTruthSchema = z16.object({
15414
15952
  /** Project root path */
15415
- projectPath: z15.string(),
15953
+ projectPath: z16.string(),
15416
15954
  /** Programming language (e.g., 'TypeScript', 'JavaScript', 'Python') */
15417
- language: z15.string().optional(),
15955
+ language: z16.string().optional(),
15418
15956
  /** Primary framework (e.g., 'Hono', 'Next.js', 'Express') */
15419
- framework: z15.string().optional(),
15957
+ framework: z16.string().optional(),
15420
15958
  /** Technology stack items (e.g., ['Hono', 'Zod', 'Vitest']) */
15421
- techStack: z15.array(z15.string()).default([]),
15959
+ techStack: z16.array(z16.string()).default([]),
15422
15960
  /** Domain flags from sealed analysis */
15423
- domains: z15.object({
15424
- hasFrontend: z15.boolean().default(false),
15425
- hasBackend: z15.boolean().default(false),
15426
- hasDatabase: z15.boolean().default(false),
15427
- hasTesting: z15.boolean().default(false),
15428
- hasDocker: z15.boolean().default(false)
15961
+ domains: z16.object({
15962
+ hasFrontend: z16.boolean().default(false),
15963
+ hasBackend: z16.boolean().default(false),
15964
+ hasDatabase: z16.boolean().default(false),
15965
+ hasTesting: z16.boolean().default(false),
15966
+ hasDocker: z16.boolean().default(false)
15429
15967
  }).optional(),
15430
15968
  /** Total files in project */
15431
- fileCount: z15.number().optional(),
15969
+ fileCount: z16.number().optional(),
15432
15970
  /** Available agent names (e.g., ['backend', 'testing']) */
15433
- availableAgents: z15.array(z15.string()).default([])
15971
+ availableAgents: z16.array(z16.string()).default([]),
15972
+ /** Sealed analysis languages — used to ground available tech (PRJ-260) */
15973
+ analysisLanguages: z16.array(z16.string()).default([]),
15974
+ /** Sealed analysis frameworks — used to ground available tech (PRJ-260) */
15975
+ analysisFrameworks: z16.array(z16.string()).default([]),
15976
+ /** Package manager from sealed analysis (PRJ-260) */
15977
+ analysisPackageManager: z16.string().optional()
15434
15978
  });
15435
15979
  DOMAIN_LABELS = {
15436
15980
  hasFrontend: "Frontend (UI/components)",
@@ -15444,21 +15988,21 @@ var init_anti_hallucination = __esm({
15444
15988
  });
15445
15989
 
15446
15990
  // core/schemas/command-context.ts
15447
- import { z as z16 } from "zod";
15991
+ import { z as z17 } from "zod";
15448
15992
  var CommandContextEntrySchema, CommandContextConfigSchema;
15449
15993
  var init_command_context = __esm({
15450
15994
  "core/schemas/command-context.ts"() {
15451
15995
  "use strict";
15452
- CommandContextEntrySchema = z16.object({
15453
- agents: z16.boolean(),
15454
- patterns: z16.boolean(),
15455
- checklist: z16.boolean(),
15456
- modules: z16.array(z16.string())
15996
+ CommandContextEntrySchema = z17.object({
15997
+ agents: z17.boolean(),
15998
+ patterns: z17.boolean(),
15999
+ checklist: z17.boolean(),
16000
+ modules: z17.array(z17.string())
15457
16001
  });
15458
- CommandContextConfigSchema = z16.object({
15459
- version: z16.string(),
15460
- description: z16.string().optional(),
15461
- commands: z16.record(z16.string(), CommandContextEntrySchema).refine((commands) => "*" in commands, {
16002
+ CommandContextConfigSchema = z17.object({
16003
+ version: z17.string(),
16004
+ description: z17.string().optional(),
16005
+ commands: z17.record(z17.string(), CommandContextEntrySchema).refine((commands) => "*" in commands, {
15462
16006
  message: 'Config must include a "*" wildcard entry for unknown commands'
15463
16007
  })
15464
16008
  });
@@ -15650,7 +16194,7 @@ var init_command_context2 = __esm({
15650
16194
 
15651
16195
  // core/agentic/environment-block.ts
15652
16196
  import os10 from "node:os";
15653
- import { z as z17 } from "zod";
16197
+ import { z as z18 } from "zod";
15654
16198
  function detectRuntime2() {
15655
16199
  if (typeof globalThis !== "undefined" && "Bun" in globalThis) {
15656
16200
  return "bun";
@@ -15690,25 +16234,25 @@ var EnvironmentBlockInputSchema;
15690
16234
  var init_environment_block = __esm({
15691
16235
  "core/agentic/environment-block.ts"() {
15692
16236
  "use strict";
15693
- EnvironmentBlockInputSchema = z17.object({
16237
+ EnvironmentBlockInputSchema = z18.object({
15694
16238
  /** Project display name */
15695
- projectName: z17.string(),
16239
+ projectName: z18.string(),
15696
16240
  /** Absolute path to project root */
15697
- projectPath: z17.string(),
16241
+ projectPath: z18.string(),
15698
16242
  /** Whether the project is a git repository */
15699
- isGitRepo: z17.boolean().default(true),
16243
+ isGitRepo: z18.boolean().default(true),
15700
16244
  /** Current git branch name */
15701
- gitBranch: z17.string().optional(),
16245
+ gitBranch: z18.string().optional(),
15702
16246
  /** Operating system platform (auto-detected if not provided) */
15703
- platform: z17.string().optional(),
16247
+ platform: z18.string().optional(),
15704
16248
  /** JavaScript runtime (auto-detected if not provided) */
15705
- runtime: z17.string().optional(),
16249
+ runtime: z18.string().optional(),
15706
16250
  /** Current date in ISO format (auto-generated if not provided) */
15707
- date: z17.string().optional(),
16251
+ date: z18.string().optional(),
15708
16252
  /** AI model identifier (e.g., 'opus', 'sonnet', '2.5-pro') */
15709
- model: z17.string().optional(),
16253
+ model: z18.string().optional(),
15710
16254
  /** AI provider name (e.g., 'claude', 'gemini', 'cursor') */
15711
- provider: z17.string().optional()
16255
+ provider: z18.string().optional()
15712
16256
  });
15713
16257
  __name(detectRuntime2, "detectRuntime");
15714
16258
  __name(normalizePlatform, "normalizePlatform");
@@ -16174,14 +16718,57 @@ ${envBlock}
16174
16718
  `);
16175
16719
  }
16176
16720
  if (orchestratorContext) {
16721
+ const sa = orchestratorContext.sealedAnalysis;
16177
16722
  parts.push("\n## PROJECT ANALYSIS (Sealed)\n");
16178
16723
  parts.push(`**Ecosystem**: ${orchestratorContext.project.ecosystem}
16179
16724
  `);
16180
16725
  parts.push(`**Primary Domain**: ${orchestratorContext.primaryDomain}
16181
16726
  `);
16182
16727
  parts.push(`**Domains**: ${orchestratorContext.detectedDomains.join(", ")}
16183
-
16184
16728
  `);
16729
+ if (sa) {
16730
+ if (sa.languages.length > 0) {
16731
+ parts.push(`**Languages**: ${sa.languages.join(", ")}
16732
+ `);
16733
+ }
16734
+ if (sa.frameworks.length > 0) {
16735
+ parts.push(`**Frameworks**: ${sa.frameworks.join(", ")}
16736
+ `);
16737
+ }
16738
+ if (sa.packageManager) {
16739
+ parts.push(`**Package Manager**: ${sa.packageManager}
16740
+ `);
16741
+ }
16742
+ if (sa.sourceDir) {
16743
+ parts.push(`**Source Dir**: ${sa.sourceDir}
16744
+ `);
16745
+ }
16746
+ if (sa.testDir) {
16747
+ parts.push(`**Test Dir**: ${sa.testDir}
16748
+ `);
16749
+ }
16750
+ parts.push(`**Files Analyzed**: ${sa.fileCount}
16751
+ `);
16752
+ parts.push(
16753
+ `**Analysis Status**: ${sa.status}${sa.commitHash ? ` (commit: ${sa.commitHash.slice(0, 8)})` : ""}
16754
+ `
16755
+ );
16756
+ if (sa.patterns.length > 0) {
16757
+ parts.push("\n### Code Patterns (Follow These)\n");
16758
+ for (const p of sa.patterns) {
16759
+ parts.push(`- **${p.name}**: ${p.description}${p.location ? ` (${p.location})` : ""}
16760
+ `);
16761
+ }
16762
+ }
16763
+ if (sa.antiPatterns.length > 0) {
16764
+ parts.push("\n### Anti-Patterns (Avoid These)\n");
16765
+ for (const ap of sa.antiPatterns) {
16766
+ parts.push(`- **${ap.issue}** in \`${ap.file}\` \u2014 ${ap.suggestion}
16767
+ `);
16768
+ }
16769
+ }
16770
+ }
16771
+ parts.push("\n");
16185
16772
  }
16186
16773
  const needsPatterns = commandContext.patterns;
16187
16774
  const codePatternsContent = state?.codePatterns || "";
@@ -16282,13 +16869,18 @@ Show changes, list affected files, ask for confirmation.
16282
16869
  );
16283
16870
  }
16284
16871
  if (projectPath) {
16872
+ const sa = orchestratorContext?.sealedAnalysis;
16285
16873
  const groundTruth2 = {
16286
16874
  projectPath,
16287
16875
  language: orchestratorContext?.project?.ecosystem,
16288
16876
  techStack: orchestratorContext?.project?.conventions || [],
16289
16877
  domains: this.extractDomains(state),
16290
16878
  fileCount: context2.files?.length || context2.filteredSize || 0,
16291
- availableAgents: orchestratorContext?.agents?.map((a) => a.name) || []
16879
+ availableAgents: orchestratorContext?.agents?.map((a) => a.name) || [],
16880
+ // Inject sealed analysis data for enriched grounding (PRJ-260)
16881
+ analysisLanguages: sa?.languages || [],
16882
+ analysisFrameworks: sa?.frameworks || [],
16883
+ analysisPackageManager: sa?.packageManager
16292
16884
  };
16293
16885
  parts.push(`
16294
16886
  ${buildAntiHallucinationBlock(groundTruth2)}
@@ -16351,6 +16943,11 @@ Read files before modifying.
16351
16943
  parts.push(relevantState);
16352
16944
  parts.push("\n");
16353
16945
  }
16946
+ if (orchestratorContext?.velocityContext) {
16947
+ parts.push("\n### VELOCITY (Historical Estimation Data)\n\n");
16948
+ parts.push(orchestratorContext.velocityContext);
16949
+ parts.push("\n\n");
16950
+ }
16354
16951
  if (learnedPatterns && Object.keys(learnedPatterns).some((k) => learnedPatterns[k])) {
16355
16952
  parts.push("\n## PROJECT DEFAULTS (apply automatically)\n");
16356
16953
  for (const [key, value] of Object.entries(learnedPatterns)) {
@@ -26288,6 +26885,23 @@ var init_command_data = __esm({
26288
26885
  "Command duration breakdown"
26289
26886
  ]
26290
26887
  },
26888
+ {
26889
+ name: "velocity",
26890
+ group: "core",
26891
+ description: "Sprint-based velocity dashboard with trend detection and projections",
26892
+ usage: { claude: "/p:velocity", terminal: "prjct velocity [backlogPoints]" },
26893
+ params: "[backlogPoints]",
26894
+ implemented: true,
26895
+ hasTemplate: false,
26896
+ requiresProject: true,
26897
+ features: [
26898
+ "Sprint-by-sprint velocity breakdown",
26899
+ "Trend detection (improving/stable/declining)",
26900
+ "Estimation accuracy tracking",
26901
+ "Over/under estimation pattern detection",
26902
+ "Completion projections for backlog"
26903
+ ]
26904
+ },
26291
26905
  {
26292
26906
  name: "suggest",
26293
26907
  group: "core",
@@ -29556,6 +30170,122 @@ Generated with [p/](https://www.prjct.app/)`;
29556
30170
  }
29557
30171
  });
29558
30172
 
30173
+ // core/commands/velocity.ts
30174
+ import chalk19 from "chalk";
30175
+ var VelocityCommands;
30176
+ var init_velocity3 = __esm({
30177
+ "core/commands/velocity.ts"() {
30178
+ "use strict";
30179
+ init_velocity2();
30180
+ init_recorder();
30181
+ init_velocity();
30182
+ init_velocity_storage();
30183
+ init_fs();
30184
+ init_base();
30185
+ VelocityCommands = class extends PrjctCommandsBase {
30186
+ static {
30187
+ __name(this, "VelocityCommands");
30188
+ }
30189
+ /**
30190
+ * prjct velocity - Velocity dashboard
30191
+ */
30192
+ async velocity(backlogPoints = "0", projectPath = process.cwd()) {
30193
+ try {
30194
+ const initResult = await this.ensureProjectInit(projectPath);
30195
+ if (!initResult.success) return initResult;
30196
+ const projectId = await config_manager_default.getProjectId(projectPath);
30197
+ if (!projectId) {
30198
+ output_default.failWithHint("NO_PROJECT_ID");
30199
+ return { success: false, error: "No project ID found" };
30200
+ }
30201
+ const config = await this.loadVelocityConfig(projectPath);
30202
+ const outcomes = await recorder_default.getAll(projectId);
30203
+ if (outcomes.length === 0) {
30204
+ console.log(`
30205
+ ${chalk19.dim("No velocity data yet.")}`);
30206
+ console.log(`${chalk19.dim("Complete tasks with estimates to build velocity history.")}
30207
+ `);
30208
+ return { success: true, message: "No data" };
30209
+ }
30210
+ const metrics = calculateVelocity(outcomes, config);
30211
+ await velocityStorage.saveMetrics(projectId, metrics);
30212
+ console.log(
30213
+ `
30214
+ ${chalk19.cyan("Sprint Velocity")} ${chalk19.dim(`(last ${config.windowSize ?? 6} sprints)`)}`
30215
+ );
30216
+ console.log("\u2550".repeat(60));
30217
+ const recentSprints = metrics.sprints.slice(-(config.windowSize ?? 6));
30218
+ for (const sprint of recentSprints) {
30219
+ const accuracyColor = sprint.estimationAccuracy >= 80 ? chalk19.green : sprint.estimationAccuracy >= 60 ? chalk19.yellow : chalk19.red;
30220
+ console.log(
30221
+ ` Sprint ${String(sprint.sprintNumber).padStart(2)}: ${chalk19.bold(`${sprint.pointsCompleted} pts`)} | ${sprint.tasksCompleted} tasks | accuracy: ${accuracyColor(`${sprint.estimationAccuracy}%`)}`
30222
+ );
30223
+ }
30224
+ console.log("");
30225
+ const trendIcon = metrics.velocityTrend === "improving" ? chalk19.green("\u2191") : metrics.velocityTrend === "declining" ? chalk19.red("\u2193") : chalk19.dim("\u2192");
30226
+ console.log(
30227
+ ` Average: ${chalk19.bold(`${metrics.averageVelocity} pts/sprint`)} | Trend: ${trendIcon} ${metrics.velocityTrend}`
30228
+ );
30229
+ console.log(
30230
+ ` Estimation accuracy: ${chalk19.bold(`${metrics.estimationAccuracy}%`)} ${chalk19.dim(`(\xB1${config.accuracyTolerance ?? 20}% tolerance)`)}`
30231
+ );
30232
+ if (metrics.underEstimated.length > 0 || metrics.overEstimated.length > 0) {
30233
+ console.log(`
30234
+ ${chalk19.dim("Patterns:")}`);
30235
+ for (const p of metrics.underEstimated) {
30236
+ console.log(
30237
+ ` ${chalk19.yellow("\u26A0")} ${p.category} tasks underestimated by avg ${chalk19.bold(`${p.avgVariance}%`)}`
30238
+ );
30239
+ }
30240
+ for (const p of metrics.overEstimated) {
30241
+ console.log(
30242
+ ` ${chalk19.green("\u2713")} ${p.category} tasks estimated within ${chalk19.bold(`${p.avgVariance}%`)}`
30243
+ );
30244
+ }
30245
+ }
30246
+ const points = parseInt(backlogPoints, 10);
30247
+ if (points > 0 && metrics.averageVelocity > 0) {
30248
+ const projection = projectCompletion(points, metrics.averageVelocity, config);
30249
+ const dateStr = projection.estimatedDate ? new Date(projection.estimatedDate).toLocaleDateString("en-US", {
30250
+ month: "short",
30251
+ day: "numeric",
30252
+ year: "numeric"
30253
+ }) : "unknown";
30254
+ console.log(`
30255
+ ${chalk19.dim("Projection:")}`);
30256
+ console.log(` Backlog: ${chalk19.bold(`${points} pts`)} remaining`);
30257
+ console.log(
30258
+ ` At current velocity: ~${projection.sprints} sprints (${projection.sprints * (config.sprintLengthDays ?? 7)} days)`
30259
+ );
30260
+ console.log(` Estimated completion: ${chalk19.bold(dateStr)}`);
30261
+ }
30262
+ console.log("\u2550".repeat(60));
30263
+ console.log("");
30264
+ return { success: true };
30265
+ } catch (error) {
30266
+ output_default.fail(getErrorMessage2(error));
30267
+ return { success: false, error: getErrorMessage2(error) };
30268
+ }
30269
+ }
30270
+ /**
30271
+ * Load velocity config from project or use defaults.
30272
+ * Velocity config can be added to prjct.config.json as { velocity: { sprintLengthDays, ... } }
30273
+ */
30274
+ async loadVelocityConfig(projectPath) {
30275
+ try {
30276
+ const config = await config_manager_default.readConfig(projectPath);
30277
+ const raw = config;
30278
+ if (raw?.velocity && typeof raw.velocity === "object") {
30279
+ return { ...DEFAULT_VELOCITY_CONFIG, ...raw.velocity };
30280
+ }
30281
+ } catch {
30282
+ }
30283
+ return DEFAULT_VELOCITY_CONFIG;
30284
+ }
30285
+ };
30286
+ }
30287
+ });
30288
+
29559
30289
  // core/domain/fibonacci.ts
29560
30290
  var FIBONACCI_POINTS, DEFAULT_MINUTES_MAP, isValidPoint, pointsToMinutes, formatMinutes, pointsToTimeRange;
29561
30291
  var init_fibonacci = __esm({
@@ -30859,6 +31589,7 @@ var init_commands = __esm({
30859
31589
  init_planning();
30860
31590
  init_setup2();
30861
31591
  init_shipping();
31592
+ init_velocity3();
30862
31593
  init_workflow();
30863
31594
  PrjctCommands = class {
30864
31595
  static {
@@ -30873,6 +31604,7 @@ var init_commands = __esm({
30873
31604
  maintenance;
30874
31605
  analysis;
30875
31606
  setupCmds;
31607
+ velocityCmds;
30876
31608
  contextCmds;
30877
31609
  // Shared state
30878
31610
  agent;
@@ -30888,6 +31620,7 @@ var init_commands = __esm({
30888
31620
  this.maintenance = new MaintenanceCommands();
30889
31621
  this.analysis = new AnalysisCommands();
30890
31622
  this.setupCmds = new SetupCommands();
31623
+ this.velocityCmds = new VelocityCommands();
30891
31624
  this.contextCmds = new ContextCommands();
30892
31625
  this.agent = null;
30893
31626
  this.agentInfo = null;
@@ -30938,6 +31671,10 @@ var init_commands = __esm({
30938
31671
  async perf(period = "7", projectPath = process.cwd()) {
30939
31672
  return this.performanceCmds.perf(period, projectPath);
30940
31673
  }
31674
+ // ========== Velocity Commands ==========
31675
+ async velocity(backlogPoints = "0", projectPath = process.cwd()) {
31676
+ return this.velocityCmds.velocity(backlogPoints, projectPath);
31677
+ }
30941
31678
  // ========== Maintenance Commands ==========
30942
31679
  async cleanup(options = {}, projectPath = process.cwd()) {
30943
31680
  return this.maintenance.cleanup(options, projectPath);
@@ -31037,6 +31774,7 @@ function registerAllCommands() {
31037
31774
  commandRegistry.registerMethod("dash", analytics, "dash", getMeta("dash"));
31038
31775
  commandRegistry.registerMethod("help", analytics, "help", getMeta("help"));
31039
31776
  commandRegistry.registerMethod("perf", performance, "perf", getMeta("perf"));
31777
+ commandRegistry.registerMethod("velocity", velocityCmd, "velocity", getMeta("velocity"));
31040
31778
  commandRegistry.registerMethod("cleanup", maintenance, "cleanup", getMeta("cleanup"));
31041
31779
  commandRegistry.registerMethod("design", maintenance, "design", getMeta("design"));
31042
31780
  commandRegistry.registerMethod("recover", maintenance, "recover", getMeta("recover"));
@@ -31054,7 +31792,7 @@ function registerAllCommands() {
31054
31792
  commandRegistry.registerMethod("uninstall", uninstallCmd, "uninstall", getMeta("uninstall"));
31055
31793
  commandRegistry.registerMethod("context", context, "context", getMeta("context"));
31056
31794
  }
31057
- var workflow, planning, shipping, analytics, performance, maintenance, analysis, setup, context, uninstallCmd;
31795
+ var workflow, planning, shipping, analytics, performance, maintenance, analysis, setup, context, velocityCmd, uninstallCmd;
31058
31796
  var init_register = __esm({
31059
31797
  "core/commands/register.ts"() {
31060
31798
  "use strict";
@@ -31069,6 +31807,7 @@ var init_register = __esm({
31069
31807
  init_setup2();
31070
31808
  init_shipping();
31071
31809
  init_uninstall();
31810
+ init_velocity3();
31072
31811
  init_workflow();
31073
31812
  workflow = new WorkflowCommands();
31074
31813
  planning = new PlanningCommands();
@@ -31079,6 +31818,7 @@ var init_register = __esm({
31079
31818
  analysis = new AnalysisCommands();
31080
31819
  setup = new SetupCommands();
31081
31820
  context = new ContextCommands();
31821
+ velocityCmd = new VelocityCommands();
31082
31822
  uninstallCmd = new UninstallCommands();
31083
31823
  __name(registerCategories, "registerCategories");
31084
31824
  __name(registerAllCommands, "registerAllCommands");
@@ -31102,7 +31842,7 @@ var require_package = __commonJS({
31102
31842
  "package.json"(exports, module) {
31103
31843
  module.exports = {
31104
31844
  name: "prjct-cli",
31105
- version: "1.12.0",
31845
+ version: "1.14.0",
31106
31846
  description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
31107
31847
  main: "core/index.ts",
31108
31848
  bin: {
@@ -31210,7 +31950,7 @@ var require_package = __commonJS({
31210
31950
  var core_exports = {};
31211
31951
  import os20 from "node:os";
31212
31952
  import path66 from "node:path";
31213
- import chalk19 from "chalk";
31953
+ import chalk20 from "chalk";
31214
31954
  async function main() {
31215
31955
  const [commandName, ...rawArgs] = process.argv.slice(2);
31216
31956
  if (["-v", "--version", "version"].includes(commandName)) {
@@ -31302,6 +32042,7 @@ async function main() {
31302
32042
  }), "status"),
31303
32043
  help: /* @__PURE__ */ __name((p) => commands.help(p || ""), "help"),
31304
32044
  perf: /* @__PURE__ */ __name((p) => commands.perf(p || "7"), "perf"),
32045
+ velocity: /* @__PURE__ */ __name((p) => commands.velocity(p || "0"), "velocity"),
31305
32046
  // Maintenance
31306
32047
  recover: /* @__PURE__ */ __name(() => commands.recover(), "recover"),
31307
32048
  undo: /* @__PURE__ */ __name(() => commands.undo(), "undo"),
@@ -31431,41 +32172,41 @@ async function displayVersion(version) {
31431
32172
  ]);
31432
32173
  const antigravityDetection = await detectAntigravity();
31433
32174
  console.log(`
31434
- ${chalk19.cyan("p/")} prjct v${version}
31435
- ${chalk19.dim("Context layer for AI coding agents")}
32175
+ ${chalk20.cyan("p/")} prjct v${version}
32176
+ ${chalk20.dim("Context layer for AI coding agents")}
31436
32177
 
31437
- ${chalk19.dim("Providers:")}`);
32178
+ ${chalk20.dim("Providers:")}`);
31438
32179
  if (detection.claude.installed) {
31439
- const status = claudeConfigured ? chalk19.green("\u2713 ready") : chalk19.yellow("\u25CF installed");
32180
+ const status = claudeConfigured ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF installed");
31440
32181
  const ver = detection.claude.version ? ` (v${detection.claude.version})` : "";
31441
- console.log(` Claude Code ${status}${chalk19.dim(ver)}`);
32182
+ console.log(` Claude Code ${status}${chalk20.dim(ver)}`);
31442
32183
  } else {
31443
- console.log(` Claude Code ${chalk19.dim("\u25CB not installed")}`);
32184
+ console.log(` Claude Code ${chalk20.dim("\u25CB not installed")}`);
31444
32185
  }
31445
32186
  if (detection.gemini.installed) {
31446
- const status = geminiConfigured ? chalk19.green("\u2713 ready") : chalk19.yellow("\u25CF installed");
32187
+ const status = geminiConfigured ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF installed");
31447
32188
  const ver = detection.gemini.version ? ` (v${detection.gemini.version})` : "";
31448
- console.log(` Gemini CLI ${status}${chalk19.dim(ver)}`);
32189
+ console.log(` Gemini CLI ${status}${chalk20.dim(ver)}`);
31449
32190
  } else {
31450
- console.log(` Gemini CLI ${chalk19.dim("\u25CB not installed")}`);
32191
+ console.log(` Gemini CLI ${chalk20.dim("\u25CB not installed")}`);
31451
32192
  }
31452
32193
  if (antigravityDetection.installed) {
31453
- const status = antigravityDetection.skillInstalled ? chalk19.green("\u2713 ready") : chalk19.yellow("\u25CF detected");
31454
- const hint = antigravityDetection.skillInstalled ? "" : ` ${chalk19.dim("(run prjct start)")}`;
32194
+ const status = antigravityDetection.skillInstalled ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF detected");
32195
+ const hint = antigravityDetection.skillInstalled ? "" : ` ${chalk20.dim("(run prjct start)")}`;
31455
32196
  console.log(` Antigravity ${status}${hint}`);
31456
32197
  } else {
31457
- console.log(` Antigravity ${chalk19.dim("\u25CB not installed")}`);
32198
+ console.log(` Antigravity ${chalk20.dim("\u25CB not installed")}`);
31458
32199
  }
31459
32200
  if (cursorConfigured) {
31460
- console.log(` Cursor IDE ${chalk19.green("\u2713 ready")} ${chalk19.dim("(use /sync, /task)")}`);
32201
+ console.log(` Cursor IDE ${chalk20.green("\u2713 ready")} ${chalk20.dim("(use /sync, /task)")}`);
31461
32202
  } else if (cursorExists) {
31462
- console.log(` Cursor IDE ${chalk19.yellow("\u25CF detected")} ${chalk19.dim("(run prjct init)")}`);
32203
+ console.log(` Cursor IDE ${chalk20.yellow("\u25CF detected")} ${chalk20.dim("(run prjct init)")}`);
31463
32204
  } else {
31464
- console.log(` Cursor IDE ${chalk19.dim("\u25CB no .cursor/ folder")}`);
32205
+ console.log(` Cursor IDE ${chalk20.dim("\u25CB no .cursor/ folder")}`);
31465
32206
  }
31466
32207
  console.log(`
31467
- ${chalk19.dim("Run 'prjct start' for Claude/Gemini, 'prjct init' for Cursor")}
31468
- ${chalk19.cyan("https://prjct.app")}
32208
+ ${chalk20.dim("Run 'prjct start' for Claude/Gemini, 'prjct init' for Cursor")}
32209
+ ${chalk20.cyan("https://prjct.app")}
31469
32210
  `);
31470
32211
  }
31471
32212
  function displayHelp() {
@@ -31567,7 +32308,7 @@ init_config_manager();
31567
32308
  init_editors_config();
31568
32309
  import os21 from "node:os";
31569
32310
  import path67 from "node:path";
31570
- import chalk20 from "chalk";
32311
+ import chalk21 from "chalk";
31571
32312
 
31572
32313
  // core/server/server.ts
31573
32314
  import { Hono as Hono3 } from "hono";
@@ -32569,51 +33310,51 @@ if (args[0] === "start" || args[0] === "setup") {
32569
33310
  fileExists(path67.join(cwd, ".windsurf", "rules", "prjct.md"))
32570
33311
  ]);
32571
33312
  console.log(`
32572
- ${chalk20.cyan("p/")} prjct v${VERSION}
32573
- ${chalk20.dim("Context layer for AI coding agents")}
33313
+ ${chalk21.cyan("p/")} prjct v${VERSION}
33314
+ ${chalk21.dim("Context layer for AI coding agents")}
32574
33315
 
32575
- ${chalk20.dim("Providers:")}`);
33316
+ ${chalk21.dim("Providers:")}`);
32576
33317
  if (detection.claude.installed) {
32577
- const status = claudeConfigured ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF installed");
33318
+ const status = claudeConfigured ? chalk21.green("\u2713 ready") : chalk21.yellow("\u25CF installed");
32578
33319
  const ver = detection.claude.version ? ` (v${detection.claude.version})` : "";
32579
- console.log(` Claude Code ${status}${chalk20.dim(ver)}`);
33320
+ console.log(` Claude Code ${status}${chalk21.dim(ver)}`);
32580
33321
  } else {
32581
- console.log(` Claude Code ${chalk20.dim("\u25CB not installed")}`);
33322
+ console.log(` Claude Code ${chalk21.dim("\u25CB not installed")}`);
32582
33323
  }
32583
33324
  if (detection.gemini.installed) {
32584
- const status = geminiConfigured ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF installed");
33325
+ const status = geminiConfigured ? chalk21.green("\u2713 ready") : chalk21.yellow("\u25CF installed");
32585
33326
  const ver = detection.gemini.version ? ` (v${detection.gemini.version})` : "";
32586
- console.log(` Gemini CLI ${status}${chalk20.dim(ver)}`);
33327
+ console.log(` Gemini CLI ${status}${chalk21.dim(ver)}`);
32587
33328
  } else {
32588
- console.log(` Gemini CLI ${chalk20.dim("\u25CB not installed")}`);
33329
+ console.log(` Gemini CLI ${chalk21.dim("\u25CB not installed")}`);
32589
33330
  }
32590
33331
  if (cursorDetected) {
32591
- const status = cursorConfigured ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF detected");
32592
- console.log(` Cursor IDE ${status}${chalk20.dim(" (project)")}`);
33332
+ const status = cursorConfigured ? chalk21.green("\u2713 ready") : chalk21.yellow("\u25CF detected");
33333
+ console.log(` Cursor IDE ${status}${chalk21.dim(" (project)")}`);
32593
33334
  } else {
32594
- console.log(` Cursor IDE ${chalk20.dim("\u25CB not detected")}`);
33335
+ console.log(` Cursor IDE ${chalk21.dim("\u25CB not detected")}`);
32595
33336
  }
32596
33337
  if (windsurfDetected) {
32597
- const status = windsurfConfigured ? chalk20.green("\u2713 ready") : chalk20.yellow("\u25CF detected");
32598
- console.log(` Windsurf IDE ${status}${chalk20.dim(" (project)")}`);
33338
+ const status = windsurfConfigured ? chalk21.green("\u2713 ready") : chalk21.yellow("\u25CF detected");
33339
+ console.log(` Windsurf IDE ${status}${chalk21.dim(" (project)")}`);
32599
33340
  } else {
32600
- console.log(` Windsurf IDE ${chalk20.dim("\u25CB not detected")}`);
33341
+ console.log(` Windsurf IDE ${chalk21.dim("\u25CB not detected")}`);
32601
33342
  }
32602
33343
  console.log(`
32603
- ${chalk20.dim("Run 'prjct start' to configure (CLI providers)")}
32604
- ${chalk20.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
32605
- ${chalk20.cyan("https://prjct.app")}
33344
+ ${chalk21.dim("Run 'prjct start' to configure (CLI providers)")}
33345
+ ${chalk21.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
33346
+ ${chalk21.cyan("https://prjct.app")}
32606
33347
  `);
32607
33348
  } else {
32608
33349
  const configPath = path67.join(os21.homedir(), ".prjct-cli", "config", "installed-editors.json");
32609
33350
  const routersInstalled = await checkRoutersInstalled();
32610
33351
  if (!await fileExists(configPath) || !routersInstalled) {
32611
33352
  console.log(`
32612
- ${chalk20.cyan.bold(" Welcome to prjct!")}
33353
+ ${chalk21.cyan.bold(" Welcome to prjct!")}
32613
33354
 
32614
- Run ${chalk20.bold("prjct start")} to configure your AI providers.
33355
+ Run ${chalk21.bold("prjct start")} to configure your AI providers.
32615
33356
 
32616
- ${chalk20.dim(`This is a one-time setup that lets you choose between
33357
+ ${chalk21.dim(`This is a one-time setup that lets you choose between
32617
33358
  Claude Code, Gemini CLI, or both.`)}
32618
33359
  `);
32619
33360
  process.exitCode = 0;
@@ -32622,7 +33363,7 @@ ${chalk20.cyan.bold(" Welcome to prjct!")}
32622
33363
  const lastVersion = await editors_config_default.getLastVersion();
32623
33364
  if (lastVersion && lastVersion !== VERSION) {
32624
33365
  console.log(`
32625
- ${chalk20.yellow("\u2139")} Updating prjct v${lastVersion} \u2192 v${VERSION}...
33366
+ ${chalk21.yellow("\u2139")} Updating prjct v${lastVersion} \u2192 v${VERSION}...
32626
33367
  `);
32627
33368
  const { default: setup2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
32628
33369
  await setup2.run();