@packmind/cli 0.25.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/main.cjs +1796 -1627
  2. package/package.json +3 -2
package/main.cjs CHANGED
@@ -1582,6 +1582,9 @@ function stripAnsi(string21) {
1582
1582
  if (typeof string21 !== "string") {
1583
1583
  throw new TypeError(`Expected a \`string\`, got \`${typeof string21}\``);
1584
1584
  }
1585
+ if (!string21.includes("\x1B") && !string21.includes("\x9B")) {
1586
+ return string21;
1587
+ }
1585
1588
  return string21.replace(regex, "");
1586
1589
  }
1587
1590
  var regex;
@@ -3852,7 +3855,7 @@ var require_package = __commonJS({
3852
3855
  "apps/cli/package.json"(exports2, module2) {
3853
3856
  module2.exports = {
3854
3857
  name: "@packmind/cli",
3855
- version: "0.25.0",
3858
+ version: "0.26.1",
3856
3859
  description: "A command-line interface for Packmind linting and code quality checks",
3857
3860
  private: false,
3858
3861
  bin: {
@@ -4427,6 +4430,48 @@ var SpaceCreatedEvent = class extends UserEvent {
4427
4430
  }
4428
4431
  };
4429
4432
 
4433
+ // packages/types/src/spaces/events/SpaceMembersAddedEvent.ts
4434
+ var SpaceMembersAddedEvent = class extends UserEvent {
4435
+ static {
4436
+ this.eventName = "spaces.space.members-added";
4437
+ }
4438
+ };
4439
+
4440
+ // packages/types/src/spaces/events/SpaceMembersRemovedEvent.ts
4441
+ var SpaceMembersRemovedEvent = class extends UserEvent {
4442
+ static {
4443
+ this.eventName = "spaces.space.members-removed";
4444
+ }
4445
+ };
4446
+
4447
+ // packages/types/src/spaces/events/SpaceMembersRoleUpdatedEvent.ts
4448
+ var SpaceMembersRoleUpdatedEvent = class extends UserEvent {
4449
+ static {
4450
+ this.eventName = "spaces.space.members-role-updated";
4451
+ }
4452
+ };
4453
+
4454
+ // packages/types/src/spaces/events/SpacePinnedEvent.ts
4455
+ var SpacePinnedEvent = class extends UserEvent {
4456
+ static {
4457
+ this.eventName = "spaces.space.pinned";
4458
+ }
4459
+ };
4460
+
4461
+ // packages/types/src/spaces/events/SpaceUnpinnedEvent.ts
4462
+ var SpaceUnpinnedEvent = class extends UserEvent {
4463
+ static {
4464
+ this.eventName = "spaces.space.unpinned";
4465
+ }
4466
+ };
4467
+
4468
+ // packages/types/src/spaces/events/SpaceVisibilityUpdatedEvent.ts
4469
+ var SpaceVisibilityUpdatedEvent = class extends UserEvent {
4470
+ static {
4471
+ this.eventName = "spaces.space.visibility-updated";
4472
+ }
4473
+ };
4474
+
4430
4475
  // packages/types/src/spaces-management/events/PlaybookArtefactMovedEvent.ts
4431
4476
  var PlaybookArtefactMovedEvent = class extends UserEvent {
4432
4477
  static {
@@ -5335,30 +5380,30 @@ var GitService = class {
5335
5380
  this.gitRunner = gitRunner;
5336
5381
  this.logger = logger2;
5337
5382
  }
5338
- getGitRepositoryRoot(path36) {
5383
+ getGitRepositoryRoot(path37) {
5339
5384
  try {
5340
5385
  const { stdout } = this.gitRunner("rev-parse --show-toplevel", {
5341
- cwd: path36
5386
+ cwd: path37
5342
5387
  });
5343
5388
  const gitRoot = stdout.trim();
5344
5389
  this.logger.debug("Resolved git repository root", {
5345
- inputPath: path36,
5390
+ inputPath: path37,
5346
5391
  gitRoot
5347
5392
  });
5348
5393
  return gitRoot;
5349
5394
  } catch (error) {
5350
5395
  if (error instanceof Error) {
5351
5396
  throw new Error(
5352
- `Failed to get Git repository root. The path '${path36}' does not appear to be inside a Git repository.
5397
+ `Failed to get Git repository root. The path '${path37}' does not appear to be inside a Git repository.
5353
5398
  ${error.message}`
5354
5399
  );
5355
5400
  }
5356
5401
  throw new Error("Failed to get Git repository root: Unknown error");
5357
5402
  }
5358
5403
  }
5359
- tryGetGitRepositoryRoot(path36) {
5404
+ tryGetGitRepositoryRoot(path37) {
5360
5405
  try {
5361
- return this.getGitRepositoryRoot(path36);
5406
+ return this.getGitRepositoryRoot(path37);
5362
5407
  } catch {
5363
5408
  return null;
5364
5409
  }
@@ -6623,10 +6668,10 @@ var PackmindHttpClient = class {
6623
6668
  return null;
6624
6669
  }
6625
6670
  }
6626
- async request(path36, options = {}) {
6671
+ async request(path37, options = {}) {
6627
6672
  const { host } = this.getAuthContext();
6628
6673
  const { method = "GET", body } = options;
6629
- const url = `${host}${path36}`;
6674
+ const url = `${host}${path37}`;
6630
6675
  try {
6631
6676
  const response = await fetch(url, {
6632
6677
  method,
@@ -6838,6 +6883,21 @@ var SpacesGateway = class {
6838
6883
  );
6839
6884
  };
6840
6885
  }
6886
+ async getSpaceBySlug(slug3) {
6887
+ const { organizationId } = this.httpClient.getAuthContext();
6888
+ try {
6889
+ return await this.httpClient.request(
6890
+ `/api/v0/organizations/${organizationId}/spaces/${slug3}`
6891
+ );
6892
+ } catch (error) {
6893
+ if (error.statusCode === 404) return null;
6894
+ throw error;
6895
+ }
6896
+ }
6897
+ getApiContext() {
6898
+ const { host, organizationId } = this.httpClient.getAuthContext();
6899
+ return { host, organizationId };
6900
+ }
6841
6901
  };
6842
6902
 
6843
6903
  // apps/cli/src/infra/repositories/SkillsGateway.ts
@@ -7026,6 +7086,21 @@ var DeploymentGateway = class {
7026
7086
  `/api/v0/organizations/${organizationId}/pull?${queryParams.toString()}`
7027
7087
  );
7028
7088
  };
7089
+ this.install = async (command33) => {
7090
+ const { organizationId } = this.httpClient.getAuthContext();
7091
+ return this.httpClient.request(
7092
+ `/api/v0/organizations/${organizationId}/install`,
7093
+ {
7094
+ method: "POST",
7095
+ body: {
7096
+ packagesSlugs: command33.packagesSlugs,
7097
+ packmindLockFile: command33.packmindLockFile,
7098
+ ...command33.relativePath && { relativePath: command33.relativePath },
7099
+ ...command33.agents !== void 0 && { agents: command33.agents }
7100
+ }
7101
+ }
7102
+ );
7103
+ };
7029
7104
  this.getDeployed = async (command33) => {
7030
7105
  const { organizationId } = this.httpClient.getAuthContext();
7031
7106
  return this.httpClient.request(
@@ -7065,6 +7140,21 @@ var DeploymentGateway = class {
7065
7140
  }
7066
7141
  );
7067
7142
  };
7143
+ this.notifyArtefactsDistribution = async (command33) => {
7144
+ const { organizationId } = this.httpClient.getAuthContext();
7145
+ return this.httpClient.request(
7146
+ `/api/v0/organizations/${organizationId}/deployments/notify-artifacts-distribution`,
7147
+ {
7148
+ method: "POST",
7149
+ body: {
7150
+ gitRemoteUrl: command33.gitRemoteUrl,
7151
+ gitBranch: command33.gitBranch,
7152
+ relativePath: command33.relativePath,
7153
+ packmindLockFile: command33.packmindLockFile
7154
+ }
7155
+ }
7156
+ );
7157
+ };
7068
7158
  this.getRenderModeConfiguration = async () => {
7069
7159
  const { organizationId } = this.httpClient.getAuthContext();
7070
7160
  return this.httpClient.request(
@@ -7086,6 +7176,24 @@ var DeploymentGateway = class {
7086
7176
  }
7087
7177
  };
7088
7178
 
7179
+ // apps/cli/src/infra/repositories/OrganizationGateway.ts
7180
+ var OrganizationGateway = class {
7181
+ constructor(httpClient) {
7182
+ this.httpClient = httpClient;
7183
+ }
7184
+ async getOrganization() {
7185
+ const { organizationId } = this.httpClient.getAuthContext();
7186
+ const organizations = await this.httpClient.request(
7187
+ "/api/v0/organizations"
7188
+ );
7189
+ const org = organizations.find((o) => o.id === organizationId);
7190
+ if (!org) {
7191
+ throw new Error(`Organization ${organizationId} not found`);
7192
+ }
7193
+ return org;
7194
+ }
7195
+ };
7196
+
7089
7197
  // apps/cli/src/infra/repositories/PackmindGateway.ts
7090
7198
  var PackmindGateway = class {
7091
7199
  constructor(apiKey) {
@@ -7100,6 +7208,7 @@ var PackmindGateway = class {
7100
7208
  this.standards = new StandardsGateway(this.httpClient);
7101
7209
  this.packages = new PackagesGateway(apiKey, this.httpClient);
7102
7210
  this.deployment = new DeploymentGateway(this.httpClient);
7211
+ this.organization = new OrganizationGateway(this.httpClient);
7103
7212
  }
7104
7213
  };
7105
7214
 
@@ -9927,69 +10036,150 @@ ${endMarker}`;
9927
10036
  }
9928
10037
  };
9929
10038
 
9930
- // apps/cli/src/application/useCases/InstallDefaultSkillsUseCase.ts
10039
+ // apps/cli/src/application/useCases/InstallUseCase.ts
9931
10040
  var fs5 = __toESM(require("fs/promises"));
9932
10041
  var path7 = __toESM(require("path"));
9933
- var import_semver = __toESM(require("semver"));
9934
- var InstallDefaultSkillsUseCase = class {
9935
- constructor(repositories) {
9936
- this.repositories = repositories;
10042
+
10043
+ // apps/cli/src/application/utils/normalizePackageSlugs.ts
10044
+ async function normalizePackageSlugs(slugs, spaceService) {
10045
+ const hasUnprefixed = slugs.some((s) => !s.startsWith("@"));
10046
+ if (!hasUnprefixed) return slugs;
10047
+ const spaces = await spaceService.getSpaces();
10048
+ if (spaces.length > 1) {
10049
+ throw new Error(
10050
+ `Your organization has multiple spaces. Please specify the space for each package using the @space/package format (e.g. @${spaces[0].slug}/my-package).`
10051
+ );
10052
+ }
10053
+ const defaultSpace = await spaceService.getDefaultSpace();
10054
+ return slugs.map(
10055
+ (slug3) => slug3.startsWith("@") ? slug3 : `@${defaultSpace.slug}/${slug3}`
10056
+ );
10057
+ }
10058
+
10059
+ // apps/cli/src/application/useCases/InstallUseCase.ts
10060
+ var InstallUseCase = class {
10061
+ constructor(packmindGateway, lockFileRepository, configFileRepository, spaceService) {
10062
+ this.packmindGateway = packmindGateway;
10063
+ this.lockFileRepository = lockFileRepository;
10064
+ this.configFileRepository = configFileRepository;
10065
+ this.spaceService = spaceService;
9937
10066
  }
9938
10067
  async execute(command33) {
9939
10068
  const baseDirectory = command33.baseDirectory || process.cwd();
9940
10069
  const result = {
9941
10070
  filesCreated: 0,
9942
10071
  filesUpdated: 0,
10072
+ filesDeleted: 0,
10073
+ contentFilesChanged: 0,
9943
10074
  errors: [],
9944
- skippedSkillsCount: 0,
9945
- skippedIncompatibleSkillNames: [],
9946
- incompatibleInstalledSkills: []
10075
+ recipesCount: 0,
10076
+ standardsCount: 0,
10077
+ commandsCount: 0,
10078
+ skillsCount: 0,
10079
+ recipesRemoved: 0,
10080
+ standardsRemoved: 0,
10081
+ commandsRemoved: 0,
10082
+ skillsRemoved: 0,
10083
+ skillDirectoriesDeleted: 0,
10084
+ missingAccess: []
9947
10085
  };
9948
- const config = await this.repositories.configFileRepository.readConfig(baseDirectory);
9949
- const agents = config?.agents;
9950
- const response = await this.repositories.packmindGateway.skills.getDefaults(
9951
- {
9952
- cliVersion: command33.cliVersion,
9953
- includeBeta: command33.includeBeta,
9954
- agents
10086
+ const hasExplicitPackages = command33.packages && command33.packages.length > 0;
10087
+ const lockFile = await this.lockFileRepository.read(baseDirectory);
10088
+ const config = await this.configFileRepository.readConfig(baseDirectory);
10089
+ if (!config && !hasExplicitPackages) {
10090
+ const configFileExists = await this.configFileRepository.configExists(baseDirectory);
10091
+ if (configFileExists) {
10092
+ throw new Error(
10093
+ "packmind.json exists but could not be parsed. Please fix the JSON syntax errors and try again."
10094
+ );
9955
10095
  }
9956
- );
9957
- result.skippedSkillsCount = response.skippedSkillsCount;
9958
- const incompatibleInstalledMap = /* @__PURE__ */ new Map();
9959
- const incompatibleSkillDirs = /* @__PURE__ */ new Map();
9960
- if (command33.cliVersion) {
9961
- for (const file of response.fileUpdates.createOrUpdate) {
9962
- if (path7.basename(file.path) === "SKILL.md" && file.content && this.isVersionConstraintViolated(file.content, command33.cliVersion)) {
9963
- const dir = path7.dirname(file.path);
9964
- const skillName = this.getSkillName(file.content) ?? path7.basename(dir);
9965
- incompatibleSkillDirs.set(dir, skillName);
10096
+ throw new Error(
10097
+ "No packmind.json found in this directory. Run `packmind-cli install <@space/package>` first to install your packages."
10098
+ );
10099
+ }
10100
+ const effectiveLockFile = lockFile ?? {
10101
+ lockfileVersion: 1,
10102
+ packageSlugs: [],
10103
+ agents: [],
10104
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
10105
+ artifacts: {}
10106
+ };
10107
+ let packagesSlugs;
10108
+ let normalizedPackages = [];
10109
+ if (hasExplicitPackages) {
10110
+ normalizedPackages = await this.normalizePackageSlugs(command33.packages);
10111
+ await this.validatePackageAccess(normalizedPackages);
10112
+ const normalizedConfigPackages = config ? await this.normalizeAndSaveConfigPackages(baseDirectory, config) : [];
10113
+ packagesSlugs = [
10114
+ .../* @__PURE__ */ new Set([...normalizedConfigPackages, ...normalizedPackages])
10115
+ ];
10116
+ } else {
10117
+ packagesSlugs = await this.normalizeAndSaveConfigPackages(
10118
+ baseDirectory,
10119
+ config
10120
+ );
10121
+ }
10122
+ if (packagesSlugs.length === 0) {
10123
+ try {
10124
+ for (const entry of Object.values(effectiveLockFile.artifacts)) {
10125
+ for (const file of entry.files) {
10126
+ await this.deleteFile(baseDirectory, file.path, result);
10127
+ }
9966
10128
  }
10129
+ await this.deleteFile(baseDirectory, "packmind-lock.json", result);
10130
+ } catch (error) {
10131
+ const errorMsg = error instanceof Error ? error.message : String(error);
10132
+ result.errors.push(`Failed to clean up artifacts: ${errorMsg}`);
10133
+ }
10134
+ return result;
10135
+ }
10136
+ const response = await this.packmindGateway.deployment.install({
10137
+ packagesSlugs,
10138
+ packmindLockFile: effectiveLockFile,
10139
+ agents: config?.agents
10140
+ });
10141
+ result.missingAccess = response.missingAccess;
10142
+ if (result.missingAccess.length > 0) {
10143
+ result.joinSpaceUrl = await this.computeJoinSpaceUrl(
10144
+ result.missingAccess
10145
+ );
10146
+ }
10147
+ const filteredCreateOrUpdate = response.fileUpdates.createOrUpdate.filter(
10148
+ (file) => file.path !== "packmind.json"
10149
+ );
10150
+ const uniqueFilesMap = /* @__PURE__ */ new Map();
10151
+ for (const file of filteredCreateOrUpdate) {
10152
+ uniqueFilesMap.set(file.path, file);
10153
+ }
10154
+ const uniqueFiles = Array.from(uniqueFilesMap.values());
10155
+ for (const file of uniqueFiles) {
10156
+ if (file.path.includes(".packmind/recipes/") && file.path.endsWith(".md")) {
10157
+ result.recipesCount++;
10158
+ } else if (file.path.includes(".packmind/standards/") && file.path.endsWith(".md")) {
10159
+ result.standardsCount++;
10160
+ } else if (file.path.includes(".packmind/commands/") && file.path.endsWith(".md")) {
10161
+ result.commandsCount++;
10162
+ } else if (file.path.includes(".packmind/skills/") && file.path.endsWith(".md")) {
10163
+ result.skillsCount++;
9967
10164
  }
9968
10165
  }
9969
10166
  try {
9970
- for (const file of response.fileUpdates.createOrUpdate) {
10167
+ result.skillDirectoriesDeleted = await this.deleteSkillFolders(
10168
+ baseDirectory,
10169
+ response.skillFolders
10170
+ );
10171
+ for (const file of uniqueFiles) {
9971
10172
  try {
9972
- if (!file.content) continue;
9973
- const isIncompatible = command33.cliVersion && (this.isVersionConstraintViolated(
9974
- file.content,
9975
- command33.cliVersion
9976
- ) || incompatibleSkillDirs.has(path7.dirname(file.path)));
9977
- if (isIncompatible) {
9978
- const skillName = this.getSkillName(file.content) ?? incompatibleSkillDirs.get(path7.dirname(file.path)) ?? path7.basename(file.path);
9979
- const fullPath = path7.join(baseDirectory, file.path);
9980
- const fileAlreadyInstalled = await this.fileExists(fullPath);
9981
- if (fileAlreadyInstalled) {
9982
- const paths = incompatibleInstalledMap.get(skillName) ?? [];
9983
- paths.push(file.path);
9984
- incompatibleInstalledMap.set(skillName, paths);
9985
- } else {
9986
- if (!result.skippedIncompatibleSkillNames.includes(skillName)) {
9987
- result.skippedIncompatibleSkillNames.push(skillName);
9988
- }
9989
- }
9990
- continue;
10173
+ const changesBefore = result.filesCreated + result.filesUpdated;
10174
+ await this.createOrUpdateFile(
10175
+ baseDirectory,
10176
+ file,
10177
+ result,
10178
+ file.skillFilePermissions
10179
+ );
10180
+ if (result.filesCreated + result.filesUpdated > changesBefore && this.isContentFile(file.path)) {
10181
+ result.contentFilesChanged++;
9991
10182
  }
9992
- await this.createOrUpdateFile(baseDirectory, file, result);
9993
10183
  } catch (error) {
9994
10184
  const errorMsg = error instanceof Error ? error.message : String(error);
9995
10185
  result.errors.push(
@@ -9997,44 +10187,489 @@ var InstallDefaultSkillsUseCase = class {
9997
10187
  );
9998
10188
  }
9999
10189
  }
10190
+ for (const file of response.fileUpdates.delete) {
10191
+ try {
10192
+ const deletedBefore = result.filesDeleted;
10193
+ await this.deleteFile(baseDirectory, file.path, result);
10194
+ if (result.filesDeleted > deletedBefore) {
10195
+ if (file.path.includes(".packmind/standards/") && file.path.endsWith(".md")) {
10196
+ result.standardsRemoved++;
10197
+ result.contentFilesChanged++;
10198
+ } else if (file.path.includes(".packmind/commands/") && file.path.endsWith(".md")) {
10199
+ result.commandsRemoved++;
10200
+ result.contentFilesChanged++;
10201
+ } else if (file.path.includes(".packmind/skills/") && file.path.endsWith(".md")) {
10202
+ result.skillsRemoved++;
10203
+ result.contentFilesChanged++;
10204
+ } else if (file.path.includes(".packmind/recipes/") && file.path.endsWith(".md")) {
10205
+ result.recipesRemoved++;
10206
+ result.contentFilesChanged++;
10207
+ }
10208
+ }
10209
+ } catch (error) {
10210
+ const errorMsg = error instanceof Error ? error.message : String(error);
10211
+ result.errors.push(`Failed to delete ${file.path}: ${errorMsg}`);
10212
+ }
10213
+ }
10000
10214
  } catch (error) {
10001
10215
  const errorMsg = error instanceof Error ? error.message : String(error);
10002
- result.errors.push(`Failed to install default skills: ${errorMsg}`);
10216
+ result.errors.push(`Failed to install packages: ${errorMsg}`);
10217
+ }
10218
+ if (normalizedPackages.length > 0) {
10219
+ await this.configFileRepository.addPackagesToConfig(
10220
+ baseDirectory,
10221
+ normalizedPackages
10222
+ );
10003
10223
  }
10004
- result.incompatibleInstalledSkills = Array.from(
10005
- incompatibleInstalledMap.entries()
10006
- ).map(
10007
- ([skillName, filePaths]) => ({
10008
- skillName,
10009
- filePaths
10010
- })
10011
- );
10012
10224
  return result;
10013
10225
  }
10014
- async createOrUpdateFile(baseDirectory, file, result) {
10226
+ async normalizePackageSlugs(slugs) {
10227
+ return normalizePackageSlugs(slugs, this.spaceService);
10228
+ }
10229
+ async normalizeAndSaveConfigPackages(baseDirectory, config) {
10230
+ const originalSlugs = Object.keys(config.packages);
10231
+ if (originalSlugs.length === 0) return [];
10232
+ const normalizedSlugs = await this.normalizePackageSlugs(originalSlugs);
10233
+ const hasChanges = normalizedSlugs.some(
10234
+ (slug3, i) => slug3 !== originalSlugs[i]
10235
+ );
10236
+ if (hasChanges) {
10237
+ const normalizedPackagesMap = {};
10238
+ for (let i = 0; i < normalizedSlugs.length; i++) {
10239
+ normalizedPackagesMap[normalizedSlugs[i]] = config.packages[originalSlugs[i]];
10240
+ }
10241
+ await this.configFileRepository.updateConfig(
10242
+ baseDirectory,
10243
+ "packages",
10244
+ normalizedPackagesMap
10245
+ );
10246
+ }
10247
+ return normalizedSlugs;
10248
+ }
10249
+ async validatePackageAccess(packages) {
10250
+ const userSpaces = await this.spaceService.getSpaces();
10251
+ const userSpaceSlugs = new Set(userSpaces.map((s) => s.slug));
10252
+ const { host } = this.spaceService.getApiContext();
10253
+ const errors = [];
10254
+ for (const pkg of packages) {
10255
+ const spaceSlug = pkg.startsWith("@") ? pkg.slice(1).split("/")[0] : null;
10256
+ if (!spaceSlug || userSpaceSlugs.has(spaceSlug)) continue;
10257
+ const space = await this.spaceService.getSpaceBySlug(spaceSlug);
10258
+ if (!space || space.type === "private" /* private */) {
10259
+ errors.push(`Package ${pkg} does not exist.`);
10260
+ } else {
10261
+ const organization = await this.packmindGateway.organization.getOrganization();
10262
+ const joinUrl = `${host}/org/${organization.slug}/spaces/${spaceSlug}/join`;
10263
+ errors.push(
10264
+ `You don't have access to space @${spaceSlug}. It is a public space \u2014 you can join at: ${joinUrl}`
10265
+ );
10266
+ }
10267
+ }
10268
+ if (errors.length > 0) {
10269
+ throw new Error(errors.join("\n"));
10270
+ }
10271
+ }
10272
+ async computeJoinSpaceUrl(missingAccessSlugs) {
10273
+ const spaceSlugs = /* @__PURE__ */ new Set();
10274
+ for (const slug3 of missingAccessSlugs) {
10275
+ if (slug3.startsWith("@")) {
10276
+ const spaceSlug2 = slug3.slice(1).split("/")[0];
10277
+ spaceSlugs.add(spaceSlug2);
10278
+ }
10279
+ }
10280
+ if (spaceSlugs.size !== 1) return void 0;
10281
+ const [spaceSlug] = spaceSlugs;
10282
+ const space = await this.spaceService.getSpaceBySlug(spaceSlug);
10283
+ if (!space || space.type !== "open" /* open */) return void 0;
10284
+ const organization = await this.packmindGateway.organization.getOrganization();
10285
+ const { host } = this.spaceService.getApiContext();
10286
+ return `${host}/org/${organization.slug}/spaces/${spaceSlug}/join`;
10287
+ }
10288
+ async createOrUpdateFile(baseDirectory, file, result, skillFilePermissions) {
10015
10289
  const fullPath = path7.join(baseDirectory, file.path);
10016
10290
  const directory = path7.dirname(fullPath);
10017
10291
  await fs5.mkdir(directory, { recursive: true });
10018
10292
  const fileExists = await this.fileExists(fullPath);
10293
+ if (file.content !== void 0) {
10294
+ await this.handleFullContentUpdate(
10295
+ fullPath,
10296
+ file.content,
10297
+ fileExists,
10298
+ result,
10299
+ file.isBase64
10300
+ );
10301
+ } else if (file.sections !== void 0) {
10302
+ await this.handleSectionsUpdate(
10303
+ fullPath,
10304
+ file.sections,
10305
+ fileExists,
10306
+ result,
10307
+ baseDirectory
10308
+ );
10309
+ }
10310
+ if (skillFilePermissions && supportsUnixPermissions()) {
10311
+ await fs5.chmod(fullPath, parsePermissionString(skillFilePermissions));
10312
+ }
10313
+ }
10314
+ async handleFullContentUpdate(fullPath, content, fileExists, result, isBase64) {
10315
+ if (isBase64) {
10316
+ const buffer = Buffer.from(content, "base64");
10317
+ await fs5.writeFile(fullPath, buffer);
10318
+ if (fileExists) {
10319
+ result.filesUpdated++;
10320
+ } else {
10321
+ result.filesCreated++;
10322
+ }
10323
+ return;
10324
+ }
10019
10325
  if (fileExists) {
10020
10326
  const existingContent = await fs5.readFile(fullPath, "utf-8");
10021
- if (existingContent !== file.content) {
10022
- await fs5.writeFile(fullPath, file.content, "utf-8");
10327
+ const commentMarker = this.extractCommentMarker(content);
10328
+ let finalContent;
10329
+ if (!commentMarker) {
10330
+ finalContent = content;
10331
+ } else {
10332
+ finalContent = this.mergeContentWithMarkers(
10333
+ existingContent,
10334
+ content,
10335
+ commentMarker
10336
+ );
10337
+ }
10338
+ if (existingContent !== finalContent) {
10339
+ await fs5.writeFile(fullPath, finalContent, "utf-8");
10023
10340
  result.filesUpdated++;
10024
10341
  }
10025
10342
  } else {
10026
- await fs5.writeFile(fullPath, file.content, "utf-8");
10343
+ await fs5.writeFile(fullPath, content, "utf-8");
10027
10344
  result.filesCreated++;
10028
10345
  }
10029
10346
  }
10030
- async fileExists(filePath) {
10031
- try {
10347
+ async handleSectionsUpdate(fullPath, sections, fileExists, result, baseDirectory) {
10348
+ let currentContent = "";
10349
+ if (fileExists) {
10350
+ currentContent = await fs5.readFile(fullPath, "utf-8");
10351
+ }
10352
+ const mergedContent = mergeSectionsIntoFileContent(
10353
+ currentContent,
10354
+ sections
10355
+ );
10356
+ if (currentContent !== mergedContent) {
10357
+ if (this.isEffectivelyEmpty(mergedContent) && fileExists) {
10358
+ await fs5.unlink(fullPath);
10359
+ result.filesDeleted++;
10360
+ await this.removeEmptyParentDirectories(fullPath, baseDirectory);
10361
+ } else {
10362
+ await fs5.writeFile(fullPath, mergedContent, "utf-8");
10363
+ if (fileExists) {
10364
+ result.filesUpdated++;
10365
+ } else {
10366
+ result.filesCreated++;
10367
+ }
10368
+ }
10369
+ }
10370
+ }
10371
+ async deleteFile(baseDirectory, filePath, result) {
10372
+ const fullPath = path7.join(baseDirectory, filePath);
10373
+ const stat9 = await fs5.stat(fullPath).catch(() => null);
10374
+ if (stat9?.isDirectory()) {
10375
+ await fs5.rm(fullPath, { recursive: true, force: true });
10376
+ result.filesDeleted++;
10377
+ await this.removeEmptyParentDirectories(fullPath, baseDirectory);
10378
+ } else if (stat9?.isFile()) {
10379
+ await fs5.unlink(fullPath);
10380
+ result.filesDeleted++;
10381
+ await this.removeEmptyParentDirectories(fullPath, baseDirectory);
10382
+ }
10383
+ }
10384
+ isContentFile(filePath) {
10385
+ return (filePath.includes(".packmind/standards/") || filePath.includes(".packmind/commands/") || filePath.includes(".packmind/skills/") || filePath.includes(".packmind/recipes/")) && filePath.endsWith(".md");
10386
+ }
10387
+ async fileExists(filePath) {
10388
+ try {
10032
10389
  await fs5.access(filePath);
10033
10390
  return true;
10034
10391
  } catch {
10035
10392
  return false;
10036
10393
  }
10037
10394
  }
10395
+ extractCommentMarker(content) {
10396
+ const startMarkerPattern = /<!--\s*start:\s*([^-]+?)\s*-->/;
10397
+ const match = content.match(startMarkerPattern);
10398
+ return match ? match[1].trim() : null;
10399
+ }
10400
+ mergeContentWithMarkers(existingContent, newContent, commentMarker) {
10401
+ const startMarker = `<!-- start: ${commentMarker} -->`;
10402
+ const endMarker = `<!-- end: ${commentMarker} -->`;
10403
+ const newSectionPattern = new RegExp(
10404
+ `${this.escapeRegex(startMarker)}([\\s\\S]*?)${this.escapeRegex(endMarker)}`
10405
+ );
10406
+ const newSectionMatch = newContent.match(newSectionPattern);
10407
+ const newSectionContent = newSectionMatch ? newSectionMatch[1].trim() : newContent;
10408
+ const existingSectionPattern = new RegExp(
10409
+ `${this.escapeRegex(startMarker)}[\\s\\S]*?${this.escapeRegex(endMarker)}`,
10410
+ "g"
10411
+ );
10412
+ if (existingSectionPattern.test(existingContent)) {
10413
+ return existingContent.replace(
10414
+ existingSectionPattern,
10415
+ `${startMarker}
10416
+ ${newSectionContent}
10417
+ ${endMarker}`
10418
+ );
10419
+ } else {
10420
+ return `${existingContent}
10421
+ ${startMarker}
10422
+ ${newSectionContent}
10423
+ ${endMarker}`;
10424
+ }
10425
+ }
10426
+ isEffectivelyEmpty(content) {
10427
+ const withoutEmptySections = content.replace(
10428
+ /<!--\s*start:\s*[^-]+?\s*-->\s*<!--\s*end:\s*[^-]+?\s*-->/g,
10429
+ ""
10430
+ );
10431
+ return withoutEmptySections.trim() === "";
10432
+ }
10433
+ escapeRegex(str) {
10434
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10435
+ }
10436
+ async deleteSkillFolders(baseDirectory, folders) {
10437
+ let deletedFilesCount = 0;
10438
+ for (const folder of folders) {
10439
+ const fullPath = path7.join(baseDirectory, folder);
10440
+ try {
10441
+ await fs5.access(fullPath);
10442
+ const fileCount = await this.countFilesInDirectory(fullPath);
10443
+ await fs5.rm(fullPath, { recursive: true, force: true });
10444
+ deletedFilesCount += fileCount;
10445
+ await this.removeEmptyParentDirectories(fullPath, baseDirectory);
10446
+ } catch {
10447
+ }
10448
+ }
10449
+ return deletedFilesCount;
10450
+ }
10451
+ async countFilesInDirectory(dirPath) {
10452
+ let count = 0;
10453
+ const entries = await fs5.readdir(dirPath, { withFileTypes: true });
10454
+ for (const entry of entries) {
10455
+ const entryPath = path7.join(dirPath, entry.name);
10456
+ if (entry.isDirectory()) {
10457
+ count += await this.countFilesInDirectory(entryPath);
10458
+ } else {
10459
+ count++;
10460
+ }
10461
+ }
10462
+ return count;
10463
+ }
10464
+ async isDirectoryEmpty(dirPath) {
10465
+ try {
10466
+ const entries = await fs5.readdir(dirPath);
10467
+ return entries.length === 0;
10468
+ } catch {
10469
+ return false;
10470
+ }
10471
+ }
10472
+ async removeEmptyParentDirectories(fullPath, baseDirectory) {
10473
+ const normalizedBase = path7.resolve(baseDirectory);
10474
+ let currentDir = path7.dirname(path7.resolve(fullPath));
10475
+ while (currentDir.startsWith(normalizedBase + path7.sep) && currentDir !== normalizedBase) {
10476
+ const isEmpty = await this.isDirectoryEmpty(currentDir);
10477
+ if (!isEmpty) break;
10478
+ try {
10479
+ await fs5.rmdir(currentDir);
10480
+ } catch {
10481
+ break;
10482
+ }
10483
+ currentDir = path7.dirname(currentDir);
10484
+ }
10485
+ }
10486
+ };
10487
+
10488
+ // apps/cli/src/application/useCases/UninstallUseCase.ts
10489
+ var UninstallUseCase = class {
10490
+ constructor(configFileRepository, spaceService, installUseCase) {
10491
+ this.configFileRepository = configFileRepository;
10492
+ this.spaceService = spaceService;
10493
+ this.installUseCase = installUseCase;
10494
+ }
10495
+ async execute(command33) {
10496
+ const baseDirectory = command33.baseDirectory || process.cwd();
10497
+ const config = await this.configFileRepository.readConfig(baseDirectory);
10498
+ if (!config) {
10499
+ const configFileExists = await this.configFileRepository.configExists(baseDirectory);
10500
+ if (configFileExists) {
10501
+ throw new Error(
10502
+ "packmind.json exists but could not be parsed. Please fix the JSON syntax errors and try again."
10503
+ );
10504
+ }
10505
+ throw new Error(
10506
+ "No packmind.json found in this directory. Run `packmind-cli install <@space/package>` first to install your packages."
10507
+ );
10508
+ }
10509
+ const normalized = await normalizePackageSlugs(
10510
+ command33.packages,
10511
+ this.spaceService
10512
+ );
10513
+ const notInstalled = normalized.filter((pkg) => !(pkg in config.packages));
10514
+ if (notInstalled.length > 0) {
10515
+ const pkgList = notInstalled.map((p) => ` - ${p}`).join("\n");
10516
+ throw new Error(
10517
+ `The following package${notInstalled.length > 1 ? "s are" : " is"} not installed:
10518
+ ${pkgList}`
10519
+ );
10520
+ }
10521
+ const updatedPackages = { ...config.packages };
10522
+ for (const pkg of normalized) {
10523
+ delete updatedPackages[pkg];
10524
+ }
10525
+ await this.configFileRepository.updateConfig(
10526
+ baseDirectory,
10527
+ "packages",
10528
+ updatedPackages
10529
+ );
10530
+ try {
10531
+ return await this.installUseCase.execute({ baseDirectory });
10532
+ } catch (error) {
10533
+ await this.configFileRepository.updateConfig(
10534
+ baseDirectory,
10535
+ "packages",
10536
+ config.packages
10537
+ );
10538
+ throw error;
10539
+ }
10540
+ }
10541
+ };
10542
+
10543
+ // apps/cli/src/application/useCases/InstallDefaultSkillsUseCase.ts
10544
+ var fs6 = __toESM(require("fs/promises"));
10545
+ var path8 = __toESM(require("path"));
10546
+ var import_semver = __toESM(require("semver"));
10547
+ var InstallDefaultSkillsUseCase = class {
10548
+ constructor(repositories) {
10549
+ this.repositories = repositories;
10550
+ }
10551
+ async execute(command33) {
10552
+ const baseDirectory = command33.baseDirectory || process.cwd();
10553
+ const result = {
10554
+ filesCreated: 0,
10555
+ filesUpdated: 0,
10556
+ errors: [],
10557
+ skippedSkillsCount: 0,
10558
+ skippedIncompatibleSkillNames: [],
10559
+ incompatibleInstalledSkills: []
10560
+ };
10561
+ const config = await this.repositories.configFileRepository.readConfig(baseDirectory);
10562
+ const agents = config?.agents;
10563
+ const response = await this.repositories.packmindGateway.skills.getDefaults(
10564
+ {
10565
+ cliVersion: command33.cliVersion,
10566
+ includeBeta: command33.includeBeta,
10567
+ agents
10568
+ }
10569
+ );
10570
+ result.skippedSkillsCount = response.skippedSkillsCount;
10571
+ const incompatibleInstalledMap = /* @__PURE__ */ new Map();
10572
+ const incompatibleSkillDirs = /* @__PURE__ */ new Map();
10573
+ if (command33.cliVersion) {
10574
+ for (const file of response.fileUpdates.createOrUpdate) {
10575
+ if (path8.basename(file.path) === "SKILL.md" && file.content && this.isVersionConstraintViolated(file.content, command33.cliVersion)) {
10576
+ const dir = path8.dirname(file.path);
10577
+ const skillName = this.getSkillName(file.content) ?? path8.basename(dir);
10578
+ incompatibleSkillDirs.set(dir, skillName);
10579
+ }
10580
+ }
10581
+ }
10582
+ try {
10583
+ for (const file of response.fileUpdates.createOrUpdate) {
10584
+ try {
10585
+ if (!file.content) continue;
10586
+ const isIncompatible = command33.cliVersion && (this.isVersionConstraintViolated(
10587
+ file.content,
10588
+ command33.cliVersion
10589
+ ) || this.isUnderIncompatibleSkillDir(
10590
+ file.path,
10591
+ incompatibleSkillDirs
10592
+ ));
10593
+ if (isIncompatible) {
10594
+ const skillName = this.getSkillName(file.content) ?? this.getSkillNameForPath(file.path, incompatibleSkillDirs) ?? path8.basename(file.path);
10595
+ const fullPath = path8.join(baseDirectory, file.path);
10596
+ const fileAlreadyInstalled = await this.fileExists(fullPath);
10597
+ if (fileAlreadyInstalled) {
10598
+ const paths = incompatibleInstalledMap.get(skillName) ?? [];
10599
+ paths.push(file.path);
10600
+ incompatibleInstalledMap.set(skillName, paths);
10601
+ } else {
10602
+ if (!result.skippedIncompatibleSkillNames.includes(skillName)) {
10603
+ result.skippedIncompatibleSkillNames.push(skillName);
10604
+ }
10605
+ }
10606
+ continue;
10607
+ }
10608
+ await this.createOrUpdateFile(baseDirectory, file, result);
10609
+ } catch (error) {
10610
+ const errorMsg = error instanceof Error ? error.message : String(error);
10611
+ result.errors.push(
10612
+ `Failed to create/update ${file.path}: ${errorMsg}`
10613
+ );
10614
+ }
10615
+ }
10616
+ } catch (error) {
10617
+ const errorMsg = error instanceof Error ? error.message : String(error);
10618
+ result.errors.push(`Failed to install default skills: ${errorMsg}`);
10619
+ }
10620
+ result.incompatibleInstalledSkills = Array.from(
10621
+ incompatibleInstalledMap.entries()
10622
+ ).map(
10623
+ ([skillName, filePaths]) => ({
10624
+ skillName,
10625
+ filePaths
10626
+ })
10627
+ );
10628
+ return result;
10629
+ }
10630
+ async createOrUpdateFile(baseDirectory, file, result) {
10631
+ const fullPath = path8.join(baseDirectory, file.path);
10632
+ const directory = path8.dirname(fullPath);
10633
+ await fs6.mkdir(directory, { recursive: true });
10634
+ const fileExists = await this.fileExists(fullPath);
10635
+ if (fileExists) {
10636
+ const existingContent = await fs6.readFile(fullPath, "utf-8");
10637
+ if (existingContent !== file.content) {
10638
+ await fs6.writeFile(fullPath, file.content, "utf-8");
10639
+ result.filesUpdated++;
10640
+ }
10641
+ } else {
10642
+ await fs6.writeFile(fullPath, file.content, "utf-8");
10643
+ result.filesCreated++;
10644
+ }
10645
+ }
10646
+ async fileExists(filePath) {
10647
+ try {
10648
+ await fs6.access(filePath);
10649
+ return true;
10650
+ } catch {
10651
+ return false;
10652
+ }
10653
+ }
10654
+ /**
10655
+ * Returns true if the given file path is inside one of the incompatible skill
10656
+ * directories, including nested subdirectories (e.g. `scripts/`).
10657
+ */
10658
+ isUnderIncompatibleSkillDir(filePath, incompatibleSkillDirs) {
10659
+ return this.getSkillNameForPath(filePath, incompatibleSkillDirs) !== null;
10660
+ }
10661
+ /**
10662
+ * Returns the skill name for the given file path by finding the incompatible
10663
+ * skill directory that contains it (including nested subdirectories).
10664
+ */
10665
+ getSkillNameForPath(filePath, incompatibleSkillDirs) {
10666
+ for (const [dir, skillName] of incompatibleSkillDirs.entries()) {
10667
+ if (filePath === dir || filePath.startsWith(dir + "/") || filePath.startsWith(dir + path8.sep)) {
10668
+ return skillName;
10669
+ }
10670
+ }
10671
+ return null;
10672
+ }
10038
10673
  /**
10039
10674
  * Returns true if the skill's `metadata.packmind-cli-version` constraint
10040
10675
  * is present AND the given CLI version does NOT satisfy it (i.e. the skill
@@ -10148,13 +10783,13 @@ var EnvCredentialsProvider = class {
10148
10783
  };
10149
10784
 
10150
10785
  // apps/cli/src/infra/utils/credentials/FileCredentialsProvider.ts
10151
- var fs6 = __toESM(require("fs"));
10152
- var path8 = __toESM(require("path"));
10786
+ var fs7 = __toESM(require("fs"));
10787
+ var path9 = __toESM(require("path"));
10153
10788
  var os2 = __toESM(require("os"));
10154
10789
  var CREDENTIALS_DIR = ".packmind";
10155
10790
  var CREDENTIALS_FILE = "credentials.json";
10156
10791
  function getCredentialsPath() {
10157
- return path8.join(os2.homedir(), CREDENTIALS_DIR, CREDENTIALS_FILE);
10792
+ return path9.join(os2.homedir(), CREDENTIALS_DIR, CREDENTIALS_FILE);
10158
10793
  }
10159
10794
  var FileCredentialsProvider = class {
10160
10795
  getSourceName() {
@@ -10162,11 +10797,11 @@ var FileCredentialsProvider = class {
10162
10797
  }
10163
10798
  hasCredentials() {
10164
10799
  const credentialsPath = getCredentialsPath();
10165
- if (!fs6.existsSync(credentialsPath)) {
10800
+ if (!fs7.existsSync(credentialsPath)) {
10166
10801
  return false;
10167
10802
  }
10168
10803
  try {
10169
- const content = fs6.readFileSync(credentialsPath, "utf-8");
10804
+ const content = fs7.readFileSync(credentialsPath, "utf-8");
10170
10805
  const credentials = JSON.parse(content);
10171
10806
  return !!credentials.apiKey;
10172
10807
  } catch {
@@ -10175,11 +10810,11 @@ var FileCredentialsProvider = class {
10175
10810
  }
10176
10811
  loadCredentials() {
10177
10812
  const credentialsPath = getCredentialsPath();
10178
- if (!fs6.existsSync(credentialsPath)) {
10813
+ if (!fs7.existsSync(credentialsPath)) {
10179
10814
  return null;
10180
10815
  }
10181
10816
  try {
10182
- const content = fs6.readFileSync(credentialsPath, "utf-8");
10817
+ const content = fs7.readFileSync(credentialsPath, "utf-8");
10183
10818
  const credentials = JSON.parse(content);
10184
10819
  if (!credentials.apiKey) {
10185
10820
  return null;
@@ -10202,13 +10837,13 @@ var FileCredentialsProvider = class {
10202
10837
  }
10203
10838
  };
10204
10839
  function saveCredentials(apiKey) {
10205
- const credentialsDir = path8.join(os2.homedir(), CREDENTIALS_DIR);
10206
- if (!fs6.existsSync(credentialsDir)) {
10207
- fs6.mkdirSync(credentialsDir, { recursive: true, mode: 448 });
10840
+ const credentialsDir = path9.join(os2.homedir(), CREDENTIALS_DIR);
10841
+ if (!fs7.existsSync(credentialsDir)) {
10842
+ fs7.mkdirSync(credentialsDir, { recursive: true, mode: 448 });
10208
10843
  }
10209
10844
  const credentialsPath = getCredentialsPath();
10210
10845
  const credentials = { apiKey };
10211
- fs6.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
10846
+ fs7.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
10212
10847
  mode: 384
10213
10848
  });
10214
10849
  }
@@ -10279,10 +10914,10 @@ async function defaultPromptForCode() {
10279
10914
  input: process.stdin,
10280
10915
  output: process.stdout
10281
10916
  });
10282
- return new Promise((resolve14) => {
10917
+ return new Promise((resolve15) => {
10283
10918
  rl.question("Enter the login code from the browser: ", (answer) => {
10284
10919
  rl.close();
10285
- resolve14(answer.trim());
10920
+ resolve15(answer.trim());
10286
10921
  });
10287
10922
  });
10288
10923
  }
@@ -10316,7 +10951,7 @@ async function defaultExchangeCodeForApiKey(code, host) {
10316
10951
  return await response.json();
10317
10952
  }
10318
10953
  function defaultStartCallbackServer() {
10319
- return new Promise((resolve14, reject) => {
10954
+ return new Promise((resolve15, reject) => {
10320
10955
  let timeoutId = null;
10321
10956
  const server = http.createServer((req, res) => {
10322
10957
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -10329,7 +10964,7 @@ function defaultStartCallbackServer() {
10329
10964
  if (timeoutId) {
10330
10965
  clearTimeout(timeoutId);
10331
10966
  }
10332
- resolve14(code);
10967
+ resolve15(code);
10333
10968
  setImmediate(() => {
10334
10969
  server.close();
10335
10970
  });
@@ -10400,14 +11035,14 @@ var LoginUseCase = class {
10400
11035
  };
10401
11036
 
10402
11037
  // apps/cli/src/application/useCases/LogoutUseCase.ts
10403
- var fs7 = __toESM(require("fs"));
11038
+ var fs8 = __toESM(require("fs"));
10404
11039
  var ENV_VAR_NAME2 = "PACKMIND_API_KEY_V3";
10405
11040
  var LogoutUseCase = class {
10406
11041
  constructor(deps) {
10407
11042
  this.deps = {
10408
11043
  getCredentialsPath: deps?.getCredentialsPath ?? getCredentialsPath,
10409
- fileExists: deps?.fileExists ?? ((path36) => fs7.existsSync(path36)),
10410
- deleteFile: deps?.deleteFile ?? ((path36) => fs7.unlinkSync(path36)),
11044
+ fileExists: deps?.fileExists ?? ((path37) => fs8.existsSync(path37)),
11045
+ deleteFile: deps?.deleteFile ?? ((path37) => fs8.unlinkSync(path37)),
10411
11046
  hasEnvVar: deps?.hasEnvVar ?? (() => !!process.env[ENV_VAR_NAME2])
10412
11047
  };
10413
11048
  }
@@ -10756,8 +11391,8 @@ var SetupMcpUseCase = class {
10756
11391
  };
10757
11392
 
10758
11393
  // apps/cli/src/application/services/McpConfigService.ts
10759
- var fs8 = __toESM(require("fs"));
10760
- var path10 = __toESM(require("path"));
11394
+ var fs9 = __toESM(require("fs"));
11395
+ var path11 = __toESM(require("path"));
10761
11396
  var os3 = __toESM(require("os"));
10762
11397
  var import_child_process3 = require("child_process");
10763
11398
  var McpConfigService = class {
@@ -10804,11 +11439,11 @@ var McpConfigService = class {
10804
11439
  }
10805
11440
  installCursorMcp(config) {
10806
11441
  try {
10807
- const cursorConfigPath = path10.join(os3.homedir(), ".cursor", "mcp.json");
11442
+ const cursorConfigPath = path11.join(os3.homedir(), ".cursor", "mcp.json");
10808
11443
  const cursorConfig = this.buildCursorConfig(config);
10809
11444
  const existingConfig = this.readExistingJsonConfig(cursorConfigPath);
10810
11445
  const mergedConfig = this.mergeConfig(existingConfig, cursorConfig);
10811
- fs8.writeFileSync(cursorConfigPath, JSON.stringify(mergedConfig, null, 2));
11446
+ fs9.writeFileSync(cursorConfigPath, JSON.stringify(mergedConfig, null, 2));
10812
11447
  return { success: true };
10813
11448
  } catch (error) {
10814
11449
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -10817,15 +11452,15 @@ var McpConfigService = class {
10817
11452
  }
10818
11453
  installVSCodeMcp(config) {
10819
11454
  try {
10820
- const vscodeDir = path10.join(this.projectDir, ".vscode");
10821
- if (!fs8.existsSync(vscodeDir)) {
10822
- fs8.mkdirSync(vscodeDir, { recursive: true });
11455
+ const vscodeDir = path11.join(this.projectDir, ".vscode");
11456
+ if (!fs9.existsSync(vscodeDir)) {
11457
+ fs9.mkdirSync(vscodeDir, { recursive: true });
10823
11458
  }
10824
- const vscodeConfigPath = path10.join(vscodeDir, "mcp.json");
11459
+ const vscodeConfigPath = path11.join(vscodeDir, "mcp.json");
10825
11460
  const vscodeConfig = this.buildVSCodeConfig(config);
10826
11461
  const existingConfig = this.readExistingJsonConfig(vscodeConfigPath);
10827
11462
  const mergedConfig = this.mergeVSCodeConfig(existingConfig, vscodeConfig);
10828
- fs8.writeFileSync(vscodeConfigPath, JSON.stringify(mergedConfig, null, 2));
11463
+ fs9.writeFileSync(vscodeConfigPath, JSON.stringify(mergedConfig, null, 2));
10829
11464
  return { success: true };
10830
11465
  } catch (error) {
10831
11466
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -10834,14 +11469,14 @@ var McpConfigService = class {
10834
11469
  }
10835
11470
  installContinueMcp(config) {
10836
11471
  try {
10837
- const continueDir = path10.join(this.projectDir, ".continue");
10838
- const mcpServersDir = path10.join(continueDir, "mcpServers");
10839
- if (!fs8.existsSync(mcpServersDir)) {
10840
- fs8.mkdirSync(mcpServersDir, { recursive: true });
11472
+ const continueDir = path11.join(this.projectDir, ".continue");
11473
+ const mcpServersDir = path11.join(continueDir, "mcpServers");
11474
+ if (!fs9.existsSync(mcpServersDir)) {
11475
+ fs9.mkdirSync(mcpServersDir, { recursive: true });
10841
11476
  }
10842
- const continueConfigPath = path10.join(mcpServersDir, "packmind.yaml");
11477
+ const continueConfigPath = path11.join(mcpServersDir, "packmind.yaml");
10843
11478
  const continueConfig = this.buildContinueYamlConfig(config);
10844
- fs8.writeFileSync(continueConfigPath, continueConfig);
11479
+ fs9.writeFileSync(continueConfigPath, continueConfig);
10845
11480
  return { success: true };
10846
11481
  } catch (error) {
10847
11482
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -10889,8 +11524,8 @@ mcpServers:
10889
11524
  }
10890
11525
  readExistingJsonConfig(filePath) {
10891
11526
  try {
10892
- if (fs8.existsSync(filePath)) {
10893
- const content = fs8.readFileSync(filePath, "utf-8");
11527
+ if (fs9.existsSync(filePath)) {
11528
+ const content = fs9.readFileSync(filePath, "utf-8");
10894
11529
  return JSON.parse(content);
10895
11530
  }
10896
11531
  } catch {
@@ -10923,8 +11558,8 @@ mcpServers:
10923
11558
  };
10924
11559
 
10925
11560
  // apps/cli/src/infra/repositories/ConfigFileRepository.ts
10926
- var fs9 = __toESM(require("fs/promises"));
10927
- var path11 = __toESM(require("path"));
11561
+ var fs10 = __toESM(require("fs/promises"));
11562
+ var path12 = __toESM(require("path"));
10928
11563
  var ConfigFileRepository = class {
10929
11564
  constructor() {
10930
11565
  this.CONFIG_FILENAME = "packmind.json";
@@ -10945,7 +11580,7 @@ var ConfigFileRepository = class {
10945
11580
  async configExists(baseDirectory) {
10946
11581
  const configPath = this.getConfigPath(baseDirectory);
10947
11582
  try {
10948
- await fs9.access(configPath);
11583
+ await fs10.access(configPath);
10949
11584
  return true;
10950
11585
  } catch {
10951
11586
  return false;
@@ -10954,7 +11589,7 @@ var ConfigFileRepository = class {
10954
11589
  async readConfig(baseDirectory) {
10955
11590
  const configPath = this.getConfigPath(baseDirectory);
10956
11591
  try {
10957
- const configContent = await fs9.readFile(configPath, "utf-8");
11592
+ const configContent = await fs10.readFile(configPath, "utf-8");
10958
11593
  const rawConfig = JSON.parse(configContent);
10959
11594
  if (!rawConfig.packages || typeof rawConfig.packages !== "object") {
10960
11595
  throw new Error(
@@ -10988,18 +11623,18 @@ var ConfigFileRepository = class {
10988
11623
  }
10989
11624
  }
10990
11625
  getConfigPath(directory) {
10991
- return path11.join(directory, this.CONFIG_FILENAME);
11626
+ return path12.join(directory, this.CONFIG_FILENAME);
10992
11627
  }
10993
11628
  async writeConfigToPath(configPath, config) {
10994
11629
  const configContent = JSON.stringify(config, null, 2) + "\n";
10995
- await fs9.writeFile(configPath, configContent, "utf-8");
11630
+ await fs10.writeFile(configPath, configContent, "utf-8");
10996
11631
  }
10997
11632
  /**
10998
11633
  * Recursively finds all directories containing packmind.json in descendant folders.
10999
11634
  * Excludes common build/dependency directories (node_modules, .git, dist, etc.)
11000
11635
  */
11001
11636
  async findDescendantConfigs(directory) {
11002
- const normalizedDir = normalizePath2(path11.resolve(directory));
11637
+ const normalizedDir = normalizePath2(path12.resolve(directory));
11003
11638
  return this.searchDescendantsRecursively(normalizedDir);
11004
11639
  }
11005
11640
  async searchDescendantsRecursively(currentDir) {
@@ -11012,7 +11647,7 @@ var ConfigFileRepository = class {
11012
11647
  if (!entry.isDirectory() || this.isExcludedDirectory(entry.name)) {
11013
11648
  continue;
11014
11649
  }
11015
- const entryPath = normalizePath2(path11.join(currentDir, entry.name));
11650
+ const entryPath = normalizePath2(path12.join(currentDir, entry.name));
11016
11651
  const config = await this.readConfig(entryPath);
11017
11652
  if (config) {
11018
11653
  results.push(entryPath);
@@ -11024,7 +11659,7 @@ var ConfigFileRepository = class {
11024
11659
  }
11025
11660
  async tryReadDirectory(directory) {
11026
11661
  try {
11027
- return await fs9.readdir(directory, { withFileTypes: true });
11662
+ return await fs10.readdir(directory, { withFileTypes: true });
11028
11663
  } catch {
11029
11664
  return null;
11030
11665
  }
@@ -11043,21 +11678,21 @@ var ConfigFileRepository = class {
11043
11678
  async readHierarchicalConfig(startDirectory, stopDirectory) {
11044
11679
  const configs = [];
11045
11680
  const configPaths = [];
11046
- const normalizedStart = normalizePath2(path11.resolve(startDirectory));
11047
- const normalizedStop = stopDirectory ? normalizePath2(path11.resolve(stopDirectory)) : null;
11681
+ const normalizedStart = normalizePath2(path12.resolve(startDirectory));
11682
+ const normalizedStop = stopDirectory ? normalizePath2(path12.resolve(stopDirectory)) : null;
11048
11683
  let currentDir = normalizedStart;
11049
11684
  while (true) {
11050
11685
  const config = await this.readConfig(currentDir);
11051
11686
  if (config) {
11052
11687
  configs.push(config);
11053
11688
  configPaths.push(
11054
- normalizePath2(path11.join(currentDir, this.CONFIG_FILENAME))
11689
+ normalizePath2(path12.join(currentDir, this.CONFIG_FILENAME))
11055
11690
  );
11056
11691
  }
11057
11692
  if (normalizedStop !== null && currentDir === normalizedStop) {
11058
11693
  break;
11059
11694
  }
11060
- const parentDir = normalizePath2(path11.dirname(currentDir));
11695
+ const parentDir = normalizePath2(path12.dirname(currentDir));
11061
11696
  if (parentDir === currentDir) {
11062
11697
  break;
11063
11698
  }
@@ -11082,8 +11717,8 @@ var ConfigFileRepository = class {
11082
11717
  * and returns each config with its target path.
11083
11718
  */
11084
11719
  async findAllConfigsInTree(startDirectory, stopDirectory) {
11085
- const normalizedStart = normalizePath2(path11.resolve(startDirectory));
11086
- const normalizedStop = stopDirectory ? normalizePath2(path11.resolve(stopDirectory)) : null;
11720
+ const normalizedStart = normalizePath2(path12.resolve(startDirectory));
11721
+ const normalizedStop = stopDirectory ? normalizePath2(path12.resolve(stopDirectory)) : null;
11087
11722
  const basePath = normalizedStop ?? normalizedStart;
11088
11723
  const searchRoot = normalizedStop ?? normalizedStart;
11089
11724
  const configsMap = /* @__PURE__ */ new Map();
@@ -11109,7 +11744,7 @@ var ConfigFileRepository = class {
11109
11744
  if (stopDir !== null && currentDir === stopDir) {
11110
11745
  break;
11111
11746
  }
11112
- const parentDir = normalizePath2(path11.dirname(currentDir));
11747
+ const parentDir = normalizePath2(path12.dirname(currentDir));
11113
11748
  if (parentDir === currentDir) {
11114
11749
  break;
11115
11750
  }
@@ -11240,7 +11875,7 @@ var ConfigFileRepository = class {
11240
11875
  }
11241
11876
  async tryReadFile(filePath) {
11242
11877
  try {
11243
- return await fs9.readFile(filePath, "utf-8");
11878
+ return await fs10.readFile(filePath, "utf-8");
11244
11879
  } catch (error) {
11245
11880
  if (error.code === "ENOENT") {
11246
11881
  return null;
@@ -11258,8 +11893,8 @@ var ConfigFileRepository = class {
11258
11893
  };
11259
11894
 
11260
11895
  // apps/cli/src/infra/repositories/LockFileRepository.ts
11261
- var fs10 = __toESM(require("fs/promises"));
11262
- var path12 = __toESM(require("path"));
11896
+ var fs11 = __toESM(require("fs/promises"));
11897
+ var path13 = __toESM(require("path"));
11263
11898
  var LockFileRepository = class {
11264
11899
  constructor() {
11265
11900
  this.LOCK_FILENAME = "packmind-lock.json";
@@ -11267,7 +11902,7 @@ var LockFileRepository = class {
11267
11902
  async read(baseDirectory) {
11268
11903
  const lockFilePath = this.getLockFilePath(baseDirectory);
11269
11904
  try {
11270
- const content = await fs10.readFile(lockFilePath, "utf-8");
11905
+ const content = await fs11.readFile(lockFilePath, "utf-8");
11271
11906
  const parsed = JSON.parse(content);
11272
11907
  if (!this.isValidLockFile(parsed)) {
11273
11908
  logWarningConsole(`Malformed lock file: ${lockFilePath}`);
@@ -11293,7 +11928,7 @@ var LockFileRepository = class {
11293
11928
  return typeof obj.installedAt === "string" && Array.isArray(obj.packageSlugs) && Array.isArray(obj.agents) && (obj.targetId === void 0 || typeof obj.targetId === "string") && typeof obj.artifacts === "object" && obj.artifacts !== null && !Array.isArray(obj.artifacts);
11294
11929
  }
11295
11930
  getLockFilePath(baseDirectory) {
11296
- return path12.join(baseDirectory, this.LOCK_FILENAME);
11931
+ return path13.join(baseDirectory, this.LOCK_FILENAME);
11297
11932
  }
11298
11933
  };
11299
11934
 
@@ -11308,17 +11943,12 @@ var ListStandardsUseCase = class {
11308
11943
  const response = await this.packmindGateway.standards.list({
11309
11944
  spaceId: command33.spaceId
11310
11945
  });
11311
- return response.standards.map((s) => ({
11312
- ...s,
11313
- spaceId: command33.spaceId
11314
- }));
11946
+ return response.standards;
11315
11947
  }
11316
11948
  const spaces = await this.spaceService.getSpaces();
11317
11949
  const results = await Promise.all(
11318
11950
  spaces.map(
11319
- (space) => this.packmindGateway.standards.list({ spaceId: space.id }).then(
11320
- (r) => r.standards.map((s) => ({ ...s, spaceId: space.id }))
11321
- )
11951
+ (space) => this.packmindGateway.standards.list({ spaceId: space.id }).then((r) => r.standards)
11322
11952
  )
11323
11953
  );
11324
11954
  return results.flat();
@@ -11363,7 +11993,7 @@ var ListSkillsUseCase = class {
11363
11993
  slug: s.slug,
11364
11994
  name: s.name,
11365
11995
  description: s.description,
11366
- spaceId: command33.spaceId
11996
+ spaceId: s.spaceId
11367
11997
  }));
11368
11998
  }
11369
11999
  const spaces = await this.spaceService.getSpaces();
@@ -11394,7 +12024,7 @@ function normalizeLineEndings(content) {
11394
12024
  }
11395
12025
 
11396
12026
  // apps/cli/src/infra/utils/binaryDetection.ts
11397
- var path13 = __toESM(require("path"));
12027
+ var path14 = __toESM(require("path"));
11398
12028
  var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
11399
12029
  // Images
11400
12030
  ".png",
@@ -11452,7 +12082,7 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
11452
12082
  ".sqlite3"
11453
12083
  ]);
11454
12084
  function isBinaryExtension(filePath) {
11455
- const ext = path13.extname(filePath).toLowerCase();
12085
+ const ext = path14.extname(filePath).toLowerCase();
11456
12086
  return BINARY_EXTENSIONS.has(ext);
11457
12087
  }
11458
12088
  function isBinaryBuffer(buffer) {
@@ -11472,7 +12102,11 @@ function normalizePath3(filePath) {
11472
12102
  }
11473
12103
  var MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
11474
12104
  var MAX_FILE_SIZE_MB = 10;
11475
- var BLACKLIST_PATTERNS = ["**/.DS_Store"];
12105
+ var BLACKLIST_PATTERNS = [
12106
+ "**/.DS_Store",
12107
+ "**/node_modules",
12108
+ "**/node_modules/**"
12109
+ ];
11476
12110
  function isBlacklisted(relativePath) {
11477
12111
  const normalizedPath = relativePath.replace(/\\/g, "/");
11478
12112
  return BLACKLIST_PATTERNS.some(
@@ -11594,17 +12228,17 @@ ${spaceList}`
11594
12228
 
11595
12229
  // apps/cli/src/application/useCases/diffStrategies/CommandDiffStrategy.ts
11596
12230
  var import_diff2 = require("diff");
11597
- var fs12 = __toESM(require("fs/promises"));
11598
- var path15 = __toESM(require("path"));
12231
+ var fs13 = __toESM(require("fs/promises"));
12232
+ var path16 = __toESM(require("path"));
11599
12233
  var CommandDiffStrategy = class {
11600
12234
  supports(file) {
11601
12235
  return file.artifactType === "command";
11602
12236
  }
11603
12237
  async diff(file, baseDirectory) {
11604
- const fullPath = path15.join(baseDirectory, file.path);
12238
+ const fullPath = path16.join(baseDirectory, file.path);
11605
12239
  let localContent;
11606
12240
  try {
11607
- localContent = await fs12.readFile(fullPath, "utf-8");
12241
+ localContent = await fs13.readFile(fullPath, "utf-8");
11608
12242
  } catch {
11609
12243
  return [];
11610
12244
  }
@@ -11634,8 +12268,8 @@ var CommandDiffStrategy = class {
11634
12268
 
11635
12269
  // apps/cli/src/application/useCases/diffStrategies/SkillDiffStrategy.ts
11636
12270
  var import_diff3 = require("diff");
11637
- var fs13 = __toESM(require("fs/promises"));
11638
- var path16 = __toESM(require("path"));
12271
+ var fs14 = __toESM(require("fs/promises"));
12272
+ var path17 = __toESM(require("path"));
11639
12273
 
11640
12274
  // apps/cli/src/application/utils/stripFrontmatter.ts
11641
12275
  var FRONTMATTER_DELIMITER2 = "---";
@@ -11670,7 +12304,7 @@ var SkillDiffStrategy = class {
11670
12304
  async diffNewFiles(skillFolders, serverFiles, baseDirectory) {
11671
12305
  const diffs = [];
11672
12306
  for (const folder of skillFolders) {
11673
- const folderPath = path16.join(baseDirectory, folder);
12307
+ const folderPath = path17.join(baseDirectory, folder);
11674
12308
  const localFiles = await this.listFilesRecursively(folderPath);
11675
12309
  const serverPathsInFolder = new Set(
11676
12310
  serverFiles.filter((f) => f.path.startsWith(folder + "/")).map((f) => f.path)
@@ -11689,7 +12323,7 @@ var SkillDiffStrategy = class {
11689
12323
  if (serverPathsInFolder.has(filePath)) {
11690
12324
  continue;
11691
12325
  }
11692
- const fullPath = path16.join(baseDirectory, filePath);
12326
+ const fullPath = path17.join(baseDirectory, filePath);
11693
12327
  const localRead = await this.tryReadFileBinaryAware(fullPath);
11694
12328
  if (localRead === null) {
11695
12329
  continue;
@@ -11716,7 +12350,7 @@ var SkillDiffStrategy = class {
11716
12350
  return diffs;
11717
12351
  }
11718
12352
  async diffSkillMd(file, baseDirectory) {
11719
- const fullPath = path16.join(baseDirectory, file.path);
12353
+ const fullPath = path17.join(baseDirectory, file.path);
11720
12354
  const localContent = await this.tryReadFile(fullPath);
11721
12355
  if (localContent === null) {
11722
12356
  return [];
@@ -11773,7 +12407,7 @@ var SkillDiffStrategy = class {
11773
12407
  return [];
11774
12408
  }
11775
12409
  const skillFileId = createSkillFileId(file.skillFileId);
11776
- const fullPath = path16.join(baseDirectory, file.path);
12410
+ const fullPath = path17.join(baseDirectory, file.path);
11777
12411
  const localRead = await this.tryReadFileBinaryAware(fullPath);
11778
12412
  const fileRelativePath = this.computeRelativePath(file.path, skillFolders);
11779
12413
  if (localRead === null) {
@@ -11983,14 +12617,14 @@ var SkillDiffStrategy = class {
11983
12617
  }
11984
12618
  async tryReadFile(filePath) {
11985
12619
  try {
11986
- return await fs13.readFile(filePath, "utf-8");
12620
+ return await fs14.readFile(filePath, "utf-8");
11987
12621
  } catch {
11988
12622
  return null;
11989
12623
  }
11990
12624
  }
11991
12625
  async tryReadFileBinaryAware(filePath) {
11992
12626
  try {
11993
- const buffer = await fs13.readFile(filePath);
12627
+ const buffer = await fs14.readFile(filePath);
11994
12628
  if (isBinaryFile(filePath, buffer)) {
11995
12629
  return { content: buffer.toString("base64"), isBase64: true };
11996
12630
  }
@@ -12002,13 +12636,13 @@ var SkillDiffStrategy = class {
12002
12636
  async listFilesRecursively(dirPath, prefix = "") {
12003
12637
  let entries;
12004
12638
  try {
12005
- entries = await fs13.readdir(dirPath);
12639
+ entries = await fs14.readdir(dirPath);
12006
12640
  } catch {
12007
12641
  return [];
12008
12642
  }
12009
12643
  const files = [];
12010
12644
  for (const entry of entries) {
12011
- const fullPath = path16.join(dirPath, entry);
12645
+ const fullPath = path17.join(dirPath, entry);
12012
12646
  const stat9 = await this.tryStatFile(fullPath);
12013
12647
  if (!stat9) {
12014
12648
  continue;
@@ -12028,7 +12662,7 @@ var SkillDiffStrategy = class {
12028
12662
  }
12029
12663
  async tryStatFile(filePath) {
12030
12664
  try {
12031
- const stat9 = await fs13.stat(filePath);
12665
+ const stat9 = await fs14.stat(filePath);
12032
12666
  return { isDirectory: stat9.isDirectory() };
12033
12667
  } catch {
12034
12668
  return null;
@@ -12036,7 +12670,7 @@ var SkillDiffStrategy = class {
12036
12670
  }
12037
12671
  async tryGetPermissions(filePath) {
12038
12672
  try {
12039
- const stat9 = await fs13.stat(filePath);
12673
+ const stat9 = await fs14.stat(filePath);
12040
12674
  return modeToPermissionStringOrDefault(stat9.mode);
12041
12675
  } catch {
12042
12676
  return null;
@@ -12052,8 +12686,8 @@ var SkillDiffStrategy = class {
12052
12686
  };
12053
12687
 
12054
12688
  // apps/cli/src/application/useCases/diffStrategies/StandardDiffStrategy.ts
12055
- var fs14 = __toESM(require("fs/promises"));
12056
- var path17 = __toESM(require("path"));
12689
+ var fs15 = __toESM(require("fs/promises"));
12690
+ var path18 = __toESM(require("path"));
12057
12691
 
12058
12692
  // apps/cli/src/application/utils/parseStandardMd.ts
12059
12693
  var DEPLOYER_PARSERS = [
@@ -12361,10 +12995,10 @@ var StandardDiffStrategy = class {
12361
12995
  return file.artifactType === "standard";
12362
12996
  }
12363
12997
  async diff(file, baseDirectory) {
12364
- const fullPath = path17.join(baseDirectory, file.path);
12998
+ const fullPath = path18.join(baseDirectory, file.path);
12365
12999
  let localContent;
12366
13000
  try {
12367
- localContent = await fs14.readFile(fullPath, "utf-8");
13001
+ localContent = await fs15.readFile(fullPath, "utf-8");
12368
13002
  } catch {
12369
13003
  return [];
12370
13004
  }
@@ -12728,6 +13362,149 @@ var SpaceService = class {
12728
13362
  }
12729
13363
  return defaultSpace;
12730
13364
  }
13365
+ async getSpaceBySlug(slug3) {
13366
+ return this.spaceGateway.getSpaceBySlug(slug3);
13367
+ }
13368
+ getApiContext() {
13369
+ return this.spaceGateway.getApiContext();
13370
+ }
13371
+ };
13372
+
13373
+ // apps/cli/src/infra/repositories/CliOutput.ts
13374
+ init_source();
13375
+ var import_log_update = __toESM(require("log-update"));
13376
+ var CLI_PREFIX2 = "packmind-cli";
13377
+ var CliFormatter = class {
13378
+ static success(message) {
13379
+ return `${source_default.bgGreen.bold(CLI_PREFIX2)} ${source_default.green.bold(message)}`;
13380
+ }
13381
+ static info(message) {
13382
+ return `${source_default.bgBlue.bold(CLI_PREFIX2)} ${source_default.blue(message)}`;
13383
+ }
13384
+ static warning(message) {
13385
+ return `${source_default.bgYellow.bold(CLI_PREFIX2)} ${source_default.yellow.bold(message)}`;
13386
+ }
13387
+ static error(message) {
13388
+ return `${source_default.bgRed.bold(CLI_PREFIX2)} ${source_default.red(message)}`;
13389
+ }
13390
+ static command(command33) {
13391
+ return source_default.yellow(command33);
13392
+ }
13393
+ static loader(text) {
13394
+ return source_default.dim.italic(text);
13395
+ }
13396
+ static header(title) {
13397
+ return source_default.bold.underline(title);
13398
+ }
13399
+ static subHeader(title) {
13400
+ return source_default.bold(title);
13401
+ }
13402
+ static slug(slug3) {
13403
+ return source_default.blue.bold(slug3);
13404
+ }
13405
+ static label(label) {
13406
+ return source_default.dim(label);
13407
+ }
13408
+ };
13409
+ var CliOutput = class {
13410
+ constructor(logger2 = console) {
13411
+ this.logger = logger2;
13412
+ }
13413
+ notifySuccess(message, help) {
13414
+ this.notifyMessage(
13415
+ CliFormatter.success(message),
13416
+ (msg) => this.logger.log(msg),
13417
+ help
13418
+ );
13419
+ }
13420
+ notifyInfo(message, help) {
13421
+ this.notifyMessage(
13422
+ CliFormatter.info(message),
13423
+ (msg) => this.logger.log(msg),
13424
+ help
13425
+ );
13426
+ }
13427
+ notifyWarning(message, help) {
13428
+ this.notifyMessage(
13429
+ CliFormatter.warning(message),
13430
+ (msg) => this.logger.warn(msg),
13431
+ help
13432
+ );
13433
+ }
13434
+ notifyError(message, help) {
13435
+ this.notifyMessage(
13436
+ CliFormatter.error(message),
13437
+ (msg) => this.logger.error(msg),
13438
+ help
13439
+ );
13440
+ }
13441
+ showLoader(message) {
13442
+ this.logger.log(CliFormatter.loader(message));
13443
+ }
13444
+ async withLoader(message, loader) {
13445
+ (0, import_log_update.default)(CliFormatter.loader(message));
13446
+ try {
13447
+ return loader();
13448
+ } finally {
13449
+ import_log_update.default.clear();
13450
+ }
13451
+ }
13452
+ showArtefact(artefact, help) {
13453
+ this.logger.log(CliFormatter.label(artefact.slug));
13454
+ this.logger.log(CliFormatter.header(artefact.title));
13455
+ if (artefact.url) {
13456
+ this.logger.log(CliFormatter.label(artefact.url));
13457
+ }
13458
+ this.logger.log("");
13459
+ if (artefact.description) {
13460
+ this.logger.log(artefact.description);
13461
+ }
13462
+ this.logger.log("");
13463
+ this.displayHelp((msg) => this.logger.log(msg), help);
13464
+ }
13465
+ listArtefacts(title, artefacts, help) {
13466
+ this.logger.log(CliFormatter.header(title));
13467
+ this.logger.log("");
13468
+ this.displayList(artefacts);
13469
+ this.displayHelp((msg) => this.logger.log(msg), help);
13470
+ }
13471
+ listScopedArtefacts(title, scopedArtefacts, help) {
13472
+ this.logger.log(CliFormatter.header(title));
13473
+ this.logger.log("");
13474
+ for (const { title: title2, artefacts } of scopedArtefacts) {
13475
+ this.logger.log(CliFormatter.subHeader(title2));
13476
+ this.logger.log("");
13477
+ this.displayList(artefacts);
13478
+ }
13479
+ this.displayHelp((msg) => this.logger.log(msg), help);
13480
+ }
13481
+ notifyMessage(message, output, help) {
13482
+ output(message);
13483
+ this.displayHelp(output, help);
13484
+ }
13485
+ displayList(artefacts) {
13486
+ for (const artefact of artefacts) {
13487
+ this.logger.log(`- ${CliFormatter.label(artefact.slug)}`);
13488
+ this.logger.log(` Name: ${CliFormatter.header(artefact.title)}`);
13489
+ if (artefact.url) {
13490
+ this.logger.log(` ${CliFormatter.label(artefact.url)}`);
13491
+ }
13492
+ this.logger.log("");
13493
+ }
13494
+ }
13495
+ displayHelp(output, help) {
13496
+ if (help) {
13497
+ output(help.content);
13498
+ if (help.exampleCommand) {
13499
+ output(`
13500
+ Example: ${CliFormatter.command(help.exampleCommand)}`);
13501
+ }
13502
+ if (help.command) {
13503
+ output(`
13504
+ ${CliFormatter.command(help.command)}`);
13505
+ }
13506
+ }
13507
+ }
12731
13508
  };
12732
13509
 
12733
13510
  // apps/cli/src/PackmindCliHexaFactory.ts
@@ -12736,7 +13513,8 @@ var PackmindCliHexaFactory = class {
12736
13513
  this.repositories = {
12737
13514
  packmindGateway: new PackmindGateway(loadApiKey()),
12738
13515
  configFileRepository: new ConfigFileRepository(),
12739
- lockFileRepository: new LockFileRepository()
13516
+ lockFileRepository: new LockFileRepository(),
13517
+ output: new CliOutput()
12740
13518
  };
12741
13519
  this.services = {
12742
13520
  listFiles: new ListFiles(),
@@ -12745,6 +13523,12 @@ var PackmindCliHexaFactory = class {
12745
13523
  diffViolationFilterService: new DiffViolationFilterService(),
12746
13524
  spaceService: new SpaceService(this.repositories.packmindGateway.spaces)
12747
13525
  };
13526
+ const installUseCase = new InstallUseCase(
13527
+ this.repositories.packmindGateway,
13528
+ this.repositories.lockFileRepository,
13529
+ this.repositories.configFileRepository,
13530
+ this.services.spaceService
13531
+ );
12748
13532
  this.useCases = {
12749
13533
  executeSingleFileAst: new ExecuteSingleFileAstUseCase(
12750
13534
  this.services.linterExecutionUseCase
@@ -12762,6 +13546,12 @@ var PackmindCliHexaFactory = class {
12762
13546
  installPackages: new InstallPackagesUseCase(
12763
13547
  this.repositories.packmindGateway
12764
13548
  ),
13549
+ install: installUseCase,
13550
+ uninstall: new UninstallUseCase(
13551
+ this.repositories.configFileRepository,
13552
+ this.services.spaceService,
13553
+ installUseCase
13554
+ ),
12765
13555
  installDefaultSkills: new InstallDefaultSkillsUseCase(this.repositories),
12766
13556
  listPackages: new ListPackagesUseCase(
12767
13557
  this.repositories.packmindGateway,
@@ -12813,6 +13603,11 @@ var PackmindCliHexa = class {
12813
13603
  command33
12814
13604
  );
12815
13605
  };
13606
+ this.notifyArtefactsDistribution = async (command33) => {
13607
+ return this.hexa.repositories.packmindGateway.deployment.notifyArtefactsDistribution(
13608
+ command33
13609
+ );
13610
+ };
12816
13611
  this.logger = logger2;
12817
13612
  try {
12818
13613
  this.hexa = new PackmindCliHexaFactory();
@@ -12830,6 +13625,9 @@ var PackmindCliHexa = class {
12830
13625
  this.logger.info("Destroying PackmindCliHexa");
12831
13626
  this.logger.info("PackmindCliHexa destroyed");
12832
13627
  }
13628
+ get output() {
13629
+ return this.hexa.repositories.output;
13630
+ }
12833
13631
  async getGitRemoteUrl(command33) {
12834
13632
  return this.hexa.useCases.getGitRemoteUrl.execute(command33);
12835
13633
  }
@@ -12845,6 +13643,12 @@ var PackmindCliHexa = class {
12845
13643
  async installPackages(command33) {
12846
13644
  return this.hexa.useCases.installPackages.execute(command33);
12847
13645
  }
13646
+ async install(command33) {
13647
+ return this.hexa.useCases.install.execute(command33);
13648
+ }
13649
+ async uninstall(command33) {
13650
+ return this.hexa.useCases.uninstall.execute(command33);
13651
+ }
12848
13652
  async diffArtefacts(command33) {
12849
13653
  return this.hexa.useCases.diffArtefacts.execute(command33);
12850
13654
  }
@@ -13103,31 +13907,31 @@ var HumanReadableLogger = class {
13103
13907
  var pathModule2 = __toESM(require("path"));
13104
13908
 
13105
13909
  // apps/cli/src/infra/commands/lintHandler.ts
13106
- var fs16 = __toESM(require("fs/promises"));
13910
+ var fs17 = __toESM(require("fs/promises"));
13107
13911
  var pathModule = __toESM(require("path"));
13108
13912
 
13109
13913
  // apps/cli/src/application/services/PackmindIgnoreReader.ts
13110
- var fs15 = __toESM(require("fs/promises"));
13111
- var path18 = __toESM(require("path"));
13914
+ var fs16 = __toESM(require("fs/promises"));
13915
+ var path19 = __toESM(require("path"));
13112
13916
  var IGNORE_FILENAME = ".packmindignore";
13113
13917
  var PackmindIgnoreReader = class {
13114
13918
  async readIgnorePatterns(startDirectory, stopDirectory) {
13115
13919
  const patterns = [];
13116
- const normalizedStart = path18.resolve(startDirectory);
13117
- const normalizedStop = stopDirectory ? path18.resolve(stopDirectory) : null;
13920
+ const normalizedStart = path19.resolve(startDirectory);
13921
+ const normalizedStop = stopDirectory ? path19.resolve(stopDirectory) : null;
13118
13922
  if (normalizedStop === null) {
13119
- const ignoreFile = path18.join(normalizedStart, IGNORE_FILENAME);
13923
+ const ignoreFile = path19.join(normalizedStart, IGNORE_FILENAME);
13120
13924
  return this.parseIgnoreFile(ignoreFile);
13121
13925
  }
13122
13926
  let currentDir = normalizedStart;
13123
13927
  while (true) {
13124
- const ignoreFile = path18.join(currentDir, IGNORE_FILENAME);
13928
+ const ignoreFile = path19.join(currentDir, IGNORE_FILENAME);
13125
13929
  const filePatterns = await this.parseIgnoreFile(ignoreFile);
13126
13930
  patterns.push(...filePatterns);
13127
13931
  if (currentDir === normalizedStop) {
13128
13932
  break;
13129
13933
  }
13130
- const parentDir = path18.dirname(currentDir);
13934
+ const parentDir = path19.dirname(currentDir);
13131
13935
  if (parentDir === currentDir) {
13132
13936
  break;
13133
13937
  }
@@ -13138,7 +13942,7 @@ var PackmindIgnoreReader = class {
13138
13942
  async parseIgnoreFile(filePath) {
13139
13943
  let content;
13140
13944
  try {
13141
- content = await fs15.readFile(filePath, "utf-8");
13945
+ content = await fs16.readFile(filePath, "utf-8");
13142
13946
  } catch (err) {
13143
13947
  if (err.code === "ENOENT") {
13144
13948
  return [];
@@ -13159,7 +13963,7 @@ function isNotLoggedInError(error) {
13159
13963
  }
13160
13964
  async function lintHandler(args2, deps) {
13161
13965
  const {
13162
- path: path36,
13966
+ path: path37,
13163
13967
  draft,
13164
13968
  rule,
13165
13969
  language,
@@ -13181,11 +13985,11 @@ async function lintHandler(args2, deps) {
13181
13985
  throw new Error("option --rule is required to use --draft mode");
13182
13986
  }
13183
13987
  const startedAt = Date.now();
13184
- const targetPath = path36 ?? ".";
13988
+ const targetPath = path37 ?? ".";
13185
13989
  const absolutePath = resolvePath(targetPath);
13186
13990
  let stats;
13187
13991
  try {
13188
- stats = await fs16.stat(absolutePath);
13992
+ stats = await fs17.stat(absolutePath);
13189
13993
  } catch (err) {
13190
13994
  const isNotFound = err.code === "ENOENT";
13191
13995
  const message = isNotFound ? `File or directory "${absolutePath}" does not exist` : `Cannot access "${absolutePath}": ${err.message}`;
@@ -13503,72 +14307,15 @@ function extractWasmFiles() {
13503
14307
 
13504
14308
  // apps/cli/src/main.ts
13505
14309
  var import_dotenv = require("dotenv");
13506
- var fs27 = __toESM(require("fs"));
13507
- var path35 = __toESM(require("path"));
14310
+ var fs28 = __toESM(require("fs"));
14311
+ var path36 = __toESM(require("path"));
13508
14312
 
13509
14313
  // apps/cli/src/infra/commands/InstallCommand.ts
13510
14314
  var import_cmd_ts2 = __toESM(require_cjs());
14315
+ var path20 = __toESM(require("path"));
14316
+ var fs18 = __toESM(require("fs"));
13511
14317
 
13512
14318
  // apps/cli/src/infra/commands/installPackagesHandler.ts
13513
- var fs17 = __toESM(require("fs/promises"));
13514
- var path19 = __toESM(require("path"));
13515
- var { version: CLI_VERSION } = require_package();
13516
- async function notifyDistributionIfInGitRepo(params) {
13517
- const { packmindCliHexa, cwd, packages, log, agents } = params;
13518
- const resolvedGitRoot = params.gitRoot ?? await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
13519
- if (!resolvedGitRoot) {
13520
- return false;
13521
- }
13522
- try {
13523
- const gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(resolvedGitRoot);
13524
- const gitBranch = packmindCliHexa.getCurrentBranch(resolvedGitRoot);
13525
- let relativePath = cwd.startsWith(resolvedGitRoot) ? cwd.slice(resolvedGitRoot.length) : "/";
13526
- if (!relativePath.startsWith("/")) {
13527
- relativePath = "/" + relativePath;
13528
- }
13529
- if (!relativePath.endsWith("/")) {
13530
- relativePath = relativePath + "/";
13531
- }
13532
- await packmindCliHexa.notifyDistribution({
13533
- distributedPackages: packages,
13534
- gitRemoteUrl,
13535
- gitBranch,
13536
- relativePath,
13537
- agents
13538
- });
13539
- log("Successfully notified Packmind of the new distribution");
13540
- return true;
13541
- } catch {
13542
- return false;
13543
- }
13544
- }
13545
- async function installDefaultSkillsIfAtGitRoot(params) {
13546
- const { packmindCliHexa, cwd, log } = params;
13547
- const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
13548
- if (!gitRoot || cwd !== gitRoot) {
13549
- return;
13550
- }
13551
- try {
13552
- log("\nInstalling default skills...");
13553
- const skillsResult = await packmindCliHexa.installDefaultSkills({
13554
- cliVersion: CLI_VERSION
13555
- });
13556
- if (skillsResult.errors.length > 0) {
13557
- skillsResult.errors.forEach((err) => {
13558
- log(` Warning: ${err}`);
13559
- });
13560
- }
13561
- const totalSkillFiles = skillsResult.filesCreated + skillsResult.filesUpdated;
13562
- if (totalSkillFiles > 0) {
13563
- log(
13564
- `Default skills: added ${skillsResult.filesCreated} files, changed ${skillsResult.filesUpdated} files`
13565
- );
13566
- } else if (skillsResult.errors.length === 0) {
13567
- log("Default skills are already up to date");
13568
- }
13569
- } catch {
13570
- }
13571
- }
13572
14319
  function formatOverviewRow(configPath, packages, pathColumnWidth) {
13573
14320
  const paddedPath = configPath.padEnd(pathColumnWidth);
13574
14321
  if (packages.length === 0) {
@@ -13641,1150 +14388,340 @@ ${uniqueCount} unique ${packageWord} currently installed.`);
13641
14388
  };
13642
14389
  }
13643
14390
  }
13644
- async function executeInstallForDirectory(directory, deps) {
13645
- const { packmindCliHexa, log } = deps;
13646
- let configPackages;
13647
- let configAgents;
14391
+
14392
+ // apps/cli/src/infra/commands/InstallCommand.ts
14393
+ var { version: CLI_VERSION } = require_package();
14394
+ function findSubDirectoriesWithPackmindJson(dirPath, recursive) {
14395
+ const result = [];
14396
+ let entries;
13648
14397
  try {
13649
- const fullConfig = await packmindCliHexa.readFullConfig(directory);
13650
- if (fullConfig) {
13651
- configPackages = Object.keys(fullConfig.packages);
13652
- configAgents = fullConfig.agents;
13653
- } else {
13654
- configPackages = [];
13655
- }
13656
- } catch (err) {
13657
- const errorMessage = err instanceof Error ? err.message : String(err);
13658
- return {
13659
- success: false,
13660
- filesCreated: 0,
13661
- filesUpdated: 0,
13662
- filesDeleted: 0,
13663
- notificationSent: false,
13664
- errorMessage: `Failed to parse packmind.json: ${errorMessage}`
13665
- };
13666
- }
13667
- if (configPackages.length === 0) {
13668
- return {
13669
- success: true,
13670
- filesCreated: 0,
13671
- filesUpdated: 0,
13672
- filesDeleted: 0,
13673
- notificationSent: false
13674
- };
14398
+ entries = fs18.readdirSync(dirPath, { withFileTypes: true });
14399
+ } catch {
14400
+ return result;
13675
14401
  }
13676
- const normalizedConfigPackages = await packmindCliHexa.normalizePackageSlugs(configPackages);
13677
- let gitRemoteUrl;
13678
- let gitBranch;
13679
- let relativePath;
13680
- const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(directory);
13681
- if (gitRoot) {
13682
- try {
13683
- gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(gitRoot);
13684
- gitBranch = packmindCliHexa.getCurrentBranch(gitRoot);
13685
- relativePath = directory.startsWith(gitRoot) ? directory.slice(gitRoot.length) : "/";
13686
- if (!relativePath.startsWith("/")) {
13687
- relativePath = "/" + relativePath;
13688
- }
13689
- if (!relativePath.endsWith("/")) {
13690
- relativePath = relativePath + "/";
13691
- }
13692
- } catch {
14402
+ for (const entry of entries) {
14403
+ if (!entry.isDirectory()) continue;
14404
+ const subDir = path20.join(dirPath, entry.name);
14405
+ if (fs18.existsSync(path20.join(subDir, "packmind.json"))) {
14406
+ result.push(subDir);
14407
+ }
14408
+ if (recursive) {
14409
+ result.push(...findSubDirectoriesWithPackmindJson(subDir, true));
13693
14410
  }
13694
14411
  }
14412
+ return result;
14413
+ }
14414
+ function mergeInstallResults(results) {
14415
+ const merged = {
14416
+ filesCreated: 0,
14417
+ filesUpdated: 0,
14418
+ filesDeleted: 0,
14419
+ contentFilesChanged: 0,
14420
+ errors: [],
14421
+ recipesCount: 0,
14422
+ standardsCount: 0,
14423
+ commandsCount: 0,
14424
+ skillsCount: 0,
14425
+ recipesRemoved: 0,
14426
+ standardsRemoved: 0,
14427
+ commandsRemoved: 0,
14428
+ skillsRemoved: 0,
14429
+ skillDirectoriesDeleted: 0,
14430
+ missingAccess: [],
14431
+ joinSpaceUrl: void 0
14432
+ };
14433
+ for (const r of results) {
14434
+ merged.filesCreated += r.filesCreated;
14435
+ merged.filesUpdated += r.filesUpdated;
14436
+ merged.filesDeleted += r.filesDeleted;
14437
+ merged.contentFilesChanged += r.contentFilesChanged;
14438
+ merged.errors.push(...r.errors);
14439
+ merged.recipesCount += r.recipesCount;
14440
+ merged.standardsCount += r.standardsCount;
14441
+ merged.commandsCount += r.commandsCount;
14442
+ merged.skillsCount += r.skillsCount;
14443
+ merged.recipesRemoved += r.recipesRemoved;
14444
+ merged.standardsRemoved += r.standardsRemoved;
14445
+ merged.commandsRemoved += r.commandsRemoved;
14446
+ merged.skillsRemoved += r.skillsRemoved;
14447
+ merged.skillDirectoriesDeleted += r.skillDirectoriesDeleted;
14448
+ merged.missingAccess.push(...r.missingAccess);
14449
+ }
14450
+ merged.missingAccess = [...new Set(merged.missingAccess)];
14451
+ const urlsFromResultsWithMissingAccess = results.filter((r) => r.missingAccess.length > 0).map((r) => r.joinSpaceUrl);
14452
+ const uniqueUrls = new Set(urlsFromResultsWithMissingAccess.filter(Boolean));
14453
+ if (uniqueUrls.size === 1 && !urlsFromResultsWithMissingAccess.some((u) => u === void 0)) {
14454
+ merged.joinSpaceUrl = [...uniqueUrls][0];
14455
+ }
14456
+ return merged;
14457
+ }
14458
+ function buildInstallSummary(result) {
14459
+ const contentParts = [
14460
+ result.standardsCount > 0 ? `${result.standardsCount} ${result.standardsCount === 1 ? "standard" : "standards"}` : null,
14461
+ result.commandsCount > 0 ? `${result.commandsCount} ${result.commandsCount === 1 ? "command" : "commands"}` : null,
14462
+ result.skillsCount > 0 ? `${result.skillsCount} ${result.skillsCount === 1 ? "skill" : "skills"}` : null,
14463
+ result.recipesCount > 0 ? `${result.recipesCount} ${result.recipesCount === 1 ? "recipe" : "recipes"}` : null
14464
+ ].filter(Boolean);
14465
+ const contentChanged = result.contentFilesChanged > 0;
14466
+ if (!contentChanged && contentParts.length === 0) {
14467
+ return "\u2705 Nothing to install";
14468
+ }
14469
+ if (!contentChanged) {
14470
+ return `\u2705 Already up to date \u2014 ${contentParts.join(", ")}`;
14471
+ }
14472
+ if (contentParts.length === 0) {
14473
+ return "\u2705 Packages removed";
14474
+ }
14475
+ return `\u2705 Synced ${contentParts.join(", ")}`;
14476
+ }
14477
+ async function notifyArtefactsDistributionIfInGitRepo(params) {
14478
+ const { packmindCliHexa, dir } = params;
13695
14479
  try {
13696
- const packageCount = normalizedConfigPackages.length;
13697
- const packageWord = packageCount === 1 ? "package" : "packages";
13698
- log(
13699
- ` Fetching ${packageCount} ${packageWord}: ${normalizedConfigPackages.join(", ")}...`
13700
- );
13701
- const result = await packmindCliHexa.installPackages({
13702
- baseDirectory: directory,
13703
- packagesSlugs: normalizedConfigPackages,
13704
- previousPackagesSlugs: normalizedConfigPackages,
13705
- // Pass for consistency
14480
+ const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(dir);
14481
+ if (!gitRoot) return;
14482
+ const lockFilePath = path20.join(dir, "packmind-lock.json");
14483
+ const content = fs18.readFileSync(lockFilePath, "utf-8");
14484
+ const packmindLockFile = JSON.parse(content);
14485
+ const gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(gitRoot);
14486
+ const gitBranch = packmindCliHexa.getCurrentBranch(gitRoot);
14487
+ let relativePath = dir.startsWith(gitRoot) ? dir.slice(gitRoot.length) : "/";
14488
+ if (!relativePath.startsWith("/")) {
14489
+ relativePath = "/" + relativePath;
14490
+ }
14491
+ if (!relativePath.endsWith("/")) {
14492
+ relativePath = relativePath + "/";
14493
+ }
14494
+ await packmindCliHexa.notifyArtefactsDistribution({
13706
14495
  gitRemoteUrl,
13707
14496
  gitBranch,
13708
14497
  relativePath,
13709
- agents: configAgents
13710
- // Pass agents from config if present
14498
+ packmindLockFile
13711
14499
  });
13712
- const parts = [];
13713
- if (result.recipesCount > 0) parts.push(`${result.recipesCount} commands`);
13714
- if (result.standardsCount > 0)
13715
- parts.push(`${result.standardsCount} standards`);
13716
- if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
13717
- log(` Installing ${parts.join(", ") || "artifacts"}...`);
13718
- log(
13719
- ` added ${result.filesCreated} files, changed ${result.filesUpdated} files, removed ${result.filesDeleted} files`
13720
- );
13721
- if (result.errors.length > 0) {
13722
- return {
13723
- success: false,
13724
- filesCreated: result.filesCreated,
13725
- filesUpdated: result.filesUpdated,
13726
- filesDeleted: result.filesDeleted,
13727
- notificationSent: false,
13728
- errorMessage: result.errors.join(", ")
13729
- };
13730
- }
13731
- const configSlugsWereNormalized = configPackages.some(
13732
- (slug3, i) => slug3 !== normalizedConfigPackages[i]
13733
- );
13734
- if (configSlugsWereNormalized) {
13735
- await packmindCliHexa.writeConfig(directory, normalizedConfigPackages);
13736
- }
13737
- const skillDirsDeleted = result.skillDirectoriesDeleted || 0;
13738
- let notificationSent = false;
13739
- if (result.filesCreated > 0 || result.filesUpdated > 0 || result.filesDeleted > 0 || skillDirsDeleted > 0) {
13740
- notificationSent = await notifyDistributionIfInGitRepo({
13741
- packmindCliHexa,
13742
- cwd: directory,
13743
- packages: normalizedConfigPackages,
13744
- agents: configAgents,
13745
- log: () => {
13746
- },
13747
- gitRoot: gitRoot ?? void 0
13748
- });
13749
- }
13750
- return {
13751
- success: true,
13752
- filesCreated: result.filesCreated,
13753
- filesUpdated: result.filesUpdated,
13754
- filesDeleted: result.filesDeleted + skillDirsDeleted,
13755
- notificationSent
13756
- };
13757
- } catch (err) {
13758
- const errorMessage = err instanceof Error ? err.message : String(err);
13759
- return {
13760
- success: false,
13761
- filesCreated: 0,
13762
- filesUpdated: 0,
13763
- filesDeleted: 0,
13764
- notificationSent: false,
13765
- errorMessage
13766
- };
14500
+ } catch {
13767
14501
  }
13768
14502
  }
13769
- async function installPackagesHandler(args2, deps) {
13770
- const { packmindCliHexa, exit, getCwd, log, error } = deps;
13771
- const { packagesSlugs } = args2;
13772
- const rawCwd = getCwd();
13773
- let cwd = rawCwd;
13774
- if (args2.path) {
13775
- const resolvedPath = path19.resolve(rawCwd, args2.path);
13776
- try {
13777
- const stat9 = await fs17.stat(resolvedPath);
13778
- if (!stat9.isDirectory()) {
13779
- logErrorConsole(`Path is not a directory: ${resolvedPath}`);
13780
- exit(1);
13781
- return {
13782
- filesCreated: 0,
13783
- filesUpdated: 0,
13784
- filesDeleted: 0,
13785
- notificationSent: false
13786
- };
13787
- }
13788
- cwd = resolvedPath;
13789
- } catch {
13790
- logErrorConsole(`Path does not exist: ${resolvedPath}`);
13791
- exit(1);
13792
- return {
13793
- filesCreated: 0,
13794
- filesUpdated: 0,
13795
- filesDeleted: 0,
13796
- notificationSent: false
13797
- };
13798
- }
13799
- const relativeToCwd = path19.relative(rawCwd, resolvedPath);
13800
- const displayPath = relativeToCwd ? `./${relativeToCwd}/packmind.json` : `./packmind.json`;
13801
- log(`Installing in ${displayPath}...`);
14503
+ async function installDefaultSkillsIfAtGitRoot(params) {
14504
+ const { packmindCliHexa, cwd } = params;
14505
+ const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
14506
+ if (!gitRoot || cwd !== gitRoot) {
14507
+ return;
13802
14508
  }
13803
- let configPackages;
13804
- let configAgents;
13805
- let configFileExists = false;
13806
14509
  try {
13807
- configFileExists = await packmindCliHexa.configExists(cwd);
13808
- const fullConfig = await packmindCliHexa.readFullConfig(cwd);
13809
- if (fullConfig) {
13810
- const hasNonWildcardVersions = Object.values(fullConfig.packages).some(
13811
- (version2) => version2 !== "*"
13812
- );
13813
- if (hasNonWildcardVersions) {
13814
- logWarningConsole(
13815
- "Package versions are not supported yet, getting the latest version"
13816
- );
13817
- }
13818
- configPackages = Object.keys(fullConfig.packages);
13819
- configAgents = fullConfig.agents;
13820
- } else {
13821
- configPackages = [];
14510
+ logConsole("\nInstalling default skills...");
14511
+ const skillsResult = await packmindCliHexa.installDefaultSkills({
14512
+ cliVersion: CLI_VERSION,
14513
+ baseDirectory: cwd
14514
+ });
14515
+ if (skillsResult.errors.length > 0) {
14516
+ skillsResult.errors.forEach((err) => {
14517
+ logWarningConsole(`Warning: ${err}`);
14518
+ });
13822
14519
  }
13823
- } catch (err) {
13824
- error("ERROR Failed to parse packmind.json");
13825
- if (err instanceof Error) {
13826
- error(`ERROR ${err.message}`);
13827
- } else {
13828
- error(`ERROR ${String(err)}`);
14520
+ const totalSkillFiles = skillsResult.filesCreated + skillsResult.filesUpdated;
14521
+ if (totalSkillFiles > 0) {
14522
+ logConsole(
14523
+ `Default skills: added ${skillsResult.filesCreated} files, changed ${skillsResult.filesUpdated} files`
14524
+ );
14525
+ } else if (skillsResult.errors.length === 0) {
14526
+ logConsole("Default skills are already up to date");
13829
14527
  }
13830
- error("\n\u{1F4A1} Please fix the packmind.json file or delete it to continue.");
13831
- exit(1);
13832
- return {
13833
- filesCreated: 0,
13834
- filesUpdated: 0,
13835
- filesDeleted: 0,
13836
- notificationSent: false
13837
- };
14528
+ } catch {
13838
14529
  }
13839
- let normalizedNewSlugs;
13840
- let normalizedConfigSlugs;
13841
- try {
13842
- normalizedNewSlugs = await packmindCliHexa.normalizePackageSlugs(packagesSlugs);
13843
- normalizedConfigSlugs = await packmindCliHexa.normalizePackageSlugs(configPackages);
13844
- } catch (err) {
13845
- error(`ERROR ${err instanceof Error ? err.message : String(err)}`);
13846
- exit(1);
13847
- return {
13848
- filesCreated: 0,
13849
- filesUpdated: 0,
13850
- filesDeleted: 0,
13851
- notificationSent: false
14530
+ }
14531
+ async function installHandler({
14532
+ installPath,
14533
+ packages,
14534
+ list,
14535
+ show,
14536
+ status
14537
+ }) {
14538
+ const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
14539
+ const packmindCliHexa = new PackmindCliHexa(packmindLogger);
14540
+ if (status) {
14541
+ const deps = {
14542
+ packmindCliHexa,
14543
+ exit: process.exit,
14544
+ getCwd: () => process.cwd(),
14545
+ log: console.log,
14546
+ error: console.error
13852
14547
  };
14548
+ await statusHandler({}, deps);
14549
+ return;
13853
14550
  }
13854
- const allPackages = [
13855
- .../* @__PURE__ */ new Set([...normalizedConfigSlugs, ...normalizedNewSlugs])
13856
- ];
13857
- if (allPackages.length === 0) {
13858
- if (configFileExists) {
13859
- logWarningConsole(
13860
- "config packmind.json is empty, no packages to install"
13861
- );
13862
- } else {
13863
- logWarningConsole("config packmind.json not found");
13864
- }
13865
- log("Usage: packmind-cli install <package-slug> [package-slug...]");
13866
- log(" packmind-cli install --list");
13867
- log("");
13868
- log("Examples:");
13869
- log(" packmind-cli install backend");
13870
- log(" packmind-cli install backend frontend");
13871
- log(" packmind-cli install --list # Show available packages");
13872
- log("");
13873
- log("Install commands and standards from the specified packages.");
13874
- exit(0);
13875
- return {
13876
- filesCreated: 0,
13877
- filesUpdated: 0,
13878
- filesDeleted: 0,
13879
- notificationSent: false
13880
- };
13881
- }
13882
- if (!configFileExists && packagesSlugs.length > 0) {
13883
- log("INFO initializing packmind.json");
13884
- }
13885
- try {
13886
- const packageCount = allPackages.length;
13887
- const packageWord = packageCount === 1 ? "package" : "packages";
13888
- log(
13889
- `Fetching ${packageCount} ${packageWord}: ${allPackages.join(", ")}...`
13890
- );
13891
- let gitRemoteUrl;
13892
- let gitBranch;
13893
- let relativePath;
13894
- const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
13895
- if (gitRoot) {
13896
- try {
13897
- gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(gitRoot);
13898
- gitBranch = packmindCliHexa.getCurrentBranch(gitRoot);
13899
- relativePath = cwd.startsWith(gitRoot) ? cwd.slice(gitRoot.length) : "/";
13900
- if (!relativePath.startsWith("/")) {
13901
- relativePath = "/" + relativePath;
13902
- }
13903
- if (!relativePath.endsWith("/")) {
13904
- relativePath = relativePath + "/";
13905
- }
13906
- } catch {
13907
- }
13908
- }
13909
- const result = await packmindCliHexa.installPackages({
13910
- baseDirectory: cwd,
13911
- packagesSlugs: allPackages,
13912
- previousPackagesSlugs: normalizedConfigSlugs,
13913
- // Pass previous config for change detection
13914
- gitRemoteUrl,
13915
- gitBranch,
13916
- relativePath,
13917
- agents: configAgents
13918
- // Pass agents from config if present (overrides org-level)
13919
- });
13920
- const parts = [];
13921
- if (result.recipesCount > 0) parts.push(`${result.recipesCount} commands`);
13922
- if (result.standardsCount > 0)
13923
- parts.push(`${result.standardsCount} standards`);
13924
- if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
13925
- log(`Installing ${parts.join(", ") || "artifacts"}...`);
13926
- const skillDirsDeleted = result.skillDirectoriesDeleted || 0;
13927
- const totalDeleted = result.filesDeleted + skillDirsDeleted;
13928
- log(
13929
- `
13930
- added ${result.filesCreated} files, changed ${result.filesUpdated} files, removed ${totalDeleted} files`
13931
- );
13932
- if (result.errors.length > 0) {
13933
- log("\n\u26A0\uFE0F Errors encountered:");
13934
- result.errors.forEach((err) => {
13935
- log(` - ${err}`);
13936
- });
13937
- exit(1);
13938
- return {
13939
- filesCreated: result.filesCreated,
13940
- filesUpdated: result.filesUpdated,
13941
- filesDeleted: totalDeleted,
13942
- notificationSent: false
13943
- };
13944
- }
13945
- const configSlugsWereNormalized = configPackages.some(
13946
- (slug3, i) => slug3 !== normalizedConfigSlugs[i]
13947
- );
13948
- const newPackages = normalizedNewSlugs.filter(
13949
- (slug3) => !normalizedConfigSlugs.includes(slug3)
13950
- );
13951
- if (configSlugsWereNormalized) {
13952
- await packmindCliHexa.writeConfig(cwd, allPackages);
13953
- } else if (newPackages.length > 0) {
13954
- await packmindCliHexa.addPackagesToConfig(cwd, newPackages);
13955
- }
13956
- let notificationSent = false;
13957
- if (result.filesCreated > 0 || result.filesUpdated > 0 || result.filesDeleted > 0 || skillDirsDeleted > 0) {
13958
- notificationSent = await notifyDistributionIfInGitRepo({
13959
- packmindCliHexa,
13960
- cwd,
13961
- packages: allPackages,
13962
- agents: configAgents,
13963
- log
13964
- });
13965
- }
13966
- await installDefaultSkillsIfAtGitRoot({
13967
- packmindCliHexa,
13968
- cwd,
13969
- log
13970
- });
13971
- if (deps.playbookLocalRepository) {
13972
- deps.playbookLocalRepository.clearAll();
13973
- }
13974
- return {
13975
- filesCreated: result.filesCreated,
13976
- filesUpdated: result.filesUpdated,
13977
- filesDeleted: totalDeleted,
13978
- notificationSent
13979
- };
13980
- } catch (err) {
13981
- error("\n\u274C Failed to install content:");
13982
- if (err instanceof Error) {
13983
- const errorObj = err;
13984
- if (errorObj.statusCode === 400) {
13985
- error(` ${errorObj.message}`);
13986
- error("\n\u{1F4A1} This is a validation error. Please check:");
13987
- error(" - The command syntax is correct");
13988
- error(" - You have provided at least one package slug");
13989
- error(" - Your packmind.json file contains valid package slugs");
13990
- } else if (errorObj.statusCode === 404) {
13991
- error(` ${errorObj.message}`);
13992
- if (configFileExists && configPackages.length > 0) {
13993
- const missingPackages = allPackages.filter(
13994
- (pkg) => configPackages.includes(pkg)
13995
- );
13996
- if (missingPackages.length > 0) {
13997
- error(
13998
- "\n\u{1F4A1} Either remove the following package(s) from packmind.json:"
13999
- );
14000
- missingPackages.forEach((pkg) => {
14001
- error(` "${pkg}"`);
14002
- });
14003
- error(" Or ensure that:");
14004
- error(" - The package slug exists and is correctly spelled");
14005
- error(" - The package exists in your organization");
14006
- error(" - You have the correct API key configured");
14007
- } else {
14008
- error("\n\u{1F4A1} Troubleshooting tips:");
14009
- error(
14010
- " - Check if the package slug exists and is correctly spelled"
14011
- );
14012
- error(" - Check that the package exists in your organization");
14013
- error(" - Ensure you have the correct API key configured");
14014
- }
14015
- } else {
14016
- error("\n\u{1F4A1} Troubleshooting tips:");
14017
- error(
14018
- " - Check if the package slug exists and is correctly spelled"
14019
- );
14020
- error(" - Check that the package exists in your organization");
14021
- error(" - Ensure you have the correct API key configured");
14022
- }
14023
- } else {
14024
- error(` ${errorObj.message}`);
14025
- const apiErrorObj = err;
14026
- if (apiErrorObj.response?.data?.message) {
14027
- error(`
14028
- Details: ${apiErrorObj.response.data.message}`);
14029
- }
14030
- error("\n\u{1F4A1} Troubleshooting tips:");
14031
- error(" - Verify that the package slugs are correct");
14032
- error(" - Check that the packages exist in your organization");
14033
- error(" - Ensure you have the correct API key configured");
14034
- }
14035
- } else {
14036
- error(` ${String(err)}`);
14037
- }
14038
- exit(1);
14039
- return {
14040
- filesCreated: 0,
14041
- filesUpdated: 0,
14042
- filesDeleted: 0,
14043
- notificationSent: false
14044
- };
14045
- }
14046
- }
14047
- async function uninstallPackagesHandler(args2, deps) {
14048
- const { packmindCliHexa, exit, getCwd, log, error } = deps;
14049
- const { packagesSlugs } = args2;
14050
- const cwd = getCwd();
14051
- if (!packagesSlugs || packagesSlugs.length === 0) {
14052
- error("\u274C No packages specified.");
14053
- log("");
14054
- log("Usage: packmind-cli uninstall <package-slug> [package-slug...]");
14055
- log(" packmind-cli remove <package-slug> [package-slug...]");
14056
- log("");
14057
- log("Examples:");
14058
- log(" packmind-cli uninstall backend");
14059
- log(" packmind-cli remove backend frontend");
14060
- exit(1);
14061
- return {
14062
- filesDeleted: 0,
14063
- packagesUninstalled: []
14064
- };
14065
- }
14066
- let configPackages;
14067
- let configAgents;
14068
- let configFileExists = false;
14069
- try {
14070
- configFileExists = await packmindCliHexa.configExists(cwd);
14071
- const fullConfig = await packmindCliHexa.readFullConfig(cwd);
14072
- if (fullConfig) {
14073
- configPackages = fullConfig.packages;
14074
- configAgents = fullConfig.agents;
14075
- } else {
14076
- configPackages = {};
14077
- }
14078
- } catch (err) {
14079
- error("\u274C Failed to read packmind.json");
14080
- if (err instanceof Error) {
14081
- error(` ${err.message}`);
14082
- } else {
14083
- error(` ${String(err)}`);
14084
- }
14085
- error("\n\u{1F4A1} Please fix the packmind.json file or delete it to continue.");
14086
- exit(1);
14087
- return {
14088
- filesDeleted: 0,
14089
- packagesUninstalled: []
14090
- };
14091
- }
14092
- if (Object.keys(configPackages).length === 0) {
14093
- if (configFileExists) {
14094
- error("\u274C packmind.json is empty.");
14095
- } else {
14096
- error("\u274C No packmind.json found in current directory.");
14097
- }
14098
- log("");
14099
- log("\u{1F4A1} There are no packages to uninstall.");
14100
- log(" To install packages, run: packmind-cli install <package-slug>");
14101
- exit(1);
14102
- return {
14103
- filesDeleted: 0,
14104
- packagesUninstalled: []
14105
- };
14106
- }
14107
- let normalizedRequestedSlugs;
14108
- let normalizedConfigSlugs;
14109
- try {
14110
- normalizedRequestedSlugs = await packmindCliHexa.normalizePackageSlugs(packagesSlugs);
14111
- normalizedConfigSlugs = await packmindCliHexa.normalizePackageSlugs(
14112
- Object.keys(configPackages)
14113
- );
14114
- } catch (err) {
14115
- error(`\u274C ${err instanceof Error ? err.message : String(err)}`);
14116
- exit(1);
14117
- return {
14118
- filesDeleted: 0,
14119
- packagesUninstalled: []
14120
- };
14121
- }
14122
- const normalizedToOriginalConfigKey = /* @__PURE__ */ new Map();
14123
- Object.keys(configPackages).forEach((originalKey, index) => {
14124
- normalizedToOriginalConfigKey.set(
14125
- normalizedConfigSlugs[index],
14126
- originalKey
14127
- );
14128
- });
14129
- const packagesToUninstall = normalizedRequestedSlugs.filter((slug3) => normalizedToOriginalConfigKey.has(slug3)).map((slug3) => normalizedToOriginalConfigKey.get(slug3));
14130
- const notInstalledPackages = packagesSlugs.filter(
14131
- (_, i) => !normalizedToOriginalConfigKey.has(normalizedRequestedSlugs[i])
14132
- );
14133
- if (notInstalledPackages.length > 0) {
14134
- const packageWord = notInstalledPackages.length === 1 ? "package" : "packages";
14135
- log(
14136
- `\u26A0\uFE0F Warning: The following ${packageWord} ${notInstalledPackages.length === 1 ? "is" : "are"} not installed:`
14137
- );
14138
- notInstalledPackages.forEach((pkg) => {
14139
- log(` - ${pkg}`);
14140
- });
14141
- log("");
14142
- }
14143
- if (packagesToUninstall.length === 0) {
14144
- error("\u274C No packages to uninstall.");
14145
- exit(1);
14146
- return {
14147
- filesDeleted: 0,
14148
- packagesUninstalled: []
14149
- };
14150
- }
14151
- try {
14152
- const packageCount = packagesToUninstall.length;
14153
- const packageWord = packageCount === 1 ? "package" : "packages";
14154
- log(
14155
- `Uninstalling ${packageCount} ${packageWord}: ${packagesToUninstall.join(", ")}...`
14156
- );
14157
- const remainingPackages = Object.keys(configPackages).filter(
14158
- (pkg) => !packagesToUninstall.includes(pkg)
14159
- );
14160
- let filesDeleted = 0;
14161
- if (remainingPackages.length === 0) {
14162
- log("Removing all packages and cleaning up...");
14163
- const result = await packmindCliHexa.installPackages({
14164
- baseDirectory: cwd,
14165
- packagesSlugs: [],
14166
- previousPackagesSlugs: Object.keys(configPackages),
14167
- agents: configAgents
14168
- });
14169
- log(`
14170
- removed ${result.filesDeleted} files`);
14171
- if (result.errors.length > 0) {
14172
- log("\n\u26A0\uFE0F Errors encountered:");
14173
- result.errors.forEach((err) => {
14174
- log(` - ${err}`);
14175
- });
14176
- exit(1);
14177
- return {
14178
- filesDeleted: result.filesDeleted,
14179
- packagesUninstalled: packagesToUninstall
14180
- };
14181
- }
14182
- filesDeleted = result.filesDeleted;
14183
- } else {
14184
- const result = await packmindCliHexa.installPackages({
14185
- baseDirectory: cwd,
14186
- packagesSlugs: remainingPackages,
14187
- previousPackagesSlugs: Object.keys(configPackages),
14188
- agents: configAgents
14189
- });
14190
- if (result.recipesCount > 0 || result.standardsCount > 0) {
14191
- log(
14192
- `Removing ${result.recipesCount} commands and ${result.standardsCount} standards...`
14193
- );
14194
- }
14195
- log(`
14196
- removed ${result.filesDeleted} files`);
14197
- if (result.errors.length > 0) {
14198
- log("\n\u26A0\uFE0F Errors encountered:");
14199
- result.errors.forEach((err) => {
14200
- log(` - ${err}`);
14201
- });
14202
- exit(1);
14203
- return {
14204
- filesDeleted: result.filesDeleted,
14205
- packagesUninstalled: packagesToUninstall
14206
- };
14207
- }
14208
- filesDeleted = result.filesDeleted;
14209
- }
14210
- await packmindCliHexa.writeConfig(cwd, remainingPackages);
14211
- await notifyDistributionIfInGitRepo({
14212
- packmindCliHexa,
14213
- cwd,
14214
- packages: remainingPackages,
14215
- log
14216
- });
14217
- log("");
14218
- if (packagesToUninstall.length === 1) {
14219
- log(`\u2713 Package '${packagesToUninstall[0]}' has been uninstalled.`);
14220
- } else {
14221
- log(`\u2713 ${packagesToUninstall.length} packages have been uninstalled.`);
14222
- }
14223
- if (remainingPackages.length === 0) {
14224
- log("");
14225
- log("\u{1F4A1} All packages have been uninstalled.");
14226
- log(" Your packmind.json still exists but contains no packages.");
14227
- }
14228
- return {
14229
- filesDeleted,
14230
- packagesUninstalled: packagesToUninstall
14231
- };
14232
- } catch (err) {
14233
- error("\n\u274C Failed to uninstall packages:");
14234
- if (err instanceof Error) {
14235
- error(` ${err.message}`);
14236
- } else {
14237
- error(` ${String(err)}`);
14238
- }
14239
- exit(1);
14240
- return {
14241
- filesDeleted: 0,
14242
- packagesUninstalled: []
14243
- };
14244
- }
14245
- }
14246
- async function recursiveInstallHandler(args2, deps) {
14247
- const { packmindCliHexa, exit, getCwd, log, error } = deps;
14248
- const cwd = getCwd();
14249
- const result = {
14250
- directoriesProcessed: 0,
14251
- totalFilesCreated: 0,
14252
- totalFilesUpdated: 0,
14253
- totalFilesDeleted: 0,
14254
- totalNotifications: 0,
14255
- errors: []
14256
- };
14257
- let startDirectory = cwd;
14258
- if (args2.path) {
14259
- const resolvedPath = path19.resolve(cwd, args2.path);
14260
- try {
14261
- const stat9 = await fs17.stat(resolvedPath);
14262
- if (!stat9.isDirectory()) {
14263
- logErrorConsole(`Path is not a directory: ${resolvedPath}`);
14264
- exit(1);
14265
- return result;
14266
- }
14267
- startDirectory = resolvedPath;
14268
- } catch {
14269
- logErrorConsole(`Path does not exist: ${resolvedPath}`);
14270
- exit(1);
14271
- return result;
14272
- }
14273
- }
14274
- try {
14275
- const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
14276
- const basePath = args2.path ? startDirectory : gitRoot ?? cwd;
14277
- const allConfigs = await packmindCliHexa.findAllConfigsInTree(
14278
- startDirectory,
14279
- basePath
14280
- );
14281
- if (!allConfigs.hasConfigs) {
14282
- log("No packmind.json files found in this repository.");
14283
- log("");
14284
- log("Usage: packmind-cli install");
14285
- log("");
14286
- log(
14287
- "This command requires at least one packmind.json file in the repository."
14288
- );
14289
- log("Create a packmind.json file first:");
14290
- log("");
14291
- log(" packmind-cli install <package-slug>");
14292
- exit(0);
14293
- return result;
14294
- }
14295
- const sortedConfigs = [...allConfigs.configs].sort(
14296
- (a, b) => a.targetPath.localeCompare(b.targetPath)
14297
- );
14298
- log(`Found ${sortedConfigs.length} packmind.json file(s) to process
14299
- `);
14300
- for (const config of sortedConfigs) {
14301
- const displayPath = args2.path ? computeDisplayPath(
14302
- config.absoluteTargetPath === cwd ? "/" : config.absoluteTargetPath.startsWith(cwd + "/") ? config.absoluteTargetPath.slice(cwd.length) : config.targetPath
14303
- ) : computeDisplayPath(config.targetPath);
14304
- log(`Installing in ${displayPath}...`);
14305
- const installResult = await executeInstallForDirectory(
14306
- config.absoluteTargetPath,
14307
- { packmindCliHexa, getCwd, log, error }
14308
- );
14309
- result.directoriesProcessed++;
14310
- result.totalFilesCreated += installResult.filesCreated;
14311
- result.totalFilesUpdated += installResult.filesUpdated;
14312
- result.totalFilesDeleted += installResult.filesDeleted;
14313
- if (installResult.notificationSent) {
14314
- result.totalNotifications++;
14315
- }
14316
- if (!installResult.success && installResult.errorMessage) {
14317
- result.errors.push({
14318
- directory: displayPath,
14319
- message: installResult.errorMessage
14320
- });
14321
- error(` Error: ${installResult.errorMessage}`);
14322
- }
14323
- log("");
14324
- }
14325
- const dirWord = result.directoriesProcessed === 1 ? "directory" : "directories";
14326
- log(
14327
- `Summary: ${result.directoriesProcessed} ${dirWord} processed, ${result.totalFilesCreated} files added, ${result.totalFilesUpdated} changed, ${result.totalFilesDeleted} removed`
14328
- );
14329
- if (result.totalNotifications > 0) {
14330
- const distWord = result.totalNotifications === 1 ? "distribution" : "distributions";
14331
- log(`Notified Packmind of ${result.totalNotifications} ${distWord}`);
14332
- }
14333
- if (result.errors.length > 0) {
14334
- log("");
14335
- log(`\u26A0\uFE0F ${result.errors.length} error(s) encountered:`);
14336
- result.errors.forEach((err) => {
14337
- log(` - ${err.directory}: ${err.message}`);
14338
- });
14339
- exit(1);
14340
- return result;
14341
- }
14342
- if (deps.playbookLocalRepository) {
14343
- deps.playbookLocalRepository.clearAll();
14344
- }
14345
- exit(0);
14346
- return result;
14347
- } catch (err) {
14348
- error("\n\u274C Failed to run recursive install:");
14349
- if (err instanceof Error) {
14350
- error(` ${err.message}`);
14351
- } else {
14352
- error(` ${String(err)}`);
14353
- }
14354
- exit(1);
14355
- return result;
14356
- }
14357
- }
14358
-
14359
- // apps/cli/src/infra/utils/spaceFilterUtils.ts
14360
- function resolveSpaceFromArgs(spaceArg, spaces) {
14361
- if (!spaceArg) return null;
14362
- const slug3 = spaceArg.startsWith("@") ? spaceArg.slice(1) : spaceArg;
14363
- return spaces.find((s) => s.slug === slug3) ?? null;
14364
- }
14365
-
14366
- // apps/cli/src/infra/utils/urlBuilderUtils.ts
14367
- function resolveUrlBuilder(buildArtifactPath) {
14368
- const apiKey = loadApiKey();
14369
- if (!apiKey) return () => null;
14370
- const decoded = decodeApiKey(apiKey);
14371
- const orgSlug = decoded?.jwt?.organization?.slug;
14372
- if (!decoded?.host || !orgSlug) return () => null;
14373
- return (spaceSlug, artifactId) => `${decoded.host}/org/${orgSlug}/space/${spaceSlug}/${buildArtifactPath(artifactId)}`;
14374
- }
14375
-
14376
- // apps/cli/src/infra/commands/packages/listPackagesHandler.ts
14377
- function logPackageEntry(pkg, fullSlug, spaceSlug, buildUrl) {
14378
- logConsole(`- ${formatSlug(fullSlug)}`);
14379
- logConsole(` ${formatLabel("Name:")} ${pkg.name}`);
14380
- const url = buildUrl(spaceSlug, pkg.id);
14381
- if (url) {
14382
- logConsole(` ${formatLabel("Link:")} ${url}`);
14383
- }
14384
- if (pkg.description) {
14385
- const lines = pkg.description.trim().split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
14386
- const [first, ...rest] = lines;
14387
- logConsole(` ${formatLabel("Description:")} ${first}`);
14388
- rest.forEach((l) => logConsole(` ${l}`));
14389
- }
14390
- }
14391
- function groupPackagesBySpace(packages, spaces) {
14392
- const spaceMap = new Map(
14393
- spaces.map((s) => [s.id, s])
14394
- );
14395
- const groupsMap = /* @__PURE__ */ new Map();
14396
- for (const pkg of packages) {
14397
- const space = spaceMap.get(pkg.spaceId);
14398
- if (!space) {
14399
- continue;
14400
- }
14401
- let group = groupsMap.get(space.id);
14402
- if (!group) {
14403
- group = { space, pkgs: [] };
14404
- groupsMap.set(space.id, group);
14405
- }
14406
- group.pkgs.push(pkg);
14551
+ if (list) {
14552
+ logErrorConsole('Command "packmind-cli install --list" has been removed.');
14553
+ logConsole(`Use ${formatCommand("packmind-cli packages list")} instead.`);
14554
+ process.exit(1);
14407
14555
  }
14408
- return [...groupsMap.values()].sort(
14409
- (a, b) => a.space.name.localeCompare(b.space.name)
14410
- );
14411
- }
14412
- function displayGroupedPackages(packages, spaces, buildUrl) {
14413
- const groups = groupPackagesBySpace(packages, spaces);
14414
- let firstSlug = null;
14415
- for (const { space, pkgs } of groups) {
14416
- logConsole(`Space "${space.name}":
14417
- `);
14418
- for (const pkg of [...pkgs].sort((a, b) => a.slug.localeCompare(b.slug))) {
14419
- const fullSlug = `@${space.slug}/${pkg.slug}`;
14420
- firstSlug ??= fullSlug;
14421
- logPackageEntry(pkg, fullSlug, space.slug, buildUrl);
14422
- logConsole("");
14423
- }
14556
+ if (show) {
14557
+ const showCommand = `packmind-cli packages show ${show}`;
14558
+ logErrorConsole('Command "packmind-cli install --show" has been removed.');
14559
+ logConsole(`Use ${formatCommand(showCommand)} instead.`);
14560
+ process.exit(1);
14424
14561
  }
14425
- return firstSlug ?? formatSlug(packages[0].slug);
14426
- }
14427
- async function listPackagesHandler(args2, deps) {
14428
- const { packmindCliHexa, exit } = deps;
14429
- try {
14430
- logInfoConsole("Fetching available packages...");
14431
- const allSpaces = await packmindCliHexa.getSpaces();
14432
- if (!allSpaces || allSpaces.length === 0) {
14433
- throw new Error("Unable to list organization spaces.");
14434
- }
14435
- const matchedSpace = resolveSpaceFromArgs(args2.space, allSpaces);
14436
- if (args2.space && !matchedSpace) {
14437
- logErrorConsole(`Space "@${args2.space}" not found.`);
14438
- logInfoConsole(
14439
- `Available spaces: ${allSpaces.map((s) => `@${s.slug}`).join(", ")}`
14440
- );
14441
- exit(1);
14562
+ const cwd = installPath ? path20.resolve(process.cwd(), installPath) : process.cwd();
14563
+ if (installPath) {
14564
+ if (!fs18.existsSync(cwd)) {
14565
+ logErrorConsole(`Path does not exist: ${cwd}`);
14566
+ process.exit(1);
14442
14567
  return;
14443
14568
  }
14444
- const packages = await packmindCliHexa.listPackages(
14445
- matchedSpace ? { spaceId: matchedSpace.id } : {}
14446
- );
14447
- const spaces = matchedSpace ? [matchedSpace] : allSpaces;
14448
- if (packages.length === 0) {
14449
- logConsole(
14450
- matchedSpace ? `No packages found in space "@${matchedSpace.slug}".` : "No packages found."
14451
- );
14452
- exit(0);
14569
+ if (!fs18.statSync(cwd).isDirectory()) {
14570
+ logErrorConsole(`Path is not a directory: ${cwd}`);
14571
+ process.exit(1);
14453
14572
  return;
14454
14573
  }
14455
- const buildUrl = resolveUrlBuilder((id) => `packages/${id}`);
14456
- logConsole("\nAvailable packages:\n");
14457
- const exampleSlug = displayGroupedPackages(packages, spaces, buildUrl);
14458
- logConsole("How to install a package:\n");
14459
- logConsole(` ${formatCommand(`packmind-cli install ${exampleSlug}`)}`);
14460
- exit(0);
14461
- } catch (err) {
14462
- logErrorConsole("Failed to list packages:");
14463
- if (err instanceof Error) {
14464
- logErrorConsole(err.message);
14465
- } else {
14466
- logErrorConsole(String(err));
14467
- }
14468
- exit(1);
14469
- }
14470
- }
14471
-
14472
- // apps/cli/src/infra/utils/packageSlugUtils.ts
14473
- function parsePackageSlug(slug3) {
14474
- if (!slug3.startsWith("@")) return null;
14475
- const slash = slug3.indexOf("/", 1);
14476
- if (slash === -1) return null;
14477
- return { spaceSlug: slug3.slice(1, slash), pkgSlug: slug3.slice(slash + 1) };
14478
- }
14479
-
14480
- // apps/cli/src/infra/commands/packages/showPackageHandler.ts
14481
- function isNotFoundError(err) {
14482
- return err instanceof Error && err.message.includes("does not exist");
14483
- }
14484
- async function resolvePackage(slug3, packmindCliHexa) {
14485
- const allSpaces = await packmindCliHexa.getSpaces();
14486
- const parsed = parsePackageSlug(slug3);
14487
- if (parsed) {
14488
- const { spaceSlug, pkgSlug } = parsed;
14489
- const matchedSpace = allSpaces.find((s) => s.slug === spaceSlug);
14490
- if (!matchedSpace) {
14491
- throw new Error(`Space '@${spaceSlug}' not found.`);
14492
- }
14493
- let pkg;
14494
- try {
14495
- pkg = await packmindCliHexa.getPackageBySlug({
14496
- slug: pkgSlug,
14497
- spaceId: matchedSpace.id
14498
- });
14499
- } catch (err) {
14500
- if (isNotFoundError(err)) {
14501
- throw new Error(
14502
- `Package '${pkgSlug}' not found in space '@${spaceSlug}'.`
14503
- );
14504
- }
14505
- throw err;
14506
- }
14507
- return { pkg, fullSlug: `@${spaceSlug}/${pkgSlug}` };
14508
14574
  }
14509
- const results = await Promise.allSettled(
14510
- allSpaces.map(async (space) => ({
14511
- pkg: await packmindCliHexa.getPackageBySlug({
14512
- slug: slug3,
14513
- spaceId: space.id
14514
- }),
14515
- spaceSlug: space.slug
14516
- }))
14517
- );
14518
- const matches = results.filter(
14519
- (r) => r.status === "fulfilled"
14520
- ).map((r) => r.value);
14521
- if (matches.length === 0) {
14522
- const realError = results.filter((r) => r.status === "rejected").find((r) => !isNotFoundError(r.reason));
14523
- if (realError) {
14524
- throw realError.reason;
14575
+ let targetDirs;
14576
+ if (installPath) {
14577
+ targetDirs = findSubDirectoriesWithPackmindJson(cwd, false);
14578
+ } else if (packages.length > 0) {
14579
+ targetDirs = [cwd];
14580
+ } else {
14581
+ targetDirs = [];
14582
+ if (fs18.existsSync(path20.join(cwd, "packmind.json"))) {
14583
+ targetDirs.push(cwd);
14525
14584
  }
14526
- throw new Error(`Package '${slug3}' not found in any space.`);
14585
+ targetDirs.push(...findSubDirectoriesWithPackmindJson(cwd, true));
14527
14586
  }
14528
- if (matches.length > 1) {
14529
- const example = `@${matches[0].spaceSlug}/${slug3}`;
14530
- throw new Error(
14531
- `Package '${slug3}' exists in multiple spaces (${matches.map((m) => `@${m.spaceSlug}`).join(", ")}). Please specify the space using the @space/package format (e.g. ${example}).`
14532
- );
14587
+ if (targetDirs.length === 0) {
14588
+ targetDirs = [cwd];
14533
14589
  }
14534
- return {
14535
- pkg: matches[0].pkg,
14536
- fullSlug: `@${matches[0].spaceSlug}/${slug3}`
14537
- };
14538
- }
14539
- async function showPackageHandler(args2, deps) {
14540
- const { packmindCliHexa, exit } = deps;
14541
- try {
14542
- logInfoConsole(`Fetching package details for '${args2.slug}'...`);
14543
- const { pkg, fullSlug } = await resolvePackage(args2.slug, packmindCliHexa);
14544
- logConsole(`
14545
- ${pkg.name} (${fullSlug}):
14546
- `);
14547
- if (pkg.description) {
14548
- logConsole(`${pkg.description}
14549
- `);
14550
- }
14551
- if (pkg.standards && pkg.standards.length > 0) {
14552
- logConsole("Standards:");
14553
- pkg.standards.forEach((standard) => {
14554
- if (standard.summary) {
14555
- logConsole(` - ${standard.name}: ${standard.summary}`);
14556
- } else {
14557
- logConsole(` - ${standard.name}`);
14558
- }
14559
- });
14560
- logConsole("");
14561
- }
14562
- if (pkg.recipes && pkg.recipes.length > 0) {
14563
- logConsole("Commands:");
14564
- pkg.recipes.forEach((recipe) => {
14565
- if (recipe.summary) {
14566
- logConsole(` - ${recipe.name}: ${recipe.summary}`);
14567
- } else {
14568
- logConsole(` - ${recipe.name}`);
14569
- }
14590
+ const results = [];
14591
+ const thrownErrors = [];
14592
+ const multiDir = targetDirs.length > 1;
14593
+ for (const dir of targetDirs) {
14594
+ try {
14595
+ const result = await packmindCliHexa.install({
14596
+ baseDirectory: dir,
14597
+ packages: packages.length > 0 ? packages : void 0
14570
14598
  });
14571
- logConsole("");
14572
- }
14573
- if (pkg.skills && pkg.skills.length > 0) {
14574
- logConsole("Skills:");
14575
- pkg.skills.forEach((skill) => {
14576
- if (skill.summary) {
14577
- logConsole(` - ${skill.name}: ${skill.summary}`);
14578
- } else {
14579
- logConsole(` - ${skill.name}`);
14580
- }
14599
+ results.push(result);
14600
+ await notifyArtefactsDistributionIfInGitRepo({
14601
+ packmindCliHexa,
14602
+ dir
14581
14603
  });
14582
- logConsole("");
14583
- }
14584
- exit(0);
14585
- } catch (err) {
14586
- logErrorConsole("Failed to fetch package details:");
14587
- if (err instanceof Error) {
14588
- logErrorConsole(err.message);
14589
- } else {
14590
- logErrorConsole(String(err));
14604
+ } catch (error) {
14605
+ const errorMessage = error instanceof Error ? error.message : String(error);
14606
+ thrownErrors.push(
14607
+ multiDir ? `[${dir}] install failed: ${errorMessage}` : `install failed: ${errorMessage}`
14608
+ );
14591
14609
  }
14592
- exit(1);
14593
14610
  }
14594
- }
14611
+ const combined = mergeInstallResults(results);
14612
+ if (combined.missingAccess.length > 0) {
14613
+ let warning = `\u26A0\uFE0F You don't have access to the following packages (their artifacts were preserved from the lock file):
14614
+ ` + combined.missingAccess.map((s) => ` - ${s}`).join("\n");
14615
+ if (combined.joinSpaceUrl) {
14616
+ warning += `
14595
14617
 
14596
- // apps/cli/src/infra/repositories/PlaybookLocalRepository.ts
14597
- var crypto = __toESM(require("crypto"));
14598
- var fs18 = __toESM(require("fs"));
14599
- var os4 = __toESM(require("os"));
14600
- var path20 = __toESM(require("path"));
14601
- var yaml = __toESM(require("yaml"));
14602
- var PlaybookLocalRepository = class {
14603
- constructor(repoRoot) {
14604
- const normalized = this.normalizeRepoRoot(repoRoot);
14605
- const hash = crypto.createHash("md5").update(normalized).digest("hex");
14606
- this.storagePath = path20.join(
14607
- os4.homedir(),
14608
- ".packmind",
14609
- hash,
14610
- "playbook.yaml"
14611
- );
14612
- }
14613
- addChange(entry) {
14614
- const data = this.readYaml();
14615
- const existingIndex = data.changes.findIndex(
14616
- (c) => c.filePath === entry.filePath && c.spaceId === entry.spaceId
14617
- );
14618
- if (existingIndex >= 0) {
14619
- data.changes[existingIndex] = entry;
14620
- } else {
14621
- data.changes.push(entry);
14618
+ \u{1F449} Join the space to get access: ${combined.joinSpaceUrl}`;
14622
14619
  }
14623
- this.writeYaml(data);
14620
+ logWarningConsole(warning);
14624
14621
  }
14625
- removeChange(filePath, spaceId) {
14626
- const data = this.readYaml();
14627
- const initialLength = data.changes.length;
14628
- data.changes = data.changes.filter(
14629
- (c) => !(c.filePath === filePath && c.spaceId === spaceId)
14630
- );
14631
- if (data.changes.length === initialLength) {
14632
- return false;
14633
- }
14634
- this.writeYaml(data);
14635
- return true;
14636
- }
14637
- getChanges() {
14638
- return this.readYaml().changes;
14622
+ logConsole(buildInstallSummary(combined));
14623
+ await installDefaultSkillsIfAtGitRoot({ packmindCliHexa, cwd });
14624
+ const allErrors = [...combined.errors, ...thrownErrors];
14625
+ if (allErrors.length > 0) {
14626
+ logWarningConsole(`Encountered ${allErrors.length} error(s):`);
14627
+ allErrors.forEach((err) => logErrorConsole(` - ${err}`));
14639
14628
  }
14640
- getChange(filePath, spaceId) {
14641
- return this.readYaml().changes.find(
14642
- (c) => c.filePath === filePath && c.spaceId === spaceId
14643
- ) ?? null;
14644
- }
14645
- clearAll() {
14646
- this.writeYaml({ version: 1, changes: [] });
14647
- }
14648
- normalizeRepoRoot(repoRoot) {
14649
- let normalized = repoRoot.replace(/\\/g, "/");
14650
- normalized = normalized.replace(/\/$/, "");
14651
- return normalized;
14652
- }
14653
- readYaml() {
14654
- if (!fs18.existsSync(this.storagePath)) {
14655
- return { version: 1, changes: [] };
14656
- }
14657
- try {
14658
- const content = fs18.readFileSync(this.storagePath, "utf-8");
14659
- const parsed = yaml.parse(content);
14660
- if (!parsed || !Array.isArray(parsed.changes)) {
14661
- return { version: 1, changes: [] };
14662
- }
14663
- return { version: 1, changes: parsed.changes };
14664
- } catch {
14665
- logWarningConsole(
14666
- `Corrupted playbook file: ${this.storagePath}. Treating as empty.`
14667
- );
14668
- return { version: 1, changes: [] };
14669
- }
14670
- }
14671
- writeYaml(data) {
14672
- const dir = path20.dirname(this.storagePath);
14673
- fs18.mkdirSync(dir, { recursive: true });
14674
- fs18.writeFileSync(this.storagePath, yaml.stringify(data), "utf-8");
14629
+ if (thrownErrors.length > 0) {
14630
+ process.exit(1);
14675
14631
  }
14676
- };
14677
-
14678
- // apps/cli/src/infra/commands/InstallCommand.ts
14632
+ }
14679
14633
  var installCommand = (0, import_cmd_ts2.command)({
14680
14634
  name: "install",
14681
- description: "Install packages and save their artifacts locally",
14682
14635
  aliases: ["pull"],
14636
+ description: "Install packages and save their artifacts locally",
14683
14637
  args: {
14684
- list: (0, import_cmd_ts2.flag)({
14685
- long: "list",
14686
- description: "List available packages"
14638
+ installPath: (0, import_cmd_ts2.option)({
14639
+ type: import_cmd_ts2.string,
14640
+ short: "p",
14641
+ long: "path",
14642
+ defaultValue: () => "",
14643
+ description: "Run install in the specified directory instead of the current directory"
14644
+ }),
14645
+ packages: (0, import_cmd_ts2.restPositionals)({
14646
+ type: import_cmd_ts2.string,
14647
+ displayName: "packages",
14648
+ description: "Package slugs to install (e.g. @my-space/my-package)"
14687
14649
  }),
14688
14650
  status: (0, import_cmd_ts2.flag)({
14689
14651
  long: "status",
14690
14652
  description: "Show status of all packmind.json files and their packages in the workspace"
14691
14653
  }),
14692
- recursive: (0, import_cmd_ts2.flag)({
14693
- short: "r",
14694
- long: "recursive",
14695
- description: "[Deprecated] Install is now recursive by default. This flag will be removed in a future version."
14696
- }),
14697
- path: (0, import_cmd_ts2.option)({
14698
- type: import_cmd_ts2.string,
14699
- short: "p",
14700
- long: "path",
14701
- defaultValue: () => "",
14702
- description: "Run install in the specified directory (recursive within that path)"
14654
+ list: (0, import_cmd_ts2.flag)({
14655
+ long: "list",
14656
+ description: "[Deprecated] List available packages"
14703
14657
  }),
14704
14658
  show: (0, import_cmd_ts2.option)({
14705
14659
  type: import_cmd_ts2.string,
14706
14660
  long: "show",
14707
- description: "Show details of a specific package",
14661
+ description: "[Deprecated] Show details of a specific package",
14708
14662
  defaultValue: () => ""
14709
- }),
14710
- packagesSlugs: (0, import_cmd_ts2.restPositionals)({
14711
- type: import_cmd_ts2.string,
14712
- displayName: "packages",
14713
- description: "Package slugs to install (e.g., backend frontend)"
14714
14663
  })
14715
14664
  },
14716
- handler: async ({ list, status, recursive, path: path36, show, packagesSlugs }) => {
14717
- const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
14718
- const packmindCliHexa = new PackmindCliHexa(packmindLogger);
14719
- const repoRoot = await packmindCliHexa.tryGetGitRepositoryRoot(
14720
- process.cwd()
14721
- );
14722
- const playbookLocalRepository = repoRoot ? new PlaybookLocalRepository(repoRoot) : void 0;
14723
- const deps = {
14724
- packmindCliHexa,
14725
- exit: process.exit,
14726
- getCwd: () => process.cwd(),
14727
- log: console.log,
14728
- error: console.error,
14729
- playbookLocalRepository
14730
- };
14731
- if (list) {
14732
- await listPackagesHandler({}, deps);
14733
- return;
14734
- }
14735
- if (status) {
14736
- await statusHandler({}, deps);
14737
- return;
14738
- }
14739
- if (show) {
14740
- await showPackageHandler(
14741
- { slug: show },
14742
- { packmindCliHexa, exit: process.exit }
14743
- );
14744
- return;
14745
- }
14746
- if (recursive) {
14747
- logWarningConsole(
14748
- "\u26A0\uFE0F The --recursive flag is deprecated. Install is now recursive by default."
14749
- );
14750
- await recursiveInstallHandler({ path: path36 || void 0 }, deps);
14751
- return;
14752
- }
14753
- if (packagesSlugs.length > 0) {
14754
- await installPackagesHandler(
14755
- { packagesSlugs, path: path36 || void 0 },
14756
- deps
14757
- );
14758
- return;
14759
- }
14760
- await recursiveInstallHandler({ path: path36 || void 0 }, deps);
14761
- }
14665
+ handler: installHandler
14762
14666
  });
14763
14667
 
14764
14668
  // apps/cli/src/infra/commands/UninstallCommand.ts
14765
14669
  var import_cmd_ts3 = __toESM(require_cjs());
14670
+ function buildUninstallSummary(result) {
14671
+ const removedParts = [
14672
+ result.standardsRemoved > 0 ? `${result.standardsRemoved} ${result.standardsRemoved === 1 ? "standard" : "standards"}` : null,
14673
+ result.commandsRemoved > 0 ? `${result.commandsRemoved} ${result.commandsRemoved === 1 ? "command" : "commands"}` : null,
14674
+ result.skillsRemoved > 0 ? `${result.skillsRemoved} ${result.skillsRemoved === 1 ? "skill" : "skills"}` : null,
14675
+ result.recipesRemoved > 0 ? `${result.recipesRemoved} ${result.recipesRemoved === 1 ? "recipe" : "recipes"}` : null
14676
+ ].filter(Boolean);
14677
+ if (removedParts.length === 0) {
14678
+ return "\u2705 Package removed";
14679
+ }
14680
+ return `\u2705 Removed ${removedParts.join(", ")}`;
14681
+ }
14766
14682
  var uninstallCommand = (0, import_cmd_ts3.command)({
14767
14683
  name: "uninstall",
14768
- description: "Uninstall packages and remove their commands and standards from the current directory",
14684
+ description: "Uninstall packages and sync artifacts. Specify package slugs (e.g. @my-space/my-package) to uninstall.",
14769
14685
  aliases: ["remove"],
14770
14686
  args: {
14771
- packagesSlugs: (0, import_cmd_ts3.restPositionals)({
14687
+ packages: (0, import_cmd_ts3.restPositionals)({
14772
14688
  type: import_cmd_ts3.string,
14773
14689
  displayName: "packages",
14774
- description: "Package slugs to uninstall (e.g., backend frontend)"
14690
+ description: "Package slugs to uninstall (e.g. @my-space/my-package)"
14775
14691
  })
14776
14692
  },
14777
- handler: async ({ packagesSlugs }) => {
14693
+ handler: async ({ packages }) => {
14694
+ if (packages.length === 0) {
14695
+ logErrorConsole("Please specify at least one package to uninstall.");
14696
+ process.exit(1);
14697
+ }
14778
14698
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
14779
14699
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
14780
- const deps = {
14781
- packmindCliHexa,
14782
- exit: process.exit,
14783
- getCwd: () => process.cwd(),
14784
- log: console.log,
14785
- error: console.error
14786
- };
14787
- await uninstallPackagesHandler({ packagesSlugs }, deps);
14700
+ try {
14701
+ const result = await packmindCliHexa.uninstall({
14702
+ baseDirectory: process.cwd(),
14703
+ packages
14704
+ });
14705
+ if (result.missingAccess.length > 0) {
14706
+ let warning = `\u26A0\uFE0F You don't have access to the following packages (their artifacts were preserved from the lock file):
14707
+ ` + result.missingAccess.map((s) => ` - ${s}`).join("\n");
14708
+ if (result.joinSpaceUrl) {
14709
+ warning += `
14710
+
14711
+ \u{1F449} Join the space to get access: ${result.joinSpaceUrl}`;
14712
+ }
14713
+ logWarningConsole(warning);
14714
+ }
14715
+ logConsole(buildUninstallSummary(result));
14716
+ if (result.errors.length > 0) {
14717
+ logWarningConsole(`Encountered ${result.errors.length} error(s):`);
14718
+ result.errors.forEach((err) => logErrorConsole(` - ${err}`));
14719
+ }
14720
+ } catch (error) {
14721
+ const errorMessage = error instanceof Error ? error.message : String(error);
14722
+ logErrorConsole(`uninstall failed: ${errorMessage}`);
14723
+ process.exit(1);
14724
+ }
14788
14725
  }
14789
14726
  });
14790
14727
 
@@ -14980,7 +14917,7 @@ var inquirer = __toESM(require("inquirer"));
14980
14917
  // apps/cli/src/application/services/AgentDetectionService.ts
14981
14918
  var fs19 = __toESM(require("fs"));
14982
14919
  var path21 = __toESM(require("path"));
14983
- var os5 = __toESM(require("os"));
14920
+ var os4 = __toESM(require("os"));
14984
14921
  var import_child_process4 = require("child_process");
14985
14922
  var AgentDetectionService = class {
14986
14923
  constructor(projectDir = process.cwd()) {
@@ -15006,7 +14943,7 @@ var AgentDetectionService = class {
15006
14943
  return this.isCommandAvailable("claude");
15007
14944
  }
15008
14945
  isCursorAvailable() {
15009
- const cursorConfigDir = path21.join(os5.homedir(), ".cursor");
14946
+ const cursorConfigDir = path21.join(os4.homedir(), ".cursor");
15010
14947
  return fs19.existsSync(cursorConfigDir);
15011
14948
  }
15012
14949
  isVSCodeAvailable() {
@@ -15073,7 +15010,7 @@ async function promptAgentsWithReadline(choices) {
15073
15010
  output.write("\n");
15074
15011
  const preselected = choices.map((c, i) => c.checked ? i + 1 : null).filter((i) => i !== null);
15075
15012
  const defaultValue = preselected.length > 0 ? preselected.join(",") : "1,2,3";
15076
- return new Promise((resolve14) => {
15013
+ return new Promise((resolve15) => {
15077
15014
  rl.question(
15078
15015
  `Enter numbers separated by commas (default: ${defaultValue}): `,
15079
15016
  (answer) => {
@@ -15084,7 +15021,7 @@ async function promptAgentsWithReadline(choices) {
15084
15021
  const numbersStr = trimmed === "" ? defaultValue : trimmed;
15085
15022
  const numbers = numbersStr.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n) && n >= 1 && n <= choices.length);
15086
15023
  const selectedAgents = numbers.map((n) => choices[n - 1].value);
15087
- resolve14(selectedAgents);
15024
+ resolve15(selectedAgents);
15088
15025
  }
15089
15026
  );
15090
15027
  });
@@ -15258,9 +15195,14 @@ var addSkillCommand = (0, import_cmd_ts9.command)({
15258
15195
  originSkill: originSkillOption
15259
15196
  },
15260
15197
  handler: async () => {
15261
- logErrorConsole('Command "packmind-cli skills add" has been removed.');
15262
- logConsole(
15263
- `Use ${formatCommand("packmind-cli playbook add <path>")} instead.`
15198
+ const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
15199
+ const packmindCliHexa = new PackmindCliHexa(packmindLogger);
15200
+ packmindCliHexa.output.notifyError(
15201
+ 'Command "packmind-cli skills add" has been removed.',
15202
+ {
15203
+ content: 'Use the "playbook add" command instead:',
15204
+ exampleCommand: "packmind-cli playbook add .packmind/commands/my-command.md"
15205
+ }
15264
15206
  );
15265
15207
  process.exit(1);
15266
15208
  }
@@ -15340,13 +15282,6 @@ var installDefaultSkillsCommand = (0, import_cmd_ts10.command)({
15340
15282
  `${result.skippedSkillsCount} skill(s) were skipped because they require a newer version of packmind-cli. Run "${formatCommand("packmind-cli update")}" to get the latest version.`
15341
15283
  );
15342
15284
  }
15343
- if (result.skippedIncompatibleSkillNames.length > 0) {
15344
- for (const skillName of result.skippedIncompatibleSkillNames) {
15345
- logWarningConsole(
15346
- `Skill "${skillName}" was not installed because it is not compatible with this version of packmind-cli.`
15347
- );
15348
- }
15349
- }
15350
15285
  if (result.incompatibleInstalledSkills.length > 0) {
15351
15286
  await handleIncompatibleInstalledSkillsWithPrompt(
15352
15287
  result.incompatibleInstalledSkills,
@@ -15393,10 +15328,10 @@ async function promptConfirmation(question) {
15393
15328
  input: process.stdin,
15394
15329
  output: process.stdout
15395
15330
  });
15396
- return new Promise((resolve14) => {
15331
+ return new Promise((resolve15) => {
15397
15332
  rl.question(question, (answer) => {
15398
15333
  rl.close();
15399
- resolve14(answer.trim().toLowerCase() === "y");
15334
+ resolve15(answer.trim().toLowerCase() === "y");
15400
15335
  });
15401
15336
  });
15402
15337
  }
@@ -15404,93 +15339,95 @@ async function promptConfirmation(question) {
15404
15339
  // apps/cli/src/infra/commands/ListSkillsCommand.ts
15405
15340
  var import_cmd_ts11 = __toESM(require_cjs());
15406
15341
 
15407
- // apps/cli/src/infra/commands/skills/listSkillsHandler.ts
15408
- function groupSkillsBySpace(skills, spaces) {
15409
- const spaceMap = new Map(
15342
+ // apps/cli/src/infra/utils/spaceFilterUtils.ts
15343
+ function resolveSpaceFromArgs(spaceArg, spaces) {
15344
+ if (!spaceArg) return null;
15345
+ const slug3 = spaceArg.startsWith("@") ? spaceArg.slice(1) : spaceArg;
15346
+ return spaces.find((s) => s.slug === slug3) ?? null;
15347
+ }
15348
+
15349
+ // apps/cli/src/infra/utils/urlBuilderUtils.ts
15350
+ function resolveUrlBuilder(buildArtifactPath) {
15351
+ const apiKey = loadApiKey();
15352
+ if (!apiKey) return () => null;
15353
+ const decoded = decodeApiKey(apiKey);
15354
+ const orgSlug = decoded?.jwt?.organization?.slug;
15355
+ if (!decoded?.host || !orgSlug) return () => null;
15356
+ return (spaceSlug, artifactId) => `${decoded.host}/org/${orgSlug}/space/${spaceSlug}/${buildArtifactPath(artifactId)}`;
15357
+ }
15358
+
15359
+ // apps/cli/src/infra/utils/groupArtefactsBySpaces.ts
15360
+ function groupArtefactBySpaces(artefacts, spaces) {
15361
+ const spacesById = new Map(
15410
15362
  spaces.map((s) => [s.id, s])
15411
15363
  );
15412
- const groupsMap = /* @__PURE__ */ new Map();
15413
- const orphaned = [];
15414
- for (const skill of skills) {
15415
- const space = spaceMap.get(skill.spaceId);
15416
- if (!space) {
15417
- orphaned.push(skill);
15418
- continue;
15419
- }
15420
- let group = groupsMap.get(space.id);
15421
- if (!group) {
15422
- group = { space, items: [] };
15423
- groupsMap.set(space.id, group);
15424
- }
15425
- group.items.push(skill);
15426
- }
15427
- const groups = [...groupsMap.values()].sort(
15428
- (a, b) => a.space.name.localeCompare(b.space.name)
15429
- );
15430
- return { groups, orphaned };
15431
- }
15432
- function displayGroupedSkills(skills, spaces, buildUrl) {
15433
- const { groups, orphaned } = groupSkillsBySpace(skills, spaces);
15434
- for (const { space, items } of groups) {
15435
- logConsole(`Space "${space.name}":
15436
- `);
15437
- for (const skill of [...items].sort(
15438
- (a, b) => a.slug.localeCompare(b.slug)
15439
- )) {
15440
- logConsole(` ${formatSlug(skill.slug)}`);
15441
- logConsole(` ${formatLabel("Name:")} ${skill.name}`);
15442
- if (skill.description) {
15443
- const descriptionLines = skill.description.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
15444
- const firstLine = descriptionLines[0];
15445
- if (firstLine) {
15446
- const truncated = firstLine.length > 80 ? firstLine.slice(0, 77) + "..." : firstLine;
15447
- logConsole(` ${formatLabel("Desc:")} ${truncated}`);
15448
- }
15449
- }
15450
- const url = buildUrl(space.slug, skill.slug);
15451
- if (url) {
15452
- logConsole(` ${formatLabel("Link:")} ${url}`);
15453
- }
15454
- logConsole("");
15364
+ const groupedArtefacts = artefacts.reduce((acc, artefact) => {
15365
+ const space = spacesById.get(artefact.spaceId);
15366
+ if (space) {
15367
+ const group = acc.get(artefact.spaceId) ?? { space, artefacts: [] };
15368
+ acc.set(artefact.spaceId, {
15369
+ space,
15370
+ artefacts: [...group.artefacts, artefact]
15371
+ });
15455
15372
  }
15456
- }
15457
- for (const skill of [...orphaned].sort(
15458
- (a, b) => a.slug.localeCompare(b.slug)
15459
- )) {
15460
- logConsole(` ${formatSlug(skill.slug)}`);
15461
- logConsole(` ${formatLabel("Name:")} ${skill.name}`);
15462
- logConsole("");
15463
- }
15373
+ return acc;
15374
+ }, /* @__PURE__ */ new Map());
15375
+ return [...groupedArtefacts.values()].map(({ space, artefacts: artefacts2 }) => ({
15376
+ space,
15377
+ artefacts: [...artefacts2].sort((a, b) => a.slug.localeCompare(b.slug))
15378
+ })).sort((a, b) => a.space.name.localeCompare(b.space.name));
15464
15379
  }
15380
+
15381
+ // apps/cli/src/infra/commands/skills/listSkillsHandler.ts
15465
15382
  async function listSkillsHandler(args2, deps) {
15466
15383
  const { packmindCliHexa, exit } = deps;
15467
15384
  try {
15468
- logConsole("Fetching skills...\n");
15469
- const spaces = await packmindCliHexa.getSpaces();
15385
+ const spaces = await packmindCliHexa.output.withLoader(
15386
+ "Fetching spaces",
15387
+ () => packmindCliHexa.getSpaces()
15388
+ );
15470
15389
  const matchedSpace = resolveSpaceFromArgs(args2.space, spaces);
15471
15390
  if (args2.space && !matchedSpace) {
15472
- logErrorConsole(`Space "@${args2.space}" not found.`);
15391
+ const availableSpaces = spaces.map((s) => ` - @${s.slug}`).join("\n");
15392
+ packmindCliHexa.output.notifyError(`Space "@${args2.space}" not found.`, {
15393
+ content: `Available spaces:
15394
+ ${availableSpaces}`
15395
+ });
15473
15396
  exit(1);
15474
15397
  return;
15475
15398
  }
15476
- const skills = await packmindCliHexa.listSkills(
15477
- matchedSpace ? { spaceId: matchedSpace.id } : {}
15399
+ const skills = await packmindCliHexa.output.withLoader(
15400
+ "Fetching skills",
15401
+ () => packmindCliHexa.listSkills(
15402
+ matchedSpace ? { spaceId: matchedSpace.id } : {}
15403
+ )
15478
15404
  );
15479
15405
  if (skills.length === 0) {
15480
- logConsole(
15406
+ packmindCliHexa.output.notifyInfo(
15481
15407
  matchedSpace ? `No skills found in space "@${matchedSpace.slug}".` : "No skills found."
15482
15408
  );
15483
15409
  exit(0);
15484
15410
  return;
15485
15411
  }
15486
- logConsole(formatHeader(`\u{1F4CB} Skills (${skills.length})
15487
- `));
15488
15412
  const buildUrl = resolveUrlBuilder((slug3) => `skills/${slug3}/files`);
15489
- displayGroupedSkills(skills, spaces, buildUrl);
15413
+ const groups = groupArtefactBySpaces(skills, spaces);
15414
+ packmindCliHexa.output.listScopedArtefacts(
15415
+ `\u{1F4CB} Skills (${skills.length})`,
15416
+ groups.map(({ space, artefacts }) => ({
15417
+ title: `Space: ${space.name}`,
15418
+ artefacts: artefacts.map((skill) => ({
15419
+ title: skill.name,
15420
+ slug: skill.slug,
15421
+ description: skill.description ?? void 0,
15422
+ url: buildUrl(space.slug, skill.slug)
15423
+ }))
15424
+ }))
15425
+ );
15490
15426
  exit(0);
15491
15427
  } catch (err) {
15492
- logErrorConsole("Failed to list skills:");
15493
- logErrorConsole(err instanceof Error ? err.message : String(err));
15428
+ packmindCliHexa.output.notifyError("Failed to list skills:", {
15429
+ content: err instanceof Error ? err.message : String(err)
15430
+ });
15494
15431
  exit(1);
15495
15432
  }
15496
15433
  }
@@ -15552,11 +15489,14 @@ var createStandardCommand = (0, import_cmd_ts13.command)({
15552
15489
  originSkill: originSkillOption
15553
15490
  },
15554
15491
  handler: async () => {
15555
- logErrorConsole(
15556
- 'Command "packmind-cli standards create" has been removed.'
15557
- );
15558
- logConsole(
15559
- `Use ${formatCommand("packmind-cli playbook add <path>")} instead.`
15492
+ const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
15493
+ const packmindCliHexa = new PackmindCliHexa(packmindLogger);
15494
+ packmindCliHexa.output.notifyError(
15495
+ 'Command "packmind-cli standards create" has been removed.',
15496
+ {
15497
+ content: 'Use the "playbook add" command instead:',
15498
+ exampleCommand: "packmind-cli playbook add .packmind/standards/my-standard.md"
15499
+ }
15560
15500
  );
15561
15501
  process.exit(1);
15562
15502
  }
@@ -15566,92 +15506,55 @@ var createStandardCommand = (0, import_cmd_ts13.command)({
15566
15506
  var import_cmd_ts14 = __toESM(require_cjs());
15567
15507
 
15568
15508
  // apps/cli/src/infra/commands/standards/listStandardsHandler.ts
15569
- function groupStandardsBySpace(standards, spaces) {
15570
- const spaceMap = new Map(
15571
- spaces.map((s) => [s.id, s])
15572
- );
15573
- const groupsMap = /* @__PURE__ */ new Map();
15574
- const orphaned = [];
15575
- for (const standard of standards) {
15576
- const space = spaceMap.get(standard.spaceId);
15577
- if (!space) {
15578
- orphaned.push(standard);
15579
- continue;
15580
- }
15581
- let group = groupsMap.get(space.id);
15582
- if (!group) {
15583
- group = { space, items: [] };
15584
- groupsMap.set(space.id, group);
15585
- }
15586
- group.items.push(standard);
15587
- }
15588
- const groups = [...groupsMap.values()].sort(
15589
- (a, b) => a.space.name.localeCompare(b.space.name)
15590
- );
15591
- return { groups, orphaned };
15592
- }
15593
- function displayGroupedStandards(standards, spaces, buildUrl) {
15594
- const { groups, orphaned } = groupStandardsBySpace(standards, spaces);
15595
- for (const { space, items } of groups) {
15596
- logConsole(`Space "${space.name}":
15597
- `);
15598
- for (const standard of [...items].sort(
15599
- (a, b) => a.slug.localeCompare(b.slug)
15600
- )) {
15601
- logConsole(` ${formatSlug(standard.slug)}`);
15602
- logConsole(` ${formatLabel("Name:")} ${standard.name}`);
15603
- if (standard.description) {
15604
- const descriptionLines = standard.description.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
15605
- const firstLine = descriptionLines[0];
15606
- if (firstLine) {
15607
- const truncated = firstLine.length > 80 ? firstLine.slice(0, 77) + "..." : firstLine;
15608
- logConsole(` ${formatLabel("Desc:")} ${truncated}`);
15609
- }
15610
- }
15611
- const url = buildUrl(space.slug, standard.id);
15612
- if (url) {
15613
- logConsole(` ${formatLabel("Link:")} ${url}`);
15614
- }
15615
- logConsole("");
15616
- }
15617
- }
15618
- for (const standard of [...orphaned].sort(
15619
- (a, b) => a.slug.localeCompare(b.slug)
15620
- )) {
15621
- logConsole(` ${formatSlug(standard.slug)}`);
15622
- logConsole(` ${formatLabel("Name:")} ${standard.name}`);
15623
- logConsole("");
15624
- }
15625
- }
15626
15509
  async function listStandardsHandler(args2, deps) {
15627
15510
  const { packmindCliHexa, exit } = deps;
15628
15511
  try {
15629
- logConsole("Fetching standards...\n");
15630
- const spaces = await packmindCliHexa.getSpaces();
15512
+ const spaces = await packmindCliHexa.output.withLoader(
15513
+ "Fetching spaces",
15514
+ () => packmindCliHexa.getSpaces()
15515
+ );
15631
15516
  const matchedSpace = resolveSpaceFromArgs(args2.space, spaces);
15632
15517
  if (args2.space && !matchedSpace) {
15633
- logErrorConsole(`Space "@${args2.space}" not found.`);
15518
+ const availableSpaces = spaces.map((space) => ` - @${space.slug}`).join("\n");
15519
+ packmindCliHexa.output.notifyError(`Space "@${args2.space}" not found.`, {
15520
+ content: `Available spaces:
15521
+ ${availableSpaces}`
15522
+ });
15634
15523
  exit(1);
15635
15524
  return;
15636
15525
  }
15637
- const standards = await packmindCliHexa.listStandards(
15638
- matchedSpace ? { spaceId: matchedSpace.id } : {}
15526
+ const standards = await packmindCliHexa.output.withLoader(
15527
+ "Fetching standards",
15528
+ () => packmindCliHexa.listStandards(
15529
+ matchedSpace ? { spaceId: matchedSpace.id } : {}
15530
+ )
15639
15531
  );
15640
15532
  if (standards.length === 0) {
15641
- logConsole(
15533
+ packmindCliHexa.output.notifyInfo(
15642
15534
  matchedSpace ? `No standards found in space "@${matchedSpace.slug}".` : "No standards found."
15643
15535
  );
15644
15536
  exit(0);
15645
15537
  return;
15646
15538
  }
15647
- logConsole(formatHeader(`\u{1F4CB} Standards (${standards.length})
15648
- `));
15539
+ const groupedStandards = groupArtefactBySpaces(standards, spaces);
15649
15540
  const buildUrl = resolveUrlBuilder((id) => `standards/${id}/summary`);
15650
- displayGroupedStandards(standards, spaces, buildUrl);
15541
+ const scopedArtefacts = groupedStandards.map(({ space, artefacts }) => ({
15542
+ title: `Space: ${space.name}`,
15543
+ artefacts: artefacts.map((s) => ({
15544
+ title: s.name,
15545
+ slug: s.slug,
15546
+ url: buildUrl(space.slug, s.id)
15547
+ }))
15548
+ }));
15549
+ packmindCliHexa.output.listScopedArtefacts(
15550
+ `\u{1F4CB} Standards (${standards.length})`,
15551
+ scopedArtefacts
15552
+ );
15651
15553
  exit(0);
15652
15554
  } catch (err) {
15653
- logErrorConsole("Failed to list standards:");
15654
- logErrorConsole(err instanceof Error ? err.message : String(err));
15555
+ packmindCliHexa.output.notifyError("Failed to list standards:", {
15556
+ content: err instanceof Error ? err.message : String(err)
15557
+ });
15655
15558
  exit(1);
15656
15559
  }
15657
15560
  }
@@ -15712,9 +15615,14 @@ var createCommandCommand = (0, import_cmd_ts16.command)({
15712
15615
  originSkill: originSkillOption
15713
15616
  },
15714
15617
  handler: async () => {
15715
- logErrorConsole('Command "packmind-cli commands create" has been removed.');
15716
- logConsole(
15717
- `Use ${formatCommand("packmind-cli playbook add <path>")} instead.`
15618
+ const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
15619
+ const packmindCliHexa = new PackmindCliHexa(packmindLogger);
15620
+ packmindCliHexa.output.notifyError(
15621
+ 'Command "packmind-cli commands create" has been removed.',
15622
+ {
15623
+ content: 'Use the "playbook add" command instead:',
15624
+ exampleCommand: "packmind-cli playbook add .packmind/commands/my-command.md"
15625
+ }
15718
15626
  );
15719
15627
  process.exit(1);
15720
15628
  }
@@ -15724,86 +15632,54 @@ var createCommandCommand = (0, import_cmd_ts16.command)({
15724
15632
  var import_cmd_ts17 = __toESM(require_cjs());
15725
15633
 
15726
15634
  // apps/cli/src/infra/commands/commands/listCommandsHandler.ts
15727
- function groupCommandsBySpace(commands, spaces) {
15728
- const spaceMap = new Map(
15729
- spaces.map((s) => [s.id, s])
15730
- );
15731
- const groupsMap = /* @__PURE__ */ new Map();
15732
- const orphaned = [];
15733
- for (const cmd of commands) {
15734
- const space = spaceMap.get(cmd.spaceId);
15735
- if (!space) {
15736
- orphaned.push(cmd);
15737
- continue;
15738
- }
15739
- let group = groupsMap.get(space.id);
15740
- if (!group) {
15741
- group = { space, cmds: [] };
15742
- groupsMap.set(space.id, group);
15743
- }
15744
- group.cmds.push(cmd);
15745
- }
15746
- const groups = [...groupsMap.values()].sort(
15747
- (a, b) => a.space.name.localeCompare(b.space.name)
15748
- );
15749
- return { groups, orphaned };
15750
- }
15751
- function displayGroupedCommands(commands, spaces, buildUrl) {
15752
- const { groups, orphaned } = groupCommandsBySpace(commands, spaces);
15753
- for (const { space, cmds } of groups) {
15754
- logConsole(`Space "${space.name}":
15755
- `);
15756
- for (const cmd of [...cmds].sort((a, b) => a.slug.localeCompare(b.slug))) {
15757
- logConsole(` ${formatSlug(cmd.slug)}`);
15758
- logConsole(` ${formatLabel("Name:")} ${cmd.name}`);
15759
- const url = buildUrl(space.slug, cmd.id);
15760
- if (url) {
15761
- logConsole(` ${formatLabel("Link:")} ${url}`);
15762
- }
15763
- logConsole("");
15764
- }
15765
- }
15766
- for (const cmd of [...orphaned].sort(
15767
- (a, b) => a.slug.localeCompare(b.slug)
15768
- )) {
15769
- logConsole(` ${formatSlug(cmd.slug)}`);
15770
- logConsole(` ${formatLabel("Name:")} ${cmd.name}`);
15771
- logConsole("");
15772
- }
15773
- }
15774
15635
  async function listCommandsHandler(args2, deps) {
15775
15636
  const { packmindCliHexa, exit } = deps;
15776
15637
  try {
15777
- logConsole("Fetching commands...\n");
15778
- const spaces = await packmindCliHexa.getSpaces();
15638
+ const spaces = await packmindCliHexa.output.withLoader(
15639
+ "Fetching spaces",
15640
+ () => packmindCliHexa.getSpaces()
15641
+ );
15779
15642
  const matchedSpace = resolveSpaceFromArgs(args2.space, spaces);
15780
15643
  if (args2.space && !matchedSpace) {
15781
- logErrorConsole(`Space "@${args2.space}" not found.`);
15644
+ const availableSpaces = spaces.map((space) => ` - @${space.slug}`).join("\n");
15645
+ packmindCliHexa.output.notifyError(`Space "@${args2.space}" not found.`, {
15646
+ content: `Available spaces:
15647
+ ${availableSpaces}`
15648
+ });
15782
15649
  exit(1);
15783
15650
  return;
15784
15651
  }
15785
- const commands = await packmindCliHexa.listCommands(
15786
- matchedSpace ? { spaceId: matchedSpace.id } : {}
15652
+ const commands = await packmindCliHexa.output.withLoader(
15653
+ "Fetching commands",
15654
+ () => packmindCliHexa.listCommands(
15655
+ matchedSpace ? { spaceId: matchedSpace.id } : {}
15656
+ )
15787
15657
  );
15788
15658
  if (commands.length === 0) {
15789
- logConsole(
15659
+ packmindCliHexa.output.notifyInfo(
15790
15660
  matchedSpace ? `No commands found in space "@${matchedSpace.slug}".` : "No commands found."
15791
15661
  );
15792
15662
  exit(0);
15793
15663
  return;
15794
15664
  }
15795
- logConsole(formatHeader(`\u{1F4CB} Commands (${commands.length})
15796
- `));
15665
+ const groupedCommands = groupArtefactBySpaces(commands, spaces);
15797
15666
  const buildUrl = resolveUrlBuilder((id) => `commands/${id}`);
15798
- displayGroupedCommands(commands, spaces, buildUrl);
15667
+ packmindCliHexa.output.listScopedArtefacts(
15668
+ `\u{1F4CB} Commands (${commands.length})`,
15669
+ groupedCommands.map(({ space, artefacts }) => ({
15670
+ title: `Space: ${space.name}`,
15671
+ artefacts: artefacts.map((cmd) => ({
15672
+ title: cmd.name,
15673
+ slug: cmd.slug,
15674
+ url: buildUrl(space.slug, cmd.id)
15675
+ }))
15676
+ }))
15677
+ );
15799
15678
  exit(0);
15800
15679
  } catch (err) {
15801
- logErrorConsole("Failed to list commands:");
15802
- if (err instanceof Error) {
15803
- logErrorConsole(err.message);
15804
- } else {
15805
- logErrorConsole(String(err));
15806
- }
15680
+ packmindCliHexa.output.notifyError("Failed to list commands:", {
15681
+ content: err instanceof Error ? err.message : String(err)
15682
+ });
15807
15683
  exit(1);
15808
15684
  }
15809
15685
  }
@@ -16011,6 +15887,21 @@ async function findTargetDirectories(searchPath, packmindCliHexa) {
16011
15887
  targets.push(dir);
16012
15888
  }
16013
15889
  }
15890
+ if (targets.length === 0) {
15891
+ let currentDir = nodePath.dirname(searchPath);
15892
+ while (true) {
15893
+ const ancestorExists = await packmindCliHexa.configExists(currentDir);
15894
+ if (ancestorExists) {
15895
+ targets.push(currentDir);
15896
+ break;
15897
+ }
15898
+ const parentDir = nodePath.dirname(currentDir);
15899
+ if (parentDir === currentDir) {
15900
+ break;
15901
+ }
15902
+ currentDir = parentDir;
15903
+ }
15904
+ }
16014
15905
  return targets;
16015
15906
  }
16016
15907
  function computeRelativePath(targetAbsDir, gitRoot) {
@@ -16193,7 +16084,11 @@ async function diffArtefactsHandler(deps) {
16193
16084
  relativePath,
16194
16085
  agents: config.agents
16195
16086
  });
16196
- targetResults.push({ targetRelativePath, diffs });
16087
+ const filterPrefix = nodePath.relative(targetDir, searchPath);
16088
+ const filteredDiffs = filterPrefix !== "" && !filterPrefix.startsWith("..") ? diffs.filter(
16089
+ (d) => d.filePath === filterPrefix || d.filePath.startsWith(filterPrefix + "/")
16090
+ ) : diffs;
16091
+ targetResults.push({ targetRelativePath, diffs: filteredDiffs });
16197
16092
  }
16198
16093
  if (targetResults.length === 0) {
16199
16094
  log("No packages configured in any target.");
@@ -16285,7 +16180,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16285
16180
  description: "Subcommand and arguments (e.g., add <path>, remove <path>)"
16286
16181
  })
16287
16182
  },
16288
- handler: async ({ submit, includeSubmitted, message, path: path36, positionals }) => {
16183
+ handler: async ({ submit, includeSubmitted, message, path: path37, positionals }) => {
16289
16184
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
16290
16185
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
16291
16186
  if (submit) {
@@ -16301,7 +16196,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16301
16196
  process.exit(1);
16302
16197
  }
16303
16198
  if (positionals[0] === "add") {
16304
- const addFilePath = path36 && positionals[1] ? `${path36}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16199
+ const addFilePath = path37 && positionals[1] ? `${path37}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16305
16200
  const addCommand = `packmind-cli playbook add ${addFilePath}`;
16306
16201
  logErrorConsole("Deprecated: `packmind-cli diff add` has been removed");
16307
16202
  logInfoConsole("Use the following command instead:");
@@ -16309,7 +16204,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16309
16204
  process.exit(1);
16310
16205
  }
16311
16206
  if (positionals[0] === "remove" || positionals[0] === "rm") {
16312
- const removeFilePath = path36 && positionals[1] ? `${path36}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16207
+ const removeFilePath = path37 && positionals[1] ? `${path37}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16313
16208
  const removeCommand = `packmind-cli playbook remove ${removeFilePath}`;
16314
16209
  logErrorConsole(
16315
16210
  "Deprecated: `packmind-cli diff remove` has been removed"
@@ -16318,7 +16213,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16318
16213
  logInfoConsole(` ${formatCommand(removeCommand)}`);
16319
16214
  process.exit(1);
16320
16215
  }
16321
- const diffCommand3 = `packmind-cli playbook diff${includeSubmitted ? " --include-submitted" : ""}${path36 ? ` --path ${path36}` : ""}`;
16216
+ const diffCommand3 = `packmind-cli playbook diff${includeSubmitted ? " --include-submitted" : ""}${path37 ? ` --path ${path37}` : ""}`;
16322
16217
  logErrorConsole("Deprecated: `packmind-cli diff` will be removed");
16323
16218
  logInfoConsole("Use the following command instead:");
16324
16219
  logInfoConsole(` ${formatCommand(diffCommand3)}`);
@@ -16328,7 +16223,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16328
16223
  getCwd: () => process.cwd(),
16329
16224
  log: console.log,
16330
16225
  includeSubmitted,
16331
- path: path36
16226
+ path: path37
16332
16227
  });
16333
16228
  }
16334
16229
  });
@@ -16608,6 +16503,14 @@ var AddToPackageUseCase = class {
16608
16503
  }
16609
16504
  };
16610
16505
 
16506
+ // apps/cli/src/infra/utils/packageSlugUtils.ts
16507
+ function parsePackageSlug(slug3) {
16508
+ if (!slug3.startsWith("@")) return null;
16509
+ const slash = slug3.indexOf("/", 1);
16510
+ if (slash === -1) return null;
16511
+ return { spaceSlug: slug3.slice(1, slash), pkgSlug: slug3.slice(slash + 1) };
16512
+ }
16513
+
16611
16514
  // apps/cli/src/infra/commands/packages/addToPackageHandler.ts
16612
16515
  function pluralize(singular, count) {
16613
16516
  return count === 1 ? singular : `${singular}s`;
@@ -16749,24 +16652,90 @@ var addToPackageCommand = (0, import_cmd_ts21.command)({
16749
16652
  );
16750
16653
  process.exit(1);
16751
16654
  }
16752
- if (itemTypes.length > 1) {
16753
- logErrorConsole(
16754
- "Cannot add standards, commands, and skills simultaneously. Use dedicated commands for each artefact."
16655
+ if (itemTypes.length > 1) {
16656
+ logErrorConsole(
16657
+ "Cannot add standards, commands, and skills simultaneously. Use dedicated commands for each artefact."
16658
+ );
16659
+ process.exit(1);
16660
+ }
16661
+ const { type: itemType, slugs: itemSlugs } = itemTypes[0];
16662
+ const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
16663
+ const hexa = new PackmindCliHexa(packmindLogger);
16664
+ await addToPackageHandler(
16665
+ { to, itemType, itemSlugs, originSkill },
16666
+ { hexa, exit: process.exit }
16667
+ );
16668
+ }
16669
+ });
16670
+
16671
+ // apps/cli/src/infra/commands/listPackagesCommand.ts
16672
+ var import_cmd_ts22 = __toESM(require_cjs());
16673
+
16674
+ // apps/cli/src/infra/commands/packages/listPackagesHandler.ts
16675
+ async function listPackagesHandler(args2, deps) {
16676
+ const { packmindCliHexa, exit } = deps;
16677
+ try {
16678
+ const allSpaces = await packmindCliHexa.output.withLoader(
16679
+ "Fetching spaces",
16680
+ () => packmindCliHexa.getSpaces()
16681
+ );
16682
+ if (!allSpaces || allSpaces.length === 0) {
16683
+ throw new Error("Unable to list organization spaces.");
16684
+ }
16685
+ const matchedSpace = resolveSpaceFromArgs(args2.space, allSpaces);
16686
+ if (args2.space && !matchedSpace) {
16687
+ const availableSpaces = allSpaces.map((s) => ` - @${s.slug}`).join("\n");
16688
+ packmindCliHexa.output.notifyError(`Space "@${args2.space}" not found.`, {
16689
+ content: `Available spaces:
16690
+ ${availableSpaces}`
16691
+ });
16692
+ exit(1);
16693
+ return;
16694
+ }
16695
+ const packages = await packmindCliHexa.output.withLoader(
16696
+ "Fetching packages",
16697
+ () => packmindCliHexa.listPackages(
16698
+ matchedSpace ? { spaceId: matchedSpace.id } : {}
16699
+ )
16700
+ );
16701
+ const spaces = matchedSpace ? [matchedSpace] : allSpaces;
16702
+ if (packages.length === 0) {
16703
+ packmindCliHexa.output.notifyInfo(
16704
+ matchedSpace ? `No packages found in space "@${matchedSpace.slug}".` : "No packages found."
16755
16705
  );
16756
- process.exit(1);
16706
+ exit(0);
16707
+ return;
16757
16708
  }
16758
- const { type: itemType, slugs: itemSlugs } = itemTypes[0];
16759
- const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
16760
- const hexa = new PackmindCliHexa(packmindLogger);
16761
- await addToPackageHandler(
16762
- { to, itemType, itemSlugs, originSkill },
16763
- { hexa, exit: process.exit }
16709
+ const buildUrl = resolveUrlBuilder((id) => `packages/${id}`);
16710
+ const groups = groupArtefactBySpaces(packages, spaces);
16711
+ const scopedArtefacts = groups.map(({ space, artefacts }) => ({
16712
+ title: `Space: ${space.name}`,
16713
+ artefacts: artefacts.map((pkg) => ({
16714
+ title: pkg.name,
16715
+ slug: `@${space.slug}/${pkg.slug}`,
16716
+ description: pkg.description,
16717
+ url: buildUrl(space.slug, pkg.id)
16718
+ }))
16719
+ }));
16720
+ const firstSlug = scopedArtefacts[0]?.artefacts[0]?.slug ?? `@${packages[0].slug}`;
16721
+ packmindCliHexa.output.listScopedArtefacts(
16722
+ `\u{1F4E6} Packages (${packages.length})`,
16723
+ scopedArtefacts,
16724
+ {
16725
+ content: "How to install a package:",
16726
+ exampleCommand: `packmind-cli install ${firstSlug}`
16727
+ }
16764
16728
  );
16729
+ exit(0);
16730
+ } catch (err) {
16731
+ packmindCliHexa.output.notifyError("Failed to list packages:", {
16732
+ content: err instanceof Error ? err.message : String(err)
16733
+ });
16734
+ exit(1);
16765
16735
  }
16766
- });
16736
+ }
16767
16737
 
16768
16738
  // apps/cli/src/infra/commands/listPackagesCommand.ts
16769
- var import_cmd_ts22 = __toESM(require_cjs());
16770
16739
  var listPackagesCommand = (0, import_cmd_ts22.command)({
16771
16740
  name: "list",
16772
16741
  description: "List available packages",
@@ -16790,6 +16759,124 @@ var listPackagesCommand = (0, import_cmd_ts22.command)({
16790
16759
 
16791
16760
  // apps/cli/src/infra/commands/packages/showPackageCommand.ts
16792
16761
  var import_cmd_ts23 = __toESM(require_cjs());
16762
+
16763
+ // apps/cli/src/infra/commands/packages/showPackageHandler.ts
16764
+ function isNotFoundError(err) {
16765
+ return err instanceof Error && err.message.includes("does not exist");
16766
+ }
16767
+ async function resolvePackage(slug3, packmindCliHexa) {
16768
+ const allSpaces = await packmindCliHexa.getSpaces();
16769
+ const parsed = parsePackageSlug(slug3);
16770
+ if (parsed) {
16771
+ const { spaceSlug, pkgSlug } = parsed;
16772
+ const matchedSpace = allSpaces.find((s) => s.slug === spaceSlug);
16773
+ if (!matchedSpace) {
16774
+ throw new Error(`Space '@${spaceSlug}' not found.`);
16775
+ }
16776
+ let pkg;
16777
+ try {
16778
+ pkg = await packmindCliHexa.getPackageBySlug({
16779
+ slug: pkgSlug,
16780
+ spaceId: matchedSpace.id
16781
+ });
16782
+ } catch (err) {
16783
+ if (isNotFoundError(err)) {
16784
+ throw new Error(
16785
+ `Package '${pkgSlug}' not found in space '@${spaceSlug}'.`
16786
+ );
16787
+ }
16788
+ throw err;
16789
+ }
16790
+ return { pkg, fullSlug: `@${spaceSlug}/${pkgSlug}` };
16791
+ }
16792
+ const results = await Promise.allSettled(
16793
+ allSpaces.map(async (space) => ({
16794
+ pkg: await packmindCliHexa.getPackageBySlug({
16795
+ slug: slug3,
16796
+ spaceId: space.id
16797
+ }),
16798
+ spaceSlug: space.slug
16799
+ }))
16800
+ );
16801
+ const matches = results.filter(
16802
+ (r) => r.status === "fulfilled"
16803
+ ).map((r) => r.value);
16804
+ if (matches.length === 0) {
16805
+ const realError = results.filter((r) => r.status === "rejected").find((r) => !isNotFoundError(r.reason));
16806
+ if (realError) {
16807
+ throw realError.reason;
16808
+ }
16809
+ throw new Error(`Package '${slug3}' not found in any space.`);
16810
+ }
16811
+ if (matches.length > 1) {
16812
+ const example = `@${matches[0].spaceSlug}/${slug3}`;
16813
+ throw new Error(
16814
+ `Package '${slug3}' exists in multiple spaces (${matches.map((m) => `@${m.spaceSlug}`).join(", ")}). Please specify the space using the @space/package format (e.g. ${example}).`
16815
+ );
16816
+ }
16817
+ return {
16818
+ pkg: matches[0].pkg,
16819
+ fullSlug: `@${matches[0].spaceSlug}/${slug3}`
16820
+ };
16821
+ }
16822
+ async function showPackageHandler(args2, deps) {
16823
+ const { packmindCliHexa, exit } = deps;
16824
+ try {
16825
+ logInfoConsole(`Fetching package details for '${args2.slug}'...`);
16826
+ const { pkg, fullSlug } = await resolvePackage(args2.slug, packmindCliHexa);
16827
+ logConsole(`
16828
+ ${pkg.name} (${fullSlug}):
16829
+ `);
16830
+ if (pkg.description) {
16831
+ logConsole(`${pkg.description}
16832
+ `);
16833
+ }
16834
+ if (pkg.standards && pkg.standards.length > 0) {
16835
+ logConsole("Standards:");
16836
+ pkg.standards.forEach((standard) => {
16837
+ if (standard.summary) {
16838
+ logConsole(` - ${standard.name}: ${standard.summary}`);
16839
+ } else {
16840
+ logConsole(` - ${standard.name}`);
16841
+ }
16842
+ });
16843
+ logConsole("");
16844
+ }
16845
+ if (pkg.recipes && pkg.recipes.length > 0) {
16846
+ logConsole("Commands:");
16847
+ pkg.recipes.forEach((recipe) => {
16848
+ if (recipe.summary) {
16849
+ logConsole(` - ${recipe.name}: ${recipe.summary}`);
16850
+ } else {
16851
+ logConsole(` - ${recipe.name}`);
16852
+ }
16853
+ });
16854
+ logConsole("");
16855
+ }
16856
+ if (pkg.skills && pkg.skills.length > 0) {
16857
+ logConsole("Skills:");
16858
+ pkg.skills.forEach((skill) => {
16859
+ if (skill.summary) {
16860
+ logConsole(` - ${skill.name}: ${skill.summary}`);
16861
+ } else {
16862
+ logConsole(` - ${skill.name}`);
16863
+ }
16864
+ });
16865
+ logConsole("");
16866
+ }
16867
+ exit(0);
16868
+ } catch (err) {
16869
+ logErrorConsole("Failed to fetch package details:");
16870
+ if (err instanceof Error) {
16871
+ logErrorConsole(err.message);
16872
+ } else {
16873
+ logErrorConsole(String(err));
16874
+ }
16875
+ exit(1);
16876
+ }
16877
+ }
16878
+
16879
+ // apps/cli/src/infra/commands/packages/showPackageCommand.ts
16793
16880
  var showPackageCommand = (0, import_cmd_ts23.command)({
16794
16881
  name: "show",
16795
16882
  description: "Show details of a specific package",
@@ -16826,14 +16913,96 @@ var import_cmd_ts31 = __toESM(require_cjs());
16826
16913
  var import_fs21 = require("fs");
16827
16914
  var import_cmd_ts25 = __toESM(require_cjs());
16828
16915
 
16829
- // apps/cli/src/infra/commands/playbook/addHandler.ts
16916
+ // apps/cli/src/infra/repositories/PlaybookLocalRepository.ts
16917
+ var crypto = __toESM(require("crypto"));
16830
16918
  var fs23 = __toESM(require("fs"));
16831
- var path26 = __toESM(require("path"));
16919
+ var os5 = __toESM(require("os"));
16920
+ var path23 = __toESM(require("path"));
16921
+ var yaml = __toESM(require("yaml"));
16922
+ var PlaybookLocalRepository = class {
16923
+ constructor(repoRoot) {
16924
+ const normalized = this.normalizeRepoRoot(repoRoot);
16925
+ const hash = crypto.createHash("md5").update(normalized).digest("hex");
16926
+ this.storagePath = path23.join(
16927
+ os5.homedir(),
16928
+ ".packmind",
16929
+ hash,
16930
+ "playbook.yaml"
16931
+ );
16932
+ }
16933
+ addChange(entry) {
16934
+ const data = this.readYaml();
16935
+ const existingIndex = data.changes.findIndex(
16936
+ (c) => c.filePath === entry.filePath && c.spaceId === entry.spaceId
16937
+ );
16938
+ if (existingIndex >= 0) {
16939
+ data.changes[existingIndex] = entry;
16940
+ } else {
16941
+ data.changes.push(entry);
16942
+ }
16943
+ this.writeYaml(data);
16944
+ }
16945
+ removeChange(filePath, spaceId) {
16946
+ const data = this.readYaml();
16947
+ const initialLength = data.changes.length;
16948
+ data.changes = data.changes.filter(
16949
+ (c) => !(c.filePath === filePath && c.spaceId === spaceId)
16950
+ );
16951
+ if (data.changes.length === initialLength) {
16952
+ return false;
16953
+ }
16954
+ this.writeYaml(data);
16955
+ return true;
16956
+ }
16957
+ getChanges() {
16958
+ return this.readYaml().changes;
16959
+ }
16960
+ getChange(filePath, spaceId) {
16961
+ return this.readYaml().changes.find(
16962
+ (c) => c.filePath === filePath && c.spaceId === spaceId
16963
+ ) ?? null;
16964
+ }
16965
+ clearAll() {
16966
+ this.writeYaml({ version: 1, changes: [] });
16967
+ }
16968
+ normalizeRepoRoot(repoRoot) {
16969
+ let normalized = repoRoot.replace(/\\/g, "/");
16970
+ normalized = normalized.replace(/\/$/, "");
16971
+ return normalized;
16972
+ }
16973
+ readYaml() {
16974
+ if (!fs23.existsSync(this.storagePath)) {
16975
+ return { version: 1, changes: [] };
16976
+ }
16977
+ try {
16978
+ const content = fs23.readFileSync(this.storagePath, "utf-8");
16979
+ const parsed = yaml.parse(content);
16980
+ if (!parsed || !Array.isArray(parsed.changes)) {
16981
+ return { version: 1, changes: [] };
16982
+ }
16983
+ return { version: 1, changes: parsed.changes };
16984
+ } catch {
16985
+ logWarningConsole(
16986
+ `Corrupted playbook file: ${this.storagePath}. Treating as empty.`
16987
+ );
16988
+ return { version: 1, changes: [] };
16989
+ }
16990
+ }
16991
+ writeYaml(data) {
16992
+ const dir = path23.dirname(this.storagePath);
16993
+ fs23.mkdirSync(dir, { recursive: true });
16994
+ fs23.writeFileSync(this.storagePath, yaml.stringify(data), "utf-8");
16995
+ }
16996
+ };
16997
+
16998
+ // apps/cli/src/infra/commands/playbook/addHandler.ts
16999
+ var fs24 = __toESM(require("fs"));
17000
+ var path27 = __toESM(require("path"));
16832
17001
  var yaml2 = __toESM(require("yaml"));
16833
17002
  var import_slug = __toESM(require("slug"));
16834
17003
 
16835
17004
  // apps/cli/src/application/utils/parseCommandFile.ts
16836
- var path23 = __toESM(require("path"));
17005
+ var path24 = __toESM(require("path"));
16837
17006
  var FRONTMATTER_DELIMITER3 = "---";
16838
17007
  function parseCommandFile(content, filePath) {
16839
17008
  content = normalizeLineEndings(content);
@@ -16889,7 +17058,7 @@ function stripYamlQuotes2(value) {
16889
17058
  return value;
16890
17059
  }
16891
17060
  function extractFilenameSlug(filePath) {
16892
- let basename4 = path23.basename(filePath);
17061
+ let basename4 = path24.basename(filePath);
16893
17062
  if (basename4.endsWith(".prompt.md")) {
16894
17063
  basename4 = basename4.slice(0, -".prompt.md".length);
16895
17064
  } else if (basename4.endsWith(".md")) {
@@ -17056,7 +17225,7 @@ function parseSkillDirectory(files) {
17056
17225
  }
17057
17226
 
17058
17227
  // apps/cli/src/application/utils/findNearestConfigDir.ts
17059
- var path24 = __toESM(require("path"));
17228
+ var path25 = __toESM(require("path"));
17060
17229
  async function findNearestConfigDir(startDir, packmindCliHexa) {
17061
17230
  let current = startDir;
17062
17231
  while (true) {
@@ -17064,7 +17233,7 @@ async function findNearestConfigDir(startDir, packmindCliHexa) {
17064
17233
  if (exists) {
17065
17234
  return current;
17066
17235
  }
17067
- const parent = path24.dirname(current);
17236
+ const parent = path25.dirname(current);
17068
17237
  if (parent === current) {
17069
17238
  return null;
17070
17239
  }
@@ -17073,7 +17242,7 @@ async function findNearestConfigDir(startDir, packmindCliHexa) {
17073
17242
  }
17074
17243
 
17075
17244
  // apps/cli/src/application/utils/resolveDeployedContext.ts
17076
- var path25 = __toESM(require("path"));
17245
+ var path26 = __toESM(require("path"));
17077
17246
  async function resolveDeployedContext(packmindCliHexa, targetDir) {
17078
17247
  try {
17079
17248
  const space = await packmindCliHexa.getDefaultSpace();
@@ -17085,7 +17254,7 @@ async function resolveDeployedContext(packmindCliHexa, targetDir) {
17085
17254
  }
17086
17255
  const gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(gitRoot);
17087
17256
  const gitBranch = packmindCliHexa.getCurrentBranch(gitRoot);
17088
- const rel = path25.relative(gitRoot, targetDir);
17257
+ const rel = path26.relative(gitRoot, targetDir);
17089
17258
  const relativePath = rel.startsWith("..") ? "/" : rel ? `/${rel}/` : "/";
17090
17259
  const deployedContent = await packmindCliHexa.getPackmindGateway().deployment.getDeployed({
17091
17260
  packagesSlugs: configPackages,
@@ -17150,19 +17319,19 @@ async function fetchDeployedFiles(gateway, lockFile) {
17150
17319
 
17151
17320
  // apps/cli/src/infra/commands/playbook/addHandler.ts
17152
17321
  async function tryStageRemovedFromLockFile(resolvedPath, deps) {
17153
- const fileDir = path26.dirname(resolvedPath);
17322
+ const fileDir = path27.dirname(resolvedPath);
17154
17323
  const targetDir = await findNearestConfigDir(fileDir, deps.packmindCliHexa);
17155
17324
  if (!targetDir) return false;
17156
17325
  const lockFile = await deps.lockFileRepository.read(targetDir);
17157
17326
  if (!lockFile) return false;
17158
- const normalizedPath = normalizePath2(path26.relative(targetDir, resolvedPath));
17327
+ const normalizedPath = normalizePath2(path27.relative(targetDir, resolvedPath));
17159
17328
  const lockEntry = findLockFileEntryForPath(
17160
17329
  normalizedPath,
17161
17330
  lockFile.artifacts
17162
17331
  );
17163
17332
  if (!lockEntry) return false;
17164
17333
  const gitRoot = await deps.packmindCliHexa.tryGetGitRepositoryRoot(targetDir);
17165
- const configDir = gitRoot ? normalizePath2(path26.relative(gitRoot, targetDir)) : "";
17334
+ const configDir = gitRoot ? normalizePath2(path27.relative(gitRoot, targetDir)) : "";
17166
17335
  const deployedContext = await resolveDeployedContext(
17167
17336
  deps.packmindCliHexa,
17168
17337
  targetDir
@@ -17194,22 +17363,22 @@ async function tryStageRemovedFromLockFile(resolvedPath, deps) {
17194
17363
  }
17195
17364
  function resolveSkillDirectoryRoot(absolutePath) {
17196
17365
  if (absolutePath.endsWith("SKILL.md")) {
17197
- return path26.dirname(absolutePath);
17366
+ return path27.dirname(absolutePath);
17198
17367
  }
17199
17368
  try {
17200
- if (fs23.statSync(absolutePath).isDirectory()) {
17369
+ if (fs24.statSync(absolutePath).isDirectory()) {
17201
17370
  return absolutePath;
17202
17371
  }
17203
17372
  } catch {
17204
17373
  return absolutePath;
17205
17374
  }
17206
- let current = path26.dirname(absolutePath);
17207
- const root = path26.parse(current).root;
17375
+ let current = path27.dirname(absolutePath);
17376
+ const root = path27.parse(current).root;
17208
17377
  while (current !== root) {
17209
- if (fs23.existsSync(path26.join(current, "SKILL.md"))) {
17378
+ if (fs24.existsSync(path27.join(current, "SKILL.md"))) {
17210
17379
  return current;
17211
17380
  }
17212
- current = path26.dirname(current);
17381
+ current = path27.dirname(current);
17213
17382
  }
17214
17383
  return absolutePath;
17215
17384
  }
@@ -17220,7 +17389,7 @@ async function playbookAddHandler(deps) {
17220
17389
  spaceSlug,
17221
17390
  exit,
17222
17391
  cwd,
17223
- readFile: readFile10,
17392
+ readFile: readFile11,
17224
17393
  readSkillDirectory: readSkillDirectory2,
17225
17394
  playbookLocalRepository,
17226
17395
  lockFileRepository
@@ -17232,17 +17401,17 @@ async function playbookAddHandler(deps) {
17232
17401
  exit(1);
17233
17402
  return;
17234
17403
  }
17235
- const absolutePath = path26.resolve(cwd, filePath);
17404
+ const absolutePath = path27.resolve(cwd, filePath);
17236
17405
  let artifactType;
17237
17406
  let codingAgent;
17238
17407
  const earlyTargetDir = await findNearestConfigDir(
17239
- path26.dirname(absolutePath),
17408
+ path27.dirname(absolutePath),
17240
17409
  packmindCliHexa
17241
17410
  );
17242
17411
  const earlyLockFile = earlyTargetDir ? await lockFileRepository.read(earlyTargetDir) : null;
17243
17412
  if (earlyLockFile && earlyTargetDir) {
17244
17413
  const normalizedForLookup = normalizePath2(
17245
- path26.relative(earlyTargetDir, absolutePath)
17414
+ path27.relative(earlyTargetDir, absolutePath)
17246
17415
  );
17247
17416
  const lockResult = findLockFileEntryAndFileForPath(
17248
17417
  normalizedForLookup,
@@ -17322,7 +17491,7 @@ async function playbookAddHandler(deps) {
17322
17491
  localContent = skillMdFile?.content ?? serializedContent;
17323
17492
  } else {
17324
17493
  try {
17325
- localContent = readFile10(absolutePath);
17494
+ localContent = readFile11(absolutePath);
17326
17495
  } catch (err) {
17327
17496
  const staged = await tryStageRemovedFromLockFile(absolutePath, {
17328
17497
  packmindCliHexa,
@@ -17376,7 +17545,7 @@ Content goes here...`
17376
17545
  return;
17377
17546
  }
17378
17547
  const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(targetDir);
17379
- const configDir = gitRoot ? normalizePath2(path26.relative(gitRoot, targetDir)) : "";
17548
+ const configDir = gitRoot ? normalizePath2(path27.relative(gitRoot, targetDir)) : "";
17380
17549
  const deployedContext = await resolveDeployedContext(
17381
17550
  packmindCliHexa,
17382
17551
  targetDir
@@ -17384,7 +17553,7 @@ Content goes here...`
17384
17553
  const targetId = deployedContext?.targetId ?? earlyLockFile?.targetId;
17385
17554
  const normalizedFilePath = (() => {
17386
17555
  const refPath = artifactType === "skill" && skillDirPath ? skillDirPath : absolutePath;
17387
- return normalizePath2(path26.relative(targetDir, refPath));
17556
+ return normalizePath2(path27.relative(targetDir, refPath));
17388
17557
  })();
17389
17558
  let spaceId;
17390
17559
  let spaceName;
@@ -17499,7 +17668,7 @@ Run ${formatLabel("packmind-cli install")} to update before making changes.`
17499
17668
  );
17500
17669
  const allMatch = skillDeployedFiles.length > 0 && skillDeployedFiles.length === skillFiles.length && skillDeployedFiles.every((deployed) => {
17501
17670
  const localFile = skillFiles.find(
17502
- (f) => normalizePath2(path26.join(normalizedFilePath, f.relativePath)) === normalizePath2(deployed.path)
17671
+ (f) => normalizePath2(path27.join(normalizedFilePath, f.relativePath)) === normalizePath2(deployed.path)
17503
17672
  );
17504
17673
  return localFile && deployed.content?.trim() === localFile.content.trim() && (!deployed.skillFilePermissions || deployed.skillFilePermissions === localFile.permissions);
17505
17674
  });
@@ -17611,8 +17780,8 @@ var addPlaybookCommand = (0, import_cmd_ts25.command)({
17611
17780
  var import_cmd_ts26 = __toESM(require_cjs());
17612
17781
 
17613
17782
  // apps/cli/src/infra/commands/playbook/rmHandler.ts
17614
- var fs24 = __toESM(require("fs"));
17615
- var path27 = __toESM(require("path"));
17783
+ var fs25 = __toESM(require("fs"));
17784
+ var path28 = __toESM(require("path"));
17616
17785
  function isSkillSupportFile(absolutePath) {
17617
17786
  const normalized = absolutePath.replace(/\\/g, "/");
17618
17787
  const skillDirMatch = normalized.match(/\/skills\/[^/]+\//);
@@ -17639,14 +17808,14 @@ async function playbookRmHandler(deps) {
17639
17808
  exit(1);
17640
17809
  return;
17641
17810
  }
17642
- const absolutePath = path27.resolve(getCwd(), filePath);
17643
- if (!fs24.existsSync(absolutePath)) {
17811
+ const absolutePath = path28.resolve(getCwd(), filePath);
17812
+ if (!fs25.existsSync(absolutePath)) {
17644
17813
  logErrorConsole(`File not found: "${filePath}"`);
17645
17814
  exit(1);
17646
17815
  return;
17647
17816
  }
17648
17817
  const targetDir = await findNearestConfigDir(
17649
- path27.dirname(absolutePath),
17818
+ path28.dirname(absolutePath),
17650
17819
  packmindCliHexa
17651
17820
  );
17652
17821
  if (!targetDir) {
@@ -17663,7 +17832,7 @@ async function playbookRmHandler(deps) {
17663
17832
  return;
17664
17833
  }
17665
17834
  const normalizedForLookup = normalizePath2(
17666
- path27.relative(targetDir, absolutePath)
17835
+ path28.relative(targetDir, absolutePath)
17667
17836
  );
17668
17837
  const lockResult = findLockFileEntryAndFileForPath(
17669
17838
  normalizedForLookup,
@@ -17685,7 +17854,7 @@ async function playbookRmHandler(deps) {
17685
17854
  }
17686
17855
  const resolvedAbsolutePath = artifactType === "skill" ? resolveSkillDirPath(absolutePath) : absolutePath;
17687
17856
  const normalizedFilePath = normalizePath2(
17688
- path27.relative(targetDir, resolvedAbsolutePath)
17857
+ path28.relative(targetDir, resolvedAbsolutePath)
17689
17858
  );
17690
17859
  const lockEntry = findLockFileEntryAndFileForPath(normalizedFilePath, lockFile.artifacts)?.entry ?? lockResult.entry;
17691
17860
  if (!lockEntry) {
@@ -17713,7 +17882,7 @@ async function playbookRmHandler(deps) {
17713
17882
  }
17714
17883
  const spaceName = matchingSpace.name;
17715
17884
  const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(targetDir);
17716
- const configDir = gitRoot ? normalizePath2(path27.relative(gitRoot, targetDir)) : "";
17885
+ const configDir = gitRoot ? normalizePath2(path28.relative(gitRoot, targetDir)) : "";
17717
17886
  const deployedContext = await resolveDeployedContext(
17718
17887
  packmindCliHexa,
17719
17888
  targetDir
@@ -17774,7 +17943,7 @@ var rmPlaybookCommand = (0, import_cmd_ts26.command)({
17774
17943
  var import_cmd_ts27 = __toESM(require_cjs());
17775
17944
 
17776
17945
  // apps/cli/src/infra/commands/playbook/unstageHandler.ts
17777
- var path28 = __toESM(require("path"));
17946
+ var path29 = __toESM(require("path"));
17778
17947
  async function playbookUnstageHandler(deps) {
17779
17948
  const {
17780
17949
  packmindCliHexa,
@@ -17792,10 +17961,10 @@ async function playbookUnstageHandler(deps) {
17792
17961
  return;
17793
17962
  }
17794
17963
  const cwd = getCwd();
17795
- const absolutePath = path28.resolve(cwd, filePath);
17964
+ const absolutePath = path29.resolve(cwd, filePath);
17796
17965
  const resolvedPath = resolveSkillDirPath(absolutePath);
17797
17966
  const configDir = await findNearestConfigDir(
17798
- path28.dirname(resolvedPath),
17967
+ path29.dirname(resolvedPath),
17799
17968
  packmindCliHexa
17800
17969
  );
17801
17970
  if (!configDir) {
@@ -17808,10 +17977,10 @@ async function playbookUnstageHandler(deps) {
17808
17977
  const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
17809
17978
  const baseDir = gitRoot ?? configDir;
17810
17979
  const normalizedFilePath = normalizePath2(
17811
- path28.relative(baseDir, resolvedPath)
17980
+ path29.relative(baseDir, resolvedPath)
17812
17981
  );
17813
17982
  const matchingEntries = playbookLocalRepository.getChanges().filter((c) => {
17814
- const fullEntryPath = c.configDir ? normalizePath2(path28.join(c.configDir, c.filePath)) : c.filePath;
17983
+ const fullEntryPath = c.configDir ? normalizePath2(path29.join(c.configDir, c.filePath)) : c.filePath;
17815
17984
  return fullEntryPath === normalizedFilePath;
17816
17985
  });
17817
17986
  if (matchingEntries.length === 0) {
@@ -17895,15 +18064,15 @@ var import_cmd_ts28 = __toESM(require_cjs());
17895
18064
 
17896
18065
  // apps/cli/src/infra/utils/listDirectoryFiles.ts
17897
18066
  var import_fs22 = require("fs");
17898
- var path29 = __toESM(require("path"));
18067
+ var path30 = __toESM(require("path"));
17899
18068
  function listDirectoryFiles(dirPath) {
17900
18069
  const results = [];
17901
18070
  const entries = (0, import_fs22.readdirSync)(dirPath, { withFileTypes: true });
17902
18071
  for (const entry of entries) {
17903
- const fullPath = path29.join(dirPath, entry.name);
18072
+ const fullPath = path30.join(dirPath, entry.name);
17904
18073
  if (entry.isDirectory()) {
17905
18074
  for (const nested of listDirectoryFiles(fullPath)) {
17906
- results.push(path29.join(entry.name, nested));
18075
+ results.push(path30.join(entry.name, nested));
17907
18076
  }
17908
18077
  } else if (entry.isFile()) {
17909
18078
  results.push(entry.name);
@@ -17913,7 +18082,7 @@ function listDirectoryFiles(dirPath) {
17913
18082
  }
17914
18083
 
17915
18084
  // apps/cli/src/infra/commands/playbook/statusHandler.ts
17916
- var path30 = __toESM(require("path"));
18085
+ var path31 = __toESM(require("path"));
17917
18086
 
17918
18087
  // apps/cli/src/infra/utils/stringUtils.ts
17919
18088
  function capitalize(s) {
@@ -17948,7 +18117,7 @@ function groupStagedChanges(changes, cwd, gitRoot) {
17948
18117
  const changeType = change.changeType ?? "updated";
17949
18118
  const key = `${change.artifactType}:${change.artifactName}:${changeType}`;
17950
18119
  const rootRelativePath = change.configDir ? `${change.configDir}/${change.filePath}` : change.filePath;
17951
- const displayPath = gitRoot ? normalizePath2(path30.relative(cwd, path30.join(gitRoot, rootRelativePath))) : rootRelativePath;
18120
+ const displayPath = gitRoot ? normalizePath2(path31.relative(cwd, path31.join(gitRoot, rootRelativePath))) : rootRelativePath;
17952
18121
  const existing = groups.get(key);
17953
18122
  if (existing) {
17954
18123
  existing.filePaths.push(displayPath);
@@ -17989,7 +18158,7 @@ async function playbookStatusHandler(deps) {
17989
18158
  lockFileRepository,
17990
18159
  cwd,
17991
18160
  exit,
17992
- readFile: readFile10,
18161
+ readFile: readFile11,
17993
18162
  listDirectoryFiles: listDirectoryFiles2,
17994
18163
  getFileMode
17995
18164
  } = deps;
@@ -18006,12 +18175,12 @@ async function playbookStatusHandler(deps) {
18006
18175
  const fallbackConfigDir = await findNearestConfigDir(cwd, packmindCliHexa);
18007
18176
  const configDirs = /* @__PURE__ */ new Set([...stagedByConfigDir.keys()]);
18008
18177
  if (fallbackConfigDir && !configDirs.has("__cwd__")) {
18009
- const rel = gitRoot ? normalizePath2(path30.relative(gitRoot, fallbackConfigDir)) : "";
18178
+ const rel = gitRoot ? normalizePath2(path31.relative(gitRoot, fallbackConfigDir)) : "";
18010
18179
  if (!configDirs.has(rel)) configDirs.add(rel);
18011
18180
  }
18012
18181
  const descendantDirs = await packmindCliHexa.findDescendantConfigs(cwd);
18013
18182
  for (const descendantDir of descendantDirs) {
18014
- const rel = gitRoot ? normalizePath2(path30.relative(gitRoot, descendantDir)) : normalizePath2(path30.relative(cwd, descendantDir));
18183
+ const rel = gitRoot ? normalizePath2(path31.relative(gitRoot, descendantDir)) : normalizePath2(path31.relative(cwd, descendantDir));
18015
18184
  if (!configDirs.has(rel)) configDirs.add(rel);
18016
18185
  }
18017
18186
  for (const configDirKey of configDirs) {
@@ -18019,7 +18188,7 @@ async function playbookStatusHandler(deps) {
18019
18188
  if (configDirKey === "__cwd__") {
18020
18189
  projectDir = fallbackConfigDir;
18021
18190
  } else if (gitRoot) {
18022
- projectDir = path30.join(gitRoot, configDirKey);
18191
+ projectDir = path31.join(gitRoot, configDirKey);
18023
18192
  } else {
18024
18193
  continue;
18025
18194
  }
@@ -18044,11 +18213,11 @@ async function playbookStatusHandler(deps) {
18044
18213
  continue;
18045
18214
  }
18046
18215
  const displayPath = normalizePath2(
18047
- path30.relative(cwd, path30.join(projectDir, deployedFile.path))
18216
+ path31.relative(cwd, path31.join(projectDir, deployedFile.path))
18048
18217
  );
18049
18218
  let localContent;
18050
18219
  try {
18051
- localContent = readFile10(path30.join(projectDir, deployedFile.path));
18220
+ localContent = readFile11(path31.join(projectDir, deployedFile.path));
18052
18221
  } catch {
18053
18222
  const artifact = findArtifactForFile(
18054
18223
  deployedFile.path,
@@ -18077,7 +18246,7 @@ async function playbookStatusHandler(deps) {
18077
18246
  });
18078
18247
  }
18079
18248
  } else if (deployedFile.skillFilePermissions && getFileMode) {
18080
- const localMode = getFileMode(path30.join(projectDir, deployedFile.path));
18249
+ const localMode = getFileMode(path31.join(projectDir, deployedFile.path));
18081
18250
  if (localMode !== null) {
18082
18251
  const localPermissions = modeToPermissionStringOrDefault(localMode);
18083
18252
  if (localPermissions !== deployedFile.skillFilePermissions) {
@@ -18106,13 +18275,13 @@ async function playbookStatusHandler(deps) {
18106
18275
  (f) => normalizePath2(f.path).endsWith("/SKILL.md")
18107
18276
  );
18108
18277
  if (!skillMdFile) continue;
18109
- const skillDir = normalizePath2(path30.dirname(skillMdFile.path));
18278
+ const skillDir = normalizePath2(path31.dirname(skillMdFile.path));
18110
18279
  if (targetStagedPaths.has(skillDir) || targetSkillDirPaths.some(
18111
18280
  (staged) => skillDir === staged || skillDir.startsWith(staged + "/")
18112
18281
  )) {
18113
18282
  continue;
18114
18283
  }
18115
- const absoluteSkillDir = path30.join(projectDir, skillDir);
18284
+ const absoluteSkillDir = path31.join(projectDir, skillDir);
18116
18285
  let localFiles;
18117
18286
  try {
18118
18287
  localFiles = listDirectoryFiles2(absoluteSkillDir);
@@ -18121,11 +18290,11 @@ async function playbookStatusHandler(deps) {
18121
18290
  }
18122
18291
  for (const localRelPath of localFiles) {
18123
18292
  const normalizedLocalPath = normalizePath2(
18124
- path30.join(skillDir, localRelPath)
18293
+ path31.join(skillDir, localRelPath)
18125
18294
  );
18126
18295
  if (!deployedPathSet.has(normalizedLocalPath)) {
18127
18296
  const displayPath = normalizePath2(
18128
- path30.relative(cwd, path30.join(projectDir, normalizedLocalPath))
18297
+ path31.relative(cwd, path31.join(projectDir, normalizedLocalPath))
18129
18298
  );
18130
18299
  untrackedChanges.push({
18131
18300
  artifactName: entry.name,
@@ -18213,7 +18382,7 @@ var import_path5 = require("path");
18213
18382
  var import_cmd_ts29 = __toESM(require_cjs());
18214
18383
 
18215
18384
  // apps/cli/src/infra/commands/playbook/submitHandler.ts
18216
- var path32 = __toESM(require("path"));
18385
+ var path33 = __toESM(require("path"));
18217
18386
 
18218
18387
  // apps/cli/src/infra/commands/playbook/submit/duplicateNameChecker.ts
18219
18388
  var import_slug2 = __toESM(require("slug"));
@@ -18275,7 +18444,7 @@ async function checkForDuplicateNames(createdEntries, packmindGateway) {
18275
18444
  }
18276
18445
 
18277
18446
  // apps/cli/src/infra/commands/playbook/submit/targetContextResolver.ts
18278
- var path31 = __toESM(require("path"));
18447
+ var path32 = __toESM(require("path"));
18279
18448
  async function createTargetContextResolver(deps) {
18280
18449
  const { lockFileRepository, cwd, packmindCliHexa } = deps;
18281
18450
  const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
@@ -18286,7 +18455,7 @@ async function createTargetContextResolver(deps) {
18286
18455
  if (cache.has(key)) return cache.get(key);
18287
18456
  let projectDir;
18288
18457
  if (entry.configDir !== void 0 && gitRoot) {
18289
- projectDir = path31.join(gitRoot, entry.configDir);
18458
+ projectDir = path32.join(gitRoot, entry.configDir);
18290
18459
  } else {
18291
18460
  projectDir = await findNearestConfigDir(cwd, packmindCliHexa);
18292
18461
  }
@@ -19234,7 +19403,7 @@ Only one agent version can be submitted at a time. Use "playbook unstage" to rem
19234
19403
  const entryCtx = resolver.getCachedContext(entry.configDir);
19235
19404
  if (!entryCtx?.projectDir) continue;
19236
19405
  try {
19237
- const fullPath = path32.join(entryCtx.projectDir, entry.filePath);
19406
+ const fullPath = path33.join(entryCtx.projectDir, entry.filePath);
19238
19407
  if (entry.artifactType === "skill") {
19239
19408
  deps.rmSync(fullPath, { recursive: true });
19240
19409
  } else {
@@ -19262,7 +19431,7 @@ Only one agent version can be submitted at a time. Use "playbook unstage" to rem
19262
19431
  const entryCtx = resolver.getCachedContext(entry.configDir);
19263
19432
  if (!entryCtx?.projectDir) continue;
19264
19433
  try {
19265
- const fullPath = path32.join(entryCtx.projectDir, entry.filePath);
19434
+ const fullPath = path33.join(entryCtx.projectDir, entry.filePath);
19266
19435
  if (entry.artifactType === "skill") {
19267
19436
  deps.rmSync(fullPath, { recursive: true });
19268
19437
  } else {
@@ -19384,7 +19553,7 @@ var diffCommand2 = (0, import_cmd_ts30.command)({
19384
19553
  type: (0, import_cmd_ts30.optional)(import_cmd_ts30.string)
19385
19554
  })
19386
19555
  },
19387
- handler: async ({ includeSubmitted, path: path36 }) => {
19556
+ handler: async ({ includeSubmitted, path: path37 }) => {
19388
19557
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
19389
19558
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
19390
19559
  await diffArtefactsHandler({
@@ -19393,7 +19562,7 @@ var diffCommand2 = (0, import_cmd_ts30.command)({
19393
19562
  getCwd: () => process.cwd(),
19394
19563
  log: console.log,
19395
19564
  includeSubmitted,
19396
- path: path36
19565
+ path: path37
19397
19566
  });
19398
19567
  }
19399
19568
  });
@@ -19482,8 +19651,8 @@ var import_cmd_ts39 = __toESM(require_cjs());
19482
19651
  var import_cmd_ts38 = __toESM(require_cjs());
19483
19652
 
19484
19653
  // apps/cli/src/application/services/AgentArtifactDetectionService.ts
19485
- var fs25 = __toESM(require("fs/promises"));
19486
- var path33 = __toESM(require("path"));
19654
+ var fs26 = __toESM(require("fs/promises"));
19655
+ var path34 = __toESM(require("path"));
19487
19656
  var AGENT_ARTIFACT_CHECKS = [
19488
19657
  { agent: "claude", paths: [".claude"] },
19489
19658
  { agent: "cursor", paths: [".cursor"] },
@@ -19512,7 +19681,7 @@ var AgentArtifactDetectionService = class {
19512
19681
  }
19513
19682
  } else {
19514
19683
  for (const relativePath of check.paths) {
19515
- const fullPath = path33.join(baseDirectory, relativePath);
19684
+ const fullPath = path34.join(baseDirectory, relativePath);
19516
19685
  const exists = await this.pathExists(fullPath);
19517
19686
  if (exists) {
19518
19687
  detected.push({
@@ -19528,7 +19697,7 @@ var AgentArtifactDetectionService = class {
19528
19697
  }
19529
19698
  async pathExists(filePath) {
19530
19699
  try {
19531
- await fs25.access(filePath);
19700
+ await fs26.access(filePath);
19532
19701
  return true;
19533
19702
  } catch {
19534
19703
  return false;
@@ -19539,16 +19708,16 @@ var AgentArtifactDetectionService = class {
19539
19708
  while (queue.length > 0) {
19540
19709
  const currentDir = queue.shift();
19541
19710
  for (const targetPath of targetPaths) {
19542
- const fullPath = path33.join(currentDir, targetPath);
19711
+ const fullPath = path34.join(currentDir, targetPath);
19543
19712
  if (await this.pathExists(fullPath)) {
19544
19713
  return fullPath;
19545
19714
  }
19546
19715
  }
19547
19716
  try {
19548
- const entries = await fs25.readdir(currentDir, { withFileTypes: true });
19717
+ const entries = await fs26.readdir(currentDir, { withFileTypes: true });
19549
19718
  for (const entry of entries) {
19550
19719
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
19551
- queue.push(path33.join(currentDir, entry.name));
19720
+ queue.push(path34.join(currentDir, entry.name));
19552
19721
  }
19553
19722
  }
19554
19723
  } catch {
@@ -19563,18 +19732,18 @@ var readline4 = __toESM(require("readline"));
19563
19732
  var inquirer2 = __toESM(require("inquirer"));
19564
19733
 
19565
19734
  // apps/cli/src/infra/commands/config/agents/agentsHandlerUtils.ts
19566
- var path34 = __toESM(require("path"));
19567
- var fs26 = __toESM(require("fs/promises"));
19735
+ var path35 = __toESM(require("path"));
19736
+ var fs27 = __toESM(require("fs/promises"));
19568
19737
  function getRelativePath(dir, startDirectory) {
19569
19738
  if (dir === startDirectory) return "./packmind.json";
19570
- return "./" + path34.relative(startDirectory, dir) + "/packmind.json";
19739
+ return "./" + path35.relative(startDirectory, dir) + "/packmind.json";
19571
19740
  }
19572
19741
  async function resolveStartDirectory(args2, getCwd, exit) {
19573
19742
  let startDirectory = getCwd();
19574
19743
  if (args2.path) {
19575
- const resolvedPath = path34.resolve(getCwd(), args2.path);
19744
+ const resolvedPath = path35.resolve(getCwd(), args2.path);
19576
19745
  try {
19577
- const stat9 = await fs26.stat(resolvedPath);
19746
+ const stat9 = await fs27.stat(resolvedPath);
19578
19747
  if (!stat9.isDirectory()) {
19579
19748
  logErrorConsole(`Path is not a directory: ${resolvedPath}`);
19580
19749
  exit(1);
@@ -19685,7 +19854,7 @@ async function promptAgentsWithReadline2(choices) {
19685
19854
  output.write("\n");
19686
19855
  const preselected = choices.map((c, i) => c.checked ? i + 1 : null).filter((i) => i !== null);
19687
19856
  const defaultValue = preselected.length > 0 ? preselected.join(",") : "1,2,3";
19688
- return new Promise((resolve14) => {
19857
+ return new Promise((resolve15) => {
19689
19858
  rl.question(
19690
19859
  `Enter numbers separated by commas (default: ${defaultValue}): `,
19691
19860
  (answer) => {
@@ -19694,7 +19863,7 @@ async function promptAgentsWithReadline2(choices) {
19694
19863
  const numbersStr = trimmed === "" ? defaultValue : trimmed;
19695
19864
  const numbers = numbersStr.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n) && n >= 1 && n <= choices.length);
19696
19865
  const selectedAgents = numbers.map((n) => choices[n - 1].value);
19697
- resolve14(selectedAgents);
19866
+ resolve15(selectedAgents);
19698
19867
  }
19699
19868
  );
19700
19869
  });
@@ -19841,14 +20010,14 @@ To restore organization settings later, remove all local agents with: packmind-c
19841
20010
 
19842
20011
  // apps/cli/src/infra/commands/config/ConfigAgentsAddCommand.ts
19843
20012
  function createPromptConfirm() {
19844
- return (message) => new Promise((resolve14) => {
20013
+ return (message) => new Promise((resolve15) => {
19845
20014
  const rl = readline5.createInterface({
19846
20015
  input: process.stdin,
19847
20016
  output: process.stdout
19848
20017
  });
19849
20018
  rl.question(`${message} (y/N) `, (answer) => {
19850
20019
  rl.close();
19851
- resolve14(answer.toLowerCase() === "y");
20020
+ resolve15(answer.toLowerCase() === "y");
19852
20021
  });
19853
20022
  });
19854
20023
  }
@@ -20263,20 +20432,20 @@ function findEnvFile() {
20263
20432
  const currentDir = process.cwd();
20264
20433
  const gitService = new GitService();
20265
20434
  const gitRoot = gitService.getGitRepositoryRootSync(currentDir);
20266
- const filesystemRoot = path35.parse(currentDir).root;
20435
+ const filesystemRoot = path36.parse(currentDir).root;
20267
20436
  const stopDir = gitRoot ?? filesystemRoot;
20268
20437
  let searchDir = currentDir;
20269
- let parentDir = path35.dirname(searchDir);
20438
+ let parentDir = path36.dirname(searchDir);
20270
20439
  while (searchDir !== parentDir) {
20271
- const envPath2 = path35.join(searchDir, ".env");
20272
- if (fs27.existsSync(envPath2)) {
20440
+ const envPath2 = path36.join(searchDir, ".env");
20441
+ if (fs28.existsSync(envPath2)) {
20273
20442
  return envPath2;
20274
20443
  }
20275
20444
  if (searchDir === stopDir) {
20276
20445
  return null;
20277
20446
  }
20278
20447
  searchDir = parentDir;
20279
- parentDir = path35.dirname(searchDir);
20448
+ parentDir = path36.dirname(searchDir);
20280
20449
  }
20281
20450
  return null;
20282
20451
  }