@packmind/cli 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/main.cjs +1234 -886
  2. package/package.json +5 -4
package/main.cjs CHANGED
@@ -371,32 +371,32 @@ var init_supports_color = __esm({
371
371
  });
372
372
 
373
373
  // node_modules/chalk/source/utilities.js
374
- function stringReplaceAll(string22, substring, replacer) {
375
- let index = string22.indexOf(substring);
374
+ function stringReplaceAll(string18, substring, replacer) {
375
+ let index = string18.indexOf(substring);
376
376
  if (index === -1) {
377
- return string22;
377
+ return string18;
378
378
  }
379
379
  const substringLength = substring.length;
380
380
  let endIndex = 0;
381
381
  let returnValue = "";
382
382
  do {
383
- returnValue += string22.slice(endIndex, index) + substring + replacer;
383
+ returnValue += string18.slice(endIndex, index) + substring + replacer;
384
384
  endIndex = index + substringLength;
385
- index = string22.indexOf(substring, endIndex);
385
+ index = string18.indexOf(substring, endIndex);
386
386
  } while (index !== -1);
387
- returnValue += string22.slice(endIndex);
387
+ returnValue += string18.slice(endIndex);
388
388
  return returnValue;
389
389
  }
390
- function stringEncaseCRLFWithFirstIndex(string22, prefix, postfix, index) {
390
+ function stringEncaseCRLFWithFirstIndex(string18, prefix, postfix, index) {
391
391
  let endIndex = 0;
392
392
  let returnValue = "";
393
393
  do {
394
- const gotCR = string22[index - 1] === "\r";
395
- returnValue += string22.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
394
+ const gotCR = string18[index - 1] === "\r";
395
+ returnValue += string18.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
396
396
  endIndex = index + 1;
397
- index = string22.indexOf("\n", endIndex);
397
+ index = string18.indexOf("\n", endIndex);
398
398
  } while (index !== -1);
399
- returnValue += string22.slice(endIndex);
399
+ returnValue += string18.slice(endIndex);
400
400
  return returnValue;
401
401
  }
402
402
  var init_utilities = __esm({
@@ -555,26 +555,26 @@ var init_source = __esm({
555
555
  builder[IS_EMPTY] = _isEmpty;
556
556
  return builder;
557
557
  };
558
- applyStyle = (self, string22) => {
559
- if (self.level <= 0 || !string22) {
560
- return self[IS_EMPTY] ? "" : string22;
558
+ applyStyle = (self, string18) => {
559
+ if (self.level <= 0 || !string18) {
560
+ return self[IS_EMPTY] ? "" : string18;
561
561
  }
562
562
  let styler = self[STYLER];
563
563
  if (styler === void 0) {
564
- return string22;
564
+ return string18;
565
565
  }
566
566
  const { openAll, closeAll } = styler;
567
- if (string22.includes("\x1B")) {
567
+ if (string18.includes("\x1B")) {
568
568
  while (styler !== void 0) {
569
- string22 = stringReplaceAll(string22, styler.close, styler.open);
569
+ string18 = stringReplaceAll(string18, styler.close, styler.open);
570
570
  styler = styler.parent;
571
571
  }
572
572
  }
573
- const lfIndex = string22.indexOf("\n");
573
+ const lfIndex = string18.indexOf("\n");
574
574
  if (lfIndex !== -1) {
575
- string22 = stringEncaseCRLFWithFirstIndex(string22, closeAll, openAll, lfIndex);
575
+ string18 = stringEncaseCRLFWithFirstIndex(string18, closeAll, openAll, lfIndex);
576
576
  }
577
- return openAll + string22 + closeAll;
577
+ return openAll + string18 + closeAll;
578
578
  };
579
579
  Object.defineProperties(createChalk.prototype, styles2);
580
580
  chalk = createChalk();
@@ -1578,11 +1578,11 @@ var strip_ansi_exports = {};
1578
1578
  __export(strip_ansi_exports, {
1579
1579
  default: () => stripAnsi
1580
1580
  });
1581
- function stripAnsi(string22) {
1582
- if (typeof string22 !== "string") {
1583
- throw new TypeError(`Expected a \`string\`, got \`${typeof string22}\``);
1581
+ function stripAnsi(string18) {
1582
+ if (typeof string18 !== "string") {
1583
+ throw new TypeError(`Expected a \`string\`, got \`${typeof string18}\``);
1584
1584
  }
1585
- return string22.replace(regex, "");
1585
+ return string18.replace(regex, "");
1586
1586
  }
1587
1587
  var regex;
1588
1588
  var init_strip_ansi = __esm({
@@ -3084,8 +3084,8 @@ var require_tokenizer = __commonJS({
3084
3084
  tokens.push(token);
3085
3085
  overallIndex += token.raw.length;
3086
3086
  };
3087
- for (const [stringIndex, string22] of (0, utils_1.enumerate)(strings)) {
3088
- const chars = [...string22];
3087
+ for (const [stringIndex, string18] of (0, utils_1.enumerate)(strings)) {
3088
+ const chars = [...string18];
3089
3089
  for (let i = 0; i < chars.length; i++) {
3090
3090
  if (chars[i] === "-" && chars[i + 1] === "-") {
3091
3091
  push({ type: "longPrefix", raw: "--", index: overallIndex });
@@ -3852,11 +3852,12 @@ var require_package = __commonJS({
3852
3852
  "apps/cli/package.json"(exports2, module2) {
3853
3853
  module2.exports = {
3854
3854
  name: "@packmind/cli",
3855
- version: "0.23.0",
3855
+ version: "0.24.0",
3856
3856
  description: "A command-line interface for Packmind linting and code quality checks",
3857
3857
  private: false,
3858
3858
  bin: {
3859
- "packmind-cli": "./main.cjs"
3859
+ "packmind-cli": "./main.cjs",
3860
+ packmind: "./main.cjs"
3860
3861
  },
3861
3862
  main: "./main.cjs",
3862
3863
  files: [
@@ -4186,6 +4187,31 @@ function resolveArtefactFromPath(filePath) {
4186
4187
  return null;
4187
4188
  }
4188
4189
 
4190
+ // packages/types/src/coding-agent/validateArtifactFileFormat.ts
4191
+ var ACCEPTED_ARTIFACT_EXTENSIONS = {
4192
+ command: [".md"],
4193
+ standard: [".md", ".mdc"],
4194
+ skill: []
4195
+ };
4196
+ function validateArtifactFileFormat(filePath, artifactType) {
4197
+ const extensions = ACCEPTED_ARTIFACT_EXTENSIONS[artifactType];
4198
+ if (extensions.length === 0) {
4199
+ return { valid: true };
4200
+ }
4201
+ const normalizedPath = filePath.toLowerCase();
4202
+ const hasValidExtension = extensions.some(
4203
+ (ext) => normalizedPath.endsWith(ext)
4204
+ );
4205
+ if (!hasValidExtension) {
4206
+ const accepted = extensions.join(", ");
4207
+ return {
4208
+ valid: false,
4209
+ reason: `Invalid file format for ${artifactType}. Accepted: ${accepted}`
4210
+ };
4211
+ }
4212
+ return { valid: true };
4213
+ }
4214
+
4189
4215
  // packages/types/src/recipes/RecipeId.ts
4190
4216
  var createRecipeId = brandedIdFactory();
4191
4217
 
@@ -4383,6 +4409,13 @@ var SpaceCreatedEvent = class extends UserEvent {
4383
4409
  }
4384
4410
  };
4385
4411
 
4412
+ // packages/types/src/spaces-management/events/PlaybookArtefactMovedEvent.ts
4413
+ var PlaybookArtefactMovedEvent = class extends UserEvent {
4414
+ static {
4415
+ this.eventName = "spaces.artefact.moved";
4416
+ }
4417
+ };
4418
+
4386
4419
  // packages/types/src/standards/StandardId.ts
4387
4420
  var createStandardId = brandedIdFactory();
4388
4421
 
@@ -4841,6 +4874,20 @@ var createDetectionProgramId = brandedIdFactory();
4841
4874
  // packages/types/src/linter/RuleDetectionAssessment.ts
4842
4875
  var createRuleDetectionAssessmentId = brandedIdFactory();
4843
4876
 
4877
+ // packages/types/src/linter/events/LinterCalledEvent.ts
4878
+ var LinterCalledEvent = class extends UserEvent {
4879
+ static {
4880
+ this.eventName = "linter.detection.called";
4881
+ }
4882
+ };
4883
+
4884
+ // packages/types/src/linter/events/LinterRuleSeverityUpdatedEvent.ts
4885
+ var LinterRuleSeverityUpdatedEvent = class extends UserEvent {
4886
+ static {
4887
+ this.eventName = "linter.rule.severity-updated";
4888
+ }
4889
+ };
4890
+
4844
4891
  // packages/types/src/llm/LLMProviderMetadata.ts
4845
4892
  var DEFAULT_OPENAI_MODELS = {
4846
4893
  model: "gpt-5.2",
@@ -5270,30 +5317,30 @@ var GitService = class {
5270
5317
  this.gitRunner = gitRunner;
5271
5318
  this.logger = logger2;
5272
5319
  }
5273
- getGitRepositoryRoot(path34) {
5320
+ getGitRepositoryRoot(path33) {
5274
5321
  try {
5275
5322
  const { stdout } = this.gitRunner("rev-parse --show-toplevel", {
5276
- cwd: path34
5323
+ cwd: path33
5277
5324
  });
5278
5325
  const gitRoot = stdout.trim();
5279
5326
  this.logger.debug("Resolved git repository root", {
5280
- inputPath: path34,
5327
+ inputPath: path33,
5281
5328
  gitRoot
5282
5329
  });
5283
5330
  return gitRoot;
5284
5331
  } catch (error) {
5285
5332
  if (error instanceof Error) {
5286
5333
  throw new Error(
5287
- `Failed to get Git repository root. The path '${path34}' does not appear to be inside a Git repository.
5334
+ `Failed to get Git repository root. The path '${path33}' does not appear to be inside a Git repository.
5288
5335
  ${error.message}`
5289
5336
  );
5290
5337
  }
5291
5338
  throw new Error("Failed to get Git repository root: Unknown error");
5292
5339
  }
5293
5340
  }
5294
- tryGetGitRepositoryRoot(path34) {
5341
+ tryGetGitRepositoryRoot(path33) {
5295
5342
  try {
5296
- return this.getGitRepositoryRoot(path34);
5343
+ return this.getGitRepositoryRoot(path33);
5297
5344
  } catch {
5298
5345
  return null;
5299
5346
  }
@@ -5772,7 +5819,6 @@ var ListFilesInDirectoryUseCase = class {
5772
5819
  };
5773
5820
 
5774
5821
  // apps/cli/src/application/useCases/LintFilesAgainstRuleUseCase.ts
5775
- var import_minimatch = require("minimatch");
5776
5822
  var path4 = __toESM(require("path"));
5777
5823
  var fs2 = __toESM(require("fs/promises"));
5778
5824
 
@@ -5789,6 +5835,63 @@ function handleScope(scope) {
5789
5835
  );
5790
5836
  }
5791
5837
 
5838
+ // apps/cli/src/application/utils/scopeMatcher.ts
5839
+ var import_minimatch = require("minimatch");
5840
+ function buildEffectivePattern(targetPath, scope) {
5841
+ const normalizedTarget = targetPath === "/" ? "/" : targetPath.replace(/\/$/, "");
5842
+ if (!scope) {
5843
+ return normalizedTarget === "/" ? "/**" : normalizedTarget + "/**";
5844
+ }
5845
+ if (scope.startsWith(normalizedTarget + "/") || scope === normalizedTarget) {
5846
+ return scope.endsWith("/") ? scope + "**" : scope;
5847
+ }
5848
+ const cleanScope = scope.startsWith("/") ? scope.substring(1) : scope;
5849
+ let pattern;
5850
+ if (normalizedTarget === "/") {
5851
+ pattern = "/" + cleanScope;
5852
+ } else {
5853
+ pattern = normalizedTarget + "/" + cleanScope;
5854
+ }
5855
+ if (pattern.endsWith("/")) {
5856
+ pattern = pattern + "**";
5857
+ }
5858
+ return pattern;
5859
+ }
5860
+ function isNegativePattern(pattern) {
5861
+ return pattern.startsWith("!");
5862
+ }
5863
+ function fileMatchesTargetAndScope(filePath, targetPath, scopePatterns) {
5864
+ if (!scopePatterns || scopePatterns.length === 0) {
5865
+ const effectivePattern = buildEffectivePattern(targetPath, null);
5866
+ return (0, import_minimatch.minimatch)(filePath, effectivePattern, { matchBase: false });
5867
+ }
5868
+ const positivePatterns = scopePatterns.filter((p) => !isNegativePattern(p));
5869
+ const negativePatterns = scopePatterns.filter((p) => isNegativePattern(p));
5870
+ if (positivePatterns.length === 0) {
5871
+ return false;
5872
+ }
5873
+ const matchesPositive = positivePatterns.some((scopePattern) => {
5874
+ const effectivePattern = buildEffectivePattern(targetPath, scopePattern);
5875
+ return (0, import_minimatch.minimatch)(filePath, effectivePattern, { matchBase: false });
5876
+ });
5877
+ if (!matchesPositive) {
5878
+ return false;
5879
+ }
5880
+ if (negativePatterns.length > 0) {
5881
+ const matchesNegative = negativePatterns.some((scopePattern) => {
5882
+ const effectivePattern = buildEffectivePattern(
5883
+ targetPath,
5884
+ scopePattern.substring(1)
5885
+ );
5886
+ return (0, import_minimatch.minimatch)(filePath, effectivePattern, { matchBase: false });
5887
+ });
5888
+ if (matchesNegative) {
5889
+ return false;
5890
+ }
5891
+ }
5892
+ return true;
5893
+ }
5894
+
5792
5895
  // apps/cli/src/application/useCases/LintFilesAgainstRuleUseCase.ts
5793
5896
  var origin2 = "LintFilesAgainstRuleUseCase";
5794
5897
  var LintFilesAgainstRuleUseCase = class {
@@ -5808,52 +5911,6 @@ var LintFilesAgainstRuleUseCase = class {
5808
5911
  };
5809
5912
  };
5810
5913
  }
5811
- fileMatchesTargetAndScope(filePath, targetPath, scopePatterns) {
5812
- if (!scopePatterns || scopePatterns.length === 0) {
5813
- const effectivePattern = this.buildEffectivePattern(targetPath, null);
5814
- const matches2 = (0, import_minimatch.minimatch)(filePath, effectivePattern, {
5815
- matchBase: false
5816
- });
5817
- this.logger.debug(
5818
- `File matching check: file="${filePath}", target="${targetPath}", scope=null, pattern="${effectivePattern}", matches=${matches2}`
5819
- );
5820
- return matches2;
5821
- }
5822
- const matches = scopePatterns.some((scopePattern) => {
5823
- const effectivePattern = this.buildEffectivePattern(
5824
- targetPath,
5825
- scopePattern
5826
- );
5827
- const patternMatches = (0, import_minimatch.minimatch)(filePath, effectivePattern, {
5828
- matchBase: false
5829
- });
5830
- this.logger.debug(
5831
- `File matching check: file="${filePath}", target="${targetPath}", scope="${scopePattern}", pattern="${effectivePattern}", matches=${patternMatches}`
5832
- );
5833
- return patternMatches;
5834
- });
5835
- return matches;
5836
- }
5837
- buildEffectivePattern(targetPath, scope) {
5838
- const normalizedTarget = targetPath === "/" ? "/" : targetPath.replace(/\/$/, "");
5839
- if (!scope) {
5840
- return normalizedTarget === "/" ? "/**" : normalizedTarget + "/**";
5841
- }
5842
- if (scope.startsWith(normalizedTarget + "/") || scope === normalizedTarget) {
5843
- return scope.endsWith("/") ? scope + "**" : scope;
5844
- }
5845
- const cleanScope = scope.startsWith("/") ? scope.substring(1) : scope;
5846
- let pattern;
5847
- if (normalizedTarget === "/") {
5848
- pattern = "/" + cleanScope;
5849
- } else {
5850
- pattern = normalizedTarget + "/" + cleanScope;
5851
- }
5852
- if (pattern.endsWith("/")) {
5853
- pattern = pattern + "**";
5854
- }
5855
- return pattern;
5856
- }
5857
5914
  async execute(command30) {
5858
5915
  const {
5859
5916
  path: userPath,
@@ -6053,7 +6110,7 @@ var LintFilesAgainstRuleUseCase = class {
6053
6110
  this.logger.debug(
6054
6111
  `Checking standard: name="${standard.name}", scope=${JSON.stringify(standard.scope)}, rulesCount=${standard.rules.length}`
6055
6112
  );
6056
- if (!this.fileMatchesTargetAndScope(
6113
+ if (!fileMatchesTargetAndScope(
6057
6114
  normalizedFilePath,
6058
6115
  target.path,
6059
6116
  standard.scope
@@ -6193,7 +6250,6 @@ var LintFilesAgainstRuleUseCase = class {
6193
6250
  };
6194
6251
 
6195
6252
  // apps/cli/src/application/useCases/LintFilesFromConfigUseCase.ts
6196
- var import_minimatch2 = require("minimatch");
6197
6253
  var path5 = __toESM(require("path"));
6198
6254
  var fs3 = __toESM(require("fs/promises"));
6199
6255
  var origin3 = "LintFilesFromConfigUseCase";
@@ -6204,39 +6260,6 @@ var LintFilesFromConfigUseCase = class {
6204
6260
  this.logger = logger2;
6205
6261
  this.detectionProgramsCache = /* @__PURE__ */ new Map();
6206
6262
  }
6207
- fileMatchesTargetAndScope(filePath, targetPath, scopePatterns) {
6208
- if (!scopePatterns || scopePatterns.length === 0) {
6209
- const effectivePattern = this.buildEffectivePattern(targetPath, null);
6210
- return (0, import_minimatch2.minimatch)(filePath, effectivePattern, { matchBase: false });
6211
- }
6212
- return scopePatterns.some((scopePattern) => {
6213
- const effectivePattern = this.buildEffectivePattern(
6214
- targetPath,
6215
- scopePattern
6216
- );
6217
- return (0, import_minimatch2.minimatch)(filePath, effectivePattern, { matchBase: false });
6218
- });
6219
- }
6220
- buildEffectivePattern(targetPath, scope) {
6221
- const normalizedTarget = targetPath === "/" ? "/" : targetPath.replace(/\/$/, "");
6222
- if (!scope) {
6223
- return normalizedTarget === "/" ? "/**" : normalizedTarget + "/**";
6224
- }
6225
- if (scope.startsWith(normalizedTarget + "/") || scope === normalizedTarget) {
6226
- return scope.endsWith("/") ? scope + "**" : scope;
6227
- }
6228
- const cleanScope = scope.startsWith("/") ? scope.substring(1) : scope;
6229
- let pattern;
6230
- if (normalizedTarget === "/") {
6231
- pattern = "/" + cleanScope;
6232
- } else {
6233
- pattern = normalizedTarget + "/" + cleanScope;
6234
- }
6235
- if (pattern.endsWith("/")) {
6236
- pattern = pattern + "**";
6237
- }
6238
- return pattern;
6239
- }
6240
6263
  async execute(command30) {
6241
6264
  const { path: userPath, diffMode, ignorePatterns } = command30;
6242
6265
  this.logger.debug(
@@ -6351,7 +6374,7 @@ var LintFilesFromConfigUseCase = class {
6351
6374
  const detectionPrograms = await this.getDetectionProgramsForTarget(targetConfig);
6352
6375
  for (const target of detectionPrograms.targets) {
6353
6376
  for (const standard of target.standards) {
6354
- if (!this.fileMatchesTargetAndScope(
6377
+ if (!fileMatchesTargetAndScope(
6355
6378
  normalizedFilePath,
6356
6379
  targetConfig.targetPath,
6357
6380
  standard.scope
@@ -6566,10 +6589,10 @@ var PackmindHttpClient = class {
6566
6589
  return null;
6567
6590
  }
6568
6591
  }
6569
- async request(path34, options = {}) {
6592
+ async request(path33, options = {}) {
6570
6593
  const { host } = this.getAuthContext();
6571
6594
  const { method = "GET", body } = options;
6572
- const url = `${host}${path34}`;
6595
+ const url = `${host}${path33}`;
6573
6596
  try {
6574
6597
  const response = await fetch(url, {
6575
6598
  method,
@@ -6613,6 +6636,16 @@ var PackmindHttpClient = class {
6613
6636
  }
6614
6637
  };
6615
6638
 
6639
+ // apps/cli/src/domain/errors/CommunityEditionError.ts
6640
+ var CommunityEditionError = class extends Error {
6641
+ constructor(feature) {
6642
+ super(
6643
+ `The "${feature}" feature is not available in Packmind Community Edition.`
6644
+ );
6645
+ this.name = "CommunityEditionError";
6646
+ }
6647
+ };
6648
+
6616
6649
  // apps/cli/src/infra/repositories/ChangeProposalGateway.ts
6617
6650
  var ChangeProposalGateway = class {
6618
6651
  constructor(httpClient) {
@@ -6623,7 +6656,12 @@ var ChangeProposalGateway = class {
6623
6656
  `/api/v0/organizations/${organizationId}/spaces/${command30.spaceId}/change-proposals/batch`,
6624
6657
  {
6625
6658
  method: "POST",
6626
- body: { proposals: command30.proposals }
6659
+ body: { proposals: command30.proposals },
6660
+ onError: (response) => {
6661
+ if (response.status === 404) {
6662
+ throw new CommunityEditionError("change proposals");
6663
+ }
6664
+ }
6627
6665
  }
6628
6666
  );
6629
6667
  };
@@ -6633,23 +6671,18 @@ var ChangeProposalGateway = class {
6633
6671
  `/api/v0/organizations/${organizationId}/spaces/${command30.spaceId}/change-proposals/check`,
6634
6672
  {
6635
6673
  method: "POST",
6636
- body: { proposals: command30.proposals }
6674
+ body: { proposals: command30.proposals },
6675
+ onError: (response) => {
6676
+ if (response.status === 404) {
6677
+ throw new CommunityEditionError("change proposals");
6678
+ }
6679
+ }
6637
6680
  }
6638
6681
  );
6639
6682
  };
6640
6683
  }
6641
6684
  };
6642
6685
 
6643
- // apps/cli/src/domain/errors/CommunityEditionError.ts
6644
- var CommunityEditionError = class extends Error {
6645
- constructor(feature) {
6646
- super(
6647
- `The "${feature}" feature is not available in Packmind Community Edition.`
6648
- );
6649
- this.name = "CommunityEditionError";
6650
- }
6651
- };
6652
-
6653
6686
  // apps/cli/src/infra/repositories/LinterGateway.ts
6654
6687
  var LinterGateway = class {
6655
6688
  constructor(httpClient) {
@@ -6882,12 +6915,12 @@ var PackagesGateway = class {
6882
6915
  );
6883
6916
  };
6884
6917
  this.getSummary = async ({
6885
- slug,
6918
+ slug: slug2,
6886
6919
  spaceId
6887
6920
  }) => {
6888
6921
  const { organizationId } = this.httpClient.getAuthContext();
6889
6922
  return this.httpClient.request(
6890
- `/api/v0/organizations/${organizationId}/spaces/${spaceId}/packages/summary/${encodeURIComponent(slug)}`
6923
+ `/api/v0/organizations/${organizationId}/spaces/${spaceId}/packages/summary/${encodeURIComponent(slug2)}`
6891
6924
  );
6892
6925
  };
6893
6926
  this.create = async (command30) => {
@@ -6922,13 +6955,13 @@ var DeploymentGateway = class {
6922
6955
  const { organizationId } = this.httpClient.getAuthContext();
6923
6956
  const queryParams = new URLSearchParams();
6924
6957
  if (command30.packagesSlugs && command30.packagesSlugs.length > 0) {
6925
- command30.packagesSlugs.forEach((slug) => {
6926
- queryParams.append("packageSlug", slug);
6958
+ command30.packagesSlugs.forEach((slug2) => {
6959
+ queryParams.append("packageSlug", slug2);
6927
6960
  });
6928
6961
  }
6929
6962
  if (command30.previousPackagesSlugs && command30.previousPackagesSlugs.length > 0) {
6930
- command30.previousPackagesSlugs.forEach((slug) => {
6931
- queryParams.append("previousPackageSlug", slug);
6963
+ command30.previousPackagesSlugs.forEach((slug2) => {
6964
+ queryParams.append("previousPackageSlug", slug2);
6932
6965
  });
6933
6966
  }
6934
6967
  if (command30.gitRemoteUrl) {
@@ -9851,7 +9884,8 @@ var InstallDefaultSkillsUseCase = class {
9851
9884
  const result = {
9852
9885
  filesCreated: 0,
9853
9886
  filesUpdated: 0,
9854
- errors: []
9887
+ errors: [],
9888
+ skippedSkillsCount: 0
9855
9889
  };
9856
9890
  const config = await this.repositories.configFileRepository.readConfig(baseDirectory);
9857
9891
  const agents = config?.agents;
@@ -9862,6 +9896,7 @@ var InstallDefaultSkillsUseCase = class {
9862
9896
  agents
9863
9897
  }
9864
9898
  );
9899
+ result.skippedSkillsCount = response.skippedSkillsCount;
9865
9900
  try {
9866
9901
  for (const file of response.fileUpdates.createOrUpdate) {
9867
9902
  try {
@@ -10254,8 +10289,8 @@ var LogoutUseCase = class {
10254
10289
  constructor(deps) {
10255
10290
  this.deps = {
10256
10291
  getCredentialsPath: deps?.getCredentialsPath ?? getCredentialsPath,
10257
- fileExists: deps?.fileExists ?? ((path34) => fs7.existsSync(path34)),
10258
- deleteFile: deps?.deleteFile ?? ((path34) => fs7.unlinkSync(path34)),
10292
+ fileExists: deps?.fileExists ?? ((path33) => fs7.existsSync(path33)),
10293
+ deleteFile: deps?.deleteFile ?? ((path33) => fs7.unlinkSync(path33)),
10259
10294
  hasEnvVar: deps?.hasEnvVar ?? (() => !!process.env[ENV_VAR_NAME2])
10260
10295
  };
10261
10296
  }
@@ -10304,120 +10339,373 @@ var WhoamiUseCase = class {
10304
10339
  }
10305
10340
  };
10306
10341
 
10307
- // apps/cli/src/application/useCases/SetupMcpUseCase.ts
10308
- var ALL_AGENTS = [
10309
- { type: "claude", name: "Claude Code" },
10310
- { type: "cursor", name: "Cursor" },
10311
- { type: "vscode", name: "VS Code" },
10312
- { type: "continue", name: "Continue.dev" }
10313
- ];
10314
- var SetupMcpUseCase = class {
10315
- constructor(deps) {
10316
- this.deps = deps;
10317
- }
10318
- async execute(command30) {
10319
- const { agentTypes } = command30;
10320
- const [tokenResult, urlResult] = await Promise.all([
10321
- this.deps.gateway.mcp.getToken({}),
10322
- this.deps.gateway.mcp.getUrl({})
10323
- ]);
10324
- const config = {
10325
- url: urlResult.url,
10326
- accessToken: tokenResult.access_token
10327
- };
10328
- const results = [];
10329
- let hasFailure = false;
10330
- for (const agentType of agentTypes) {
10331
- const agentName = ALL_AGENTS.find((a) => a.type === agentType)?.name || agentType;
10332
- const installResult = this.deps.mcpConfigService.installForAgent(
10333
- agentType,
10334
- config
10335
- );
10336
- results.push({
10337
- agentType,
10338
- agentName,
10339
- success: installResult.success,
10340
- error: installResult.error
10341
- });
10342
- if (!installResult.success) {
10343
- hasFailure = true;
10344
- }
10345
- }
10346
- return {
10347
- results,
10348
- manualConfigJson: hasFailure ? this.deps.mcpConfigService.getClassicConfig(config) : void 0
10349
- };
10350
- }
10351
- };
10342
+ // apps/cli/src/application/useCases/CheckCliVersionUseCase.ts
10343
+ var import_semver2 = __toESM(require("semver"));
10352
10344
 
10353
- // apps/cli/src/application/services/McpConfigService.ts
10354
- var fs8 = __toESM(require("fs"));
10355
- var path9 = __toESM(require("path"));
10356
- var os3 = __toESM(require("os"));
10345
+ // apps/cli/src/infra/commands/updateHandler.ts
10346
+ var import_path2 = __toESM(require("path"));
10357
10347
  var import_child_process2 = require("child_process");
10358
- var McpConfigService = class {
10359
- constructor(projectDir = process.cwd()) {
10360
- this.projectDir = projectDir;
10348
+ var import_fs19 = require("fs");
10349
+ var import_promises = require("stream/promises");
10350
+ var import_stream = require("stream");
10351
+ var import_semver = __toESM(require("semver"));
10352
+ var GITHUB_REPO = "PackmindHub/packmind";
10353
+ var NPM_PACKAGE = "@packmind/cli";
10354
+ function getPlatformAssetSuffix(platform, arch) {
10355
+ const osMap = {
10356
+ linux: "linux",
10357
+ darwin: "macos",
10358
+ win32: "windows"
10359
+ };
10360
+ const osName = osMap[platform];
10361
+ if (!osName) {
10362
+ throw new Error(`Unsupported platform: ${platform}`);
10361
10363
  }
10362
- installForAgent(agent, config) {
10363
- switch (agent) {
10364
- case "claude":
10365
- return this.installClaudeMcp(config);
10366
- case "cursor":
10367
- return this.installCursorMcp(config);
10368
- case "vscode":
10369
- return this.installVSCodeMcp(config);
10370
- case "continue":
10371
- return this.installContinueMcp(config);
10372
- default:
10373
- return { success: false, error: `Unknown agent: ${agent}` };
10364
+ const archName = platform === "darwin" && arch === "x64" ? "x64-baseline" : arch;
10365
+ const ext = platform === "win32" ? ".exe" : "";
10366
+ return `${osName}-${archName}${ext}`;
10367
+ }
10368
+ async function fetchLatestVersionFromNpm(fetchFn) {
10369
+ const res = await fetchFn(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`);
10370
+ if (!res.ok) {
10371
+ throw new Error(
10372
+ `Failed to fetch from npm registry: ${res.status} ${res.statusText}`
10373
+ );
10374
+ }
10375
+ const data = await res.json();
10376
+ return data.version;
10377
+ }
10378
+ async function fetchLatestVersionFromGitHub(fetchFn) {
10379
+ const res = await fetchFn(
10380
+ `https://api.github.com/repos/${GITHUB_REPO}/releases?per_page=20`,
10381
+ {
10382
+ headers: { Accept: "application/vnd.github.v3+json" }
10374
10383
  }
10384
+ );
10385
+ if (!res.ok) {
10386
+ throw new Error(
10387
+ `Failed to fetch from GitHub API: ${res.status} ${res.statusText}`
10388
+ );
10375
10389
  }
10376
- getClassicConfig(config) {
10377
- const mcpConfig = {
10378
- mcpServers: {
10379
- packmind: {
10380
- url: config.url,
10381
- headers: {
10382
- Authorization: `Bearer ${config.accessToken}`
10383
- }
10384
- }
10385
- }
10386
- };
10387
- return JSON.stringify(mcpConfig, null, 2);
10390
+ const releases = await res.json();
10391
+ const cliReleases = releases.filter((r) => r.tag_name?.startsWith("release-cli/")).map((r) => ({
10392
+ ...r,
10393
+ version: r.tag_name.replace("release-cli/", "")
10394
+ })).filter((r) => import_semver.default.valid(r.version)).sort((a, b) => import_semver.default.rcompare(a.version, b.version));
10395
+ if (cliReleases.length === 0) {
10396
+ throw new Error("No CLI release found on GitHub");
10388
10397
  }
10389
- installClaudeMcp(config) {
10390
- const command30 = `claude mcp add --transport http packmind ${config.url} --header "Authorization: Bearer ${config.accessToken}"`;
10391
- try {
10392
- (0, import_child_process2.execSync)(command30, { stdio: "pipe" });
10393
- return { success: true };
10394
- } catch (error) {
10395
- const execError = error;
10396
- const errorMessage = execError.stderr ? execError.stderr.toString().trim() : execError.message || String(error);
10397
- return { success: false, error: errorMessage };
10398
- }
10398
+ return cliReleases[0].version;
10399
+ }
10400
+ async function downloadExecutable(fetchFn, version2, platformSuffix, targetPath) {
10401
+ const assetName = `packmind-cli-${platformSuffix}-${version2}`;
10402
+ const url = `https://github.com/${GITHUB_REPO}/releases/download/release-cli/${version2}/${assetName}`;
10403
+ logInfoConsole(`Downloading ${assetName}...`);
10404
+ const res = await fetchFn(url, { redirect: "follow" });
10405
+ if (!res.ok) {
10406
+ throw new Error(
10407
+ `Failed to download executable: ${res.status} ${res.statusText}
10408
+ URL: ${url}`
10409
+ );
10399
10410
  }
10400
- installCursorMcp(config) {
10401
- try {
10402
- const cursorConfigPath = path9.join(os3.homedir(), ".cursor", "mcp.json");
10403
- const cursorConfig = this.buildCursorConfig(config);
10404
- const existingConfig = this.readExistingJsonConfig(cursorConfigPath);
10405
- const mergedConfig = this.mergeConfig(existingConfig, cursorConfig);
10406
- fs8.writeFileSync(cursorConfigPath, JSON.stringify(mergedConfig, null, 2));
10407
- return { success: true };
10408
- } catch (error) {
10409
- const errorMessage = error instanceof Error ? error.message : String(error);
10410
- return { success: false, error: errorMessage };
10411
- }
10411
+ if (!res.body) {
10412
+ throw new Error("No response body received");
10412
10413
  }
10413
- installVSCodeMcp(config) {
10414
- try {
10415
- const vscodeDir = path9.join(this.projectDir, ".vscode");
10416
- if (!fs8.existsSync(vscodeDir)) {
10417
- fs8.mkdirSync(vscodeDir, { recursive: true });
10418
- }
10419
- const vscodeConfigPath = path9.join(vscodeDir, "mcp.json");
10420
- const vscodeConfig = this.buildVSCodeConfig(config);
10414
+ const nodeReadable = import_stream.Readable.fromWeb(res.body);
10415
+ const fileStream = (0, import_fs19.createWriteStream)(targetPath);
10416
+ await (0, import_promises.pipeline)(nodeReadable, fileStream);
10417
+ const stats = (0, import_fs19.statSync)(targetPath);
10418
+ if (stats.size < 1e6) {
10419
+ (0, import_fs19.unlinkSync)(targetPath);
10420
+ throw new Error(
10421
+ `Downloaded file is too small (${stats.size} bytes). The download may have failed.`
10422
+ );
10423
+ }
10424
+ logInfoConsole(
10425
+ `Downloaded successfully (${(stats.size / 1048576).toFixed(1)} MB)`
10426
+ );
10427
+ }
10428
+ function createForwardCompatSymlink(currentPath, platform) {
10429
+ const dir = import_path2.default.dirname(currentPath);
10430
+ const ext = platform === "win32" ? ".exe" : "";
10431
+ const primaryName = `packmind-cli${ext}`;
10432
+ const aliasName = `packmind${ext}`;
10433
+ const currentBasename = import_path2.default.basename(currentPath);
10434
+ if (currentBasename !== primaryName) {
10435
+ return;
10436
+ }
10437
+ const targetName = primaryName;
10438
+ const symlinkName = aliasName;
10439
+ const symlinkPath = import_path2.default.join(dir, symlinkName);
10440
+ try {
10441
+ (0, import_fs19.unlinkSync)(symlinkPath);
10442
+ } catch {
10443
+ }
10444
+ try {
10445
+ (0, import_fs19.symlinkSync)(targetName, symlinkPath);
10446
+ logInfoConsole(
10447
+ `Created forward-compatible symlink: ${symlinkPath} -> ${targetName}`
10448
+ );
10449
+ } catch {
10450
+ }
10451
+ }
10452
+ function updateViaNpm(version2) {
10453
+ logInfoConsole(`Updating via npm to version ${version2}...`);
10454
+ (0, import_child_process2.execSync)(`npm install -g ${NPM_PACKAGE}@${version2}`, {
10455
+ stdio: "inherit"
10456
+ });
10457
+ }
10458
+ async function updateViaExecutableReplace(deps, version2) {
10459
+ const platformSuffix = getPlatformAssetSuffix(deps.platform, deps.arch);
10460
+ const currentPath = deps.executablePath;
10461
+ const tempPath = currentPath + ".update-tmp";
10462
+ try {
10463
+ await downloadExecutable(deps.fetchFn, version2, platformSuffix, tempPath);
10464
+ (0, import_fs19.renameSync)(tempPath, currentPath);
10465
+ if (deps.platform !== "win32") {
10466
+ (0, import_fs19.chmodSync)(currentPath, 493);
10467
+ }
10468
+ createForwardCompatSymlink(currentPath, deps.platform);
10469
+ } catch (error) {
10470
+ try {
10471
+ (0, import_fs19.unlinkSync)(tempPath);
10472
+ } catch {
10473
+ }
10474
+ throw error;
10475
+ }
10476
+ }
10477
+ function isLocalNpmPackage(scriptPath) {
10478
+ if (!scriptPath) return false;
10479
+ return scriptPath.includes(import_path2.default.join("node_modules", "@packmind", "cli"));
10480
+ }
10481
+ function isHomebrewInstall(executablePath) {
10482
+ try {
10483
+ const realPath = (0, import_fs19.realpathSync)(executablePath);
10484
+ return realPath.includes("/Cellar/");
10485
+ } catch {
10486
+ return false;
10487
+ }
10488
+ }
10489
+ async function updateHandler(deps) {
10490
+ const execBasename = import_path2.default.basename(deps.executablePath).replace(/\.exe$/, "");
10491
+ const jsRuntimes = ["node", "bun", "deno"];
10492
+ if (jsRuntimes.includes(execBasename)) {
10493
+ if (isLocalNpmPackage(deps.scriptPath)) {
10494
+ logErrorConsole(
10495
+ "Your CLI version is managed by your local package.json.\nTo update, run: npm update @packmind/cli"
10496
+ );
10497
+ } else {
10498
+ logErrorConsole(
10499
+ "The update command is not available when running the CLI via a JavaScript runtime.\nTo update, use the standalone executable or run: npm install -g @packmind/cli@latest"
10500
+ );
10501
+ }
10502
+ process.exit(1);
10503
+ return;
10504
+ }
10505
+ if (isHomebrewInstall(deps.executablePath)) {
10506
+ logInfoConsole(
10507
+ "This CLI was installed via Homebrew.\nTo update, run: brew upgrade packmind-cli"
10508
+ );
10509
+ process.exit(0);
10510
+ return;
10511
+ }
10512
+ logInfoConsole(
10513
+ `Current version: ${deps.currentVersion} (${deps.isExecutableMode ? "standalone executable" : "npm package"})`
10514
+ );
10515
+ let latestVersion;
10516
+ try {
10517
+ latestVersion = deps.isExecutableMode ? await fetchLatestVersionFromGitHub(deps.fetchFn) : await fetchLatestVersionFromNpm(deps.fetchFn);
10518
+ } catch (error) {
10519
+ logErrorConsole(
10520
+ `Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`
10521
+ );
10522
+ process.exit(1);
10523
+ return;
10524
+ }
10525
+ if (!import_semver.default.gt(latestVersion, deps.currentVersion)) {
10526
+ logSuccessConsole(`Already up to date (v${deps.currentVersion})`);
10527
+ return;
10528
+ }
10529
+ logConsole("");
10530
+ logInfoConsole(
10531
+ `New version available: ${deps.currentVersion} -> ${latestVersion}`
10532
+ );
10533
+ if (deps.checkOnly) {
10534
+ process.exit(1);
10535
+ return;
10536
+ }
10537
+ try {
10538
+ if (deps.isExecutableMode) {
10539
+ await updateViaExecutableReplace(deps, latestVersion);
10540
+ } else {
10541
+ updateViaNpm(latestVersion);
10542
+ }
10543
+ logConsole("");
10544
+ logSuccessConsole(`Updated to v${latestVersion}`);
10545
+ if (deps.isExecutableMode) {
10546
+ logInfoConsole(`Binary location: ${deps.executablePath}`);
10547
+ }
10548
+ } catch (error) {
10549
+ const message = error instanceof Error ? error.message : String(error);
10550
+ if (message.includes("EACCES") || message.includes("permission denied")) {
10551
+ logErrorConsole(
10552
+ `Permission denied. Try running with sudo:
10553
+ sudo packmind-cli update`
10554
+ );
10555
+ } else {
10556
+ logErrorConsole(`Update failed: ${message}`);
10557
+ }
10558
+ process.exit(1);
10559
+ }
10560
+ }
10561
+
10562
+ // apps/cli/src/application/useCases/CheckCliVersionUseCase.ts
10563
+ var VERSION_CHECK_TIMEOUT_MS = 5e3;
10564
+ var CheckCliVersionUseCase = class {
10565
+ constructor(deps) {
10566
+ this.deps = {
10567
+ fetchLatestVersion: deps?.fetchLatestVersion ?? fetchLatestVersionFromGitHub,
10568
+ fetchFn: deps?.fetchFn ?? fetch,
10569
+ timeoutMs: deps?.timeoutMs ?? VERSION_CHECK_TIMEOUT_MS
10570
+ };
10571
+ }
10572
+ async execute(command30) {
10573
+ try {
10574
+ const latestVersion = await Promise.race([
10575
+ this.deps.fetchLatestVersion(this.deps.fetchFn),
10576
+ new Promise(
10577
+ (_, reject) => setTimeout(
10578
+ () => reject(new Error("Version check timed out")),
10579
+ this.deps.timeoutMs
10580
+ )
10581
+ )
10582
+ ]);
10583
+ const updateAvailable = import_semver2.default.gt(latestVersion, command30.currentVersion);
10584
+ return {
10585
+ currentVersion: command30.currentVersion,
10586
+ latestVersion,
10587
+ updateAvailable
10588
+ };
10589
+ } catch {
10590
+ return null;
10591
+ }
10592
+ }
10593
+ };
10594
+
10595
+ // apps/cli/src/application/useCases/SetupMcpUseCase.ts
10596
+ var ALL_AGENTS = [
10597
+ { type: "claude", name: "Claude Code" },
10598
+ { type: "cursor", name: "Cursor" },
10599
+ { type: "vscode", name: "VS Code" },
10600
+ { type: "continue", name: "Continue.dev" }
10601
+ ];
10602
+ var SetupMcpUseCase = class {
10603
+ constructor(deps) {
10604
+ this.deps = deps;
10605
+ }
10606
+ async execute(command30) {
10607
+ const { agentTypes } = command30;
10608
+ const [tokenResult, urlResult] = await Promise.all([
10609
+ this.deps.gateway.mcp.getToken({}),
10610
+ this.deps.gateway.mcp.getUrl({})
10611
+ ]);
10612
+ const config = {
10613
+ url: urlResult.url,
10614
+ accessToken: tokenResult.access_token
10615
+ };
10616
+ const results = [];
10617
+ let hasFailure = false;
10618
+ for (const agentType of agentTypes) {
10619
+ const agentName = ALL_AGENTS.find((a) => a.type === agentType)?.name || agentType;
10620
+ const installResult = this.deps.mcpConfigService.installForAgent(
10621
+ agentType,
10622
+ config
10623
+ );
10624
+ results.push({
10625
+ agentType,
10626
+ agentName,
10627
+ success: installResult.success,
10628
+ error: installResult.error
10629
+ });
10630
+ if (!installResult.success) {
10631
+ hasFailure = true;
10632
+ }
10633
+ }
10634
+ return {
10635
+ results,
10636
+ manualConfigJson: hasFailure ? this.deps.mcpConfigService.getClassicConfig(config) : void 0
10637
+ };
10638
+ }
10639
+ };
10640
+
10641
+ // apps/cli/src/application/services/McpConfigService.ts
10642
+ var fs8 = __toESM(require("fs"));
10643
+ var path10 = __toESM(require("path"));
10644
+ var os3 = __toESM(require("os"));
10645
+ var import_child_process3 = require("child_process");
10646
+ var McpConfigService = class {
10647
+ constructor(projectDir = process.cwd()) {
10648
+ this.projectDir = projectDir;
10649
+ }
10650
+ installForAgent(agent, config) {
10651
+ switch (agent) {
10652
+ case "claude":
10653
+ return this.installClaudeMcp(config);
10654
+ case "cursor":
10655
+ return this.installCursorMcp(config);
10656
+ case "vscode":
10657
+ return this.installVSCodeMcp(config);
10658
+ case "continue":
10659
+ return this.installContinueMcp(config);
10660
+ default:
10661
+ return { success: false, error: `Unknown agent: ${agent}` };
10662
+ }
10663
+ }
10664
+ getClassicConfig(config) {
10665
+ const mcpConfig = {
10666
+ mcpServers: {
10667
+ packmind: {
10668
+ url: config.url,
10669
+ headers: {
10670
+ Authorization: `Bearer ${config.accessToken}`
10671
+ }
10672
+ }
10673
+ }
10674
+ };
10675
+ return JSON.stringify(mcpConfig, null, 2);
10676
+ }
10677
+ installClaudeMcp(config) {
10678
+ const command30 = `claude mcp add --transport http packmind ${config.url} --header "Authorization: Bearer ${config.accessToken}"`;
10679
+ try {
10680
+ (0, import_child_process3.execSync)(command30, { stdio: "pipe" });
10681
+ return { success: true };
10682
+ } catch (error) {
10683
+ const execError = error;
10684
+ const errorMessage = execError.stderr ? execError.stderr.toString().trim() : execError.message || String(error);
10685
+ return { success: false, error: errorMessage };
10686
+ }
10687
+ }
10688
+ installCursorMcp(config) {
10689
+ try {
10690
+ const cursorConfigPath = path10.join(os3.homedir(), ".cursor", "mcp.json");
10691
+ const cursorConfig = this.buildCursorConfig(config);
10692
+ const existingConfig = this.readExistingJsonConfig(cursorConfigPath);
10693
+ const mergedConfig = this.mergeConfig(existingConfig, cursorConfig);
10694
+ fs8.writeFileSync(cursorConfigPath, JSON.stringify(mergedConfig, null, 2));
10695
+ return { success: true };
10696
+ } catch (error) {
10697
+ const errorMessage = error instanceof Error ? error.message : String(error);
10698
+ return { success: false, error: errorMessage };
10699
+ }
10700
+ }
10701
+ installVSCodeMcp(config) {
10702
+ try {
10703
+ const vscodeDir = path10.join(this.projectDir, ".vscode");
10704
+ if (!fs8.existsSync(vscodeDir)) {
10705
+ fs8.mkdirSync(vscodeDir, { recursive: true });
10706
+ }
10707
+ const vscodeConfigPath = path10.join(vscodeDir, "mcp.json");
10708
+ const vscodeConfig = this.buildVSCodeConfig(config);
10421
10709
  const existingConfig = this.readExistingJsonConfig(vscodeConfigPath);
10422
10710
  const mergedConfig = this.mergeVSCodeConfig(existingConfig, vscodeConfig);
10423
10711
  fs8.writeFileSync(vscodeConfigPath, JSON.stringify(mergedConfig, null, 2));
@@ -10429,12 +10717,12 @@ var McpConfigService = class {
10429
10717
  }
10430
10718
  installContinueMcp(config) {
10431
10719
  try {
10432
- const continueDir = path9.join(this.projectDir, ".continue");
10433
- const mcpServersDir = path9.join(continueDir, "mcpServers");
10720
+ const continueDir = path10.join(this.projectDir, ".continue");
10721
+ const mcpServersDir = path10.join(continueDir, "mcpServers");
10434
10722
  if (!fs8.existsSync(mcpServersDir)) {
10435
10723
  fs8.mkdirSync(mcpServersDir, { recursive: true });
10436
10724
  }
10437
- const continueConfigPath = path9.join(mcpServersDir, "packmind.yaml");
10725
+ const continueConfigPath = path10.join(mcpServersDir, "packmind.yaml");
10438
10726
  const continueConfig = this.buildContinueYamlConfig(config);
10439
10727
  fs8.writeFileSync(continueConfigPath, continueConfig);
10440
10728
  return { success: true };
@@ -10519,7 +10807,7 @@ mcpServers:
10519
10807
 
10520
10808
  // apps/cli/src/infra/repositories/ConfigFileRepository.ts
10521
10809
  var fs9 = __toESM(require("fs/promises"));
10522
- var path10 = __toESM(require("path"));
10810
+ var path11 = __toESM(require("path"));
10523
10811
  var ConfigFileRepository = class {
10524
10812
  constructor() {
10525
10813
  this.CONFIG_FILENAME = "packmind.json";
@@ -10583,7 +10871,7 @@ var ConfigFileRepository = class {
10583
10871
  }
10584
10872
  }
10585
10873
  getConfigPath(directory) {
10586
- return path10.join(directory, this.CONFIG_FILENAME);
10874
+ return path11.join(directory, this.CONFIG_FILENAME);
10587
10875
  }
10588
10876
  async writeConfigToPath(configPath, config) {
10589
10877
  const configContent = JSON.stringify(config, null, 2) + "\n";
@@ -10594,7 +10882,7 @@ var ConfigFileRepository = class {
10594
10882
  * Excludes common build/dependency directories (node_modules, .git, dist, etc.)
10595
10883
  */
10596
10884
  async findDescendantConfigs(directory) {
10597
- const normalizedDir = normalizePath2(path10.resolve(directory));
10885
+ const normalizedDir = normalizePath2(path11.resolve(directory));
10598
10886
  return this.searchDescendantsRecursively(normalizedDir);
10599
10887
  }
10600
10888
  async searchDescendantsRecursively(currentDir) {
@@ -10607,7 +10895,7 @@ var ConfigFileRepository = class {
10607
10895
  if (!entry.isDirectory() || this.isExcludedDirectory(entry.name)) {
10608
10896
  continue;
10609
10897
  }
10610
- const entryPath = normalizePath2(path10.join(currentDir, entry.name));
10898
+ const entryPath = normalizePath2(path11.join(currentDir, entry.name));
10611
10899
  const config = await this.readConfig(entryPath);
10612
10900
  if (config) {
10613
10901
  results.push(entryPath);
@@ -10638,21 +10926,21 @@ var ConfigFileRepository = class {
10638
10926
  async readHierarchicalConfig(startDirectory, stopDirectory) {
10639
10927
  const configs = [];
10640
10928
  const configPaths = [];
10641
- const normalizedStart = normalizePath2(path10.resolve(startDirectory));
10642
- const normalizedStop = stopDirectory ? normalizePath2(path10.resolve(stopDirectory)) : null;
10929
+ const normalizedStart = normalizePath2(path11.resolve(startDirectory));
10930
+ const normalizedStop = stopDirectory ? normalizePath2(path11.resolve(stopDirectory)) : null;
10643
10931
  let currentDir = normalizedStart;
10644
10932
  while (true) {
10645
10933
  const config = await this.readConfig(currentDir);
10646
10934
  if (config) {
10647
10935
  configs.push(config);
10648
10936
  configPaths.push(
10649
- normalizePath2(path10.join(currentDir, this.CONFIG_FILENAME))
10937
+ normalizePath2(path11.join(currentDir, this.CONFIG_FILENAME))
10650
10938
  );
10651
10939
  }
10652
10940
  if (normalizedStop !== null && currentDir === normalizedStop) {
10653
10941
  break;
10654
10942
  }
10655
- const parentDir = normalizePath2(path10.dirname(currentDir));
10943
+ const parentDir = normalizePath2(path11.dirname(currentDir));
10656
10944
  if (parentDir === currentDir) {
10657
10945
  break;
10658
10946
  }
@@ -10660,9 +10948,9 @@ var ConfigFileRepository = class {
10660
10948
  }
10661
10949
  const mergedPackages = {};
10662
10950
  for (const config of configs) {
10663
- for (const [slug, version2] of Object.entries(config.packages)) {
10664
- if (!(slug in mergedPackages)) {
10665
- mergedPackages[slug] = version2;
10951
+ for (const [slug2, version2] of Object.entries(config.packages)) {
10952
+ if (!(slug2 in mergedPackages)) {
10953
+ mergedPackages[slug2] = version2;
10666
10954
  }
10667
10955
  }
10668
10956
  }
@@ -10677,8 +10965,8 @@ var ConfigFileRepository = class {
10677
10965
  * and returns each config with its target path.
10678
10966
  */
10679
10967
  async findAllConfigsInTree(startDirectory, stopDirectory) {
10680
- const normalizedStart = normalizePath2(path10.resolve(startDirectory));
10681
- const normalizedStop = stopDirectory ? normalizePath2(path10.resolve(stopDirectory)) : null;
10968
+ const normalizedStart = normalizePath2(path11.resolve(startDirectory));
10969
+ const normalizedStop = stopDirectory ? normalizePath2(path11.resolve(stopDirectory)) : null;
10682
10970
  const basePath = normalizedStop ?? normalizedStart;
10683
10971
  const searchRoot = normalizedStop ?? normalizedStart;
10684
10972
  const configsMap = /* @__PURE__ */ new Map();
@@ -10704,7 +10992,7 @@ var ConfigFileRepository = class {
10704
10992
  if (stopDir !== null && currentDir === stopDir) {
10705
10993
  break;
10706
10994
  }
10707
- const parentDir = normalizePath2(path10.dirname(currentDir));
10995
+ const parentDir = normalizePath2(path11.dirname(currentDir));
10708
10996
  if (parentDir === currentDir) {
10709
10997
  break;
10710
10998
  }
@@ -10776,9 +11064,9 @@ var ConfigFileRepository = class {
10776
11064
  parsed.packages = {};
10777
11065
  }
10778
11066
  const packages = parsed.packages;
10779
- for (const slug of newPackageSlugs) {
10780
- if (!(slug in packages)) {
10781
- packages[slug] = "*";
11067
+ for (const slug2 of newPackageSlugs) {
11068
+ if (!(slug2 in packages)) {
11069
+ packages[slug2] = "*";
10782
11070
  }
10783
11071
  }
10784
11072
  await this.writeConfigToPath(configPath, parsed);
@@ -10828,8 +11116,8 @@ var ConfigFileRepository = class {
10828
11116
  }
10829
11117
  createConfigWithPackages(slugs) {
10830
11118
  const packages = {};
10831
- for (const slug of slugs) {
10832
- packages[slug] = "*";
11119
+ for (const slug2 of slugs) {
11120
+ packages[slug2] = "*";
10833
11121
  }
10834
11122
  return { packages };
10835
11123
  }
@@ -10837,7 +11125,7 @@ var ConfigFileRepository = class {
10837
11125
 
10838
11126
  // apps/cli/src/infra/repositories/LockFileRepository.ts
10839
11127
  var fs10 = __toESM(require("fs/promises"));
10840
- var path11 = __toESM(require("path"));
11128
+ var path12 = __toESM(require("path"));
10841
11129
  var LockFileRepository = class {
10842
11130
  constructor() {
10843
11131
  this.LOCK_FILENAME = "packmind-lock.json";
@@ -10871,7 +11159,7 @@ var LockFileRepository = class {
10871
11159
  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);
10872
11160
  }
10873
11161
  getLockFilePath(baseDirectory) {
10874
- return path11.join(baseDirectory, this.LOCK_FILENAME);
11162
+ return path12.join(baseDirectory, this.LOCK_FILENAME);
10875
11163
  }
10876
11164
  };
10877
11165
 
@@ -10962,9 +11250,9 @@ var ListSkillsUseCase = class {
10962
11250
  };
10963
11251
 
10964
11252
  // apps/cli/src/infra/utils/readSkillDirectory.ts
10965
- var import_promises = __toESM(require("fs/promises"));
10966
- var import_path2 = __toESM(require("path"));
10967
- var import_minimatch3 = require("minimatch");
11253
+ var import_promises2 = __toESM(require("fs/promises"));
11254
+ var import_path3 = __toESM(require("path"));
11255
+ var import_minimatch2 = require("minimatch");
10968
11256
 
10969
11257
  // apps/cli/src/application/utils/normalizeLineEndings.ts
10970
11258
  function normalizeLineEndings(content) {
@@ -10972,7 +11260,7 @@ function normalizeLineEndings(content) {
10972
11260
  }
10973
11261
 
10974
11262
  // apps/cli/src/infra/utils/binaryDetection.ts
10975
- var path12 = __toESM(require("path"));
11263
+ var path13 = __toESM(require("path"));
10976
11264
  var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
10977
11265
  // Images
10978
11266
  ".png",
@@ -11030,7 +11318,7 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
11030
11318
  ".sqlite3"
11031
11319
  ]);
11032
11320
  function isBinaryExtension(filePath) {
11033
- const ext = path12.extname(filePath).toLowerCase();
11321
+ const ext = path13.extname(filePath).toLowerCase();
11034
11322
  return BINARY_EXTENSIONS.has(ext);
11035
11323
  }
11036
11324
  function isBinaryBuffer(buffer) {
@@ -11054,30 +11342,30 @@ var BLACKLIST_PATTERNS = ["**/.DS_Store"];
11054
11342
  function isBlacklisted(relativePath) {
11055
11343
  const normalizedPath = relativePath.replace(/\\/g, "/");
11056
11344
  return BLACKLIST_PATTERNS.some(
11057
- (pattern) => (0, import_minimatch3.minimatch)(normalizedPath, pattern, { dot: true })
11345
+ (pattern) => (0, import_minimatch2.minimatch)(normalizedPath, pattern, { dot: true })
11058
11346
  );
11059
11347
  }
11060
11348
  async function readSkillDirectory(dirPath) {
11061
11349
  const files = [];
11062
11350
  async function readDir(currentPath, basePath) {
11063
- const entries = await import_promises.default.readdir(currentPath, { withFileTypes: true });
11351
+ const entries = await import_promises2.default.readdir(currentPath, { withFileTypes: true });
11064
11352
  for (const entry of entries) {
11065
- const fullPath = import_path2.default.join(currentPath, entry.name);
11066
- const relativePath = import_path2.default.relative(basePath, fullPath);
11353
+ const fullPath = import_path3.default.join(currentPath, entry.name);
11354
+ const relativePath = import_path3.default.relative(basePath, fullPath);
11067
11355
  if (isBlacklisted(relativePath)) {
11068
11356
  continue;
11069
11357
  }
11070
11358
  if (entry.isDirectory()) {
11071
11359
  await readDir(fullPath, basePath);
11072
11360
  } else if (entry.isFile()) {
11073
- const stat8 = await import_promises.default.stat(fullPath);
11361
+ const stat8 = await import_promises2.default.stat(fullPath);
11074
11362
  if (stat8.size > MAX_FILE_SIZE_BYTES) {
11075
11363
  const fileSizeMB = (stat8.size / (1024 * 1024)).toFixed(2);
11076
11364
  throw new Error(
11077
11365
  `File "${relativePath}" is ${fileSizeMB} MB which exceeds the maximum allowed size of ${MAX_FILE_SIZE_MB} MB per file.`
11078
11366
  );
11079
11367
  }
11080
- const buffer = await import_promises.default.readFile(fullPath);
11368
+ const buffer = await import_promises2.default.readFile(fullPath);
11081
11369
  const isBinary = isBinaryFile(fullPath, buffer);
11082
11370
  const normalizedPath = normalizePath3(relativePath);
11083
11371
  let content;
@@ -11173,7 +11461,7 @@ ${spaceList}`
11173
11461
  // apps/cli/src/application/useCases/diffStrategies/CommandDiffStrategy.ts
11174
11462
  var import_diff2 = require("diff");
11175
11463
  var fs12 = __toESM(require("fs/promises"));
11176
- var path14 = __toESM(require("path"));
11464
+ var path15 = __toESM(require("path"));
11177
11465
 
11178
11466
  // apps/cli/src/application/utils/stripFrontmatter.ts
11179
11467
  var FRONTMATTER_DELIMITER2 = "---";
@@ -11200,7 +11488,7 @@ var CommandDiffStrategy = class {
11200
11488
  return file.artifactType === "command";
11201
11489
  }
11202
11490
  async diff(file, baseDirectory) {
11203
- const fullPath = path14.join(baseDirectory, file.path);
11491
+ const fullPath = path15.join(baseDirectory, file.path);
11204
11492
  let localContent;
11205
11493
  try {
11206
11494
  localContent = await fs12.readFile(fullPath, "utf-8");
@@ -11236,7 +11524,7 @@ var CommandDiffStrategy = class {
11236
11524
  // apps/cli/src/application/useCases/diffStrategies/SkillDiffStrategy.ts
11237
11525
  var import_diff3 = require("diff");
11238
11526
  var fs13 = __toESM(require("fs/promises"));
11239
- var path15 = __toESM(require("path"));
11527
+ var path16 = __toESM(require("path"));
11240
11528
  var SkillDiffStrategy = class {
11241
11529
  supports(file) {
11242
11530
  return file.artifactType === "skill";
@@ -11250,7 +11538,7 @@ var SkillDiffStrategy = class {
11250
11538
  async diffNewFiles(skillFolders, serverFiles, baseDirectory) {
11251
11539
  const diffs = [];
11252
11540
  for (const folder of skillFolders) {
11253
- const folderPath = path15.join(baseDirectory, folder);
11541
+ const folderPath = path16.join(baseDirectory, folder);
11254
11542
  const localFiles = await this.listFilesRecursively(folderPath);
11255
11543
  const serverPathsInFolder = new Set(
11256
11544
  serverFiles.filter((f) => f.path.startsWith(folder + "/")).map((f) => f.path)
@@ -11269,7 +11557,7 @@ var SkillDiffStrategy = class {
11269
11557
  if (serverPathsInFolder.has(filePath)) {
11270
11558
  continue;
11271
11559
  }
11272
- const fullPath = path15.join(baseDirectory, filePath);
11560
+ const fullPath = path16.join(baseDirectory, filePath);
11273
11561
  const localRead = await this.tryReadFileBinaryAware(fullPath);
11274
11562
  if (localRead === null) {
11275
11563
  continue;
@@ -11296,7 +11584,7 @@ var SkillDiffStrategy = class {
11296
11584
  return diffs;
11297
11585
  }
11298
11586
  async diffSkillMd(file, baseDirectory) {
11299
- const fullPath = path15.join(baseDirectory, file.path);
11587
+ const fullPath = path16.join(baseDirectory, file.path);
11300
11588
  const localContent = await this.tryReadFile(fullPath);
11301
11589
  if (localContent === null) {
11302
11590
  return [];
@@ -11353,7 +11641,7 @@ var SkillDiffStrategy = class {
11353
11641
  return [];
11354
11642
  }
11355
11643
  const skillFileId = createSkillFileId(file.skillFileId);
11356
- const fullPath = path15.join(baseDirectory, file.path);
11644
+ const fullPath = path16.join(baseDirectory, file.path);
11357
11645
  const localRead = await this.tryReadFileBinaryAware(fullPath);
11358
11646
  const fileRelativePath = this.computeRelativePath(file.path, skillFolders);
11359
11647
  if (localRead === null) {
@@ -11588,7 +11876,7 @@ var SkillDiffStrategy = class {
11588
11876
  }
11589
11877
  const files = [];
11590
11878
  for (const entry of entries) {
11591
- const fullPath = path15.join(dirPath, entry);
11879
+ const fullPath = path16.join(dirPath, entry);
11592
11880
  const stat8 = await this.tryStatFile(fullPath);
11593
11881
  if (!stat8) {
11594
11882
  continue;
@@ -11633,7 +11921,7 @@ var SkillDiffStrategy = class {
11633
11921
 
11634
11922
  // apps/cli/src/application/useCases/diffStrategies/StandardDiffStrategy.ts
11635
11923
  var fs14 = __toESM(require("fs/promises"));
11636
- var path16 = __toESM(require("path"));
11924
+ var path17 = __toESM(require("path"));
11637
11925
 
11638
11926
  // apps/cli/src/application/utils/parseStandardMd.ts
11639
11927
  var DEPLOYER_PARSERS = [
@@ -11930,7 +12218,7 @@ var StandardDiffStrategy = class {
11930
12218
  return file.artifactType === "standard";
11931
12219
  }
11932
12220
  async diff(file, baseDirectory) {
11933
- const fullPath = path16.join(baseDirectory, file.path);
12221
+ const fullPath = path17.join(baseDirectory, file.path);
11934
12222
  let localContent;
11935
12223
  try {
11936
12224
  localContent = await fs14.readFile(fullPath, "utf-8");
@@ -12342,6 +12630,7 @@ var PackmindCliHexaFactory = class {
12342
12630
  login: new LoginUseCase(),
12343
12631
  logout: new LogoutUseCase(),
12344
12632
  whoami: new WhoamiUseCase(),
12633
+ checkCliVersion: new CheckCliVersionUseCase(),
12345
12634
  setupMcp: new SetupMcpUseCase({
12346
12635
  gateway: this.repositories.packmindGateway,
12347
12636
  mcpConfigService: new McpConfigService()
@@ -12468,8 +12757,8 @@ var PackmindCliHexa = class {
12468
12757
  }
12469
12758
  async writeConfig(baseDirectory, packagesSlugs) {
12470
12759
  const packages = {};
12471
- packagesSlugs.forEach((slug) => {
12472
- packages[slug] = "*";
12760
+ packagesSlugs.forEach((slug2) => {
12761
+ packages[slug2] = "*";
12473
12762
  });
12474
12763
  const existingConfig = await this.hexa.repositories.configFileRepository.readConfig(
12475
12764
  baseDirectory
@@ -12531,6 +12820,9 @@ var PackmindCliHexa = class {
12531
12820
  async whoami(command30) {
12532
12821
  return this.hexa.useCases.whoami.execute(command30);
12533
12822
  }
12823
+ async checkCliVersion(command30) {
12824
+ return this.hexa.useCases.checkCliVersion.execute(command30);
12825
+ }
12534
12826
  async setupMcp(command30) {
12535
12827
  return this.hexa.useCases.setupMcp.execute(command30);
12536
12828
  }
@@ -12581,7 +12873,7 @@ var PackmindCliHexa = class {
12581
12873
  }
12582
12874
  const defaultSpace = await this.getDefaultSpace();
12583
12875
  return slugs.map(
12584
- (slug) => slug.startsWith("@") ? slug : `@${defaultSpace.slug}/${slug}`
12876
+ (slug2) => slug2.startsWith("@") ? slug2 : `@${defaultSpace.slug}/${slug2}`
12585
12877
  );
12586
12878
  }
12587
12879
  getSpaceService() {
@@ -12673,26 +12965,26 @@ var pathModule = __toESM(require("path"));
12673
12965
 
12674
12966
  // apps/cli/src/application/services/PackmindIgnoreReader.ts
12675
12967
  var fs15 = __toESM(require("fs/promises"));
12676
- var path17 = __toESM(require("path"));
12968
+ var path18 = __toESM(require("path"));
12677
12969
  var IGNORE_FILENAME = ".packmindignore";
12678
12970
  var PackmindIgnoreReader = class {
12679
12971
  async readIgnorePatterns(startDirectory, stopDirectory) {
12680
12972
  const patterns = [];
12681
- const normalizedStart = path17.resolve(startDirectory);
12682
- const normalizedStop = stopDirectory ? path17.resolve(stopDirectory) : null;
12973
+ const normalizedStart = path18.resolve(startDirectory);
12974
+ const normalizedStop = stopDirectory ? path18.resolve(stopDirectory) : null;
12683
12975
  if (normalizedStop === null) {
12684
- const ignoreFile = path17.join(normalizedStart, IGNORE_FILENAME);
12976
+ const ignoreFile = path18.join(normalizedStart, IGNORE_FILENAME);
12685
12977
  return this.parseIgnoreFile(ignoreFile);
12686
12978
  }
12687
12979
  let currentDir = normalizedStart;
12688
12980
  while (true) {
12689
- const ignoreFile = path17.join(currentDir, IGNORE_FILENAME);
12981
+ const ignoreFile = path18.join(currentDir, IGNORE_FILENAME);
12690
12982
  const filePatterns = await this.parseIgnoreFile(ignoreFile);
12691
12983
  patterns.push(...filePatterns);
12692
12984
  if (currentDir === normalizedStop) {
12693
12985
  break;
12694
12986
  }
12695
- const parentDir = path17.dirname(currentDir);
12987
+ const parentDir = path18.dirname(currentDir);
12696
12988
  if (parentDir === currentDir) {
12697
12989
  break;
12698
12990
  }
@@ -12724,7 +13016,7 @@ function isNotLoggedInError(error) {
12724
13016
  }
12725
13017
  async function lintHandler(args2, deps) {
12726
13018
  const {
12727
- path: path34,
13019
+ path: path33,
12728
13020
  draft,
12729
13021
  rule,
12730
13022
  language,
@@ -12746,7 +13038,7 @@ async function lintHandler(args2, deps) {
12746
13038
  throw new Error("option --rule is required to use --draft mode");
12747
13039
  }
12748
13040
  const startedAt = Date.now();
12749
- const targetPath = path34 ?? ".";
13041
+ const targetPath = path33 ?? ".";
12750
13042
  const absolutePath = resolvePath(targetPath);
12751
13043
  let stats;
12752
13044
  try {
@@ -12858,7 +13150,7 @@ async function lintHandler(args2, deps) {
12858
13150
  }
12859
13151
  }
12860
13152
 
12861
- // apps/cli/src/infra/commands/LinterCommand.ts
13153
+ // apps/cli/src/infra/commands/customParameters/Logger.ts
12862
13154
  var Logger = {
12863
13155
  from: async (input) => {
12864
13156
  switch (input) {
@@ -12872,6 +13164,8 @@ var Logger = {
12872
13164
  );
12873
13165
  }
12874
13166
  };
13167
+
13168
+ // apps/cli/src/infra/commands/customParameters/RuleID.ts
12875
13169
  var RuleID = {
12876
13170
  from: async (input) => {
12877
13171
  const match = input.match(/^@([^/]+)\/(.+)$/);
@@ -12886,6 +13180,8 @@ var RuleID = {
12886
13180
  };
12887
13181
  }
12888
13182
  };
13183
+
13184
+ // apps/cli/src/infra/commands/customParameters/DiffModeType.ts
12889
13185
  var DiffModeType = {
12890
13186
  from: async (input) => {
12891
13187
  switch (input) {
@@ -12899,6 +13195,8 @@ var DiffModeType = {
12899
13195
  );
12900
13196
  }
12901
13197
  };
13198
+
13199
+ // apps/cli/src/infra/commands/customParameters/LevelType.ts
12902
13200
  var LevelType = {
12903
13201
  from: async (input) => {
12904
13202
  switch (input) {
@@ -12912,6 +13210,8 @@ var LevelType = {
12912
13210
  );
12913
13211
  }
12914
13212
  };
13213
+
13214
+ // apps/cli/src/infra/commands/LinterCommand.ts
12915
13215
  var lintCommand = (0, import_cmd_ts.command)({
12916
13216
  name: "lint",
12917
13217
  description: "Lint code at the specified path",
@@ -13005,8 +13305,8 @@ var lintCommand = (0, import_cmd_ts.command)({
13005
13305
  });
13006
13306
 
13007
13307
  // apps/cli/src/wasm-runtime.ts
13008
- var import_fs19 = require("fs");
13009
- var import_path3 = require("path");
13308
+ var import_fs20 = require("fs");
13309
+ var import_path4 = require("path");
13010
13310
  var import_os = require("os");
13011
13311
 
13012
13312
  // apps/cli/src/embedded-wasm.ts
@@ -13037,20 +13337,20 @@ function hasEmbeddedWasmFiles() {
13037
13337
  return Object.keys(EMBEDDED_WASM_FILES).length > 0;
13038
13338
  }
13039
13339
  function extractWasmFiles() {
13040
- if (wasmExtractedDir && (0, import_fs19.existsSync)(wasmExtractedDir)) {
13340
+ if (wasmExtractedDir && (0, import_fs20.existsSync)(wasmExtractedDir)) {
13041
13341
  return wasmExtractedDir;
13042
13342
  }
13043
- const tempDir = (0, import_path3.join)((0, import_os.tmpdir)(), `packmind-wasm-${process.pid}`);
13044
- if (!(0, import_fs19.existsSync)(tempDir)) {
13045
- (0, import_fs19.mkdirSync)(tempDir, { recursive: true });
13343
+ const tempDir = (0, import_path4.join)((0, import_os.tmpdir)(), `packmind-wasm-${process.pid}`);
13344
+ if (!(0, import_fs20.existsSync)(tempDir)) {
13345
+ (0, import_fs20.mkdirSync)(tempDir, { recursive: true });
13046
13346
  }
13047
13347
  for (const [filename, base64Data] of Object.entries(EMBEDDED_WASM_FILES)) {
13048
- const wasmPath = (0, import_path3.join)(tempDir, filename);
13049
- if ((0, import_fs19.existsSync)(wasmPath)) {
13348
+ const wasmPath = (0, import_path4.join)(tempDir, filename);
13349
+ if ((0, import_fs20.existsSync)(wasmPath)) {
13050
13350
  continue;
13051
13351
  }
13052
13352
  const wasmBuffer = Buffer.from(base64Data, "base64");
13053
- (0, import_fs19.writeFileSync)(wasmPath, wasmBuffer);
13353
+ (0, import_fs20.writeFileSync)(wasmPath, wasmBuffer);
13054
13354
  }
13055
13355
  wasmExtractedDir = tempDir;
13056
13356
  process.on("exit", () => {
@@ -13061,14 +13361,14 @@ function extractWasmFiles() {
13061
13361
  // apps/cli/src/main.ts
13062
13362
  var import_dotenv = require("dotenv");
13063
13363
  var fs26 = __toESM(require("fs"));
13064
- var path33 = __toESM(require("path"));
13364
+ var path32 = __toESM(require("path"));
13065
13365
 
13066
13366
  // apps/cli/src/infra/commands/InstallCommand.ts
13067
13367
  var import_cmd_ts2 = __toESM(require_cjs());
13068
13368
 
13069
13369
  // apps/cli/src/infra/commands/installPackagesHandler.ts
13070
13370
  var fs17 = __toESM(require("fs/promises"));
13071
- var path18 = __toESM(require("path"));
13371
+ var path19 = __toESM(require("path"));
13072
13372
  var { version: CLI_VERSION } = require_package();
13073
13373
  async function notifyDistributionIfInGitRepo(params) {
13074
13374
  const { packmindCliHexa, cwd, packages, log, agents } = params;
@@ -13265,7 +13565,7 @@ async function executeInstallForDirectory(directory, deps) {
13265
13565
  };
13266
13566
  }
13267
13567
  const configSlugsWereNormalized = configPackages.some(
13268
- (slug, i) => slug !== normalizedConfigPackages[i]
13568
+ (slug2, i) => slug2 !== normalizedConfigPackages[i]
13269
13569
  );
13270
13570
  if (configSlugsWereNormalized) {
13271
13571
  await packmindCliHexa.writeConfig(directory, normalizedConfigPackages);
@@ -13307,7 +13607,7 @@ async function installPackagesHandler(args2, deps) {
13307
13607
  const rawCwd = getCwd();
13308
13608
  let cwd = rawCwd;
13309
13609
  if (args2.path) {
13310
- const resolvedPath = path18.resolve(rawCwd, args2.path);
13610
+ const resolvedPath = path19.resolve(rawCwd, args2.path);
13311
13611
  try {
13312
13612
  const stat8 = await fs17.stat(resolvedPath);
13313
13613
  if (!stat8.isDirectory()) {
@@ -13331,7 +13631,7 @@ async function installPackagesHandler(args2, deps) {
13331
13631
  notificationSent: false
13332
13632
  };
13333
13633
  }
13334
- const relativeToCwd = path18.relative(rawCwd, resolvedPath);
13634
+ const relativeToCwd = path19.relative(rawCwd, resolvedPath);
13335
13635
  const displayPath = relativeToCwd ? `./${relativeToCwd}/packmind.json` : `./packmind.json`;
13336
13636
  log(`Installing in ${displayPath}...`);
13337
13637
  }
@@ -13478,10 +13778,10 @@ added ${result.filesCreated} files, changed ${result.filesUpdated} files, remove
13478
13778
  };
13479
13779
  }
13480
13780
  const configSlugsWereNormalized = configPackages.some(
13481
- (slug, i) => slug !== normalizedConfigSlugs[i]
13781
+ (slug2, i) => slug2 !== normalizedConfigSlugs[i]
13482
13782
  );
13483
13783
  const newPackages = normalizedNewSlugs.filter(
13484
- (slug) => !normalizedConfigSlugs.includes(slug)
13784
+ (slug2) => !normalizedConfigSlugs.includes(slug2)
13485
13785
  );
13486
13786
  if (configSlugsWereNormalized) {
13487
13787
  await packmindCliHexa.writeConfig(cwd, allPackages);
@@ -13661,7 +13961,7 @@ async function uninstallPackagesHandler(args2, deps) {
13661
13961
  originalKey
13662
13962
  );
13663
13963
  });
13664
- const packagesToUninstall = normalizedRequestedSlugs.filter((slug) => normalizedToOriginalConfigKey.has(slug)).map((slug) => normalizedToOriginalConfigKey.get(slug));
13964
+ const packagesToUninstall = normalizedRequestedSlugs.filter((slug2) => normalizedToOriginalConfigKey.has(slug2)).map((slug2) => normalizedToOriginalConfigKey.get(slug2));
13665
13965
  const notInstalledPackages = packagesSlugs.filter(
13666
13966
  (_, i) => !normalizedToOriginalConfigKey.has(normalizedRequestedSlugs[i])
13667
13967
  );
@@ -13791,7 +14091,7 @@ async function recursiveInstallHandler(args2, deps) {
13791
14091
  };
13792
14092
  let startDirectory = cwd;
13793
14093
  if (args2.path) {
13794
- const resolvedPath = path18.resolve(cwd, args2.path);
14094
+ const resolvedPath = path19.resolve(cwd, args2.path);
13795
14095
  try {
13796
14096
  const stat8 = await fs17.stat(resolvedPath);
13797
14097
  if (!stat8.isDirectory()) {
@@ -13894,8 +14194,8 @@ async function recursiveInstallHandler(args2, deps) {
13894
14194
  // apps/cli/src/infra/utils/spaceFilterUtils.ts
13895
14195
  function resolveSpaceFromArgs(spaceArg, spaces) {
13896
14196
  if (!spaceArg) return null;
13897
- const slug = spaceArg.startsWith("@") ? spaceArg.slice(1) : spaceArg;
13898
- return spaces.find((s) => s.slug === slug) ?? null;
14197
+ const slug2 = spaceArg.startsWith("@") ? spaceArg.slice(1) : spaceArg;
14198
+ return spaces.find((s) => s.slug === slug2) ?? null;
13899
14199
  }
13900
14200
 
13901
14201
  // apps/cli/src/infra/utils/urlBuilderUtils.ts
@@ -13969,8 +14269,7 @@ async function listPackagesHandler(args2, deps) {
13969
14269
  }
13970
14270
  const matchedSpace = resolveSpaceFromArgs(args2.space, allSpaces);
13971
14271
  if (args2.space && !matchedSpace) {
13972
- const slug = args2.space.startsWith("@") ? args2.space.slice(1) : args2.space;
13973
- logErrorConsole(`Space '@${slug}' not found.`);
14272
+ logErrorConsole(`Space "@${args2.space}" not found.`);
13974
14273
  logInfoConsole(
13975
14274
  `Available spaces: ${allSpaces.map((s) => `@${s.slug}`).join(", ")}`
13976
14275
  );
@@ -13983,7 +14282,7 @@ async function listPackagesHandler(args2, deps) {
13983
14282
  const spaces = matchedSpace ? [matchedSpace] : allSpaces;
13984
14283
  if (packages.length === 0) {
13985
14284
  logConsole(
13986
- matchedSpace ? `No packages found in space '@${matchedSpace.slug}'.` : "No packages found."
14285
+ matchedSpace ? `No packages found in space "@${matchedSpace.slug}".` : "No packages found."
13987
14286
  );
13988
14287
  exit(0);
13989
14288
  return;
@@ -14006,20 +14305,20 @@ async function listPackagesHandler(args2, deps) {
14006
14305
  }
14007
14306
 
14008
14307
  // apps/cli/src/infra/utils/packageSlugUtils.ts
14009
- function parsePackageSlug(slug) {
14010
- if (!slug.startsWith("@")) return null;
14011
- const slash = slug.indexOf("/", 1);
14308
+ function parsePackageSlug(slug2) {
14309
+ if (!slug2.startsWith("@")) return null;
14310
+ const slash = slug2.indexOf("/", 1);
14012
14311
  if (slash === -1) return null;
14013
- return { spaceSlug: slug.slice(1, slash), pkgSlug: slug.slice(slash + 1) };
14312
+ return { spaceSlug: slug2.slice(1, slash), pkgSlug: slug2.slice(slash + 1) };
14014
14313
  }
14015
14314
 
14016
14315
  // apps/cli/src/infra/commands/packages/showPackageHandler.ts
14017
14316
  function isNotFoundError(err) {
14018
14317
  return err instanceof Error && err.message.includes("does not exist");
14019
14318
  }
14020
- async function resolvePackage(slug, packmindCliHexa) {
14319
+ async function resolvePackage(slug2, packmindCliHexa) {
14021
14320
  const allSpaces = await packmindCliHexa.getSpaces();
14022
- const parsed = parsePackageSlug(slug);
14321
+ const parsed = parsePackageSlug(slug2);
14023
14322
  if (parsed) {
14024
14323
  const { spaceSlug, pkgSlug } = parsed;
14025
14324
  const matchedSpace = allSpaces.find((s) => s.slug === spaceSlug);
@@ -14045,7 +14344,7 @@ async function resolvePackage(slug, packmindCliHexa) {
14045
14344
  const results = await Promise.allSettled(
14046
14345
  allSpaces.map(async (space) => ({
14047
14346
  pkg: await packmindCliHexa.getPackageBySlug({
14048
- slug,
14347
+ slug: slug2,
14049
14348
  spaceId: space.id
14050
14349
  }),
14051
14350
  spaceSlug: space.slug
@@ -14059,17 +14358,17 @@ async function resolvePackage(slug, packmindCliHexa) {
14059
14358
  if (realError) {
14060
14359
  throw realError.reason;
14061
14360
  }
14062
- throw new Error(`Package '${slug}' not found in any space.`);
14361
+ throw new Error(`Package '${slug2}' not found in any space.`);
14063
14362
  }
14064
14363
  if (matches.length > 1) {
14065
- const example = `@${matches[0].spaceSlug}/${slug}`;
14364
+ const example = `@${matches[0].spaceSlug}/${slug2}`;
14066
14365
  throw new Error(
14067
- `Package '${slug}' exists in multiple spaces (${matches.map((m) => `@${m.spaceSlug}`).join(", ")}). Please specify the space using the @space/package format (e.g. ${example}).`
14366
+ `Package '${slug2}' exists in multiple spaces (${matches.map((m) => `@${m.spaceSlug}`).join(", ")}). Please specify the space using the @space/package format (e.g. ${example}).`
14068
14367
  );
14069
14368
  }
14070
14369
  return {
14071
14370
  pkg: matches[0].pkg,
14072
- fullSlug: `@${matches[0].spaceSlug}/${slug}`
14371
+ fullSlug: `@${matches[0].spaceSlug}/${slug2}`
14073
14372
  };
14074
14373
  }
14075
14374
  async function showPackageHandler(args2, deps) {
@@ -14133,13 +14432,13 @@ ${pkg.name} (${fullSlug}):
14133
14432
  var crypto = __toESM(require("crypto"));
14134
14433
  var fs18 = __toESM(require("fs"));
14135
14434
  var os4 = __toESM(require("os"));
14136
- var path19 = __toESM(require("path"));
14435
+ var path20 = __toESM(require("path"));
14137
14436
  var yaml = __toESM(require("yaml"));
14138
14437
  var PlaybookLocalRepository = class {
14139
14438
  constructor(repoRoot) {
14140
14439
  const normalized = this.normalizeRepoRoot(repoRoot);
14141
14440
  const hash = crypto.createHash("md5").update(normalized).digest("hex");
14142
- this.storagePath = path19.join(
14441
+ this.storagePath = path20.join(
14143
14442
  os4.homedir(),
14144
14443
  ".packmind",
14145
14444
  hash,
@@ -14205,7 +14504,7 @@ var PlaybookLocalRepository = class {
14205
14504
  }
14206
14505
  }
14207
14506
  writeYaml(data) {
14208
- const dir = path19.dirname(this.storagePath);
14507
+ const dir = path20.dirname(this.storagePath);
14209
14508
  fs18.mkdirSync(dir, { recursive: true });
14210
14509
  fs18.writeFileSync(this.storagePath, yaml.stringify(data), "utf-8");
14211
14510
  }
@@ -14249,7 +14548,7 @@ var installCommand = (0, import_cmd_ts2.command)({
14249
14548
  description: "Package slugs to install (e.g., backend frontend)"
14250
14549
  })
14251
14550
  },
14252
- handler: async ({ list, status, recursive, path: path34, show, packagesSlugs }) => {
14551
+ handler: async ({ list, status, recursive, path: path33, show, packagesSlugs }) => {
14253
14552
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
14254
14553
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
14255
14554
  const repoRoot = await packmindCliHexa.tryGetGitRepositoryRoot(
@@ -14283,17 +14582,17 @@ var installCommand = (0, import_cmd_ts2.command)({
14283
14582
  logWarningConsole(
14284
14583
  "\u26A0\uFE0F The --recursive flag is deprecated. Install is now recursive by default."
14285
14584
  );
14286
- await recursiveInstallHandler({ path: path34 || void 0 }, deps);
14585
+ await recursiveInstallHandler({ path: path33 || void 0 }, deps);
14287
14586
  return;
14288
14587
  }
14289
14588
  if (packagesSlugs.length > 0) {
14290
14589
  await installPackagesHandler(
14291
- { packagesSlugs, path: path34 || void 0 },
14590
+ { packagesSlugs, path: path33 || void 0 },
14292
14591
  deps
14293
14592
  );
14294
14593
  return;
14295
14594
  }
14296
- await recursiveInstallHandler({ path: path34 || void 0 }, deps);
14595
+ await recursiveInstallHandler({ path: path33 || void 0 }, deps);
14297
14596
  }
14298
14597
  });
14299
14598
 
@@ -14422,6 +14721,20 @@ var logoutCommand = (0, import_cmd_ts5.command)({
14422
14721
 
14423
14722
  // apps/cli/src/infra/commands/WhoamiCommand.ts
14424
14723
  var import_cmd_ts6 = __toESM(require_cjs());
14724
+
14725
+ // apps/cli/src/infra/commands/versionCheckNotice.ts
14726
+ function displayVersionNotice(result) {
14727
+ if (!result?.updateAvailable) {
14728
+ return;
14729
+ }
14730
+ logConsole("");
14731
+ logWarningConsole(
14732
+ `Update available: ${result.currentVersion} \u2192 ${result.latestVersion} \u2014 run \`packmind-cli update\` to upgrade`
14733
+ );
14734
+ }
14735
+
14736
+ // apps/cli/src/infra/commands/WhoamiCommand.ts
14737
+ var { version: CLI_VERSION2 } = require_package();
14425
14738
  function formatExpiresAt(expiresAt) {
14426
14739
  const now = /* @__PURE__ */ new Date();
14427
14740
  if (expiresAt < now) {
@@ -14464,6 +14777,9 @@ var whoamiCommand = (0, import_cmd_ts6.command)({
14464
14777
  handler: async () => {
14465
14778
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
14466
14779
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
14780
+ const versionCheckPromise = packmindCliHexa.checkCliVersion({
14781
+ currentVersion: CLI_VERSION2
14782
+ });
14467
14783
  const result = await packmindCliHexa.whoami({});
14468
14784
  if (!result.isAuthenticated) {
14469
14785
  logErrorConsole("Not authenticated");
@@ -14483,6 +14799,7 @@ Credentials are loaded from (in order of priority):`);
14483
14799
  logSuccessConsole("Authenticated");
14484
14800
  }
14485
14801
  displayAuthInfo(result);
14802
+ displayVersionNotice(await versionCheckPromise);
14486
14803
  if (result.isExpired) {
14487
14804
  process.exit(1);
14488
14805
  }
@@ -14497,9 +14814,9 @@ var inquirer = __toESM(require("inquirer"));
14497
14814
 
14498
14815
  // apps/cli/src/application/services/AgentDetectionService.ts
14499
14816
  var fs19 = __toESM(require("fs"));
14500
- var path20 = __toESM(require("path"));
14817
+ var path21 = __toESM(require("path"));
14501
14818
  var os5 = __toESM(require("os"));
14502
- var import_child_process3 = require("child_process");
14819
+ var import_child_process4 = require("child_process");
14503
14820
  var AgentDetectionService = class {
14504
14821
  constructor(projectDir = process.cwd()) {
14505
14822
  this.projectDir = projectDir;
@@ -14524,21 +14841,21 @@ var AgentDetectionService = class {
14524
14841
  return this.isCommandAvailable("claude");
14525
14842
  }
14526
14843
  isCursorAvailable() {
14527
- const cursorConfigDir = path20.join(os5.homedir(), ".cursor");
14844
+ const cursorConfigDir = path21.join(os5.homedir(), ".cursor");
14528
14845
  return fs19.existsSync(cursorConfigDir);
14529
14846
  }
14530
14847
  isVSCodeAvailable() {
14531
- const vscodeDir = path20.join(this.projectDir, ".vscode");
14848
+ const vscodeDir = path21.join(this.projectDir, ".vscode");
14532
14849
  return fs19.existsSync(vscodeDir);
14533
14850
  }
14534
14851
  isContinueAvailable() {
14535
- const continueDir = path20.join(this.projectDir, ".continue");
14852
+ const continueDir = path21.join(this.projectDir, ".continue");
14536
14853
  return fs19.existsSync(continueDir);
14537
14854
  }
14538
14855
  isCommandAvailable(command30) {
14539
14856
  try {
14540
14857
  const whichCommand = process.platform === "win32" ? "where" : "which";
14541
- (0, import_child_process3.execSync)(`${whichCommand} ${command30}`, { stdio: "pipe" });
14858
+ (0, import_child_process4.execSync)(`${whichCommand} ${command30}`, { stdio: "pipe" });
14542
14859
  return true;
14543
14860
  } catch {
14544
14861
  return false;
@@ -14546,7 +14863,7 @@ var AgentDetectionService = class {
14546
14863
  }
14547
14864
  };
14548
14865
 
14549
- // apps/cli/src/infra/commands/SetupMcpCommand.ts
14866
+ // apps/cli/src/infra/commands/customParameters/AgentArgType.ts
14550
14867
  var VALID_AGENTS = ["copilot", "cursor", "claude", "continue"];
14551
14868
  var agentArgToType = {
14552
14869
  copilot: "vscode",
@@ -14565,6 +14882,8 @@ var AgentArgType = {
14565
14882
  );
14566
14883
  }
14567
14884
  };
14885
+
14886
+ // apps/cli/src/infra/commands/SetupMcpCommand.ts
14568
14887
  var ALL_AGENTS2 = [
14569
14888
  { type: "claude", name: "Claude Code" },
14570
14889
  { type: "cursor", name: "Cursor" },
@@ -14747,6 +15066,13 @@ var originSkillOption = (0, import_cmd_ts8.option)({
14747
15066
  type: (0, import_cmd_ts8.optional)(import_cmd_ts8.string)
14748
15067
  });
14749
15068
 
15069
+ // apps/cli/src/infra/commands/customParameters/SpaceSlug.ts
15070
+ var SpaceSlug = {
15071
+ from: async (input) => {
15072
+ return input.startsWith("@") ? input.slice(1) : input;
15073
+ }
15074
+ };
15075
+
14750
15076
  // apps/cli/src/infra/commands/skills/AddSkillCommand.ts
14751
15077
  var addSkillCommand = (0, import_cmd_ts9.command)({
14752
15078
  name: "add",
@@ -14760,7 +15086,7 @@ var addSkillCommand = (0, import_cmd_ts9.command)({
14760
15086
  space: (0, import_cmd_ts9.option)({
14761
15087
  long: "space",
14762
15088
  description: "Slug of the space in which to add the skill (with or without leading @)",
14763
- type: (0, import_cmd_ts9.optional)(import_cmd_ts9.string)
15089
+ type: (0, import_cmd_ts9.optional)(SpaceSlug)
14764
15090
  }),
14765
15091
  originSkill: originSkillOption
14766
15092
  },
@@ -14805,7 +15131,7 @@ Example: ${formatCommand(`packmind-cli skills add --space <slug> ${skillPath}`)}
14805
15131
 
14806
15132
  // apps/cli/src/infra/commands/skills/InstallDefaultSkillsCommand.ts
14807
15133
  var import_cmd_ts10 = __toESM(require_cjs());
14808
- var { version: CLI_VERSION2 } = require_package();
15134
+ var { version: CLI_VERSION3 } = require_package();
14809
15135
  var installDefaultSkillsCommand = (0, import_cmd_ts10.command)({
14810
15136
  name: "install-default",
14811
15137
  description: "Install default Packmind skills for configured coding agents",
@@ -14822,8 +15148,13 @@ var installDefaultSkillsCommand = (0, import_cmd_ts10.command)({
14822
15148
  logInfoConsole("Installing default skills...");
14823
15149
  const result = await packmindCliHexa.installDefaultSkills({
14824
15150
  includeBeta,
14825
- cliVersion: includeBeta ? void 0 : CLI_VERSION2
15151
+ cliVersion: includeBeta ? void 0 : CLI_VERSION3
14826
15152
  });
15153
+ if (result.skippedSkillsCount > 0) {
15154
+ logWarningConsole(
15155
+ `${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.`
15156
+ );
15157
+ }
14827
15158
  if (result.errors.length > 0) {
14828
15159
  for (const error of result.errors) {
14829
15160
  logErrorConsole(`Error: ${error}`);
@@ -14921,8 +15252,7 @@ async function listSkillsHandler(args2, deps) {
14921
15252
  const spaces = await packmindCliHexa.getSpaces();
14922
15253
  const matchedSpace = resolveSpaceFromArgs(args2.space, spaces);
14923
15254
  if (args2.space && !matchedSpace) {
14924
- const slug = args2.space.startsWith("@") ? args2.space.slice(1) : args2.space;
14925
- logErrorConsole(`Space "${slug}" not found.`);
15255
+ logErrorConsole(`Space "@${args2.space}" not found.`);
14926
15256
  exit(1);
14927
15257
  return;
14928
15258
  }
@@ -14931,14 +15261,14 @@ async function listSkillsHandler(args2, deps) {
14931
15261
  );
14932
15262
  if (skills.length === 0) {
14933
15263
  logConsole(
14934
- matchedSpace ? `No skills found in space "${matchedSpace.slug}".` : "No skills found."
15264
+ matchedSpace ? `No skills found in space "@${matchedSpace.slug}".` : "No skills found."
14935
15265
  );
14936
15266
  exit(0);
14937
15267
  return;
14938
15268
  }
14939
15269
  logConsole(formatHeader(`\u{1F4CB} Skills (${skills.length})
14940
15270
  `));
14941
- const buildUrl = resolveUrlBuilder((slug) => `skills/${slug}/files`);
15271
+ const buildUrl = resolveUrlBuilder((slug2) => `skills/${slug2}/files`);
14942
15272
  displayGroupedSkills(skills, spaces, buildUrl);
14943
15273
  exit(0);
14944
15274
  } catch (err) {
@@ -14954,7 +15284,7 @@ var listSkillsCommand = (0, import_cmd_ts11.command)({
14954
15284
  description: "List available skills",
14955
15285
  args: {
14956
15286
  space: (0, import_cmd_ts11.option)({
14957
- type: (0, import_cmd_ts11.optional)(import_cmd_ts11.string),
15287
+ type: (0, import_cmd_ts11.optional)(SpaceSlug),
14958
15288
  long: "space",
14959
15289
  description: "Filter skills by space slug"
14960
15290
  })
@@ -15121,8 +15451,8 @@ async function createStandardHandler(filePath, useCase, originSkill, spaceSlug)
15121
15451
  }
15122
15452
 
15123
15453
  // apps/cli/src/application/utils/spaceUtils.ts
15124
- function resolveSpace(spaces, slug) {
15125
- const normalizedSlug = slug?.replace(/^@/, "");
15454
+ function resolveSpace(spaces, slug2) {
15455
+ const normalizedSlug = slug2?.replace(/^@/, "");
15126
15456
  if (normalizedSlug) {
15127
15457
  const found = spaces.find((s) => s.slug === normalizedSlug);
15128
15458
  if (!found) {
@@ -15186,7 +15516,7 @@ var createStandardCommand = (0, import_cmd_ts13.command)({
15186
15516
  space: (0, import_cmd_ts13.option)({
15187
15517
  long: "space",
15188
15518
  description: "Slug of the space in which to create the standard (with or without leading @)",
15189
- type: (0, import_cmd_ts13.optional)(import_cmd_ts13.string)
15519
+ type: (0, import_cmd_ts13.optional)(SpaceSlug)
15190
15520
  }),
15191
15521
  originSkill: originSkillOption
15192
15522
  },
@@ -15297,8 +15627,7 @@ async function listStandardsHandler(args2, deps) {
15297
15627
  const spaces = await packmindCliHexa.getSpaces();
15298
15628
  const matchedSpace = resolveSpaceFromArgs(args2.space, spaces);
15299
15629
  if (args2.space && !matchedSpace) {
15300
- const slug = args2.space.startsWith("@") ? args2.space.slice(1) : args2.space;
15301
- logErrorConsole(`Space "${slug}" not found.`);
15630
+ logErrorConsole(`Space "@${args2.space}" not found.`);
15302
15631
  exit(1);
15303
15632
  return;
15304
15633
  }
@@ -15307,7 +15636,7 @@ async function listStandardsHandler(args2, deps) {
15307
15636
  );
15308
15637
  if (standards.length === 0) {
15309
15638
  logConsole(
15310
- matchedSpace ? `No standards found in space "${matchedSpace.slug}".` : "No standards found."
15639
+ matchedSpace ? `No standards found in space "@${matchedSpace.slug}".` : "No standards found."
15311
15640
  );
15312
15641
  exit(0);
15313
15642
  return;
@@ -15330,7 +15659,7 @@ var listStandardsCommand = (0, import_cmd_ts14.command)({
15330
15659
  description: "List available coding standards",
15331
15660
  args: {
15332
15661
  space: (0, import_cmd_ts14.option)({
15333
- type: (0, import_cmd_ts14.optional)(import_cmd_ts14.string),
15662
+ type: (0, import_cmd_ts14.optional)(SpaceSlug),
15334
15663
  long: "space",
15335
15664
  description: "Filter standards by space slug"
15336
15665
  })
@@ -15537,7 +15866,7 @@ var createCommandCommand = (0, import_cmd_ts16.command)({
15537
15866
  space: (0, import_cmd_ts16.option)({
15538
15867
  long: "space",
15539
15868
  description: "Slug of the space in which to create the command",
15540
- type: (0, import_cmd_ts16.optional)(import_cmd_ts16.string)
15869
+ type: (0, import_cmd_ts16.optional)(SpaceSlug)
15541
15870
  }),
15542
15871
  originSkill: originSkillOption
15543
15872
  },
@@ -15642,8 +15971,7 @@ async function listCommandsHandler(args2, deps) {
15642
15971
  const spaces = await packmindCliHexa.getSpaces();
15643
15972
  const matchedSpace = resolveSpaceFromArgs(args2.space, spaces);
15644
15973
  if (args2.space && !matchedSpace) {
15645
- const slug = args2.space.startsWith("@") ? args2.space.slice(1) : args2.space;
15646
- logErrorConsole(`Space "${slug}" not found.`);
15974
+ logErrorConsole(`Space "@${args2.space}" not found.`);
15647
15975
  exit(1);
15648
15976
  return;
15649
15977
  }
@@ -15652,7 +15980,7 @@ async function listCommandsHandler(args2, deps) {
15652
15980
  );
15653
15981
  if (commands.length === 0) {
15654
15982
  logConsole(
15655
- matchedSpace ? `No commands found in space "${matchedSpace.slug}".` : "No commands found."
15983
+ matchedSpace ? `No commands found in space "@${matchedSpace.slug}".` : "No commands found."
15656
15984
  );
15657
15985
  exit(0);
15658
15986
  return;
@@ -15679,7 +16007,7 @@ var listCommandsCommand = (0, import_cmd_ts17.command)({
15679
16007
  description: "List available commands",
15680
16008
  args: {
15681
16009
  space: (0, import_cmd_ts17.option)({
15682
- type: (0, import_cmd_ts17.optional)(import_cmd_ts17.string),
16010
+ type: (0, import_cmd_ts17.optional)(SpaceSlug),
15683
16011
  long: "space",
15684
16012
  description: "Filter commands by space slug"
15685
16013
  })
@@ -16150,7 +16478,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16150
16478
  description: "Subcommand and arguments (e.g., add <path>, remove <path>)"
16151
16479
  })
16152
16480
  },
16153
- handler: async ({ submit, includeSubmitted, message, path: path34, positionals }) => {
16481
+ handler: async ({ submit, includeSubmitted, message, path: path33, positionals }) => {
16154
16482
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
16155
16483
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
16156
16484
  if (submit) {
@@ -16166,7 +16494,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16166
16494
  process.exit(1);
16167
16495
  }
16168
16496
  if (positionals[0] === "add") {
16169
- const addFilePath = path34 && positionals[1] ? `${path34}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16497
+ const addFilePath = path33 && positionals[1] ? `${path33}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16170
16498
  const addCommand = `packmind-cli playbook add ${addFilePath}`;
16171
16499
  logErrorConsole("Deprecated: `packmind-cli diff add` has been removed");
16172
16500
  logInfoConsole("Use the following command instead:");
@@ -16174,7 +16502,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16174
16502
  process.exit(1);
16175
16503
  }
16176
16504
  if (positionals[0] === "remove" || positionals[0] === "rm") {
16177
- const removeFilePath = path34 && positionals[1] ? `${path34}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16505
+ const removeFilePath = path33 && positionals[1] ? `${path33}/${positionals[1]}`.replace(/\/+/g, "/") : positionals[1];
16178
16506
  const removeCommand = `packmind-cli playbook remove ${removeFilePath}`;
16179
16507
  logErrorConsole(
16180
16508
  "Deprecated: `packmind-cli diff remove` has been removed"
@@ -16183,7 +16511,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16183
16511
  logInfoConsole(` ${formatCommand(removeCommand)}`);
16184
16512
  process.exit(1);
16185
16513
  }
16186
- const diffCommand3 = `packmind-cli playbook diff${includeSubmitted ? " --include-submitted" : ""}${path34 ? ` --path ${path34}` : ""}`;
16514
+ const diffCommand3 = `packmind-cli playbook diff${includeSubmitted ? " --include-submitted" : ""}${path33 ? ` --path ${path33}` : ""}`;
16187
16515
  logErrorConsole("Deprecated: `packmind-cli diff` will be removed");
16188
16516
  logInfoConsole("Use the following command instead:");
16189
16517
  logInfoConsole(` ${formatCommand(diffCommand3)}`);
@@ -16193,7 +16521,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
16193
16521
  getCwd: () => process.cwd(),
16194
16522
  log: console.log,
16195
16523
  includeSubmitted,
16196
- path: path34
16524
+ path: path33
16197
16525
  });
16198
16526
  }
16199
16527
  });
@@ -16317,7 +16645,7 @@ var createPackageCommand = (0, import_cmd_ts20.command)({
16317
16645
  space: (0, import_cmd_ts20.option)({
16318
16646
  long: "space",
16319
16647
  description: "Slug of the space in which to create the package",
16320
- type: (0, import_cmd_ts20.optional)(import_cmd_ts20.string)
16648
+ type: (0, import_cmd_ts20.optional)(SpaceSlug)
16321
16649
  }),
16322
16650
  originSkill: originSkillOption
16323
16651
  },
@@ -16375,11 +16703,11 @@ var import_cmd_ts21 = __toESM(require_cjs());
16375
16703
 
16376
16704
  // apps/cli/src/domain/errors/ItemNotFoundError.ts
16377
16705
  var ItemNotFoundError = class extends Error {
16378
- constructor(itemType, slug, spaceSlug) {
16379
- const message = spaceSlug ? `${itemType} '${slug}' not found in space '@${spaceSlug}'` : `${itemType} '${slug}' not found`;
16706
+ constructor(itemType, slug2, spaceSlug) {
16707
+ const message = spaceSlug ? `${itemType} '${slug2}' not found in space '@${spaceSlug}'` : `${itemType} '${slug2}' not found`;
16380
16708
  super(message);
16381
16709
  this.itemType = itemType;
16382
- this.slug = slug;
16710
+ this.slug = slug2;
16383
16711
  this.spaceSlug = spaceSlug;
16384
16712
  this.name = "ItemNotFoundError";
16385
16713
  }
@@ -16442,34 +16770,34 @@ var AddToPackageUseCase = class {
16442
16770
  async resolveSlugsToIds(itemType, slugs, spaceId, spaceSlug) {
16443
16771
  const ids = [];
16444
16772
  const idToSlugMap = /* @__PURE__ */ new Map();
16445
- for (const slug of slugs) {
16773
+ for (const slug2 of slugs) {
16446
16774
  let item = null;
16447
16775
  if (itemType === "standard") {
16448
- item = await this.findStandardBySlug(slug, spaceId);
16776
+ item = await this.findStandardBySlug(slug2, spaceId);
16449
16777
  } else if (itemType === "command") {
16450
- item = await this.findCommandBySlug(slug, spaceId);
16778
+ item = await this.findCommandBySlug(slug2, spaceId);
16451
16779
  } else if (itemType === "skill") {
16452
- item = await this.findSkillBySlug(slug, spaceId);
16780
+ item = await this.findSkillBySlug(slug2, spaceId);
16453
16781
  }
16454
16782
  if (!item) {
16455
- throw new ItemNotFoundError(itemType, slug, spaceSlug);
16783
+ throw new ItemNotFoundError(itemType, slug2, spaceSlug);
16456
16784
  }
16457
16785
  ids.push(item.id);
16458
- idToSlugMap.set(item.id, slug);
16786
+ idToSlugMap.set(item.id, slug2);
16459
16787
  }
16460
16788
  return { ids, idToSlugMap };
16461
16789
  }
16462
- async findStandardBySlug(slug, spaceId) {
16790
+ async findStandardBySlug(slug2, spaceId) {
16463
16791
  const standards = await this.gateway.standards.list({ spaceId });
16464
- return standards.standards.find((standard) => standard.slug === slug) ?? null;
16792
+ return standards.standards.find((standard) => standard.slug === slug2) ?? null;
16465
16793
  }
16466
- async findCommandBySlug(slug, spaceId) {
16794
+ async findCommandBySlug(slug2, spaceId) {
16467
16795
  const commands = await this.gateway.commands.list({ spaceId });
16468
- return commands.recipes.find((command30) => command30.slug === slug) ?? null;
16796
+ return commands.recipes.find((command30) => command30.slug === slug2) ?? null;
16469
16797
  }
16470
- async findSkillBySlug(slug, spaceId) {
16798
+ async findSkillBySlug(slug2, spaceId) {
16471
16799
  const skills = await this.gateway.skills.list({ spaceId });
16472
- return skills.find((skill) => skill.slug === slug) ?? null;
16800
+ return skills.find((skill) => skill.slug === slug2) ?? null;
16473
16801
  }
16474
16802
  };
16475
16803
 
@@ -16637,7 +16965,7 @@ var listPackagesCommand = (0, import_cmd_ts22.command)({
16637
16965
  description: "List available packages",
16638
16966
  args: {
16639
16967
  space: (0, import_cmd_ts22.option)({
16640
- type: (0, import_cmd_ts22.optional)(import_cmd_ts22.string),
16968
+ type: (0, import_cmd_ts22.optional)(SpaceSlug),
16641
16969
  long: "space",
16642
16970
  description: "Filter packages by space slug"
16643
16971
  })
@@ -16665,10 +16993,10 @@ var showPackageCommand = (0, import_cmd_ts23.command)({
16665
16993
  description: "Package slug (e.g. backend or @my-space/backend)"
16666
16994
  })
16667
16995
  },
16668
- handler: async ({ slug }) => {
16996
+ handler: async ({ slug: slug2 }) => {
16669
16997
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
16670
16998
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
16671
- await showPackageHandler({ slug }, { packmindCliHexa, exit: process.exit });
16999
+ await showPackageHandler({ slug: slug2 }, { packmindCliHexa, exit: process.exit });
16672
17000
  }
16673
17001
  });
16674
17002
 
@@ -16688,16 +17016,17 @@ var packagesCommand = (0, import_cmd_ts24.subcommands)({
16688
17016
  var import_cmd_ts31 = __toESM(require_cjs());
16689
17017
 
16690
17018
  // apps/cli/src/infra/commands/playbook/AddCommand.ts
16691
- var import_fs20 = require("fs");
17019
+ var import_fs21 = require("fs");
16692
17020
  var import_cmd_ts25 = __toESM(require_cjs());
16693
17021
 
16694
17022
  // apps/cli/src/infra/commands/playbook/addHandler.ts
16695
17023
  var fs24 = __toESM(require("fs"));
16696
17024
  var path25 = __toESM(require("path"));
16697
17025
  var yaml2 = __toESM(require("yaml"));
17026
+ var import_slug = __toESM(require("slug"));
16698
17027
 
16699
17028
  // apps/cli/src/application/utils/parseCommandFile.ts
16700
- var path21 = __toESM(require("path"));
17029
+ var path22 = __toESM(require("path"));
16701
17030
  var FRONTMATTER_DELIMITER3 = "---";
16702
17031
  function parseCommandFile(content, filePath) {
16703
17032
  content = normalizeLineEndings(content);
@@ -16720,6 +17049,9 @@ ${FRONTMATTER_DELIMITER3}`
16720
17049
  const frontmatter = contentAfterOpening.slice(0, closingIndex);
16721
17050
  const name2 = resolveName(frontmatter, filePath);
16722
17051
  const body = contentAfterOpening.slice(closingIndex + FRONTMATTER_DELIMITER3.length + 1).replace(/^\n+/, "");
17052
+ if (!body || body.trim().length === 0) {
17053
+ return { success: false, error: "Command body is empty" };
17054
+ }
16723
17055
  return { success: true, parsed: { name: name2, content: body } };
16724
17056
  }
16725
17057
  const name = humanizeSlug(extractFilenameSlug(filePath));
@@ -16750,7 +17082,7 @@ function stripYamlQuotes2(value) {
16750
17082
  return value;
16751
17083
  }
16752
17084
  function extractFilenameSlug(filePath) {
16753
- let basename2 = path21.basename(filePath);
17085
+ let basename2 = path22.basename(filePath);
16754
17086
  if (basename2.endsWith(".prompt.md")) {
16755
17087
  basename2 = basename2.slice(0, -".prompt.md".length);
16756
17088
  } else if (basename2.endsWith(".md")) {
@@ -16758,37 +17090,84 @@ function extractFilenameSlug(filePath) {
16758
17090
  }
16759
17091
  return basename2;
16760
17092
  }
16761
- function humanizeSlug(slug) {
16762
- const words = slug.replace(/[-_]/g, " ");
17093
+ function humanizeSlug(slug2) {
17094
+ const words = slug2.replace(/[-_]/g, " ");
16763
17095
  return words.charAt(0).toUpperCase() + words.slice(1);
16764
17096
  }
16765
17097
 
16766
17098
  // apps/cli/src/application/utils/parseLenientStandard.ts
16767
- var import_path4 = __toESM(require("path"));
16768
- function parseLenientStandard(content, filePath) {
17099
+ function parseLenientStandard(content) {
16769
17100
  content = normalizeLineEndings(content);
16770
17101
  if (!content.trim()) {
16771
17102
  return null;
16772
17103
  }
16773
- const lines = content.split("\n");
16774
- let headingIndex = -1;
17104
+ let lines = content.split("\n");
17105
+ if (lines[0]?.trim() === "---") {
17106
+ const closingIdx = lines.findIndex(
17107
+ (line, i) => i > 0 && line.trim() === "---"
17108
+ );
17109
+ if (closingIdx !== -1) {
17110
+ lines = lines.slice(closingIdx + 1);
17111
+ }
17112
+ }
17113
+ let headingIdx = -1;
17114
+ let name = "";
16775
17115
  for (let i = 0; i < lines.length; i++) {
16776
- if (lines[i].trim() === "") continue;
16777
- if (lines[i].startsWith("# ")) {
16778
- const name = lines[i].slice(2).trim();
16779
- if (name) {
16780
- headingIndex = i;
16781
- const description = lines.slice(headingIndex + 1).join("\n").trim();
16782
- return { name, description };
17116
+ const line = lines[i];
17117
+ if (line.startsWith("# Standard: ")) {
17118
+ const text = line.slice("# Standard: ".length).trim();
17119
+ if (text) {
17120
+ name = text;
17121
+ headingIdx = i;
17122
+ break;
17123
+ }
17124
+ } else if (line.startsWith("# ")) {
17125
+ const text = line.slice(2).trim();
17126
+ if (text) {
17127
+ name = text;
17128
+ headingIdx = i;
17129
+ break;
16783
17130
  }
16784
17131
  }
16785
- break;
16786
17132
  }
16787
- const stem = import_path4.default.basename(filePath, import_path4.default.extname(filePath));
16788
- return {
16789
- name: stem,
16790
- description: content.trim()
16791
- };
17133
+ if (headingIdx === -1) {
17134
+ return null;
17135
+ }
17136
+ const bodyLines = [];
17137
+ for (let i = headingIdx + 1; i < lines.length; i++) {
17138
+ const line = lines[i];
17139
+ if (line.startsWith("#")) continue;
17140
+ bodyLines.push({
17141
+ line,
17142
+ isBullet: line.startsWith("* ") || line.startsWith("- ")
17143
+ });
17144
+ }
17145
+ const listGroups = [];
17146
+ let currentGroup = null;
17147
+ for (let i = 0; i < bodyLines.length; i++) {
17148
+ if (bodyLines[i].isBullet) {
17149
+ if (!currentGroup) {
17150
+ currentGroup = { startIdx: i, endIdx: i, items: [] };
17151
+ listGroups.push(currentGroup);
17152
+ }
17153
+ currentGroup.endIdx = i;
17154
+ currentGroup.items.push(bodyLines[i].line.slice(2).trim());
17155
+ } else {
17156
+ currentGroup = null;
17157
+ }
17158
+ }
17159
+ const joinAndClean = (bLines) => bLines.map((b) => b.line).join("\n").trim().replace(/\s*:\s*$/, "");
17160
+ if (listGroups.length === 0) {
17161
+ return { name, description: joinAndClean(bodyLines), rules: [] };
17162
+ }
17163
+ const lastGroup = listGroups[listGroups.length - 1];
17164
+ const hasTextAfterLastList = bodyLines.slice(lastGroup.endIdx + 1).some((b) => !b.isBullet && b.line.trim() !== "");
17165
+ if (hasTextAfterLastList) {
17166
+ return { name, description: joinAndClean(bodyLines), rules: [] };
17167
+ }
17168
+ const rules = lastGroup.items;
17169
+ const description = joinAndClean(bodyLines.slice(0, lastGroup.startIdx));
17170
+ return { name, description, rules };
16792
17171
  }
16793
17172
 
16794
17173
  // apps/cli/src/application/utils/parseSkillDirectory.ts
@@ -17086,6 +17465,15 @@ async function playbookAddHandler(deps) {
17086
17465
  artifactType = artefactResult.artifactType;
17087
17466
  codingAgent = artefactResult.codingAgent;
17088
17467
  }
17468
+ const formatValidation = validateArtifactFileFormat(
17469
+ absolutePath,
17470
+ artifactType
17471
+ );
17472
+ if (!formatValidation.valid) {
17473
+ logErrorConsole(formatValidation.reason);
17474
+ exit(1);
17475
+ return;
17476
+ }
17089
17477
  let localContent;
17090
17478
  let artifactName;
17091
17479
  let serializedContent;
@@ -17152,9 +17540,15 @@ async function playbookAddHandler(deps) {
17152
17540
  if (parsed) {
17153
17541
  artifactName = parsed.name;
17154
17542
  } else {
17155
- const lenient = parseLenientStandard(localContent, absolutePath);
17543
+ const lenient = parseLenientStandard(localContent);
17156
17544
  if (!lenient) {
17157
- logErrorConsole("File is empty.");
17545
+ logErrorConsole(
17546
+ `${filePath} is not a valid artifact. Expected format:
17547
+
17548
+ # My standard name
17549
+
17550
+ Content goes here...`
17551
+ );
17158
17552
  exit(1);
17159
17553
  return;
17160
17554
  }
@@ -17186,11 +17580,10 @@ async function playbookAddHandler(deps) {
17186
17580
  let spaceName;
17187
17581
  const allSpaces = await packmindCliHexa.getSpaces();
17188
17582
  if (spaceSlug) {
17189
- const normalizedSlug = spaceSlug.startsWith("@") ? spaceSlug.slice(1) : spaceSlug;
17190
- const matchedSpace = allSpaces.find((s) => s.slug === normalizedSlug);
17583
+ const matchedSpace = allSpaces.find((s) => s.slug === spaceSlug);
17191
17584
  if (!matchedSpace) {
17192
17585
  logErrorConsole(
17193
- `Space "${spaceSlug}" not found. Available spaces:
17586
+ `Space "@${spaceSlug}" not found. Available spaces:
17194
17587
  ${formatSpaceList(allSpaces)}`
17195
17588
  );
17196
17589
  exit(1);
@@ -17202,10 +17595,9 @@ ${formatSpaceList(allSpaces)}`
17202
17595
  spaceId = allSpaces[0].id;
17203
17596
  spaceName = allSpaces[0].name;
17204
17597
  } else {
17205
- const isExistingArtifact = earlyLockFile && findLockFileEntryForPath(normalizedFilePath, earlyLockFile.artifacts);
17206
- const deployedSpaceId = deployedContext?.spaceId;
17207
- if (isExistingArtifact && deployedSpaceId) {
17208
- spaceId = deployedSpaceId;
17598
+ const existingLockEntry = earlyLockFile && findLockFileEntryForPath(normalizedFilePath, earlyLockFile.artifacts);
17599
+ if (existingLockEntry) {
17600
+ spaceId = existingLockEntry.spaceId;
17209
17601
  spaceName = allSpaces.find((s) => s.id === spaceId)?.name;
17210
17602
  } else {
17211
17603
  logErrorConsole(
@@ -17228,6 +17620,32 @@ Example: packmind-cli playbook add --space ${allSpaces[0].slug} <path>`
17228
17620
  changeType = "updated";
17229
17621
  }
17230
17622
  }
17623
+ if (changeType === "created") {
17624
+ try {
17625
+ const existingNames = await listExistingArtifactNames(
17626
+ packmindCliHexa,
17627
+ artifactType,
17628
+ spaceId
17629
+ );
17630
+ const nameExists = existingNames.some(
17631
+ (name) => (0, import_slug.default)(name) === (0, import_slug.default)(artifactName)
17632
+ );
17633
+ if (nameExists) {
17634
+ logErrorConsole(
17635
+ `A ${artifactType} named "${artifactName}" already exists in Packmind.`
17636
+ );
17637
+ exit(1);
17638
+ return;
17639
+ }
17640
+ } catch (err) {
17641
+ const errorMessage = err instanceof Error ? err.message : String(err);
17642
+ logErrorConsole(
17643
+ `Failed to check for existing ${artifactType}s: ${errorMessage}`
17644
+ );
17645
+ exit(1);
17646
+ return;
17647
+ }
17648
+ }
17231
17649
  if (changeType === "updated" && earlyLockFile) {
17232
17650
  const deployedFiles = await fetchDeployedFiles(
17233
17651
  packmindCliHexa.getPackmindGateway(),
@@ -17278,6 +17696,28 @@ Example: packmind-cli playbook add --space ${allSpaces[0].slug} <path>`
17278
17696
  );
17279
17697
  exit(0);
17280
17698
  }
17699
+ async function listExistingArtifactNames(packmindCliHexa, artifactType, spaceId) {
17700
+ switch (artifactType) {
17701
+ case "skill": {
17702
+ const skills = await packmindCliHexa.listSkills({
17703
+ spaceId
17704
+ });
17705
+ return skills.map((s) => s.name);
17706
+ }
17707
+ case "command": {
17708
+ const commands = await packmindCliHexa.listCommands({
17709
+ spaceId
17710
+ });
17711
+ return commands.map((c) => c.name);
17712
+ }
17713
+ case "standard": {
17714
+ const standards = await packmindCliHexa.listStandards({
17715
+ spaceId
17716
+ });
17717
+ return standards.map((s) => s.name);
17718
+ }
17719
+ }
17720
+ }
17281
17721
  function formatSpaceList(spaces) {
17282
17722
  const maxSlugLength = Math.max(...spaces.map((s) => s.slug.length));
17283
17723
  return spaces.map((s) => ` ${s.slug.padEnd(maxSlugLength)} (${s.name})`).join("\n");
@@ -17294,7 +17734,7 @@ var addPlaybookCommand = (0, import_cmd_ts25.command)({
17294
17734
  description: "Path to the artifact file or directory to stage"
17295
17735
  }),
17296
17736
  space: (0, import_cmd_ts25.option)({
17297
- type: (0, import_cmd_ts25.optional)(import_cmd_ts25.string),
17737
+ type: (0, import_cmd_ts25.optional)(SpaceSlug),
17298
17738
  long: "space",
17299
17739
  description: "Target space slug"
17300
17740
  })
@@ -17314,7 +17754,7 @@ var addPlaybookCommand = (0, import_cmd_ts25.command)({
17314
17754
  spaceSlug: space,
17315
17755
  exit: process.exit,
17316
17756
  cwd: process.cwd(),
17317
- readFile: (p) => (0, import_fs20.readFileSync)(p, "utf-8"),
17757
+ readFile: (p) => (0, import_fs21.readFileSync)(p, "utf-8"),
17318
17758
  readSkillDirectory,
17319
17759
  playbookLocalRepository,
17320
17760
  lockFileRepository
@@ -17521,13 +17961,10 @@ async function playbookUnstageHandler(deps) {
17521
17961
  return;
17522
17962
  }
17523
17963
  if (spaceSlug) {
17524
- const normalizedSlug = spaceSlug.startsWith("@") ? spaceSlug.slice(1) : spaceSlug;
17525
- const entry = matchingEntries.find(
17526
- (c) => c.spaceName === normalizedSlug || c.spaceId === normalizedSlug
17527
- );
17964
+ const entry = matchingEntries.find((c) => c.spaceName === spaceSlug);
17528
17965
  if (!entry) {
17529
17966
  logErrorConsole(
17530
- `No staged change found for ${normalizedFilePath} in space "${spaceSlug}"`
17967
+ `No staged change found for ${normalizedFilePath} in space "@${spaceSlug}"`
17531
17968
  );
17532
17969
  exit(1);
17533
17970
  return;
@@ -17569,7 +18006,7 @@ var unstagePlaybookCommand = (0, import_cmd_ts27.command)({
17569
18006
  description: "Path to the artifact file or directory to unstage"
17570
18007
  }),
17571
18008
  space: (0, import_cmd_ts27.option)({
17572
- type: (0, import_cmd_ts27.optional)(import_cmd_ts27.string),
18009
+ type: (0, import_cmd_ts27.optional)(SpaceSlug),
17573
18010
  long: "space",
17574
18011
  description: "Target space slug (required when artifact is staged for multiple spaces)"
17575
18012
  })
@@ -17594,15 +18031,15 @@ var unstagePlaybookCommand = (0, import_cmd_ts27.command)({
17594
18031
  });
17595
18032
 
17596
18033
  // apps/cli/src/infra/commands/playbook/StatusCommand.ts
17597
- var import_fs22 = require("fs");
18034
+ var import_fs23 = require("fs");
17598
18035
  var import_cmd_ts28 = __toESM(require_cjs());
17599
18036
 
17600
18037
  // apps/cli/src/infra/utils/listDirectoryFiles.ts
17601
- var import_fs21 = require("fs");
18038
+ var import_fs22 = require("fs");
17602
18039
  var path28 = __toESM(require("path"));
17603
18040
  function listDirectoryFiles(dirPath) {
17604
18041
  const results = [];
17605
- const entries = (0, import_fs21.readdirSync)(dirPath, { withFileTypes: true });
18042
+ const entries = (0, import_fs22.readdirSync)(dirPath, { withFileTypes: true });
17606
18043
  for (const entry of entries) {
17607
18044
  const fullPath = path28.join(dirPath, entry.name);
17608
18045
  if (entry.isDirectory()) {
@@ -17896,11 +18333,11 @@ var statusPlaybookCommand = (0, import_cmd_ts28.command)({
17896
18333
  lockFileRepository,
17897
18334
  cwd: process.cwd(),
17898
18335
  exit: process.exit,
17899
- readFile: (p) => (0, import_fs22.readFileSync)(p, "utf-8"),
18336
+ readFile: (p) => (0, import_fs23.readFileSync)(p, "utf-8"),
17900
18337
  listDirectoryFiles,
17901
18338
  getFileMode: (p) => {
17902
18339
  try {
17903
- return (0, import_fs22.statSync)(p).mode;
18340
+ return (0, import_fs23.statSync)(p).mode;
17904
18341
  } catch {
17905
18342
  return null;
17906
18343
  }
@@ -17910,8 +18347,8 @@ var statusPlaybookCommand = (0, import_cmd_ts28.command)({
17910
18347
  });
17911
18348
 
17912
18349
  // apps/cli/src/infra/commands/playbook/SubmitCommand.ts
17913
- var import_fs23 = require("fs");
17914
- var import_child_process4 = require("child_process");
18350
+ var import_fs24 = require("fs");
18351
+ var import_child_process5 = require("child_process");
17915
18352
  var import_os2 = require("os");
17916
18353
  var import_path5 = require("path");
17917
18354
  var import_cmd_ts29 = __toESM(require_cjs());
@@ -17919,6 +18356,204 @@ var import_cmd_ts29 = __toESM(require_cjs());
17919
18356
  // apps/cli/src/infra/commands/playbook/submitHandler.ts
17920
18357
  var path30 = __toESM(require("path"));
17921
18358
  var yaml3 = __toESM(require("yaml"));
18359
+
18360
+ // apps/cli/src/application/utils/artifactComparison.ts
18361
+ function compareStandardFields(localContent, deployedContent, filePath) {
18362
+ const localParsed = parseStandardMd(localContent, filePath);
18363
+ const serverParsed = parseStandardMd(deployedContent, filePath);
18364
+ if (!localParsed || !serverParsed) return [];
18365
+ const changes = [];
18366
+ if (serverParsed.frontmatterName && localParsed.frontmatterName && serverParsed.frontmatterName !== localParsed.frontmatterName) {
18367
+ changes.push({
18368
+ type: "updateStandardName" /* updateStandardName */,
18369
+ payload: {
18370
+ oldValue: serverParsed.frontmatterName,
18371
+ newValue: localParsed.frontmatterName
18372
+ }
18373
+ });
18374
+ }
18375
+ if (serverParsed.name !== localParsed.name) {
18376
+ changes.push({
18377
+ type: "updateStandardName" /* updateStandardName */,
18378
+ payload: {
18379
+ oldValue: serverParsed.name,
18380
+ newValue: localParsed.name
18381
+ }
18382
+ });
18383
+ }
18384
+ if (serverParsed.frontmatterDescription && localParsed.frontmatterDescription && serverParsed.frontmatterDescription !== localParsed.frontmatterDescription) {
18385
+ changes.push({
18386
+ type: "updateStandardDescription" /* updateStandardDescription */,
18387
+ payload: {
18388
+ oldValue: serverParsed.frontmatterDescription,
18389
+ newValue: localParsed.frontmatterDescription
18390
+ }
18391
+ });
18392
+ }
18393
+ if (serverParsed.description !== localParsed.description) {
18394
+ changes.push({
18395
+ type: "updateStandardDescription" /* updateStandardDescription */,
18396
+ payload: {
18397
+ oldValue: serverParsed.description,
18398
+ newValue: localParsed.description
18399
+ }
18400
+ });
18401
+ }
18402
+ if (serverParsed.scope !== localParsed.scope) {
18403
+ changes.push({
18404
+ type: "updateStandardScope" /* updateStandardScope */,
18405
+ payload: {
18406
+ oldValue: serverParsed.scope,
18407
+ newValue: localParsed.scope
18408
+ }
18409
+ });
18410
+ }
18411
+ const serverRules = new Set(serverParsed.rules);
18412
+ const localRules = new Set(localParsed.rules);
18413
+ const deletedRules = [...serverRules].filter((r) => !localRules.has(r));
18414
+ const addedRules = [...localRules].filter((r) => !serverRules.has(r));
18415
+ const { updates, remainingDeleted, remainingAdded } = matchUpdatedRules(
18416
+ deletedRules,
18417
+ addedRules
18418
+ );
18419
+ for (const update of updates) {
18420
+ const ruleId = createRuleId("unresolved");
18421
+ changes.push({
18422
+ type: "updateRule" /* updateRule */,
18423
+ payload: {
18424
+ targetId: ruleId,
18425
+ oldValue: update.oldValue,
18426
+ newValue: update.newValue
18427
+ }
18428
+ });
18429
+ }
18430
+ for (const rule of remainingDeleted) {
18431
+ const ruleId = createRuleId("unresolved");
18432
+ changes.push({
18433
+ type: "deleteRule" /* deleteRule */,
18434
+ payload: {
18435
+ targetId: ruleId,
18436
+ item: { id: ruleId, content: rule }
18437
+ }
18438
+ });
18439
+ }
18440
+ for (const rule of remainingAdded) {
18441
+ changes.push({
18442
+ type: "addRule" /* addRule */,
18443
+ payload: {
18444
+ item: { content: rule }
18445
+ }
18446
+ });
18447
+ }
18448
+ return changes;
18449
+ }
18450
+ function compareCommandFields(localContent, deployedContent, filePath) {
18451
+ const localParsed = parseCommandFile(localContent, filePath);
18452
+ if (!localParsed.success) return [];
18453
+ const serverParsed = parseCommandFile(deployedContent, filePath);
18454
+ if (!serverParsed.success) return [];
18455
+ const changes = [];
18456
+ if (serverParsed.parsed.name !== localParsed.parsed.name) {
18457
+ changes.push({
18458
+ type: "updateCommandName" /* updateCommandName */,
18459
+ payload: {
18460
+ oldValue: serverParsed.parsed.name,
18461
+ newValue: localParsed.parsed.name
18462
+ }
18463
+ });
18464
+ }
18465
+ if (serverParsed.parsed.content !== localParsed.parsed.content) {
18466
+ changes.push({
18467
+ type: "updateCommandDescription" /* updateCommandDescription */,
18468
+ payload: {
18469
+ oldValue: serverParsed.parsed.content,
18470
+ newValue: localParsed.parsed.content
18471
+ }
18472
+ });
18473
+ }
18474
+ return changes;
18475
+ }
18476
+ function compareSkillDefinitionFields(local, deployed) {
18477
+ const changes = [];
18478
+ if (local.name !== deployed.name) {
18479
+ changes.push({
18480
+ type: "updateSkillName" /* updateSkillName */,
18481
+ payload: { oldValue: deployed.name, newValue: local.name }
18482
+ });
18483
+ }
18484
+ if (local.description !== deployed.description) {
18485
+ changes.push({
18486
+ type: "updateSkillDescription" /* updateSkillDescription */,
18487
+ payload: { oldValue: deployed.description, newValue: local.description }
18488
+ });
18489
+ }
18490
+ if (local.prompt !== deployed.body) {
18491
+ changes.push({
18492
+ type: "updateSkillPrompt" /* updateSkillPrompt */,
18493
+ payload: { oldValue: deployed.body, newValue: local.prompt }
18494
+ });
18495
+ }
18496
+ const localLicense = local.license ?? "";
18497
+ if (localLicense !== deployed.license) {
18498
+ changes.push({
18499
+ type: "updateSkillLicense" /* updateSkillLicense */,
18500
+ payload: { oldValue: deployed.license, newValue: localLicense }
18501
+ });
18502
+ }
18503
+ const localCompatibility = local.compatibility ?? "";
18504
+ if (localCompatibility !== deployed.compatibility) {
18505
+ changes.push({
18506
+ type: "updateSkillCompatibility" /* updateSkillCompatibility */,
18507
+ payload: {
18508
+ oldValue: deployed.compatibility,
18509
+ newValue: localCompatibility
18510
+ }
18511
+ });
18512
+ }
18513
+ const localAllowedTools = local.allowedTools ?? "";
18514
+ if (localAllowedTools !== deployed.allowedTools) {
18515
+ changes.push({
18516
+ type: "updateSkillAllowedTools" /* updateSkillAllowedTools */,
18517
+ payload: {
18518
+ oldValue: deployed.allowedTools,
18519
+ newValue: localAllowedTools
18520
+ }
18521
+ });
18522
+ }
18523
+ const localMetadataJson = local.metadata && Object.keys(local.metadata).length > 0 ? serializeSkillMetadata(local.metadata) : "{}";
18524
+ if (localMetadataJson !== deployed.metadataJson) {
18525
+ changes.push({
18526
+ type: "updateSkillMetadata" /* updateSkillMetadata */,
18527
+ payload: {
18528
+ oldValue: deployed.metadataJson,
18529
+ newValue: localMetadataJson
18530
+ }
18531
+ });
18532
+ }
18533
+ const localAdditionalProps = local.additionalProperties ?? {};
18534
+ const deployedAdditionalProps = deployed.additionalProperties;
18535
+ const allKeys = /* @__PURE__ */ new Set([
18536
+ ...Object.keys(localAdditionalProps),
18537
+ ...Object.keys(deployedAdditionalProps)
18538
+ ]);
18539
+ for (const key of allKeys) {
18540
+ const localValue = key in localAdditionalProps ? canonicalJsonStringify(localAdditionalProps[key]) : "";
18541
+ const deployedValue = deployedAdditionalProps[key] ?? "null";
18542
+ if (localValue !== deployedValue) {
18543
+ changes.push({
18544
+ type: "updateSkillAdditionalProperty" /* updateSkillAdditionalProperty */,
18545
+ payload: {
18546
+ targetId: key,
18547
+ oldValue: deployedValue,
18548
+ newValue: localValue
18549
+ }
18550
+ });
18551
+ }
18552
+ }
18553
+ return changes;
18554
+ }
18555
+
18556
+ // apps/cli/src/infra/commands/playbook/submitHandler.ts
17922
18557
  function buildEditorPrefill(changes) {
17923
18558
  const lines = [
17924
18559
  "",
@@ -17963,7 +18598,7 @@ function buildCreatedStandardProposals(entry) {
17963
18598
  }
17964
18599
  ];
17965
18600
  }
17966
- const lenient = parseLenientStandard(entry.content, entry.filePath);
18601
+ const lenient = parseLenientStandard(entry.content);
17967
18602
  if (lenient) {
17968
18603
  return [
17969
18604
  {
@@ -17973,7 +18608,7 @@ function buildCreatedStandardProposals(entry) {
17973
18608
  name: lenient.name,
17974
18609
  description: lenient.description,
17975
18610
  scope: "",
17976
- rules: []
18611
+ rules: lenient.rules.map((r) => ({ content: r }))
17977
18612
  },
17978
18613
  targetId: entry.targetId,
17979
18614
  spaceId: entry.spaceId
@@ -18022,143 +18657,53 @@ function buildCreatedSkillProposals(entry) {
18022
18657
  }
18023
18658
  function buildUpdatedStandardProposals(entry, artifactId, deployedContent) {
18024
18659
  if (!artifactId) return [];
18025
- const localParsed = parseStandardMd(entry.content, entry.filePath);
18026
- if (!localParsed) return [];
18027
- const serverParsed = deployedContent ? parseStandardMd(deployedContent, entry.filePath) : null;
18028
- const proposals = [];
18029
18660
  const base = {
18030
18661
  artefactId: artifactId,
18031
18662
  targetId: entry.targetId,
18032
18663
  spaceId: entry.spaceId
18033
18664
  };
18034
- if (serverParsed) {
18035
- if (serverParsed.frontmatterName && localParsed.frontmatterName && serverParsed.frontmatterName !== localParsed.frontmatterName) {
18036
- proposals.push({
18037
- ...base,
18038
- type: "updateStandardName" /* updateStandardName */,
18039
- payload: {
18040
- oldValue: serverParsed.frontmatterName,
18041
- newValue: localParsed.frontmatterName
18042
- }
18043
- });
18044
- }
18045
- if (serverParsed.name !== localParsed.name) {
18046
- proposals.push({
18047
- ...base,
18048
- type: "updateStandardName" /* updateStandardName */,
18049
- payload: {
18050
- oldValue: serverParsed.name,
18051
- newValue: localParsed.name
18052
- }
18053
- });
18054
- }
18055
- if (serverParsed.frontmatterDescription && localParsed.frontmatterDescription && serverParsed.frontmatterDescription !== localParsed.frontmatterDescription) {
18056
- proposals.push({
18057
- ...base,
18058
- type: "updateStandardDescription" /* updateStandardDescription */,
18059
- payload: {
18060
- oldValue: serverParsed.frontmatterDescription,
18061
- newValue: localParsed.frontmatterDescription
18062
- }
18063
- });
18064
- }
18065
- if (serverParsed.description !== localParsed.description) {
18066
- proposals.push({
18067
- ...base,
18068
- type: "updateStandardDescription" /* updateStandardDescription */,
18069
- payload: {
18070
- oldValue: serverParsed.description,
18071
- newValue: localParsed.description
18072
- }
18073
- });
18074
- }
18075
- if (serverParsed.scope !== localParsed.scope) {
18076
- proposals.push({
18077
- ...base,
18078
- type: "updateStandardScope" /* updateStandardScope */,
18079
- payload: {
18080
- oldValue: serverParsed.scope,
18081
- newValue: localParsed.scope
18082
- }
18083
- });
18084
- }
18085
- }
18086
- const serverRules = new Set(serverParsed?.rules ?? []);
18087
- const localRules = new Set(localParsed.rules);
18088
- const deletedRules = [...serverRules].filter((r) => !localRules.has(r));
18089
- const addedRules = [...localRules].filter((r) => !serverRules.has(r));
18090
- const { updates, remainingDeleted, remainingAdded } = matchUpdatedRules(
18091
- deletedRules,
18092
- addedRules
18093
- );
18094
- for (const update of updates) {
18095
- const ruleId = createRuleId("unresolved");
18096
- proposals.push({
18097
- ...base,
18098
- type: "updateRule" /* updateRule */,
18099
- payload: {
18100
- targetId: ruleId,
18101
- oldValue: update.oldValue,
18102
- newValue: update.newValue
18103
- }
18104
- });
18105
- }
18106
- for (const rule of remainingDeleted) {
18107
- const ruleId = createRuleId("unresolved");
18108
- proposals.push({
18665
+ if (deployedContent) {
18666
+ const fieldChanges = compareStandardFields(
18667
+ entry.content,
18668
+ deployedContent,
18669
+ entry.filePath
18670
+ );
18671
+ return fieldChanges.map((change) => ({
18109
18672
  ...base,
18110
- type: "deleteRule" /* deleteRule */,
18111
- payload: {
18112
- targetId: ruleId,
18113
- item: { id: ruleId, content: rule }
18114
- }
18115
- });
18673
+ type: change.type,
18674
+ payload: change.payload
18675
+ }));
18116
18676
  }
18117
- for (const rule of remainingAdded) {
18677
+ const localParsed = parseStandardMd(entry.content, entry.filePath);
18678
+ if (!localParsed) return [];
18679
+ const proposals = [];
18680
+ const localRules = new Set(localParsed.rules);
18681
+ for (const rule of localRules) {
18118
18682
  proposals.push({
18119
18683
  ...base,
18120
18684
  type: "addRule" /* addRule */,
18121
- payload: {
18122
- item: { content: rule }
18123
- }
18685
+ payload: { item: { content: rule } }
18124
18686
  });
18125
18687
  }
18126
18688
  return proposals;
18127
18689
  }
18128
18690
  function buildUpdatedCommandProposals(entry, artifactId, deployedContent) {
18129
- if (!artifactId) return [];
18130
- const localParsed = parseCommandFile(entry.content, entry.filePath);
18131
- if (!localParsed.success) return [];
18132
- const serverParsed = deployedContent ? parseCommandFile(deployedContent, entry.filePath) : null;
18133
- const proposals = [];
18691
+ if (!artifactId || !deployedContent) return [];
18692
+ const fieldChanges = compareCommandFields(
18693
+ entry.content,
18694
+ deployedContent,
18695
+ entry.filePath
18696
+ );
18134
18697
  const base = {
18135
18698
  artefactId: artifactId,
18136
18699
  targetId: entry.targetId,
18137
18700
  spaceId: entry.spaceId
18138
18701
  };
18139
- if (serverParsed?.success) {
18140
- if (serverParsed.parsed.name !== localParsed.parsed.name) {
18141
- proposals.push({
18142
- ...base,
18143
- type: "updateCommandName" /* updateCommandName */,
18144
- payload: {
18145
- oldValue: serverParsed.parsed.name,
18146
- newValue: localParsed.parsed.name
18147
- }
18148
- });
18149
- }
18150
- if (serverParsed.parsed.content !== localParsed.parsed.content) {
18151
- proposals.push({
18152
- ...base,
18153
- type: "updateCommandDescription" /* updateCommandDescription */,
18154
- payload: {
18155
- oldValue: serverParsed.parsed.content,
18156
- newValue: localParsed.parsed.content
18157
- }
18158
- });
18159
- }
18160
- }
18161
- return proposals;
18702
+ return fieldChanges.map((change) => ({
18703
+ ...base,
18704
+ type: change.type,
18705
+ payload: change.payload
18706
+ }));
18162
18707
  }
18163
18708
  function buildUpdatedSkillProposals(entry, artifactId, deployedFiles) {
18164
18709
  if (!artifactId) return [];
@@ -18185,7 +18730,14 @@ function buildUpdatedSkillProposals(entry, artifactId, deployedFiles) {
18185
18730
  if (skillMdFile?.content) {
18186
18731
  const deployed = parseSkillMd(skillMdFile.content);
18187
18732
  if (deployed) {
18188
- proposals.push(...diffSkillDefinition(local, deployed, base));
18733
+ const fieldChanges = compareSkillDefinitionFields(local, deployed);
18734
+ proposals.push(
18735
+ ...fieldChanges.map((change) => ({
18736
+ ...base,
18737
+ type: change.type,
18738
+ payload: change.payload
18739
+ }))
18740
+ );
18189
18741
  } else {
18190
18742
  proposals.push({
18191
18743
  ...base,
@@ -18237,123 +18789,36 @@ function buildUpdatedSkillProposals(entry, artifactId, deployedFiles) {
18237
18789
  });
18238
18790
  }
18239
18791
  const localPermissions = localFile?.permissions ?? "rw-r--r--";
18240
- const deployedPermissions = deployed.skillFilePermissions ?? "read";
18241
- if (localFile && localPermissions !== deployedPermissions) {
18242
- proposals.push({
18243
- ...base,
18244
- type: "updateSkillFilePermissions" /* updateSkillFilePermissions */,
18245
- payload: {
18246
- targetId: deployed.skillFileId,
18247
- oldValue: deployedPermissions,
18248
- newValue: localPermissions
18249
- }
18250
- });
18251
- }
18252
- }
18253
- const deployedRelativePaths = new Set(
18254
- deployedHelperFiles.map(
18255
- (f) => normalizePath2(f.path).slice(normalizedEntryPath.length + 1)
18256
- )
18257
- );
18258
- for (const localFile of localFiles) {
18259
- if (!deployedRelativePaths.has(localFile.path)) {
18260
- proposals.push({
18261
- ...base,
18262
- type: "addSkillFile" /* addSkillFile */,
18263
- payload: {
18264
- item: {
18265
- path: localFile.path,
18266
- content: localFile.content,
18267
- permissions: localFile.permissions ?? "rw-r--r--",
18268
- isBase64: localFile.isBase64 ?? false
18269
- }
18270
- }
18271
- });
18272
- }
18273
- }
18274
- return proposals;
18275
- }
18276
- function diffSkillDefinition(local, deployed, base) {
18277
- const proposals = [];
18278
- if (local.name !== deployed.name) {
18279
- proposals.push({
18280
- ...base,
18281
- type: "updateSkillName" /* updateSkillName */,
18282
- payload: { oldValue: deployed.name, newValue: local.name }
18283
- });
18284
- }
18285
- if (local.description !== deployed.description) {
18286
- proposals.push({
18287
- ...base,
18288
- type: "updateSkillDescription" /* updateSkillDescription */,
18289
- payload: { oldValue: deployed.description, newValue: local.description }
18290
- });
18291
- }
18292
- if (local.prompt !== deployed.body) {
18293
- proposals.push({
18294
- ...base,
18295
- type: "updateSkillPrompt" /* updateSkillPrompt */,
18296
- payload: { oldValue: deployed.body, newValue: local.prompt }
18297
- });
18298
- }
18299
- const localLicense = local.license ?? "";
18300
- if (localLicense !== deployed.license) {
18301
- proposals.push({
18302
- ...base,
18303
- type: "updateSkillLicense" /* updateSkillLicense */,
18304
- payload: { oldValue: deployed.license, newValue: localLicense }
18305
- });
18306
- }
18307
- const localCompatibility = local.compatibility ?? "";
18308
- if (localCompatibility !== deployed.compatibility) {
18309
- proposals.push({
18310
- ...base,
18311
- type: "updateSkillCompatibility" /* updateSkillCompatibility */,
18312
- payload: {
18313
- oldValue: deployed.compatibility,
18314
- newValue: localCompatibility
18315
- }
18316
- });
18317
- }
18318
- const localAllowedTools = local.allowedTools ?? "";
18319
- if (localAllowedTools !== deployed.allowedTools) {
18320
- proposals.push({
18321
- ...base,
18322
- type: "updateSkillAllowedTools" /* updateSkillAllowedTools */,
18323
- payload: {
18324
- oldValue: deployed.allowedTools,
18325
- newValue: localAllowedTools
18326
- }
18327
- });
18328
- }
18329
- const localMetadataJson = local.metadata && Object.keys(local.metadata).length > 0 ? serializeSkillMetadata(local.metadata) : "{}";
18330
- if (localMetadataJson !== deployed.metadataJson) {
18331
- proposals.push({
18332
- ...base,
18333
- type: "updateSkillMetadata" /* updateSkillMetadata */,
18334
- payload: {
18335
- oldValue: deployed.metadataJson,
18336
- newValue: localMetadataJson
18337
- }
18338
- });
18792
+ const deployedPermissions = deployed.skillFilePermissions ?? "read";
18793
+ if (localFile && localPermissions !== deployedPermissions) {
18794
+ proposals.push({
18795
+ ...base,
18796
+ type: "updateSkillFilePermissions" /* updateSkillFilePermissions */,
18797
+ payload: {
18798
+ targetId: deployed.skillFileId,
18799
+ oldValue: deployedPermissions,
18800
+ newValue: localPermissions
18801
+ }
18802
+ });
18803
+ }
18339
18804
  }
18340
- const localAdditionalProps = local.additionalProperties ?? {};
18341
- const deployedAdditionalProps = deployed.additionalProperties;
18342
- const allKeys = /* @__PURE__ */ new Set([
18343
- ...Object.keys(localAdditionalProps),
18344
- ...Object.keys(deployedAdditionalProps)
18345
- ]);
18346
- for (const key of allKeys) {
18347
- const localValue = key in localAdditionalProps ? canonicalJsonStringify(localAdditionalProps[key]) : "";
18348
- const deployedValue = deployedAdditionalProps[key] ?? "null";
18349
- if (localValue !== deployedValue) {
18805
+ const deployedRelativePaths = new Set(
18806
+ deployedHelperFiles.map(
18807
+ (f) => normalizePath2(f.path).slice(normalizedEntryPath.length + 1)
18808
+ )
18809
+ );
18810
+ for (const localFile of localFiles) {
18811
+ if (!deployedRelativePaths.has(localFile.path)) {
18350
18812
  proposals.push({
18351
18813
  ...base,
18352
- type: "updateSkillAdditionalProperty" /* updateSkillAdditionalProperty */,
18814
+ type: "addSkillFile" /* addSkillFile */,
18353
18815
  payload: {
18354
- targetId: key,
18355
- oldValue: deployedValue,
18356
- newValue: localValue
18816
+ item: {
18817
+ path: localFile.path,
18818
+ content: localFile.content,
18819
+ permissions: localFile.permissions ?? "rw-r--r--",
18820
+ isBase64: localFile.isBase64 ?? false
18821
+ }
18357
18822
  }
18358
18823
  });
18359
18824
  }
@@ -18385,6 +18850,64 @@ function findDeployedContentForPath(filePath, deployedFiles) {
18385
18850
  const match = deployedFiles.find((f) => normalizePath2(f.path) === normalized);
18386
18851
  return match?.content ?? null;
18387
18852
  }
18853
+ async function checkForDuplicateNames(createdEntries, packmindGateway) {
18854
+ const errors = [];
18855
+ const groups = /* @__PURE__ */ new Map();
18856
+ for (const entry of createdEntries) {
18857
+ const key = `${entry.spaceId}:${entry.artifactType}`;
18858
+ const existing = groups.get(key) ?? [];
18859
+ existing.push(entry);
18860
+ groups.set(key, existing);
18861
+ }
18862
+ for (const [, entries] of groups) {
18863
+ const seen = /* @__PURE__ */ new Map();
18864
+ for (const entry of entries) {
18865
+ const lowerName = entry.artifactName.toLowerCase();
18866
+ if (seen.has(lowerName)) {
18867
+ errors.push(
18868
+ `A ${entry.artifactType} named "${entry.artifactName}" is staged multiple times. Remove the duplicate with "playbook unstage" or rename the artifact.`
18869
+ );
18870
+ } else {
18871
+ seen.set(lowerName, entry.artifactName);
18872
+ }
18873
+ }
18874
+ }
18875
+ for (const [key, entries] of groups) {
18876
+ const [rawSpaceId, artifactType] = key.split(":");
18877
+ const typedSpaceId = rawSpaceId;
18878
+ try {
18879
+ let existingNames = [];
18880
+ if (artifactType === "standard") {
18881
+ const response = await packmindGateway.standards.list({
18882
+ spaceId: typedSpaceId
18883
+ });
18884
+ existingNames = response.standards.map((s) => s.name);
18885
+ } else if (artifactType === "command") {
18886
+ const response = await packmindGateway.commands.list({
18887
+ spaceId: typedSpaceId
18888
+ });
18889
+ existingNames = response.recipes.map((r) => r.name);
18890
+ } else if (artifactType === "skill") {
18891
+ const response = await packmindGateway.skills.list({
18892
+ spaceId: typedSpaceId
18893
+ });
18894
+ existingNames = response.map((s) => s.name);
18895
+ }
18896
+ const existingNamesLower = new Set(
18897
+ existingNames.map((n) => n.toLowerCase())
18898
+ );
18899
+ for (const entry of entries) {
18900
+ if (existingNamesLower.has(entry.artifactName.toLowerCase())) {
18901
+ errors.push(
18902
+ `A ${entry.artifactType} named "${entry.artifactName}" already exists in this space. Use "playbook unstage" to remove it or rename the artifact.`
18903
+ );
18904
+ }
18905
+ }
18906
+ } catch {
18907
+ }
18908
+ }
18909
+ return errors;
18910
+ }
18388
18911
  async function playbookSubmitHandler(deps) {
18389
18912
  const {
18390
18913
  packmindCliHexa,
@@ -18420,6 +18943,20 @@ async function playbookSubmitHandler(deps) {
18420
18943
  }
18421
18944
  resolvedMessage = stripped;
18422
18945
  }
18946
+ const createdEntries = changes.filter((c) => c.changeType === "created");
18947
+ if (createdEntries.length > 0) {
18948
+ const duplicateErrors = await checkForDuplicateNames(
18949
+ createdEntries,
18950
+ packmindCliHexa.getPackmindGateway()
18951
+ );
18952
+ if (duplicateErrors.length > 0) {
18953
+ for (const error of duplicateErrors) {
18954
+ logErrorConsole(error);
18955
+ }
18956
+ exit(1);
18957
+ return;
18958
+ }
18959
+ }
18423
18960
  const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
18424
18961
  const targetContextCache = /* @__PURE__ */ new Map();
18425
18962
  async function getTargetContext(entry) {
@@ -18652,16 +19189,16 @@ function openEditorForMessage(prefill) {
18652
19189
  const editor = process.env.VISUAL || process.env.EDITOR || "vi";
18653
19190
  const tmpFile = (0, import_path5.join)((0, import_os2.tmpdir)(), `packmind-submit-${Date.now()}.md`);
18654
19191
  try {
18655
- (0, import_fs23.writeFileSync)(tmpFile, prefill, "utf-8");
18656
- (0, import_child_process4.execSync)(`${editor} "${tmpFile}"`, { stdio: "inherit" });
18657
- const content = (0, import_fs23.readFileSync)(tmpFile, "utf-8");
19192
+ (0, import_fs24.writeFileSync)(tmpFile, prefill, "utf-8");
19193
+ (0, import_child_process5.execSync)(`${editor} "${tmpFile}"`, { stdio: "inherit" });
19194
+ const content = (0, import_fs24.readFileSync)(tmpFile, "utf-8");
18658
19195
  const stripped = content.split("\n").filter((line) => !line.startsWith("#")).join("\n").trim();
18659
19196
  return stripped || null;
18660
19197
  } catch {
18661
19198
  return null;
18662
19199
  } finally {
18663
19200
  try {
18664
- (0, import_fs23.unlinkSync)(tmpFile);
19201
+ (0, import_fs24.unlinkSync)(tmpFile);
18665
19202
  } catch {
18666
19203
  }
18667
19204
  }
@@ -18694,8 +19231,8 @@ var submitPlaybookCommand = (0, import_cmd_ts29.command)({
18694
19231
  exit: process.exit,
18695
19232
  message,
18696
19233
  openEditor: (prefill) => openEditorForMessage(prefill),
18697
- unlinkSync: (p) => (0, import_fs23.unlinkSync)(p),
18698
- rmSync: (p, opts) => (0, import_fs23.rmSync)(p, opts)
19234
+ unlinkSync: (p) => (0, import_fs24.unlinkSync)(p),
19235
+ rmSync: (p, opts) => (0, import_fs24.rmSync)(p, opts)
18699
19236
  });
18700
19237
  }
18701
19238
  });
@@ -18717,7 +19254,7 @@ var diffCommand2 = (0, import_cmd_ts30.command)({
18717
19254
  type: (0, import_cmd_ts30.optional)(import_cmd_ts30.string)
18718
19255
  })
18719
19256
  },
18720
- handler: async ({ includeSubmitted, path: path34 }) => {
19257
+ handler: async ({ includeSubmitted, path: path33 }) => {
18721
19258
  const packmindLogger = new PackmindLogger("PackmindCLI", "info" /* INFO */);
18722
19259
  const packmindCliHexa = new PackmindCliHexa(packmindLogger);
18723
19260
  await diffArtefactsHandler({
@@ -18726,7 +19263,7 @@ var diffCommand2 = (0, import_cmd_ts30.command)({
18726
19263
  getCwd: () => process.cwd(),
18727
19264
  log: console.log,
18728
19265
  includeSubmitted,
18729
- path: path34
19266
+ path: path33
18730
19267
  });
18731
19268
  }
18732
19269
  });
@@ -19034,6 +19571,11 @@ async function initHandler(deps) {
19034
19571
  };
19035
19572
  }
19036
19573
  const totalFiles = result.filesCreated + result.filesUpdated;
19574
+ if (result.skippedSkillsCount > 0) {
19575
+ logWarningConsole(
19576
+ `${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.`
19577
+ );
19578
+ }
19037
19579
  if (totalFiles === 0) {
19038
19580
  logInfoConsole("Default skills are already up to date.");
19039
19581
  } else {
@@ -19057,7 +19599,7 @@ async function initHandler(deps) {
19057
19599
  }
19058
19600
 
19059
19601
  // apps/cli/src/infra/commands/InitCommand.ts
19060
- var { version: CLI_VERSION3 } = require_package();
19602
+ var { version: CLI_VERSION4 } = require_package();
19061
19603
  var initCommand = (0, import_cmd_ts36.command)({
19062
19604
  name: "init",
19063
19605
  description: "Initialize Packmind in the current project",
@@ -19074,7 +19616,7 @@ var initCommand = (0, import_cmd_ts36.command)({
19074
19616
  packmindGateway: packmindCliHexa.getPackmindGateway(),
19075
19617
  baseDirectory,
19076
19618
  installDefaultSkills: packmindCliHexa.installDefaultSkills.bind(packmindCliHexa),
19077
- cliVersion: CLI_VERSION3
19619
+ cliVersion: CLI_VERSION4
19078
19620
  });
19079
19621
  if (!result.success) {
19080
19622
  for (const error of result.errors) {
@@ -19087,201 +19629,7 @@ var initCommand = (0, import_cmd_ts36.command)({
19087
19629
 
19088
19630
  // apps/cli/src/infra/commands/UpdateCommand.ts
19089
19631
  var import_cmd_ts37 = __toESM(require_cjs());
19090
-
19091
- // apps/cli/src/infra/commands/updateHandler.ts
19092
- var import_path6 = __toESM(require("path"));
19093
- var import_child_process5 = require("child_process");
19094
- var import_fs24 = require("fs");
19095
- var import_promises2 = require("stream/promises");
19096
- var import_stream = require("stream");
19097
- var import_semver = __toESM(require("semver"));
19098
- var GITHUB_REPO = "PackmindHub/packmind";
19099
- var NPM_PACKAGE = "@packmind/cli";
19100
- function getPlatformAssetSuffix(platform, arch) {
19101
- const osMap = {
19102
- linux: "linux",
19103
- darwin: "macos",
19104
- win32: "windows"
19105
- };
19106
- const osName = osMap[platform];
19107
- if (!osName) {
19108
- throw new Error(`Unsupported platform: ${platform}`);
19109
- }
19110
- const archName = platform === "darwin" && arch === "x64" ? "x64-baseline" : arch;
19111
- const ext = platform === "win32" ? ".exe" : "";
19112
- return `${osName}-${archName}${ext}`;
19113
- }
19114
- async function fetchLatestVersionFromNpm(fetchFn) {
19115
- const res = await fetchFn(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`);
19116
- if (!res.ok) {
19117
- throw new Error(
19118
- `Failed to fetch from npm registry: ${res.status} ${res.statusText}`
19119
- );
19120
- }
19121
- const data = await res.json();
19122
- return data.version;
19123
- }
19124
- async function fetchLatestVersionFromGitHub(fetchFn) {
19125
- const res = await fetchFn(
19126
- `https://api.github.com/repos/${GITHUB_REPO}/releases?per_page=20`,
19127
- {
19128
- headers: { Accept: "application/vnd.github.v3+json" }
19129
- }
19130
- );
19131
- if (!res.ok) {
19132
- throw new Error(
19133
- `Failed to fetch from GitHub API: ${res.status} ${res.statusText}`
19134
- );
19135
- }
19136
- const releases = await res.json();
19137
- const cliReleases = releases.filter((r) => r.tag_name?.startsWith("release-cli/")).map((r) => ({
19138
- ...r,
19139
- version: r.tag_name.replace("release-cli/", "")
19140
- })).filter((r) => import_semver.default.valid(r.version)).sort((a, b) => import_semver.default.rcompare(a.version, b.version));
19141
- if (cliReleases.length === 0) {
19142
- throw new Error("No CLI release found on GitHub");
19143
- }
19144
- return cliReleases[0].version;
19145
- }
19146
- async function downloadExecutable(fetchFn, version2, platformSuffix, targetPath) {
19147
- const assetName = `packmind-cli-${platformSuffix}-${version2}`;
19148
- const url = `https://github.com/${GITHUB_REPO}/releases/download/release-cli/${version2}/${assetName}`;
19149
- logInfoConsole(`Downloading ${assetName}...`);
19150
- const res = await fetchFn(url, { redirect: "follow" });
19151
- if (!res.ok) {
19152
- throw new Error(
19153
- `Failed to download executable: ${res.status} ${res.statusText}
19154
- URL: ${url}`
19155
- );
19156
- }
19157
- if (!res.body) {
19158
- throw new Error("No response body received");
19159
- }
19160
- const nodeReadable = import_stream.Readable.fromWeb(res.body);
19161
- const fileStream = (0, import_fs24.createWriteStream)(targetPath);
19162
- await (0, import_promises2.pipeline)(nodeReadable, fileStream);
19163
- const stats = (0, import_fs24.statSync)(targetPath);
19164
- if (stats.size < 1e6) {
19165
- (0, import_fs24.unlinkSync)(targetPath);
19166
- throw new Error(
19167
- `Downloaded file is too small (${stats.size} bytes). The download may have failed.`
19168
- );
19169
- }
19170
- logInfoConsole(
19171
- `Downloaded successfully (${(stats.size / 1048576).toFixed(1)} MB)`
19172
- );
19173
- }
19174
- function updateViaNpm(version2) {
19175
- logInfoConsole(`Updating via npm to version ${version2}...`);
19176
- (0, import_child_process5.execSync)(`npm install -g ${NPM_PACKAGE}@${version2}`, {
19177
- stdio: "inherit"
19178
- });
19179
- }
19180
- async function updateViaExecutableReplace(deps, version2) {
19181
- const platformSuffix = getPlatformAssetSuffix(deps.platform, deps.arch);
19182
- const currentPath = deps.executablePath;
19183
- const tempPath = currentPath + ".update-tmp";
19184
- try {
19185
- await downloadExecutable(deps.fetchFn, version2, platformSuffix, tempPath);
19186
- (0, import_fs24.renameSync)(tempPath, currentPath);
19187
- if (deps.platform !== "win32") {
19188
- (0, import_fs24.chmodSync)(currentPath, 493);
19189
- }
19190
- } catch (error) {
19191
- try {
19192
- (0, import_fs24.unlinkSync)(tempPath);
19193
- } catch {
19194
- }
19195
- throw error;
19196
- }
19197
- }
19198
- function isLocalNpmPackage(scriptPath) {
19199
- if (!scriptPath) return false;
19200
- return scriptPath.includes(import_path6.default.join("node_modules", "@packmind", "cli"));
19201
- }
19202
- function isHomebrewInstall(executablePath) {
19203
- try {
19204
- const realPath = (0, import_fs24.realpathSync)(executablePath);
19205
- return realPath.includes("/Cellar/");
19206
- } catch {
19207
- return false;
19208
- }
19209
- }
19210
- async function updateHandler(deps) {
19211
- const execBasename = import_path6.default.basename(deps.executablePath).replace(/\.exe$/, "");
19212
- const jsRuntimes = ["node", "bun", "deno"];
19213
- if (jsRuntimes.includes(execBasename)) {
19214
- if (isLocalNpmPackage(deps.scriptPath)) {
19215
- logErrorConsole(
19216
- "Your CLI version is managed by your local package.json.\nTo update, run: npm update @packmind/cli"
19217
- );
19218
- } else {
19219
- logErrorConsole(
19220
- "The update command is not available when running the CLI via a JavaScript runtime.\nTo update, use the standalone executable or run: npm install -g @packmind/cli@latest"
19221
- );
19222
- }
19223
- process.exit(1);
19224
- return;
19225
- }
19226
- if (isHomebrewInstall(deps.executablePath)) {
19227
- logInfoConsole(
19228
- "This CLI was installed via Homebrew.\nTo update, run: brew upgrade packmind-cli"
19229
- );
19230
- process.exit(0);
19231
- return;
19232
- }
19233
- logInfoConsole(
19234
- `Current version: ${deps.currentVersion} (${deps.isExecutableMode ? "standalone executable" : "npm package"})`
19235
- );
19236
- let latestVersion;
19237
- try {
19238
- latestVersion = deps.isExecutableMode ? await fetchLatestVersionFromGitHub(deps.fetchFn) : await fetchLatestVersionFromNpm(deps.fetchFn);
19239
- } catch (error) {
19240
- logErrorConsole(
19241
- `Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`
19242
- );
19243
- process.exit(1);
19244
- return;
19245
- }
19246
- if (!import_semver.default.gt(latestVersion, deps.currentVersion)) {
19247
- logSuccessConsole(`Already up to date (v${deps.currentVersion})`);
19248
- return;
19249
- }
19250
- logConsole("");
19251
- logInfoConsole(
19252
- `New version available: ${deps.currentVersion} -> ${latestVersion}`
19253
- );
19254
- if (deps.checkOnly) {
19255
- process.exit(1);
19256
- return;
19257
- }
19258
- try {
19259
- if (deps.isExecutableMode) {
19260
- await updateViaExecutableReplace(deps, latestVersion);
19261
- } else {
19262
- updateViaNpm(latestVersion);
19263
- }
19264
- logConsole("");
19265
- logSuccessConsole(`Updated to v${latestVersion}`);
19266
- if (deps.isExecutableMode) {
19267
- logInfoConsole(`Binary location: ${deps.executablePath}`);
19268
- }
19269
- } catch (error) {
19270
- const message = error instanceof Error ? error.message : String(error);
19271
- if (message.includes("EACCES") || message.includes("permission denied")) {
19272
- logErrorConsole(
19273
- `Permission denied. Try running with sudo:
19274
- sudo packmind-cli update`
19275
- );
19276
- } else {
19277
- logErrorConsole(`Update failed: ${message}`);
19278
- }
19279
- process.exit(1);
19280
- }
19281
- }
19282
-
19283
- // apps/cli/src/infra/commands/UpdateCommand.ts
19284
- var { version: CLI_VERSION4 } = require_package();
19632
+ var { version: CLI_VERSION5 } = require_package();
19285
19633
  var updateCommand = (0, import_cmd_ts37.command)({
19286
19634
  name: "update",
19287
19635
  description: "Update packmind-cli to the latest version",
@@ -19293,7 +19641,7 @@ var updateCommand = (0, import_cmd_ts37.command)({
19293
19641
  },
19294
19642
  handler: async ({ check }) => {
19295
19643
  await updateHandler({
19296
- currentVersion: CLI_VERSION4,
19644
+ currentVersion: CLI_VERSION5,
19297
19645
  isExecutableMode: hasEmbeddedWasmFiles(),
19298
19646
  executablePath: process.execPath,
19299
19647
  scriptPath: require.main?.filename,
@@ -19306,17 +19654,17 @@ var updateCommand = (0, import_cmd_ts37.command)({
19306
19654
  });
19307
19655
 
19308
19656
  // apps/cli/src/main.ts
19309
- var { version: CLI_VERSION5 } = require_package();
19657
+ var { version: CLI_VERSION6 } = require_package();
19310
19658
  function findEnvFile() {
19311
19659
  const currentDir = process.cwd();
19312
19660
  const gitService = new GitService();
19313
19661
  const gitRoot = gitService.getGitRepositoryRootSync(currentDir);
19314
- const filesystemRoot = path33.parse(currentDir).root;
19662
+ const filesystemRoot = path32.parse(currentDir).root;
19315
19663
  const stopDir = gitRoot ?? filesystemRoot;
19316
19664
  let searchDir = currentDir;
19317
- let parentDir = path33.dirname(searchDir);
19665
+ let parentDir = path32.dirname(searchDir);
19318
19666
  while (searchDir !== parentDir) {
19319
- const envPath2 = path33.join(searchDir, ".env");
19667
+ const envPath2 = path32.join(searchDir, ".env");
19320
19668
  if (fs26.existsSync(envPath2)) {
19321
19669
  return envPath2;
19322
19670
  }
@@ -19324,7 +19672,7 @@ function findEnvFile() {
19324
19672
  return null;
19325
19673
  }
19326
19674
  searchDir = parentDir;
19327
- parentDir = path33.dirname(searchDir);
19675
+ parentDir = path32.dirname(searchDir);
19328
19676
  }
19329
19677
  return null;
19330
19678
  }
@@ -19341,7 +19689,7 @@ if (hasEmbeddedWasmFiles()) {
19341
19689
  }
19342
19690
  var args = process.argv.slice(2);
19343
19691
  if (args.includes("--version") || args.includes("-v")) {
19344
- logConsole(`packmind-cli version ${CLI_VERSION5}`);
19692
+ logConsole(`packmind-cli version ${CLI_VERSION6}`);
19345
19693
  process.exit(0);
19346
19694
  }
19347
19695
  var app = (0, import_cmd_ts38.subcommands)({