prjct-cli 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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) => (path72) => {
20
- var fn = map[path72];
19
+ var __glob = (map) => (path73) => {
20
+ var fn = map[path73];
21
21
  if (fn) return fn();
22
- throw new Error("Module not found in bundle: " + path72);
22
+ throw new Error("Module not found in bundle: " + path73);
23
23
  };
24
24
  var __esm = (fn, res) => function __init() {
25
25
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -4277,6 +4277,30 @@ var init_database = __esm({
4277
4277
  );
4278
4278
  `);
4279
4279
  }, "up")
4280
+ },
4281
+ {
4282
+ version: 2,
4283
+ name: "archives-table",
4284
+ up: /* @__PURE__ */ __name((db) => {
4285
+ db.run(`
4286
+ -- =======================================================================
4287
+ -- Archives: Stale data moved out of active storage (PRJ-267)
4288
+ -- =======================================================================
4289
+ CREATE TABLE archives (
4290
+ id TEXT PRIMARY KEY,
4291
+ entity_type TEXT NOT NULL,
4292
+ entity_id TEXT NOT NULL,
4293
+ entity_data TEXT NOT NULL,
4294
+ summary TEXT,
4295
+ archived_at TEXT NOT NULL,
4296
+ reason TEXT NOT NULL
4297
+ );
4298
+
4299
+ CREATE INDEX idx_archives_entity_type ON archives(entity_type);
4300
+ CREATE INDEX idx_archives_archived_at ON archives(archived_at);
4301
+ CREATE INDEX idx_archives_entity_id ON archives(entity_id);
4302
+ `);
4303
+ }, "up")
4280
4304
  }
4281
4305
  ];
4282
4306
  PrjctDatabase = class {
@@ -6576,11 +6600,11 @@ async function runSignaturesTool(args2, projectPath) {
6576
6600
  }
6577
6601
  };
6578
6602
  }
6579
- const fs60 = await import("node:fs/promises");
6580
- const path72 = await import("node:path");
6581
- const fullPath = path72.isAbsolute(filePath) ? filePath : path72.join(projectPath, filePath);
6603
+ const fs61 = await import("node:fs/promises");
6604
+ const path73 = await import("node:path");
6605
+ const fullPath = path73.isAbsolute(filePath) ? filePath : path73.join(projectPath, filePath);
6582
6606
  try {
6583
- const stat = await fs60.stat(fullPath);
6607
+ const stat = await fs61.stat(fullPath);
6584
6608
  if (stat.isDirectory()) {
6585
6609
  const results = await extractDirectorySignatures(filePath, projectPath, {
6586
6610
  recursive: args2.includes("--recursive") || args2.includes("-r")
@@ -6647,11 +6671,11 @@ async function runSummaryTool(args2, projectPath) {
6647
6671
  }
6648
6672
  };
6649
6673
  }
6650
- const fs60 = await import("node:fs/promises");
6651
- const path72 = await import("node:path");
6652
- const fullPath = path72.isAbsolute(targetPath) ? targetPath : path72.join(projectPath, targetPath);
6674
+ const fs61 = await import("node:fs/promises");
6675
+ const path73 = await import("node:path");
6676
+ const fullPath = path73.isAbsolute(targetPath) ? targetPath : path73.join(projectPath, targetPath);
6653
6677
  try {
6654
- const stat = await fs60.stat(fullPath);
6678
+ const stat = await fs61.stat(fullPath);
6655
6679
  if (stat.isDirectory()) {
6656
6680
  const results = await summarizeDirectory(targetPath, projectPath, {
6657
6681
  recursive: args2.includes("--recursive") || args2.includes("-r")
@@ -9716,7 +9740,7 @@ var init_ideas = __esm({
9716
9740
  "core/schemas/ideas.ts"() {
9717
9741
  "use strict";
9718
9742
  IdeaPrioritySchema = z6.enum(["low", "medium", "high"]);
9719
- IdeaStatusSchema = z6.enum(["pending", "converted", "completed", "archived"]);
9743
+ IdeaStatusSchema = z6.enum(["pending", "converted", "completed", "archived", "dormant"]);
9720
9744
  ImpactLevelSchema = z6.enum(["high", "medium", "low"]);
9721
9745
  ImpactEffortSchema = z6.object({
9722
9746
  impact: ImpactLevelSchema,
@@ -12726,6 +12750,147 @@ var init_analysis_storage = __esm({
12726
12750
  }
12727
12751
  });
12728
12752
 
12753
+ // core/storage/archive-storage.ts
12754
+ var ARCHIVE_POLICIES, ArchiveStorage, archiveStorage;
12755
+ var init_archive_storage = __esm({
12756
+ "core/storage/archive-storage.ts"() {
12757
+ "use strict";
12758
+ init_schemas2();
12759
+ init_date_helper();
12760
+ init_database();
12761
+ ARCHIVE_POLICIES = {
12762
+ SHIPPED_RETENTION_DAYS: 90,
12763
+ IDEA_DORMANT_DAYS: 180,
12764
+ QUEUE_COMPLETED_DAYS: 7,
12765
+ PAUSED_TASK_DAYS: 30,
12766
+ MEMORY_MAX_ENTRIES: 500
12767
+ };
12768
+ ArchiveStorage = class {
12769
+ static {
12770
+ __name(this, "ArchiveStorage");
12771
+ }
12772
+ /**
12773
+ * Archive a single item
12774
+ */
12775
+ archive(projectId, item) {
12776
+ const id = generateUUID();
12777
+ const now = getTimestamp();
12778
+ prjctDb.run(
12779
+ projectId,
12780
+ "INSERT INTO archives (id, entity_type, entity_id, entity_data, summary, archived_at, reason) VALUES (?, ?, ?, ?, ?, ?, ?)",
12781
+ id,
12782
+ item.entityType,
12783
+ item.entityId,
12784
+ JSON.stringify(item.entityData),
12785
+ item.summary ?? null,
12786
+ now,
12787
+ item.reason
12788
+ );
12789
+ return id;
12790
+ }
12791
+ /**
12792
+ * Archive multiple items in a transaction
12793
+ */
12794
+ archiveMany(projectId, items) {
12795
+ if (items.length === 0) return 0;
12796
+ const now = getTimestamp();
12797
+ prjctDb.transaction(projectId, (db) => {
12798
+ const stmt = db.prepare(
12799
+ "INSERT INTO archives (id, entity_type, entity_id, entity_data, summary, archived_at, reason) VALUES (?, ?, ?, ?, ?, ?, ?)"
12800
+ );
12801
+ for (const item of items) {
12802
+ stmt.run(
12803
+ generateUUID(),
12804
+ item.entityType,
12805
+ item.entityId,
12806
+ JSON.stringify(item.entityData),
12807
+ item.summary ?? null,
12808
+ now,
12809
+ item.reason
12810
+ );
12811
+ }
12812
+ });
12813
+ return items.length;
12814
+ }
12815
+ /**
12816
+ * Query archived items by type
12817
+ */
12818
+ getArchived(projectId, entityType, limit = 50) {
12819
+ if (entityType) {
12820
+ return prjctDb.query(
12821
+ projectId,
12822
+ "SELECT * FROM archives WHERE entity_type = ? ORDER BY archived_at DESC LIMIT ?",
12823
+ entityType,
12824
+ limit
12825
+ );
12826
+ }
12827
+ return prjctDb.query(
12828
+ projectId,
12829
+ "SELECT * FROM archives ORDER BY archived_at DESC LIMIT ?",
12830
+ limit
12831
+ );
12832
+ }
12833
+ /**
12834
+ * Get count of archived items by type
12835
+ */
12836
+ getStats(projectId) {
12837
+ const rows = prjctDb.query(
12838
+ projectId,
12839
+ "SELECT entity_type, COUNT(*) as count FROM archives GROUP BY entity_type"
12840
+ );
12841
+ const stats = {
12842
+ shipped: 0,
12843
+ idea: 0,
12844
+ queue_task: 0,
12845
+ paused_task: 0,
12846
+ memory_entry: 0,
12847
+ total: 0
12848
+ };
12849
+ for (const row of rows) {
12850
+ const type = row.entity_type;
12851
+ if (type in stats) {
12852
+ stats[type] = row.count;
12853
+ }
12854
+ stats.total += row.count;
12855
+ }
12856
+ return stats;
12857
+ }
12858
+ /**
12859
+ * Restore an item from archive (removes from archive table)
12860
+ * Returns the entity data for the caller to re-insert into active storage.
12861
+ */
12862
+ restore(projectId, archiveId) {
12863
+ const record = prjctDb.get(
12864
+ projectId,
12865
+ "SELECT * FROM archives WHERE id = ?",
12866
+ archiveId
12867
+ );
12868
+ if (!record) return null;
12869
+ prjctDb.run(projectId, "DELETE FROM archives WHERE id = ?", archiveId);
12870
+ return JSON.parse(record.entity_data);
12871
+ }
12872
+ /**
12873
+ * Permanently delete archives older than N days
12874
+ */
12875
+ pruneOldArchives(projectId, olderThanDays) {
12876
+ const threshold = new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1e3).toISOString();
12877
+ const before = this.getTotalCount(projectId);
12878
+ prjctDb.run(projectId, "DELETE FROM archives WHERE archived_at < ?", threshold);
12879
+ const after = this.getTotalCount(projectId);
12880
+ return before - after;
12881
+ }
12882
+ /**
12883
+ * Get total count of archived items
12884
+ */
12885
+ getTotalCount(projectId) {
12886
+ const row = prjctDb.get(projectId, "SELECT COUNT(*) as count FROM archives");
12887
+ return row?.count ?? 0;
12888
+ }
12889
+ };
12890
+ archiveStorage = new ArchiveStorage();
12891
+ }
12892
+ });
12893
+
12729
12894
  // core/storage/ideas-storage.ts
12730
12895
  var IdeasStorage, ideasStorage;
12731
12896
  var init_ideas_storage = __esm({
@@ -12734,6 +12899,7 @@ var init_ideas_storage = __esm({
12734
12899
  init_schemas2();
12735
12900
  init_ideas();
12736
12901
  init_date_helper();
12902
+ init_archive_storage();
12737
12903
  init_storage_manager();
12738
12904
  IdeasStorage = class extends StorageManager {
12739
12905
  static {
@@ -12762,6 +12928,7 @@ var init_ideas_storage = __esm({
12762
12928
  const pending = data.ideas.filter((i) => i.status === "pending");
12763
12929
  const converted = data.ideas.filter((i) => i.status === "converted");
12764
12930
  const archived = data.ideas.filter((i) => i.status === "archived");
12931
+ const dormant = data.ideas.filter((i) => i.status === "dormant");
12765
12932
  lines.push("## Brain Dump");
12766
12933
  if (pending.length > 0) {
12767
12934
  pending.forEach((idea) => {
@@ -12791,6 +12958,10 @@ var init_ideas_storage = __esm({
12791
12958
  });
12792
12959
  lines.push("");
12793
12960
  }
12961
+ if (dormant.length > 0) {
12962
+ lines.push(`_${dormant.length} dormant idea(s) excluded from context_`);
12963
+ lines.push("");
12964
+ }
12794
12965
  return lines.join("\n");
12795
12966
  }
12796
12967
  // =========== Domain Methods ===========
@@ -12926,6 +13097,40 @@ var init_ideas_storage = __esm({
12926
13097
  }));
12927
13098
  return { removed };
12928
13099
  }
13100
+ /**
13101
+ * Mark pending ideas older than retention period as dormant (PRJ-267).
13102
+ * Dormant ideas are excluded from LLM context but remain queryable.
13103
+ * Returns count of newly dormant ideas.
13104
+ */
13105
+ async markDormantIdeas(projectId) {
13106
+ const data = await this.read(projectId);
13107
+ const threshold = getDaysAgo(ARCHIVE_POLICIES.IDEA_DORMANT_DAYS);
13108
+ const stalePending = data.ideas.filter(
13109
+ (i) => i.status === "pending" && new Date(i.addedAt) < threshold
13110
+ );
13111
+ if (stalePending.length === 0) return 0;
13112
+ archiveStorage.archiveMany(
13113
+ projectId,
13114
+ stalePending.map((idea) => ({
13115
+ entityType: "idea",
13116
+ entityId: idea.id,
13117
+ entityData: idea,
13118
+ summary: idea.text,
13119
+ reason: "dormant"
13120
+ }))
13121
+ );
13122
+ const staleIds = new Set(stalePending.map((i) => i.id));
13123
+ await this.update(projectId, (d) => ({
13124
+ ideas: d.ideas.map(
13125
+ (i) => staleIds.has(i.id) ? { ...i, status: "dormant" } : i
13126
+ ),
13127
+ lastUpdated: getTimestamp()
13128
+ }));
13129
+ await this.publishEvent(projectId, "ideas.dormant", {
13130
+ count: stalePending.length
13131
+ });
13132
+ return stalePending.length;
13133
+ }
12929
13134
  };
12930
13135
  ideasStorage = new IdeasStorage();
12931
13136
  }
@@ -13764,6 +13969,7 @@ var init_queue_storage = __esm({
13764
13969
  init_schemas2();
13765
13970
  init_state();
13766
13971
  init_date_helper();
13972
+ init_archive_storage();
13767
13973
  init_storage_manager();
13768
13974
  QueueStorage = class extends StorageManager {
13769
13975
  static {
@@ -13969,6 +14175,38 @@ var init_queue_storage = __esm({
13969
14175
  }));
13970
14176
  return completedCount;
13971
14177
  }
14178
+ /**
14179
+ * Remove completed tasks older than retention period (PRJ-267).
14180
+ * Archives them to SQLite before removal.
14181
+ * Returns count of removed tasks.
14182
+ */
14183
+ async removeStaleCompleted(projectId) {
14184
+ const queue = await this.read(projectId);
14185
+ const threshold = getDaysAgo(ARCHIVE_POLICIES.QUEUE_COMPLETED_DAYS);
14186
+ const stale = queue.tasks.filter(
14187
+ (t) => t.completed && t.completedAt && new Date(t.completedAt) < threshold
14188
+ );
14189
+ if (stale.length === 0) return 0;
14190
+ archiveStorage.archiveMany(
14191
+ projectId,
14192
+ stale.map((t) => ({
14193
+ entityType: "queue_task",
14194
+ entityId: t.id,
14195
+ entityData: t,
14196
+ summary: t.description,
14197
+ reason: "age"
14198
+ }))
14199
+ );
14200
+ const staleIds = new Set(stale.map((t) => t.id));
14201
+ await this.update(projectId, (q) => ({
14202
+ tasks: q.tasks.filter((t) => !staleIds.has(t.id)),
14203
+ lastUpdated: getTimestamp()
14204
+ }));
14205
+ await this.publishEvent(projectId, "queue.stale_removed", {
14206
+ count: stale.length
14207
+ });
14208
+ return stale.length;
14209
+ }
13972
14210
  /**
13973
14211
  * Sort tasks by priority and section
13974
14212
  */
@@ -14005,6 +14243,7 @@ var init_shipped_storage = __esm({
14005
14243
  init_schemas2();
14006
14244
  init_shipped();
14007
14245
  init_date_helper();
14246
+ init_archive_storage();
14008
14247
  init_storage_manager();
14009
14248
  ShippedStorage = class extends StorageManager {
14010
14249
  static {
@@ -14154,6 +14393,39 @@ var init_shipped_storage = __esm({
14154
14393
  period
14155
14394
  };
14156
14395
  }
14396
+ /**
14397
+ * Archive shipped features older than retention period (PRJ-267).
14398
+ * Moves old items to archive table, keeps 1-line summary in active storage.
14399
+ * Returns count of archived items.
14400
+ */
14401
+ async archiveOldShipped(projectId) {
14402
+ const data = await this.read(projectId);
14403
+ const threshold = getDaysAgo(ARCHIVE_POLICIES.SHIPPED_RETENTION_DAYS);
14404
+ const stale = data.shipped.filter((s) => new Date(s.shippedAt) < threshold);
14405
+ if (stale.length === 0) return 0;
14406
+ archiveStorage.archiveMany(
14407
+ projectId,
14408
+ stale.map((s) => ({
14409
+ entityType: "shipped",
14410
+ entityId: s.id,
14411
+ entityData: s,
14412
+ summary: `${s.name} v${s.version}`,
14413
+ reason: "age"
14414
+ }))
14415
+ );
14416
+ const freshIds = new Set(
14417
+ data.shipped.filter((s) => new Date(s.shippedAt) >= threshold).map((s) => s.id)
14418
+ );
14419
+ await this.update(projectId, (d) => ({
14420
+ shipped: d.shipped.filter((s) => freshIds.has(s.id)),
14421
+ lastUpdated: getTimestamp()
14422
+ }));
14423
+ await this.publishEvent(projectId, "shipped.archived", {
14424
+ count: stale.length,
14425
+ oldestShippedAt: stale[stale.length - 1]?.shippedAt
14426
+ });
14427
+ return stale.length;
14428
+ }
14157
14429
  };
14158
14430
  shippedStorage = new ShippedStorage();
14159
14431
  }
@@ -14557,6 +14829,7 @@ var init_state_storage = __esm({
14557
14829
  init_date_helper();
14558
14830
  init_markdown_builder();
14559
14831
  init_state_machine();
14832
+ init_archive_storage();
14560
14833
  init_storage_manager();
14561
14834
  StateStorage = class extends StorageManager {
14562
14835
  static {
@@ -14809,8 +15082,9 @@ var init_state_storage = __esm({
14809
15082
  return pausedTasks.filter((t) => new Date(t.pausedAt).getTime() < threshold);
14810
15083
  }
14811
15084
  /**
14812
- * Archive stale paused tasks (remove from pausedTasks)
14813
- * Returns archived tasks
15085
+ * Archive stale paused tasks (PRJ-267).
15086
+ * Persists to archive table before removing from active storage.
15087
+ * Returns archived tasks.
14814
15088
  */
14815
15089
  async archiveStalePausedTasks(projectId) {
14816
15090
  const state = await this.read(projectId);
@@ -14819,6 +15093,16 @@ var init_state_storage = __esm({
14819
15093
  const stale = pausedTasks.filter((t) => new Date(t.pausedAt).getTime() < threshold);
14820
15094
  const fresh = pausedTasks.filter((t) => new Date(t.pausedAt).getTime() >= threshold);
14821
15095
  if (stale.length === 0) return [];
15096
+ archiveStorage.archiveMany(
15097
+ projectId,
15098
+ stale.map((task) => ({
15099
+ entityType: "paused_task",
15100
+ entityId: task.id,
15101
+ entityData: task,
15102
+ summary: task.description,
15103
+ reason: "staleness"
15104
+ }))
15105
+ );
14822
15106
  await this.update(projectId, (s) => ({
14823
15107
  ...s,
14824
15108
  pausedTasks: fresh,
@@ -15434,6 +15718,7 @@ var init_storage2 = __esm({
15434
15718
  "core/storage/index.ts"() {
15435
15719
  "use strict";
15436
15720
  init_analysis_storage();
15721
+ init_archive_storage();
15437
15722
  init_database();
15438
15723
  init_ideas_storage();
15439
15724
  init_index_storage();
@@ -20764,6 +21049,7 @@ var init_memory_service = __esm({
20764
21049
  "use strict";
20765
21050
  init_config_manager();
20766
21051
  init_path_manager();
21052
+ init_archive_storage();
20767
21053
  init_fs();
20768
21054
  init_date_helper();
20769
21055
  init_jsonl_helper();
@@ -20859,6 +21145,39 @@ var init_memory_service = __esm({
20859
21145
  return [];
20860
21146
  }
20861
21147
  }
21148
+ /**
21149
+ * Cap memory log at max entries (PRJ-267).
21150
+ * Moves overflow entries to archive table, keeps most recent entries.
21151
+ * Returns count of archived entries.
21152
+ */
21153
+ async capEntries(projectId) {
21154
+ try {
21155
+ const memoryPath = path_manager_default.getFilePath(projectId, "memory", "context.jsonl");
21156
+ const entries = await readJsonLines(memoryPath);
21157
+ if (entries.length <= ARCHIVE_POLICIES.MEMORY_MAX_ENTRIES) {
21158
+ return 0;
21159
+ }
21160
+ const overflow = entries.slice(0, entries.length - ARCHIVE_POLICIES.MEMORY_MAX_ENTRIES);
21161
+ const kept = entries.slice(-ARCHIVE_POLICIES.MEMORY_MAX_ENTRIES);
21162
+ archiveStorage.archiveMany(
21163
+ projectId,
21164
+ overflow.map((entry, i) => ({
21165
+ entityType: "memory_entry",
21166
+ entityId: `memory-${entry.timestamp || i}`,
21167
+ entityData: entry,
21168
+ summary: entry.action,
21169
+ reason: "overflow"
21170
+ }))
21171
+ );
21172
+ await writeJsonLines(memoryPath, kept);
21173
+ return overflow.length;
21174
+ } catch (error) {
21175
+ if (!isNotFoundError(error)) {
21176
+ console.error(`Memory cap error: ${getErrorMessage2(error)}`);
21177
+ }
21178
+ return 0;
21179
+ }
21180
+ }
20862
21181
  };
20863
21182
  memoryService = new MemoryService();
20864
21183
  }
@@ -21768,16 +22087,16 @@ var init_onboarding = __esm({
21768
22087
  * Detect project type from file system
21769
22088
  */
21770
22089
  async detectProjectType() {
21771
- const fs60 = await import("node:fs/promises");
21772
- const path72 = await import("node:path");
22090
+ const fs61 = await import("node:fs/promises");
22091
+ const path73 = await import("node:path");
21773
22092
  try {
21774
- const files = await fs60.readdir(this.projectPath);
22093
+ const files = await fs61.readdir(this.projectPath);
21775
22094
  if (files.includes("turbo.json") || files.includes("lerna.json") || files.includes("nx.json")) {
21776
22095
  return "monorepo";
21777
22096
  }
21778
22097
  if (files.includes("package.json")) {
21779
- const pkgPath = path72.join(this.projectPath, "package.json");
21780
- const pkgContent = await fs60.readFile(pkgPath, "utf-8");
22098
+ const pkgPath = path73.join(this.projectPath, "package.json");
22099
+ const pkgContent = await fs61.readFile(pkgPath, "utf-8");
21781
22100
  const pkg = JSON.parse(pkgContent);
21782
22101
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
21783
22102
  if (pkg.bin) return "cli-tool";
@@ -21813,32 +22132,32 @@ var init_onboarding = __esm({
21813
22132
  * Detect installed AI agents from config files
21814
22133
  */
21815
22134
  async detectInstalledAgents() {
21816
- const fs60 = await import("node:fs/promises");
21817
- const path72 = await import("node:path");
22135
+ const fs61 = await import("node:fs/promises");
22136
+ const path73 = await import("node:path");
21818
22137
  const os22 = await import("node:os");
21819
22138
  const agents = [];
21820
22139
  try {
21821
- await fs60.access(path72.join(os22.homedir(), ".claude"));
22140
+ await fs61.access(path73.join(os22.homedir(), ".claude"));
21822
22141
  agents.push("claude");
21823
22142
  } catch {
21824
22143
  }
21825
22144
  try {
21826
- await fs60.access(path72.join(this.projectPath, ".cursorrules"));
22145
+ await fs61.access(path73.join(this.projectPath, ".cursorrules"));
21827
22146
  agents.push("cursor");
21828
22147
  } catch {
21829
22148
  }
21830
22149
  try {
21831
- await fs60.access(path72.join(this.projectPath, ".windsurfrules"));
22150
+ await fs61.access(path73.join(this.projectPath, ".windsurfrules"));
21832
22151
  agents.push("windsurf");
21833
22152
  } catch {
21834
22153
  }
21835
22154
  try {
21836
- await fs60.access(path72.join(this.projectPath, ".github", "copilot-instructions.md"));
22155
+ await fs61.access(path73.join(this.projectPath, ".github", "copilot-instructions.md"));
21837
22156
  agents.push("copilot");
21838
22157
  } catch {
21839
22158
  }
21840
22159
  try {
21841
- await fs60.access(path72.join(os22.homedir(), ".gemini"));
22160
+ await fs61.access(path73.join(os22.homedir(), ".gemini"));
21842
22161
  agents.push("gemini");
21843
22162
  } catch {
21844
22163
  }
@@ -21848,17 +22167,17 @@ var init_onboarding = __esm({
21848
22167
  * Detect tech stack from project files
21849
22168
  */
21850
22169
  async detectStack() {
21851
- const fs60 = await import("node:fs/promises");
21852
- const path72 = await import("node:path");
22170
+ const fs61 = await import("node:fs/promises");
22171
+ const path73 = await import("node:path");
21853
22172
  const stack = {
21854
22173
  language: "Unknown",
21855
22174
  technologies: []
21856
22175
  };
21857
22176
  try {
21858
- const files = await fs60.readdir(this.projectPath);
22177
+ const files = await fs61.readdir(this.projectPath);
21859
22178
  if (files.includes("package.json")) {
21860
- const pkgPath = path72.join(this.projectPath, "package.json");
21861
- const pkgContent = await fs60.readFile(pkgPath, "utf-8");
22179
+ const pkgPath = path73.join(this.projectPath, "package.json");
22180
+ const pkgContent = await fs61.readFile(pkgPath, "utf-8");
21862
22181
  const pkg = JSON.parse(pkgContent);
21863
22182
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
21864
22183
  stack.language = deps.typescript ? "TypeScript" : "JavaScript";
@@ -22984,7 +23303,10 @@ var init_analysis2 = __esm({
22984
23303
  if (!isNonInteractive) {
22985
23304
  output_default.spin("Analyzing changes...");
22986
23305
  }
22987
- const result2 = await syncService.sync(projectPath, { aiTools: options.aiTools });
23306
+ const result2 = await syncService.sync(projectPath, {
23307
+ aiTools: options.aiTools,
23308
+ full: options.full
23309
+ });
22988
23310
  if (!result2.success) {
22989
23311
  if (isNonInteractive) {
22990
23312
  console.log(JSON.stringify({ success: false, error: result2.error || "Sync failed" }));
@@ -23098,7 +23420,10 @@ ${formatFullDiff(diff)}`);
23098
23420
  return this.showSyncResult(result2, startTime);
23099
23421
  }
23100
23422
  output_default.spin("Syncing project...");
23101
- const result = await syncService.sync(projectPath, { aiTools: options.aiTools });
23423
+ const result = await syncService.sync(projectPath, {
23424
+ aiTools: options.aiTools,
23425
+ full: options.full
23426
+ });
23102
23427
  if (!result.success) {
23103
23428
  output_default.fail(result.error || "Sync failed");
23104
23429
  return { success: false, error: result.error };
@@ -24083,8 +24408,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
24083
24408
  const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
24084
24409
  const specsPath2 = path45.join(globalPath2, "planning", "specs");
24085
24410
  try {
24086
- const fs60 = await import("node:fs/promises");
24087
- const files = await fs60.readdir(specsPath2);
24411
+ const fs61 = await import("node:fs/promises");
24412
+ const files = await fs61.readdir(specsPath2);
24088
24413
  const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
24089
24414
  if (specs.length === 0) {
24090
24415
  output_default.warn("no specs yet");
@@ -25283,109 +25608,6 @@ var init_bm25 = __esm({
25283
25608
  }
25284
25609
  });
25285
25610
 
25286
- // core/domain/git-cochange.ts
25287
- import { exec as execCallback7 } from "node:child_process";
25288
- import { promisify as promisify15 } from "node:util";
25289
- async function parseGitLog(projectPath, maxCommits = 100) {
25290
- try {
25291
- const { stdout } = await exec14(
25292
- `git log --name-only --pretty=format:'---COMMIT---' -${maxCommits}`,
25293
- { cwd: projectPath, maxBuffer: 10 * 1024 * 1024 }
25294
- );
25295
- const commits = [];
25296
- let currentFiles = null;
25297
- for (const line of stdout.split("\n")) {
25298
- const trimmed = line.trim();
25299
- if (trimmed === "---COMMIT---") {
25300
- if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
25301
- commits.push(currentFiles);
25302
- }
25303
- currentFiles = /* @__PURE__ */ new Set();
25304
- } else if (trimmed && currentFiles) {
25305
- if (isSourceFile(trimmed)) {
25306
- currentFiles.add(trimmed);
25307
- }
25308
- }
25309
- }
25310
- if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
25311
- commits.push(currentFiles);
25312
- }
25313
- return commits;
25314
- } catch {
25315
- return [];
25316
- }
25317
- }
25318
- function isSourceFile(filePath) {
25319
- const sourceExtensions = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|cs|rb|php|vue|svelte)$/i;
25320
- return sourceExtensions.test(filePath) && !filePath.includes("node_modules/");
25321
- }
25322
- async function buildMatrix(projectPath, maxCommits = 100) {
25323
- const commitSets = await parseGitLog(projectPath, maxCommits);
25324
- const fileCommitCount = /* @__PURE__ */ new Map();
25325
- const pairCount = /* @__PURE__ */ new Map();
25326
- for (const files of commitSets) {
25327
- const fileArray = Array.from(files);
25328
- for (const file of fileArray) {
25329
- fileCommitCount.set(file, (fileCommitCount.get(file) || 0) + 1);
25330
- }
25331
- for (let i = 0; i < fileArray.length; i++) {
25332
- for (let j = i + 1; j < fileArray.length; j++) {
25333
- const key = pairKey(fileArray[i], fileArray[j]);
25334
- pairCount.set(key, (pairCount.get(key) || 0) + 1);
25335
- }
25336
- }
25337
- }
25338
- const matrix = {};
25339
- for (const [key, count] of pairCount) {
25340
- const [fileA, fileB] = key.split("\0");
25341
- const countA = fileCommitCount.get(fileA) || 0;
25342
- const countB = fileCommitCount.get(fileB) || 0;
25343
- if (countA < MIN_FILE_OCCURRENCES || countB < MIN_FILE_OCCURRENCES) continue;
25344
- const unionCount = countA + countB - count;
25345
- const similarity = unionCount > 0 ? count / unionCount : 0;
25346
- if (similarity < MIN_SIMILARITY) continue;
25347
- if (!matrix[fileA]) matrix[fileA] = {};
25348
- if (!matrix[fileB]) matrix[fileB] = {};
25349
- matrix[fileA][fileB] = similarity;
25350
- matrix[fileB][fileA] = similarity;
25351
- }
25352
- return {
25353
- matrix,
25354
- commitsAnalyzed: commitSets.length,
25355
- filesAnalyzed: fileCommitCount.size,
25356
- builtAt: (/* @__PURE__ */ new Date()).toISOString()
25357
- };
25358
- }
25359
- function pairKey(a, b) {
25360
- return a < b ? `${a}\0${b}` : `${b}\0${a}`;
25361
- }
25362
- function saveMatrix(projectId, index) {
25363
- database_default.setDoc(projectId, INDEX_KEY2, index);
25364
- }
25365
- async function indexCoChanges(projectPath, projectId, maxCommits = 100) {
25366
- const index = await buildMatrix(projectPath, maxCommits);
25367
- saveMatrix(projectId, index);
25368
- return index;
25369
- }
25370
- var exec14, MIN_SIMILARITY, MIN_FILE_OCCURRENCES, MAX_FILES_PER_COMMIT, INDEX_KEY2;
25371
- var init_git_cochange = __esm({
25372
- "core/domain/git-cochange.ts"() {
25373
- "use strict";
25374
- init_database();
25375
- exec14 = promisify15(execCallback7);
25376
- MIN_SIMILARITY = 0.1;
25377
- MIN_FILE_OCCURRENCES = 2;
25378
- MAX_FILES_PER_COMMIT = 30;
25379
- __name(parseGitLog, "parseGitLog");
25380
- __name(isSourceFile, "isSourceFile");
25381
- __name(buildMatrix, "buildMatrix");
25382
- __name(pairKey, "pairKey");
25383
- INDEX_KEY2 = "cochange-index";
25384
- __name(saveMatrix, "saveMatrix");
25385
- __name(indexCoChanges, "indexCoChanges");
25386
- }
25387
- });
25388
-
25389
25611
  // core/domain/import-graph.ts
25390
25612
  import fs47 from "node:fs/promises";
25391
25613
  import path50 from "node:path";
@@ -25483,14 +25705,17 @@ async function buildGraph(projectPath) {
25483
25705
  };
25484
25706
  }
25485
25707
  function saveGraph(projectId, graph) {
25486
- database_default.setDoc(projectId, INDEX_KEY3, graph);
25708
+ database_default.setDoc(projectId, INDEX_KEY2, graph);
25709
+ }
25710
+ function loadGraph(projectId) {
25711
+ return database_default.getDoc(projectId, INDEX_KEY2);
25487
25712
  }
25488
25713
  async function indexImports(projectPath, projectId) {
25489
25714
  const graph = await buildGraph(projectPath);
25490
25715
  saveGraph(projectId, graph);
25491
25716
  return graph;
25492
25717
  }
25493
- var INDEXABLE_EXTENSIONS2, SKIP_DIRS2, RESOLVE_EXTENSIONS, IMPORT_REGEX, INDEX_KEY3;
25718
+ var INDEXABLE_EXTENSIONS2, SKIP_DIRS2, RESOLVE_EXTENSIONS, IMPORT_REGEX, INDEX_KEY2;
25494
25719
  var init_import_graph = __esm({
25495
25720
  "core/domain/import-graph.ts"() {
25496
25721
  "use strict";
@@ -25514,15 +25739,362 @@ var init_import_graph = __esm({
25514
25739
  __name(resolveImport2, "resolveImport");
25515
25740
  __name(listFiles3, "listFiles");
25516
25741
  __name(buildGraph, "buildGraph");
25517
- INDEX_KEY3 = "import-graph";
25742
+ INDEX_KEY2 = "import-graph";
25518
25743
  __name(saveGraph, "saveGraph");
25744
+ __name(loadGraph, "loadGraph");
25519
25745
  __name(indexImports, "indexImports");
25520
25746
  }
25521
25747
  });
25522
25748
 
25523
- // core/services/context-generator.ts
25749
+ // core/domain/change-propagator.ts
25750
+ function propagateChanges(diff, projectId) {
25751
+ const directlyChanged = [...diff.added, ...diff.modified];
25752
+ const directSet = new Set(directlyChanged);
25753
+ const affected = /* @__PURE__ */ new Set();
25754
+ const graph = loadGraph(projectId);
25755
+ if (graph) {
25756
+ for (const changedFile of directlyChanged) {
25757
+ const importers = graph.reverse[changedFile];
25758
+ if (importers) {
25759
+ for (const importer of importers) {
25760
+ if (!directSet.has(importer)) {
25761
+ affected.add(importer);
25762
+ }
25763
+ }
25764
+ }
25765
+ }
25766
+ }
25767
+ const affectedByImports = Array.from(affected);
25768
+ const allAffected = [...directlyChanged, ...affectedByImports];
25769
+ return {
25770
+ directlyChanged,
25771
+ affectedByImports,
25772
+ deleted: diff.deleted,
25773
+ allAffected
25774
+ };
25775
+ }
25776
+ function affectedDomains(changedFiles) {
25777
+ const domains = /* @__PURE__ */ new Set();
25778
+ for (const file of changedFiles) {
25779
+ const lower = file.toLowerCase();
25780
+ if (lower.endsWith(".tsx") || lower.endsWith(".jsx") || lower.endsWith(".css") || lower.endsWith(".scss") || lower.endsWith(".vue") || lower.endsWith(".svelte") || lower.includes("/components/") || lower.includes("/pages/") || lower.includes("/app/")) {
25781
+ domains.add("frontend");
25782
+ domains.add("uxui");
25783
+ }
25784
+ if (lower.includes(".test.") || lower.includes(".spec.") || lower.includes("__tests__") || lower.includes("/test/")) {
25785
+ domains.add("testing");
25786
+ }
25787
+ if (lower.includes("dockerfile") || lower.includes("docker-compose") || lower.includes(".dockerignore") || lower.includes(".github/") || lower.includes("ci/") || lower.includes("cd/")) {
25788
+ domains.add("devops");
25789
+ }
25790
+ if (lower.endsWith(".sql") || lower.includes("prisma") || lower.includes("drizzle") || lower.includes("migration") || lower.includes("/db/")) {
25791
+ domains.add("database");
25792
+ }
25793
+ if ((lower.endsWith(".ts") || lower.endsWith(".js")) && !lower.includes(".test.") && !lower.includes(".spec.") && !lower.endsWith(".d.ts")) {
25794
+ domains.add("backend");
25795
+ }
25796
+ }
25797
+ return domains;
25798
+ }
25799
+ var init_change_propagator = __esm({
25800
+ "core/domain/change-propagator.ts"() {
25801
+ "use strict";
25802
+ init_import_graph();
25803
+ __name(propagateChanges, "propagateChanges");
25804
+ __name(affectedDomains, "affectedDomains");
25805
+ }
25806
+ });
25807
+
25808
+ // core/domain/file-hasher.ts
25524
25809
  import fs48 from "node:fs/promises";
25525
25810
  import path51 from "node:path";
25811
+ async function listProjectFiles(dir, projectPath) {
25812
+ const files = [];
25813
+ const entries = await fs48.readdir(dir, { withFileTypes: true }).catch(() => []);
25814
+ for (const entry of entries) {
25815
+ const name = String(entry.name);
25816
+ if (SKIP_DIRS3.has(name)) continue;
25817
+ if (name.startsWith(".") && name !== ".env.example") continue;
25818
+ const fullPath = path51.join(dir, name);
25819
+ if (entry.isDirectory()) {
25820
+ files.push(...await listProjectFiles(fullPath, projectPath));
25821
+ } else if (entry.isFile()) {
25822
+ const ext = path51.extname(name).toLowerCase();
25823
+ if (INDEXABLE_EXTENSIONS3.has(ext)) {
25824
+ files.push(path51.relative(projectPath, fullPath));
25825
+ }
25826
+ }
25827
+ }
25828
+ return files;
25829
+ }
25830
+ function hashContent(content) {
25831
+ if (typeof Bun !== "undefined" && Bun.hash) {
25832
+ return `xxh64:${Bun.hash(content).toString(36)}`;
25833
+ }
25834
+ let h = 2166136261;
25835
+ for (let i = 0; i < content.length; i++) {
25836
+ h ^= content.charCodeAt(i);
25837
+ h = Math.imul(h, 16777619);
25838
+ }
25839
+ return `fnv1a:${(h >>> 0).toString(36)}`;
25840
+ }
25841
+ async function computeHashes(projectPath) {
25842
+ const filePaths = await listProjectFiles(projectPath, projectPath);
25843
+ const hashes = /* @__PURE__ */ new Map();
25844
+ const BATCH_SIZE = 100;
25845
+ for (let i = 0; i < filePaths.length; i += BATCH_SIZE) {
25846
+ const batch = filePaths.slice(i, i + BATCH_SIZE);
25847
+ const results = await Promise.all(
25848
+ batch.map(async (filePath) => {
25849
+ try {
25850
+ const fullPath = path51.join(projectPath, filePath);
25851
+ const [content, stat] = await Promise.all([
25852
+ fs48.readFile(fullPath, "utf-8"),
25853
+ fs48.stat(fullPath)
25854
+ ]);
25855
+ return {
25856
+ path: filePath,
25857
+ hash: hashContent(content),
25858
+ size: stat.size,
25859
+ mtime: stat.mtime.toISOString()
25860
+ };
25861
+ } catch {
25862
+ return null;
25863
+ }
25864
+ })
25865
+ );
25866
+ for (const result of results) {
25867
+ if (result) {
25868
+ hashes.set(result.path, result);
25869
+ }
25870
+ }
25871
+ }
25872
+ return hashes;
25873
+ }
25874
+ function diffHashes(current, stored) {
25875
+ const added = [];
25876
+ const modified = [];
25877
+ const unchanged = [];
25878
+ for (const [filePath, currentHash] of current) {
25879
+ const storedHash = stored.get(filePath);
25880
+ if (!storedHash) {
25881
+ added.push(filePath);
25882
+ } else if (storedHash.hash !== currentHash.hash) {
25883
+ modified.push(filePath);
25884
+ } else {
25885
+ unchanged.push(filePath);
25886
+ }
25887
+ }
25888
+ const deleted = [];
25889
+ for (const filePath of stored.keys()) {
25890
+ if (!current.has(filePath)) {
25891
+ deleted.push(filePath);
25892
+ }
25893
+ }
25894
+ return { added, modified, deleted, unchanged };
25895
+ }
25896
+ function saveHashes(projectId, hashes) {
25897
+ const db = database_default.getDb(projectId);
25898
+ db.transaction(() => {
25899
+ db.prepare("DELETE FROM index_checksums").run();
25900
+ const insert = db.prepare(
25901
+ "INSERT INTO index_checksums (path, checksum, size, mtime) VALUES (?, ?, ?, ?)"
25902
+ );
25903
+ for (const [, hash] of hashes) {
25904
+ insert.run(hash.path, hash.hash, hash.size, hash.mtime);
25905
+ }
25906
+ })();
25907
+ database_default.setDoc(projectId, "file-hashes-meta", {
25908
+ fileCount: hashes.size,
25909
+ builtAt: (/* @__PURE__ */ new Date()).toISOString()
25910
+ });
25911
+ }
25912
+ function loadHashes(projectId) {
25913
+ const hashes = /* @__PURE__ */ new Map();
25914
+ try {
25915
+ const rows = database_default.query(
25916
+ projectId,
25917
+ "SELECT path, checksum, size, mtime FROM index_checksums"
25918
+ );
25919
+ for (const row of rows) {
25920
+ hashes.set(row.path, {
25921
+ path: row.path,
25922
+ hash: row.checksum,
25923
+ size: row.size || 0,
25924
+ mtime: row.mtime || ""
25925
+ });
25926
+ }
25927
+ } catch {
25928
+ }
25929
+ return hashes;
25930
+ }
25931
+ async function detectChanges(projectPath, projectId) {
25932
+ const [currentHashes, storedHashes] = await Promise.all([
25933
+ computeHashes(projectPath),
25934
+ Promise.resolve(loadHashes(projectId))
25935
+ ]);
25936
+ const diff = diffHashes(currentHashes, storedHashes);
25937
+ return { diff, currentHashes };
25938
+ }
25939
+ function hasHashRegistry(projectId) {
25940
+ return database_default.hasDoc(projectId, "file-hashes-meta");
25941
+ }
25942
+ var INDEXABLE_EXTENSIONS3, SKIP_DIRS3;
25943
+ var init_file_hasher = __esm({
25944
+ "core/domain/file-hasher.ts"() {
25945
+ "use strict";
25946
+ init_database();
25947
+ INDEXABLE_EXTENSIONS3 = /* @__PURE__ */ new Set([
25948
+ ".ts",
25949
+ ".tsx",
25950
+ ".js",
25951
+ ".jsx",
25952
+ ".mjs",
25953
+ ".cjs",
25954
+ ".json",
25955
+ ".md",
25956
+ ".css",
25957
+ ".scss",
25958
+ ".html",
25959
+ ".vue",
25960
+ ".svelte",
25961
+ ".py",
25962
+ ".go",
25963
+ ".rs",
25964
+ ".yaml",
25965
+ ".yml",
25966
+ ".toml"
25967
+ ]);
25968
+ SKIP_DIRS3 = /* @__PURE__ */ new Set([
25969
+ "node_modules",
25970
+ ".git",
25971
+ "dist",
25972
+ "build",
25973
+ "out",
25974
+ ".next",
25975
+ "coverage",
25976
+ ".cache",
25977
+ ".turbo",
25978
+ ".vercel",
25979
+ ".prjct"
25980
+ ]);
25981
+ __name(listProjectFiles, "listProjectFiles");
25982
+ __name(hashContent, "hashContent");
25983
+ __name(computeHashes, "computeHashes");
25984
+ __name(diffHashes, "diffHashes");
25985
+ __name(saveHashes, "saveHashes");
25986
+ __name(loadHashes, "loadHashes");
25987
+ __name(detectChanges, "detectChanges");
25988
+ __name(hasHashRegistry, "hasHashRegistry");
25989
+ }
25990
+ });
25991
+
25992
+ // core/domain/git-cochange.ts
25993
+ import { exec as execCallback7 } from "node:child_process";
25994
+ import { promisify as promisify15 } from "node:util";
25995
+ async function parseGitLog(projectPath, maxCommits = 100) {
25996
+ try {
25997
+ const { stdout } = await exec14(
25998
+ `git log --name-only --pretty=format:'---COMMIT---' -${maxCommits}`,
25999
+ { cwd: projectPath, maxBuffer: 10 * 1024 * 1024 }
26000
+ );
26001
+ const commits = [];
26002
+ let currentFiles = null;
26003
+ for (const line of stdout.split("\n")) {
26004
+ const trimmed = line.trim();
26005
+ if (trimmed === "---COMMIT---") {
26006
+ if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
26007
+ commits.push(currentFiles);
26008
+ }
26009
+ currentFiles = /* @__PURE__ */ new Set();
26010
+ } else if (trimmed && currentFiles) {
26011
+ if (isSourceFile(trimmed)) {
26012
+ currentFiles.add(trimmed);
26013
+ }
26014
+ }
26015
+ }
26016
+ if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
26017
+ commits.push(currentFiles);
26018
+ }
26019
+ return commits;
26020
+ } catch {
26021
+ return [];
26022
+ }
26023
+ }
26024
+ function isSourceFile(filePath) {
26025
+ const sourceExtensions = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|cs|rb|php|vue|svelte)$/i;
26026
+ return sourceExtensions.test(filePath) && !filePath.includes("node_modules/");
26027
+ }
26028
+ async function buildMatrix(projectPath, maxCommits = 100) {
26029
+ const commitSets = await parseGitLog(projectPath, maxCommits);
26030
+ const fileCommitCount = /* @__PURE__ */ new Map();
26031
+ const pairCount = /* @__PURE__ */ new Map();
26032
+ for (const files of commitSets) {
26033
+ const fileArray = Array.from(files);
26034
+ for (const file of fileArray) {
26035
+ fileCommitCount.set(file, (fileCommitCount.get(file) || 0) + 1);
26036
+ }
26037
+ for (let i = 0; i < fileArray.length; i++) {
26038
+ for (let j = i + 1; j < fileArray.length; j++) {
26039
+ const key = pairKey(fileArray[i], fileArray[j]);
26040
+ pairCount.set(key, (pairCount.get(key) || 0) + 1);
26041
+ }
26042
+ }
26043
+ }
26044
+ const matrix = {};
26045
+ for (const [key, count] of pairCount) {
26046
+ const [fileA, fileB] = key.split("\0");
26047
+ const countA = fileCommitCount.get(fileA) || 0;
26048
+ const countB = fileCommitCount.get(fileB) || 0;
26049
+ if (countA < MIN_FILE_OCCURRENCES || countB < MIN_FILE_OCCURRENCES) continue;
26050
+ const unionCount = countA + countB - count;
26051
+ const similarity = unionCount > 0 ? count / unionCount : 0;
26052
+ if (similarity < MIN_SIMILARITY) continue;
26053
+ if (!matrix[fileA]) matrix[fileA] = {};
26054
+ if (!matrix[fileB]) matrix[fileB] = {};
26055
+ matrix[fileA][fileB] = similarity;
26056
+ matrix[fileB][fileA] = similarity;
26057
+ }
26058
+ return {
26059
+ matrix,
26060
+ commitsAnalyzed: commitSets.length,
26061
+ filesAnalyzed: fileCommitCount.size,
26062
+ builtAt: (/* @__PURE__ */ new Date()).toISOString()
26063
+ };
26064
+ }
26065
+ function pairKey(a, b) {
26066
+ return a < b ? `${a}\0${b}` : `${b}\0${a}`;
26067
+ }
26068
+ function saveMatrix(projectId, index) {
26069
+ database_default.setDoc(projectId, INDEX_KEY3, index);
26070
+ }
26071
+ async function indexCoChanges(projectPath, projectId, maxCommits = 100) {
26072
+ const index = await buildMatrix(projectPath, maxCommits);
26073
+ saveMatrix(projectId, index);
26074
+ return index;
26075
+ }
26076
+ var exec14, MIN_SIMILARITY, MIN_FILE_OCCURRENCES, MAX_FILES_PER_COMMIT, INDEX_KEY3;
26077
+ var init_git_cochange = __esm({
26078
+ "core/domain/git-cochange.ts"() {
26079
+ "use strict";
26080
+ init_database();
26081
+ exec14 = promisify15(execCallback7);
26082
+ MIN_SIMILARITY = 0.1;
26083
+ MIN_FILE_OCCURRENCES = 2;
26084
+ MAX_FILES_PER_COMMIT = 30;
26085
+ __name(parseGitLog, "parseGitLog");
26086
+ __name(isSourceFile, "isSourceFile");
26087
+ __name(buildMatrix, "buildMatrix");
26088
+ __name(pairKey, "pairKey");
26089
+ INDEX_KEY3 = "cochange-index";
26090
+ __name(saveMatrix, "saveMatrix");
26091
+ __name(indexCoChanges, "indexCoChanges");
26092
+ }
26093
+ });
26094
+
26095
+ // core/services/context-generator.ts
26096
+ import fs49 from "node:fs/promises";
26097
+ import path52 from "node:path";
25526
26098
  var ContextFileGenerator;
25527
26099
  var init_context_generator = __esm({
25528
26100
  "core/services/context-generator.ts"() {
@@ -25547,10 +26119,10 @@ var init_context_generator = __esm({
25547
26119
  async writeWithPreservation(filePath, content) {
25548
26120
  let finalContent = content;
25549
26121
  try {
25550
- const existingContent = await fs48.readFile(filePath, "utf-8");
26122
+ const existingContent = await fs49.readFile(filePath, "utf-8");
25551
26123
  const validation = validatePreserveBlocks(existingContent);
25552
26124
  if (!validation.valid) {
25553
- const filename = path51.basename(filePath);
26125
+ const filename = path52.basename(filePath);
25554
26126
  console.warn(`\u26A0\uFE0F ${filename} has invalid preserve blocks:`);
25555
26127
  for (const error of validation.errors) {
25556
26128
  console.warn(` ${error}`);
@@ -25559,13 +26131,13 @@ var init_context_generator = __esm({
25559
26131
  finalContent = mergePreservedSections(content, existingContent);
25560
26132
  } catch {
25561
26133
  }
25562
- await fs48.writeFile(filePath, finalContent, "utf-8");
26134
+ await fs49.writeFile(filePath, finalContent, "utf-8");
25563
26135
  }
25564
26136
  /**
25565
26137
  * Generate all context files in parallel
25566
26138
  */
25567
26139
  async generate(git, stats, commands, agents, sources) {
25568
- const contextPath = path51.join(this.config.globalPath, "context");
26140
+ const contextPath = path52.join(this.config.globalPath, "context");
25569
26141
  await Promise.all([
25570
26142
  this.generateClaudeMd(contextPath, git, stats, commands, agents, sources),
25571
26143
  this.generateNowMd(contextPath),
@@ -25665,7 +26237,7 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
25665
26237
  **Workflow**: ${workflowAgents.join(", ")}
25666
26238
  **Domain**: ${domainAgents.join(", ") || "none"}
25667
26239
  `;
25668
- const claudePath = path51.join(contextPath, "CLAUDE.md");
26240
+ const claudePath = path52.join(contextPath, "CLAUDE.md");
25669
26241
  await this.writeWithPreservation(claudePath, content);
25670
26242
  }
25671
26243
  /**
@@ -25674,8 +26246,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
25674
26246
  async generateNowMd(contextPath) {
25675
26247
  let currentTask = null;
25676
26248
  try {
25677
- const statePath = path51.join(this.config.globalPath, "storage", "state.json");
25678
- const state = JSON.parse(await fs48.readFile(statePath, "utf-8"));
26249
+ const statePath = path52.join(this.config.globalPath, "storage", "state.json");
26250
+ const state = JSON.parse(await fs49.readFile(statePath, "utf-8"));
25679
26251
  currentTask = state.currentTask;
25680
26252
  } catch {
25681
26253
  }
@@ -25691,7 +26263,7 @@ _No active task_
25691
26263
 
25692
26264
  Use \`p. task "description"\` to start working.
25693
26265
  `;
25694
- await this.writeWithPreservation(path51.join(contextPath, "now.md"), content);
26266
+ await this.writeWithPreservation(path52.join(contextPath, "now.md"), content);
25695
26267
  }
25696
26268
  /**
25697
26269
  * Generate next.md - task queue
@@ -25699,15 +26271,15 @@ Use \`p. task "description"\` to start working.
25699
26271
  async generateNextMd(contextPath) {
25700
26272
  let queue = { tasks: [] };
25701
26273
  try {
25702
- const queuePath = path51.join(this.config.globalPath, "storage", "queue.json");
25703
- queue = JSON.parse(await fs48.readFile(queuePath, "utf-8"));
26274
+ const queuePath = path52.join(this.config.globalPath, "storage", "queue.json");
26275
+ queue = JSON.parse(await fs49.readFile(queuePath, "utf-8"));
25704
26276
  } catch {
25705
26277
  }
25706
26278
  const content = `# NEXT
25707
26279
 
25708
26280
  ${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}${t.priority ? ` [${t.priority}]` : ""}`).join("\n") : "_Empty queue_"}
25709
26281
  `;
25710
- await this.writeWithPreservation(path51.join(contextPath, "next.md"), content);
26282
+ await this.writeWithPreservation(path52.join(contextPath, "next.md"), content);
25711
26283
  }
25712
26284
  /**
25713
26285
  * Generate ideas.md - captured ideas
@@ -25715,15 +26287,15 @@ ${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}
25715
26287
  async generateIdeasMd(contextPath) {
25716
26288
  let ideas = { ideas: [] };
25717
26289
  try {
25718
- const ideasPath = path51.join(this.config.globalPath, "storage", "ideas.json");
25719
- ideas = JSON.parse(await fs48.readFile(ideasPath, "utf-8"));
26290
+ const ideasPath = path52.join(this.config.globalPath, "storage", "ideas.json");
26291
+ ideas = JSON.parse(await fs49.readFile(ideasPath, "utf-8"));
25720
26292
  } catch {
25721
26293
  }
25722
26294
  const content = `# IDEAS
25723
26295
 
25724
26296
  ${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [${i.priority}]` : ""}`).join("\n") : "_No ideas captured yet_"}
25725
26297
  `;
25726
- await this.writeWithPreservation(path51.join(contextPath, "ideas.md"), content);
26298
+ await this.writeWithPreservation(path52.join(contextPath, "ideas.md"), content);
25727
26299
  }
25728
26300
  /**
25729
26301
  * Generate shipped.md - completed features
@@ -25733,8 +26305,8 @@ ${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [
25733
26305
  shipped: []
25734
26306
  };
25735
26307
  try {
25736
- const shippedPath = path51.join(this.config.globalPath, "storage", "shipped.json");
25737
- shipped = JSON.parse(await fs48.readFile(shippedPath, "utf-8"));
26308
+ const shippedPath = path52.join(this.config.globalPath, "storage", "shipped.json");
26309
+ shipped = JSON.parse(await fs49.readFile(shippedPath, "utf-8"));
25738
26310
  } catch {
25739
26311
  }
25740
26312
  const content = `# SHIPPED \u{1F680}
@@ -25743,7 +26315,7 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
25743
26315
 
25744
26316
  **Total shipped:** ${shipped.shipped.length}
25745
26317
  `;
25746
- await this.writeWithPreservation(path51.join(contextPath, "shipped.md"), content);
26318
+ await this.writeWithPreservation(path52.join(contextPath, "shipped.md"), content);
25747
26319
  }
25748
26320
  // ==========================================================================
25749
26321
  // MONOREPO SUPPORT
@@ -25772,9 +26344,9 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
25772
26344
  commands,
25773
26345
  agents
25774
26346
  );
25775
- const claudePath = path51.join(pkg.path, "CLAUDE.md");
26347
+ const claudePath = path52.join(pkg.path, "CLAUDE.md");
25776
26348
  await this.writeWithPreservation(claudePath, content);
25777
- generatedFiles.push(path51.relative(this.config.projectPath, claudePath));
26349
+ generatedFiles.push(path52.relative(this.config.projectPath, claudePath));
25778
26350
  }
25779
26351
  return generatedFiles;
25780
26352
  }
@@ -25787,8 +26359,8 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
25787
26359
  let pkgVersion = stats.version;
25788
26360
  let pkgName = pkg.name;
25789
26361
  try {
25790
- const pkgJsonPath = path51.join(pkg.path, "package.json");
25791
- const pkgJson = JSON.parse(await fs48.readFile(pkgJsonPath, "utf-8"));
26362
+ const pkgJsonPath = path52.join(pkg.path, "package.json");
26363
+ const pkgJson = JSON.parse(await fs49.readFile(pkgJsonPath, "utf-8"));
25792
26364
  pkgVersion = pkgJson.version || stats.version;
25793
26365
  pkgName = pkgJson.name || pkg.name;
25794
26366
  } catch {
@@ -25853,8 +26425,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
25853
26425
  });
25854
26426
 
25855
26427
  // core/services/local-state-generator.ts
25856
- import fs49 from "node:fs/promises";
25857
- import path52 from "node:path";
26428
+ import fs50 from "node:fs/promises";
26429
+ import path53 from "node:path";
25858
26430
  var LOCAL_STATE_FILENAME, LocalStateGenerator, localStateGenerator;
25859
26431
  var init_local_state_generator = __esm({
25860
26432
  "core/services/local-state-generator.ts"() {
@@ -25869,17 +26441,17 @@ var init_local_state_generator = __esm({
25869
26441
  * Generate .prjct-state.md in the project root
25870
26442
  */
25871
26443
  async generate(projectPath, state) {
25872
- const filePath = path52.join(projectPath, LOCAL_STATE_FILENAME);
26444
+ const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
25873
26445
  const content = this.toMarkdown(state);
25874
- await fs49.writeFile(filePath, content, "utf-8");
26446
+ await fs50.writeFile(filePath, content, "utf-8");
25875
26447
  }
25876
26448
  /**
25877
26449
  * Remove local state file
25878
26450
  */
25879
26451
  async remove(projectPath) {
25880
- const filePath = path52.join(projectPath, LOCAL_STATE_FILENAME);
26452
+ const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
25881
26453
  try {
25882
- await fs49.unlink(filePath);
26454
+ await fs50.unlink(filePath);
25883
26455
  } catch (error) {
25884
26456
  if (!isNotFoundError(error)) throw error;
25885
26457
  }
@@ -25888,9 +26460,9 @@ var init_local_state_generator = __esm({
25888
26460
  * Check if local state file exists
25889
26461
  */
25890
26462
  async exists(projectPath) {
25891
- const filePath = path52.join(projectPath, LOCAL_STATE_FILENAME);
26463
+ const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
25892
26464
  try {
25893
- await fs49.access(filePath);
26465
+ await fs50.access(filePath);
25894
26466
  return true;
25895
26467
  } catch {
25896
26468
  return false;
@@ -25969,11 +26541,11 @@ var init_local_state_generator = __esm({
25969
26541
  });
25970
26542
 
25971
26543
  // core/services/skill-lock.ts
25972
- import fs50 from "node:fs/promises";
26544
+ import fs51 from "node:fs/promises";
25973
26545
  import os14 from "node:os";
25974
- import path53 from "node:path";
26546
+ import path54 from "node:path";
25975
26547
  function getLockFilePath() {
25976
- return path53.join(os14.homedir(), ".prjct-cli", "skills", LOCK_FILE_NAME);
26548
+ return path54.join(os14.homedir(), ".prjct-cli", "skills", LOCK_FILE_NAME);
25977
26549
  }
25978
26550
  function createEmptyLockFile() {
25979
26551
  return {
@@ -25984,7 +26556,7 @@ function createEmptyLockFile() {
25984
26556
  }
25985
26557
  async function read() {
25986
26558
  try {
25987
- const content = await fs50.readFile(getLockFilePath(), "utf-8");
26559
+ const content = await fs51.readFile(getLockFilePath(), "utf-8");
25988
26560
  return JSON.parse(content);
25989
26561
  } catch {
25990
26562
  return createEmptyLockFile();
@@ -25992,9 +26564,9 @@ async function read() {
25992
26564
  }
25993
26565
  async function write(lockFile) {
25994
26566
  const lockPath = getLockFilePath();
25995
- await fs50.mkdir(path53.dirname(lockPath), { recursive: true });
26567
+ await fs51.mkdir(path54.dirname(lockPath), { recursive: true });
25996
26568
  lockFile.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
25997
- await fs50.writeFile(lockPath, JSON.stringify(lockFile, null, 2), "utf-8");
26569
+ await fs51.writeFile(lockPath, JSON.stringify(lockFile, null, 2), "utf-8");
25998
26570
  }
25999
26571
  async function addEntry(entry) {
26000
26572
  const lockFile = await read();
@@ -26047,14 +26619,14 @@ var init_skill_lock = __esm({
26047
26619
 
26048
26620
  // core/services/skill-installer.ts
26049
26621
  import { exec as execCallback8 } from "node:child_process";
26050
- import fs51 from "node:fs/promises";
26622
+ import fs52 from "node:fs/promises";
26051
26623
  import os15 from "node:os";
26052
- import path54 from "node:path";
26624
+ import path55 from "node:path";
26053
26625
  import { promisify as promisify16 } from "node:util";
26054
26626
  import { glob } from "glob";
26055
26627
  function parseSource(source) {
26056
26628
  if (source.startsWith("./") || source.startsWith("/") || source.startsWith("~")) {
26057
- const resolvedPath = source.startsWith("~") ? path54.join(os15.homedir(), source.slice(1)) : path54.resolve(source);
26629
+ const resolvedPath = source.startsWith("~") ? path55.join(os15.homedir(), source.slice(1)) : path55.resolve(source);
26058
26630
  return {
26059
26631
  type: "local",
26060
26632
  localPath: resolvedPath,
@@ -26092,22 +26664,22 @@ function parseSource(source) {
26092
26664
  async function discoverSkills(dir) {
26093
26665
  const skills = [];
26094
26666
  try {
26095
- const rootSkill = path54.join(dir, "SKILL.md");
26096
- await fs51.access(rootSkill);
26097
- const dirName = path54.basename(dir);
26667
+ const rootSkill = path55.join(dir, "SKILL.md");
26668
+ await fs52.access(rootSkill);
26669
+ const dirName = path55.basename(dir);
26098
26670
  skills.push({ name: dirName, filePath: rootSkill });
26099
26671
  } catch {
26100
26672
  }
26101
26673
  const subdirSkills = await glob("*/SKILL.md", { cwd: dir, absolute: true });
26102
26674
  for (const filePath of subdirSkills) {
26103
- const name = path54.basename(path54.dirname(filePath));
26675
+ const name = path55.basename(path55.dirname(filePath));
26104
26676
  if (!skills.some((s) => s.name === name)) {
26105
26677
  skills.push({ name, filePath });
26106
26678
  }
26107
26679
  }
26108
26680
  const nestedSkills = await glob("skills/*/SKILL.md", { cwd: dir, absolute: true });
26109
26681
  for (const filePath of nestedSkills) {
26110
- const name = path54.basename(path54.dirname(filePath));
26682
+ const name = path55.basename(path55.dirname(filePath));
26111
26683
  if (!skills.some((s) => s.name === name)) {
26112
26684
  skills.push({ name, filePath });
26113
26685
  }
@@ -26143,16 +26715,16 @@ ${prjctBlock.join("\n")}
26143
26715
  ${content}`;
26144
26716
  }
26145
26717
  function getInstallDir() {
26146
- return path54.join(os15.homedir(), ".claude", "skills");
26718
+ return path55.join(os15.homedir(), ".claude", "skills");
26147
26719
  }
26148
26720
  async function installSkillFile(sourcePath, name, source, sha) {
26149
26721
  const installDir = getInstallDir();
26150
- const targetDir = path54.join(installDir, name);
26151
- const targetPath = path54.join(targetDir, "SKILL.md");
26152
- const content = await fs51.readFile(sourcePath, "utf-8");
26722
+ const targetDir = path55.join(installDir, name);
26723
+ const targetPath = path55.join(targetDir, "SKILL.md");
26724
+ const content = await fs52.readFile(sourcePath, "utf-8");
26153
26725
  const enrichedContent = injectSourceMetadata(content, source, sha);
26154
- await fs51.mkdir(targetDir, { recursive: true });
26155
- await fs51.writeFile(targetPath, enrichedContent, "utf-8");
26726
+ await fs52.mkdir(targetDir, { recursive: true });
26727
+ await fs52.writeFile(targetPath, enrichedContent, "utf-8");
26156
26728
  return {
26157
26729
  name,
26158
26730
  filePath: targetPath,
@@ -26169,7 +26741,7 @@ async function installFromGitHub(source) {
26169
26741
  );
26170
26742
  return result;
26171
26743
  }
26172
- const tmpDir = path54.join(os15.tmpdir(), `prjct-skill-${Date.now()}`);
26744
+ const tmpDir = path55.join(os15.tmpdir(), `prjct-skill-${Date.now()}`);
26173
26745
  try {
26174
26746
  const cloneUrl = `https://github.com/${source.owner}/${source.repo}.git`;
26175
26747
  await exec15(`git clone --depth 1 ${cloneUrl} ${tmpDir}`, { timeout: getTimeout("GIT_CLONE") });
@@ -26213,7 +26785,7 @@ async function installFromGitHub(source) {
26213
26785
  }
26214
26786
  } finally {
26215
26787
  try {
26216
- await fs51.rm(tmpDir, { recursive: true, force: true });
26788
+ await fs52.rm(tmpDir, { recursive: true, force: true });
26217
26789
  } catch {
26218
26790
  }
26219
26791
  }
@@ -26223,14 +26795,14 @@ async function installFromLocal(source) {
26223
26795
  const result = { installed: [], skipped: [], errors: [] };
26224
26796
  const localPath = source.localPath;
26225
26797
  try {
26226
- await fs51.access(localPath);
26798
+ await fs52.access(localPath);
26227
26799
  } catch {
26228
26800
  result.errors.push(`Local path not found: ${localPath}`);
26229
26801
  return result;
26230
26802
  }
26231
- const stat = await fs51.stat(localPath);
26803
+ const stat = await fs52.stat(localPath);
26232
26804
  if (stat.isFile()) {
26233
- const name = path54.basename(path54.dirname(localPath));
26805
+ const name = path55.basename(path55.dirname(localPath));
26234
26806
  try {
26235
26807
  const installed = await installSkillFile(localPath, name, source);
26236
26808
  const lockEntry = {
@@ -26270,14 +26842,14 @@ async function installFromLocal(source) {
26270
26842
  }
26271
26843
  async function remove(name) {
26272
26844
  const installDir = getInstallDir();
26273
- const subdirPath = path54.join(installDir, name);
26845
+ const subdirPath = path55.join(installDir, name);
26274
26846
  try {
26275
- await fs51.rm(subdirPath, { recursive: true, force: true });
26847
+ await fs52.rm(subdirPath, { recursive: true, force: true });
26276
26848
  } catch {
26277
26849
  }
26278
- const flatPath = path54.join(installDir, `${name}.md`);
26850
+ const flatPath = path55.join(installDir, `${name}.md`);
26279
26851
  try {
26280
- await fs51.rm(flatPath, { force: true });
26852
+ await fs52.rm(flatPath, { force: true });
26281
26853
  } catch {
26282
26854
  }
26283
26855
  return skillLock.removeEntry(name);
@@ -26325,8 +26897,8 @@ var init_skill_installer = __esm({
26325
26897
  });
26326
26898
 
26327
26899
  // core/services/stack-detector.ts
26328
- import fs52 from "node:fs/promises";
26329
- import path55 from "node:path";
26900
+ import fs53 from "node:fs/promises";
26901
+ import path56 from "node:path";
26330
26902
  var StackDetector;
26331
26903
  var init_stack_detector = __esm({
26332
26904
  "core/services/stack-detector.ts"() {
@@ -26485,8 +27057,8 @@ var init_stack_detector = __esm({
26485
27057
  */
26486
27058
  async readPackageJson() {
26487
27059
  try {
26488
- const pkgPath = path55.join(this.projectPath, "package.json");
26489
- const content = await fs52.readFile(pkgPath, "utf-8");
27060
+ const pkgPath = path56.join(this.projectPath, "package.json");
27061
+ const content = await fs53.readFile(pkgPath, "utf-8");
26490
27062
  return JSON.parse(content);
26491
27063
  } catch {
26492
27064
  return null;
@@ -26497,7 +27069,7 @@ var init_stack_detector = __esm({
26497
27069
  */
26498
27070
  async fileExists(filename) {
26499
27071
  try {
26500
- await fs52.access(path55.join(this.projectPath, filename));
27072
+ await fs53.access(path56.join(this.projectPath, filename));
26501
27073
  return true;
26502
27074
  } catch {
26503
27075
  return false;
@@ -26509,8 +27081,8 @@ var init_stack_detector = __esm({
26509
27081
 
26510
27082
  // core/services/sync-verifier.ts
26511
27083
  import { exec as exec16 } from "node:child_process";
26512
- import fs53 from "node:fs/promises";
26513
- import path56 from "node:path";
27084
+ import fs54 from "node:fs/promises";
27085
+ import path57 from "node:path";
26514
27086
  import { promisify as promisify17 } from "node:util";
26515
27087
  var execAsync10, BUILTIN_CHECKS, SyncVerifier, syncVerifier;
26516
27088
  var init_sync_verifier = __esm({
@@ -26527,9 +27099,9 @@ var init_sync_verifier = __esm({
26527
27099
  const expected = ["context/CLAUDE.md"];
26528
27100
  const missing = [];
26529
27101
  for (const file of expected) {
26530
- const filePath = path56.join(globalPath, file);
27102
+ const filePath = path57.join(globalPath, file);
26531
27103
  try {
26532
- await fs53.access(filePath);
27104
+ await fs54.access(filePath);
26533
27105
  } catch {
26534
27106
  missing.push(file);
26535
27107
  }
@@ -26550,9 +27122,9 @@ var init_sync_verifier = __esm({
26550
27122
  const jsonFiles = ["storage/state.json"];
26551
27123
  const invalid = [];
26552
27124
  for (const file of jsonFiles) {
26553
- const filePath = path56.join(globalPath, file);
27125
+ const filePath = path57.join(globalPath, file);
26554
27126
  try {
26555
- const content = await fs53.readFile(filePath, "utf-8");
27127
+ const content = await fs54.readFile(filePath, "utf-8");
26556
27128
  JSON.parse(content);
26557
27129
  } catch (error) {
26558
27130
  if (!isNotFoundError(error)) {
@@ -26573,7 +27145,7 @@ var init_sync_verifier = __esm({
26573
27145
  */
26574
27146
  async noSensitiveData(globalPath) {
26575
27147
  const start = Date.now();
26576
- const contextDir = path56.join(globalPath, "context");
27148
+ const contextDir = path57.join(globalPath, "context");
26577
27149
  const patterns = [
26578
27150
  /(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]{10,}/i,
26579
27151
  /(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{4,}/i,
@@ -26581,10 +27153,10 @@ var init_sync_verifier = __esm({
26581
27153
  ];
26582
27154
  const violations = [];
26583
27155
  try {
26584
- const files = await fs53.readdir(contextDir);
27156
+ const files = await fs54.readdir(contextDir);
26585
27157
  for (const file of files) {
26586
27158
  if (!file.endsWith(".md")) continue;
26587
- const content = await fs53.readFile(path56.join(contextDir, file), "utf-8");
27159
+ const content = await fs54.readFile(path57.join(contextDir, file), "utf-8");
26588
27160
  for (const pattern of patterns) {
26589
27161
  if (pattern.test(content)) {
26590
27162
  violations.push(`${file}: potential sensitive data detected`);
@@ -26705,9 +27277,9 @@ var init_sync_verifier = __esm({
26705
27277
 
26706
27278
  // core/services/sync-service.ts
26707
27279
  import { exec as exec17 } from "node:child_process";
26708
- import fs54 from "node:fs/promises";
27280
+ import fs55 from "node:fs/promises";
26709
27281
  import os16 from "node:os";
26710
- import path57 from "node:path";
27282
+ import path58 from "node:path";
26711
27283
  import { promisify as promisify18 } from "node:util";
26712
27284
  var execAsync11, SyncService, syncService;
26713
27285
  var init_sync_service = __esm({
@@ -26715,6 +27287,8 @@ var init_sync_service = __esm({
26715
27287
  "use strict";
26716
27288
  init_ai_tools();
26717
27289
  init_bm25();
27290
+ init_change_propagator();
27291
+ init_file_hasher();
26718
27292
  init_git_cochange();
26719
27293
  init_import_graph();
26720
27294
  init_errors();
@@ -26722,13 +27296,19 @@ var init_sync_service = __esm({
26722
27296
  init_config_manager();
26723
27297
  init_path_manager();
26724
27298
  init_analysis_storage();
27299
+ init_archive_storage();
27300
+ init_ideas_storage();
26725
27301
  init_metrics_storage();
26726
27302
  init_migrate_json();
27303
+ init_queue_storage();
27304
+ init_shipped_storage();
27305
+ init_state_storage();
26727
27306
  init_citations();
26728
27307
  init_date_helper();
26729
27308
  init_logger();
26730
27309
  init_context_generator();
26731
27310
  init_local_state_generator();
27311
+ init_memory_service();
26732
27312
  init_skill_installer();
26733
27313
  init_stack_detector();
26734
27314
  init_sync_verifier();
@@ -26794,20 +27374,80 @@ var init_sync_service = __esm({
26794
27374
  this.detectCommands(),
26795
27375
  this.detectStack()
26796
27376
  ]);
26797
- try {
26798
- await Promise.all([
26799
- indexProject(this.projectPath, this.projectId),
26800
- indexImports(this.projectPath, this.projectId),
26801
- indexCoChanges(this.projectPath, this.projectId)
26802
- ]);
26803
- } catch (error) {
26804
- logger_default.debug("File ranking index build failed (non-critical)", {
26805
- error: getErrorMessage(error)
26806
- });
27377
+ const isFullSync = options.full === true;
27378
+ let incrementalInfo;
27379
+ let shouldRebuildIndexes = true;
27380
+ let shouldRegenerateAgents = true;
27381
+ let changedDomains = /* @__PURE__ */ new Set();
27382
+ if (!isFullSync && hasHashRegistry(this.projectId)) {
27383
+ try {
27384
+ const { diff, currentHashes } = await detectChanges(this.projectPath, this.projectId);
27385
+ const totalChanged = diff.added.length + diff.modified.length + diff.deleted.length;
27386
+ if (totalChanged === 0 && !options.changedFiles?.length) {
27387
+ shouldRebuildIndexes = false;
27388
+ shouldRegenerateAgents = false;
27389
+ incrementalInfo = {
27390
+ isIncremental: true,
27391
+ filesChanged: 0,
27392
+ filesUnchanged: diff.unchanged.length,
27393
+ indexesRebuilt: false,
27394
+ agentsRegenerated: false,
27395
+ affectedDomains: []
27396
+ };
27397
+ } else {
27398
+ const propagated = propagateChanges(diff, this.projectId);
27399
+ changedDomains = affectedDomains(propagated.allAffected);
27400
+ const sourceExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
27401
+ const hasSourceChanges = propagated.allAffected.some((f) => {
27402
+ const ext = f.substring(f.lastIndexOf("."));
27403
+ return sourceExtensions.has(ext);
27404
+ });
27405
+ shouldRebuildIndexes = hasSourceChanges;
27406
+ const configChanged = propagated.directlyChanged.some(
27407
+ (f) => f === "package.json" || f === "tsconfig.json" || f.includes("Dockerfile") || f.includes("docker-compose")
27408
+ );
27409
+ shouldRegenerateAgents = configChanged;
27410
+ incrementalInfo = {
27411
+ isIncremental: true,
27412
+ filesChanged: totalChanged,
27413
+ filesUnchanged: diff.unchanged.length,
27414
+ indexesRebuilt: shouldRebuildIndexes,
27415
+ agentsRegenerated: shouldRegenerateAgents,
27416
+ affectedDomains: Array.from(changedDomains)
27417
+ };
27418
+ }
27419
+ saveHashes(this.projectId, currentHashes);
27420
+ } catch (error) {
27421
+ logger_default.debug("Incremental detection failed, falling back to full sync", {
27422
+ error: getErrorMessage(error)
27423
+ });
27424
+ }
27425
+ } else {
27426
+ try {
27427
+ const { currentHashes } = await detectChanges(this.projectPath, this.projectId);
27428
+ saveHashes(this.projectId, currentHashes);
27429
+ } catch (error) {
27430
+ logger_default.debug("Hash computation failed (non-critical)", {
27431
+ error: getErrorMessage(error)
27432
+ });
27433
+ }
26807
27434
  }
26808
- const agents = await this.generateAgents(stack, stats);
27435
+ if (shouldRebuildIndexes) {
27436
+ try {
27437
+ await Promise.all([
27438
+ indexProject(this.projectPath, this.projectId),
27439
+ indexImports(this.projectPath, this.projectId),
27440
+ indexCoChanges(this.projectPath, this.projectId)
27441
+ ]);
27442
+ } catch (error) {
27443
+ logger_default.debug("File ranking index build failed (non-critical)", {
27444
+ error: getErrorMessage(error)
27445
+ });
27446
+ }
27447
+ }
27448
+ const agents = shouldRegenerateAgents ? await this.generateAgents(stack, stats) : await this.loadExistingAgents();
26809
27449
  const skills = this.configureSkills(agents);
26810
- const skillsInstalled = await this.autoInstallSkills(agents);
27450
+ const skillsInstalled = shouldRegenerateAgents ? await this.autoInstallSkills(agents) : [];
26811
27451
  const sources = this.buildSources(stats, commands);
26812
27452
  const contextFiles = await this.generateContextFiles(git, stats, commands, agents, sources);
26813
27453
  const projectContext = {
@@ -26844,6 +27484,7 @@ var init_sync_service = __esm({
26844
27484
  ]);
26845
27485
  const duration = Date.now() - startTime;
26846
27486
  const syncMetrics = await this.recordSyncMetrics(stats, contextFiles, agents, duration);
27487
+ await this.archiveStaleData();
26847
27488
  await command_installer_default.installGlobalConfig();
26848
27489
  await command_installer_default.syncCommands();
26849
27490
  let verification;
@@ -26875,7 +27516,8 @@ var init_sync_service = __esm({
26875
27516
  success: r.success
26876
27517
  })),
26877
27518
  syncMetrics,
26878
- verification
27519
+ verification,
27520
+ incremental: incrementalInfo
26879
27521
  };
26880
27522
  } catch (error) {
26881
27523
  return {
@@ -26901,7 +27543,7 @@ var init_sync_service = __esm({
26901
27543
  async ensureDirectories() {
26902
27544
  const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
26903
27545
  await Promise.all(
26904
- dirs.map((dir) => fs54.mkdir(path57.join(this.globalPath, dir), { recursive: true }))
27546
+ dirs.map((dir) => fs55.mkdir(path58.join(this.globalPath, dir), { recursive: true }))
26905
27547
  );
26906
27548
  }
26907
27549
  // ==========================================================================
@@ -26972,7 +27614,7 @@ var init_sync_service = __esm({
26972
27614
  const stats = {
26973
27615
  fileCount: 0,
26974
27616
  version: "0.0.0",
26975
- name: path57.basename(this.projectPath),
27617
+ name: path58.basename(this.projectPath),
26976
27618
  ecosystem: "unknown",
26977
27619
  projectType: "simple",
26978
27620
  languages: [],
@@ -26989,8 +27631,8 @@ var init_sync_service = __esm({
26989
27631
  stats.fileCount = 0;
26990
27632
  }
26991
27633
  try {
26992
- const pkgPath = path57.join(this.projectPath, "package.json");
26993
- const pkg = JSON.parse(await fs54.readFile(pkgPath, "utf-8"));
27634
+ const pkgPath = path58.join(this.projectPath, "package.json");
27635
+ const pkg = JSON.parse(await fs55.readFile(pkgPath, "utf-8"));
26994
27636
  stats.version = pkg.version || "0.0.0";
26995
27637
  stats.name = pkg.name || stats.name;
26996
27638
  stats.ecosystem = "JavaScript";
@@ -27135,12 +27777,12 @@ var init_sync_service = __esm({
27135
27777
  // ==========================================================================
27136
27778
  async generateAgents(stack, stats) {
27137
27779
  const agents = [];
27138
- const agentsPath = path57.join(this.globalPath, "agents");
27780
+ const agentsPath = path58.join(this.globalPath, "agents");
27139
27781
  try {
27140
- const files = await fs54.readdir(agentsPath);
27782
+ const files = await fs55.readdir(agentsPath);
27141
27783
  for (const file of files) {
27142
27784
  if (file.endsWith(".md")) {
27143
- await fs54.unlink(path57.join(agentsPath, file));
27785
+ await fs55.unlink(path58.join(agentsPath, file));
27144
27786
  }
27145
27787
  }
27146
27788
  } catch (error) {
@@ -27178,6 +27820,27 @@ var init_sync_service = __esm({
27178
27820
  }
27179
27821
  return agents;
27180
27822
  }
27823
+ /**
27824
+ * Load existing agent info from disk (for incremental sync when agents don't need regeneration).
27825
+ * Reads the agents directory and returns metadata without regenerating files.
27826
+ */
27827
+ async loadExistingAgents() {
27828
+ const agentsPath = path58.join(this.globalPath, "agents");
27829
+ const agents = [];
27830
+ try {
27831
+ const files = await fs55.readdir(agentsPath);
27832
+ const workflowNames = /* @__PURE__ */ new Set(["prjct-workflow", "prjct-planner", "prjct-shipper"]);
27833
+ for (const file of files) {
27834
+ if (!file.endsWith(".md")) continue;
27835
+ const name = file.replace(".md", "");
27836
+ const type = workflowNames.has(name) ? "workflow" : "domain";
27837
+ agents.push({ name, type });
27838
+ }
27839
+ } catch {
27840
+ return [];
27841
+ }
27842
+ return agents;
27843
+ }
27181
27844
  /**
27182
27845
  * Resolve {{> partial-name }} includes in template content.
27183
27846
  * Loads partials from templates/subagents/.
@@ -27189,7 +27852,7 @@ var init_sync_service = __esm({
27189
27852
  let resolved = content;
27190
27853
  for (const match of matches) {
27191
27854
  const partialName = match[1];
27192
- const partialPath = path57.join(
27855
+ const partialPath = path58.join(
27193
27856
  __dirname,
27194
27857
  "..",
27195
27858
  "..",
@@ -27198,7 +27861,7 @@ var init_sync_service = __esm({
27198
27861
  `${partialName}.md`
27199
27862
  );
27200
27863
  try {
27201
- const partialContent = await fs54.readFile(partialPath, "utf-8");
27864
+ const partialContent = await fs55.readFile(partialPath, "utf-8");
27202
27865
  resolved = resolved.replace(match[0], partialContent.trim());
27203
27866
  } catch {
27204
27867
  resolved = resolved.replace(match[0], `<!-- partial "${partialName}" not found -->`);
@@ -27209,7 +27872,7 @@ var init_sync_service = __esm({
27209
27872
  async generateWorkflowAgent(name, agentsPath) {
27210
27873
  let content = "";
27211
27874
  try {
27212
- const templatePath = path57.join(
27875
+ const templatePath = path58.join(
27213
27876
  __dirname,
27214
27877
  "..",
27215
27878
  "..",
@@ -27218,7 +27881,7 @@ var init_sync_service = __esm({
27218
27881
  "workflow",
27219
27882
  `${name}.md`
27220
27883
  );
27221
- content = await fs54.readFile(templatePath, "utf-8");
27884
+ content = await fs55.readFile(templatePath, "utf-8");
27222
27885
  content = await this.resolveTemplateIncludes(content);
27223
27886
  } catch (error) {
27224
27887
  logger_default.debug("Workflow agent template not found, generating minimal", {
@@ -27227,12 +27890,12 @@ var init_sync_service = __esm({
27227
27890
  });
27228
27891
  content = this.generateMinimalWorkflowAgent(name);
27229
27892
  }
27230
- await fs54.writeFile(path57.join(agentsPath, `${name}.md`), content, "utf-8");
27893
+ await fs55.writeFile(path58.join(agentsPath, `${name}.md`), content, "utf-8");
27231
27894
  }
27232
27895
  async generateDomainAgent(name, agentsPath, stats, stack) {
27233
27896
  let content = "";
27234
27897
  try {
27235
- const templatePath = path57.join(
27898
+ const templatePath = path58.join(
27236
27899
  __dirname,
27237
27900
  "..",
27238
27901
  "..",
@@ -27241,7 +27904,7 @@ var init_sync_service = __esm({
27241
27904
  "domain",
27242
27905
  `${name}.md`
27243
27906
  );
27244
- content = await fs54.readFile(templatePath, "utf-8");
27907
+ content = await fs55.readFile(templatePath, "utf-8");
27245
27908
  content = await this.resolveTemplateIncludes(content);
27246
27909
  content = content.replace("{projectName}", stats.name);
27247
27910
  content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
@@ -27253,7 +27916,7 @@ var init_sync_service = __esm({
27253
27916
  });
27254
27917
  content = this.generateMinimalDomainAgent(name, stats, stack);
27255
27918
  }
27256
- await fs54.writeFile(path57.join(agentsPath, `${name}.md`), content, "utf-8");
27919
+ await fs55.writeFile(path58.join(agentsPath, `${name}.md`), content, "utf-8");
27257
27920
  }
27258
27921
  generateMinimalWorkflowAgent(name) {
27259
27922
  const descriptions = {
@@ -27321,8 +27984,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
27321
27984
  })),
27322
27985
  agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
27323
27986
  };
27324
- fs54.writeFile(
27325
- path57.join(this.globalPath, "config", "skills.json"),
27987
+ fs55.writeFile(
27988
+ path58.join(this.globalPath, "config", "skills.json"),
27326
27989
  JSON.stringify(skillsConfig, null, 2),
27327
27990
  "utf-8"
27328
27991
  ).catch((error) => {
@@ -27340,7 +28003,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
27340
28003
  async autoInstallSkills(agents) {
27341
28004
  const results = [];
27342
28005
  try {
27343
- const mappingsPath = path57.join(
28006
+ const mappingsPath = path58.join(
27344
28007
  __dirname,
27345
28008
  "..",
27346
28009
  "..",
@@ -27348,7 +28011,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
27348
28011
  "config",
27349
28012
  "skill-mappings.json"
27350
28013
  );
27351
- const mappingsContent = await fs54.readFile(mappingsPath, "utf-8");
28014
+ const mappingsContent = await fs55.readFile(mappingsPath, "utf-8");
27352
28015
  const mappings = JSON.parse(mappingsContent);
27353
28016
  const agentToSkillMap = mappings.agentToSkillMap || {};
27354
28017
  const packagesToInstall = [];
@@ -27361,18 +28024,18 @@ You are the ${name} expert for this project. Apply best practices for the detect
27361
28024
  }
27362
28025
  }
27363
28026
  if (packagesToInstall.length === 0) return results;
27364
- const skillsDir = path57.join(os16.homedir(), ".claude", "skills");
28027
+ const skillsDir = path58.join(os16.homedir(), ".claude", "skills");
27365
28028
  for (const { pkg, agent } of packagesToInstall) {
27366
28029
  const skillName = pkg.split("/").pop() || pkg;
27367
- const subdirPath = path57.join(skillsDir, skillName, "SKILL.md");
27368
- const flatPath = path57.join(skillsDir, `${skillName}.md`);
28030
+ const subdirPath = path58.join(skillsDir, skillName, "SKILL.md");
28031
+ const flatPath = path58.join(skillsDir, `${skillName}.md`);
27369
28032
  let alreadyInstalled = false;
27370
28033
  try {
27371
- await fs54.access(subdirPath);
28034
+ await fs55.access(subdirPath);
27372
28035
  alreadyInstalled = true;
27373
28036
  } catch {
27374
28037
  try {
27375
- await fs54.access(flatPath);
28038
+ await fs55.access(flatPath);
27376
28039
  alreadyInstalled = true;
27377
28040
  } catch {
27378
28041
  }
@@ -27424,10 +28087,10 @@ You are the ${name} expert for this project. Apply best practices for the detect
27424
28087
  // PROJECT.JSON UPDATE
27425
28088
  // ==========================================================================
27426
28089
  async updateProjectJson(git, stats) {
27427
- const projectJsonPath = path57.join(this.globalPath, "project.json");
28090
+ const projectJsonPath = path58.join(this.globalPath, "project.json");
27428
28091
  let existing = {};
27429
28092
  try {
27430
- existing = JSON.parse(await fs54.readFile(projectJsonPath, "utf-8"));
28093
+ existing = JSON.parse(await fs55.readFile(projectJsonPath, "utf-8"));
27431
28094
  } catch (error) {
27432
28095
  logger_default.debug("No existing project.json", {
27433
28096
  path: projectJsonPath,
@@ -27453,16 +28116,16 @@ You are the ${name} expert for this project. Apply best practices for the detect
27453
28116
  lastSyncCommit: git.recentCommits[0]?.hash || null,
27454
28117
  lastSyncBranch: git.branch
27455
28118
  };
27456
- await fs54.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
28119
+ await fs55.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
27457
28120
  }
27458
28121
  // ==========================================================================
27459
28122
  // STATE.JSON UPDATE
27460
28123
  // ==========================================================================
27461
28124
  async updateStateJson(stats, stack) {
27462
- const statePath = path57.join(this.globalPath, "storage", "state.json");
28125
+ const statePath = path58.join(this.globalPath, "storage", "state.json");
27463
28126
  let state = {};
27464
28127
  try {
27465
- state = JSON.parse(await fs54.readFile(statePath, "utf-8"));
28128
+ state = JSON.parse(await fs55.readFile(statePath, "utf-8"));
27466
28129
  } catch (error) {
27467
28130
  logger_default.debug("No existing state.json", { path: statePath, error: getErrorMessage(error) });
27468
28131
  }
@@ -27490,7 +28153,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
27490
28153
  lastAction: "Synced project",
27491
28154
  nextAction: 'Run `p. task "description"` to start working'
27492
28155
  };
27493
- await fs54.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
28156
+ await fs55.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
27494
28157
  try {
27495
28158
  await localStateGenerator.generate(
27496
28159
  this.projectPath,
@@ -27504,7 +28167,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
27504
28167
  // MEMORY LOGGING
27505
28168
  // ==========================================================================
27506
28169
  async logToMemory(git, stats) {
27507
- const memoryPath = path57.join(this.globalPath, "memory", "events.jsonl");
28170
+ const memoryPath = path58.join(this.globalPath, "memory", "events.jsonl");
27508
28171
  const event = {
27509
28172
  ts: getTimestamp(),
27510
28173
  action: "sync",
@@ -27513,7 +28176,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
27513
28176
  fileCount: stats.fileCount,
27514
28177
  commitCount: git.commits
27515
28178
  };
27516
- await fs54.appendFile(memoryPath, `${JSON.stringify(event)}
28179
+ await fs55.appendFile(memoryPath, `${JSON.stringify(event)}
27517
28180
  `, "utf-8");
27518
28181
  }
27519
28182
  // ==========================================================================
@@ -27533,8 +28196,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
27533
28196
  let filteredChars = 0;
27534
28197
  for (const file of contextFiles) {
27535
28198
  try {
27536
- const filePath = path57.join(this.globalPath, file);
27537
- const content = await fs54.readFile(filePath, "utf-8");
28199
+ const filePath = path58.join(this.globalPath, file);
28200
+ const content = await fs55.readFile(filePath, "utf-8");
27538
28201
  filteredChars += content.length;
27539
28202
  } catch (error) {
27540
28203
  logger_default.debug("Context file not found for metrics", { file, error: getErrorMessage(error) });
@@ -27542,8 +28205,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
27542
28205
  }
27543
28206
  for (const agent of agents) {
27544
28207
  try {
27545
- const agentPath = path57.join(this.globalPath, "agents", `${agent.name}.md`);
27546
- const content = await fs54.readFile(agentPath, "utf-8");
28208
+ const agentPath = path58.join(this.globalPath, "agents", `${agent.name}.md`);
28209
+ const content = await fs55.readFile(agentPath, "utf-8");
27547
28210
  filteredChars += content.length;
27548
28211
  } catch (error) {
27549
28212
  logger_default.debug("Agent file not found for metrics", {
@@ -27601,11 +28264,45 @@ You are the ${name} expert for this project. Apply best practices for the detect
27601
28264
  }
27602
28265
  }
27603
28266
  // ==========================================================================
28267
+ // ARCHIVAL (PRJ-267)
28268
+ // ==========================================================================
28269
+ /**
28270
+ * Archive stale data across all storage types.
28271
+ * Runs during sync to keep active storage lean.
28272
+ */
28273
+ async archiveStaleData() {
28274
+ if (!this.projectId) return;
28275
+ try {
28276
+ const [shipped, dormant, staleQueue, stalePaused, memoryCapped] = await Promise.all([
28277
+ shippedStorage.archiveOldShipped(this.projectId).catch(() => 0),
28278
+ ideasStorage.markDormantIdeas(this.projectId).catch(() => 0),
28279
+ queueStorage.removeStaleCompleted(this.projectId).catch(() => 0),
28280
+ stateStorage.archiveStalePausedTasks(this.projectId).catch(() => []),
28281
+ memoryService.capEntries(this.projectId).catch(() => 0)
28282
+ ]);
28283
+ const totalArchived = shipped + dormant + staleQueue + stalePaused.length + memoryCapped;
28284
+ if (totalArchived > 0) {
28285
+ logger_default.info("Archived stale data", {
28286
+ shipped,
28287
+ dormant,
28288
+ staleQueue,
28289
+ stalePaused: stalePaused.length,
28290
+ memoryCapped,
28291
+ total: totalArchived
28292
+ });
28293
+ const stats = archiveStorage.getStats(this.projectId);
28294
+ logger_default.debug("Archive stats", stats);
28295
+ }
28296
+ } catch (error) {
28297
+ logger_default.debug("Archival failed (non-critical)", { error: getErrorMessage(error) });
28298
+ }
28299
+ }
28300
+ // ==========================================================================
27604
28301
  // HELPERS
27605
28302
  // ==========================================================================
27606
28303
  async fileExists(filename) {
27607
28304
  try {
27608
- await fs54.access(path57.join(this.projectPath, filename));
28305
+ await fs55.access(path58.join(this.projectPath, filename));
27609
28306
  return true;
27610
28307
  } catch (error) {
27611
28308
  logger_default.debug("File not found", { filename, error: getErrorMessage(error) });
@@ -27614,8 +28311,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
27614
28311
  }
27615
28312
  async getCliVersion() {
27616
28313
  try {
27617
- const pkgPath = path57.join(__dirname, "..", "..", "package.json");
27618
- const pkg = JSON.parse(await fs54.readFile(pkgPath, "utf-8"));
28314
+ const pkgPath = path58.join(__dirname, "..", "..", "package.json");
28315
+ const pkg = JSON.parse(await fs55.readFile(pkgPath, "utf-8"));
27619
28316
  return pkg.version || "0.0.0";
27620
28317
  } catch (error) {
27621
28318
  logger_default.debug("Failed to read CLI version", { error: getErrorMessage(error) });
@@ -27776,22 +28473,22 @@ __export(uninstall_exports, {
27776
28473
  uninstall: () => uninstall
27777
28474
  });
27778
28475
  import { execSync as execSync3 } from "node:child_process";
27779
- import fs55 from "node:fs/promises";
28476
+ import fs56 from "node:fs/promises";
27780
28477
  import os17 from "node:os";
27781
- import path58 from "node:path";
28478
+ import path59 from "node:path";
27782
28479
  import readline2 from "node:readline";
27783
28480
  import chalk12 from "chalk";
27784
28481
  async function getDirectorySize(dirPath) {
27785
28482
  let totalSize = 0;
27786
28483
  try {
27787
- const entries = await fs55.readdir(dirPath, { withFileTypes: true });
28484
+ const entries = await fs56.readdir(dirPath, { withFileTypes: true });
27788
28485
  for (const entry of entries) {
27789
- const entryPath = path58.join(dirPath, entry.name);
28486
+ const entryPath = path59.join(dirPath, entry.name);
27790
28487
  if (entry.isDirectory()) {
27791
28488
  totalSize += await getDirectorySize(entryPath);
27792
28489
  } else {
27793
28490
  try {
27794
- const stats = await fs55.stat(entryPath);
28491
+ const stats = await fs56.stat(entryPath);
27795
28492
  totalSize += stats.size;
27796
28493
  } catch {
27797
28494
  }
@@ -27810,7 +28507,7 @@ function formatSize(bytes) {
27810
28507
  }
27811
28508
  async function countDirectoryItems(dirPath) {
27812
28509
  try {
27813
- const entries = await fs55.readdir(dirPath, { withFileTypes: true });
28510
+ const entries = await fs56.readdir(dirPath, { withFileTypes: true });
27814
28511
  return entries.filter((e) => e.isDirectory()).length;
27815
28512
  } catch {
27816
28513
  return 0;
@@ -27843,7 +28540,7 @@ async function gatherUninstallItems() {
27843
28540
  const providerPaths = getProviderPaths();
27844
28541
  const prjctCliPath = path_manager_default.getGlobalBasePath();
27845
28542
  const prjctCliExists = await fileExists(prjctCliPath);
27846
- const projectCount = prjctCliExists ? await countDirectoryItems(path58.join(prjctCliPath, "projects")) : 0;
28543
+ const projectCount = prjctCliExists ? await countDirectoryItems(path59.join(prjctCliPath, "projects")) : 0;
27847
28544
  const prjctCliSize = prjctCliExists ? await getDirectorySize(prjctCliPath) : 0;
27848
28545
  items.push({
27849
28546
  path: prjctCliPath,
@@ -27853,12 +28550,12 @@ async function gatherUninstallItems() {
27853
28550
  count: projectCount,
27854
28551
  exists: prjctCliExists
27855
28552
  });
27856
- const claudeMdPath = path58.join(providerPaths.claude.config, "CLAUDE.md");
28553
+ const claudeMdPath = path59.join(providerPaths.claude.config, "CLAUDE.md");
27857
28554
  const claudeMdExists = await fileExists(claudeMdPath);
27858
28555
  let hasPrjctSection = false;
27859
28556
  if (claudeMdExists) {
27860
28557
  try {
27861
- const content = await fs55.readFile(claudeMdPath, "utf-8");
28558
+ const content = await fs56.readFile(claudeMdPath, "utf-8");
27862
28559
  hasPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
27863
28560
  } catch {
27864
28561
  }
@@ -27887,7 +28584,7 @@ async function gatherUninstallItems() {
27887
28584
  description: "Claude router",
27888
28585
  exists: claudeRouterExists
27889
28586
  });
27890
- const statusLinePath = path58.join(providerPaths.claude.config, "prjct-statusline.sh");
28587
+ const statusLinePath = path59.join(providerPaths.claude.config, "prjct-statusline.sh");
27891
28588
  const statusLineExists = await fileExists(statusLinePath);
27892
28589
  items.push({
27893
28590
  path: statusLinePath,
@@ -27903,12 +28600,12 @@ async function gatherUninstallItems() {
27903
28600
  description: "Gemini router",
27904
28601
  exists: geminiRouterExists
27905
28602
  });
27906
- const geminiMdPath = path58.join(providerPaths.gemini.config, "GEMINI.md");
28603
+ const geminiMdPath = path59.join(providerPaths.gemini.config, "GEMINI.md");
27907
28604
  const geminiMdExists = await fileExists(geminiMdPath);
27908
28605
  let hasGeminiPrjctSection = false;
27909
28606
  if (geminiMdExists) {
27910
28607
  try {
27911
- const content = await fs55.readFile(geminiMdPath, "utf-8");
28608
+ const content = await fs56.readFile(geminiMdPath, "utf-8");
27912
28609
  hasGeminiPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
27913
28610
  } catch {
27914
28611
  }
@@ -27925,7 +28622,7 @@ async function gatherUninstallItems() {
27925
28622
  }
27926
28623
  async function removePrjctSection(filePath) {
27927
28624
  try {
27928
- const content = await fs55.readFile(filePath, "utf-8");
28625
+ const content = await fs56.readFile(filePath, "utf-8");
27929
28626
  if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
27930
28627
  return false;
27931
28628
  }
@@ -27934,9 +28631,9 @@ async function removePrjctSection(filePath) {
27934
28631
  let newContent = content.substring(0, startIndex) + content.substring(endIndex);
27935
28632
  newContent = newContent.replace(/\n{3,}/g, "\n\n").trim();
27936
28633
  if (!newContent || newContent.trim().length === 0) {
27937
- await fs55.unlink(filePath);
28634
+ await fs56.unlink(filePath);
27938
28635
  } else {
27939
- await fs55.writeFile(filePath, `${newContent}
28636
+ await fs56.writeFile(filePath, `${newContent}
27940
28637
  `, "utf-8");
27941
28638
  }
27942
28639
  return true;
@@ -27947,12 +28644,12 @@ async function removePrjctSection(filePath) {
27947
28644
  async function createBackup3() {
27948
28645
  const homeDir = os17.homedir();
27949
28646
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
27950
- const backupDir = path58.join(homeDir, `.prjct-backup-${timestamp}`);
28647
+ const backupDir = path59.join(homeDir, `.prjct-backup-${timestamp}`);
27951
28648
  try {
27952
- await fs55.mkdir(backupDir, { recursive: true });
28649
+ await fs56.mkdir(backupDir, { recursive: true });
27953
28650
  const prjctCliPath = path_manager_default.getGlobalBasePath();
27954
28651
  if (await fileExists(prjctCliPath)) {
27955
- await copyDirectory(prjctCliPath, path58.join(backupDir, ".prjct-cli"));
28652
+ await copyDirectory(prjctCliPath, path59.join(backupDir, ".prjct-cli"));
27956
28653
  }
27957
28654
  return backupDir;
27958
28655
  } catch {
@@ -27960,15 +28657,15 @@ async function createBackup3() {
27960
28657
  }
27961
28658
  }
27962
28659
  async function copyDirectory(src, dest) {
27963
- await fs55.mkdir(dest, { recursive: true });
27964
- const entries = await fs55.readdir(src, { withFileTypes: true });
28660
+ await fs56.mkdir(dest, { recursive: true });
28661
+ const entries = await fs56.readdir(src, { withFileTypes: true });
27965
28662
  for (const entry of entries) {
27966
- const srcPath = path58.join(src, entry.name);
27967
- const destPath = path58.join(dest, entry.name);
28663
+ const srcPath = path59.join(src, entry.name);
28664
+ const destPath = path59.join(dest, entry.name);
27968
28665
  if (entry.isDirectory()) {
27969
28666
  await copyDirectory(srcPath, destPath);
27970
28667
  } else {
27971
- await fs55.copyFile(srcPath, destPath);
28668
+ await fs56.copyFile(srcPath, destPath);
27972
28669
  }
27973
28670
  }
27974
28671
  }
@@ -27984,10 +28681,10 @@ async function performUninstall(items, installation, options) {
27984
28681
  deleted.push(item.path);
27985
28682
  }
27986
28683
  } else if (item.type === "directory") {
27987
- await fs55.rm(item.path, { recursive: true, force: true });
28684
+ await fs56.rm(item.path, { recursive: true, force: true });
27988
28685
  deleted.push(item.path);
27989
28686
  } else if (item.type === "file") {
27990
- await fs55.unlink(item.path);
28687
+ await fs56.unlink(item.path);
27991
28688
  deleted.push(item.path);
27992
28689
  }
27993
28690
  } catch (error) {
@@ -28164,7 +28861,7 @@ __export(watch_service_exports, {
28164
28861
  WatchService: () => WatchService,
28165
28862
  watchService: () => watchService
28166
28863
  });
28167
- import path59 from "node:path";
28864
+ import path60 from "node:path";
28168
28865
  import chalk13 from "chalk";
28169
28866
  import chokidar from "chokidar";
28170
28867
  var TRIGGER_PATTERNS, IGNORE_PATTERNS2, WatchService, watchService;
@@ -28353,7 +29050,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
28353
29050
  );
28354
29051
  }
28355
29052
  try {
28356
- const result = await syncService.sync(this.projectPath);
29053
+ const result = await syncService.sync(this.projectPath, { changedFiles });
28357
29054
  this.lastSyncTime = Date.now();
28358
29055
  this.syncCount++;
28359
29056
  if (result.success) {
@@ -28385,7 +29082,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
28385
29082
  printStartup() {
28386
29083
  console.log("");
28387
29084
  console.log(chalk13.cyan("\u{1F441}\uFE0F Watching for changes..."));
28388
- console.log(chalk13.dim(` Project: ${path59.basename(this.projectPath)}`));
29085
+ console.log(chalk13.dim(` Project: ${path60.basename(this.projectPath)}`));
28389
29086
  console.log(chalk13.dim(` Debounce: ${this.options.debounceMs}ms`));
28390
29087
  console.log(chalk13.dim(` Min interval: ${this.options.minIntervalMs / 1e3}s`));
28391
29088
  console.log("");
@@ -28558,11 +29255,13 @@ var init_command_data = __esm({
28558
29255
  name: "sync",
28559
29256
  group: "core",
28560
29257
  description: "Sync project state and update workflow agents",
28561
- usage: { claude: "/p:sync", terminal: "prjct sync [--package=<name>]" },
29258
+ usage: { claude: "/p:sync", terminal: "prjct sync [--package=<name>] [--full]" },
28562
29259
  implemented: true,
28563
29260
  hasTemplate: true,
28564
29261
  requiresProject: true,
28565
29262
  features: [
29263
+ "Incremental sync: only re-analyzes changed files (default)",
29264
+ "Force full sync: --full bypasses incremental cache",
28566
29265
  "Monorepo support: --package=<name> for single package sync",
28567
29266
  "Nested PRJCT.md inheritance",
28568
29267
  "Per-package CLAUDE.md generation"
@@ -29116,9 +29815,9 @@ __export(setup_exports, {
29116
29815
  run: () => run
29117
29816
  });
29118
29817
  import { execSync as execSync4 } from "node:child_process";
29119
- import fs56 from "node:fs/promises";
29818
+ import fs57 from "node:fs/promises";
29120
29819
  import os18 from "node:os";
29121
- import path60 from "node:path";
29820
+ import path61 from "node:path";
29122
29821
  import chalk15 from "chalk";
29123
29822
  async function installAICLI(provider) {
29124
29823
  const packageName = provider.name === "claude" ? "@anthropic-ai/claude-code" : "@google/gemini-cli";
@@ -29257,12 +29956,12 @@ async function run() {
29257
29956
  }
29258
29957
  async function installGeminiRouter() {
29259
29958
  try {
29260
- const geminiCommandsDir = path60.join(os18.homedir(), ".gemini", "commands");
29261
- const routerSource = path60.join(PACKAGE_ROOT, "templates", "commands", "p.toml");
29262
- const routerDest = path60.join(geminiCommandsDir, "p.toml");
29263
- await fs56.mkdir(geminiCommandsDir, { recursive: true });
29959
+ const geminiCommandsDir = path61.join(os18.homedir(), ".gemini", "commands");
29960
+ const routerSource = path61.join(PACKAGE_ROOT, "templates", "commands", "p.toml");
29961
+ const routerDest = path61.join(geminiCommandsDir, "p.toml");
29962
+ await fs57.mkdir(geminiCommandsDir, { recursive: true });
29264
29963
  if (await fileExists(routerSource)) {
29265
- await fs56.copyFile(routerSource, routerDest);
29964
+ await fs57.copyFile(routerSource, routerDest);
29266
29965
  return true;
29267
29966
  }
29268
29967
  return false;
@@ -29273,15 +29972,15 @@ async function installGeminiRouter() {
29273
29972
  }
29274
29973
  async function installGeminiGlobalConfig() {
29275
29974
  try {
29276
- const geminiDir = path60.join(os18.homedir(), ".gemini");
29277
- const globalConfigPath = path60.join(geminiDir, "GEMINI.md");
29278
- const templatePath = path60.join(PACKAGE_ROOT, "templates", "global", "GEMINI.md");
29279
- await fs56.mkdir(geminiDir, { recursive: true });
29280
- const templateContent = await fs56.readFile(templatePath, "utf-8");
29975
+ const geminiDir = path61.join(os18.homedir(), ".gemini");
29976
+ const globalConfigPath = path61.join(geminiDir, "GEMINI.md");
29977
+ const templatePath = path61.join(PACKAGE_ROOT, "templates", "global", "GEMINI.md");
29978
+ await fs57.mkdir(geminiDir, { recursive: true });
29979
+ const templateContent = await fs57.readFile(templatePath, "utf-8");
29281
29980
  let existingContent = "";
29282
29981
  let configExists = false;
29283
29982
  try {
29284
- existingContent = await fs56.readFile(globalConfigPath, "utf-8");
29983
+ existingContent = await fs57.readFile(globalConfigPath, "utf-8");
29285
29984
  configExists = true;
29286
29985
  } catch (error) {
29287
29986
  if (isNotFoundError(error)) {
@@ -29291,7 +29990,7 @@ async function installGeminiGlobalConfig() {
29291
29990
  }
29292
29991
  }
29293
29992
  if (!configExists) {
29294
- await fs56.writeFile(globalConfigPath, templateContent, "utf-8");
29993
+ await fs57.writeFile(globalConfigPath, templateContent, "utf-8");
29295
29994
  return { success: true, action: "created" };
29296
29995
  }
29297
29996
  const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
@@ -29301,7 +30000,7 @@ async function installGeminiGlobalConfig() {
29301
30000
  const updatedContent2 = `${existingContent}
29302
30001
 
29303
30002
  ${templateContent}`;
29304
- await fs56.writeFile(globalConfigPath, updatedContent2, "utf-8");
30003
+ await fs57.writeFile(globalConfigPath, updatedContent2, "utf-8");
29305
30004
  return { success: true, action: "appended" };
29306
30005
  }
29307
30006
  const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
@@ -29313,7 +30012,7 @@ ${templateContent}`;
29313
30012
  templateContent.indexOf(endMarker) + endMarker.length
29314
30013
  );
29315
30014
  const updatedContent = beforeMarker + prjctSection + afterMarker;
29316
- await fs56.writeFile(globalConfigPath, updatedContent, "utf-8");
30015
+ await fs57.writeFile(globalConfigPath, updatedContent, "utf-8");
29317
30016
  return { success: true, action: "updated" };
29318
30017
  } catch (error) {
29319
30018
  logger_default.warn(`Gemini config warning: ${getErrorMessage2(error)}`);
@@ -29322,18 +30021,18 @@ ${templateContent}`;
29322
30021
  }
29323
30022
  async function installAntigravitySkill() {
29324
30023
  try {
29325
- const antigravitySkillsDir = path60.join(os18.homedir(), ".gemini", "antigravity", "skills");
29326
- const prjctSkillDir = path60.join(antigravitySkillsDir, "prjct");
29327
- const skillMdPath = path60.join(prjctSkillDir, "SKILL.md");
29328
- const templatePath = path60.join(PACKAGE_ROOT, "templates", "antigravity", "SKILL.md");
29329
- await fs56.mkdir(prjctSkillDir, { recursive: true });
30024
+ const antigravitySkillsDir = path61.join(os18.homedir(), ".gemini", "antigravity", "skills");
30025
+ const prjctSkillDir = path61.join(antigravitySkillsDir, "prjct");
30026
+ const skillMdPath = path61.join(prjctSkillDir, "SKILL.md");
30027
+ const templatePath = path61.join(PACKAGE_ROOT, "templates", "antigravity", "SKILL.md");
30028
+ await fs57.mkdir(prjctSkillDir, { recursive: true });
29330
30029
  const skillExists = await fileExists(skillMdPath);
29331
30030
  if (!await fileExists(templatePath)) {
29332
30031
  logger_default.warn("Antigravity SKILL.md template not found");
29333
30032
  return { success: false, action: null };
29334
30033
  }
29335
- const templateContent = await fs56.readFile(templatePath, "utf-8");
29336
- await fs56.writeFile(skillMdPath, templateContent, "utf-8");
30034
+ const templateContent = await fs57.readFile(templatePath, "utf-8");
30035
+ await fs57.writeFile(skillMdPath, templateContent, "utf-8");
29337
30036
  return { success: true, action: skillExists ? "updated" : "created" };
29338
30037
  } catch (error) {
29339
30038
  logger_default.warn(`Antigravity skill warning: ${getErrorMessage2(error)}`);
@@ -29352,24 +30051,24 @@ async function installCursorProject(projectRoot) {
29352
30051
  gitignoreUpdated: false
29353
30052
  };
29354
30053
  try {
29355
- const cursorDir = path60.join(projectRoot, ".cursor");
29356
- const rulesDir = path60.join(cursorDir, "rules");
29357
- const commandsDir = path60.join(cursorDir, "commands");
29358
- const routerMdcDest = path60.join(rulesDir, "prjct.mdc");
29359
- const routerMdcSource = path60.join(PACKAGE_ROOT, "templates", "cursor", "router.mdc");
29360
- const cursorCommandsSource = path60.join(PACKAGE_ROOT, "templates", "cursor", "commands");
29361
- await fs56.mkdir(rulesDir, { recursive: true });
29362
- await fs56.mkdir(commandsDir, { recursive: true });
30054
+ const cursorDir = path61.join(projectRoot, ".cursor");
30055
+ const rulesDir = path61.join(cursorDir, "rules");
30056
+ const commandsDir = path61.join(cursorDir, "commands");
30057
+ const routerMdcDest = path61.join(rulesDir, "prjct.mdc");
30058
+ const routerMdcSource = path61.join(PACKAGE_ROOT, "templates", "cursor", "router.mdc");
30059
+ const cursorCommandsSource = path61.join(PACKAGE_ROOT, "templates", "cursor", "commands");
30060
+ await fs57.mkdir(rulesDir, { recursive: true });
30061
+ await fs57.mkdir(commandsDir, { recursive: true });
29363
30062
  if (await fileExists(routerMdcSource)) {
29364
- await fs56.copyFile(routerMdcSource, routerMdcDest);
30063
+ await fs57.copyFile(routerMdcSource, routerMdcDest);
29365
30064
  result.rulesCreated = true;
29366
30065
  }
29367
30066
  if (await fileExists(cursorCommandsSource)) {
29368
- const commandFiles = (await fs56.readdir(cursorCommandsSource)).filter((f) => f.endsWith(".md"));
30067
+ const commandFiles = (await fs57.readdir(cursorCommandsSource)).filter((f) => f.endsWith(".md"));
29369
30068
  for (const file of commandFiles) {
29370
- const src = path60.join(cursorCommandsSource, file);
29371
- const dest = path60.join(commandsDir, file);
29372
- await fs56.copyFile(src, dest);
30069
+ const src = path61.join(cursorCommandsSource, file);
30070
+ const dest = path61.join(commandsDir, file);
30071
+ await fs57.copyFile(src, dest);
29373
30072
  }
29374
30073
  result.commandsCreated = commandFiles.length > 0;
29375
30074
  }
@@ -29383,7 +30082,7 @@ async function installCursorProject(projectRoot) {
29383
30082
  }
29384
30083
  async function addCursorToGitignore(projectRoot) {
29385
30084
  try {
29386
- const gitignorePath = path60.join(projectRoot, ".gitignore");
30085
+ const gitignorePath = path61.join(projectRoot, ".gitignore");
29387
30086
  const entriesToAdd = [
29388
30087
  "# prjct Cursor routers (regenerated per-developer)",
29389
30088
  ".cursor/rules/prjct.mdc",
@@ -29398,7 +30097,7 @@ async function addCursorToGitignore(projectRoot) {
29398
30097
  let content = "";
29399
30098
  let configExists = false;
29400
30099
  try {
29401
- content = await fs56.readFile(gitignorePath, "utf-8");
30100
+ content = await fs57.readFile(gitignorePath, "utf-8");
29402
30101
  configExists = true;
29403
30102
  } catch (error) {
29404
30103
  if (!isNotFoundError(error)) {
@@ -29413,7 +30112,7 @@ async function addCursorToGitignore(projectRoot) {
29413
30112
  ${entriesToAdd.join("\n")}
29414
30113
  ` : `${entriesToAdd.join("\n")}
29415
30114
  `;
29416
- await fs56.writeFile(gitignorePath, newContent, "utf-8");
30115
+ await fs57.writeFile(gitignorePath, newContent, "utf-8");
29417
30116
  return true;
29418
30117
  } catch (error) {
29419
30118
  logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
@@ -29421,11 +30120,11 @@ ${entriesToAdd.join("\n")}
29421
30120
  }
29422
30121
  }
29423
30122
  async function hasCursorProject(projectRoot) {
29424
- return await fileExists(path60.join(projectRoot, ".cursor"));
30123
+ return await fileExists(path61.join(projectRoot, ".cursor"));
29425
30124
  }
29426
30125
  async function needsCursorRegeneration(projectRoot) {
29427
- const cursorDir = path60.join(projectRoot, ".cursor");
29428
- const routerPath = path60.join(cursorDir, "rules", "prjct.mdc");
30126
+ const cursorDir = path61.join(projectRoot, ".cursor");
30127
+ const routerPath = path61.join(cursorDir, "rules", "prjct.mdc");
29429
30128
  return await fileExists(cursorDir) && !await fileExists(routerPath);
29430
30129
  }
29431
30130
  async function installWindsurfProject(projectRoot) {
@@ -29436,26 +30135,26 @@ async function installWindsurfProject(projectRoot) {
29436
30135
  gitignoreUpdated: false
29437
30136
  };
29438
30137
  try {
29439
- const windsurfDir = path60.join(projectRoot, ".windsurf");
29440
- const rulesDir = path60.join(windsurfDir, "rules");
29441
- const workflowsDir = path60.join(windsurfDir, "workflows");
29442
- const routerDest = path60.join(rulesDir, "prjct.md");
29443
- const routerSource = path60.join(PACKAGE_ROOT, "templates", "windsurf", "router.md");
29444
- const windsurfWorkflowsSource = path60.join(PACKAGE_ROOT, "templates", "windsurf", "workflows");
29445
- await fs56.mkdir(rulesDir, { recursive: true });
29446
- await fs56.mkdir(workflowsDir, { recursive: true });
30138
+ const windsurfDir = path61.join(projectRoot, ".windsurf");
30139
+ const rulesDir = path61.join(windsurfDir, "rules");
30140
+ const workflowsDir = path61.join(windsurfDir, "workflows");
30141
+ const routerDest = path61.join(rulesDir, "prjct.md");
30142
+ const routerSource = path61.join(PACKAGE_ROOT, "templates", "windsurf", "router.md");
30143
+ const windsurfWorkflowsSource = path61.join(PACKAGE_ROOT, "templates", "windsurf", "workflows");
30144
+ await fs57.mkdir(rulesDir, { recursive: true });
30145
+ await fs57.mkdir(workflowsDir, { recursive: true });
29447
30146
  if (await fileExists(routerSource)) {
29448
- await fs56.copyFile(routerSource, routerDest);
30147
+ await fs57.copyFile(routerSource, routerDest);
29449
30148
  result.rulesCreated = true;
29450
30149
  }
29451
30150
  if (await fileExists(windsurfWorkflowsSource)) {
29452
- const workflowFiles = (await fs56.readdir(windsurfWorkflowsSource)).filter(
30151
+ const workflowFiles = (await fs57.readdir(windsurfWorkflowsSource)).filter(
29453
30152
  (f) => f.endsWith(".md")
29454
30153
  );
29455
30154
  for (const file of workflowFiles) {
29456
- const src = path60.join(windsurfWorkflowsSource, file);
29457
- const dest = path60.join(workflowsDir, file);
29458
- await fs56.copyFile(src, dest);
30155
+ const src = path61.join(windsurfWorkflowsSource, file);
30156
+ const dest = path61.join(workflowsDir, file);
30157
+ await fs57.copyFile(src, dest);
29459
30158
  }
29460
30159
  result.workflowsCreated = workflowFiles.length > 0;
29461
30160
  }
@@ -29469,7 +30168,7 @@ async function installWindsurfProject(projectRoot) {
29469
30168
  }
29470
30169
  async function addWindsurfToGitignore(projectRoot) {
29471
30170
  try {
29472
- const gitignorePath = path60.join(projectRoot, ".gitignore");
30171
+ const gitignorePath = path61.join(projectRoot, ".gitignore");
29473
30172
  const entriesToAdd = [
29474
30173
  "# prjct Windsurf routers (regenerated per-developer)",
29475
30174
  ".windsurf/rules/prjct.md",
@@ -29484,7 +30183,7 @@ async function addWindsurfToGitignore(projectRoot) {
29484
30183
  let content = "";
29485
30184
  let configExists = false;
29486
30185
  try {
29487
- content = await fs56.readFile(gitignorePath, "utf-8");
30186
+ content = await fs57.readFile(gitignorePath, "utf-8");
29488
30187
  configExists = true;
29489
30188
  } catch (error) {
29490
30189
  if (!isNotFoundError(error)) {
@@ -29499,7 +30198,7 @@ async function addWindsurfToGitignore(projectRoot) {
29499
30198
  ${entriesToAdd.join("\n")}
29500
30199
  ` : `${entriesToAdd.join("\n")}
29501
30200
  `;
29502
- await fs56.writeFile(gitignorePath, newContent, "utf-8");
30201
+ await fs57.writeFile(gitignorePath, newContent, "utf-8");
29503
30202
  return true;
29504
30203
  } catch (error) {
29505
30204
  logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
@@ -29507,32 +30206,32 @@ ${entriesToAdd.join("\n")}
29507
30206
  }
29508
30207
  }
29509
30208
  async function hasWindsurfProject(projectRoot) {
29510
- return await fileExists(path60.join(projectRoot, ".windsurf"));
30209
+ return await fileExists(path61.join(projectRoot, ".windsurf"));
29511
30210
  }
29512
30211
  async function needsWindsurfRegeneration(projectRoot) {
29513
- const windsurfDir = path60.join(projectRoot, ".windsurf");
29514
- const routerPath = path60.join(windsurfDir, "rules", "prjct.md");
30212
+ const windsurfDir = path61.join(projectRoot, ".windsurf");
30213
+ const routerPath = path61.join(windsurfDir, "rules", "prjct.md");
29515
30214
  return await fileExists(windsurfDir) && !await fileExists(routerPath);
29516
30215
  }
29517
30216
  async function migrateProjectsCliVersion() {
29518
30217
  try {
29519
- const projectsDir = path60.join(os18.homedir(), ".prjct-cli", "projects");
30218
+ const projectsDir = path61.join(os18.homedir(), ".prjct-cli", "projects");
29520
30219
  if (!await fileExists(projectsDir)) {
29521
30220
  return;
29522
30221
  }
29523
- const projectDirs = (await fs56.readdir(projectsDir, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
30222
+ const projectDirs = (await fs57.readdir(projectsDir, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
29524
30223
  let migrated = 0;
29525
30224
  for (const projectId of projectDirs) {
29526
- const projectJsonPath = path60.join(projectsDir, projectId, "project.json");
30225
+ const projectJsonPath = path61.join(projectsDir, projectId, "project.json");
29527
30226
  if (!await fileExists(projectJsonPath)) {
29528
30227
  continue;
29529
30228
  }
29530
30229
  try {
29531
- const content = await fs56.readFile(projectJsonPath, "utf8");
30230
+ const content = await fs57.readFile(projectJsonPath, "utf8");
29532
30231
  const project = JSON.parse(content);
29533
30232
  if (project.cliVersion !== VERSION) {
29534
30233
  project.cliVersion = VERSION;
29535
- await fs56.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
30234
+ await fs57.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
29536
30235
  migrated++;
29537
30236
  }
29538
30237
  } catch (error) {
@@ -29554,7 +30253,7 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
29554
30253
  let settings = {};
29555
30254
  if (await fileExists(settingsPath)) {
29556
30255
  try {
29557
- settings = JSON.parse(await fs56.readFile(settingsPath, "utf8"));
30256
+ settings = JSON.parse(await fs57.readFile(settingsPath, "utf8"));
29558
30257
  } catch (error) {
29559
30258
  if (!(error instanceof SyntaxError)) {
29560
30259
  throw error;
@@ -29562,42 +30261,42 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
29562
30261
  }
29563
30262
  }
29564
30263
  settings.statusLine = { type: "command", command: statusLinePath };
29565
- await fs56.writeFile(settingsPath, JSON.stringify(settings, null, 2));
30264
+ await fs57.writeFile(settingsPath, JSON.stringify(settings, null, 2));
29566
30265
  }
29567
30266
  async function installStatusLine() {
29568
30267
  try {
29569
- const claudeDir = path60.join(os18.homedir(), ".claude");
29570
- const settingsPath = path60.join(claudeDir, "settings.json");
29571
- const claudeStatusLinePath = path60.join(claudeDir, "prjct-statusline.sh");
29572
- const prjctStatusLineDir = path60.join(os18.homedir(), ".prjct-cli", "statusline");
29573
- const prjctStatusLinePath = path60.join(prjctStatusLineDir, "statusline.sh");
29574
- const prjctThemesDir = path60.join(prjctStatusLineDir, "themes");
29575
- const prjctLibDir = path60.join(prjctStatusLineDir, "lib");
29576
- const prjctComponentsDir = path60.join(prjctStatusLineDir, "components");
29577
- const prjctConfigPath = path60.join(prjctStatusLineDir, "config.json");
29578
- const assetsDir = path60.join(PACKAGE_ROOT, "assets", "statusline");
29579
- const sourceScript = path60.join(assetsDir, "statusline.sh");
29580
- const sourceThemeDir = path60.join(assetsDir, "themes");
29581
- const sourceLibDir = path60.join(assetsDir, "lib");
29582
- const sourceComponentsDir = path60.join(assetsDir, "components");
29583
- const sourceConfigPath = path60.join(assetsDir, "default-config.json");
30268
+ const claudeDir = path61.join(os18.homedir(), ".claude");
30269
+ const settingsPath = path61.join(claudeDir, "settings.json");
30270
+ const claudeStatusLinePath = path61.join(claudeDir, "prjct-statusline.sh");
30271
+ const prjctStatusLineDir = path61.join(os18.homedir(), ".prjct-cli", "statusline");
30272
+ const prjctStatusLinePath = path61.join(prjctStatusLineDir, "statusline.sh");
30273
+ const prjctThemesDir = path61.join(prjctStatusLineDir, "themes");
30274
+ const prjctLibDir = path61.join(prjctStatusLineDir, "lib");
30275
+ const prjctComponentsDir = path61.join(prjctStatusLineDir, "components");
30276
+ const prjctConfigPath = path61.join(prjctStatusLineDir, "config.json");
30277
+ const assetsDir = path61.join(PACKAGE_ROOT, "assets", "statusline");
30278
+ const sourceScript = path61.join(assetsDir, "statusline.sh");
30279
+ const sourceThemeDir = path61.join(assetsDir, "themes");
30280
+ const sourceLibDir = path61.join(assetsDir, "lib");
30281
+ const sourceComponentsDir = path61.join(assetsDir, "components");
30282
+ const sourceConfigPath = path61.join(assetsDir, "default-config.json");
29584
30283
  if (!await fileExists(claudeDir)) {
29585
- await fs56.mkdir(claudeDir, { recursive: true });
30284
+ await fs57.mkdir(claudeDir, { recursive: true });
29586
30285
  }
29587
30286
  if (!await fileExists(prjctStatusLineDir)) {
29588
- await fs56.mkdir(prjctStatusLineDir, { recursive: true });
30287
+ await fs57.mkdir(prjctStatusLineDir, { recursive: true });
29589
30288
  }
29590
30289
  if (!await fileExists(prjctThemesDir)) {
29591
- await fs56.mkdir(prjctThemesDir, { recursive: true });
30290
+ await fs57.mkdir(prjctThemesDir, { recursive: true });
29592
30291
  }
29593
30292
  if (!await fileExists(prjctLibDir)) {
29594
- await fs56.mkdir(prjctLibDir, { recursive: true });
30293
+ await fs57.mkdir(prjctLibDir, { recursive: true });
29595
30294
  }
29596
30295
  if (!await fileExists(prjctComponentsDir)) {
29597
- await fs56.mkdir(prjctComponentsDir, { recursive: true });
30296
+ await fs57.mkdir(prjctComponentsDir, { recursive: true });
29598
30297
  }
29599
30298
  if (await fileExists(prjctStatusLinePath)) {
29600
- const existingContent = await fs56.readFile(prjctStatusLinePath, "utf8");
30299
+ const existingContent = await fs57.readFile(prjctStatusLinePath, "utf8");
29601
30300
  if (existingContent.includes("CLI_VERSION=")) {
29602
30301
  const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
29603
30302
  if (versionMatch && versionMatch[1] !== VERSION) {
@@ -29605,7 +30304,7 @@ async function installStatusLine() {
29605
30304
  /CLI_VERSION="[^"]*"/,
29606
30305
  `CLI_VERSION="${VERSION}"`
29607
30306
  );
29608
- await fs56.writeFile(prjctStatusLinePath, updatedContent, { mode: 493 });
30307
+ await fs57.writeFile(prjctStatusLinePath, updatedContent, { mode: 493 });
29609
30308
  }
29610
30309
  await installStatusLineModules(sourceLibDir, prjctLibDir);
29611
30310
  await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
@@ -29615,21 +30314,21 @@ async function installStatusLine() {
29615
30314
  }
29616
30315
  }
29617
30316
  if (await fileExists(sourceScript)) {
29618
- let scriptContent = await fs56.readFile(sourceScript, "utf8");
30317
+ let scriptContent = await fs57.readFile(sourceScript, "utf8");
29619
30318
  scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
29620
- await fs56.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
30319
+ await fs57.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
29621
30320
  await installStatusLineModules(sourceLibDir, prjctLibDir);
29622
30321
  await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
29623
30322
  if (await fileExists(sourceThemeDir)) {
29624
- const themes = await fs56.readdir(sourceThemeDir);
30323
+ const themes = await fs57.readdir(sourceThemeDir);
29625
30324
  for (const theme of themes) {
29626
- const src = path60.join(sourceThemeDir, theme);
29627
- const dest = path60.join(prjctThemesDir, theme);
29628
- await fs56.copyFile(src, dest);
30325
+ const src = path61.join(sourceThemeDir, theme);
30326
+ const dest = path61.join(prjctThemesDir, theme);
30327
+ await fs57.copyFile(src, dest);
29629
30328
  }
29630
30329
  }
29631
30330
  if (!await fileExists(prjctConfigPath) && await fileExists(sourceConfigPath)) {
29632
- await fs56.copyFile(sourceConfigPath, prjctConfigPath);
30331
+ await fs57.copyFile(sourceConfigPath, prjctConfigPath);
29633
30332
  }
29634
30333
  } else {
29635
30334
  const scriptContent = `#!/bin/bash
@@ -29664,7 +30363,7 @@ if [ -f "$CONFIG" ]; then
29664
30363
  fi
29665
30364
  echo "prjct"
29666
30365
  `;
29667
- await fs56.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
30366
+ await fs57.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
29668
30367
  }
29669
30368
  await ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
29670
30369
  await ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
@@ -29676,10 +30375,10 @@ echo "prjct"
29676
30375
  }
29677
30376
  async function installContext7MCP() {
29678
30377
  try {
29679
- const claudeDir = path60.join(os18.homedir(), ".claude");
29680
- const mcpConfigPath = path60.join(claudeDir, "mcp.json");
30378
+ const claudeDir = path61.join(os18.homedir(), ".claude");
30379
+ const mcpConfigPath = path61.join(claudeDir, "mcp.json");
29681
30380
  if (!await fileExists(claudeDir)) {
29682
- await fs56.mkdir(claudeDir, { recursive: true });
30381
+ await fs57.mkdir(claudeDir, { recursive: true });
29683
30382
  }
29684
30383
  const context7Config = {
29685
30384
  mcpServers: {
@@ -29690,16 +30389,16 @@ async function installContext7MCP() {
29690
30389
  }
29691
30390
  };
29692
30391
  if (await fileExists(mcpConfigPath)) {
29693
- const existingContent = await fs56.readFile(mcpConfigPath, "utf-8");
30392
+ const existingContent = await fs57.readFile(mcpConfigPath, "utf-8");
29694
30393
  const existingConfig = JSON.parse(existingContent);
29695
30394
  if (existingConfig.mcpServers?.context7) {
29696
30395
  return;
29697
30396
  }
29698
30397
  existingConfig.mcpServers = existingConfig.mcpServers || {};
29699
30398
  existingConfig.mcpServers.context7 = context7Config.mcpServers.context7;
29700
- await fs56.writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
30399
+ await fs57.writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
29701
30400
  } else {
29702
- await fs56.writeFile(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
30401
+ await fs57.writeFile(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
29703
30402
  }
29704
30403
  } catch (error) {
29705
30404
  logger_default.warn(`Context7 MCP setup warning: ${getErrorMessage2(error)}`);
@@ -29709,34 +30408,34 @@ async function installStatusLineModules(sourceDir, destDir) {
29709
30408
  if (!await fileExists(sourceDir)) {
29710
30409
  return;
29711
30410
  }
29712
- const files = await fs56.readdir(sourceDir);
30411
+ const files = await fs57.readdir(sourceDir);
29713
30412
  for (const file of files) {
29714
30413
  if (file.endsWith(".sh")) {
29715
- const src = path60.join(sourceDir, file);
29716
- const dest = path60.join(destDir, file);
29717
- await fs56.copyFile(src, dest);
29718
- await fs56.chmod(dest, 493);
30414
+ const src = path61.join(sourceDir, file);
30415
+ const dest = path61.join(destDir, file);
30416
+ await fs57.copyFile(src, dest);
30417
+ await fs57.chmod(dest, 493);
29719
30418
  }
29720
30419
  }
29721
30420
  }
29722
30421
  async function ensureStatusLineSymlink(linkPath, targetPath) {
29723
30422
  try {
29724
30423
  if (await fileExists(linkPath)) {
29725
- const stats = await fs56.lstat(linkPath);
30424
+ const stats = await fs57.lstat(linkPath);
29726
30425
  if (stats.isSymbolicLink()) {
29727
- const existingTarget = await fs56.readlink(linkPath);
30426
+ const existingTarget = await fs57.readlink(linkPath);
29728
30427
  if (existingTarget === targetPath) {
29729
30428
  return;
29730
30429
  }
29731
30430
  }
29732
- await fs56.unlink(linkPath);
30431
+ await fs57.unlink(linkPath);
29733
30432
  }
29734
- await fs56.symlink(targetPath, linkPath);
30433
+ await fs57.symlink(targetPath, linkPath);
29735
30434
  } catch (_error) {
29736
30435
  try {
29737
30436
  if (await fileExists(targetPath)) {
29738
- await fs56.copyFile(targetPath, linkPath);
29739
- await fs56.chmod(linkPath, 493);
30437
+ await fs57.copyFile(targetPath, linkPath);
30438
+ await fs57.chmod(linkPath, 493);
29740
30439
  }
29741
30440
  } catch (copyError) {
29742
30441
  if (!isNotFoundError(copyError)) {
@@ -30151,7 +30850,7 @@ var init_registry2 = __esm({
30151
30850
  });
30152
30851
 
30153
30852
  // core/commands/analytics.ts
30154
- import path61 from "node:path";
30853
+ import path62 from "node:path";
30155
30854
  var AnalyticsCommands;
30156
30855
  var init_analytics = __esm({
30157
30856
  "core/commands/analytics.ts"() {
@@ -30178,7 +30877,7 @@ var init_analytics = __esm({
30178
30877
  output_default.failWithHint("NO_PROJECT_ID");
30179
30878
  return { success: false, error: "No project ID found" };
30180
30879
  }
30181
- const projectName = path61.basename(projectPath);
30880
+ const projectName = path62.basename(projectPath);
30182
30881
  const currentTask = await stateStorage.getCurrentTask(projectId);
30183
30882
  const queueTasks = await queueStorage.getActiveTasks(projectId);
30184
30883
  const shipped = await shippedStorage.getRecent(projectId, 5);
@@ -30430,8 +31129,8 @@ ${"\u2550".repeat(50)}
30430
31129
  });
30431
31130
 
30432
31131
  // core/commands/context.ts
30433
- import fs57 from "node:fs/promises";
30434
- import path62 from "node:path";
31132
+ import fs58 from "node:fs/promises";
31133
+ import path63 from "node:path";
30435
31134
  var ContextCommands, contextCommands;
30436
31135
  var init_context = __esm({
30437
31136
  "core/commands/context.ts"() {
@@ -30557,8 +31256,8 @@ var init_context = __esm({
30557
31256
  */
30558
31257
  async loadRepoAnalysis(globalPath) {
30559
31258
  try {
30560
- const analysisPath = path62.join(globalPath, "analysis", "repo-analysis.json");
30561
- const content = await fs57.readFile(analysisPath, "utf-8");
31259
+ const analysisPath = path63.join(globalPath, "analysis", "repo-analysis.json");
31260
+ const content = await fs58.readFile(analysisPath, "utf-8");
30562
31261
  const data = JSON.parse(content);
30563
31262
  return {
30564
31263
  ecosystem: data.ecosystem || "unknown",
@@ -30577,7 +31276,7 @@ var init_context = __esm({
30577
31276
  });
30578
31277
 
30579
31278
  // core/commands/cleanup.ts
30580
- import path63 from "node:path";
31279
+ import path64 from "node:path";
30581
31280
  async function cleanupMemory(projectPath) {
30582
31281
  const projectId = await config_manager_default.getProjectId(projectPath);
30583
31282
  const results = { rotated: [], totalSize: 0, freedSpace: 0 };
@@ -30593,7 +31292,7 @@ async function cleanupMemory(projectPath) {
30593
31292
  results.totalSize += sizeMB;
30594
31293
  const rotated = await jsonl_helper_exports.rotateJsonLinesIfNeeded(filePath, 10);
30595
31294
  if (rotated) {
30596
- results.rotated.push(path63.basename(filePath));
31295
+ results.rotated.push(path64.basename(filePath));
30597
31296
  results.freedSpace += sizeMB;
30598
31297
  }
30599
31298
  }
@@ -30700,7 +31399,7 @@ var init_cleanup = __esm({
30700
31399
  });
30701
31400
 
30702
31401
  // core/commands/design.ts
30703
- import path64 from "node:path";
31402
+ import path65 from "node:path";
30704
31403
  async function design(target = null, options = {}, projectPath = process.cwd()) {
30705
31404
  try {
30706
31405
  const designType = options.type || "architecture";
@@ -30712,7 +31411,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
30712
31411
  const designTarget = target || "system";
30713
31412
  output_default.spin(`designing ${designType}...`);
30714
31413
  const projectId = await config_manager_default.getProjectId(projectPath);
30715
- const designsPath = path64.join(
31414
+ const designsPath = path65.join(
30716
31415
  path_manager_default.getGlobalProjectPath(projectId),
30717
31416
  "planning",
30718
31417
  "designs"
@@ -30752,7 +31451,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
30752
31451
  break;
30753
31452
  }
30754
31453
  const designFileName = `${designType}-${designTarget.toLowerCase().replace(/\s+/g, "-")}.md`;
30755
- const designFilePath = path64.join(designsPath, designFileName);
31454
+ const designFilePath = path65.join(designsPath, designFileName);
30756
31455
  await file_helper_exports.writeFile(designFilePath, designContent);
30757
31456
  await memoryService.log(projectPath, "design_created", {
30758
31457
  type: designType,
@@ -30777,7 +31476,7 @@ var init_design = __esm({
30777
31476
  });
30778
31477
 
30779
31478
  // core/commands/snapshots.ts
30780
- import path65 from "node:path";
31479
+ import path66 from "node:path";
30781
31480
  async function recover(projectPath = process.cwd()) {
30782
31481
  try {
30783
31482
  const projectId = await config_manager_default.getProjectId(projectPath);
@@ -30829,7 +31528,7 @@ async function undo(projectPath = process.cwd()) {
30829
31528
  output_default.failWithHint("NO_PROJECT_ID");
30830
31529
  return { success: false, error: "No project ID found" };
30831
31530
  }
30832
- const snapshotsPath = path65.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
31531
+ const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
30833
31532
  await file_helper_exports.ensureDir(snapshotsPath);
30834
31533
  const { execSync: execSync5 } = await import("node:child_process");
30835
31534
  try {
@@ -30847,7 +31546,7 @@ async function undo(projectPath = process.cwd()) {
30847
31546
  cwd: projectPath,
30848
31547
  encoding: "utf-8"
30849
31548
  });
30850
- const snapshotFile = path65.join(snapshotsPath, "history.json");
31549
+ const snapshotFile = path66.join(snapshotsPath, "history.json");
30851
31550
  let history2 = { snapshots: [], current: -1 };
30852
31551
  try {
30853
31552
  const content = await file_helper_exports.readFile(snapshotFile);
@@ -30887,8 +31586,8 @@ async function redo(projectPath = process.cwd()) {
30887
31586
  output_default.failWithHint("NO_PROJECT_ID");
30888
31587
  return { success: false, error: "No project ID found" };
30889
31588
  }
30890
- const snapshotsPath = path65.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
30891
- const snapshotFile = path65.join(snapshotsPath, "history.json");
31589
+ const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
31590
+ const snapshotFile = path66.join(snapshotsPath, "history.json");
30892
31591
  let history2;
30893
31592
  try {
30894
31593
  const content = await file_helper_exports.readFile(snapshotFile);
@@ -30947,8 +31646,8 @@ async function history(projectPath = process.cwd()) {
30947
31646
  output_default.failWithHint("NO_PROJECT_ID");
30948
31647
  return { success: false, error: "No project ID found" };
30949
31648
  }
30950
- const snapshotsPath = path65.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
30951
- const snapshotFile = path65.join(snapshotsPath, "history.json");
31649
+ const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
31650
+ const snapshotFile = path66.join(snapshotsPath, "history.json");
30952
31651
  let snapshotHistory;
30953
31652
  try {
30954
31653
  const content = await file_helper_exports.readFile(snapshotFile);
@@ -31151,8 +31850,8 @@ ${chalk16.cyan("Performance Report")} ${chalk16.dim(`(last ${days} days)`)}`);
31151
31850
  });
31152
31851
 
31153
31852
  // core/commands/setup.ts
31154
- import fs58 from "node:fs/promises";
31155
- import path66 from "node:path";
31853
+ import fs59 from "node:fs/promises";
31854
+ import path67 from "node:path";
31156
31855
  import chalk17 from "chalk";
31157
31856
  var SetupCommands;
31158
31857
  var init_setup2 = __esm({
@@ -31281,7 +31980,7 @@ Please install it first:
31281
31980
  try {
31282
31981
  const claudeDir = path_manager_default.getClaudeDir();
31283
31982
  const settingsPath = path_manager_default.getClaudeSettingsPath();
31284
- const statusLinePath = path66.join(claudeDir, "prjct-statusline.sh");
31983
+ const statusLinePath = path67.join(claudeDir, "prjct-statusline.sh");
31285
31984
  const scriptContent = `#!/bin/bash
31286
31985
  # prjct Status Line for Claude Code
31287
31986
  # Shows version update notifications and current task
@@ -31339,11 +32038,11 @@ fi
31339
32038
  # Default: show prjct branding
31340
32039
  echo "\u26A1 prjct"
31341
32040
  `;
31342
- await fs58.writeFile(statusLinePath, scriptContent, { mode: 493 });
32041
+ await fs59.writeFile(statusLinePath, scriptContent, { mode: 493 });
31343
32042
  let settings = {};
31344
32043
  if (await fileExists(settingsPath)) {
31345
32044
  try {
31346
- settings = JSON.parse(await fs58.readFile(settingsPath, "utf8"));
32045
+ settings = JSON.parse(await fs59.readFile(settingsPath, "utf8"));
31347
32046
  } catch (_error) {
31348
32047
  }
31349
32048
  }
@@ -31351,7 +32050,7 @@ echo "\u26A1 prjct"
31351
32050
  type: "command",
31352
32051
  command: statusLinePath
31353
32052
  };
31354
- await fs58.writeFile(settingsPath, JSON.stringify(settings, null, 2));
32053
+ await fs59.writeFile(settingsPath, JSON.stringify(settings, null, 2));
31355
32054
  return { success: true };
31356
32055
  } catch (error) {
31357
32056
  return { success: false, error: getErrorMessage2(error) };
@@ -31407,18 +32106,18 @@ echo "\u26A1 prjct"
31407
32106
  });
31408
32107
 
31409
32108
  // core/utils/project-commands.ts
31410
- import path67 from "node:path";
32109
+ import path68 from "node:path";
31411
32110
  async function detectPackageManager(projectPath, pkg) {
31412
32111
  const declared = pkg?.packageManager?.trim().toLowerCase();
31413
32112
  if (declared?.startsWith("pnpm@")) return "pnpm";
31414
32113
  if (declared?.startsWith("yarn@")) return "yarn";
31415
32114
  if (declared?.startsWith("bun@")) return "bun";
31416
32115
  if (declared?.startsWith("npm@")) return "npm";
31417
- if (await fileExists2(path67.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
31418
- if (await fileExists2(path67.join(projectPath, "yarn.lock"))) return "yarn";
31419
- if (await fileExists2(path67.join(projectPath, "bun.lockb"))) return "bun";
31420
- if (await fileExists2(path67.join(projectPath, "bun.lock"))) return "bun";
31421
- if (await fileExists2(path67.join(projectPath, "package-lock.json"))) return "npm";
32116
+ if (await fileExists2(path68.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
32117
+ if (await fileExists2(path68.join(projectPath, "yarn.lock"))) return "yarn";
32118
+ if (await fileExists2(path68.join(projectPath, "bun.lockb"))) return "bun";
32119
+ if (await fileExists2(path68.join(projectPath, "bun.lock"))) return "bun";
32120
+ if (await fileExists2(path68.join(projectPath, "package-lock.json"))) return "npm";
31422
32121
  return "npm";
31423
32122
  }
31424
32123
  function pmRun(pm, scriptName) {
@@ -31434,7 +32133,7 @@ function pmTest(pm) {
31434
32133
  return "npm test";
31435
32134
  }
31436
32135
  async function detectProjectCommands(projectPath) {
31437
- const pkgPath = path67.join(projectPath, "package.json");
32136
+ const pkgPath = path68.join(projectPath, "package.json");
31438
32137
  const pkg = await readJson(pkgPath, null);
31439
32138
  if (pkg) {
31440
32139
  const pm = await detectPackageManager(projectPath, pkg);
@@ -31451,27 +32150,27 @@ async function detectProjectCommands(projectPath) {
31451
32150
  }
31452
32151
  return result;
31453
32152
  }
31454
- if (await fileExists2(path67.join(projectPath, "pytest.ini"))) {
32153
+ if (await fileExists2(path68.join(projectPath, "pytest.ini"))) {
31455
32154
  return { stack: "python", test: { tool: "pytest", command: "pytest" } };
31456
32155
  }
31457
- const pyproject = await readFile(path67.join(projectPath, "pyproject.toml"), "");
32156
+ const pyproject = await readFile(path68.join(projectPath, "pyproject.toml"), "");
31458
32157
  if (pyproject.includes("[tool.pytest") || pyproject.includes("pytest")) {
31459
32158
  return { stack: "python", test: { tool: "pytest", command: "pytest" } };
31460
32159
  }
31461
- if (await fileExists2(path67.join(projectPath, "Cargo.toml"))) {
32160
+ if (await fileExists2(path68.join(projectPath, "Cargo.toml"))) {
31462
32161
  return { stack: "rust", test: { tool: "cargo", command: "cargo test" } };
31463
32162
  }
31464
- if (await fileExists2(path67.join(projectPath, "go.mod"))) {
32163
+ if (await fileExists2(path68.join(projectPath, "go.mod"))) {
31465
32164
  return { stack: "go", test: { tool: "go", command: "go test ./..." } };
31466
32165
  }
31467
32166
  const files = await listFiles(projectPath);
31468
32167
  if (files.some((f) => f.endsWith(".sln") || f.endsWith(".csproj") || f.endsWith(".fsproj"))) {
31469
32168
  return { stack: "dotnet", test: { tool: "dotnet", command: "dotnet test" } };
31470
32169
  }
31471
- if (await fileExists2(path67.join(projectPath, "pom.xml"))) {
32170
+ if (await fileExists2(path68.join(projectPath, "pom.xml"))) {
31472
32171
  return { stack: "java", test: { tool: "maven", command: "mvn test" } };
31473
32172
  }
31474
- if (await fileExists2(path67.join(projectPath, "gradlew")) && (await fileExists2(path67.join(projectPath, "build.gradle")) || await fileExists2(path67.join(projectPath, "build.gradle.kts")))) {
32173
+ if (await fileExists2(path68.join(projectPath, "gradlew")) && (await fileExists2(path68.join(projectPath, "build.gradle")) || await fileExists2(path68.join(projectPath, "build.gradle.kts")))) {
31475
32174
  return { stack: "java", test: { tool: "gradle", command: "./gradlew test" } };
31476
32175
  }
31477
32176
  return { stack: "unknown" };
@@ -31646,7 +32345,7 @@ var init_workflow_preferences = __esm({
31646
32345
  });
31647
32346
 
31648
32347
  // core/commands/shipping.ts
31649
- import path68 from "node:path";
32348
+ import path69 from "node:path";
31650
32349
  var ShippingCommands;
31651
32350
  var init_shipping = __esm({
31652
32351
  "core/commands/shipping.ts"() {
@@ -31792,7 +32491,7 @@ ${result.stderr}`.trim();
31792
32491
  */
31793
32492
  async _bumpVersion(projectPath) {
31794
32493
  try {
31795
- const pkgPath = path68.join(projectPath, "package.json");
32494
+ const pkgPath = path69.join(projectPath, "package.json");
31796
32495
  const pkg = await file_helper_exports.readJson(pkgPath, { version: "0.0.0" });
31797
32496
  const oldVersion = pkg?.version || "0.0.0";
31798
32497
  const [major, minor, patch] = oldVersion.split(".").map(Number);
@@ -31814,7 +32513,7 @@ ${result.stderr}`.trim();
31814
32513
  */
31815
32514
  async _updateChangelog(feature, version, projectPath) {
31816
32515
  try {
31817
- const changelogPath = path68.join(projectPath, "CHANGELOG.md");
32516
+ const changelogPath = path69.join(projectPath, "CHANGELOG.md");
31818
32517
  const changelog = await file_helper_exports.readFile(changelogPath, "# Changelog\n\n");
31819
32518
  const entry = `## [${version}] - ${date_helper_exports.formatDate(/* @__PURE__ */ new Date())}
31820
32519
 
@@ -32858,11 +33557,11 @@ var init_linear = __esm({
32858
33557
  });
32859
33558
 
32860
33559
  // core/utils/project-credentials.ts
32861
- import fs59 from "node:fs/promises";
33560
+ import fs60 from "node:fs/promises";
32862
33561
  import os19 from "node:os";
32863
- import path69 from "node:path";
33562
+ import path70 from "node:path";
32864
33563
  function getCredentialsPath(projectId) {
32865
- return path69.join(os19.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
33564
+ return path70.join(os19.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
32866
33565
  }
32867
33566
  async function getProjectCredentials(projectId) {
32868
33567
  const credPath = getCredentialsPath(projectId);
@@ -32870,7 +33569,7 @@ async function getProjectCredentials(projectId) {
32870
33569
  return {};
32871
33570
  }
32872
33571
  try {
32873
- return JSON.parse(await fs59.readFile(credPath, "utf-8"));
33572
+ return JSON.parse(await fs60.readFile(credPath, "utf-8"));
32874
33573
  } catch (error) {
32875
33574
  console.error("[project-credentials] Failed to read credentials:", getErrorMessage2(error));
32876
33575
  return {};
@@ -33542,7 +34241,7 @@ var require_package = __commonJS({
33542
34241
  "package.json"(exports, module) {
33543
34242
  module.exports = {
33544
34243
  name: "prjct-cli",
33545
- version: "1.17.0",
34244
+ version: "1.19.0",
33546
34245
  description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
33547
34246
  main: "core/index.ts",
33548
34247
  bin: {
@@ -33649,7 +34348,7 @@ var require_package = __commonJS({
33649
34348
  // core/index.ts
33650
34349
  var core_exports = {};
33651
34350
  import os20 from "node:os";
33652
- import path70 from "node:path";
34351
+ import path71 from "node:path";
33653
34352
  import chalk20 from "chalk";
33654
34353
  async function main() {
33655
34354
  const [commandName, ...rawArgs] = process.argv.slice(2);
@@ -33754,7 +34453,8 @@ async function main() {
33754
34453
  preview: options.preview === true || options["dry-run"] === true,
33755
34454
  yes: options.yes === true,
33756
34455
  json: options.json === true,
33757
- package: options.package ? String(options.package) : void 0
34456
+ package: options.package ? String(options.package) : void 0,
34457
+ full: options.full === true
33758
34458
  }), "sync"),
33759
34459
  seal: /* @__PURE__ */ __name(() => commands.seal(process.cwd(), { json: options.json === true }), "seal"),
33760
34460
  verify: /* @__PURE__ */ __name(() => commands.verify(process.cwd(), { json: options.json === true }), "verify"),
@@ -33862,13 +34562,13 @@ function parseCommandArgs(_cmd, rawArgs) {
33862
34562
  }
33863
34563
  async function displayVersion(version) {
33864
34564
  const detection = await detectAllProviders();
33865
- const claudeCommandPath = path70.join(os20.homedir(), ".claude", "commands", "p.md");
33866
- const geminiCommandPath = path70.join(os20.homedir(), ".gemini", "commands", "p.toml");
34565
+ const claudeCommandPath = path71.join(os20.homedir(), ".claude", "commands", "p.md");
34566
+ const geminiCommandPath = path71.join(os20.homedir(), ".gemini", "commands", "p.toml");
33867
34567
  const [claudeConfigured, geminiConfigured, cursorConfigured, cursorExists] = await Promise.all([
33868
34568
  fileExists(claudeCommandPath),
33869
34569
  fileExists(geminiCommandPath),
33870
- fileExists(path70.join(process.cwd(), ".cursor", "commands", "sync.md")),
33871
- fileExists(path70.join(process.cwd(), ".cursor"))
34570
+ fileExists(path71.join(process.cwd(), ".cursor", "commands", "sync.md")),
34571
+ fileExists(path71.join(process.cwd(), ".cursor"))
33872
34572
  ]);
33873
34573
  const antigravityDetection = await detectAntigravity();
33874
34574
  console.log(`
@@ -34007,7 +34707,7 @@ init_ai_provider();
34007
34707
  init_config_manager();
34008
34708
  init_editors_config();
34009
34709
  import os21 from "node:os";
34010
- import path71 from "node:path";
34710
+ import path72 from "node:path";
34011
34711
  import chalk21 from "chalk";
34012
34712
 
34013
34713
  // core/server/server.ts
@@ -34828,13 +35528,13 @@ async function checkRoutersInstalled() {
34828
35528
  const home = os21.homedir();
34829
35529
  const detection = await detectAllProviders();
34830
35530
  if (detection.claude.installed) {
34831
- const claudeRouter = path71.join(home, ".claude", "commands", "p.md");
35531
+ const claudeRouter = path72.join(home, ".claude", "commands", "p.md");
34832
35532
  if (!await fileExists(claudeRouter)) {
34833
35533
  return false;
34834
35534
  }
34835
35535
  }
34836
35536
  if (detection.gemini.installed) {
34837
- const geminiRouter = path71.join(home, ".gemini", "commands", "p.toml");
35537
+ const geminiRouter = path72.join(home, ".gemini", "commands", "p.toml");
34838
35538
  if (!await fileExists(geminiRouter)) {
34839
35539
  return false;
34840
35540
  }
@@ -34975,7 +35675,7 @@ if (args[0] === "start" || args[0] === "setup") {
34975
35675
  console.error('No prjct project found. Run "prjct init" first.');
34976
35676
  process.exitCode = 1;
34977
35677
  } else {
34978
- const linearCliPath = path71.join(__dirname, "..", "core", "cli", "linear.ts");
35678
+ const linearCliPath = path72.join(__dirname, "..", "core", "cli", "linear.ts");
34979
35679
  const linearArgs = ["--project", projectId, ...args.slice(1)];
34980
35680
  const child = spawn("bun", [linearCliPath, ...linearArgs], {
34981
35681
  stdio: "inherit",
@@ -35002,12 +35702,12 @@ if (args[0] === "start" || args[0] === "setup") {
35002
35702
  windsurfDetected,
35003
35703
  windsurfConfigured
35004
35704
  ] = await Promise.all([
35005
- fileExists(path71.join(home, ".claude", "commands", "p.md")),
35006
- fileExists(path71.join(home, ".gemini", "commands", "p.toml")),
35007
- fileExists(path71.join(cwd, ".cursor")),
35008
- fileExists(path71.join(cwd, ".cursor", "rules", "prjct.mdc")),
35009
- fileExists(path71.join(cwd, ".windsurf")),
35010
- fileExists(path71.join(cwd, ".windsurf", "rules", "prjct.md"))
35705
+ fileExists(path72.join(home, ".claude", "commands", "p.md")),
35706
+ fileExists(path72.join(home, ".gemini", "commands", "p.toml")),
35707
+ fileExists(path72.join(cwd, ".cursor")),
35708
+ fileExists(path72.join(cwd, ".cursor", "rules", "prjct.mdc")),
35709
+ fileExists(path72.join(cwd, ".windsurf")),
35710
+ fileExists(path72.join(cwd, ".windsurf", "rules", "prjct.md"))
35011
35711
  ]);
35012
35712
  console.log(`
35013
35713
  ${chalk21.cyan("p/")} prjct v${VERSION}
@@ -35046,7 +35746,7 @@ ${chalk21.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
35046
35746
  ${chalk21.cyan("https://prjct.app")}
35047
35747
  `);
35048
35748
  } else {
35049
- const configPath = path71.join(os21.homedir(), ".prjct-cli", "config", "installed-editors.json");
35749
+ const configPath = path72.join(os21.homedir(), ".prjct-cli", "config", "installed-editors.json");
35050
35750
  const routersInstalled = await checkRoutersInstalled();
35051
35751
  if (!await fileExists(configPath) || !routersInstalled) {
35052
35752
  console.log(`