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.
- package/CHANGELOG.md +89 -0
- package/core/__tests__/agentic/analysis-injection.test.ts +377 -0
- package/core/__tests__/domain/velocity.test.ts +623 -0
- package/core/agentic/anti-hallucination.ts +23 -1
- package/core/agentic/orchestrator-executor.ts +59 -3
- package/core/agentic/prompt-builder.ts +53 -1
- package/core/commands/command-data.ts +17 -0
- package/core/commands/commands.ts +12 -0
- package/core/commands/register.ts +6 -0
- package/core/commands/velocity.ts +149 -0
- package/core/domain/velocity.ts +470 -0
- package/core/index.ts +1 -0
- package/core/schemas/index.ts +2 -0
- package/core/schemas/velocity.ts +103 -0
- package/core/storage/index.ts +2 -1
- package/core/storage/velocity-storage.ts +149 -0
- package/core/types/agentic.ts +33 -0
- package/core/types/index.ts +2 -0
- package/dist/bin/prjct.mjs +1103 -362
- package/package.json +1 -1
package/dist/bin/prjct.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
14446
|
-
const subdirPath =
|
|
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
|
-
*
|
|
15576
|
+
* Generate approval prompt for destructive commands (class method wrapper)
|
|
15092
15577
|
*/
|
|
15093
|
-
|
|
15094
|
-
return
|
|
15578
|
+
generateApprovalPrompt(commandName, context2) {
|
|
15579
|
+
return generateApprovalPrompt(commandName, context2);
|
|
15095
15580
|
}
|
|
15096
15581
|
/**
|
|
15097
|
-
*
|
|
15582
|
+
* Format plan status for display
|
|
15098
15583
|
*/
|
|
15099
|
-
|
|
15100
|
-
const
|
|
15101
|
-
if (
|
|
15102
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
15127
|
-
* "2h" → 120, "30m" → 30, "1h 30m" → 90
|
|
15609
|
+
* Calculate duration between two timestamps
|
|
15128
15610
|
*/
|
|
15129
|
-
|
|
15130
|
-
|
|
15131
|
-
const
|
|
15132
|
-
|
|
15133
|
-
|
|
15134
|
-
|
|
15135
|
-
|
|
15136
|
-
if (
|
|
15137
|
-
|
|
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
|
-
|
|
15143
|
-
|
|
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
|
|
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 =
|
|
15951
|
+
ProjectGroundTruthSchema = z16.object({
|
|
15414
15952
|
/** Project root path */
|
|
15415
|
-
projectPath:
|
|
15953
|
+
projectPath: z16.string(),
|
|
15416
15954
|
/** Programming language (e.g., 'TypeScript', 'JavaScript', 'Python') */
|
|
15417
|
-
language:
|
|
15955
|
+
language: z16.string().optional(),
|
|
15418
15956
|
/** Primary framework (e.g., 'Hono', 'Next.js', 'Express') */
|
|
15419
|
-
framework:
|
|
15957
|
+
framework: z16.string().optional(),
|
|
15420
15958
|
/** Technology stack items (e.g., ['Hono', 'Zod', 'Vitest']) */
|
|
15421
|
-
techStack:
|
|
15959
|
+
techStack: z16.array(z16.string()).default([]),
|
|
15422
15960
|
/** Domain flags from sealed analysis */
|
|
15423
|
-
domains:
|
|
15424
|
-
hasFrontend:
|
|
15425
|
-
hasBackend:
|
|
15426
|
-
hasDatabase:
|
|
15427
|
-
hasTesting:
|
|
15428
|
-
hasDocker:
|
|
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:
|
|
15969
|
+
fileCount: z16.number().optional(),
|
|
15432
15970
|
/** Available agent names (e.g., ['backend', 'testing']) */
|
|
15433
|
-
availableAgents:
|
|
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
|
|
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 =
|
|
15453
|
-
agents:
|
|
15454
|
-
patterns:
|
|
15455
|
-
checklist:
|
|
15456
|
-
modules:
|
|
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 =
|
|
15459
|
-
version:
|
|
15460
|
-
description:
|
|
15461
|
-
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
|
|
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 =
|
|
16237
|
+
EnvironmentBlockInputSchema = z18.object({
|
|
15694
16238
|
/** Project display name */
|
|
15695
|
-
projectName:
|
|
16239
|
+
projectName: z18.string(),
|
|
15696
16240
|
/** Absolute path to project root */
|
|
15697
|
-
projectPath:
|
|
16241
|
+
projectPath: z18.string(),
|
|
15698
16242
|
/** Whether the project is a git repository */
|
|
15699
|
-
isGitRepo:
|
|
16243
|
+
isGitRepo: z18.boolean().default(true),
|
|
15700
16244
|
/** Current git branch name */
|
|
15701
|
-
gitBranch:
|
|
16245
|
+
gitBranch: z18.string().optional(),
|
|
15702
16246
|
/** Operating system platform (auto-detected if not provided) */
|
|
15703
|
-
platform:
|
|
16247
|
+
platform: z18.string().optional(),
|
|
15704
16248
|
/** JavaScript runtime (auto-detected if not provided) */
|
|
15705
|
-
runtime:
|
|
16249
|
+
runtime: z18.string().optional(),
|
|
15706
16250
|
/** Current date in ISO format (auto-generated if not provided) */
|
|
15707
|
-
date:
|
|
16251
|
+
date: z18.string().optional(),
|
|
15708
16252
|
/** AI model identifier (e.g., 'opus', 'sonnet', '2.5-pro') */
|
|
15709
|
-
model:
|
|
16253
|
+
model: z18.string().optional(),
|
|
15710
16254
|
/** AI provider name (e.g., 'claude', 'gemini', 'cursor') */
|
|
15711
|
-
provider:
|
|
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.
|
|
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
|
|
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
|
-
${
|
|
31435
|
-
${
|
|
32175
|
+
${chalk20.cyan("p/")} prjct v${version}
|
|
32176
|
+
${chalk20.dim("Context layer for AI coding agents")}
|
|
31436
32177
|
|
|
31437
|
-
${
|
|
32178
|
+
${chalk20.dim("Providers:")}`);
|
|
31438
32179
|
if (detection.claude.installed) {
|
|
31439
|
-
const status = claudeConfigured ?
|
|
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}${
|
|
32182
|
+
console.log(` Claude Code ${status}${chalk20.dim(ver)}`);
|
|
31442
32183
|
} else {
|
|
31443
|
-
console.log(` Claude Code ${
|
|
32184
|
+
console.log(` Claude Code ${chalk20.dim("\u25CB not installed")}`);
|
|
31444
32185
|
}
|
|
31445
32186
|
if (detection.gemini.installed) {
|
|
31446
|
-
const status = geminiConfigured ?
|
|
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}${
|
|
32189
|
+
console.log(` Gemini CLI ${status}${chalk20.dim(ver)}`);
|
|
31449
32190
|
} else {
|
|
31450
|
-
console.log(` Gemini CLI ${
|
|
32191
|
+
console.log(` Gemini CLI ${chalk20.dim("\u25CB not installed")}`);
|
|
31451
32192
|
}
|
|
31452
32193
|
if (antigravityDetection.installed) {
|
|
31453
|
-
const status = antigravityDetection.skillInstalled ?
|
|
31454
|
-
const hint = antigravityDetection.skillInstalled ? "" : ` ${
|
|
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 ${
|
|
32198
|
+
console.log(` Antigravity ${chalk20.dim("\u25CB not installed")}`);
|
|
31458
32199
|
}
|
|
31459
32200
|
if (cursorConfigured) {
|
|
31460
|
-
console.log(` Cursor IDE ${
|
|
32201
|
+
console.log(` Cursor IDE ${chalk20.green("\u2713 ready")} ${chalk20.dim("(use /sync, /task)")}`);
|
|
31461
32202
|
} else if (cursorExists) {
|
|
31462
|
-
console.log(` Cursor IDE ${
|
|
32203
|
+
console.log(` Cursor IDE ${chalk20.yellow("\u25CF detected")} ${chalk20.dim("(run prjct init)")}`);
|
|
31463
32204
|
} else {
|
|
31464
|
-
console.log(` Cursor IDE ${
|
|
32205
|
+
console.log(` Cursor IDE ${chalk20.dim("\u25CB no .cursor/ folder")}`);
|
|
31465
32206
|
}
|
|
31466
32207
|
console.log(`
|
|
31467
|
-
${
|
|
31468
|
-
${
|
|
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
|
|
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
|
-
${
|
|
32573
|
-
${
|
|
33313
|
+
${chalk21.cyan("p/")} prjct v${VERSION}
|
|
33314
|
+
${chalk21.dim("Context layer for AI coding agents")}
|
|
32574
33315
|
|
|
32575
|
-
${
|
|
33316
|
+
${chalk21.dim("Providers:")}`);
|
|
32576
33317
|
if (detection.claude.installed) {
|
|
32577
|
-
const status = claudeConfigured ?
|
|
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}${
|
|
33320
|
+
console.log(` Claude Code ${status}${chalk21.dim(ver)}`);
|
|
32580
33321
|
} else {
|
|
32581
|
-
console.log(` Claude Code ${
|
|
33322
|
+
console.log(` Claude Code ${chalk21.dim("\u25CB not installed")}`);
|
|
32582
33323
|
}
|
|
32583
33324
|
if (detection.gemini.installed) {
|
|
32584
|
-
const status = geminiConfigured ?
|
|
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}${
|
|
33327
|
+
console.log(` Gemini CLI ${status}${chalk21.dim(ver)}`);
|
|
32587
33328
|
} else {
|
|
32588
|
-
console.log(` Gemini CLI ${
|
|
33329
|
+
console.log(` Gemini CLI ${chalk21.dim("\u25CB not installed")}`);
|
|
32589
33330
|
}
|
|
32590
33331
|
if (cursorDetected) {
|
|
32591
|
-
const status = cursorConfigured ?
|
|
32592
|
-
console.log(` Cursor IDE ${status}${
|
|
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 ${
|
|
33335
|
+
console.log(` Cursor IDE ${chalk21.dim("\u25CB not detected")}`);
|
|
32595
33336
|
}
|
|
32596
33337
|
if (windsurfDetected) {
|
|
32597
|
-
const status = windsurfConfigured ?
|
|
32598
|
-
console.log(` Windsurf IDE ${status}${
|
|
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 ${
|
|
33341
|
+
console.log(` Windsurf IDE ${chalk21.dim("\u25CB not detected")}`);
|
|
32601
33342
|
}
|
|
32602
33343
|
console.log(`
|
|
32603
|
-
${
|
|
32604
|
-
${
|
|
32605
|
-
${
|
|
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
|
-
${
|
|
33353
|
+
${chalk21.cyan.bold(" Welcome to prjct!")}
|
|
32613
33354
|
|
|
32614
|
-
Run ${
|
|
33355
|
+
Run ${chalk21.bold("prjct start")} to configure your AI providers.
|
|
32615
33356
|
|
|
32616
|
-
${
|
|
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
|
-
${
|
|
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();
|