prjct-cli 0.42.0 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +97 -0
- package/core/agentic/command-executor.ts +15 -5
- package/core/ai-tools/formatters.ts +302 -0
- package/core/ai-tools/generator.ts +124 -0
- package/core/ai-tools/index.ts +15 -0
- package/core/ai-tools/registry.ts +195 -0
- package/core/cli/linear.ts +61 -2
- package/core/commands/analysis.ts +36 -2
- package/core/commands/commands.ts +2 -2
- package/core/commands/planning.ts +8 -4
- package/core/commands/shipping.ts +9 -7
- package/core/commands/workflow.ts +67 -17
- package/core/index.ts +3 -1
- package/core/infrastructure/ai-provider.ts +11 -36
- package/core/integrations/issue-tracker/types.ts +7 -1
- package/core/integrations/linear/client.ts +56 -24
- package/core/integrations/linear/index.ts +3 -0
- package/core/integrations/linear/sync.ts +313 -0
- package/core/schemas/index.ts +3 -0
- package/core/schemas/issues.ts +144 -0
- package/core/schemas/state.ts +3 -0
- package/core/services/sync-service.ts +71 -4
- package/core/utils/agent-stream.ts +138 -0
- package/core/utils/branding.ts +2 -3
- package/core/utils/next-steps.ts +95 -0
- package/core/utils/output.ts +26 -0
- package/core/workflow/index.ts +6 -0
- package/core/workflow/state-machine.ts +185 -0
- package/dist/bin/prjct.mjs +2382 -541
- package/package.json +1 -1
- package/templates/_bases/tracker-base.md +11 -0
- package/templates/commands/done.md +18 -13
- package/templates/commands/git.md +143 -54
- package/templates/commands/merge.md +121 -13
- package/templates/commands/review.md +1 -1
- package/templates/commands/ship.md +165 -20
- package/templates/commands/sync.md +17 -0
- package/templates/commands/task.md +123 -17
- package/templates/global/ANTIGRAVITY.md +2 -4
- package/templates/global/CLAUDE.md +115 -28
- package/templates/global/CURSOR.mdc +1 -3
- package/templates/global/GEMINI.md +2 -4
- package/templates/global/WINDSURF.md +1 -3
- package/templates/subagents/workflow/prjct-shipper.md +1 -2
package/dist/bin/prjct.mjs
CHANGED
|
@@ -16,10 +16,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
16
16
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
17
17
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
18
18
|
});
|
|
19
|
-
var __glob = (map) => (
|
|
20
|
-
var fn = map[
|
|
19
|
+
var __glob = (map) => (path44) => {
|
|
20
|
+
var fn = map[path44];
|
|
21
21
|
if (fn) return fn();
|
|
22
|
-
throw new Error("Module not found in bundle: " +
|
|
22
|
+
throw new Error("Module not found in bundle: " + path44);
|
|
23
23
|
};
|
|
24
24
|
var __esm = (fn, res) => function __init() {
|
|
25
25
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -3330,7 +3330,12 @@ var init_state = __esm({
|
|
|
3330
3330
|
// Subtask tracking for fragmented tasks
|
|
3331
3331
|
subtasks: z2.array(SubtaskSchema).optional(),
|
|
3332
3332
|
currentSubtaskIndex: z2.number().optional(),
|
|
3333
|
-
subtaskProgress: SubtaskProgressSchema.optional()
|
|
3333
|
+
subtaskProgress: SubtaskProgressSchema.optional(),
|
|
3334
|
+
// Linear integration - bidirectional sync
|
|
3335
|
+
linearId: z2.string().optional(),
|
|
3336
|
+
// "PRJ-123" - Linear identifier
|
|
3337
|
+
linearUuid: z2.string().optional()
|
|
3338
|
+
// Linear internal UUID for API calls
|
|
3334
3339
|
});
|
|
3335
3340
|
PreviousTaskSchema = z2.object({
|
|
3336
3341
|
id: z2.string(),
|
|
@@ -3399,26 +3404,108 @@ var init_state = __esm({
|
|
|
3399
3404
|
}
|
|
3400
3405
|
});
|
|
3401
3406
|
|
|
3402
|
-
// core/schemas/
|
|
3407
|
+
// core/schemas/issues.ts
|
|
3403
3408
|
import { z as z3 } from "zod";
|
|
3409
|
+
function createEmptyIssues(provider) {
|
|
3410
|
+
return {
|
|
3411
|
+
provider,
|
|
3412
|
+
lastSync: "",
|
|
3413
|
+
staleAfter: 18e5,
|
|
3414
|
+
issues: {}
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
var IssueProviderSchema, IssueStatusSchema, IssuePrioritySchema, IssueTypeSchema, CachedIssueSchema, IssuesJsonSchema, SyncResultSchema, parseIssues;
|
|
3418
|
+
var init_issues = __esm({
|
|
3419
|
+
"core/schemas/issues.ts"() {
|
|
3420
|
+
"use strict";
|
|
3421
|
+
IssueProviderSchema = z3.enum(["linear", "jira", "github", "monday", "asana", "none"]);
|
|
3422
|
+
IssueStatusSchema = z3.enum(["backlog", "todo", "in_progress", "in_review", "done", "cancelled"]);
|
|
3423
|
+
IssuePrioritySchema = z3.enum(["none", "urgent", "high", "medium", "low"]);
|
|
3424
|
+
IssueTypeSchema = z3.enum(["feature", "bug", "improvement", "task", "chore", "epic"]);
|
|
3425
|
+
CachedIssueSchema = z3.object({
|
|
3426
|
+
// Core identifiers
|
|
3427
|
+
id: z3.string(),
|
|
3428
|
+
// Provider UUID
|
|
3429
|
+
identifier: z3.string(),
|
|
3430
|
+
// Human-readable ID (e.g., "PRJ-123")
|
|
3431
|
+
// Issue content
|
|
3432
|
+
title: z3.string(),
|
|
3433
|
+
description: z3.string().optional(),
|
|
3434
|
+
// State
|
|
3435
|
+
status: IssueStatusSchema,
|
|
3436
|
+
priority: IssuePrioritySchema,
|
|
3437
|
+
type: IssueTypeSchema.optional(),
|
|
3438
|
+
// Metadata
|
|
3439
|
+
assignee: z3.object({
|
|
3440
|
+
id: z3.string(),
|
|
3441
|
+
name: z3.string(),
|
|
3442
|
+
email: z3.string().optional()
|
|
3443
|
+
}).optional(),
|
|
3444
|
+
labels: z3.array(z3.string()).default([]),
|
|
3445
|
+
team: z3.object({
|
|
3446
|
+
id: z3.string(),
|
|
3447
|
+
name: z3.string(),
|
|
3448
|
+
key: z3.string().optional()
|
|
3449
|
+
}).optional(),
|
|
3450
|
+
project: z3.object({
|
|
3451
|
+
id: z3.string(),
|
|
3452
|
+
name: z3.string()
|
|
3453
|
+
}).optional(),
|
|
3454
|
+
// URLs and timestamps
|
|
3455
|
+
url: z3.string(),
|
|
3456
|
+
createdAt: z3.string(),
|
|
3457
|
+
// ISO8601 from provider
|
|
3458
|
+
updatedAt: z3.string(),
|
|
3459
|
+
// ISO8601 from provider
|
|
3460
|
+
fetchedAt: z3.string()
|
|
3461
|
+
// ISO8601 when we cached it
|
|
3462
|
+
});
|
|
3463
|
+
IssuesJsonSchema = z3.object({
|
|
3464
|
+
// Provider info
|
|
3465
|
+
provider: IssueProviderSchema,
|
|
3466
|
+
// Sync metadata
|
|
3467
|
+
lastSync: z3.string(),
|
|
3468
|
+
// ISO8601 of last full sync
|
|
3469
|
+
staleAfter: z3.number().default(18e5),
|
|
3470
|
+
// 30 minutes in ms
|
|
3471
|
+
// Issues map: identifier -> issue
|
|
3472
|
+
issues: z3.record(z3.string(), CachedIssueSchema)
|
|
3473
|
+
});
|
|
3474
|
+
SyncResultSchema = z3.object({
|
|
3475
|
+
provider: IssueProviderSchema,
|
|
3476
|
+
fetched: z3.number(),
|
|
3477
|
+
updated: z3.number(),
|
|
3478
|
+
errors: z3.array(z3.object({
|
|
3479
|
+
issueId: z3.string(),
|
|
3480
|
+
error: z3.string()
|
|
3481
|
+
})),
|
|
3482
|
+
timestamp: z3.string()
|
|
3483
|
+
});
|
|
3484
|
+
parseIssues = /* @__PURE__ */ __name((data) => IssuesJsonSchema.parse(data), "parseIssues");
|
|
3485
|
+
__name(createEmptyIssues, "createEmptyIssues");
|
|
3486
|
+
}
|
|
3487
|
+
});
|
|
3488
|
+
|
|
3489
|
+
// core/schemas/project.ts
|
|
3490
|
+
import { z as z4 } from "zod";
|
|
3404
3491
|
var ProjectItemSchema, DEFAULT_PROJECT;
|
|
3405
3492
|
var init_project = __esm({
|
|
3406
3493
|
"core/schemas/project.ts"() {
|
|
3407
3494
|
"use strict";
|
|
3408
|
-
ProjectItemSchema =
|
|
3409
|
-
projectId:
|
|
3410
|
-
name:
|
|
3411
|
-
repoPath:
|
|
3412
|
-
description:
|
|
3413
|
-
version:
|
|
3414
|
-
cliVersion:
|
|
3495
|
+
ProjectItemSchema = z4.object({
|
|
3496
|
+
projectId: z4.string(),
|
|
3497
|
+
name: z4.string(),
|
|
3498
|
+
repoPath: z4.string(),
|
|
3499
|
+
description: z4.string().optional(),
|
|
3500
|
+
version: z4.string().optional(),
|
|
3501
|
+
cliVersion: z4.string().optional(),
|
|
3415
3502
|
// prjct-cli version used to sync
|
|
3416
|
-
techStack:
|
|
3417
|
-
fileCount:
|
|
3418
|
-
commitCount:
|
|
3419
|
-
createdAt:
|
|
3503
|
+
techStack: z4.array(z4.string()),
|
|
3504
|
+
fileCount: z4.number(),
|
|
3505
|
+
commitCount: z4.number(),
|
|
3506
|
+
createdAt: z4.string(),
|
|
3420
3507
|
// ISO8601
|
|
3421
|
-
lastSync:
|
|
3508
|
+
lastSync: z4.string()
|
|
3422
3509
|
// ISO8601
|
|
3423
3510
|
});
|
|
3424
3511
|
DEFAULT_PROJECT = {
|
|
@@ -3439,74 +3526,74 @@ var init_agents = __esm({
|
|
|
3439
3526
|
});
|
|
3440
3527
|
|
|
3441
3528
|
// core/schemas/ideas.ts
|
|
3442
|
-
import { z as
|
|
3529
|
+
import { z as z5 } from "zod";
|
|
3443
3530
|
var IdeaPrioritySchema, IdeaStatusSchema, ImpactLevelSchema, ImpactEffortSchema, TechStackSchema, IdeaModuleSchema, IdeaRoleSchema, IdeaItemSchema, IdeasJsonSchema, DEFAULT_IDEA;
|
|
3444
3531
|
var init_ideas = __esm({
|
|
3445
3532
|
"core/schemas/ideas.ts"() {
|
|
3446
3533
|
"use strict";
|
|
3447
|
-
IdeaPrioritySchema =
|
|
3448
|
-
IdeaStatusSchema =
|
|
3449
|
-
ImpactLevelSchema =
|
|
3450
|
-
ImpactEffortSchema =
|
|
3534
|
+
IdeaPrioritySchema = z5.enum(["low", "medium", "high"]);
|
|
3535
|
+
IdeaStatusSchema = z5.enum(["pending", "converted", "completed", "archived"]);
|
|
3536
|
+
ImpactLevelSchema = z5.enum(["high", "medium", "low"]);
|
|
3537
|
+
ImpactEffortSchema = z5.object({
|
|
3451
3538
|
impact: ImpactLevelSchema,
|
|
3452
3539
|
effort: ImpactLevelSchema
|
|
3453
3540
|
});
|
|
3454
|
-
TechStackSchema =
|
|
3455
|
-
frontend:
|
|
3541
|
+
TechStackSchema = z5.object({
|
|
3542
|
+
frontend: z5.string().optional(),
|
|
3456
3543
|
// "Next.js 14, HeroUI"
|
|
3457
|
-
backend:
|
|
3544
|
+
backend: z5.string().optional(),
|
|
3458
3545
|
// "Supabase (Auth, DB, RLS, Realtime)"
|
|
3459
|
-
payments:
|
|
3546
|
+
payments: z5.string().optional(),
|
|
3460
3547
|
// "Stripe Billing"
|
|
3461
|
-
ai:
|
|
3548
|
+
ai: z5.string().optional(),
|
|
3462
3549
|
// "Vercel AI SDK"
|
|
3463
|
-
deploy:
|
|
3550
|
+
deploy: z5.string().optional(),
|
|
3464
3551
|
// "Vercel"
|
|
3465
|
-
other:
|
|
3552
|
+
other: z5.array(z5.string()).optional()
|
|
3466
3553
|
});
|
|
3467
|
-
IdeaModuleSchema =
|
|
3468
|
-
name:
|
|
3554
|
+
IdeaModuleSchema = z5.object({
|
|
3555
|
+
name: z5.string(),
|
|
3469
3556
|
// "Multi-tenant"
|
|
3470
|
-
description:
|
|
3557
|
+
description: z5.string()
|
|
3471
3558
|
// "Empresas con RLS estricto"
|
|
3472
3559
|
});
|
|
3473
|
-
IdeaRoleSchema =
|
|
3474
|
-
name:
|
|
3560
|
+
IdeaRoleSchema = z5.object({
|
|
3561
|
+
name: z5.string(),
|
|
3475
3562
|
// "SUPER_ADMIN"
|
|
3476
|
-
description:
|
|
3563
|
+
description: z5.string().optional()
|
|
3477
3564
|
});
|
|
3478
|
-
IdeaItemSchema =
|
|
3479
|
-
id:
|
|
3565
|
+
IdeaItemSchema = z5.object({
|
|
3566
|
+
id: z5.string(),
|
|
3480
3567
|
// idea_xxxxxxxx
|
|
3481
|
-
text:
|
|
3568
|
+
text: z5.string(),
|
|
3482
3569
|
// Title/summary
|
|
3483
|
-
details:
|
|
3570
|
+
details: z5.string().optional(),
|
|
3484
3571
|
priority: IdeaPrioritySchema,
|
|
3485
3572
|
status: IdeaStatusSchema,
|
|
3486
|
-
tags:
|
|
3487
|
-
addedAt:
|
|
3573
|
+
tags: z5.array(z5.string()),
|
|
3574
|
+
addedAt: z5.string(),
|
|
3488
3575
|
// ISO8601
|
|
3489
|
-
completedAt:
|
|
3490
|
-
convertedTo:
|
|
3576
|
+
completedAt: z5.string().optional(),
|
|
3577
|
+
convertedTo: z5.string().optional(),
|
|
3491
3578
|
// Source documentation
|
|
3492
|
-
source:
|
|
3493
|
-
sourceFiles:
|
|
3579
|
+
source: z5.string().optional(),
|
|
3580
|
+
sourceFiles: z5.array(z5.string()).optional(),
|
|
3494
3581
|
// Enriched fields from MD
|
|
3495
|
-
painPoints:
|
|
3496
|
-
solutions:
|
|
3497
|
-
filesAffected:
|
|
3582
|
+
painPoints: z5.array(z5.string()).optional(),
|
|
3583
|
+
solutions: z5.array(z5.string()).optional(),
|
|
3584
|
+
filesAffected: z5.array(z5.string()).optional(),
|
|
3498
3585
|
impactEffort: ImpactEffortSchema.optional(),
|
|
3499
|
-
implementationNotes:
|
|
3586
|
+
implementationNotes: z5.string().optional(),
|
|
3500
3587
|
// Technical spec fields for ZERO DATA LOSS
|
|
3501
3588
|
stack: TechStackSchema.optional(),
|
|
3502
|
-
modules:
|
|
3503
|
-
roles:
|
|
3504
|
-
risks:
|
|
3505
|
-
risksCount:
|
|
3589
|
+
modules: z5.array(IdeaModuleSchema).optional(),
|
|
3590
|
+
roles: z5.array(IdeaRoleSchema).optional(),
|
|
3591
|
+
risks: z5.array(z5.string()).optional(),
|
|
3592
|
+
risksCount: z5.number().optional()
|
|
3506
3593
|
});
|
|
3507
|
-
IdeasJsonSchema =
|
|
3508
|
-
ideas:
|
|
3509
|
-
lastUpdated:
|
|
3594
|
+
IdeasJsonSchema = z5.object({
|
|
3595
|
+
ideas: z5.array(IdeaItemSchema),
|
|
3596
|
+
lastUpdated: z5.string()
|
|
3510
3597
|
});
|
|
3511
3598
|
DEFAULT_IDEA = {
|
|
3512
3599
|
priority: "medium",
|
|
@@ -3518,174 +3605,174 @@ var init_ideas = __esm({
|
|
|
3518
3605
|
});
|
|
3519
3606
|
|
|
3520
3607
|
// core/schemas/roadmap.ts
|
|
3521
|
-
import { z as
|
|
3608
|
+
import { z as z6 } from "zod";
|
|
3522
3609
|
var FeatureStatusSchema, FeatureImpactSchema, FeatureTypeSchema, PhaseStatusSchema, QuarterStatusSchema, InferredFromSchema, FeatureTaskSchema, RoadmapPhaseSchema, RoadmapStrategySchema, FeatureDurationSchema, GitCommitSchema, EffortEstimateSchema, EffortActualSchema, FeatureEffortSchema, QuarterCapacitySchema, QuarterSchema, FeatureItemSchema, BacklogItemSchema, RoadmapJsonSchema, DEFAULT_FEATURE;
|
|
3523
3610
|
var init_roadmap = __esm({
|
|
3524
3611
|
"core/schemas/roadmap.ts"() {
|
|
3525
3612
|
"use strict";
|
|
3526
|
-
FeatureStatusSchema =
|
|
3527
|
-
FeatureImpactSchema =
|
|
3528
|
-
FeatureTypeSchema =
|
|
3529
|
-
PhaseStatusSchema =
|
|
3530
|
-
QuarterStatusSchema =
|
|
3531
|
-
InferredFromSchema =
|
|
3532
|
-
FeatureTaskSchema =
|
|
3533
|
-
id:
|
|
3613
|
+
FeatureStatusSchema = z6.enum(["planned", "active", "completed", "shipped"]);
|
|
3614
|
+
FeatureImpactSchema = z6.enum(["low", "medium", "high"]);
|
|
3615
|
+
FeatureTypeSchema = z6.enum(["feature", "breaking_change", "refactor", "infrastructure"]);
|
|
3616
|
+
PhaseStatusSchema = z6.enum(["completed", "active", "planned"]);
|
|
3617
|
+
QuarterStatusSchema = z6.enum(["planned", "active", "completed"]);
|
|
3618
|
+
InferredFromSchema = z6.enum(["git", "git-branch", "manual", "prd"]);
|
|
3619
|
+
FeatureTaskSchema = z6.object({
|
|
3620
|
+
id: z6.string(),
|
|
3534
3621
|
// task_xxxxxxxx
|
|
3535
|
-
description:
|
|
3536
|
-
completed:
|
|
3537
|
-
completedAt:
|
|
3622
|
+
description: z6.string(),
|
|
3623
|
+
completed: z6.boolean(),
|
|
3624
|
+
completedAt: z6.string().optional()
|
|
3538
3625
|
});
|
|
3539
|
-
RoadmapPhaseSchema =
|
|
3540
|
-
id:
|
|
3626
|
+
RoadmapPhaseSchema = z6.object({
|
|
3627
|
+
id: z6.string(),
|
|
3541
3628
|
// P0, P1, etc.
|
|
3542
|
-
name:
|
|
3629
|
+
name: z6.string(),
|
|
3543
3630
|
status: PhaseStatusSchema,
|
|
3544
|
-
completedAt:
|
|
3631
|
+
completedAt: z6.string().optional()
|
|
3545
3632
|
});
|
|
3546
|
-
RoadmapStrategySchema =
|
|
3547
|
-
goal:
|
|
3548
|
-
phases:
|
|
3549
|
-
successMetrics:
|
|
3633
|
+
RoadmapStrategySchema = z6.object({
|
|
3634
|
+
goal: z6.string(),
|
|
3635
|
+
phases: z6.array(RoadmapPhaseSchema),
|
|
3636
|
+
successMetrics: z6.array(z6.string()).optional()
|
|
3550
3637
|
});
|
|
3551
|
-
FeatureDurationSchema =
|
|
3552
|
-
hours:
|
|
3553
|
-
minutes:
|
|
3554
|
-
totalMinutes:
|
|
3555
|
-
display:
|
|
3638
|
+
FeatureDurationSchema = z6.object({
|
|
3639
|
+
hours: z6.number(),
|
|
3640
|
+
minutes: z6.number(),
|
|
3641
|
+
totalMinutes: z6.number(),
|
|
3642
|
+
display: z6.string().optional()
|
|
3556
3643
|
});
|
|
3557
|
-
GitCommitSchema =
|
|
3558
|
-
hash:
|
|
3559
|
-
message:
|
|
3560
|
-
date:
|
|
3561
|
-
author:
|
|
3644
|
+
GitCommitSchema = z6.object({
|
|
3645
|
+
hash: z6.string(),
|
|
3646
|
+
message: z6.string(),
|
|
3647
|
+
date: z6.string(),
|
|
3648
|
+
author: z6.string().optional()
|
|
3562
3649
|
});
|
|
3563
|
-
EffortEstimateSchema =
|
|
3564
|
-
hours:
|
|
3565
|
-
confidence:
|
|
3566
|
-
breakdown:
|
|
3567
|
-
area:
|
|
3568
|
-
hours:
|
|
3650
|
+
EffortEstimateSchema = z6.object({
|
|
3651
|
+
hours: z6.number(),
|
|
3652
|
+
confidence: z6.enum(["low", "medium", "high"]).optional(),
|
|
3653
|
+
breakdown: z6.array(z6.object({
|
|
3654
|
+
area: z6.string(),
|
|
3655
|
+
hours: z6.number()
|
|
3569
3656
|
})).optional()
|
|
3570
3657
|
});
|
|
3571
|
-
EffortActualSchema =
|
|
3572
|
-
hours:
|
|
3573
|
-
commits:
|
|
3574
|
-
linesAdded:
|
|
3575
|
-
linesRemoved:
|
|
3658
|
+
EffortActualSchema = z6.object({
|
|
3659
|
+
hours: z6.number().optional(),
|
|
3660
|
+
commits: z6.number().optional(),
|
|
3661
|
+
linesAdded: z6.number().optional(),
|
|
3662
|
+
linesRemoved: z6.number().optional()
|
|
3576
3663
|
});
|
|
3577
|
-
FeatureEffortSchema =
|
|
3664
|
+
FeatureEffortSchema = z6.object({
|
|
3578
3665
|
estimated: EffortEstimateSchema.nullable(),
|
|
3579
3666
|
actual: EffortActualSchema.nullable()
|
|
3580
3667
|
});
|
|
3581
|
-
QuarterCapacitySchema =
|
|
3582
|
-
totalHours:
|
|
3583
|
-
allocatedHours:
|
|
3584
|
-
bufferPercent:
|
|
3668
|
+
QuarterCapacitySchema = z6.object({
|
|
3669
|
+
totalHours: z6.number(),
|
|
3670
|
+
allocatedHours: z6.number(),
|
|
3671
|
+
bufferPercent: z6.number().optional()
|
|
3585
3672
|
// % reserved for unknowns
|
|
3586
3673
|
});
|
|
3587
|
-
QuarterSchema =
|
|
3588
|
-
id:
|
|
3674
|
+
QuarterSchema = z6.object({
|
|
3675
|
+
id: z6.string(),
|
|
3589
3676
|
// Q1-2026
|
|
3590
|
-
name:
|
|
3677
|
+
name: z6.string(),
|
|
3591
3678
|
// "Q1 2026"
|
|
3592
|
-
theme:
|
|
3679
|
+
theme: z6.string().optional(),
|
|
3593
3680
|
// "Foundation"
|
|
3594
|
-
goals:
|
|
3595
|
-
features:
|
|
3681
|
+
goals: z6.array(z6.string()).optional(),
|
|
3682
|
+
features: z6.array(z6.string()),
|
|
3596
3683
|
// Feature IDs
|
|
3597
3684
|
capacity: QuarterCapacitySchema.optional(),
|
|
3598
3685
|
status: QuarterStatusSchema,
|
|
3599
|
-
startDate:
|
|
3686
|
+
startDate: z6.string().optional(),
|
|
3600
3687
|
// ISO8601
|
|
3601
|
-
endDate:
|
|
3688
|
+
endDate: z6.string().optional()
|
|
3602
3689
|
// ISO8601
|
|
3603
3690
|
});
|
|
3604
|
-
FeatureItemSchema =
|
|
3605
|
-
id:
|
|
3691
|
+
FeatureItemSchema = z6.object({
|
|
3692
|
+
id: z6.string(),
|
|
3606
3693
|
// feat_xxxxxxxx
|
|
3607
|
-
name:
|
|
3608
|
-
description:
|
|
3609
|
-
date:
|
|
3694
|
+
name: z6.string(),
|
|
3695
|
+
description: z6.string().optional(),
|
|
3696
|
+
date: z6.string(),
|
|
3610
3697
|
// YYYY-MM-DD creation date
|
|
3611
3698
|
status: FeatureStatusSchema,
|
|
3612
3699
|
impact: FeatureImpactSchema,
|
|
3613
|
-
effort:
|
|
3614
|
-
progress:
|
|
3700
|
+
effort: z6.string().optional(),
|
|
3701
|
+
progress: z6.number(),
|
|
3615
3702
|
// 0-100
|
|
3616
3703
|
// Enriched fields from MD
|
|
3617
3704
|
type: FeatureTypeSchema.optional(),
|
|
3618
|
-
roi:
|
|
3705
|
+
roi: z6.number().optional(),
|
|
3619
3706
|
// 1-5 from star count
|
|
3620
|
-
why:
|
|
3621
|
-
technicalNotes:
|
|
3622
|
-
compatibility:
|
|
3623
|
-
phase:
|
|
3707
|
+
why: z6.array(z6.string()).optional(),
|
|
3708
|
+
technicalNotes: z6.array(z6.string()).optional(),
|
|
3709
|
+
compatibility: z6.string().optional(),
|
|
3710
|
+
phase: z6.string().optional(),
|
|
3624
3711
|
// P0, P1, etc.
|
|
3625
|
-
tasks:
|
|
3626
|
-
createdAt:
|
|
3712
|
+
tasks: z6.array(FeatureTaskSchema),
|
|
3713
|
+
createdAt: z6.string(),
|
|
3627
3714
|
// ISO8601
|
|
3628
|
-
shippedAt:
|
|
3629
|
-
version:
|
|
3715
|
+
shippedAt: z6.string().optional(),
|
|
3716
|
+
version: z6.string().optional(),
|
|
3630
3717
|
// ZERO DATA LOSS - additional fields
|
|
3631
3718
|
duration: FeatureDurationSchema.optional(),
|
|
3632
|
-
taskCount:
|
|
3633
|
-
agent:
|
|
3719
|
+
taskCount: z6.number().optional(),
|
|
3720
|
+
agent: z6.string().optional(),
|
|
3634
3721
|
// "fe+be", "fe", "be"
|
|
3635
|
-
sprintName:
|
|
3636
|
-
completedDate:
|
|
3722
|
+
sprintName: z6.string().optional(),
|
|
3723
|
+
completedDate: z6.string().optional(),
|
|
3637
3724
|
// =========================================================================
|
|
3638
3725
|
// AI ORCHESTRATION FIELDS (v0.29.0)
|
|
3639
3726
|
// =========================================================================
|
|
3640
3727
|
// PRD Integration
|
|
3641
|
-
prdId:
|
|
3728
|
+
prdId: z6.string().nullable().optional(),
|
|
3642
3729
|
// Link to PRD (prd_xxxxxxxx)
|
|
3643
3730
|
// Legacy Support (for existing projects)
|
|
3644
|
-
legacy:
|
|
3731
|
+
legacy: z6.boolean().optional(),
|
|
3645
3732
|
// true = no PRD required
|
|
3646
3733
|
inferredFrom: InferredFromSchema.optional(),
|
|
3647
3734
|
// git, git-branch, manual, prd
|
|
3648
3735
|
// Quarter Planning
|
|
3649
|
-
quarter:
|
|
3736
|
+
quarter: z6.string().nullable().optional(),
|
|
3650
3737
|
// Q1-2026, etc.
|
|
3651
3738
|
// Dependency Tracking
|
|
3652
|
-
dependencies:
|
|
3739
|
+
dependencies: z6.array(z6.string()).optional(),
|
|
3653
3740
|
// Feature IDs this depends on
|
|
3654
|
-
blockedBy:
|
|
3741
|
+
blockedBy: z6.array(z6.string()).optional(),
|
|
3655
3742
|
// Feature IDs blocking this
|
|
3656
3743
|
// Effort Tracking (for PRD comparison)
|
|
3657
3744
|
effortTracking: FeatureEffortSchema.optional(),
|
|
3658
3745
|
// Value Scoring (calculated from PRD)
|
|
3659
|
-
valueScore:
|
|
3746
|
+
valueScore: z6.number().optional(),
|
|
3660
3747
|
// Calculated priority score
|
|
3661
3748
|
// Git Data (for legacy features)
|
|
3662
|
-
commits:
|
|
3749
|
+
commits: z6.array(GitCommitSchema).optional(),
|
|
3663
3750
|
// Commits for this feature
|
|
3664
|
-
branch:
|
|
3751
|
+
branch: z6.string().optional(),
|
|
3665
3752
|
// Branch name (for active)
|
|
3666
|
-
commitsAhead:
|
|
3753
|
+
commitsAhead: z6.number().optional()
|
|
3667
3754
|
// Commits ahead of main
|
|
3668
3755
|
});
|
|
3669
|
-
BacklogItemSchema =
|
|
3670
|
-
id:
|
|
3671
|
-
title:
|
|
3672
|
-
prdId:
|
|
3673
|
-
valueScore:
|
|
3674
|
-
effortEstimate:
|
|
3675
|
-
reason:
|
|
3756
|
+
BacklogItemSchema = z6.object({
|
|
3757
|
+
id: z6.string(),
|
|
3758
|
+
title: z6.string(),
|
|
3759
|
+
prdId: z6.string().nullable().optional(),
|
|
3760
|
+
valueScore: z6.number().optional(),
|
|
3761
|
+
effortEstimate: z6.number().optional(),
|
|
3762
|
+
reason: z6.string().optional()
|
|
3676
3763
|
// Why in backlog
|
|
3677
3764
|
});
|
|
3678
|
-
RoadmapJsonSchema =
|
|
3765
|
+
RoadmapJsonSchema = z6.object({
|
|
3679
3766
|
strategy: RoadmapStrategySchema.nullable().optional(),
|
|
3680
|
-
features:
|
|
3681
|
-
backlog:
|
|
3767
|
+
features: z6.array(FeatureItemSchema),
|
|
3768
|
+
backlog: z6.array(z6.union([z6.string(), BacklogItemSchema])),
|
|
3682
3769
|
// Support both formats
|
|
3683
|
-
lastUpdated:
|
|
3770
|
+
lastUpdated: z6.string(),
|
|
3684
3771
|
// AI ORCHESTRATION FIELDS (v0.29.0)
|
|
3685
|
-
quarters:
|
|
3772
|
+
quarters: z6.array(QuarterSchema).optional(),
|
|
3686
3773
|
// Metadata (for git-inferred roadmaps)
|
|
3687
|
-
generatedFrom:
|
|
3688
|
-
generatedAt:
|
|
3774
|
+
generatedFrom: z6.enum(["git-history", "manual", "prd"]).optional(),
|
|
3775
|
+
generatedAt: z6.string().optional()
|
|
3689
3776
|
});
|
|
3690
3777
|
DEFAULT_FEATURE = {
|
|
3691
3778
|
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
@@ -3703,64 +3790,64 @@ var init_roadmap = __esm({
|
|
|
3703
3790
|
});
|
|
3704
3791
|
|
|
3705
3792
|
// core/schemas/shipped.ts
|
|
3706
|
-
import { z as
|
|
3793
|
+
import { z as z7 } from "zod";
|
|
3707
3794
|
var ShipTypeSchema, CheckStatusSchema, ChangeTypeSchema, DurationSchema, CodeMetricsSchema, ShipChangeSchema, QualityMetricsSchema, CommitInfoSchema, ShippedItemSchema, ShippedJsonSchema;
|
|
3708
3795
|
var init_shipped = __esm({
|
|
3709
3796
|
"core/schemas/shipped.ts"() {
|
|
3710
3797
|
"use strict";
|
|
3711
|
-
ShipTypeSchema =
|
|
3712
|
-
CheckStatusSchema =
|
|
3713
|
-
ChangeTypeSchema =
|
|
3714
|
-
DurationSchema =
|
|
3715
|
-
hours:
|
|
3716
|
-
minutes:
|
|
3717
|
-
totalMinutes:
|
|
3798
|
+
ShipTypeSchema = z7.enum(["feature", "fix", "improvement", "refactor"]);
|
|
3799
|
+
CheckStatusSchema = z7.enum(["pass", "warning", "fail", "skipped"]);
|
|
3800
|
+
ChangeTypeSchema = z7.enum(["added", "changed", "fixed", "removed"]);
|
|
3801
|
+
DurationSchema = z7.object({
|
|
3802
|
+
hours: z7.number(),
|
|
3803
|
+
minutes: z7.number(),
|
|
3804
|
+
totalMinutes: z7.number()
|
|
3718
3805
|
});
|
|
3719
|
-
CodeMetricsSchema =
|
|
3720
|
-
filesChanged:
|
|
3721
|
-
linesAdded:
|
|
3722
|
-
linesRemoved:
|
|
3723
|
-
commits:
|
|
3806
|
+
CodeMetricsSchema = z7.object({
|
|
3807
|
+
filesChanged: z7.number().nullable().optional(),
|
|
3808
|
+
linesAdded: z7.number().nullable().optional(),
|
|
3809
|
+
linesRemoved: z7.number().nullable().optional(),
|
|
3810
|
+
commits: z7.number().nullable().optional()
|
|
3724
3811
|
});
|
|
3725
|
-
ShipChangeSchema =
|
|
3726
|
-
description:
|
|
3812
|
+
ShipChangeSchema = z7.object({
|
|
3813
|
+
description: z7.string(),
|
|
3727
3814
|
type: ChangeTypeSchema.optional()
|
|
3728
3815
|
});
|
|
3729
|
-
QualityMetricsSchema =
|
|
3816
|
+
QualityMetricsSchema = z7.object({
|
|
3730
3817
|
lintStatus: CheckStatusSchema.nullable().optional(),
|
|
3731
|
-
lintDetails:
|
|
3818
|
+
lintDetails: z7.string().optional(),
|
|
3732
3819
|
testStatus: CheckStatusSchema.nullable().optional(),
|
|
3733
|
-
testDetails:
|
|
3820
|
+
testDetails: z7.string().optional()
|
|
3734
3821
|
});
|
|
3735
|
-
CommitInfoSchema =
|
|
3736
|
-
hash:
|
|
3737
|
-
message:
|
|
3738
|
-
branch:
|
|
3822
|
+
CommitInfoSchema = z7.object({
|
|
3823
|
+
hash: z7.string().optional(),
|
|
3824
|
+
message: z7.string().optional(),
|
|
3825
|
+
branch: z7.string().optional()
|
|
3739
3826
|
});
|
|
3740
|
-
ShippedItemSchema =
|
|
3741
|
-
id:
|
|
3827
|
+
ShippedItemSchema = z7.object({
|
|
3828
|
+
id: z7.string(),
|
|
3742
3829
|
// ship_xxxxxxxx
|
|
3743
|
-
name:
|
|
3744
|
-
version:
|
|
3830
|
+
name: z7.string(),
|
|
3831
|
+
version: z7.string().nullable().optional(),
|
|
3745
3832
|
type: ShipTypeSchema,
|
|
3746
|
-
agent:
|
|
3833
|
+
agent: z7.string().optional(),
|
|
3747
3834
|
// "fe+be", "be", "fe"
|
|
3748
|
-
description:
|
|
3749
|
-
changes:
|
|
3750
|
-
codeSnippets:
|
|
3835
|
+
description: z7.string().optional(),
|
|
3836
|
+
changes: z7.array(ShipChangeSchema),
|
|
3837
|
+
codeSnippets: z7.array(z7.string()).optional(),
|
|
3751
3838
|
commit: CommitInfoSchema.optional(),
|
|
3752
3839
|
codeMetrics: CodeMetricsSchema.optional(),
|
|
3753
3840
|
qualityMetrics: QualityMetricsSchema.optional(),
|
|
3754
|
-
quantitativeImpact:
|
|
3841
|
+
quantitativeImpact: z7.string().optional(),
|
|
3755
3842
|
duration: DurationSchema.optional(),
|
|
3756
|
-
tasksCompleted:
|
|
3757
|
-
shippedAt:
|
|
3843
|
+
tasksCompleted: z7.number().nullable().optional(),
|
|
3844
|
+
shippedAt: z7.string(),
|
|
3758
3845
|
// ISO8601
|
|
3759
|
-
featureId:
|
|
3846
|
+
featureId: z7.string().optional()
|
|
3760
3847
|
});
|
|
3761
|
-
ShippedJsonSchema =
|
|
3762
|
-
items:
|
|
3763
|
-
lastUpdated:
|
|
3848
|
+
ShippedJsonSchema = z7.object({
|
|
3849
|
+
items: z7.array(ShippedItemSchema),
|
|
3850
|
+
lastUpdated: z7.string()
|
|
3764
3851
|
});
|
|
3765
3852
|
}
|
|
3766
3853
|
});
|
|
@@ -3783,15 +3870,15 @@ var init_analysis = __esm({
|
|
|
3783
3870
|
});
|
|
3784
3871
|
|
|
3785
3872
|
// core/schemas/outcomes.ts
|
|
3786
|
-
import { z as
|
|
3873
|
+
import { z as z8 } from "zod";
|
|
3787
3874
|
var QualityScoreSchema, SuccessLevelSchema, WorthAssessmentSchema, VarianceReasonSchema, EffortComparisonSchema, MetricResultSchema, AcceptanceCriteriaResultSchema, SuccessTrackingSchema, LearningSchema, LearningsSchema, ROIAssessmentSchema, TaskOutcomeSchema, FeatureOutcomeSchema, AggregateMetricsSchema, OutcomesJsonSchema;
|
|
3788
3875
|
var init_outcomes = __esm({
|
|
3789
3876
|
"core/schemas/outcomes.ts"() {
|
|
3790
3877
|
"use strict";
|
|
3791
|
-
QualityScoreSchema =
|
|
3792
|
-
SuccessLevelSchema =
|
|
3793
|
-
WorthAssessmentSchema =
|
|
3794
|
-
VarianceReasonSchema =
|
|
3878
|
+
QualityScoreSchema = z8.number().min(1).max(5);
|
|
3879
|
+
SuccessLevelSchema = z8.enum(["exceeded", "met", "partial", "failed"]);
|
|
3880
|
+
WorthAssessmentSchema = z8.enum(["definitely", "probably", "maybe", "no"]);
|
|
3881
|
+
VarianceReasonSchema = z8.enum([
|
|
3795
3882
|
"scope_creep",
|
|
3796
3883
|
"underestimated_complexity",
|
|
3797
3884
|
"technical_debt",
|
|
@@ -3802,54 +3889,54 @@ var init_outcomes = __esm({
|
|
|
3802
3889
|
"team_changes",
|
|
3803
3890
|
"other"
|
|
3804
3891
|
]);
|
|
3805
|
-
EffortComparisonSchema =
|
|
3806
|
-
estimated:
|
|
3807
|
-
hours:
|
|
3808
|
-
confidence:
|
|
3809
|
-
source:
|
|
3892
|
+
EffortComparisonSchema = z8.object({
|
|
3893
|
+
estimated: z8.object({
|
|
3894
|
+
hours: z8.number(),
|
|
3895
|
+
confidence: z8.enum(["low", "medium", "high"]).optional(),
|
|
3896
|
+
source: z8.enum(["prd", "manual", "historical"]).optional()
|
|
3810
3897
|
}),
|
|
3811
|
-
actual:
|
|
3812
|
-
hours:
|
|
3813
|
-
commits:
|
|
3814
|
-
linesAdded:
|
|
3815
|
-
linesRemoved:
|
|
3816
|
-
sessions:
|
|
3898
|
+
actual: z8.object({
|
|
3899
|
+
hours: z8.number(),
|
|
3900
|
+
commits: z8.number().optional(),
|
|
3901
|
+
linesAdded: z8.number().optional(),
|
|
3902
|
+
linesRemoved: z8.number().optional(),
|
|
3903
|
+
sessions: z8.number().optional()
|
|
3817
3904
|
// Number of work sessions
|
|
3818
3905
|
}),
|
|
3819
|
-
variance:
|
|
3820
|
-
hours:
|
|
3906
|
+
variance: z8.object({
|
|
3907
|
+
hours: z8.number(),
|
|
3821
3908
|
// actual - estimated
|
|
3822
|
-
percentage:
|
|
3909
|
+
percentage: z8.number(),
|
|
3823
3910
|
// ((actual - estimated) / estimated) * 100
|
|
3824
3911
|
reason: VarianceReasonSchema.optional(),
|
|
3825
|
-
explanation:
|
|
3912
|
+
explanation: z8.string().optional()
|
|
3826
3913
|
})
|
|
3827
3914
|
});
|
|
3828
|
-
MetricResultSchema =
|
|
3829
|
-
name:
|
|
3830
|
-
baseline:
|
|
3831
|
-
target:
|
|
3832
|
-
actual:
|
|
3833
|
-
unit:
|
|
3834
|
-
achieved:
|
|
3915
|
+
MetricResultSchema = z8.object({
|
|
3916
|
+
name: z8.string(),
|
|
3917
|
+
baseline: z8.number().nullable(),
|
|
3918
|
+
target: z8.number(),
|
|
3919
|
+
actual: z8.number(),
|
|
3920
|
+
unit: z8.string(),
|
|
3921
|
+
achieved: z8.boolean(),
|
|
3835
3922
|
// actual >= target (or <= for decrease metrics)
|
|
3836
|
-
percentOfTarget:
|
|
3923
|
+
percentOfTarget: z8.number()
|
|
3837
3924
|
// (actual / target) * 100
|
|
3838
3925
|
});
|
|
3839
|
-
AcceptanceCriteriaResultSchema =
|
|
3840
|
-
criteria:
|
|
3841
|
-
met:
|
|
3842
|
-
notes:
|
|
3926
|
+
AcceptanceCriteriaResultSchema = z8.object({
|
|
3927
|
+
criteria: z8.string(),
|
|
3928
|
+
met: z8.boolean(),
|
|
3929
|
+
notes: z8.string().optional()
|
|
3843
3930
|
});
|
|
3844
|
-
SuccessTrackingSchema =
|
|
3845
|
-
metrics:
|
|
3846
|
-
acceptanceCriteria:
|
|
3931
|
+
SuccessTrackingSchema = z8.object({
|
|
3932
|
+
metrics: z8.array(MetricResultSchema),
|
|
3933
|
+
acceptanceCriteria: z8.array(AcceptanceCriteriaResultSchema),
|
|
3847
3934
|
overallSuccess: SuccessLevelSchema,
|
|
3848
|
-
successScore:
|
|
3935
|
+
successScore: z8.number().min(0).max(100)
|
|
3849
3936
|
// Percentage of metrics/criteria met
|
|
3850
3937
|
});
|
|
3851
|
-
LearningSchema =
|
|
3852
|
-
category:
|
|
3938
|
+
LearningSchema = z8.object({
|
|
3939
|
+
category: z8.enum([
|
|
3853
3940
|
"estimation",
|
|
3854
3941
|
"technical",
|
|
3855
3942
|
"process",
|
|
@@ -3859,62 +3946,62 @@ var init_outcomes = __esm({
|
|
|
3859
3946
|
"testing",
|
|
3860
3947
|
"other"
|
|
3861
3948
|
]),
|
|
3862
|
-
insight:
|
|
3863
|
-
actionable:
|
|
3864
|
-
action:
|
|
3949
|
+
insight: z8.string(),
|
|
3950
|
+
actionable: z8.boolean(),
|
|
3951
|
+
action: z8.string().optional()
|
|
3865
3952
|
// What to do differently next time
|
|
3866
3953
|
});
|
|
3867
|
-
LearningsSchema =
|
|
3868
|
-
whatWorked:
|
|
3869
|
-
whatDidnt:
|
|
3870
|
-
surprises:
|
|
3871
|
-
recommendations:
|
|
3954
|
+
LearningsSchema = z8.object({
|
|
3955
|
+
whatWorked: z8.array(z8.string()),
|
|
3956
|
+
whatDidnt: z8.array(z8.string()),
|
|
3957
|
+
surprises: z8.array(z8.string()),
|
|
3958
|
+
recommendations: z8.array(LearningSchema)
|
|
3872
3959
|
});
|
|
3873
|
-
ROIAssessmentSchema =
|
|
3874
|
-
valueDelivered:
|
|
3960
|
+
ROIAssessmentSchema = z8.object({
|
|
3961
|
+
valueDelivered: z8.number().min(1).max(10),
|
|
3875
3962
|
// Subjective 1-10 score
|
|
3876
|
-
userImpact:
|
|
3877
|
-
businessImpact:
|
|
3963
|
+
userImpact: z8.enum(["none", "low", "medium", "high", "critical"]),
|
|
3964
|
+
businessImpact: z8.enum(["none", "low", "medium", "high", "critical"]),
|
|
3878
3965
|
// Calculated: (valueDelivered * 10) / (actual hours)
|
|
3879
|
-
roiScore:
|
|
3966
|
+
roiScore: z8.number(),
|
|
3880
3967
|
// Would you build this again knowing what you know now?
|
|
3881
3968
|
worthIt: WorthAssessmentSchema,
|
|
3882
|
-
worthItReason:
|
|
3969
|
+
worthItReason: z8.string().optional(),
|
|
3883
3970
|
// Comparison to alternatives
|
|
3884
|
-
alternativeConsidered:
|
|
3885
|
-
betterAlternativeExists:
|
|
3971
|
+
alternativeConsidered: z8.string().optional(),
|
|
3972
|
+
betterAlternativeExists: z8.boolean().optional()
|
|
3886
3973
|
});
|
|
3887
|
-
TaskOutcomeSchema =
|
|
3888
|
-
id:
|
|
3974
|
+
TaskOutcomeSchema = z8.object({
|
|
3975
|
+
id: z8.string(),
|
|
3889
3976
|
// out_task_xxxxxxxx
|
|
3890
|
-
taskId:
|
|
3891
|
-
description:
|
|
3977
|
+
taskId: z8.string(),
|
|
3978
|
+
description: z8.string(),
|
|
3892
3979
|
// Time tracking
|
|
3893
|
-
estimatedMinutes:
|
|
3894
|
-
actualMinutes:
|
|
3980
|
+
estimatedMinutes: z8.number().optional(),
|
|
3981
|
+
actualMinutes: z8.number(),
|
|
3895
3982
|
// Quality
|
|
3896
|
-
completedAsPlanned:
|
|
3983
|
+
completedAsPlanned: z8.boolean(),
|
|
3897
3984
|
qualityScore: QualityScoreSchema,
|
|
3898
3985
|
// Context
|
|
3899
|
-
blockers:
|
|
3900
|
-
agentUsed:
|
|
3901
|
-
skillsUsed:
|
|
3986
|
+
blockers: z8.array(z8.string()),
|
|
3987
|
+
agentUsed: z8.string().optional(),
|
|
3988
|
+
skillsUsed: z8.array(z8.string()).optional(),
|
|
3902
3989
|
// Timestamps
|
|
3903
|
-
startedAt:
|
|
3904
|
-
completedAt:
|
|
3990
|
+
startedAt: z8.string(),
|
|
3991
|
+
completedAt: z8.string()
|
|
3905
3992
|
});
|
|
3906
|
-
FeatureOutcomeSchema =
|
|
3907
|
-
id:
|
|
3993
|
+
FeatureOutcomeSchema = z8.object({
|
|
3994
|
+
id: z8.string(),
|
|
3908
3995
|
// out_feat_xxxxxxxx
|
|
3909
3996
|
// Links
|
|
3910
|
-
featureId:
|
|
3911
|
-
featureName:
|
|
3912
|
-
prdId:
|
|
3997
|
+
featureId: z8.string(),
|
|
3998
|
+
featureName: z8.string(),
|
|
3999
|
+
prdId: z8.string().nullable(),
|
|
3913
4000
|
// null for legacy features
|
|
3914
4001
|
// Version info
|
|
3915
|
-
version:
|
|
3916
|
-
branch:
|
|
3917
|
-
prUrl:
|
|
4002
|
+
version: z8.string().optional(),
|
|
4003
|
+
branch: z8.string().optional(),
|
|
4004
|
+
prUrl: z8.string().optional(),
|
|
3918
4005
|
// Effort
|
|
3919
4006
|
effort: EffortComparisonSchema,
|
|
3920
4007
|
// Success (only if PRD exists)
|
|
@@ -3926,57 +4013,57 @@ var init_outcomes = __esm({
|
|
|
3926
4013
|
// Overall rating
|
|
3927
4014
|
rating: QualityScoreSchema,
|
|
3928
4015
|
// Task outcomes (sub-tasks)
|
|
3929
|
-
taskOutcomes:
|
|
4016
|
+
taskOutcomes: z8.array(TaskOutcomeSchema).optional(),
|
|
3930
4017
|
// Timestamps
|
|
3931
|
-
startedAt:
|
|
3932
|
-
shippedAt:
|
|
3933
|
-
reviewedAt:
|
|
4018
|
+
startedAt: z8.string(),
|
|
4019
|
+
shippedAt: z8.string(),
|
|
4020
|
+
reviewedAt: z8.string().optional(),
|
|
3934
4021
|
// When impact was captured
|
|
3935
4022
|
// Metadata
|
|
3936
|
-
reviewedBy:
|
|
4023
|
+
reviewedBy: z8.string().optional(),
|
|
3937
4024
|
// Who filled out the impact review
|
|
3938
|
-
legacy:
|
|
4025
|
+
legacy: z8.boolean().optional()
|
|
3939
4026
|
// Legacy feature (no PRD)
|
|
3940
4027
|
});
|
|
3941
|
-
AggregateMetricsSchema =
|
|
3942
|
-
totalFeatures:
|
|
3943
|
-
averageEstimationAccuracy:
|
|
4028
|
+
AggregateMetricsSchema = z8.object({
|
|
4029
|
+
totalFeatures: z8.number(),
|
|
4030
|
+
averageEstimationAccuracy: z8.number(),
|
|
3944
4031
|
// Percentage
|
|
3945
|
-
averageSuccessRate:
|
|
4032
|
+
averageSuccessRate: z8.number(),
|
|
3946
4033
|
// Percentage
|
|
3947
|
-
averageROI:
|
|
4034
|
+
averageROI: z8.number(),
|
|
3948
4035
|
// By category
|
|
3949
|
-
bySuccessLevel:
|
|
3950
|
-
exceeded:
|
|
3951
|
-
met:
|
|
3952
|
-
partial:
|
|
3953
|
-
failed:
|
|
4036
|
+
bySuccessLevel: z8.object({
|
|
4037
|
+
exceeded: z8.number(),
|
|
4038
|
+
met: z8.number(),
|
|
4039
|
+
partial: z8.number(),
|
|
4040
|
+
failed: z8.number()
|
|
3954
4041
|
}),
|
|
3955
4042
|
// Variance patterns
|
|
3956
|
-
variancePatterns:
|
|
4043
|
+
variancePatterns: z8.array(z8.object({
|
|
3957
4044
|
reason: VarianceReasonSchema,
|
|
3958
|
-
count:
|
|
3959
|
-
averageVariance:
|
|
4045
|
+
count: z8.number(),
|
|
4046
|
+
averageVariance: z8.number()
|
|
3960
4047
|
})),
|
|
3961
4048
|
// Top learnings (aggregated)
|
|
3962
|
-
topLearnings:
|
|
3963
|
-
insight:
|
|
3964
|
-
frequency:
|
|
4049
|
+
topLearnings: z8.array(z8.object({
|
|
4050
|
+
insight: z8.string(),
|
|
4051
|
+
frequency: z8.number()
|
|
3965
4052
|
}))
|
|
3966
4053
|
});
|
|
3967
|
-
OutcomesJsonSchema =
|
|
3968
|
-
outcomes:
|
|
3969
|
-
taskOutcomes:
|
|
4054
|
+
OutcomesJsonSchema = z8.object({
|
|
4055
|
+
outcomes: z8.array(FeatureOutcomeSchema),
|
|
4056
|
+
taskOutcomes: z8.array(TaskOutcomeSchema).optional(),
|
|
3970
4057
|
// Standalone task outcomes
|
|
3971
4058
|
aggregates: AggregateMetricsSchema.optional(),
|
|
3972
|
-
lastUpdated:
|
|
3973
|
-
lastAggregated:
|
|
4059
|
+
lastUpdated: z8.string(),
|
|
4060
|
+
lastAggregated: z8.string().optional()
|
|
3974
4061
|
});
|
|
3975
4062
|
}
|
|
3976
4063
|
});
|
|
3977
4064
|
|
|
3978
4065
|
// core/schemas/permissions.ts
|
|
3979
|
-
import { z as
|
|
4066
|
+
import { z as z9 } from "zod";
|
|
3980
4067
|
function buildDefaultPermissions() {
|
|
3981
4068
|
const bash = {};
|
|
3982
4069
|
for (const pattern of DEFAULT_BASH_ALLOW) {
|
|
@@ -4009,20 +4096,20 @@ var PermissionLevelSchema, FileOperationSchema, BashPermissionSchema, FilePermis
|
|
|
4009
4096
|
var init_permissions = __esm({
|
|
4010
4097
|
"core/schemas/permissions.ts"() {
|
|
4011
4098
|
"use strict";
|
|
4012
|
-
PermissionLevelSchema =
|
|
4013
|
-
FileOperationSchema =
|
|
4014
|
-
BashPermissionSchema =
|
|
4015
|
-
FilePermissionSchema =
|
|
4016
|
-
WebPermissionSchema =
|
|
4017
|
-
enabled:
|
|
4018
|
-
allowedDomains:
|
|
4019
|
-
blockedDomains:
|
|
4099
|
+
PermissionLevelSchema = z9.enum(["allow", "deny", "ask"]);
|
|
4100
|
+
FileOperationSchema = z9.enum(["read", "write", "delete", "create"]);
|
|
4101
|
+
BashPermissionSchema = z9.record(z9.string(), PermissionLevelSchema);
|
|
4102
|
+
FilePermissionSchema = z9.record(z9.string(), PermissionLevelSchema);
|
|
4103
|
+
WebPermissionSchema = z9.object({
|
|
4104
|
+
enabled: z9.boolean().default(true),
|
|
4105
|
+
allowedDomains: z9.array(z9.string()).optional(),
|
|
4106
|
+
blockedDomains: z9.array(z9.string()).optional()
|
|
4020
4107
|
});
|
|
4021
|
-
PermissionsConfigSchema =
|
|
4108
|
+
PermissionsConfigSchema = z9.object({
|
|
4022
4109
|
/** Bash command permissions - glob patterns */
|
|
4023
4110
|
bash: BashPermissionSchema.optional(),
|
|
4024
4111
|
/** File operation permissions - glob patterns */
|
|
4025
|
-
files:
|
|
4112
|
+
files: z9.object({
|
|
4026
4113
|
read: FilePermissionSchema.optional(),
|
|
4027
4114
|
write: FilePermissionSchema.optional(),
|
|
4028
4115
|
delete: FilePermissionSchema.optional()
|
|
@@ -4030,11 +4117,11 @@ var init_permissions = __esm({
|
|
|
4030
4117
|
/** Web fetch permissions */
|
|
4031
4118
|
web: WebPermissionSchema.optional(),
|
|
4032
4119
|
/** Skill invocation permissions */
|
|
4033
|
-
skills:
|
|
4120
|
+
skills: z9.record(z9.string(), PermissionLevelSchema).optional(),
|
|
4034
4121
|
/** Doom loop protection - prevent infinite retries */
|
|
4035
|
-
doomLoop:
|
|
4036
|
-
enabled:
|
|
4037
|
-
maxRetries:
|
|
4122
|
+
doomLoop: z9.object({
|
|
4123
|
+
enabled: z9.boolean().default(true),
|
|
4124
|
+
maxRetries: z9.number().default(3)
|
|
4038
4125
|
}).optional(),
|
|
4039
4126
|
/** External directory access */
|
|
4040
4127
|
externalDirectories: PermissionLevelSchema.default("ask")
|
|
@@ -4093,12 +4180,16 @@ import { homedir } from "os";
|
|
|
4093
4180
|
function generateUUID() {
|
|
4094
4181
|
return crypto3.randomUUID();
|
|
4095
4182
|
}
|
|
4183
|
+
function getProjectPath2(projectId) {
|
|
4184
|
+
return join(GLOBAL_STORAGE, projectId);
|
|
4185
|
+
}
|
|
4096
4186
|
var GLOBAL_STORAGE;
|
|
4097
4187
|
var init_schemas = __esm({
|
|
4098
4188
|
"core/schemas/schemas.ts"() {
|
|
4099
4189
|
"use strict";
|
|
4100
4190
|
__name(generateUUID, "generateUUID");
|
|
4101
4191
|
GLOBAL_STORAGE = join(homedir(), ".prjct-cli", "projects");
|
|
4192
|
+
__name(getProjectPath2, "getProjectPath");
|
|
4102
4193
|
}
|
|
4103
4194
|
});
|
|
4104
4195
|
|
|
@@ -4107,6 +4198,7 @@ var init_schemas2 = __esm({
|
|
|
4107
4198
|
"core/schemas/index.ts"() {
|
|
4108
4199
|
"use strict";
|
|
4109
4200
|
init_state();
|
|
4201
|
+
init_issues();
|
|
4110
4202
|
init_project();
|
|
4111
4203
|
init_agents();
|
|
4112
4204
|
init_ideas();
|
|
@@ -10004,6 +10096,120 @@ var init_orchestrator_executor = __esm({
|
|
|
10004
10096
|
}
|
|
10005
10097
|
});
|
|
10006
10098
|
|
|
10099
|
+
// core/utils/agent-stream.ts
|
|
10100
|
+
import chalk from "chalk";
|
|
10101
|
+
function getIcon(domain) {
|
|
10102
|
+
return DOMAIN_ICONS[domain.toLowerCase()] || DOMAIN_ICONS.default;
|
|
10103
|
+
}
|
|
10104
|
+
var DOMAIN_ICONS, AgentStream, agentStream;
|
|
10105
|
+
var init_agent_stream = __esm({
|
|
10106
|
+
"core/utils/agent-stream.ts"() {
|
|
10107
|
+
"use strict";
|
|
10108
|
+
DOMAIN_ICONS = {
|
|
10109
|
+
database: "\u{1F4BE}",
|
|
10110
|
+
backend: "\u{1F527}",
|
|
10111
|
+
frontend: "\u{1F4E6}",
|
|
10112
|
+
testing: "\u{1F9EA}",
|
|
10113
|
+
devops: "\u{1F680}",
|
|
10114
|
+
uxui: "\u{1F3A8}",
|
|
10115
|
+
security: "\u{1F512}",
|
|
10116
|
+
docs: "\u{1F4DD}",
|
|
10117
|
+
api: "\u{1F310}",
|
|
10118
|
+
default: "\u26A1"
|
|
10119
|
+
};
|
|
10120
|
+
__name(getIcon, "getIcon");
|
|
10121
|
+
AgentStream = class {
|
|
10122
|
+
static {
|
|
10123
|
+
__name(this, "AgentStream");
|
|
10124
|
+
}
|
|
10125
|
+
currentAgent = null;
|
|
10126
|
+
startTime = 0;
|
|
10127
|
+
quiet = false;
|
|
10128
|
+
/**
|
|
10129
|
+
* Set quiet mode (no output)
|
|
10130
|
+
*/
|
|
10131
|
+
setQuiet(quiet) {
|
|
10132
|
+
this.quiet = quiet;
|
|
10133
|
+
}
|
|
10134
|
+
/**
|
|
10135
|
+
* Show orchestration start
|
|
10136
|
+
*/
|
|
10137
|
+
orchestrate(domains) {
|
|
10138
|
+
if (this.quiet) return;
|
|
10139
|
+
console.log(chalk.cyan(`
|
|
10140
|
+
\u{1F3AF} Orchestrating: ${domains.join(", ")} domains detected
|
|
10141
|
+
`));
|
|
10142
|
+
}
|
|
10143
|
+
/**
|
|
10144
|
+
* Start an agent activity block
|
|
10145
|
+
*/
|
|
10146
|
+
startAgent(name, domain, description) {
|
|
10147
|
+
if (this.quiet) return;
|
|
10148
|
+
this.currentAgent = name;
|
|
10149
|
+
this.startTime = Date.now();
|
|
10150
|
+
const icon = getIcon(domain);
|
|
10151
|
+
console.log(chalk.cyan(`\u250C\u2500 ${icon} ${name} (${domain})`));
|
|
10152
|
+
if (description) {
|
|
10153
|
+
console.log(chalk.dim(`\u2502 ${description}`));
|
|
10154
|
+
}
|
|
10155
|
+
}
|
|
10156
|
+
/**
|
|
10157
|
+
* Show progress within current agent
|
|
10158
|
+
*/
|
|
10159
|
+
progress(message) {
|
|
10160
|
+
if (this.quiet || !this.currentAgent) return;
|
|
10161
|
+
console.log(chalk.dim(`\u2502 \u2514\u2500\u2500 ${message}`));
|
|
10162
|
+
}
|
|
10163
|
+
/**
|
|
10164
|
+
* Show multiple progress items
|
|
10165
|
+
*/
|
|
10166
|
+
progressList(items) {
|
|
10167
|
+
if (this.quiet || !this.currentAgent) return;
|
|
10168
|
+
for (const item of items) {
|
|
10169
|
+
console.log(chalk.dim(`\u2502 \u2514\u2500\u2500 ${item}`));
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
/**
|
|
10173
|
+
* End current agent block
|
|
10174
|
+
*/
|
|
10175
|
+
endAgent(success = true) {
|
|
10176
|
+
if (this.quiet || !this.currentAgent) return;
|
|
10177
|
+
const duration = Date.now() - this.startTime;
|
|
10178
|
+
const durationStr = this.formatDuration(duration);
|
|
10179
|
+
const icon = success ? chalk.green("\u2713") : chalk.red("\u2717");
|
|
10180
|
+
const status = success ? "Complete" : "Failed";
|
|
10181
|
+
console.log(`\u2514\u2500 ${icon} ${status} ${chalk.dim(`(${durationStr})`)}
|
|
10182
|
+
`);
|
|
10183
|
+
this.currentAgent = null;
|
|
10184
|
+
}
|
|
10185
|
+
/**
|
|
10186
|
+
* Show a simple status line (no block)
|
|
10187
|
+
*/
|
|
10188
|
+
status(icon, message) {
|
|
10189
|
+
if (this.quiet) return;
|
|
10190
|
+
console.log(`${icon} ${message}`);
|
|
10191
|
+
}
|
|
10192
|
+
/**
|
|
10193
|
+
* Show task completion summary
|
|
10194
|
+
*/
|
|
10195
|
+
complete(taskName, totalDuration) {
|
|
10196
|
+
if (this.quiet) return;
|
|
10197
|
+
const durationStr = totalDuration ? ` ${chalk.dim(`[${this.formatDuration(totalDuration)}]`)}` : "";
|
|
10198
|
+
console.log(chalk.green(`\u2705 ${taskName}${durationStr}`));
|
|
10199
|
+
}
|
|
10200
|
+
/**
|
|
10201
|
+
* Format duration in human-readable form
|
|
10202
|
+
*/
|
|
10203
|
+
formatDuration(ms) {
|
|
10204
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
10205
|
+
const seconds = (ms / 1e3).toFixed(1);
|
|
10206
|
+
return `${seconds}s`;
|
|
10207
|
+
}
|
|
10208
|
+
};
|
|
10209
|
+
agentStream = new AgentStream();
|
|
10210
|
+
}
|
|
10211
|
+
});
|
|
10212
|
+
|
|
10007
10213
|
// core/agentic/command-executor.ts
|
|
10008
10214
|
import fs23 from "fs";
|
|
10009
10215
|
import path22 from "path";
|
|
@@ -10041,6 +10247,7 @@ var init_command_executor = __esm({
|
|
|
10041
10247
|
init_plan_mode();
|
|
10042
10248
|
init_template_executor();
|
|
10043
10249
|
init_orchestrator_executor();
|
|
10250
|
+
init_agent_stream();
|
|
10044
10251
|
RUNNING_FILE = path22.join(os10.homedir(), ".prjct-cli", ".running");
|
|
10045
10252
|
__name(signalStart, "signalStart");
|
|
10046
10253
|
__name(signalEnd, "signalEnd");
|
|
@@ -10129,11 +10336,16 @@ var init_command_executor = __esm({
|
|
|
10129
10336
|
taskDescription,
|
|
10130
10337
|
projectPath
|
|
10131
10338
|
);
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10339
|
+
if (orchestratorContext.detectedDomains.length > 0) {
|
|
10340
|
+
agentStream.orchestrate(orchestratorContext.detectedDomains);
|
|
10341
|
+
}
|
|
10342
|
+
for (const agent of orchestratorContext.agents) {
|
|
10343
|
+
const domain = agent.domain || agent.name.replace(".md", "");
|
|
10344
|
+
agentStream.startAgent(agent.name, domain, `Loading ${domain} specialist...`);
|
|
10345
|
+
agentStream.endAgent(true);
|
|
10346
|
+
}
|
|
10135
10347
|
if (orchestratorContext.requiresFragmentation && orchestratorContext.subtasks) {
|
|
10136
|
-
|
|
10348
|
+
agentStream.status("\u{1F4CB}", `${orchestratorContext.subtasks.length} subtasks planned`);
|
|
10137
10349
|
}
|
|
10138
10350
|
} catch (error) {
|
|
10139
10351
|
console.warn(`\u26A0\uFE0F Orchestrator warning: ${error.message}`);
|
|
@@ -10321,7 +10533,7 @@ import https from "https";
|
|
|
10321
10533
|
import fs24 from "fs";
|
|
10322
10534
|
import path23 from "path";
|
|
10323
10535
|
import os11 from "os";
|
|
10324
|
-
import
|
|
10536
|
+
import chalk2 from "chalk";
|
|
10325
10537
|
var UpdateChecker, update_checker_default;
|
|
10326
10538
|
var init_update_checker = __esm({
|
|
10327
10539
|
"core/infrastructure/update-checker.ts"() {
|
|
@@ -10484,7 +10696,7 @@ var init_update_checker = __esm({
|
|
|
10484
10696
|
if (!result || !result.updateAvailable) {
|
|
10485
10697
|
return null;
|
|
10486
10698
|
}
|
|
10487
|
-
return "\n" +
|
|
10699
|
+
return "\n" + chalk2.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510") + "\n" + chalk2.yellow("\u2502") + " " + chalk2.bold("Update available!") + " " + chalk2.dim(`${result.currentVersion} \u2192 ${result.latestVersion}`) + " " + chalk2.yellow("\u2502") + "\n" + chalk2.yellow("\u2502") + " " + chalk2.yellow("\u2502") + "\n" + chalk2.yellow("\u2502") + " Run: " + chalk2.cyan("npm update -g prjct-cli") + " " + chalk2.yellow("\u2502") + "\n" + chalk2.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518") + "\n";
|
|
10488
10700
|
}
|
|
10489
10701
|
};
|
|
10490
10702
|
update_checker_default = UpdateChecker;
|
|
@@ -10492,7 +10704,7 @@ var init_update_checker = __esm({
|
|
|
10492
10704
|
});
|
|
10493
10705
|
|
|
10494
10706
|
// core/utils/branding.ts
|
|
10495
|
-
import
|
|
10707
|
+
import chalk3 from "chalk";
|
|
10496
10708
|
var SPINNER_FRAMES, SPINNER_SPEED, branding, branding_default;
|
|
10497
10709
|
var init_branding = __esm({
|
|
10498
10710
|
"core/utils/branding.ts"() {
|
|
@@ -10512,9 +10724,9 @@ var init_branding = __esm({
|
|
|
10512
10724
|
},
|
|
10513
10725
|
// CLI output (with chalk colors)
|
|
10514
10726
|
cli: {
|
|
10515
|
-
header: /* @__PURE__ */ __name(() =>
|
|
10516
|
-
footer: /* @__PURE__ */ __name(() =>
|
|
10517
|
-
spin: /* @__PURE__ */ __name((frame2, msg) =>
|
|
10727
|
+
header: /* @__PURE__ */ __name(() => chalk3.cyan.bold("\u26A1") + " " + chalk3.cyan("prjct"), "header"),
|
|
10728
|
+
footer: /* @__PURE__ */ __name(() => chalk3.dim("\u26A1 prjct"), "footer"),
|
|
10729
|
+
spin: /* @__PURE__ */ __name((frame2, msg) => chalk3.cyan("\u26A1") + " " + chalk3.cyan("prjct") + " " + chalk3.cyan(SPINNER_FRAMES[frame2 % 10]) + " " + chalk3.dim(msg || ""), "spin")
|
|
10518
10730
|
},
|
|
10519
10731
|
// Template (plain text)
|
|
10520
10732
|
template: {
|
|
@@ -10543,7 +10755,7 @@ Designed for [Claude](https://www.anthropic.com/claude)`,
|
|
|
10543
10755
|
});
|
|
10544
10756
|
|
|
10545
10757
|
// core/utils/output.ts
|
|
10546
|
-
import
|
|
10758
|
+
import chalk4 from "chalk";
|
|
10547
10759
|
var FRAMES, SPEED, interval, frame, truncate, clear, out, output_default;
|
|
10548
10760
|
var init_output = __esm({
|
|
10549
10761
|
"core/utils/output.ts"() {
|
|
@@ -10576,17 +10788,17 @@ var init_output = __esm({
|
|
|
10576
10788
|
},
|
|
10577
10789
|
done(msg) {
|
|
10578
10790
|
this.stop();
|
|
10579
|
-
console.log(`${
|
|
10791
|
+
console.log(`${chalk4.green("\u2713")} ${truncate(msg, 65)}`);
|
|
10580
10792
|
return this;
|
|
10581
10793
|
},
|
|
10582
10794
|
fail(msg) {
|
|
10583
10795
|
this.stop();
|
|
10584
|
-
console.log(`${
|
|
10796
|
+
console.log(`${chalk4.red("\u2717")} ${truncate(msg, 65)}`);
|
|
10585
10797
|
return this;
|
|
10586
10798
|
},
|
|
10587
10799
|
warn(msg) {
|
|
10588
10800
|
this.stop();
|
|
10589
|
-
console.log(`${
|
|
10801
|
+
console.log(`${chalk4.yellow("\u26A0")} ${truncate(msg, 65)}`);
|
|
10590
10802
|
return this;
|
|
10591
10803
|
},
|
|
10592
10804
|
stop() {
|
|
@@ -10596,6 +10808,28 @@ var init_output = __esm({
|
|
|
10596
10808
|
clear();
|
|
10597
10809
|
}
|
|
10598
10810
|
return this;
|
|
10811
|
+
},
|
|
10812
|
+
// Step counter: [3/7] Running tests...
|
|
10813
|
+
step(current, total, msg) {
|
|
10814
|
+
this.stop();
|
|
10815
|
+
const counter = chalk4.dim(`[${current}/${total}]`);
|
|
10816
|
+
interval = setInterval(() => {
|
|
10817
|
+
process.stdout.write(`\r${branding_default.cli.spin(frame++, `${counter} ${truncate(msg, 35)}`)}`);
|
|
10818
|
+
}, SPEED);
|
|
10819
|
+
return this;
|
|
10820
|
+
},
|
|
10821
|
+
// Progress bar: [████░░░░] 50% Analyzing...
|
|
10822
|
+
progress(current, total, msg) {
|
|
10823
|
+
this.stop();
|
|
10824
|
+
const percent = Math.round(current / total * 100);
|
|
10825
|
+
const filled = Math.round(percent / 10);
|
|
10826
|
+
const empty = 10 - filled;
|
|
10827
|
+
const bar = chalk4.cyan("\u2588".repeat(filled)) + chalk4.dim("\u2591".repeat(empty));
|
|
10828
|
+
const text = msg ? ` ${truncate(msg, 25)}` : "";
|
|
10829
|
+
interval = setInterval(() => {
|
|
10830
|
+
process.stdout.write(`\r${branding_default.cli.spin(frame++, `[${bar}] ${percent}%${text}`)}`);
|
|
10831
|
+
}, SPEED);
|
|
10832
|
+
return this;
|
|
10599
10833
|
}
|
|
10600
10834
|
};
|
|
10601
10835
|
output_default = out;
|
|
@@ -10980,6 +11214,206 @@ var init_agent_service = __esm({
|
|
|
10980
11214
|
}
|
|
10981
11215
|
});
|
|
10982
11216
|
|
|
11217
|
+
// core/workflow/state-machine.ts
|
|
11218
|
+
var WORKFLOW_STATES, WorkflowStateMachine, workflowStateMachine;
|
|
11219
|
+
var init_state_machine = __esm({
|
|
11220
|
+
"core/workflow/state-machine.ts"() {
|
|
11221
|
+
"use strict";
|
|
11222
|
+
WORKFLOW_STATES = {
|
|
11223
|
+
idle: {
|
|
11224
|
+
transitions: ["task", "next"],
|
|
11225
|
+
prompt: "p. task <description> Start working",
|
|
11226
|
+
description: "No active task"
|
|
11227
|
+
},
|
|
11228
|
+
working: {
|
|
11229
|
+
transitions: ["done", "pause"],
|
|
11230
|
+
prompt: "p. done Complete task | p. pause Switch context",
|
|
11231
|
+
description: "Task in progress"
|
|
11232
|
+
},
|
|
11233
|
+
paused: {
|
|
11234
|
+
transitions: ["resume", "task"],
|
|
11235
|
+
prompt: "p. resume Continue | p. task <new> Start different",
|
|
11236
|
+
description: "Task paused"
|
|
11237
|
+
},
|
|
11238
|
+
completed: {
|
|
11239
|
+
transitions: ["ship", "task", "next"],
|
|
11240
|
+
prompt: "p. ship Ship it | p. task <next> Start next",
|
|
11241
|
+
description: "Task completed"
|
|
11242
|
+
},
|
|
11243
|
+
shipped: {
|
|
11244
|
+
transitions: ["task", "next"],
|
|
11245
|
+
prompt: "p. task <description> Start new task",
|
|
11246
|
+
description: "Feature shipped"
|
|
11247
|
+
}
|
|
11248
|
+
};
|
|
11249
|
+
WorkflowStateMachine = class {
|
|
11250
|
+
static {
|
|
11251
|
+
__name(this, "WorkflowStateMachine");
|
|
11252
|
+
}
|
|
11253
|
+
/**
|
|
11254
|
+
* Get current state from storage state
|
|
11255
|
+
*/
|
|
11256
|
+
getCurrentState(storageState) {
|
|
11257
|
+
const task = storageState?.currentTask;
|
|
11258
|
+
if (!task) {
|
|
11259
|
+
return "idle";
|
|
11260
|
+
}
|
|
11261
|
+
const status = task.status?.toLowerCase();
|
|
11262
|
+
switch (status) {
|
|
11263
|
+
case "in_progress":
|
|
11264
|
+
case "working":
|
|
11265
|
+
return "working";
|
|
11266
|
+
case "paused":
|
|
11267
|
+
return "paused";
|
|
11268
|
+
case "completed":
|
|
11269
|
+
case "done":
|
|
11270
|
+
return "completed";
|
|
11271
|
+
case "shipped":
|
|
11272
|
+
return "shipped";
|
|
11273
|
+
default:
|
|
11274
|
+
return task ? "working" : "idle";
|
|
11275
|
+
}
|
|
11276
|
+
}
|
|
11277
|
+
/**
|
|
11278
|
+
* Check if a command is valid for the current state
|
|
11279
|
+
*/
|
|
11280
|
+
canTransition(currentState, command) {
|
|
11281
|
+
const stateConfig = WORKFLOW_STATES[currentState];
|
|
11282
|
+
if (stateConfig.transitions.includes(command)) {
|
|
11283
|
+
return { valid: true };
|
|
11284
|
+
}
|
|
11285
|
+
const validCommands = stateConfig.transitions.map((c) => `p. ${c}`).join(", ");
|
|
11286
|
+
return {
|
|
11287
|
+
valid: false,
|
|
11288
|
+
error: `Cannot run 'p. ${command}' in ${currentState} state`,
|
|
11289
|
+
suggestion: `Valid commands: ${validCommands}`
|
|
11290
|
+
};
|
|
11291
|
+
}
|
|
11292
|
+
/**
|
|
11293
|
+
* Get the next state after a command
|
|
11294
|
+
*/
|
|
11295
|
+
getNextState(currentState, command) {
|
|
11296
|
+
switch (command) {
|
|
11297
|
+
case "task":
|
|
11298
|
+
return "working";
|
|
11299
|
+
case "done":
|
|
11300
|
+
return "completed";
|
|
11301
|
+
case "pause":
|
|
11302
|
+
return "paused";
|
|
11303
|
+
case "resume":
|
|
11304
|
+
return "working";
|
|
11305
|
+
case "ship":
|
|
11306
|
+
return "shipped";
|
|
11307
|
+
case "next":
|
|
11308
|
+
return currentState;
|
|
11309
|
+
// next doesn't change state
|
|
11310
|
+
default:
|
|
11311
|
+
return currentState;
|
|
11312
|
+
}
|
|
11313
|
+
}
|
|
11314
|
+
/**
|
|
11315
|
+
* Get state definition
|
|
11316
|
+
*/
|
|
11317
|
+
getStateInfo(state) {
|
|
11318
|
+
return WORKFLOW_STATES[state];
|
|
11319
|
+
}
|
|
11320
|
+
/**
|
|
11321
|
+
* Get prompt for current state
|
|
11322
|
+
*/
|
|
11323
|
+
getPrompt(state) {
|
|
11324
|
+
return WORKFLOW_STATES[state].prompt;
|
|
11325
|
+
}
|
|
11326
|
+
/**
|
|
11327
|
+
* Get valid commands for current state
|
|
11328
|
+
*/
|
|
11329
|
+
getValidCommands(state) {
|
|
11330
|
+
return WORKFLOW_STATES[state].transitions;
|
|
11331
|
+
}
|
|
11332
|
+
/**
|
|
11333
|
+
* Format next steps for display
|
|
11334
|
+
*/
|
|
11335
|
+
formatNextSteps(state) {
|
|
11336
|
+
const stateConfig = WORKFLOW_STATES[state];
|
|
11337
|
+
return stateConfig.transitions.map((cmd) => {
|
|
11338
|
+
switch (cmd) {
|
|
11339
|
+
case "task":
|
|
11340
|
+
return "p. task <desc> Start new task";
|
|
11341
|
+
case "done":
|
|
11342
|
+
return "p. done Complete current task";
|
|
11343
|
+
case "pause":
|
|
11344
|
+
return "p. pause Pause and switch context";
|
|
11345
|
+
case "resume":
|
|
11346
|
+
return "p. resume Continue paused task";
|
|
11347
|
+
case "ship":
|
|
11348
|
+
return "p. ship Ship the feature";
|
|
11349
|
+
case "next":
|
|
11350
|
+
return "p. next View task queue";
|
|
11351
|
+
default:
|
|
11352
|
+
return `p. ${cmd}`;
|
|
11353
|
+
}
|
|
11354
|
+
});
|
|
11355
|
+
}
|
|
11356
|
+
};
|
|
11357
|
+
workflowStateMachine = new WorkflowStateMachine();
|
|
11358
|
+
}
|
|
11359
|
+
});
|
|
11360
|
+
|
|
11361
|
+
// core/utils/next-steps.ts
|
|
11362
|
+
import chalk5 from "chalk";
|
|
11363
|
+
function showNextSteps(command, options = {}) {
|
|
11364
|
+
if (options.quiet) return;
|
|
11365
|
+
const resultingState = COMMAND_TO_STATE[command] || "idle";
|
|
11366
|
+
const validCommands = workflowStateMachine.getValidCommands(resultingState);
|
|
11367
|
+
if (validCommands.length === 0) return;
|
|
11368
|
+
const steps = validCommands.map((cmd) => ({
|
|
11369
|
+
cmd: `p. ${cmd}`,
|
|
11370
|
+
desc: CMD_DESCRIPTIONS[cmd] || cmd
|
|
11371
|
+
}));
|
|
11372
|
+
console.log(chalk5.dim("\nNext:"));
|
|
11373
|
+
for (const step of steps) {
|
|
11374
|
+
const cmd = chalk5.cyan(step.cmd.padEnd(12));
|
|
11375
|
+
console.log(chalk5.dim(` ${cmd} \u2192 ${step.desc}`));
|
|
11376
|
+
}
|
|
11377
|
+
}
|
|
11378
|
+
function showStateInfo(state) {
|
|
11379
|
+
const info = workflowStateMachine.getStateInfo(state);
|
|
11380
|
+
console.log(chalk5.dim(`\u{1F4CD} State: ${chalk5.white(state.toUpperCase())} - ${info.description}`));
|
|
11381
|
+
}
|
|
11382
|
+
var CMD_DESCRIPTIONS, COMMAND_TO_STATE;
|
|
11383
|
+
var init_next_steps = __esm({
|
|
11384
|
+
"core/utils/next-steps.ts"() {
|
|
11385
|
+
"use strict";
|
|
11386
|
+
init_state_machine();
|
|
11387
|
+
CMD_DESCRIPTIONS = {
|
|
11388
|
+
task: "Start new task",
|
|
11389
|
+
done: "Complete current task",
|
|
11390
|
+
pause: "Pause and switch context",
|
|
11391
|
+
resume: "Continue paused task",
|
|
11392
|
+
ship: "Ship the feature",
|
|
11393
|
+
next: "View task queue",
|
|
11394
|
+
sync: "Analyze project",
|
|
11395
|
+
bug: "Report a bug",
|
|
11396
|
+
idea: "Capture an idea"
|
|
11397
|
+
};
|
|
11398
|
+
COMMAND_TO_STATE = {
|
|
11399
|
+
task: "working",
|
|
11400
|
+
done: "completed",
|
|
11401
|
+
"done-subtask": "working",
|
|
11402
|
+
// Still working on subtasks
|
|
11403
|
+
pause: "paused",
|
|
11404
|
+
resume: "working",
|
|
11405
|
+
ship: "shipped",
|
|
11406
|
+
next: "idle",
|
|
11407
|
+
sync: "idle",
|
|
11408
|
+
init: "idle",
|
|
11409
|
+
bug: "working",
|
|
11410
|
+
idea: "idle"
|
|
11411
|
+
};
|
|
11412
|
+
__name(showNextSteps, "showNextSteps");
|
|
11413
|
+
__name(showStateInfo, "showStateInfo");
|
|
11414
|
+
}
|
|
11415
|
+
});
|
|
11416
|
+
|
|
10983
11417
|
// core/domain/analyzer.ts
|
|
10984
11418
|
import fs27 from "fs/promises";
|
|
10985
11419
|
import path26 from "path";
|
|
@@ -11536,6 +11970,7 @@ var init_analysis2 = __esm({
|
|
|
11536
11970
|
init_generator();
|
|
11537
11971
|
init_command_installer();
|
|
11538
11972
|
init_services();
|
|
11973
|
+
init_next_steps();
|
|
11539
11974
|
AnalysisCommands = class extends PrjctCommandsBase {
|
|
11540
11975
|
static {
|
|
11541
11976
|
__name(this, "AnalysisCommands");
|
|
@@ -11694,12 +12129,13 @@ var init_analysis2 = __esm({
|
|
|
11694
12129
|
*
|
|
11695
12130
|
* This eliminates the need for Claude to make 50+ individual tool calls.
|
|
11696
12131
|
*/
|
|
11697
|
-
async sync(projectPath = process.cwd()) {
|
|
12132
|
+
async sync(projectPath = process.cwd(), options = {}) {
|
|
11698
12133
|
try {
|
|
11699
12134
|
const initResult = await this.ensureProjectInit(projectPath);
|
|
11700
12135
|
if (!initResult.success) return initResult;
|
|
12136
|
+
const startTime = Date.now();
|
|
11701
12137
|
console.log("\u{1F504} Syncing project...\n");
|
|
11702
|
-
const result = await syncService.sync(projectPath);
|
|
12138
|
+
const result = await syncService.sync(projectPath, { aiTools: options.aiTools });
|
|
11703
12139
|
if (!result.success) {
|
|
11704
12140
|
console.error("\u274C Sync failed:", result.error);
|
|
11705
12141
|
return { success: false, error: result.error };
|
|
@@ -11726,6 +12162,15 @@ var init_analysis2 = __esm({
|
|
|
11726
12162
|
console.log(`\u251C\u2500\u2500 ${file}`);
|
|
11727
12163
|
}
|
|
11728
12164
|
console.log("");
|
|
12165
|
+
if (result.aiTools && result.aiTools.length > 0) {
|
|
12166
|
+
const successTools = result.aiTools.filter((t) => t.success);
|
|
12167
|
+
console.log(`\u{1F916} AI Tools Context (${successTools.length})`);
|
|
12168
|
+
for (const tool of result.aiTools) {
|
|
12169
|
+
const status = tool.success ? "\u2713" : "\u2717";
|
|
12170
|
+
console.log(`\u251C\u2500\u2500 ${status} ${tool.outputFile} (${tool.toolId})`);
|
|
12171
|
+
}
|
|
12172
|
+
console.log("");
|
|
12173
|
+
}
|
|
11729
12174
|
const workflowAgents = result.agents.filter((a) => a.type === "workflow").map((a) => a.name);
|
|
11730
12175
|
const domainAgents = result.agents.filter((a) => a.type === "domain").map((a) => a.name);
|
|
11731
12176
|
console.log(`\u{1F916} Agents Regenerated (${result.agents.length})`);
|
|
@@ -11744,9 +12189,26 @@ var init_analysis2 = __esm({
|
|
|
11744
12189
|
} else {
|
|
11745
12190
|
console.log("\u2728 Repository is clean!\n");
|
|
11746
12191
|
}
|
|
12192
|
+
showNextSteps("sync");
|
|
12193
|
+
const elapsed = Date.now() - startTime;
|
|
12194
|
+
const contextFilesCount = result.contextFiles.length + (result.aiTools?.filter((t) => t.success).length || 0);
|
|
12195
|
+
const agentCount = result.agents.length;
|
|
12196
|
+
console.log("\u2500".repeat(45));
|
|
12197
|
+
console.log(`\u{1F4CA} Sync Summary`);
|
|
12198
|
+
console.log(` Stack: ${result.stats.ecosystem} (${result.stats.frameworks.join(", ") || "no frameworks"})`);
|
|
12199
|
+
console.log(` Files: ${result.stats.fileCount} analyzed \u2192 ${contextFilesCount} context files`);
|
|
12200
|
+
console.log(` Agents: ${agentCount} (${result.agents.filter((a) => a.type === "domain").length} domain)`);
|
|
12201
|
+
console.log(` Time: ${(elapsed / 1e3).toFixed(1)}s`);
|
|
12202
|
+
console.log("");
|
|
11747
12203
|
return {
|
|
11748
12204
|
success: true,
|
|
11749
|
-
data: result
|
|
12205
|
+
data: result,
|
|
12206
|
+
metrics: {
|
|
12207
|
+
elapsed,
|
|
12208
|
+
contextFilesCount,
|
|
12209
|
+
agentCount,
|
|
12210
|
+
fileCount: result.stats.fileCount
|
|
12211
|
+
}
|
|
11750
12212
|
};
|
|
11751
12213
|
} catch (error) {
|
|
11752
12214
|
console.error("\u274C Error:", error.message);
|
|
@@ -11779,6 +12241,7 @@ var init_planning = __esm({
|
|
|
11779
12241
|
init_storage2();
|
|
11780
12242
|
init_author_detector();
|
|
11781
12243
|
init_command_installer();
|
|
12244
|
+
init_next_steps();
|
|
11782
12245
|
_analysisCommands = null;
|
|
11783
12246
|
__name(getAnalysisCommands, "getAnalysisCommands");
|
|
11784
12247
|
PlanningCommands = class extends PrjctCommandsBase {
|
|
@@ -11796,7 +12259,7 @@ var init_planning = __esm({
|
|
|
11796
12259
|
output_default.warn("already initialized");
|
|
11797
12260
|
return { success: false, message: "Already initialized" };
|
|
11798
12261
|
}
|
|
11799
|
-
output_default.
|
|
12262
|
+
output_default.step(1, 4, "Detecting author...");
|
|
11800
12263
|
const detectedAuthor = await author_detector_default.detect();
|
|
11801
12264
|
const author = {
|
|
11802
12265
|
name: detectedAuthor.name || void 0,
|
|
@@ -11805,7 +12268,7 @@ var init_planning = __esm({
|
|
|
11805
12268
|
};
|
|
11806
12269
|
const config = await config_manager_default.createConfig(projectPath, author);
|
|
11807
12270
|
const projectId = config.projectId;
|
|
11808
|
-
output_default.
|
|
12271
|
+
output_default.step(2, 4, "Creating structure...");
|
|
11809
12272
|
await path_manager_default.ensureProjectStructure(projectId);
|
|
11810
12273
|
const globalPath = path_manager_default.getGlobalProjectPath(projectId);
|
|
11811
12274
|
const baseFiles = {
|
|
@@ -11832,11 +12295,11 @@ var init_planning = __esm({
|
|
|
11832
12295
|
const isEmpty = await this._detectEmptyDirectory(projectPath);
|
|
11833
12296
|
const hasCode = await this._detectExistingCode(projectPath);
|
|
11834
12297
|
if (hasCode || !isEmpty) {
|
|
11835
|
-
output_default.
|
|
12298
|
+
output_default.step(3, 4, "Analyzing project...");
|
|
11836
12299
|
const analysis2 = await getAnalysisCommands();
|
|
11837
12300
|
const analysisResult = await analysis2.analyze({}, projectPath);
|
|
11838
12301
|
if (analysisResult.success) {
|
|
11839
|
-
output_default.
|
|
12302
|
+
output_default.step(4, 4, "Generating agents...");
|
|
11840
12303
|
await analysis2.sync(projectPath);
|
|
11841
12304
|
output_default.done("initialized");
|
|
11842
12305
|
return { success: true, mode: "existing", projectId };
|
|
@@ -11866,6 +12329,7 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
11866
12329
|
}
|
|
11867
12330
|
await command_installer_default.installGlobalConfig();
|
|
11868
12331
|
output_default.done("initialized");
|
|
12332
|
+
showNextSteps("init");
|
|
11869
12333
|
return { success: true, projectId };
|
|
11870
12334
|
} catch (error) {
|
|
11871
12335
|
output_default.fail(error.message);
|
|
@@ -11969,6 +12433,7 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
11969
12433
|
timestamp: date_helper_default.getTimestamp()
|
|
11970
12434
|
});
|
|
11971
12435
|
output_default.done(`bug [${severity}] \u2192 ${agent}`);
|
|
12436
|
+
showNextSteps("bug");
|
|
11972
12437
|
return { success: true, bug: description, severity, agent };
|
|
11973
12438
|
} catch (error) {
|
|
11974
12439
|
output_default.fail(error.message);
|
|
@@ -12097,6 +12562,7 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
12097
12562
|
timestamp: date_helper_default.getTimestamp()
|
|
12098
12563
|
});
|
|
12099
12564
|
output_default.done(`idea captured: ${description.slice(0, 40)}`);
|
|
12565
|
+
showNextSteps("idea");
|
|
12100
12566
|
return { success: true, mode: "capture", idea: description };
|
|
12101
12567
|
}
|
|
12102
12568
|
} catch (error) {
|
|
@@ -12121,8 +12587,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
12121
12587
|
const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
|
|
12122
12588
|
const specsPath2 = path29.join(globalPath2, "planning", "specs");
|
|
12123
12589
|
try {
|
|
12124
|
-
const
|
|
12125
|
-
const files = await
|
|
12590
|
+
const fs37 = await import("fs/promises");
|
|
12591
|
+
const files = await fs37.readdir(specsPath2);
|
|
12126
12592
|
const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
12127
12593
|
if (specs.length === 0) {
|
|
12128
12594
|
output_default.warn("no specs yet");
|
|
@@ -12507,52 +12973,466 @@ var init_breakdown_service = __esm({
|
|
|
12507
12973
|
}
|
|
12508
12974
|
});
|
|
12509
12975
|
|
|
12510
|
-
// core/
|
|
12511
|
-
import
|
|
12976
|
+
// core/ai-tools/registry.ts
|
|
12977
|
+
import { execSync as execSync4 } from "child_process";
|
|
12978
|
+
import fs29 from "fs";
|
|
12512
12979
|
import path30 from "path";
|
|
12513
|
-
import
|
|
12514
|
-
|
|
12515
|
-
|
|
12516
|
-
|
|
12517
|
-
|
|
12980
|
+
import os12 from "os";
|
|
12981
|
+
function getAIToolConfig(id) {
|
|
12982
|
+
return AI_TOOLS[id] || null;
|
|
12983
|
+
}
|
|
12984
|
+
function commandExists(cmd) {
|
|
12985
|
+
try {
|
|
12986
|
+
execSync4(`which ${cmd}`, { stdio: "ignore" });
|
|
12987
|
+
return true;
|
|
12988
|
+
} catch {
|
|
12989
|
+
return false;
|
|
12990
|
+
}
|
|
12991
|
+
}
|
|
12992
|
+
function detectInstalledTools(repoPath = process.cwd()) {
|
|
12993
|
+
const detected = [];
|
|
12994
|
+
if (commandExists("claude")) {
|
|
12995
|
+
detected.push("claude");
|
|
12996
|
+
}
|
|
12997
|
+
if (commandExists("cursor") || fs29.existsSync(path30.join(repoPath, ".cursor"))) {
|
|
12998
|
+
detected.push("cursor");
|
|
12999
|
+
}
|
|
13000
|
+
if (fs29.existsSync(path30.join(repoPath, ".github"))) {
|
|
13001
|
+
detected.push("copilot");
|
|
13002
|
+
}
|
|
13003
|
+
if (commandExists("windsurf") || fs29.existsSync(path30.join(repoPath, ".windsurf"))) {
|
|
13004
|
+
detected.push("windsurf");
|
|
13005
|
+
}
|
|
13006
|
+
if (fs29.existsSync(path30.join(repoPath, ".continue")) || fs29.existsSync(path30.join(os12.homedir(), ".continue"))) {
|
|
13007
|
+
detected.push("continue");
|
|
13008
|
+
}
|
|
13009
|
+
return detected;
|
|
13010
|
+
}
|
|
13011
|
+
function resolveToolIds(mode, repoPath = process.cwd()) {
|
|
13012
|
+
if (mode === "auto") {
|
|
13013
|
+
const detected = detectInstalledTools(repoPath);
|
|
13014
|
+
return detected.length > 0 ? detected : ["claude"];
|
|
13015
|
+
}
|
|
13016
|
+
if (mode === "all") {
|
|
13017
|
+
return SUPPORTED_AI_TOOLS;
|
|
13018
|
+
}
|
|
13019
|
+
return mode.filter((id) => AI_TOOLS[id]);
|
|
13020
|
+
}
|
|
13021
|
+
var AI_TOOLS, DEFAULT_AI_TOOLS, SUPPORTED_AI_TOOLS;
|
|
13022
|
+
var init_registry = __esm({
|
|
13023
|
+
"core/ai-tools/registry.ts"() {
|
|
12518
13024
|
"use strict";
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
|
|
12525
|
-
|
|
12526
|
-
|
|
12527
|
-
|
|
12528
|
-
|
|
12529
|
-
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
13025
|
+
AI_TOOLS = {
|
|
13026
|
+
claude: {
|
|
13027
|
+
id: "claude",
|
|
13028
|
+
name: "Claude Code",
|
|
13029
|
+
outputFile: "CLAUDE.md",
|
|
13030
|
+
outputPath: "global",
|
|
13031
|
+
maxTokens: 3e3,
|
|
13032
|
+
format: "detailed",
|
|
13033
|
+
description: "Anthropic Claude Code CLI"
|
|
13034
|
+
},
|
|
13035
|
+
cursor: {
|
|
13036
|
+
id: "cursor",
|
|
13037
|
+
name: "Cursor",
|
|
13038
|
+
outputFile: ".cursorrules",
|
|
13039
|
+
outputPath: "repo",
|
|
13040
|
+
maxTokens: 2e3,
|
|
13041
|
+
format: "concise",
|
|
13042
|
+
description: "Cursor AI Editor"
|
|
13043
|
+
},
|
|
13044
|
+
copilot: {
|
|
13045
|
+
id: "copilot",
|
|
13046
|
+
name: "GitHub Copilot",
|
|
13047
|
+
outputFile: ".github/copilot-instructions.md",
|
|
13048
|
+
outputPath: "repo",
|
|
13049
|
+
maxTokens: 1500,
|
|
13050
|
+
format: "minimal",
|
|
13051
|
+
description: "GitHub Copilot"
|
|
13052
|
+
},
|
|
13053
|
+
windsurf: {
|
|
13054
|
+
id: "windsurf",
|
|
13055
|
+
name: "Windsurf",
|
|
13056
|
+
outputFile: ".windsurfrules",
|
|
13057
|
+
outputPath: "repo",
|
|
13058
|
+
maxTokens: 2e3,
|
|
13059
|
+
format: "concise",
|
|
13060
|
+
description: "Codeium Windsurf Editor"
|
|
13061
|
+
},
|
|
13062
|
+
continue: {
|
|
13063
|
+
id: "continue",
|
|
13064
|
+
name: "Continue.dev",
|
|
13065
|
+
outputFile: ".continue/config.json",
|
|
13066
|
+
outputPath: "repo",
|
|
13067
|
+
maxTokens: 1500,
|
|
13068
|
+
format: "json",
|
|
13069
|
+
description: "Continue.dev open-source AI assistant"
|
|
12533
13070
|
}
|
|
12534
|
-
|
|
12535
|
-
|
|
12536
|
-
|
|
12537
|
-
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
|
|
12555
|
-
|
|
13071
|
+
};
|
|
13072
|
+
DEFAULT_AI_TOOLS = ["claude", "cursor", "copilot", "windsurf"];
|
|
13073
|
+
SUPPORTED_AI_TOOLS = Object.keys(AI_TOOLS);
|
|
13074
|
+
__name(getAIToolConfig, "getAIToolConfig");
|
|
13075
|
+
__name(commandExists, "commandExists");
|
|
13076
|
+
__name(detectInstalledTools, "detectInstalledTools");
|
|
13077
|
+
__name(resolveToolIds, "resolveToolIds");
|
|
13078
|
+
}
|
|
13079
|
+
});
|
|
13080
|
+
|
|
13081
|
+
// core/ai-tools/formatters.ts
|
|
13082
|
+
function formatForClaude(ctx, config) {
|
|
13083
|
+
return `# ${ctx.name} - Project Rules
|
|
13084
|
+
<!-- projectId: ${ctx.projectId} -->
|
|
13085
|
+
<!-- Generated: ${(/* @__PURE__ */ new Date()).toISOString()} -->
|
|
13086
|
+
<!-- Ecosystem: ${ctx.ecosystem} | Type: ${ctx.projectType} -->
|
|
13087
|
+
|
|
13088
|
+
## THIS PROJECT (${ctx.ecosystem})
|
|
13089
|
+
|
|
13090
|
+
**Type:** ${ctx.projectType}
|
|
13091
|
+
**Path:** ${ctx.repoPath}
|
|
13092
|
+
|
|
13093
|
+
### Commands (USE THESE, NOT OTHERS)
|
|
13094
|
+
|
|
13095
|
+
| Action | Command |
|
|
13096
|
+
|--------|---------|
|
|
13097
|
+
| Install dependencies | \`${ctx.commands.install}\` |
|
|
13098
|
+
| Run dev server | \`${ctx.commands.dev}\` |
|
|
13099
|
+
| Run tests | \`${ctx.commands.test}\` |
|
|
13100
|
+
| Build | \`${ctx.commands.build}\` |
|
|
13101
|
+
| Lint | \`${ctx.commands.lint}\` |
|
|
13102
|
+
| Format | \`${ctx.commands.format}\` |
|
|
13103
|
+
|
|
13104
|
+
### Code Conventions
|
|
13105
|
+
|
|
13106
|
+
- **Languages**: ${ctx.languages.join(", ") || "Not detected"}
|
|
13107
|
+
- **Frameworks**: ${ctx.frameworks.join(", ") || "Not detected"}
|
|
13108
|
+
|
|
13109
|
+
---
|
|
13110
|
+
|
|
13111
|
+
## PRJCT RULES
|
|
13112
|
+
|
|
13113
|
+
### Path Resolution
|
|
13114
|
+
**ALL prjct writes go to**: \`~/.prjct-cli/projects/${ctx.projectId}/\`
|
|
13115
|
+
- NEVER write to \`.prjct/\`
|
|
13116
|
+
- NEVER write to \`./\` for prjct data
|
|
13117
|
+
|
|
13118
|
+
### Workflow
|
|
13119
|
+
\`\`\`
|
|
13120
|
+
p. sync \u2192 p. task "desc" \u2192 [work] \u2192 p. done \u2192 p. ship
|
|
13121
|
+
\`\`\`
|
|
13122
|
+
|
|
13123
|
+
| Command | Action |
|
|
13124
|
+
|---------|--------|
|
|
13125
|
+
| \`p. sync\` | Re-analyze project |
|
|
13126
|
+
| \`p. task X\` | Start task |
|
|
13127
|
+
| \`p. done\` | Complete subtask |
|
|
13128
|
+
| \`p. ship X\` | Ship feature |
|
|
13129
|
+
|
|
13130
|
+
---
|
|
13131
|
+
|
|
13132
|
+
## PROJECT STATE
|
|
13133
|
+
|
|
13134
|
+
| Field | Value |
|
|
13135
|
+
|-------|-------|
|
|
13136
|
+
| Name | ${ctx.name} |
|
|
13137
|
+
| Version | ${ctx.version} |
|
|
13138
|
+
| Ecosystem | ${ctx.ecosystem} |
|
|
13139
|
+
| Branch | ${ctx.branch} |
|
|
13140
|
+
| Files | ~${ctx.fileCount} |
|
|
13141
|
+
| Commits | ${ctx.commits} |
|
|
13142
|
+
|
|
13143
|
+
---
|
|
13144
|
+
|
|
13145
|
+
## AGENTS
|
|
13146
|
+
|
|
13147
|
+
Load from \`~/.prjct-cli/projects/${ctx.projectId}/agents/\`:
|
|
13148
|
+
|
|
13149
|
+
**Workflow**: ${ctx.agents.workflow.join(", ")}
|
|
13150
|
+
**Domain**: ${ctx.agents.domain.join(", ") || "none"}
|
|
13151
|
+
`;
|
|
13152
|
+
}
|
|
13153
|
+
function formatForCursor(ctx, config) {
|
|
13154
|
+
const rules = [];
|
|
13155
|
+
rules.push(`You are working on ${ctx.name}, a ${ctx.projectType} ${ctx.ecosystem} project.`);
|
|
13156
|
+
rules.push("");
|
|
13157
|
+
rules.push("## Tech Stack");
|
|
13158
|
+
if (ctx.languages.length > 0) {
|
|
13159
|
+
rules.push(`- Languages: ${ctx.languages.join(", ")}`);
|
|
13160
|
+
}
|
|
13161
|
+
if (ctx.frameworks.length > 0) {
|
|
13162
|
+
rules.push(`- Frameworks: ${ctx.frameworks.join(", ")}`);
|
|
13163
|
+
}
|
|
13164
|
+
rules.push("");
|
|
13165
|
+
rules.push("## Commands");
|
|
13166
|
+
rules.push(`- Install: \`${ctx.commands.install}\``);
|
|
13167
|
+
rules.push(`- Dev: \`${ctx.commands.dev}\``);
|
|
13168
|
+
rules.push(`- Test: \`${ctx.commands.test}\``);
|
|
13169
|
+
rules.push(`- Build: \`${ctx.commands.build}\``);
|
|
13170
|
+
rules.push("");
|
|
13171
|
+
rules.push("## Code Style");
|
|
13172
|
+
rules.push(`- Follow ${ctx.ecosystem} conventions`);
|
|
13173
|
+
rules.push("- Match existing code patterns in this project");
|
|
13174
|
+
rules.push("- Use idiomatic constructs for the language");
|
|
13175
|
+
rules.push("");
|
|
13176
|
+
rules.push("## Best Practices");
|
|
13177
|
+
rules.push("- Write clean, readable code");
|
|
13178
|
+
rules.push("- Add comments only for complex logic");
|
|
13179
|
+
rules.push("- Keep functions small and focused");
|
|
13180
|
+
rules.push("- Handle errors appropriately");
|
|
13181
|
+
rules.push("- Write tests for new functionality");
|
|
13182
|
+
return rules.join("\n");
|
|
13183
|
+
}
|
|
13184
|
+
function formatForCopilot(ctx, config) {
|
|
13185
|
+
const lines = [];
|
|
13186
|
+
lines.push("# Copilot Instructions");
|
|
13187
|
+
lines.push("");
|
|
13188
|
+
lines.push(`This is ${ctx.name}, a ${ctx.ecosystem} project.`);
|
|
13189
|
+
lines.push("");
|
|
13190
|
+
lines.push("## Project Info");
|
|
13191
|
+
lines.push(`- Type: ${ctx.projectType}`);
|
|
13192
|
+
lines.push(`- Stack: ${ctx.frameworks.join(", ") || ctx.ecosystem}`);
|
|
13193
|
+
lines.push("");
|
|
13194
|
+
lines.push("## Conventions");
|
|
13195
|
+
lines.push(`- Follow ${ctx.ecosystem} conventions`);
|
|
13196
|
+
lines.push("- Match existing code patterns");
|
|
13197
|
+
lines.push("- Keep code clean and readable");
|
|
13198
|
+
lines.push("");
|
|
13199
|
+
lines.push("## Commands");
|
|
13200
|
+
lines.push(`- Test: \`${ctx.commands.test}\``);
|
|
13201
|
+
lines.push(`- Build: \`${ctx.commands.build}\``);
|
|
13202
|
+
return lines.join("\n");
|
|
13203
|
+
}
|
|
13204
|
+
function formatForWindsurf(ctx, config) {
|
|
13205
|
+
const rules = [];
|
|
13206
|
+
rules.push(`# ${ctx.name}`);
|
|
13207
|
+
rules.push("");
|
|
13208
|
+
rules.push(`${ctx.projectType} project using ${ctx.ecosystem}.`);
|
|
13209
|
+
rules.push("");
|
|
13210
|
+
rules.push("## Stack");
|
|
13211
|
+
rules.push(`- ${ctx.languages.join(", ")}`);
|
|
13212
|
+
if (ctx.frameworks.length > 0) {
|
|
13213
|
+
rules.push(`- ${ctx.frameworks.join(", ")}`);
|
|
13214
|
+
}
|
|
13215
|
+
rules.push("");
|
|
13216
|
+
rules.push("## Commands");
|
|
13217
|
+
rules.push(`\`\`\`bash`);
|
|
13218
|
+
rules.push(`# Install`);
|
|
13219
|
+
rules.push(ctx.commands.install);
|
|
13220
|
+
rules.push(`# Dev`);
|
|
13221
|
+
rules.push(ctx.commands.dev);
|
|
13222
|
+
rules.push(`# Test`);
|
|
13223
|
+
rules.push(ctx.commands.test);
|
|
13224
|
+
rules.push(`# Build`);
|
|
13225
|
+
rules.push(ctx.commands.build);
|
|
13226
|
+
rules.push(`\`\`\``);
|
|
13227
|
+
rules.push("");
|
|
13228
|
+
rules.push("## Rules");
|
|
13229
|
+
rules.push(`- Follow ${ctx.ecosystem} conventions`);
|
|
13230
|
+
rules.push("- Match existing project patterns");
|
|
13231
|
+
rules.push("- Clean code, minimal comments");
|
|
13232
|
+
rules.push("- Test new functionality");
|
|
13233
|
+
return rules.join("\n");
|
|
13234
|
+
}
|
|
13235
|
+
function formatForContinue(ctx, config) {
|
|
13236
|
+
const systemMessage = [
|
|
13237
|
+
`You are working on ${ctx.name}, a ${ctx.projectType} ${ctx.ecosystem} project.`,
|
|
13238
|
+
"",
|
|
13239
|
+
`Stack: ${ctx.languages.join(", ")}${ctx.frameworks.length > 0 ? ` with ${ctx.frameworks.join(", ")}` : ""}`,
|
|
13240
|
+
"",
|
|
13241
|
+
"Commands:",
|
|
13242
|
+
`- Install: ${ctx.commands.install}`,
|
|
13243
|
+
`- Dev: ${ctx.commands.dev}`,
|
|
13244
|
+
`- Test: ${ctx.commands.test}`,
|
|
13245
|
+
`- Build: ${ctx.commands.build}`,
|
|
13246
|
+
"",
|
|
13247
|
+
`Follow ${ctx.ecosystem} conventions. Match existing code patterns.`
|
|
13248
|
+
].join("\n");
|
|
13249
|
+
const continueConfig = {
|
|
13250
|
+
systemMessage,
|
|
13251
|
+
models: [],
|
|
13252
|
+
contextProviders: [
|
|
13253
|
+
{ name: "code" },
|
|
13254
|
+
{ name: "docs" },
|
|
13255
|
+
{ name: "diff" },
|
|
13256
|
+
{ name: "terminal" },
|
|
13257
|
+
{ name: "problems" },
|
|
13258
|
+
{ name: "folder" },
|
|
13259
|
+
{ name: "codebase" }
|
|
13260
|
+
],
|
|
13261
|
+
slashCommands: [
|
|
13262
|
+
{ name: "edit", description: "Edit selected code" },
|
|
13263
|
+
{ name: "comment", description: "Add comments to code" },
|
|
13264
|
+
{ name: "share", description: "Export conversation" },
|
|
13265
|
+
{ name: "cmd", description: "Run terminal command" }
|
|
13266
|
+
],
|
|
13267
|
+
customCommands: [
|
|
13268
|
+
{
|
|
13269
|
+
name: "test",
|
|
13270
|
+
prompt: `Write tests for the selected code. Use the project's testing conventions. Test command: ${ctx.commands.test}`
|
|
13271
|
+
}
|
|
13272
|
+
]
|
|
13273
|
+
};
|
|
13274
|
+
return JSON.stringify(continueConfig, null, 2);
|
|
13275
|
+
}
|
|
13276
|
+
function getFormatter(toolId) {
|
|
13277
|
+
const formatters = {
|
|
13278
|
+
claude: formatForClaude,
|
|
13279
|
+
cursor: formatForCursor,
|
|
13280
|
+
copilot: formatForCopilot,
|
|
13281
|
+
windsurf: formatForWindsurf,
|
|
13282
|
+
continue: formatForContinue
|
|
13283
|
+
};
|
|
13284
|
+
return formatters[toolId] || null;
|
|
13285
|
+
}
|
|
13286
|
+
var init_formatters = __esm({
|
|
13287
|
+
"core/ai-tools/formatters.ts"() {
|
|
13288
|
+
"use strict";
|
|
13289
|
+
__name(formatForClaude, "formatForClaude");
|
|
13290
|
+
__name(formatForCursor, "formatForCursor");
|
|
13291
|
+
__name(formatForCopilot, "formatForCopilot");
|
|
13292
|
+
__name(formatForWindsurf, "formatForWindsurf");
|
|
13293
|
+
__name(formatForContinue, "formatForContinue");
|
|
13294
|
+
__name(getFormatter, "getFormatter");
|
|
13295
|
+
}
|
|
13296
|
+
});
|
|
13297
|
+
|
|
13298
|
+
// core/ai-tools/generator.ts
|
|
13299
|
+
import fs30 from "fs/promises";
|
|
13300
|
+
import path31 from "path";
|
|
13301
|
+
async function generateAIToolContexts(context2, globalPath, repoPath, toolIds = DEFAULT_AI_TOOLS) {
|
|
13302
|
+
const results = [];
|
|
13303
|
+
for (const toolId of toolIds) {
|
|
13304
|
+
const config = getAIToolConfig(toolId);
|
|
13305
|
+
if (!config) {
|
|
13306
|
+
results.push({
|
|
13307
|
+
toolId,
|
|
13308
|
+
outputFile: "",
|
|
13309
|
+
outputPath: "",
|
|
13310
|
+
success: false,
|
|
13311
|
+
error: `Unknown tool: ${toolId}`
|
|
13312
|
+
});
|
|
13313
|
+
continue;
|
|
13314
|
+
}
|
|
13315
|
+
const result = await generateForTool(context2, config, globalPath, repoPath);
|
|
13316
|
+
results.push(result);
|
|
13317
|
+
}
|
|
13318
|
+
return results;
|
|
13319
|
+
}
|
|
13320
|
+
async function generateForTool(context2, config, globalPath, repoPath) {
|
|
13321
|
+
const formatter = getFormatter(config.id);
|
|
13322
|
+
if (!formatter) {
|
|
13323
|
+
return {
|
|
13324
|
+
toolId: config.id,
|
|
13325
|
+
outputFile: config.outputFile,
|
|
13326
|
+
outputPath: "",
|
|
13327
|
+
success: false,
|
|
13328
|
+
error: `No formatter for: ${config.id}`
|
|
13329
|
+
};
|
|
13330
|
+
}
|
|
13331
|
+
try {
|
|
13332
|
+
const content = formatter(context2, config);
|
|
13333
|
+
let outputPath;
|
|
13334
|
+
if (config.outputPath === "repo") {
|
|
13335
|
+
outputPath = path31.join(repoPath, config.outputFile);
|
|
13336
|
+
} else {
|
|
13337
|
+
outputPath = path31.join(globalPath, "context", config.outputFile);
|
|
13338
|
+
}
|
|
13339
|
+
await fs30.mkdir(path31.dirname(outputPath), { recursive: true });
|
|
13340
|
+
await fs30.writeFile(outputPath, content, "utf-8");
|
|
13341
|
+
return {
|
|
13342
|
+
toolId: config.id,
|
|
13343
|
+
outputFile: config.outputFile,
|
|
13344
|
+
outputPath,
|
|
13345
|
+
success: true
|
|
13346
|
+
};
|
|
13347
|
+
} catch (error) {
|
|
13348
|
+
return {
|
|
13349
|
+
toolId: config.id,
|
|
13350
|
+
outputFile: config.outputFile,
|
|
13351
|
+
outputPath: "",
|
|
13352
|
+
success: false,
|
|
13353
|
+
error: error.message
|
|
13354
|
+
};
|
|
13355
|
+
}
|
|
13356
|
+
}
|
|
13357
|
+
var init_generator2 = __esm({
|
|
13358
|
+
"core/ai-tools/generator.ts"() {
|
|
13359
|
+
"use strict";
|
|
13360
|
+
init_registry();
|
|
13361
|
+
init_formatters();
|
|
13362
|
+
__name(generateAIToolContexts, "generateAIToolContexts");
|
|
13363
|
+
__name(generateForTool, "generateForTool");
|
|
13364
|
+
}
|
|
13365
|
+
});
|
|
13366
|
+
|
|
13367
|
+
// core/ai-tools/index.ts
|
|
13368
|
+
var init_ai_tools = __esm({
|
|
13369
|
+
"core/ai-tools/index.ts"() {
|
|
13370
|
+
"use strict";
|
|
13371
|
+
init_registry();
|
|
13372
|
+
init_formatters();
|
|
13373
|
+
init_generator2();
|
|
13374
|
+
}
|
|
13375
|
+
});
|
|
13376
|
+
|
|
13377
|
+
// core/services/sync-service.ts
|
|
13378
|
+
import fs31 from "fs/promises";
|
|
13379
|
+
import path32 from "path";
|
|
13380
|
+
import { exec as exec5 } from "child_process";
|
|
13381
|
+
import { promisify as promisify5 } from "util";
|
|
13382
|
+
var execAsync3, SyncService, syncService;
|
|
13383
|
+
var init_sync_service = __esm({
|
|
13384
|
+
"core/services/sync-service.ts"() {
|
|
13385
|
+
"use strict";
|
|
13386
|
+
init_path_manager();
|
|
13387
|
+
init_config_manager();
|
|
13388
|
+
init_date_helper();
|
|
13389
|
+
init_ai_tools();
|
|
13390
|
+
execAsync3 = promisify5(exec5);
|
|
13391
|
+
SyncService = class {
|
|
13392
|
+
static {
|
|
13393
|
+
__name(this, "SyncService");
|
|
13394
|
+
}
|
|
13395
|
+
projectPath;
|
|
13396
|
+
projectId = null;
|
|
13397
|
+
globalPath = "";
|
|
13398
|
+
cliVersion = "0.0.0";
|
|
13399
|
+
constructor() {
|
|
13400
|
+
this.projectPath = process.cwd();
|
|
13401
|
+
}
|
|
13402
|
+
/**
|
|
13403
|
+
* Main sync method - does everything in one call
|
|
13404
|
+
*/
|
|
13405
|
+
async sync(projectPath = process.cwd(), options = {}) {
|
|
13406
|
+
this.projectPath = projectPath;
|
|
13407
|
+
let aiToolIds;
|
|
13408
|
+
if (!options.aiTools || options.aiTools.length === 0) {
|
|
13409
|
+
aiToolIds = DEFAULT_AI_TOOLS;
|
|
13410
|
+
} else if (options.aiTools[0] === "auto") {
|
|
13411
|
+
aiToolIds = detectInstalledTools(projectPath);
|
|
13412
|
+
if (aiToolIds.length === 0) aiToolIds = ["claude"];
|
|
13413
|
+
} else if (options.aiTools[0] === "all") {
|
|
13414
|
+
aiToolIds = resolveToolIds("all", projectPath);
|
|
13415
|
+
} else {
|
|
13416
|
+
aiToolIds = options.aiTools;
|
|
13417
|
+
}
|
|
13418
|
+
try {
|
|
13419
|
+
this.projectId = await config_manager_default.getProjectId(projectPath);
|
|
13420
|
+
if (!this.projectId) {
|
|
13421
|
+
return {
|
|
13422
|
+
success: false,
|
|
13423
|
+
projectId: "",
|
|
13424
|
+
cliVersion: "",
|
|
13425
|
+
git: this.emptyGitData(),
|
|
13426
|
+
stats: this.emptyStats(),
|
|
13427
|
+
commands: this.emptyCommands(),
|
|
13428
|
+
stack: this.emptyStack(),
|
|
13429
|
+
agents: [],
|
|
13430
|
+
skills: [],
|
|
13431
|
+
contextFiles: [],
|
|
13432
|
+
aiTools: [],
|
|
13433
|
+
error: "No prjct project. Run p. init first."
|
|
13434
|
+
};
|
|
13435
|
+
}
|
|
12556
13436
|
this.globalPath = path_manager_default.getGlobalProjectPath(this.projectId);
|
|
12557
13437
|
this.cliVersion = await this.getCliVersion();
|
|
12558
13438
|
await this.ensureDirectories();
|
|
@@ -12563,6 +13443,31 @@ var init_sync_service = __esm({
|
|
|
12563
13443
|
const agents = await this.generateAgents(stack, stats);
|
|
12564
13444
|
const skills = this.configureSkills(agents);
|
|
12565
13445
|
const contextFiles = await this.generateContextFiles(git, stats, commands, agents);
|
|
13446
|
+
const projectContext = {
|
|
13447
|
+
projectId: this.projectId,
|
|
13448
|
+
name: stats.name,
|
|
13449
|
+
version: stats.version,
|
|
13450
|
+
ecosystem: stats.ecosystem,
|
|
13451
|
+
projectType: stats.projectType,
|
|
13452
|
+
languages: stats.languages,
|
|
13453
|
+
frameworks: stats.frameworks,
|
|
13454
|
+
repoPath: this.projectPath,
|
|
13455
|
+
branch: git.branch,
|
|
13456
|
+
fileCount: stats.fileCount,
|
|
13457
|
+
commits: git.commits,
|
|
13458
|
+
hasChanges: git.hasChanges,
|
|
13459
|
+
commands,
|
|
13460
|
+
agents: {
|
|
13461
|
+
workflow: agents.filter((a) => a.type === "workflow").map((a) => a.name),
|
|
13462
|
+
domain: agents.filter((a) => a.type === "domain").map((a) => a.name)
|
|
13463
|
+
}
|
|
13464
|
+
};
|
|
13465
|
+
const aiToolResults = await generateAIToolContexts(
|
|
13466
|
+
projectContext,
|
|
13467
|
+
this.globalPath,
|
|
13468
|
+
this.projectPath,
|
|
13469
|
+
aiToolIds
|
|
13470
|
+
);
|
|
12566
13471
|
await this.updateProjectJson(git, stats);
|
|
12567
13472
|
await this.updateStateJson(stats, stack);
|
|
12568
13473
|
await this.logToMemory(git, stats);
|
|
@@ -12576,7 +13481,12 @@ var init_sync_service = __esm({
|
|
|
12576
13481
|
stack,
|
|
12577
13482
|
agents,
|
|
12578
13483
|
skills,
|
|
12579
|
-
contextFiles
|
|
13484
|
+
contextFiles,
|
|
13485
|
+
aiTools: aiToolResults.map((r) => ({
|
|
13486
|
+
toolId: r.toolId,
|
|
13487
|
+
outputFile: r.outputFile,
|
|
13488
|
+
success: r.success
|
|
13489
|
+
}))
|
|
12580
13490
|
};
|
|
12581
13491
|
} catch (error) {
|
|
12582
13492
|
return {
|
|
@@ -12590,6 +13500,7 @@ var init_sync_service = __esm({
|
|
|
12590
13500
|
agents: [],
|
|
12591
13501
|
skills: [],
|
|
12592
13502
|
contextFiles: [],
|
|
13503
|
+
aiTools: [],
|
|
12593
13504
|
error: error.message
|
|
12594
13505
|
};
|
|
12595
13506
|
}
|
|
@@ -12600,7 +13511,7 @@ var init_sync_service = __esm({
|
|
|
12600
13511
|
async ensureDirectories() {
|
|
12601
13512
|
const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
|
|
12602
13513
|
for (const dir of dirs) {
|
|
12603
|
-
await
|
|
13514
|
+
await fs31.mkdir(path32.join(this.globalPath, dir), { recursive: true });
|
|
12604
13515
|
}
|
|
12605
13516
|
}
|
|
12606
13517
|
// ==========================================================================
|
|
@@ -12670,7 +13581,7 @@ var init_sync_service = __esm({
|
|
|
12670
13581
|
const stats = {
|
|
12671
13582
|
fileCount: 0,
|
|
12672
13583
|
version: "0.0.0",
|
|
12673
|
-
name:
|
|
13584
|
+
name: path32.basename(this.projectPath),
|
|
12674
13585
|
ecosystem: "unknown",
|
|
12675
13586
|
projectType: "simple",
|
|
12676
13587
|
languages: [],
|
|
@@ -12686,8 +13597,8 @@ var init_sync_service = __esm({
|
|
|
12686
13597
|
stats.fileCount = 0;
|
|
12687
13598
|
}
|
|
12688
13599
|
try {
|
|
12689
|
-
const pkgPath =
|
|
12690
|
-
const pkg = JSON.parse(await
|
|
13600
|
+
const pkgPath = path32.join(this.projectPath, "package.json");
|
|
13601
|
+
const pkg = JSON.parse(await fs31.readFile(pkgPath, "utf-8"));
|
|
12691
13602
|
stats.version = pkg.version || "0.0.0";
|
|
12692
13603
|
stats.name = pkg.name || stats.name;
|
|
12693
13604
|
stats.ecosystem = "JavaScript";
|
|
@@ -12797,8 +13708,8 @@ var init_sync_service = __esm({
|
|
|
12797
13708
|
frameworks: []
|
|
12798
13709
|
};
|
|
12799
13710
|
try {
|
|
12800
|
-
const pkgPath =
|
|
12801
|
-
const pkg = JSON.parse(await
|
|
13711
|
+
const pkgPath = path32.join(this.projectPath, "package.json");
|
|
13712
|
+
const pkg = JSON.parse(await fs31.readFile(pkgPath, "utf-8"));
|
|
12802
13713
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12803
13714
|
if (deps.react || deps.vue || deps.svelte || deps["@angular/core"]) {
|
|
12804
13715
|
stack.hasFrontend = true;
|
|
@@ -12831,12 +13742,12 @@ var init_sync_service = __esm({
|
|
|
12831
13742
|
// ==========================================================================
|
|
12832
13743
|
async generateAgents(stack, stats) {
|
|
12833
13744
|
const agents = [];
|
|
12834
|
-
const agentsPath =
|
|
13745
|
+
const agentsPath = path32.join(this.globalPath, "agents");
|
|
12835
13746
|
try {
|
|
12836
|
-
const files = await
|
|
13747
|
+
const files = await fs31.readdir(agentsPath);
|
|
12837
13748
|
for (const file of files) {
|
|
12838
13749
|
if (file.endsWith(".md")) {
|
|
12839
|
-
await
|
|
13750
|
+
await fs31.unlink(path32.join(agentsPath, file));
|
|
12840
13751
|
}
|
|
12841
13752
|
}
|
|
12842
13753
|
} catch {
|
|
@@ -12873,7 +13784,7 @@ var init_sync_service = __esm({
|
|
|
12873
13784
|
async generateWorkflowAgent(name, agentsPath) {
|
|
12874
13785
|
let content = "";
|
|
12875
13786
|
try {
|
|
12876
|
-
const templatePath =
|
|
13787
|
+
const templatePath = path32.join(
|
|
12877
13788
|
__dirname,
|
|
12878
13789
|
"..",
|
|
12879
13790
|
"..",
|
|
@@ -12882,16 +13793,16 @@ var init_sync_service = __esm({
|
|
|
12882
13793
|
"workflow",
|
|
12883
13794
|
`${name}.md`
|
|
12884
13795
|
);
|
|
12885
|
-
content = await
|
|
13796
|
+
content = await fs31.readFile(templatePath, "utf-8");
|
|
12886
13797
|
} catch {
|
|
12887
13798
|
content = this.generateMinimalWorkflowAgent(name);
|
|
12888
13799
|
}
|
|
12889
|
-
await
|
|
13800
|
+
await fs31.writeFile(path32.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
12890
13801
|
}
|
|
12891
13802
|
async generateDomainAgent(name, agentsPath, stats, stack) {
|
|
12892
13803
|
let content = "";
|
|
12893
13804
|
try {
|
|
12894
|
-
const templatePath =
|
|
13805
|
+
const templatePath = path32.join(
|
|
12895
13806
|
__dirname,
|
|
12896
13807
|
"..",
|
|
12897
13808
|
"..",
|
|
@@ -12900,14 +13811,14 @@ var init_sync_service = __esm({
|
|
|
12900
13811
|
"domain",
|
|
12901
13812
|
`${name}.md`
|
|
12902
13813
|
);
|
|
12903
|
-
content = await
|
|
13814
|
+
content = await fs31.readFile(templatePath, "utf-8");
|
|
12904
13815
|
content = content.replace("{projectName}", stats.name);
|
|
12905
13816
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
12906
13817
|
content = content.replace("{ecosystem}", stats.ecosystem);
|
|
12907
13818
|
} catch {
|
|
12908
13819
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
12909
13820
|
}
|
|
12910
|
-
await
|
|
13821
|
+
await fs31.writeFile(path32.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
12911
13822
|
}
|
|
12912
13823
|
generateMinimalWorkflowAgent(name) {
|
|
12913
13824
|
const descriptions = {
|
|
@@ -12975,8 +13886,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
12975
13886
|
})),
|
|
12976
13887
|
agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
|
|
12977
13888
|
};
|
|
12978
|
-
|
|
12979
|
-
|
|
13889
|
+
fs31.writeFile(
|
|
13890
|
+
path32.join(this.globalPath, "config", "skills.json"),
|
|
12980
13891
|
JSON.stringify(skillsConfig, null, 2),
|
|
12981
13892
|
"utf-8"
|
|
12982
13893
|
).catch(() => {
|
|
@@ -12987,7 +13898,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
12987
13898
|
// CONTEXT FILE GENERATION
|
|
12988
13899
|
// ==========================================================================
|
|
12989
13900
|
async generateContextFiles(git, stats, commands, agents) {
|
|
12990
|
-
const contextPath =
|
|
13901
|
+
const contextPath = path32.join(this.globalPath, "context");
|
|
12991
13902
|
const files = [];
|
|
12992
13903
|
await this.generateClaudeMd(contextPath, git, stats, commands, agents);
|
|
12993
13904
|
files.push("context/CLAUDE.md");
|
|
@@ -13073,13 +13984,13 @@ Load from \`~/.prjct-cli/projects/${this.projectId}/agents/\`:
|
|
|
13073
13984
|
**Workflow**: ${workflowAgents.join(", ")}
|
|
13074
13985
|
**Domain**: ${domainAgents.join(", ") || "none"}
|
|
13075
13986
|
`;
|
|
13076
|
-
await
|
|
13987
|
+
await fs31.writeFile(path32.join(contextPath, "CLAUDE.md"), content, "utf-8");
|
|
13077
13988
|
}
|
|
13078
13989
|
async generateNowMd(contextPath) {
|
|
13079
13990
|
let currentTask = null;
|
|
13080
13991
|
try {
|
|
13081
|
-
const statePath =
|
|
13082
|
-
const state = JSON.parse(await
|
|
13992
|
+
const statePath = path32.join(this.globalPath, "storage", "state.json");
|
|
13993
|
+
const state = JSON.parse(await fs31.readFile(statePath, "utf-8"));
|
|
13083
13994
|
currentTask = state.currentTask;
|
|
13084
13995
|
} catch {
|
|
13085
13996
|
}
|
|
@@ -13095,41 +14006,41 @@ _No active task_
|
|
|
13095
14006
|
|
|
13096
14007
|
Use \`p. task "description"\` to start working.
|
|
13097
14008
|
`;
|
|
13098
|
-
await
|
|
14009
|
+
await fs31.writeFile(path32.join(contextPath, "now.md"), content, "utf-8");
|
|
13099
14010
|
}
|
|
13100
14011
|
async generateNextMd(contextPath) {
|
|
13101
14012
|
let queue = { tasks: [] };
|
|
13102
14013
|
try {
|
|
13103
|
-
const queuePath =
|
|
13104
|
-
queue = JSON.parse(await
|
|
14014
|
+
const queuePath = path32.join(this.globalPath, "storage", "queue.json");
|
|
14015
|
+
queue = JSON.parse(await fs31.readFile(queuePath, "utf-8"));
|
|
13105
14016
|
} catch {
|
|
13106
14017
|
}
|
|
13107
14018
|
const content = `# NEXT
|
|
13108
14019
|
|
|
13109
14020
|
${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}${t.priority ? ` [${t.priority}]` : ""}`).join("\n") : "_Empty queue_"}
|
|
13110
14021
|
`;
|
|
13111
|
-
await
|
|
14022
|
+
await fs31.writeFile(path32.join(contextPath, "next.md"), content, "utf-8");
|
|
13112
14023
|
}
|
|
13113
14024
|
async generateIdeasMd(contextPath) {
|
|
13114
14025
|
let ideas = { ideas: [] };
|
|
13115
14026
|
try {
|
|
13116
|
-
const ideasPath =
|
|
13117
|
-
ideas = JSON.parse(await
|
|
14027
|
+
const ideasPath = path32.join(this.globalPath, "storage", "ideas.json");
|
|
14028
|
+
ideas = JSON.parse(await fs31.readFile(ideasPath, "utf-8"));
|
|
13118
14029
|
} catch {
|
|
13119
14030
|
}
|
|
13120
14031
|
const content = `# IDEAS
|
|
13121
14032
|
|
|
13122
14033
|
${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [${i.priority}]` : ""}`).join("\n") : "_No ideas captured yet_"}
|
|
13123
14034
|
`;
|
|
13124
|
-
await
|
|
14035
|
+
await fs31.writeFile(path32.join(contextPath, "ideas.md"), content, "utf-8");
|
|
13125
14036
|
}
|
|
13126
14037
|
async generateShippedMd(contextPath) {
|
|
13127
14038
|
let shipped = {
|
|
13128
14039
|
shipped: []
|
|
13129
14040
|
};
|
|
13130
14041
|
try {
|
|
13131
|
-
const shippedPath =
|
|
13132
|
-
shipped = JSON.parse(await
|
|
14042
|
+
const shippedPath = path32.join(this.globalPath, "storage", "shipped.json");
|
|
14043
|
+
shipped = JSON.parse(await fs31.readFile(shippedPath, "utf-8"));
|
|
13133
14044
|
} catch {
|
|
13134
14045
|
}
|
|
13135
14046
|
const content = `# SHIPPED \u{1F680}
|
|
@@ -13138,16 +14049,16 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
13138
14049
|
|
|
13139
14050
|
**Total shipped:** ${shipped.shipped.length}
|
|
13140
14051
|
`;
|
|
13141
|
-
await
|
|
14052
|
+
await fs31.writeFile(path32.join(contextPath, "shipped.md"), content, "utf-8");
|
|
13142
14053
|
}
|
|
13143
14054
|
// ==========================================================================
|
|
13144
14055
|
// PROJECT.JSON UPDATE
|
|
13145
14056
|
// ==========================================================================
|
|
13146
14057
|
async updateProjectJson(git, stats) {
|
|
13147
|
-
const projectJsonPath =
|
|
14058
|
+
const projectJsonPath = path32.join(this.globalPath, "project.json");
|
|
13148
14059
|
let existing = {};
|
|
13149
14060
|
try {
|
|
13150
|
-
existing = JSON.parse(await
|
|
14061
|
+
existing = JSON.parse(await fs31.readFile(projectJsonPath, "utf-8"));
|
|
13151
14062
|
} catch {
|
|
13152
14063
|
}
|
|
13153
14064
|
const updated = {
|
|
@@ -13166,16 +14077,16 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
13166
14077
|
createdAt: existing.createdAt || date_helper_default.getTimestamp(),
|
|
13167
14078
|
lastSync: date_helper_default.getTimestamp()
|
|
13168
14079
|
};
|
|
13169
|
-
await
|
|
14080
|
+
await fs31.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
13170
14081
|
}
|
|
13171
14082
|
// ==========================================================================
|
|
13172
14083
|
// STATE.JSON UPDATE
|
|
13173
14084
|
// ==========================================================================
|
|
13174
14085
|
async updateStateJson(stats, stack) {
|
|
13175
|
-
const statePath =
|
|
14086
|
+
const statePath = path32.join(this.globalPath, "storage", "state.json");
|
|
13176
14087
|
let state = {};
|
|
13177
14088
|
try {
|
|
13178
|
-
state = JSON.parse(await
|
|
14089
|
+
state = JSON.parse(await fs31.readFile(statePath, "utf-8"));
|
|
13179
14090
|
} catch {
|
|
13180
14091
|
}
|
|
13181
14092
|
state.projectId = this.projectId;
|
|
@@ -13202,13 +14113,13 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
13202
14113
|
lastAction: "Synced project",
|
|
13203
14114
|
nextAction: 'Run `p. task "description"` to start working'
|
|
13204
14115
|
};
|
|
13205
|
-
await
|
|
14116
|
+
await fs31.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
13206
14117
|
}
|
|
13207
14118
|
// ==========================================================================
|
|
13208
14119
|
// MEMORY LOGGING
|
|
13209
14120
|
// ==========================================================================
|
|
13210
14121
|
async logToMemory(git, stats) {
|
|
13211
|
-
const memoryPath =
|
|
14122
|
+
const memoryPath = path32.join(this.globalPath, "memory", "events.jsonl");
|
|
13212
14123
|
const event = {
|
|
13213
14124
|
ts: date_helper_default.getTimestamp(),
|
|
13214
14125
|
action: "sync",
|
|
@@ -13217,14 +14128,14 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
13217
14128
|
fileCount: stats.fileCount,
|
|
13218
14129
|
commitCount: git.commits
|
|
13219
14130
|
};
|
|
13220
|
-
await
|
|
14131
|
+
await fs31.appendFile(memoryPath, JSON.stringify(event) + "\n", "utf-8");
|
|
13221
14132
|
}
|
|
13222
14133
|
// ==========================================================================
|
|
13223
14134
|
// HELPERS
|
|
13224
14135
|
// ==========================================================================
|
|
13225
14136
|
async fileExists(filename) {
|
|
13226
14137
|
try {
|
|
13227
|
-
await
|
|
14138
|
+
await fs31.access(path32.join(this.projectPath, filename));
|
|
13228
14139
|
return true;
|
|
13229
14140
|
} catch {
|
|
13230
14141
|
return false;
|
|
@@ -13232,8 +14143,8 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
13232
14143
|
}
|
|
13233
14144
|
async getCliVersion() {
|
|
13234
14145
|
try {
|
|
13235
|
-
const pkgPath =
|
|
13236
|
-
const pkg = JSON.parse(await
|
|
14146
|
+
const pkgPath = path32.join(__dirname, "..", "..", "package.json");
|
|
14147
|
+
const pkg = JSON.parse(await fs31.readFile(pkgPath, "utf-8"));
|
|
13237
14148
|
return pkg.version || "0.0.0";
|
|
13238
14149
|
} catch {
|
|
13239
14150
|
return "0.0.0";
|
|
@@ -13378,6 +14289,886 @@ var init_base = __esm({
|
|
|
13378
14289
|
}
|
|
13379
14290
|
});
|
|
13380
14291
|
|
|
14292
|
+
// core/utils/keychain.ts
|
|
14293
|
+
import { exec as exec6 } from "child_process";
|
|
14294
|
+
import { promisify as promisify6 } from "util";
|
|
14295
|
+
async function getCredential(key) {
|
|
14296
|
+
if (process.platform !== "darwin") {
|
|
14297
|
+
return getEnvFallback(key);
|
|
14298
|
+
}
|
|
14299
|
+
try {
|
|
14300
|
+
const { stdout } = await execAsync4(
|
|
14301
|
+
`security find-generic-password -s "${SERVICE_NAME}" -a "${key}" -w 2>/dev/null`
|
|
14302
|
+
);
|
|
14303
|
+
return stdout.trim() || null;
|
|
14304
|
+
} catch (_error) {
|
|
14305
|
+
return getEnvFallback(key);
|
|
14306
|
+
}
|
|
14307
|
+
}
|
|
14308
|
+
function getEnvFallback(key) {
|
|
14309
|
+
const envMap = {
|
|
14310
|
+
"linear-api-key": "LINEAR_API_KEY",
|
|
14311
|
+
"jira-api-token": "JIRA_API_TOKEN"
|
|
14312
|
+
};
|
|
14313
|
+
const envVar = envMap[key];
|
|
14314
|
+
return process.env[envVar] || null;
|
|
14315
|
+
}
|
|
14316
|
+
var execAsync4, SERVICE_NAME;
|
|
14317
|
+
var init_keychain = __esm({
|
|
14318
|
+
"core/utils/keychain.ts"() {
|
|
14319
|
+
"use strict";
|
|
14320
|
+
execAsync4 = promisify6(exec6);
|
|
14321
|
+
SERVICE_NAME = "prjct-cli";
|
|
14322
|
+
__name(getCredential, "getCredential");
|
|
14323
|
+
__name(getEnvFallback, "getEnvFallback");
|
|
14324
|
+
}
|
|
14325
|
+
});
|
|
14326
|
+
|
|
14327
|
+
// core/integrations/linear/client.ts
|
|
14328
|
+
import { LinearClient as LinearSDK } from "@linear/sdk";
|
|
14329
|
+
var LINEAR_STATUS_MAP, LINEAR_PRIORITY_MAP, PRIORITY_TO_LINEAR, LinearProvider, linearProvider;
|
|
14330
|
+
var init_client = __esm({
|
|
14331
|
+
"core/integrations/linear/client.ts"() {
|
|
14332
|
+
"use strict";
|
|
14333
|
+
init_keychain();
|
|
14334
|
+
LINEAR_STATUS_MAP = {
|
|
14335
|
+
backlog: "backlog",
|
|
14336
|
+
unstarted: "todo",
|
|
14337
|
+
started: "in_progress",
|
|
14338
|
+
completed: "done",
|
|
14339
|
+
canceled: "cancelled",
|
|
14340
|
+
cancelled: "cancelled"
|
|
14341
|
+
};
|
|
14342
|
+
LINEAR_PRIORITY_MAP = {
|
|
14343
|
+
0: "none",
|
|
14344
|
+
1: "urgent",
|
|
14345
|
+
2: "high",
|
|
14346
|
+
3: "medium",
|
|
14347
|
+
4: "low"
|
|
14348
|
+
};
|
|
14349
|
+
PRIORITY_TO_LINEAR = {
|
|
14350
|
+
none: 0,
|
|
14351
|
+
urgent: 1,
|
|
14352
|
+
high: 2,
|
|
14353
|
+
medium: 3,
|
|
14354
|
+
low: 4
|
|
14355
|
+
};
|
|
14356
|
+
LinearProvider = class {
|
|
14357
|
+
static {
|
|
14358
|
+
__name(this, "LinearProvider");
|
|
14359
|
+
}
|
|
14360
|
+
name = "linear";
|
|
14361
|
+
displayName = "Linear";
|
|
14362
|
+
sdk = null;
|
|
14363
|
+
config = null;
|
|
14364
|
+
/**
|
|
14365
|
+
* Check if provider is configured
|
|
14366
|
+
*/
|
|
14367
|
+
isConfigured() {
|
|
14368
|
+
return this.sdk !== null && this.config?.enabled === true;
|
|
14369
|
+
}
|
|
14370
|
+
/**
|
|
14371
|
+
* Initialize with config
|
|
14372
|
+
* Looks for API key in: 1) config.apiKey, 2) macOS Keychain, 3) LINEAR_API_KEY env var
|
|
14373
|
+
*/
|
|
14374
|
+
async initialize(config) {
|
|
14375
|
+
this.config = config;
|
|
14376
|
+
const apiKey = config.apiKey || await getCredential("linear-api-key");
|
|
14377
|
+
if (!apiKey) {
|
|
14378
|
+
throw new Error(
|
|
14379
|
+
"LINEAR_API_KEY not configured. Run `p. linear setup` to configure."
|
|
14380
|
+
);
|
|
14381
|
+
}
|
|
14382
|
+
this.sdk = new LinearSDK({ apiKey });
|
|
14383
|
+
try {
|
|
14384
|
+
const viewer = await this.sdk.viewer;
|
|
14385
|
+
console.error(`[linear] Connected as ${viewer.name} (${viewer.email})`);
|
|
14386
|
+
} catch (error) {
|
|
14387
|
+
this.sdk = null;
|
|
14388
|
+
throw new Error(`Linear connection failed: ${error.message}`);
|
|
14389
|
+
}
|
|
14390
|
+
}
|
|
14391
|
+
/**
|
|
14392
|
+
* Get issues assigned to current user
|
|
14393
|
+
* Filters by configured team if defaultTeamId is set
|
|
14394
|
+
*/
|
|
14395
|
+
async fetchAssignedIssues(options) {
|
|
14396
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14397
|
+
const viewer = await this.sdk.viewer;
|
|
14398
|
+
const filter = {};
|
|
14399
|
+
if (!options?.includeCompleted) {
|
|
14400
|
+
filter.state = { type: { nin: ["completed", "canceled"] } };
|
|
14401
|
+
}
|
|
14402
|
+
if (this.config?.defaultTeamId) {
|
|
14403
|
+
filter.team = { id: { eq: this.config.defaultTeamId } };
|
|
14404
|
+
}
|
|
14405
|
+
const assignedIssues = await viewer.assignedIssues({
|
|
14406
|
+
first: options?.limit || 50,
|
|
14407
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
14408
|
+
});
|
|
14409
|
+
return Promise.all(
|
|
14410
|
+
assignedIssues.nodes.map((issue) => this.mapIssue(issue))
|
|
14411
|
+
);
|
|
14412
|
+
}
|
|
14413
|
+
/**
|
|
14414
|
+
* Get issues from a team
|
|
14415
|
+
*/
|
|
14416
|
+
async fetchTeamIssues(teamId, options) {
|
|
14417
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14418
|
+
const team = await this.sdk.team(teamId);
|
|
14419
|
+
const issues = await team.issues({
|
|
14420
|
+
first: options?.limit || 50,
|
|
14421
|
+
filter: options?.includeCompleted ? void 0 : { state: { type: { nin: ["completed", "canceled"] } } }
|
|
14422
|
+
});
|
|
14423
|
+
return Promise.all(issues.nodes.map((issue) => this.mapIssue(issue)));
|
|
14424
|
+
}
|
|
14425
|
+
/**
|
|
14426
|
+
* Get a single issue by ID or identifier (e.g., "PRJ-123")
|
|
14427
|
+
*/
|
|
14428
|
+
async fetchIssue(id) {
|
|
14429
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14430
|
+
try {
|
|
14431
|
+
if (id.includes("-") && /^[A-Z]+-\d+$/.test(id)) {
|
|
14432
|
+
const match = id.match(/^([A-Z]+)-(\d+)$/);
|
|
14433
|
+
if (!match) return null;
|
|
14434
|
+
const [, teamKey, numberStr] = match;
|
|
14435
|
+
const issueNumber = parseInt(numberStr, 10);
|
|
14436
|
+
const teams = await this.sdk.teams({ first: 50 });
|
|
14437
|
+
const team = teams.nodes.find((t) => t.key === teamKey);
|
|
14438
|
+
if (!team) return null;
|
|
14439
|
+
const issues = await team.issues({
|
|
14440
|
+
first: 1,
|
|
14441
|
+
filter: { number: { eq: issueNumber } }
|
|
14442
|
+
});
|
|
14443
|
+
if (issues.nodes.length > 0) {
|
|
14444
|
+
return this.mapIssue(issues.nodes[0]);
|
|
14445
|
+
}
|
|
14446
|
+
return null;
|
|
14447
|
+
}
|
|
14448
|
+
const issue = await this.sdk.issue(id);
|
|
14449
|
+
return this.mapIssue(issue);
|
|
14450
|
+
} catch (_error) {
|
|
14451
|
+
return null;
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
/**
|
|
14455
|
+
* Create a new issue
|
|
14456
|
+
*/
|
|
14457
|
+
async createIssue(input) {
|
|
14458
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14459
|
+
const teamId = input.teamId || this.config?.defaultTeamId;
|
|
14460
|
+
if (!teamId) {
|
|
14461
|
+
throw new Error("Team ID required for creating issues");
|
|
14462
|
+
}
|
|
14463
|
+
const payload = await this.sdk.createIssue({
|
|
14464
|
+
teamId,
|
|
14465
|
+
title: input.title,
|
|
14466
|
+
description: input.description,
|
|
14467
|
+
priority: input.priority ? PRIORITY_TO_LINEAR[input.priority] : void 0,
|
|
14468
|
+
projectId: input.projectId || this.config?.defaultProjectId,
|
|
14469
|
+
assigneeId: input.assigneeId,
|
|
14470
|
+
labelIds: input.labels ? await this.resolveLabelIds(teamId, input.labels) : void 0
|
|
14471
|
+
});
|
|
14472
|
+
const createdIssue = await payload.issue;
|
|
14473
|
+
if (!createdIssue) {
|
|
14474
|
+
throw new Error("Failed to create issue");
|
|
14475
|
+
}
|
|
14476
|
+
return this.mapIssue(createdIssue);
|
|
14477
|
+
}
|
|
14478
|
+
/**
|
|
14479
|
+
* Update an issue
|
|
14480
|
+
*/
|
|
14481
|
+
async updateIssue(id, input) {
|
|
14482
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14483
|
+
const issue = await this.fetchIssue(id);
|
|
14484
|
+
if (!issue) {
|
|
14485
|
+
throw new Error(`Issue ${id} not found`);
|
|
14486
|
+
}
|
|
14487
|
+
const updatePayload = {};
|
|
14488
|
+
if (input.title !== void 0) updatePayload.title = input.title;
|
|
14489
|
+
if (input.description !== void 0) updatePayload.description = input.description;
|
|
14490
|
+
if (input.priority !== void 0) updatePayload.priority = PRIORITY_TO_LINEAR[input.priority];
|
|
14491
|
+
if (input.assigneeId !== void 0) updatePayload.assigneeId = input.assigneeId;
|
|
14492
|
+
if (input.stateId !== void 0) updatePayload.stateId = input.stateId;
|
|
14493
|
+
if (input.projectId !== void 0) updatePayload.projectId = input.projectId;
|
|
14494
|
+
if (input.labels !== void 0 && issue.team) {
|
|
14495
|
+
updatePayload.labelIds = await this.resolveLabelIds(issue.team.id, input.labels);
|
|
14496
|
+
}
|
|
14497
|
+
await this.sdk.updateIssue(issue.id, updatePayload);
|
|
14498
|
+
const updated = await this.fetchIssue(issue.id);
|
|
14499
|
+
if (!updated) {
|
|
14500
|
+
throw new Error("Failed to fetch updated issue");
|
|
14501
|
+
}
|
|
14502
|
+
return updated;
|
|
14503
|
+
}
|
|
14504
|
+
/**
|
|
14505
|
+
* Mark issue as in progress
|
|
14506
|
+
*/
|
|
14507
|
+
async markInProgress(id) {
|
|
14508
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14509
|
+
const issue = await this.fetchIssue(id);
|
|
14510
|
+
if (!issue) throw new Error(`Issue ${id} not found`);
|
|
14511
|
+
const linearIssue = await this.sdk.issue(issue.id);
|
|
14512
|
+
const team = await linearIssue.team;
|
|
14513
|
+
if (!team) throw new Error("Issue has no team");
|
|
14514
|
+
const states = await team.states();
|
|
14515
|
+
const startedState = states.nodes.find((s) => s.type === "started");
|
|
14516
|
+
if (startedState) {
|
|
14517
|
+
await this.sdk.updateIssue(issue.id, { stateId: startedState.id });
|
|
14518
|
+
}
|
|
14519
|
+
}
|
|
14520
|
+
/**
|
|
14521
|
+
* Mark issue as done
|
|
14522
|
+
*/
|
|
14523
|
+
async markDone(id) {
|
|
14524
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14525
|
+
const issue = await this.fetchIssue(id);
|
|
14526
|
+
if (!issue) throw new Error(`Issue ${id} not found`);
|
|
14527
|
+
const linearIssue = await this.sdk.issue(issue.id);
|
|
14528
|
+
const team = await linearIssue.team;
|
|
14529
|
+
if (!team) throw new Error("Issue has no team");
|
|
14530
|
+
const states = await team.states();
|
|
14531
|
+
const doneState = states.nodes.find((s) => s.type === "completed");
|
|
14532
|
+
if (doneState) {
|
|
14533
|
+
await this.sdk.updateIssue(issue.id, { stateId: doneState.id });
|
|
14534
|
+
}
|
|
14535
|
+
}
|
|
14536
|
+
/**
|
|
14537
|
+
* Add a comment to an issue
|
|
14538
|
+
*/
|
|
14539
|
+
async addComment(id, body) {
|
|
14540
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14541
|
+
const issue = await this.fetchIssue(id);
|
|
14542
|
+
if (!issue) throw new Error(`Issue ${id} not found`);
|
|
14543
|
+
await this.sdk.createComment({
|
|
14544
|
+
issueId: issue.id,
|
|
14545
|
+
body
|
|
14546
|
+
});
|
|
14547
|
+
}
|
|
14548
|
+
/**
|
|
14549
|
+
* Get available teams
|
|
14550
|
+
*/
|
|
14551
|
+
async getTeams() {
|
|
14552
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14553
|
+
const teams = await this.sdk.teams({ first: 50 });
|
|
14554
|
+
return teams.nodes.map((team) => ({
|
|
14555
|
+
id: team.id,
|
|
14556
|
+
name: team.name,
|
|
14557
|
+
key: team.key
|
|
14558
|
+
}));
|
|
14559
|
+
}
|
|
14560
|
+
/**
|
|
14561
|
+
* Get available projects
|
|
14562
|
+
*/
|
|
14563
|
+
async getProjects() {
|
|
14564
|
+
if (!this.sdk) throw new Error("Linear not initialized");
|
|
14565
|
+
const projects = await this.sdk.projects({ first: 50 });
|
|
14566
|
+
return projects.nodes.map((project) => ({
|
|
14567
|
+
id: project.id,
|
|
14568
|
+
name: project.name
|
|
14569
|
+
}));
|
|
14570
|
+
}
|
|
14571
|
+
// =============================================================================
|
|
14572
|
+
// Private Helpers
|
|
14573
|
+
// =============================================================================
|
|
14574
|
+
/**
|
|
14575
|
+
* Map Linear issue to normalized Issue
|
|
14576
|
+
*/
|
|
14577
|
+
async mapIssue(linearIssue) {
|
|
14578
|
+
const state = await linearIssue.state;
|
|
14579
|
+
const assignee = await linearIssue.assignee;
|
|
14580
|
+
const team = await linearIssue.team;
|
|
14581
|
+
const project = await linearIssue.project;
|
|
14582
|
+
const labels = await linearIssue.labels();
|
|
14583
|
+
return {
|
|
14584
|
+
id: linearIssue.id,
|
|
14585
|
+
externalId: linearIssue.identifier,
|
|
14586
|
+
provider: "linear",
|
|
14587
|
+
title: linearIssue.title,
|
|
14588
|
+
description: linearIssue.description || void 0,
|
|
14589
|
+
status: LINEAR_STATUS_MAP[state?.type || "backlog"] || "backlog",
|
|
14590
|
+
priority: LINEAR_PRIORITY_MAP[linearIssue.priority] || "none",
|
|
14591
|
+
type: this.inferType(linearIssue.title, labels.nodes.map((l) => l.name)),
|
|
14592
|
+
assignee: assignee ? {
|
|
14593
|
+
id: assignee.id,
|
|
14594
|
+
name: assignee.name,
|
|
14595
|
+
email: assignee.email
|
|
14596
|
+
} : void 0,
|
|
14597
|
+
labels: labels.nodes.map((l) => l.name),
|
|
14598
|
+
team: team ? {
|
|
14599
|
+
id: team.id,
|
|
14600
|
+
name: team.name,
|
|
14601
|
+
key: team.key
|
|
14602
|
+
} : void 0,
|
|
14603
|
+
project: project ? {
|
|
14604
|
+
id: project.id,
|
|
14605
|
+
name: project.name
|
|
14606
|
+
} : void 0,
|
|
14607
|
+
url: linearIssue.url,
|
|
14608
|
+
createdAt: linearIssue.createdAt.toISOString(),
|
|
14609
|
+
updatedAt: linearIssue.updatedAt.toISOString(),
|
|
14610
|
+
raw: linearIssue
|
|
14611
|
+
};
|
|
14612
|
+
}
|
|
14613
|
+
/**
|
|
14614
|
+
* Infer issue type from title and labels
|
|
14615
|
+
*/
|
|
14616
|
+
inferType(title, labels) {
|
|
14617
|
+
const titleLower = title.toLowerCase();
|
|
14618
|
+
const labelsLower = labels.map((l) => l.toLowerCase());
|
|
14619
|
+
if (labelsLower.includes("bug") || titleLower.includes("fix") || titleLower.includes("bug")) {
|
|
14620
|
+
return "bug";
|
|
14621
|
+
}
|
|
14622
|
+
if (labelsLower.includes("feature") || titleLower.includes("add") || titleLower.includes("implement")) {
|
|
14623
|
+
return "feature";
|
|
14624
|
+
}
|
|
14625
|
+
if (labelsLower.includes("improvement") || titleLower.includes("improve") || titleLower.includes("enhance")) {
|
|
14626
|
+
return "improvement";
|
|
14627
|
+
}
|
|
14628
|
+
if (labelsLower.includes("chore") || titleLower.includes("chore") || titleLower.includes("deps")) {
|
|
14629
|
+
return "chore";
|
|
14630
|
+
}
|
|
14631
|
+
return "task";
|
|
14632
|
+
}
|
|
14633
|
+
/**
|
|
14634
|
+
* Resolve label names to IDs
|
|
14635
|
+
*/
|
|
14636
|
+
async resolveLabelIds(teamId, labelNames) {
|
|
14637
|
+
if (!this.sdk) return [];
|
|
14638
|
+
const team = await this.sdk.team(teamId);
|
|
14639
|
+
const labels = await team.labels();
|
|
14640
|
+
return labels.nodes.filter((label) => labelNames.includes(label.name)).map((label) => label.id);
|
|
14641
|
+
}
|
|
14642
|
+
};
|
|
14643
|
+
linearProvider = new LinearProvider();
|
|
14644
|
+
}
|
|
14645
|
+
});
|
|
14646
|
+
|
|
14647
|
+
// core/integrations/linear/cache.ts
|
|
14648
|
+
function clearLinearCache() {
|
|
14649
|
+
issueCache.clear();
|
|
14650
|
+
assignedIssuesCache.clear();
|
|
14651
|
+
teamsCache.clear();
|
|
14652
|
+
projectsCache.clear();
|
|
14653
|
+
}
|
|
14654
|
+
function getLinearCacheStats() {
|
|
14655
|
+
return {
|
|
14656
|
+
issues: issueCache.stats(),
|
|
14657
|
+
assignedIssues: assignedIssuesCache.stats(),
|
|
14658
|
+
teams: teamsCache.stats(),
|
|
14659
|
+
projects: projectsCache.stats()
|
|
14660
|
+
};
|
|
14661
|
+
}
|
|
14662
|
+
var LINEAR_CACHE_TTL, issueCache, assignedIssuesCache, teamsCache, projectsCache;
|
|
14663
|
+
var init_cache2 = __esm({
|
|
14664
|
+
"core/integrations/linear/cache.ts"() {
|
|
14665
|
+
"use strict";
|
|
14666
|
+
init_cache();
|
|
14667
|
+
LINEAR_CACHE_TTL = 5 * 60 * 1e3;
|
|
14668
|
+
issueCache = new TTLCache({
|
|
14669
|
+
ttl: LINEAR_CACHE_TTL,
|
|
14670
|
+
maxSize: 100
|
|
14671
|
+
});
|
|
14672
|
+
assignedIssuesCache = new TTLCache({
|
|
14673
|
+
ttl: LINEAR_CACHE_TTL,
|
|
14674
|
+
maxSize: 10
|
|
14675
|
+
});
|
|
14676
|
+
teamsCache = new TTLCache({
|
|
14677
|
+
ttl: LINEAR_CACHE_TTL,
|
|
14678
|
+
maxSize: 5
|
|
14679
|
+
});
|
|
14680
|
+
projectsCache = new TTLCache({
|
|
14681
|
+
ttl: LINEAR_CACHE_TTL,
|
|
14682
|
+
maxSize: 5
|
|
14683
|
+
});
|
|
14684
|
+
__name(clearLinearCache, "clearLinearCache");
|
|
14685
|
+
__name(getLinearCacheStats, "getLinearCacheStats");
|
|
14686
|
+
}
|
|
14687
|
+
});
|
|
14688
|
+
|
|
14689
|
+
// core/integrations/linear/service.ts
|
|
14690
|
+
var LinearService, linearService;
|
|
14691
|
+
var init_service = __esm({
|
|
14692
|
+
"core/integrations/linear/service.ts"() {
|
|
14693
|
+
"use strict";
|
|
14694
|
+
init_client();
|
|
14695
|
+
init_cache2();
|
|
14696
|
+
LinearService = class {
|
|
14697
|
+
static {
|
|
14698
|
+
__name(this, "LinearService");
|
|
14699
|
+
}
|
|
14700
|
+
initialized = false;
|
|
14701
|
+
userId = null;
|
|
14702
|
+
/**
|
|
14703
|
+
* Check if service is ready
|
|
14704
|
+
*/
|
|
14705
|
+
isReady() {
|
|
14706
|
+
return this.initialized && linearProvider.isConfigured();
|
|
14707
|
+
}
|
|
14708
|
+
/**
|
|
14709
|
+
* Initialize the service with config
|
|
14710
|
+
* Must be called before any operations
|
|
14711
|
+
*/
|
|
14712
|
+
async initialize(config) {
|
|
14713
|
+
if (this.initialized) return;
|
|
14714
|
+
await linearProvider.initialize(config);
|
|
14715
|
+
this.initialized = true;
|
|
14716
|
+
}
|
|
14717
|
+
/**
|
|
14718
|
+
* Initialize from API key directly
|
|
14719
|
+
* Convenience method for simple setup
|
|
14720
|
+
*/
|
|
14721
|
+
async initializeFromApiKey(apiKey, teamId) {
|
|
14722
|
+
const config = {
|
|
14723
|
+
enabled: true,
|
|
14724
|
+
provider: "linear",
|
|
14725
|
+
apiKey,
|
|
14726
|
+
defaultTeamId: teamId,
|
|
14727
|
+
syncOn: { task: true, done: true, ship: true },
|
|
14728
|
+
enrichment: { enabled: true, updateProvider: true }
|
|
14729
|
+
};
|
|
14730
|
+
await this.initialize(config);
|
|
14731
|
+
}
|
|
14732
|
+
/**
|
|
14733
|
+
* Get issues assigned to current user (cached)
|
|
14734
|
+
*/
|
|
14735
|
+
async fetchAssignedIssues(options) {
|
|
14736
|
+
this.ensureInitialized();
|
|
14737
|
+
const cacheKey = `assigned:${this.userId || "me"}`;
|
|
14738
|
+
const cached = assignedIssuesCache.get(cacheKey);
|
|
14739
|
+
if (cached) {
|
|
14740
|
+
return cached;
|
|
14741
|
+
}
|
|
14742
|
+
const issues = await linearProvider.fetchAssignedIssues(options);
|
|
14743
|
+
assignedIssuesCache.set(cacheKey, issues);
|
|
14744
|
+
for (const issue of issues) {
|
|
14745
|
+
issueCache.set(`issue:${issue.id}`, issue);
|
|
14746
|
+
issueCache.set(`issue:${issue.externalId}`, issue);
|
|
14747
|
+
}
|
|
14748
|
+
return issues;
|
|
14749
|
+
}
|
|
14750
|
+
/**
|
|
14751
|
+
* Get issues from a team (cached)
|
|
14752
|
+
*/
|
|
14753
|
+
async fetchTeamIssues(teamId, options) {
|
|
14754
|
+
this.ensureInitialized();
|
|
14755
|
+
const cacheKey = `team:${teamId}`;
|
|
14756
|
+
const cached = assignedIssuesCache.get(cacheKey);
|
|
14757
|
+
if (cached) {
|
|
14758
|
+
return cached;
|
|
14759
|
+
}
|
|
14760
|
+
const issues = await linearProvider.fetchTeamIssues(teamId, options);
|
|
14761
|
+
assignedIssuesCache.set(cacheKey, issues);
|
|
14762
|
+
for (const issue of issues) {
|
|
14763
|
+
issueCache.set(`issue:${issue.id}`, issue);
|
|
14764
|
+
issueCache.set(`issue:${issue.externalId}`, issue);
|
|
14765
|
+
}
|
|
14766
|
+
return issues;
|
|
14767
|
+
}
|
|
14768
|
+
/**
|
|
14769
|
+
* Get a single issue by ID or identifier (cached)
|
|
14770
|
+
* Accepts UUID or identifier like "PRJ-123"
|
|
14771
|
+
*/
|
|
14772
|
+
async fetchIssue(id) {
|
|
14773
|
+
this.ensureInitialized();
|
|
14774
|
+
const cacheKey = `issue:${id}`;
|
|
14775
|
+
const cached = issueCache.get(cacheKey);
|
|
14776
|
+
if (cached) {
|
|
14777
|
+
return cached;
|
|
14778
|
+
}
|
|
14779
|
+
const issue = await linearProvider.fetchIssue(id);
|
|
14780
|
+
if (issue) {
|
|
14781
|
+
issueCache.set(`issue:${issue.id}`, issue);
|
|
14782
|
+
issueCache.set(`issue:${issue.externalId}`, issue);
|
|
14783
|
+
}
|
|
14784
|
+
return issue;
|
|
14785
|
+
}
|
|
14786
|
+
/**
|
|
14787
|
+
* Create a new issue (invalidates assigned cache)
|
|
14788
|
+
*/
|
|
14789
|
+
async createIssue(input) {
|
|
14790
|
+
this.ensureInitialized();
|
|
14791
|
+
const issue = await linearProvider.createIssue(input);
|
|
14792
|
+
issueCache.set(`issue:${issue.id}`, issue);
|
|
14793
|
+
issueCache.set(`issue:${issue.externalId}`, issue);
|
|
14794
|
+
assignedIssuesCache.clear();
|
|
14795
|
+
return issue;
|
|
14796
|
+
}
|
|
14797
|
+
/**
|
|
14798
|
+
* Update an issue (invalidates cache for that issue)
|
|
14799
|
+
*/
|
|
14800
|
+
async updateIssue(id, input) {
|
|
14801
|
+
this.ensureInitialized();
|
|
14802
|
+
const issue = await linearProvider.updateIssue(id, input);
|
|
14803
|
+
issueCache.set(`issue:${issue.id}`, issue);
|
|
14804
|
+
issueCache.set(`issue:${issue.externalId}`, issue);
|
|
14805
|
+
return issue;
|
|
14806
|
+
}
|
|
14807
|
+
/**
|
|
14808
|
+
* Mark issue as in progress (invalidates cache)
|
|
14809
|
+
*/
|
|
14810
|
+
async markInProgress(id) {
|
|
14811
|
+
this.ensureInitialized();
|
|
14812
|
+
await linearProvider.markInProgress(id);
|
|
14813
|
+
issueCache.delete(`issue:${id}`);
|
|
14814
|
+
assignedIssuesCache.clear();
|
|
14815
|
+
}
|
|
14816
|
+
/**
|
|
14817
|
+
* Mark issue as done (invalidates cache)
|
|
14818
|
+
*/
|
|
14819
|
+
async markDone(id) {
|
|
14820
|
+
this.ensureInitialized();
|
|
14821
|
+
await linearProvider.markDone(id);
|
|
14822
|
+
issueCache.delete(`issue:${id}`);
|
|
14823
|
+
assignedIssuesCache.clear();
|
|
14824
|
+
}
|
|
14825
|
+
/**
|
|
14826
|
+
* Add a comment to an issue
|
|
14827
|
+
*/
|
|
14828
|
+
async addComment(id, body) {
|
|
14829
|
+
this.ensureInitialized();
|
|
14830
|
+
await linearProvider.addComment(id, body);
|
|
14831
|
+
}
|
|
14832
|
+
/**
|
|
14833
|
+
* Get available teams (cached)
|
|
14834
|
+
*/
|
|
14835
|
+
async getTeams() {
|
|
14836
|
+
this.ensureInitialized();
|
|
14837
|
+
const cached = teamsCache.get("teams");
|
|
14838
|
+
if (cached) {
|
|
14839
|
+
return cached;
|
|
14840
|
+
}
|
|
14841
|
+
const teams = await linearProvider.getTeams();
|
|
14842
|
+
teamsCache.set("teams", teams);
|
|
14843
|
+
return teams;
|
|
14844
|
+
}
|
|
14845
|
+
/**
|
|
14846
|
+
* Get available projects (cached)
|
|
14847
|
+
*/
|
|
14848
|
+
async getProjects() {
|
|
14849
|
+
this.ensureInitialized();
|
|
14850
|
+
const cached = projectsCache.get("projects");
|
|
14851
|
+
if (cached) {
|
|
14852
|
+
return cached;
|
|
14853
|
+
}
|
|
14854
|
+
const projects = await linearProvider.getProjects();
|
|
14855
|
+
projectsCache.set("projects", projects);
|
|
14856
|
+
return projects;
|
|
14857
|
+
}
|
|
14858
|
+
/**
|
|
14859
|
+
* Clear all caches
|
|
14860
|
+
*/
|
|
14861
|
+
clearCache() {
|
|
14862
|
+
clearLinearCache();
|
|
14863
|
+
}
|
|
14864
|
+
/**
|
|
14865
|
+
* Get cache statistics for debugging
|
|
14866
|
+
*/
|
|
14867
|
+
getCacheStats() {
|
|
14868
|
+
return getLinearCacheStats();
|
|
14869
|
+
}
|
|
14870
|
+
/**
|
|
14871
|
+
* Ensure service is initialized
|
|
14872
|
+
*/
|
|
14873
|
+
ensureInitialized() {
|
|
14874
|
+
if (!this.initialized) {
|
|
14875
|
+
throw new Error(
|
|
14876
|
+
"Linear service not initialized. Call linearService.initialize() first or run `p. linear setup`."
|
|
14877
|
+
);
|
|
14878
|
+
}
|
|
14879
|
+
}
|
|
14880
|
+
};
|
|
14881
|
+
linearService = new LinearService();
|
|
14882
|
+
}
|
|
14883
|
+
});
|
|
14884
|
+
|
|
14885
|
+
// core/integrations/linear/sync.ts
|
|
14886
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
14887
|
+
import { existsSync } from "fs";
|
|
14888
|
+
import { join as join2 } from "path";
|
|
14889
|
+
var DEFAULT_STALE_AFTER, LinearSync, linearSync;
|
|
14890
|
+
var init_sync = __esm({
|
|
14891
|
+
"core/integrations/linear/sync.ts"() {
|
|
14892
|
+
"use strict";
|
|
14893
|
+
init_service();
|
|
14894
|
+
init_schemas();
|
|
14895
|
+
init_issues();
|
|
14896
|
+
DEFAULT_STALE_AFTER = 30 * 60 * 1e3;
|
|
14897
|
+
LinearSync = class {
|
|
14898
|
+
static {
|
|
14899
|
+
__name(this, "LinearSync");
|
|
14900
|
+
}
|
|
14901
|
+
/**
|
|
14902
|
+
* Pull all assigned issues from Linear and store in issues.json
|
|
14903
|
+
* This is the main sync operation - call on `p. sync`
|
|
14904
|
+
*/
|
|
14905
|
+
async pullAll(projectId) {
|
|
14906
|
+
const storagePath = join2(getProjectPath2(projectId), "storage");
|
|
14907
|
+
const issuesPath = join2(storagePath, "issues.json");
|
|
14908
|
+
if (!existsSync(storagePath)) {
|
|
14909
|
+
await mkdir(storagePath, { recursive: true });
|
|
14910
|
+
}
|
|
14911
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
14912
|
+
const errors = [];
|
|
14913
|
+
try {
|
|
14914
|
+
const issues = await linearService.fetchAssignedIssues({ limit: 100 });
|
|
14915
|
+
const issuesMap = {};
|
|
14916
|
+
for (const issue of issues) {
|
|
14917
|
+
try {
|
|
14918
|
+
issuesMap[issue.externalId] = this.toCachedIssue(issue, timestamp);
|
|
14919
|
+
} catch (err) {
|
|
14920
|
+
errors.push({
|
|
14921
|
+
issueId: issue.externalId || issue.id,
|
|
14922
|
+
error: err.message
|
|
14923
|
+
});
|
|
14924
|
+
}
|
|
14925
|
+
}
|
|
14926
|
+
const issuesJson = {
|
|
14927
|
+
provider: "linear",
|
|
14928
|
+
lastSync: timestamp,
|
|
14929
|
+
staleAfter: DEFAULT_STALE_AFTER,
|
|
14930
|
+
issues: issuesMap
|
|
14931
|
+
};
|
|
14932
|
+
await writeFile2(issuesPath, JSON.stringify(issuesJson, null, 2));
|
|
14933
|
+
return {
|
|
14934
|
+
provider: "linear",
|
|
14935
|
+
fetched: issues.length,
|
|
14936
|
+
updated: Object.keys(issuesMap).length,
|
|
14937
|
+
errors,
|
|
14938
|
+
timestamp
|
|
14939
|
+
};
|
|
14940
|
+
} catch (err) {
|
|
14941
|
+
errors.push({
|
|
14942
|
+
issueId: "all",
|
|
14943
|
+
error: err.message
|
|
14944
|
+
});
|
|
14945
|
+
return {
|
|
14946
|
+
provider: "linear",
|
|
14947
|
+
fetched: 0,
|
|
14948
|
+
updated: 0,
|
|
14949
|
+
errors,
|
|
14950
|
+
timestamp
|
|
14951
|
+
};
|
|
14952
|
+
}
|
|
14953
|
+
}
|
|
14954
|
+
/**
|
|
14955
|
+
* Get issue from local cache, fetch from API if not found or stale
|
|
14956
|
+
* Local-first approach for performance
|
|
14957
|
+
*/
|
|
14958
|
+
async getIssue(projectId, identifier) {
|
|
14959
|
+
const issuesJson = await this.loadIssues(projectId);
|
|
14960
|
+
if (issuesJson && issuesJson.issues[identifier]) {
|
|
14961
|
+
const cachedIssue = issuesJson.issues[identifier];
|
|
14962
|
+
const fetchedAt = new Date(cachedIssue.fetchedAt).getTime();
|
|
14963
|
+
const now = Date.now();
|
|
14964
|
+
const issueStaleness = 10 * 60 * 1e3;
|
|
14965
|
+
if (now - fetchedAt < issueStaleness) {
|
|
14966
|
+
return cachedIssue;
|
|
14967
|
+
}
|
|
14968
|
+
}
|
|
14969
|
+
try {
|
|
14970
|
+
const issue = await linearService.fetchIssue(identifier);
|
|
14971
|
+
if (!issue) return null;
|
|
14972
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
14973
|
+
const cachedIssue = this.toCachedIssue(issue, timestamp);
|
|
14974
|
+
await this.updateIssueInCache(projectId, identifier, cachedIssue);
|
|
14975
|
+
return cachedIssue;
|
|
14976
|
+
} catch {
|
|
14977
|
+
if (issuesJson?.issues[identifier]) {
|
|
14978
|
+
return issuesJson.issues[identifier];
|
|
14979
|
+
}
|
|
14980
|
+
return null;
|
|
14981
|
+
}
|
|
14982
|
+
}
|
|
14983
|
+
/**
|
|
14984
|
+
* Get issue from local cache ONLY (no API call)
|
|
14985
|
+
* Use for fast lookups when you know the issue should be cached
|
|
14986
|
+
*/
|
|
14987
|
+
async getIssueLocal(projectId, identifier) {
|
|
14988
|
+
const issuesJson = await this.loadIssues(projectId);
|
|
14989
|
+
return issuesJson?.issues[identifier] || null;
|
|
14990
|
+
}
|
|
14991
|
+
/**
|
|
14992
|
+
* Push local status change to Linear
|
|
14993
|
+
* Called when task status changes (in_progress, done)
|
|
14994
|
+
*/
|
|
14995
|
+
async pushStatus(projectId, identifier, status) {
|
|
14996
|
+
if (status === "in_progress") {
|
|
14997
|
+
await linearService.markInProgress(identifier);
|
|
14998
|
+
} else if (status === "done") {
|
|
14999
|
+
await linearService.markDone(identifier);
|
|
15000
|
+
}
|
|
15001
|
+
const issuesJson = await this.loadIssues(projectId);
|
|
15002
|
+
if (issuesJson?.issues[identifier]) {
|
|
15003
|
+
const cachedStatus = status === "done" ? "done" : "in_progress";
|
|
15004
|
+
issuesJson.issues[identifier].status = cachedStatus;
|
|
15005
|
+
issuesJson.issues[identifier].fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15006
|
+
await this.saveIssues(projectId, issuesJson);
|
|
15007
|
+
}
|
|
15008
|
+
}
|
|
15009
|
+
/**
|
|
15010
|
+
* Check if the local issues cache is stale
|
|
15011
|
+
* Staleness = lastSync is older than staleAfter threshold
|
|
15012
|
+
*/
|
|
15013
|
+
async isStale(projectId) {
|
|
15014
|
+
const issuesJson = await this.loadIssues(projectId);
|
|
15015
|
+
if (!issuesJson || !issuesJson.lastSync) {
|
|
15016
|
+
return true;
|
|
15017
|
+
}
|
|
15018
|
+
const lastSyncTime = new Date(issuesJson.lastSync).getTime();
|
|
15019
|
+
const now = Date.now();
|
|
15020
|
+
const staleAfter = issuesJson.staleAfter || DEFAULT_STALE_AFTER;
|
|
15021
|
+
return now - lastSyncTime > staleAfter;
|
|
15022
|
+
}
|
|
15023
|
+
/**
|
|
15024
|
+
* Get sync status for display
|
|
15025
|
+
*/
|
|
15026
|
+
async getSyncStatus(projectId) {
|
|
15027
|
+
const issuesJson = await this.loadIssues(projectId);
|
|
15028
|
+
if (!issuesJson) {
|
|
15029
|
+
return {
|
|
15030
|
+
hasCache: false,
|
|
15031
|
+
lastSync: null,
|
|
15032
|
+
issueCount: 0,
|
|
15033
|
+
isStale: true
|
|
15034
|
+
};
|
|
15035
|
+
}
|
|
15036
|
+
return {
|
|
15037
|
+
hasCache: true,
|
|
15038
|
+
lastSync: issuesJson.lastSync || null,
|
|
15039
|
+
issueCount: Object.keys(issuesJson.issues).length,
|
|
15040
|
+
isStale: await this.isStale(projectId)
|
|
15041
|
+
};
|
|
15042
|
+
}
|
|
15043
|
+
/**
|
|
15044
|
+
* List all cached issues
|
|
15045
|
+
*/
|
|
15046
|
+
async listCachedIssues(projectId) {
|
|
15047
|
+
const issuesJson = await this.loadIssues(projectId);
|
|
15048
|
+
if (!issuesJson) return [];
|
|
15049
|
+
return Object.values(issuesJson.issues);
|
|
15050
|
+
}
|
|
15051
|
+
// =============================================================================
|
|
15052
|
+
// Private Helpers
|
|
15053
|
+
// =============================================================================
|
|
15054
|
+
/**
|
|
15055
|
+
* Load issues.json from disk
|
|
15056
|
+
*/
|
|
15057
|
+
async loadIssues(projectId) {
|
|
15058
|
+
const issuesPath = join2(getProjectPath2(projectId), "storage", "issues.json");
|
|
15059
|
+
if (!existsSync(issuesPath)) {
|
|
15060
|
+
return null;
|
|
15061
|
+
}
|
|
15062
|
+
try {
|
|
15063
|
+
const content = await readFile2(issuesPath, "utf-8");
|
|
15064
|
+
return parseIssues(JSON.parse(content));
|
|
15065
|
+
} catch {
|
|
15066
|
+
return null;
|
|
15067
|
+
}
|
|
15068
|
+
}
|
|
15069
|
+
/**
|
|
15070
|
+
* Save issues.json to disk
|
|
15071
|
+
*/
|
|
15072
|
+
async saveIssues(projectId, issuesJson) {
|
|
15073
|
+
const storagePath = join2(getProjectPath2(projectId), "storage");
|
|
15074
|
+
const issuesPath = join2(storagePath, "issues.json");
|
|
15075
|
+
if (!existsSync(storagePath)) {
|
|
15076
|
+
await mkdir(storagePath, { recursive: true });
|
|
15077
|
+
}
|
|
15078
|
+
await writeFile2(issuesPath, JSON.stringify(issuesJson, null, 2));
|
|
15079
|
+
}
|
|
15080
|
+
/**
|
|
15081
|
+
* Update a single issue in the cache
|
|
15082
|
+
*/
|
|
15083
|
+
async updateIssueInCache(projectId, identifier, issue) {
|
|
15084
|
+
let issuesJson = await this.loadIssues(projectId);
|
|
15085
|
+
if (!issuesJson) {
|
|
15086
|
+
issuesJson = createEmptyIssues("linear");
|
|
15087
|
+
}
|
|
15088
|
+
issuesJson.issues[identifier] = issue;
|
|
15089
|
+
await this.saveIssues(projectId, issuesJson);
|
|
15090
|
+
}
|
|
15091
|
+
/**
|
|
15092
|
+
* Convert API Issue to CachedIssue format
|
|
15093
|
+
*/
|
|
15094
|
+
toCachedIssue(issue, timestamp) {
|
|
15095
|
+
return {
|
|
15096
|
+
id: issue.id,
|
|
15097
|
+
identifier: issue.externalId,
|
|
15098
|
+
title: issue.title,
|
|
15099
|
+
description: issue.description,
|
|
15100
|
+
status: issue.status,
|
|
15101
|
+
priority: issue.priority,
|
|
15102
|
+
type: issue.type,
|
|
15103
|
+
assignee: issue.assignee,
|
|
15104
|
+
labels: issue.labels,
|
|
15105
|
+
team: issue.team,
|
|
15106
|
+
project: issue.project,
|
|
15107
|
+
url: issue.url,
|
|
15108
|
+
createdAt: issue.createdAt,
|
|
15109
|
+
updatedAt: issue.updatedAt,
|
|
15110
|
+
fetchedAt: timestamp
|
|
15111
|
+
};
|
|
15112
|
+
}
|
|
15113
|
+
};
|
|
15114
|
+
linearSync = new LinearSync();
|
|
15115
|
+
}
|
|
15116
|
+
});
|
|
15117
|
+
|
|
15118
|
+
// core/integrations/linear/index.ts
|
|
15119
|
+
var init_linear = __esm({
|
|
15120
|
+
"core/integrations/linear/index.ts"() {
|
|
15121
|
+
"use strict";
|
|
15122
|
+
init_client();
|
|
15123
|
+
init_service();
|
|
15124
|
+
init_sync();
|
|
15125
|
+
init_cache2();
|
|
15126
|
+
}
|
|
15127
|
+
});
|
|
15128
|
+
|
|
15129
|
+
// core/utils/project-credentials.ts
|
|
15130
|
+
import fs32 from "fs";
|
|
15131
|
+
import path33 from "path";
|
|
15132
|
+
import os13 from "os";
|
|
15133
|
+
function getCredentialsPath(projectId) {
|
|
15134
|
+
return path33.join(
|
|
15135
|
+
os13.homedir(),
|
|
15136
|
+
".prjct-cli",
|
|
15137
|
+
"projects",
|
|
15138
|
+
projectId,
|
|
15139
|
+
"config",
|
|
15140
|
+
"credentials.json"
|
|
15141
|
+
);
|
|
15142
|
+
}
|
|
15143
|
+
async function getProjectCredentials(projectId) {
|
|
15144
|
+
const credPath = getCredentialsPath(projectId);
|
|
15145
|
+
if (!fs32.existsSync(credPath)) {
|
|
15146
|
+
return {};
|
|
15147
|
+
}
|
|
15148
|
+
try {
|
|
15149
|
+
return JSON.parse(fs32.readFileSync(credPath, "utf-8"));
|
|
15150
|
+
} catch (error) {
|
|
15151
|
+
console.error("[project-credentials] Failed to read credentials:", error.message);
|
|
15152
|
+
return {};
|
|
15153
|
+
}
|
|
15154
|
+
}
|
|
15155
|
+
async function getLinearApiKey(projectId) {
|
|
15156
|
+
const projectCreds = await getProjectCredentials(projectId);
|
|
15157
|
+
if (projectCreds.linear?.apiKey) {
|
|
15158
|
+
return projectCreds.linear.apiKey;
|
|
15159
|
+
}
|
|
15160
|
+
return getCredential("linear-api-key");
|
|
15161
|
+
}
|
|
15162
|
+
var init_project_credentials = __esm({
|
|
15163
|
+
"core/utils/project-credentials.ts"() {
|
|
15164
|
+
"use strict";
|
|
15165
|
+
init_keychain();
|
|
15166
|
+
__name(getCredentialsPath, "getCredentialsPath");
|
|
15167
|
+
__name(getProjectCredentials, "getProjectCredentials");
|
|
15168
|
+
__name(getLinearApiKey, "getLinearApiKey");
|
|
15169
|
+
}
|
|
15170
|
+
});
|
|
15171
|
+
|
|
13381
15172
|
// core/commands/workflow.ts
|
|
13382
15173
|
var WorkflowCommands;
|
|
13383
15174
|
var init_workflow = __esm({
|
|
@@ -13388,6 +15179,9 @@ var init_workflow = __esm({
|
|
|
13388
15179
|
init_storage2();
|
|
13389
15180
|
init_template_executor();
|
|
13390
15181
|
init_command_executor();
|
|
15182
|
+
init_next_steps();
|
|
15183
|
+
init_linear();
|
|
15184
|
+
init_project_credentials();
|
|
13391
15185
|
WorkflowCommands = class extends PrjctCommandsBase {
|
|
13392
15186
|
static {
|
|
13393
15187
|
__name(this, "WorkflowCommands");
|
|
@@ -13410,23 +15204,39 @@ var init_workflow = __esm({
|
|
|
13410
15204
|
output_default.fail(result.error || "Failed to execute task");
|
|
13411
15205
|
return { success: false, error: result.error };
|
|
13412
15206
|
}
|
|
15207
|
+
let linearId;
|
|
15208
|
+
let taskDescription = task;
|
|
15209
|
+
const linearPattern = /^[A-Z]+-\d+$/;
|
|
15210
|
+
if (linearPattern.test(task)) {
|
|
15211
|
+
try {
|
|
15212
|
+
const creds = await getProjectCredentials(projectId);
|
|
15213
|
+
const apiKey = await getLinearApiKey(projectId);
|
|
15214
|
+
if (apiKey && creds.linear?.teamId) {
|
|
15215
|
+
await linearService.initializeFromApiKey(
|
|
15216
|
+
apiKey,
|
|
15217
|
+
creds.linear.teamId
|
|
15218
|
+
);
|
|
15219
|
+
const issue = await linearService.fetchIssue(task);
|
|
15220
|
+
if (issue) {
|
|
15221
|
+
linearId = task;
|
|
15222
|
+
taskDescription = `${task}: ${issue.title}`;
|
|
15223
|
+
await linearService.markInProgress(task);
|
|
15224
|
+
}
|
|
15225
|
+
}
|
|
15226
|
+
} catch {
|
|
15227
|
+
}
|
|
15228
|
+
}
|
|
13413
15229
|
await stateStorage.startTask(projectId, {
|
|
13414
15230
|
id: generateUUID(),
|
|
13415
|
-
description:
|
|
13416
|
-
sessionId: generateUUID()
|
|
15231
|
+
description: taskDescription,
|
|
15232
|
+
sessionId: generateUUID(),
|
|
15233
|
+
linearId
|
|
13417
15234
|
});
|
|
13418
|
-
if (result.orchestratorContext) {
|
|
13419
|
-
const oc = result.orchestratorContext;
|
|
13420
|
-
const agentsList2 = oc.agents.map((a) => a.name).join(", ") || "none";
|
|
13421
|
-
const domainsList = oc.detectedDomains.join(", ");
|
|
13422
|
-
console.log(`\u{1F3AF} Orchestrator: ${domainsList} \u2192 [${agentsList2}]`);
|
|
13423
|
-
if (oc.requiresFragmentation && oc.subtasks) {
|
|
13424
|
-
console.log(` \u2192 ${oc.subtasks.length} subtasks created`);
|
|
13425
|
-
}
|
|
13426
|
-
}
|
|
13427
15235
|
const availableAgents = await templateExecutor.getAvailableAgents(projectPath);
|
|
13428
15236
|
const agentsList = availableAgents.length > 0 ? availableAgents.join(", ") : "none (run p. sync)";
|
|
13429
|
-
output_default.done(`${task}
|
|
15237
|
+
output_default.done(`${task}`);
|
|
15238
|
+
showStateInfo("working");
|
|
15239
|
+
showNextSteps("task");
|
|
13430
15240
|
await this.logToMemory(projectPath, "task_started", {
|
|
13431
15241
|
task,
|
|
13432
15242
|
agenticMode: true,
|
|
@@ -13481,7 +15291,29 @@ var init_workflow = __esm({
|
|
|
13481
15291
|
duration = date_helper_default.calculateDuration(started);
|
|
13482
15292
|
}
|
|
13483
15293
|
await stateStorage.completeTask(projectId);
|
|
13484
|
-
|
|
15294
|
+
const linearId = currentTask.linearId;
|
|
15295
|
+
if (linearId) {
|
|
15296
|
+
try {
|
|
15297
|
+
const creds = await getProjectCredentials(projectId);
|
|
15298
|
+
const apiKey = await getLinearApiKey(projectId);
|
|
15299
|
+
if (apiKey && creds.linear?.teamId) {
|
|
15300
|
+
await linearService.initializeFromApiKey(
|
|
15301
|
+
apiKey,
|
|
15302
|
+
creds.linear.teamId
|
|
15303
|
+
);
|
|
15304
|
+
await linearService.markDone(linearId);
|
|
15305
|
+
output_default.done(`${task}${duration ? ` (${duration})` : ""} \u2192 Linear \u2713`);
|
|
15306
|
+
} else {
|
|
15307
|
+
output_default.done(`${task}${duration ? ` (${duration})` : ""}`);
|
|
15308
|
+
}
|
|
15309
|
+
} catch {
|
|
15310
|
+
output_default.done(`${task}${duration ? ` (${duration})` : ""}`);
|
|
15311
|
+
}
|
|
15312
|
+
} else {
|
|
15313
|
+
output_default.done(`${task}${duration ? ` (${duration})` : ""}`);
|
|
15314
|
+
}
|
|
15315
|
+
showStateInfo("completed");
|
|
15316
|
+
showNextSteps("done");
|
|
13485
15317
|
await this.logToMemory(projectPath, "task_completed", {
|
|
13486
15318
|
task,
|
|
13487
15319
|
duration,
|
|
@@ -13511,6 +15343,7 @@ var init_workflow = __esm({
|
|
|
13511
15343
|
return { success: true, message: "Queue is empty" };
|
|
13512
15344
|
}
|
|
13513
15345
|
output_default.done(`${tasks.length} task${tasks.length !== 1 ? "s" : ""} queued`);
|
|
15346
|
+
showNextSteps("next");
|
|
13514
15347
|
return { success: true, tasks, count: tasks.length };
|
|
13515
15348
|
} catch (error) {
|
|
13516
15349
|
output_default.fail(error.message);
|
|
@@ -13537,6 +15370,8 @@ var init_workflow = __esm({
|
|
|
13537
15370
|
await stateStorage.pauseTask(projectId, reason2);
|
|
13538
15371
|
const taskDesc = currentTask.description.slice(0, 40);
|
|
13539
15372
|
output_default.done(`paused: ${taskDesc}${reason2 ? ` (${reason2})` : ""}`);
|
|
15373
|
+
showStateInfo("paused");
|
|
15374
|
+
showNextSteps("pause");
|
|
13540
15375
|
await this.logToMemory(projectPath, "task_paused", {
|
|
13541
15376
|
task: currentTask.description,
|
|
13542
15377
|
reason: reason2,
|
|
@@ -13571,6 +15406,8 @@ var init_workflow = __esm({
|
|
|
13571
15406
|
return { success: false, message: "No paused task found" };
|
|
13572
15407
|
}
|
|
13573
15408
|
output_default.done(`resumed: ${resumed.description.slice(0, 40)}`);
|
|
15409
|
+
showStateInfo("working");
|
|
15410
|
+
showNextSteps("resume");
|
|
13574
15411
|
await this.logToMemory(projectPath, "task_resumed", {
|
|
13575
15412
|
task: resumed.description,
|
|
13576
15413
|
timestamp: date_helper_default.getTimestamp()
|
|
@@ -13586,18 +15423,18 @@ var init_workflow = __esm({
|
|
|
13586
15423
|
});
|
|
13587
15424
|
|
|
13588
15425
|
// core/utils/project-commands.ts
|
|
13589
|
-
import
|
|
15426
|
+
import path34 from "path";
|
|
13590
15427
|
async function detectPackageManager(projectPath, pkg) {
|
|
13591
15428
|
const declared = pkg?.packageManager?.trim().toLowerCase();
|
|
13592
15429
|
if (declared?.startsWith("pnpm@")) return "pnpm";
|
|
13593
15430
|
if (declared?.startsWith("yarn@")) return "yarn";
|
|
13594
15431
|
if (declared?.startsWith("bun@")) return "bun";
|
|
13595
15432
|
if (declared?.startsWith("npm@")) return "npm";
|
|
13596
|
-
if (await fileExists(
|
|
13597
|
-
if (await fileExists(
|
|
13598
|
-
if (await fileExists(
|
|
13599
|
-
if (await fileExists(
|
|
13600
|
-
if (await fileExists(
|
|
15433
|
+
if (await fileExists(path34.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
|
|
15434
|
+
if (await fileExists(path34.join(projectPath, "yarn.lock"))) return "yarn";
|
|
15435
|
+
if (await fileExists(path34.join(projectPath, "bun.lockb"))) return "bun";
|
|
15436
|
+
if (await fileExists(path34.join(projectPath, "bun.lock"))) return "bun";
|
|
15437
|
+
if (await fileExists(path34.join(projectPath, "package-lock.json"))) return "npm";
|
|
13601
15438
|
return "npm";
|
|
13602
15439
|
}
|
|
13603
15440
|
function pmRun(pm, scriptName) {
|
|
@@ -13613,7 +15450,7 @@ function pmTest(pm) {
|
|
|
13613
15450
|
return "npm test";
|
|
13614
15451
|
}
|
|
13615
15452
|
async function detectProjectCommands(projectPath) {
|
|
13616
|
-
const pkgPath =
|
|
15453
|
+
const pkgPath = path34.join(projectPath, "package.json");
|
|
13617
15454
|
const pkg = await readJson(pkgPath, null);
|
|
13618
15455
|
if (pkg) {
|
|
13619
15456
|
const pm = await detectPackageManager(projectPath, pkg);
|
|
@@ -13630,27 +15467,27 @@ async function detectProjectCommands(projectPath) {
|
|
|
13630
15467
|
}
|
|
13631
15468
|
return result;
|
|
13632
15469
|
}
|
|
13633
|
-
if (await fileExists(
|
|
15470
|
+
if (await fileExists(path34.join(projectPath, "pytest.ini"))) {
|
|
13634
15471
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
13635
15472
|
}
|
|
13636
|
-
const pyproject = await readFile(
|
|
15473
|
+
const pyproject = await readFile(path34.join(projectPath, "pyproject.toml"), "");
|
|
13637
15474
|
if (pyproject.includes("[tool.pytest") || pyproject.includes("pytest")) {
|
|
13638
15475
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
13639
15476
|
}
|
|
13640
|
-
if (await fileExists(
|
|
15477
|
+
if (await fileExists(path34.join(projectPath, "Cargo.toml"))) {
|
|
13641
15478
|
return { stack: "rust", test: { tool: "cargo", command: "cargo test" } };
|
|
13642
15479
|
}
|
|
13643
|
-
if (await fileExists(
|
|
15480
|
+
if (await fileExists(path34.join(projectPath, "go.mod"))) {
|
|
13644
15481
|
return { stack: "go", test: { tool: "go", command: "go test ./..." } };
|
|
13645
15482
|
}
|
|
13646
15483
|
const files = await listFiles(projectPath);
|
|
13647
15484
|
if (files.some((f) => f.endsWith(".sln") || f.endsWith(".csproj") || f.endsWith(".fsproj"))) {
|
|
13648
15485
|
return { stack: "dotnet", test: { tool: "dotnet", command: "dotnet test" } };
|
|
13649
15486
|
}
|
|
13650
|
-
if (await fileExists(
|
|
15487
|
+
if (await fileExists(path34.join(projectPath, "pom.xml"))) {
|
|
13651
15488
|
return { stack: "java", test: { tool: "maven", command: "mvn test" } };
|
|
13652
15489
|
}
|
|
13653
|
-
if (await fileExists(
|
|
15490
|
+
if (await fileExists(path34.join(projectPath, "gradlew")) && (await fileExists(path34.join(projectPath, "build.gradle")) || await fileExists(path34.join(projectPath, "build.gradle.kts")))) {
|
|
13654
15491
|
return { stack: "java", test: { tool: "gradle", command: "./gradlew test" } };
|
|
13655
15492
|
}
|
|
13656
15493
|
return { stack: "unknown" };
|
|
@@ -13667,7 +15504,7 @@ var init_project_commands = __esm({
|
|
|
13667
15504
|
});
|
|
13668
15505
|
|
|
13669
15506
|
// core/commands/shipping.ts
|
|
13670
|
-
import
|
|
15507
|
+
import path35 from "path";
|
|
13671
15508
|
var ShippingCommands;
|
|
13672
15509
|
var init_shipping = __esm({
|
|
13673
15510
|
"core/commands/shipping.ts"() {
|
|
@@ -13677,6 +15514,7 @@ var init_shipping = __esm({
|
|
|
13677
15514
|
init_project_commands();
|
|
13678
15515
|
init_base();
|
|
13679
15516
|
init_storage2();
|
|
15517
|
+
init_next_steps();
|
|
13680
15518
|
ShippingCommands = class extends PrjctCommandsBase {
|
|
13681
15519
|
static {
|
|
13682
15520
|
__name(this, "ShippingCommands");
|
|
@@ -13719,17 +15557,17 @@ ${result.stderr}`.trim();
|
|
|
13719
15557
|
const currentTask = await stateStorage.getCurrentTask(projectId);
|
|
13720
15558
|
featureName = currentTask?.description || "current work";
|
|
13721
15559
|
}
|
|
13722
|
-
output_default.
|
|
15560
|
+
output_default.step(1, 5, `Linting ${featureName}...`);
|
|
13723
15561
|
const lintResult = await this._runLint(projectPath);
|
|
13724
|
-
output_default.
|
|
15562
|
+
output_default.step(2, 5, "Running tests...");
|
|
13725
15563
|
const testResult = await this._runTests(projectPath);
|
|
13726
|
-
output_default.
|
|
15564
|
+
output_default.step(3, 5, "Updating version...");
|
|
13727
15565
|
const newVersion = await this._bumpVersion(projectPath);
|
|
13728
15566
|
await this._updateChangelog(featureName, newVersion, projectPath);
|
|
13729
|
-
output_default.
|
|
15567
|
+
output_default.step(4, 5, "Committing...");
|
|
13730
15568
|
const commitResult = await this._createShipCommit(featureName, projectPath);
|
|
13731
15569
|
if (commitResult.success) {
|
|
13732
|
-
output_default.
|
|
15570
|
+
output_default.step(5, 5, "Pushing...");
|
|
13733
15571
|
await this._gitPush(projectPath);
|
|
13734
15572
|
}
|
|
13735
15573
|
await shippedStorage.addShipped(projectId, {
|
|
@@ -13753,6 +15591,7 @@ ${result.stderr}`.trim();
|
|
|
13753
15591
|
});
|
|
13754
15592
|
}
|
|
13755
15593
|
output_default.done(`v${newVersion} shipped`);
|
|
15594
|
+
showNextSteps("ship");
|
|
13756
15595
|
return { success: true, feature: featureName, version: newVersion };
|
|
13757
15596
|
} catch (error) {
|
|
13758
15597
|
output_default.fail(error.message);
|
|
@@ -13796,7 +15635,7 @@ ${result.stderr}`.trim();
|
|
|
13796
15635
|
*/
|
|
13797
15636
|
async _bumpVersion(projectPath) {
|
|
13798
15637
|
try {
|
|
13799
|
-
const pkgPath =
|
|
15638
|
+
const pkgPath = path35.join(projectPath, "package.json");
|
|
13800
15639
|
const pkg = await file_helper_exports.readJson(pkgPath, { version: "0.0.0" });
|
|
13801
15640
|
const oldVersion = pkg?.version || "0.0.0";
|
|
13802
15641
|
const [major, minor, patch] = oldVersion.split(".").map(Number);
|
|
@@ -13818,7 +15657,7 @@ ${result.stderr}`.trim();
|
|
|
13818
15657
|
*/
|
|
13819
15658
|
async _updateChangelog(feature, version, projectPath) {
|
|
13820
15659
|
try {
|
|
13821
|
-
const changelogPath =
|
|
15660
|
+
const changelogPath = path35.join(projectPath, "CHANGELOG.md");
|
|
13822
15661
|
const changelog = await file_helper_exports.readFile(changelogPath, "# Changelog\n\n");
|
|
13823
15662
|
const entry = `## [${version}] - ${date_helper_default.formatDate(/* @__PURE__ */ new Date())}
|
|
13824
15663
|
|
|
@@ -13877,7 +15716,7 @@ Designed for [Claude](https://www.anthropic.com/claude)`;
|
|
|
13877
15716
|
|
|
13878
15717
|
// core/commands/registry.ts
|
|
13879
15718
|
var CommandRegistry, commandRegistry;
|
|
13880
|
-
var
|
|
15719
|
+
var init_registry2 = __esm({
|
|
13881
15720
|
"core/commands/registry.ts"() {
|
|
13882
15721
|
"use strict";
|
|
13883
15722
|
init_config_manager();
|
|
@@ -14214,12 +16053,12 @@ var init_registry = __esm({
|
|
|
14214
16053
|
});
|
|
14215
16054
|
|
|
14216
16055
|
// core/commands/analytics.ts
|
|
14217
|
-
import
|
|
16056
|
+
import path36 from "path";
|
|
14218
16057
|
var AnalyticsCommands;
|
|
14219
16058
|
var init_analytics = __esm({
|
|
14220
16059
|
"core/commands/analytics.ts"() {
|
|
14221
16060
|
"use strict";
|
|
14222
|
-
|
|
16061
|
+
init_registry2();
|
|
14223
16062
|
init_base();
|
|
14224
16063
|
init_storage2();
|
|
14225
16064
|
AnalyticsCommands = class extends PrjctCommandsBase {
|
|
@@ -14239,7 +16078,7 @@ var init_analytics = __esm({
|
|
|
14239
16078
|
output_default.fail("no project ID");
|
|
14240
16079
|
return { success: false, error: "No project ID found" };
|
|
14241
16080
|
}
|
|
14242
|
-
const projectName =
|
|
16081
|
+
const projectName = path36.basename(projectPath);
|
|
14243
16082
|
const currentTask = await stateStorage.getCurrentTask(projectId);
|
|
14244
16083
|
const queueTasks = await queueStorage.getActiveTasks(projectId);
|
|
14245
16084
|
const shipped = await shippedStorage.getRecent(projectId, 5);
|
|
@@ -14477,7 +16316,7 @@ ${catInfo?.title || cat}:`);
|
|
|
14477
16316
|
});
|
|
14478
16317
|
|
|
14479
16318
|
// core/commands/cleanup.ts
|
|
14480
|
-
import
|
|
16319
|
+
import path37 from "path";
|
|
14481
16320
|
async function cleanupMemory(projectPath) {
|
|
14482
16321
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
14483
16322
|
const results = { rotated: [], totalSize: 0, freedSpace: 0 };
|
|
@@ -14493,7 +16332,7 @@ async function cleanupMemory(projectPath) {
|
|
|
14493
16332
|
results.totalSize += sizeMB;
|
|
14494
16333
|
const rotated = await jsonl_helper_default.rotateJsonLinesIfNeeded(filePath, 10);
|
|
14495
16334
|
if (rotated) {
|
|
14496
|
-
results.rotated.push(
|
|
16335
|
+
results.rotated.push(path37.basename(filePath));
|
|
14497
16336
|
results.freedSpace += sizeMB;
|
|
14498
16337
|
}
|
|
14499
16338
|
}
|
|
@@ -14600,7 +16439,7 @@ var init_cleanup = __esm({
|
|
|
14600
16439
|
});
|
|
14601
16440
|
|
|
14602
16441
|
// core/commands/design.ts
|
|
14603
|
-
import
|
|
16442
|
+
import path38 from "path";
|
|
14604
16443
|
async function design(target = null, options = {}, projectPath = process.cwd()) {
|
|
14605
16444
|
try {
|
|
14606
16445
|
const designType = options.type || "architecture";
|
|
@@ -14612,7 +16451,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
14612
16451
|
const designTarget = target || "system";
|
|
14613
16452
|
output_default.spin(`designing ${designType}...`);
|
|
14614
16453
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
14615
|
-
const designsPath =
|
|
16454
|
+
const designsPath = path38.join(
|
|
14616
16455
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
14617
16456
|
"planning",
|
|
14618
16457
|
"designs"
|
|
@@ -14652,7 +16491,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
14652
16491
|
break;
|
|
14653
16492
|
}
|
|
14654
16493
|
const designFileName = `${designType}-${designTarget.toLowerCase().replace(/\s+/g, "-")}.md`;
|
|
14655
|
-
const designFilePath =
|
|
16494
|
+
const designFilePath = path38.join(designsPath, designFileName);
|
|
14656
16495
|
await file_helper_exports.writeFile(designFilePath, designContent);
|
|
14657
16496
|
await memoryService.log(projectPath, "design_created", {
|
|
14658
16497
|
type: designType,
|
|
@@ -14676,7 +16515,7 @@ var init_design = __esm({
|
|
|
14676
16515
|
});
|
|
14677
16516
|
|
|
14678
16517
|
// core/commands/snapshots.ts
|
|
14679
|
-
import
|
|
16518
|
+
import path39 from "path";
|
|
14680
16519
|
async function recover(projectPath = process.cwd()) {
|
|
14681
16520
|
try {
|
|
14682
16521
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
@@ -14728,14 +16567,14 @@ async function undo(projectPath = process.cwd()) {
|
|
|
14728
16567
|
output_default.fail("no project ID");
|
|
14729
16568
|
return { success: false, error: "No project ID found" };
|
|
14730
16569
|
}
|
|
14731
|
-
const snapshotsPath =
|
|
16570
|
+
const snapshotsPath = path39.join(
|
|
14732
16571
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
14733
16572
|
"snapshots"
|
|
14734
16573
|
);
|
|
14735
16574
|
await file_helper_exports.ensureDir(snapshotsPath);
|
|
14736
|
-
const { execSync:
|
|
16575
|
+
const { execSync: execSync5 } = await import("child_process");
|
|
14737
16576
|
try {
|
|
14738
|
-
const status =
|
|
16577
|
+
const status = execSync5("git status --porcelain", {
|
|
14739
16578
|
cwd: projectPath,
|
|
14740
16579
|
encoding: "utf-8"
|
|
14741
16580
|
}).trim();
|
|
@@ -14745,11 +16584,11 @@ async function undo(projectPath = process.cwd()) {
|
|
|
14745
16584
|
}
|
|
14746
16585
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
14747
16586
|
const stashMessage = `prjct-undo-${timestamp}`;
|
|
14748
|
-
|
|
16587
|
+
execSync5(`git stash push -m "${stashMessage}"`, {
|
|
14749
16588
|
cwd: projectPath,
|
|
14750
16589
|
encoding: "utf-8"
|
|
14751
16590
|
});
|
|
14752
|
-
const snapshotFile =
|
|
16591
|
+
const snapshotFile = path39.join(snapshotsPath, "history.json");
|
|
14753
16592
|
let history2 = { snapshots: [], current: -1 };
|
|
14754
16593
|
try {
|
|
14755
16594
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -14789,11 +16628,11 @@ async function redo(projectPath = process.cwd()) {
|
|
|
14789
16628
|
output_default.fail("no project ID");
|
|
14790
16629
|
return { success: false, error: "No project ID found" };
|
|
14791
16630
|
}
|
|
14792
|
-
const snapshotsPath =
|
|
16631
|
+
const snapshotsPath = path39.join(
|
|
14793
16632
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
14794
16633
|
"snapshots"
|
|
14795
16634
|
);
|
|
14796
|
-
const snapshotFile =
|
|
16635
|
+
const snapshotFile = path39.join(snapshotsPath, "history.json");
|
|
14797
16636
|
let history2;
|
|
14798
16637
|
try {
|
|
14799
16638
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -14809,9 +16648,9 @@ async function redo(projectPath = process.cwd()) {
|
|
|
14809
16648
|
output_default.warn("nothing to redo");
|
|
14810
16649
|
return { success: false, message: "Nothing to redo" };
|
|
14811
16650
|
}
|
|
14812
|
-
const { execSync:
|
|
16651
|
+
const { execSync: execSync5 } = await import("child_process");
|
|
14813
16652
|
try {
|
|
14814
|
-
const stashList =
|
|
16653
|
+
const stashList = execSync5("git stash list", {
|
|
14815
16654
|
cwd: projectPath,
|
|
14816
16655
|
encoding: "utf-8"
|
|
14817
16656
|
}).trim();
|
|
@@ -14824,7 +16663,7 @@ async function redo(projectPath = process.cwd()) {
|
|
|
14824
16663
|
output_default.warn("no prjct undo point found");
|
|
14825
16664
|
return { success: false, message: "No prjct undo point found" };
|
|
14826
16665
|
}
|
|
14827
|
-
|
|
16666
|
+
execSync5("git stash pop", {
|
|
14828
16667
|
cwd: projectPath,
|
|
14829
16668
|
encoding: "utf-8"
|
|
14830
16669
|
});
|
|
@@ -14852,11 +16691,11 @@ async function history(projectPath = process.cwd()) {
|
|
|
14852
16691
|
output_default.fail("no project ID");
|
|
14853
16692
|
return { success: false, error: "No project ID found" };
|
|
14854
16693
|
}
|
|
14855
|
-
const snapshotsPath =
|
|
16694
|
+
const snapshotsPath = path39.join(
|
|
14856
16695
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
14857
16696
|
"snapshots"
|
|
14858
16697
|
);
|
|
14859
|
-
const snapshotFile =
|
|
16698
|
+
const snapshotFile = path39.join(snapshotsPath, "history.json");
|
|
14860
16699
|
let snapshotHistory;
|
|
14861
16700
|
try {
|
|
14862
16701
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -14962,9 +16801,9 @@ var init_maintenance = __esm({
|
|
|
14962
16801
|
});
|
|
14963
16802
|
|
|
14964
16803
|
// core/commands/setup.ts
|
|
14965
|
-
import
|
|
14966
|
-
import
|
|
14967
|
-
import
|
|
16804
|
+
import path40 from "path";
|
|
16805
|
+
import fs33 from "fs";
|
|
16806
|
+
import chalk6 from "chalk";
|
|
14968
16807
|
var SetupCommands;
|
|
14969
16808
|
var init_setup2 = __esm({
|
|
14970
16809
|
"core/commands/setup.ts"() {
|
|
@@ -15084,7 +16923,7 @@ Please install it first:
|
|
|
15084
16923
|
try {
|
|
15085
16924
|
const claudeDir = path_manager_default.getClaudeDir();
|
|
15086
16925
|
const settingsPath = path_manager_default.getClaudeSettingsPath();
|
|
15087
|
-
const statusLinePath =
|
|
16926
|
+
const statusLinePath = path40.join(claudeDir, "prjct-statusline.sh");
|
|
15088
16927
|
const scriptContent = `#!/bin/bash
|
|
15089
16928
|
# prjct Status Line for Claude Code
|
|
15090
16929
|
# Shows version update notifications and current task
|
|
@@ -15142,11 +16981,11 @@ fi
|
|
|
15142
16981
|
# Default: show prjct branding
|
|
15143
16982
|
echo "\u26A1 prjct"
|
|
15144
16983
|
`;
|
|
15145
|
-
|
|
16984
|
+
fs33.writeFileSync(statusLinePath, scriptContent, { mode: 493 });
|
|
15146
16985
|
let settings = {};
|
|
15147
|
-
if (
|
|
16986
|
+
if (fs33.existsSync(settingsPath)) {
|
|
15148
16987
|
try {
|
|
15149
|
-
settings = JSON.parse(
|
|
16988
|
+
settings = JSON.parse(fs33.readFileSync(settingsPath, "utf8"));
|
|
15150
16989
|
} catch (_error) {
|
|
15151
16990
|
}
|
|
15152
16991
|
}
|
|
@@ -15154,7 +16993,7 @@ echo "\u26A1 prjct"
|
|
|
15154
16993
|
type: "command",
|
|
15155
16994
|
command: statusLinePath
|
|
15156
16995
|
};
|
|
15157
|
-
|
|
16996
|
+
fs33.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
15158
16997
|
return { success: true };
|
|
15159
16998
|
} catch (error) {
|
|
15160
16999
|
return { success: false, error: error.message };
|
|
@@ -15164,41 +17003,41 @@ echo "\u26A1 prjct"
|
|
|
15164
17003
|
* Show beautiful ASCII art with quick start
|
|
15165
17004
|
*/
|
|
15166
17005
|
showAsciiArt() {
|
|
15167
|
-
console.log(
|
|
17006
|
+
console.log(chalk6.cyan("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
15168
17007
|
console.log("");
|
|
15169
|
-
console.log(
|
|
15170
|
-
console.log(
|
|
15171
|
-
console.log(
|
|
15172
|
-
console.log(
|
|
15173
|
-
console.log(
|
|
15174
|
-
console.log(
|
|
17008
|
+
console.log(chalk6.bold.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"));
|
|
17009
|
+
console.log(chalk6.bold.cyan(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D"));
|
|
17010
|
+
console.log(chalk6.bold.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551"));
|
|
17011
|
+
console.log(chalk6.bold.cyan(" \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551"));
|
|
17012
|
+
console.log(chalk6.bold.cyan(" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551"));
|
|
17013
|
+
console.log(chalk6.bold.cyan(" \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D"));
|
|
15175
17014
|
console.log("");
|
|
15176
|
-
console.log(` ${
|
|
17015
|
+
console.log(` ${chalk6.bold.cyan("prjct")}${chalk6.magenta("/")}${chalk6.green("cli")} ${chalk6.dim.white("v" + VERSION + " installed")}`);
|
|
15177
17016
|
console.log("");
|
|
15178
|
-
console.log(` ${
|
|
15179
|
-
console.log(` ${
|
|
15180
|
-
console.log(` ${
|
|
17017
|
+
console.log(` ${chalk6.yellow("\u26A1")} Ship faster with zero friction`);
|
|
17018
|
+
console.log(` ${chalk6.green("\u{1F4DD}")} From idea to technical tasks in minutes`);
|
|
17019
|
+
console.log(` ${chalk6.cyan("\u{1F916}")} Perfect context for AI agents`);
|
|
15181
17020
|
console.log("");
|
|
15182
|
-
console.log(
|
|
17021
|
+
console.log(chalk6.cyan("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
15183
17022
|
console.log("");
|
|
15184
|
-
console.log(
|
|
15185
|
-
console.log(
|
|
17023
|
+
console.log(chalk6.bold.cyan("\u{1F680} Quick Start"));
|
|
17024
|
+
console.log(chalk6.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
15186
17025
|
console.log("");
|
|
15187
|
-
console.log(` ${
|
|
15188
|
-
console.log(` ${
|
|
17026
|
+
console.log(` ${chalk6.bold("1.")} Initialize your project:`);
|
|
17027
|
+
console.log(` ${chalk6.green("cd your-project && prjct init")}`);
|
|
15189
17028
|
console.log("");
|
|
15190
|
-
console.log(` ${
|
|
15191
|
-
console.log(` ${
|
|
17029
|
+
console.log(` ${chalk6.bold("2.")} Start your first task:`);
|
|
17030
|
+
console.log(` ${chalk6.green('prjct task "build auth"')}`);
|
|
15192
17031
|
console.log("");
|
|
15193
|
-
console.log(` ${
|
|
15194
|
-
console.log(` ${
|
|
17032
|
+
console.log(` ${chalk6.bold("3.")} Ship & celebrate:`);
|
|
17033
|
+
console.log(` ${chalk6.green('prjct ship "user login"')}`);
|
|
15195
17034
|
console.log("");
|
|
15196
|
-
console.log(
|
|
17035
|
+
console.log(chalk6.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
15197
17036
|
console.log("");
|
|
15198
|
-
console.log(` ${
|
|
15199
|
-
console.log(` ${
|
|
17037
|
+
console.log(` ${chalk6.dim("Documentation:")} ${chalk6.cyan("https://prjct.app")}`);
|
|
17038
|
+
console.log(` ${chalk6.dim("Report issues:")} ${chalk6.cyan("https://github.com/jlopezlira/prjct-cli/issues")}`);
|
|
15200
17039
|
console.log("");
|
|
15201
|
-
console.log(
|
|
17040
|
+
console.log(chalk6.bold.magenta("Happy shipping! \u{1F680}"));
|
|
15202
17041
|
console.log("");
|
|
15203
17042
|
}
|
|
15204
17043
|
};
|
|
@@ -15206,8 +17045,8 @@ echo "\u26A1 prjct"
|
|
|
15206
17045
|
});
|
|
15207
17046
|
|
|
15208
17047
|
// core/commands/context.ts
|
|
15209
|
-
import
|
|
15210
|
-
import
|
|
17048
|
+
import fs34 from "fs/promises";
|
|
17049
|
+
import path41 from "path";
|
|
15211
17050
|
var ContextCommands, contextCommands;
|
|
15212
17051
|
var init_context = __esm({
|
|
15213
17052
|
"core/commands/context.ts"() {
|
|
@@ -15333,8 +17172,8 @@ var init_context = __esm({
|
|
|
15333
17172
|
*/
|
|
15334
17173
|
async loadRepoAnalysis(globalPath) {
|
|
15335
17174
|
try {
|
|
15336
|
-
const analysisPath =
|
|
15337
|
-
const content = await
|
|
17175
|
+
const analysisPath = path41.join(globalPath, "analysis", "repo-analysis.json");
|
|
17176
|
+
const content = await fs34.readFile(analysisPath, "utf-8");
|
|
15338
17177
|
const data = JSON.parse(content);
|
|
15339
17178
|
return {
|
|
15340
17179
|
ecosystem: data.ecosystem || "unknown",
|
|
@@ -15457,8 +17296,8 @@ var init_commands = __esm({
|
|
|
15457
17296
|
async analyze(options = {}, projectPath = process.cwd()) {
|
|
15458
17297
|
return this.analysis.analyze(options, projectPath);
|
|
15459
17298
|
}
|
|
15460
|
-
async sync(projectPath = process.cwd()) {
|
|
15461
|
-
return this.analysis.sync(projectPath);
|
|
17299
|
+
async sync(projectPath = process.cwd(), options = {}) {
|
|
17300
|
+
return this.analysis.sync(projectPath, options);
|
|
15462
17301
|
}
|
|
15463
17302
|
// ========== Context Commands ==========
|
|
15464
17303
|
async context(input = null, projectPath = process.cwd()) {
|
|
@@ -15848,7 +17687,7 @@ var workflow, planning, shipping, analytics, maintenance, analysis, setup, conte
|
|
|
15848
17687
|
var init_register = __esm({
|
|
15849
17688
|
"core/commands/register.ts"() {
|
|
15850
17689
|
"use strict";
|
|
15851
|
-
|
|
17690
|
+
init_registry2();
|
|
15852
17691
|
init_command_data();
|
|
15853
17692
|
init_workflow();
|
|
15854
17693
|
init_planning();
|
|
@@ -15877,7 +17716,7 @@ var init_commands2 = __esm({
|
|
|
15877
17716
|
"core/commands/index.ts"() {
|
|
15878
17717
|
"use strict";
|
|
15879
17718
|
init_commands();
|
|
15880
|
-
|
|
17719
|
+
init_registry2();
|
|
15881
17720
|
init_register();
|
|
15882
17721
|
init_types2();
|
|
15883
17722
|
}
|
|
@@ -15888,7 +17727,7 @@ var require_package = __commonJS({
|
|
|
15888
17727
|
"package.json"(exports, module) {
|
|
15889
17728
|
module.exports = {
|
|
15890
17729
|
name: "prjct-cli",
|
|
15891
|
-
version: "0.
|
|
17730
|
+
version: "0.43.0",
|
|
15892
17731
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
15893
17732
|
main: "core/index.ts",
|
|
15894
17733
|
bin: {
|
|
@@ -15993,9 +17832,9 @@ var require_package = __commonJS({
|
|
|
15993
17832
|
|
|
15994
17833
|
// core/index.ts
|
|
15995
17834
|
var core_exports = {};
|
|
15996
|
-
import
|
|
15997
|
-
import
|
|
15998
|
-
import
|
|
17835
|
+
import fs35 from "fs";
|
|
17836
|
+
import path42 from "path";
|
|
17837
|
+
import os14 from "os";
|
|
15999
17838
|
async function main() {
|
|
16000
17839
|
const [commandName, ...rawArgs] = process.argv.slice(2);
|
|
16001
17840
|
if (["-v", "--version", "version"].includes(commandName)) {
|
|
@@ -16068,7 +17907,9 @@ Use 'prjct --help' to see available commands.`);
|
|
|
16068
17907
|
redo: /* @__PURE__ */ __name(() => commands.redo(), "redo"),
|
|
16069
17908
|
history: /* @__PURE__ */ __name(() => commands.history(), "history"),
|
|
16070
17909
|
// Setup
|
|
16071
|
-
sync: /* @__PURE__ */ __name(() => commands.sync(),
|
|
17910
|
+
sync: /* @__PURE__ */ __name(() => commands.sync(process.cwd(), {
|
|
17911
|
+
aiTools: options.agents ? String(options.agents).split(",") : void 0
|
|
17912
|
+
}), "sync"),
|
|
16072
17913
|
start: /* @__PURE__ */ __name(() => commands.start(), "start"),
|
|
16073
17914
|
// Context (for Claude templates)
|
|
16074
17915
|
context: /* @__PURE__ */ __name((p) => commands.context(p), "context")
|
|
@@ -16114,12 +17955,12 @@ function parseCommandArgs(cmd, rawArgs) {
|
|
|
16114
17955
|
}
|
|
16115
17956
|
function displayVersion(version) {
|
|
16116
17957
|
const detection = detectAllProviders();
|
|
16117
|
-
const claudeCommandPath =
|
|
16118
|
-
const geminiCommandPath =
|
|
16119
|
-
const claudeConfigured =
|
|
16120
|
-
const geminiConfigured =
|
|
16121
|
-
const cursorConfigured =
|
|
16122
|
-
const cursorExists =
|
|
17958
|
+
const claudeCommandPath = path42.join(os14.homedir(), ".claude", "commands", "p.md");
|
|
17959
|
+
const geminiCommandPath = path42.join(os14.homedir(), ".gemini", "commands", "p.toml");
|
|
17960
|
+
const claudeConfigured = fs35.existsSync(claudeCommandPath);
|
|
17961
|
+
const geminiConfigured = fs35.existsSync(geminiCommandPath);
|
|
17962
|
+
const cursorConfigured = fs35.existsSync(path42.join(process.cwd(), ".cursor", "commands", "sync.md"));
|
|
17963
|
+
const cursorExists = fs35.existsSync(path42.join(process.cwd(), ".cursor"));
|
|
16123
17964
|
console.log(`
|
|
16124
17965
|
${CYAN2}p/${RESET2} prjct v${version}
|
|
16125
17966
|
${DIM3}Context layer for AI coding agents${RESET2}
|
|
@@ -16217,7 +18058,7 @@ var init_core = __esm({
|
|
|
16217
18058
|
"core/index.ts"() {
|
|
16218
18059
|
"use strict";
|
|
16219
18060
|
init_commands2();
|
|
16220
|
-
|
|
18061
|
+
init_registry2();
|
|
16221
18062
|
init_register();
|
|
16222
18063
|
init_output();
|
|
16223
18064
|
init_ai_provider();
|
|
@@ -16243,9 +18084,9 @@ var init_core = __esm({
|
|
|
16243
18084
|
// bin/prjct.ts
|
|
16244
18085
|
init_version();
|
|
16245
18086
|
init_editors_config();
|
|
16246
|
-
import
|
|
16247
|
-
import
|
|
16248
|
-
import
|
|
18087
|
+
import fs36 from "fs";
|
|
18088
|
+
import path43 from "path";
|
|
18089
|
+
import os15 from "os";
|
|
16249
18090
|
|
|
16250
18091
|
// core/server/server.ts
|
|
16251
18092
|
import { Hono as Hono3 } from "hono";
|
|
@@ -16985,17 +18826,17 @@ __name(startServer, "startServer");
|
|
|
16985
18826
|
init_config_manager();
|
|
16986
18827
|
init_ai_provider();
|
|
16987
18828
|
function checkRoutersInstalled() {
|
|
16988
|
-
const home =
|
|
18829
|
+
const home = os15.homedir();
|
|
16989
18830
|
const detection = detectAllProviders();
|
|
16990
18831
|
if (detection.claude.installed) {
|
|
16991
|
-
const claudeRouter =
|
|
16992
|
-
if (!
|
|
18832
|
+
const claudeRouter = path43.join(home, ".claude", "commands", "p.md");
|
|
18833
|
+
if (!fs36.existsSync(claudeRouter)) {
|
|
16993
18834
|
return false;
|
|
16994
18835
|
}
|
|
16995
18836
|
}
|
|
16996
18837
|
if (detection.gemini.installed) {
|
|
16997
|
-
const geminiRouter =
|
|
16998
|
-
if (!
|
|
18838
|
+
const geminiRouter = path43.join(home, ".gemini", "commands", "p.toml");
|
|
18839
|
+
if (!fs36.existsSync(geminiRouter)) {
|
|
16999
18840
|
return false;
|
|
17000
18841
|
}
|
|
17001
18842
|
}
|
|
@@ -17041,7 +18882,7 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
17041
18882
|
console.error('No prjct project found. Run "prjct init" first.');
|
|
17042
18883
|
process.exitCode = 1;
|
|
17043
18884
|
} else {
|
|
17044
|
-
const linearCliPath =
|
|
18885
|
+
const linearCliPath = path43.join(__dirname, "..", "core", "cli", "linear.ts");
|
|
17045
18886
|
const linearArgs = ["--project", projectId, ...args.slice(1)];
|
|
17046
18887
|
const child = spawn("bun", [linearCliPath, ...linearArgs], {
|
|
17047
18888
|
stdio: "inherit",
|
|
@@ -17053,14 +18894,14 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
17053
18894
|
}
|
|
17054
18895
|
} else if (args[0] === "version" || args[0] === "-v" || args[0] === "--version") {
|
|
17055
18896
|
const detection = detectAllProviders();
|
|
17056
|
-
const home =
|
|
18897
|
+
const home = os15.homedir();
|
|
17057
18898
|
const cwd = process.cwd();
|
|
17058
|
-
const claudeConfigured =
|
|
17059
|
-
const geminiConfigured =
|
|
17060
|
-
const cursorDetected =
|
|
17061
|
-
const cursorConfigured =
|
|
17062
|
-
const windsurfDetected =
|
|
17063
|
-
const windsurfConfigured =
|
|
18899
|
+
const claudeConfigured = fs36.existsSync(path43.join(home, ".claude", "commands", "p.md"));
|
|
18900
|
+
const geminiConfigured = fs36.existsSync(path43.join(home, ".gemini", "commands", "p.toml"));
|
|
18901
|
+
const cursorDetected = fs36.existsSync(path43.join(cwd, ".cursor"));
|
|
18902
|
+
const cursorConfigured = fs36.existsSync(path43.join(cwd, ".cursor", "rules", "prjct.mdc"));
|
|
18903
|
+
const windsurfDetected = fs36.existsSync(path43.join(cwd, ".windsurf"));
|
|
18904
|
+
const windsurfConfigured = fs36.existsSync(path43.join(cwd, ".windsurf", "rules", "prjct.md"));
|
|
17064
18905
|
const GREEN4 = "\x1B[32m";
|
|
17065
18906
|
console.log(`
|
|
17066
18907
|
${CYAN3}p/${RESET3} prjct v${VERSION}
|
|
@@ -17099,9 +18940,9 @@ ${DIM4}Run 'prjct init' to configure (Cursor/Windsurf IDE)${RESET3}
|
|
|
17099
18940
|
${CYAN3}https://prjct.app${RESET3}
|
|
17100
18941
|
`);
|
|
17101
18942
|
} else {
|
|
17102
|
-
const configPath =
|
|
18943
|
+
const configPath = path43.join(os15.homedir(), ".prjct-cli", "config", "installed-editors.json");
|
|
17103
18944
|
const routersInstalled = checkRoutersInstalled();
|
|
17104
|
-
if (!
|
|
18945
|
+
if (!fs36.existsSync(configPath) || !routersInstalled) {
|
|
17105
18946
|
console.log(`
|
|
17106
18947
|
${CYAN3}${BOLD2} Welcome to prjct!${RESET3}
|
|
17107
18948
|
|