@packmind/cli 0.20.0 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/main.cjs +344 -43
  2. package/package.json +3 -3
package/main.cjs CHANGED
@@ -3852,7 +3852,7 @@ var require_package = __commonJS({
3852
3852
  "apps/cli/package.json"(exports2, module2) {
3853
3853
  module2.exports = {
3854
3854
  name: "@packmind/cli",
3855
- version: "0.20.0",
3855
+ version: "0.21.1",
3856
3856
  description: "A command-line interface for Packmind linting and code quality checks",
3857
3857
  private: false,
3858
3858
  bin: {
@@ -3887,6 +3887,7 @@ var require_package = __commonJS({
3887
3887
  },
3888
3888
  dependencies: {
3889
3889
  "@types/inquirer": "^9.0.9",
3890
+ diff: "^8.0.3",
3890
3891
  inquirer: "^13.0.2",
3891
3892
  zod: "^4.3.5",
3892
3893
  semver: "^6.3.1"
@@ -5034,9 +5035,9 @@ var CHANGE_PROPOSAL_TYPE_LABELS = {
5034
5035
  ["createStandard" /* createStandard */]: "New standard",
5035
5036
  ["createCommand" /* createCommand */]: "New command",
5036
5037
  ["createSkill" /* createSkill */]: "New skill",
5037
- ["removeStandard" /* removeStandard */]: "Remove standard",
5038
- ["removeCommand" /* removeCommand */]: "Remove command",
5039
- ["removeSkill" /* removeSkill */]: "Remove skill"
5038
+ ["removeStandard" /* removeStandard */]: "Removed",
5039
+ ["removeCommand" /* removeCommand */]: "Removed",
5040
+ ["removeSkill" /* removeSkill */]: "Removed"
5040
5041
  };
5041
5042
 
5042
5043
  // packages/types/src/playbookChangeManagement/events/ChangeProposalAcceptedEvent.ts
@@ -5060,6 +5061,39 @@ var ChangeProposalSubmittedEvent = class extends UserEvent {
5060
5061
  }
5061
5062
  };
5062
5063
 
5064
+ // packages/types/src/playbookChangeManagement/applier/DiffService.ts
5065
+ var import_diff = require("diff");
5066
+
5067
+ // packages/types/src/playbookChangeManagement/applier/types.ts
5068
+ var STANDARD_CHANGE_TYPES = [
5069
+ "updateStandardName" /* updateStandardName */,
5070
+ "updateStandardScope" /* updateStandardScope */,
5071
+ "updateStandardDescription" /* updateStandardDescription */,
5072
+ "addRule" /* addRule */,
5073
+ "updateRule" /* updateRule */,
5074
+ "deleteRule" /* deleteRule */,
5075
+ "removeStandard" /* removeStandard */
5076
+ ];
5077
+ var RECIPE_CHANGE_TYPES = [
5078
+ "updateCommandName" /* updateCommandName */,
5079
+ "updateCommandDescription" /* updateCommandDescription */,
5080
+ "removeCommand" /* removeCommand */
5081
+ ];
5082
+ var SKILL_CHANGE_TYPES = [
5083
+ "updateSkillName" /* updateSkillName */,
5084
+ "updateSkillDescription" /* updateSkillDescription */,
5085
+ "updateSkillPrompt" /* updateSkillPrompt */,
5086
+ "updateSkillMetadata" /* updateSkillMetadata */,
5087
+ "updateSkillLicense" /* updateSkillLicense */,
5088
+ "updateSkillCompatibility" /* updateSkillCompatibility */,
5089
+ "updateSkillAllowedTools" /* updateSkillAllowedTools */,
5090
+ "addSkillFile" /* addSkillFile */,
5091
+ "updateSkillFileContent" /* updateSkillFileContent */,
5092
+ "updateSkillFilePermissions" /* updateSkillFilePermissions */,
5093
+ "deleteSkillFile" /* deleteSkillFile */,
5094
+ "removeSkill" /* removeSkill */
5095
+ ];
5096
+
5063
5097
  // apps/cli/src/application/useCases/ExecuteSingleFileAstUseCase.ts
5064
5098
  var ExecuteSingleFileAstUseCase = class _ExecuteSingleFileAstUseCase {
5065
5099
  constructor(linterExecutionUseCase) {
@@ -5123,30 +5157,30 @@ var GitService = class {
5123
5157
  this.gitRunner = gitRunner;
5124
5158
  this.logger = logger2;
5125
5159
  }
5126
- getGitRepositoryRoot(path21) {
5160
+ getGitRepositoryRoot(path22) {
5127
5161
  try {
5128
5162
  const { stdout } = this.gitRunner("rev-parse --show-toplevel", {
5129
- cwd: path21
5163
+ cwd: path22
5130
5164
  });
5131
5165
  const gitRoot = stdout.trim();
5132
5166
  this.logger.debug("Resolved git repository root", {
5133
- inputPath: path21,
5167
+ inputPath: path22,
5134
5168
  gitRoot
5135
5169
  });
5136
5170
  return gitRoot;
5137
5171
  } catch (error) {
5138
5172
  if (error instanceof Error) {
5139
5173
  throw new Error(
5140
- `Failed to get Git repository root. The path '${path21}' does not appear to be inside a Git repository.
5174
+ `Failed to get Git repository root. The path '${path22}' does not appear to be inside a Git repository.
5141
5175
  ${error.message}`
5142
5176
  );
5143
5177
  }
5144
5178
  throw new Error("Failed to get Git repository root: Unknown error");
5145
5179
  }
5146
5180
  }
5147
- tryGetGitRepositoryRoot(path21) {
5181
+ tryGetGitRepositoryRoot(path22) {
5148
5182
  try {
5149
- return this.getGitRepositoryRoot(path21);
5183
+ return this.getGitRepositoryRoot(path22);
5150
5184
  } catch {
5151
5185
  return null;
5152
5186
  }
@@ -6400,10 +6434,10 @@ var PackmindHttpClient = class {
6400
6434
  return null;
6401
6435
  }
6402
6436
  }
6403
- async request(path21, options = {}) {
6437
+ async request(path22, options = {}) {
6404
6438
  const { host } = this.getAuthContext();
6405
6439
  const { method = "GET", body } = options;
6406
- const url = `${host}${path21}`;
6440
+ const url = `${host}${path22}`;
6407
6441
  try {
6408
6442
  const response = await fetch(url, {
6409
6443
  method,
@@ -9924,10 +9958,10 @@ async function defaultPromptForCode() {
9924
9958
  input: process.stdin,
9925
9959
  output: process.stdout
9926
9960
  });
9927
- return new Promise((resolve8) => {
9961
+ return new Promise((resolve9) => {
9928
9962
  rl.question("Enter the login code from the browser: ", (answer) => {
9929
9963
  rl.close();
9930
- resolve8(answer.trim());
9964
+ resolve9(answer.trim());
9931
9965
  });
9932
9966
  });
9933
9967
  }
@@ -9961,7 +9995,7 @@ async function defaultExchangeCodeForApiKey(code, host) {
9961
9995
  return await response.json();
9962
9996
  }
9963
9997
  function defaultStartCallbackServer() {
9964
- return new Promise((resolve8, reject) => {
9998
+ return new Promise((resolve9, reject) => {
9965
9999
  let timeoutId = null;
9966
10000
  const server = http.createServer((req, res) => {
9967
10001
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -9974,7 +10008,7 @@ function defaultStartCallbackServer() {
9974
10008
  if (timeoutId) {
9975
10009
  clearTimeout(timeoutId);
9976
10010
  }
9977
- resolve8(code);
10011
+ resolve9(code);
9978
10012
  setImmediate(() => {
9979
10013
  server.close();
9980
10014
  });
@@ -10051,8 +10085,8 @@ var LogoutUseCase = class {
10051
10085
  constructor(deps) {
10052
10086
  this.deps = {
10053
10087
  getCredentialsPath: deps?.getCredentialsPath ?? getCredentialsPath,
10054
- fileExists: deps?.fileExists ?? ((path21) => fs7.existsSync(path21)),
10055
- deleteFile: deps?.deleteFile ?? ((path21) => fs7.unlinkSync(path21)),
10088
+ fileExists: deps?.fileExists ?? ((path22) => fs7.existsSync(path22)),
10089
+ deleteFile: deps?.deleteFile ?? ((path22) => fs7.unlinkSync(path22)),
10056
10090
  hasEnvVar: deps?.hasEnvVar ?? (() => !!process.env[ENV_VAR_NAME2])
10057
10091
  };
10058
10092
  }
@@ -10865,7 +10899,7 @@ var UploadSkillUseCase = class {
10865
10899
  };
10866
10900
 
10867
10901
  // apps/cli/src/application/useCases/diffStrategies/CommandDiffStrategy.ts
10868
- var import_diff = require("diff");
10902
+ var import_diff2 = require("diff");
10869
10903
  var fs11 = __toESM(require("fs/promises"));
10870
10904
  var path12 = __toESM(require("path"));
10871
10905
 
@@ -10903,7 +10937,7 @@ var CommandDiffStrategy = class {
10903
10937
  }
10904
10938
  const serverBody = stripFrontmatter(file.content);
10905
10939
  const localBody = stripFrontmatter(localContent);
10906
- const changes = (0, import_diff.diffLines)(serverBody, localBody);
10940
+ const changes = (0, import_diff2.diffLines)(serverBody, localBody);
10907
10941
  const hasDifferences = changes.some(
10908
10942
  (change) => change.added || change.removed
10909
10943
  );
@@ -10928,7 +10962,7 @@ var CommandDiffStrategy = class {
10928
10962
  };
10929
10963
 
10930
10964
  // apps/cli/src/application/useCases/diffStrategies/SkillDiffStrategy.ts
10931
- var import_diff2 = require("diff");
10965
+ var import_diff3 = require("diff");
10932
10966
  var fs12 = __toESM(require("fs/promises"));
10933
10967
  var path13 = __toESM(require("path"));
10934
10968
  var SkillDiffStrategy = class {
@@ -11000,7 +11034,7 @@ var SkillDiffStrategy = class {
11000
11034
  if (!serverParsed || !localParsed) {
11001
11035
  const serverBody = stripFrontmatter(file.content);
11002
11036
  const localBody = stripFrontmatter(localContent);
11003
- const changes = (0, import_diff2.diffLines)(serverBody, localBody);
11037
+ const changes = (0, import_diff3.diffLines)(serverBody, localBody);
11004
11038
  const hasDifferences = changes.some(
11005
11039
  (change) => change.added || change.removed
11006
11040
  );
@@ -11761,7 +11795,7 @@ var DiffArtefactsUseCase = class {
11761
11795
  diffs.push(...newFileDiffs);
11762
11796
  }
11763
11797
  }
11764
- return diffs;
11798
+ return diffs.map((diff) => ({ ...diff, targetId: response.targetId }));
11765
11799
  }
11766
11800
  prefixSkillFolders(skillFolders, relativePath) {
11767
11801
  if (!relativePath) return skillFolders;
@@ -11835,7 +11869,8 @@ var SubmitDiffsUseCase = class {
11835
11869
  artefactId: CREATION_TYPES.has(diff.type) ? null : diff.artifactId,
11836
11870
  payload: diff.payload,
11837
11871
  captureMode: "commit" /* commit */,
11838
- message
11872
+ message,
11873
+ targetId: diff.targetId
11839
11874
  }))
11840
11875
  });
11841
11876
  submitted += response.created;
@@ -11888,7 +11923,8 @@ var CheckDiffsUseCase = class {
11888
11923
  artefactId: diff.artifactId,
11889
11924
  payload: diff.payload,
11890
11925
  captureMode: "commit" /* commit */,
11891
- message: ""
11926
+ message: "",
11927
+ targetId: diff.targetId
11892
11928
  }))
11893
11929
  });
11894
11930
  for (const result of response.results) {
@@ -12261,7 +12297,7 @@ function isNotLoggedInError(error) {
12261
12297
  }
12262
12298
  async function lintHandler(args2, deps) {
12263
12299
  const {
12264
- path: path21,
12300
+ path: path22,
12265
12301
  draft,
12266
12302
  rule,
12267
12303
  language,
@@ -12282,7 +12318,7 @@ async function lintHandler(args2, deps) {
12282
12318
  throw new Error("option --rule is required to use --draft mode");
12283
12319
  }
12284
12320
  const startedAt = Date.now();
12285
- const targetPath = path21 ?? ".";
12321
+ const targetPath = path22 ?? ".";
12286
12322
  const absolutePath = resolvePath(targetPath);
12287
12323
  if (diff) {
12288
12324
  const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(absolutePath);
@@ -12565,7 +12601,7 @@ function extractWasmFiles() {
12565
12601
  // apps/cli/src/main.ts
12566
12602
  var import_dotenv = require("dotenv");
12567
12603
  var fs19 = __toESM(require("fs"));
12568
- var path20 = __toESM(require("path"));
12604
+ var path21 = __toESM(require("path"));
12569
12605
 
12570
12606
  // apps/cli/src/infra/commands/InstallCommand.ts
12571
12607
  var import_cmd_ts2 = __toESM(require_cjs());
@@ -13736,7 +13772,7 @@ async function promptAgentsWithReadline(choices) {
13736
13772
  output.write("\n");
13737
13773
  const preselected = choices.map((c, i) => c.checked ? i + 1 : null).filter((i) => i !== null);
13738
13774
  const defaultValue = preselected.length > 0 ? preselected.join(",") : "1,2,3";
13739
- return new Promise((resolve8) => {
13775
+ return new Promise((resolve9) => {
13740
13776
  rl.question(
13741
13777
  `Enter numbers separated by commas (default: ${defaultValue}): `,
13742
13778
  (answer) => {
@@ -13747,7 +13783,7 @@ async function promptAgentsWithReadline(choices) {
13747
13783
  const numbersStr = trimmed === "" ? defaultValue : trimmed;
13748
13784
  const numbers = numbersStr.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n) && n >= 1 && n <= choices.length);
13749
13785
  const selectedAgents = numbers.map((n) => choices[n - 1].value);
13750
- resolve8(selectedAgents);
13786
+ resolve9(selectedAgents);
13751
13787
  }
13752
13788
  );
13753
13789
  });
@@ -14660,10 +14696,10 @@ var import_fs20 = require("fs");
14660
14696
  var import_cmd_ts19 = __toESM(require_cjs());
14661
14697
 
14662
14698
  // apps/cli/src/infra/utils/diffFormatter.ts
14663
- var import_diff3 = require("diff");
14699
+ var import_diff4 = require("diff");
14664
14700
  init_source();
14665
14701
  function formatContentDiff(oldContent, newContent) {
14666
- const changes = (0, import_diff3.diffLines)(oldContent, newContent);
14702
+ const changes = (0, import_diff4.diffLines)(oldContent, newContent);
14667
14703
  const lines = [];
14668
14704
  for (const change of changes) {
14669
14705
  const trimmedValue = change.value.replace(/\n$/, "");
@@ -15299,6 +15335,9 @@ function parseSkillDirectory(files) {
15299
15335
  if (typeof properties.allowedTools === "string") {
15300
15336
  payload.allowedTools = properties.allowedTools;
15301
15337
  }
15338
+ if (properties.metadata != null && typeof properties.metadata === "object") {
15339
+ payload.metadata = properties.metadata;
15340
+ }
15302
15341
  const supportingFiles = files.filter(
15303
15342
  (f) => f.relativePath !== SKILL_MD_FILENAME
15304
15343
  );
@@ -15420,14 +15459,38 @@ async function diffAddHandler(deps) {
15420
15459
  return;
15421
15460
  }
15422
15461
  const space = await packmindCliHexa.getPackmindGateway().spaces.getGlobal();
15462
+ let targetId;
15463
+ try {
15464
+ const cwd = getCwd();
15465
+ const fullConfig = await packmindCliHexa.readFullConfig(cwd);
15466
+ const configPackages = fullConfig ? Object.keys(fullConfig.packages) : [];
15467
+ const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
15468
+ if (gitRoot && configPackages.length > 0) {
15469
+ const gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(gitRoot);
15470
+ const gitBranch = packmindCliHexa.getCurrentBranch(gitRoot);
15471
+ let relativePath = cwd.startsWith(gitRoot) ? cwd.slice(gitRoot.length) : "/";
15472
+ if (!relativePath.startsWith("/")) relativePath = "/" + relativePath;
15473
+ if (!relativePath.endsWith("/")) relativePath = relativePath + "/";
15474
+ const deployedContent = await packmindCliHexa.getPackmindGateway().deployment.getDeployed({
15475
+ packagesSlugs: configPackages,
15476
+ gitRemoteUrl,
15477
+ gitBranch,
15478
+ relativePath,
15479
+ agents: fullConfig?.agents
15480
+ });
15481
+ targetId = deployedContent.targetId;
15482
+ }
15483
+ } catch {
15484
+ }
15423
15485
  const diff = {
15424
15486
  ...diffResult.diff,
15425
15487
  filePath: absolutePath,
15426
- spaceId: space.id
15488
+ spaceId: space.id,
15489
+ targetId
15427
15490
  };
15428
15491
  const result = await packmindCliHexa.submitDiffs([[diff]], message);
15429
15492
  for (const err of result.errors) {
15430
- logErrorConsole(`Failed to submit "${err.name}": ${err.message}`);
15493
+ logErrorConsole(`Failed to submit addition "${err.name}": ${err.message}`);
15431
15494
  }
15432
15495
  const summaryParts = [];
15433
15496
  if (result.submitted > 0) {
@@ -15524,6 +15587,216 @@ function isErrnoException(err) {
15524
15587
  return err instanceof Error && "code" in err;
15525
15588
  }
15526
15589
 
15590
+ // apps/cli/src/infra/commands/diffRemoveHandler.ts
15591
+ var path18 = __toESM(require("path"));
15592
+ var ARTIFACT_TYPE_LABELS2 = {
15593
+ command: "command",
15594
+ standard: "standard",
15595
+ skill: "skill"
15596
+ };
15597
+ async function diffRemoveHandler(deps) {
15598
+ const {
15599
+ packmindCliHexa,
15600
+ filePath,
15601
+ message: messageFlag,
15602
+ exit,
15603
+ getCwd,
15604
+ existsSync: existsSync25,
15605
+ unlinkSync: unlinkSync5,
15606
+ rmSync: rmSync2
15607
+ } = deps;
15608
+ if (!filePath) {
15609
+ logErrorConsole(
15610
+ 'Missing file path. Usage: packmind-cli diff remove <path> -m "message"'
15611
+ );
15612
+ exit(1);
15613
+ return;
15614
+ }
15615
+ const cwd = getCwd();
15616
+ const absolutePath = path18.resolve(cwd, filePath);
15617
+ const artefactResult = resolveArtefactFromPath(absolutePath);
15618
+ if (!artefactResult) {
15619
+ logErrorConsole(
15620
+ `Unsupported file path: ${absolutePath}. File must be in a recognized artefact directory (command, standard, or skill).`
15621
+ );
15622
+ exit(1);
15623
+ return;
15624
+ }
15625
+ const matchPath = artefactResult.artifactType === "skill" ? absolutePath.endsWith("SKILL.md") ? absolutePath : path18.join(absolutePath, "SKILL.md") : absolutePath;
15626
+ const skillDirPath = artefactResult.artifactType === "skill" ? absolutePath.endsWith("SKILL.md") ? path18.dirname(absolutePath) : absolutePath : void 0;
15627
+ const existsCheckPath = skillDirPath ?? absolutePath;
15628
+ if (!existsSync25(existsCheckPath)) {
15629
+ logErrorConsole(`File or directory does not exist: ${filePath}`);
15630
+ exit(1);
15631
+ return;
15632
+ }
15633
+ let configPackages;
15634
+ let configAgents;
15635
+ try {
15636
+ const fullConfig = await packmindCliHexa.readFullConfig(cwd);
15637
+ if (fullConfig) {
15638
+ configPackages = Object.keys(fullConfig.packages);
15639
+ configAgents = fullConfig.agents;
15640
+ } else {
15641
+ configPackages = [];
15642
+ }
15643
+ } catch (err) {
15644
+ logErrorConsole("Failed to parse packmind.json");
15645
+ if (err instanceof Error) {
15646
+ logErrorConsole(err.message);
15647
+ } else {
15648
+ logErrorConsole(String(err));
15649
+ }
15650
+ logErrorConsole(
15651
+ "\n\u{1F4A1} Please fix the packmind.json file or delete it to continue."
15652
+ );
15653
+ exit(1);
15654
+ return;
15655
+ }
15656
+ if (configPackages.length === 0) {
15657
+ logErrorConsole(
15658
+ "No packages configured. Configure packages in packmind.json first."
15659
+ );
15660
+ exit(1);
15661
+ return;
15662
+ }
15663
+ let gitRemoteUrl;
15664
+ let gitBranch;
15665
+ let relativePath;
15666
+ const gitRoot = await packmindCliHexa.tryGetGitRepositoryRoot(cwd);
15667
+ if (gitRoot) {
15668
+ try {
15669
+ gitRemoteUrl = packmindCliHexa.getGitRemoteUrlFromPath(gitRoot);
15670
+ gitBranch = packmindCliHexa.getCurrentBranch(gitRoot);
15671
+ relativePath = cwd.startsWith(gitRoot) ? cwd.slice(gitRoot.length) : "/";
15672
+ if (!relativePath.startsWith("/")) {
15673
+ relativePath = "/" + relativePath;
15674
+ }
15675
+ if (!relativePath.endsWith("/")) {
15676
+ relativePath = relativePath + "/";
15677
+ }
15678
+ } catch (err) {
15679
+ logErrorConsole(
15680
+ `Failed to collect git info: ${err instanceof Error ? err.message : String(err)}`
15681
+ );
15682
+ }
15683
+ }
15684
+ if (!gitRemoteUrl || !gitBranch || !relativePath) {
15685
+ logErrorConsole(
15686
+ "\n\u274C Could not determine git repository info. The diff command requires a git repository with a remote configured."
15687
+ );
15688
+ exit(1);
15689
+ return;
15690
+ }
15691
+ const deployedContent = await packmindCliHexa.getPackmindGateway().deployment.getDeployed({
15692
+ packagesSlugs: configPackages,
15693
+ gitRemoteUrl,
15694
+ gitBranch,
15695
+ relativePath,
15696
+ agents: configAgents
15697
+ });
15698
+ const relativeToGitRoot = matchPath.startsWith(gitRoot) ? matchPath.slice(gitRoot.length) : matchPath;
15699
+ let normalizedFilePath = normalizePath(relativeToGitRoot);
15700
+ if (normalizedFilePath.startsWith("/")) {
15701
+ normalizedFilePath = normalizedFilePath.slice(1);
15702
+ }
15703
+ const relativePathPrefix = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
15704
+ const filePathForComparison = relativePathPrefix.length > 0 && normalizedFilePath.startsWith(relativePathPrefix) ? normalizedFilePath.slice(relativePathPrefix.length) : normalizedFilePath;
15705
+ const deployedFile = deployedContent.fileUpdates.createOrUpdate.find(
15706
+ (file) => normalizePath(file.path) === filePathForComparison
15707
+ );
15708
+ if (!deployedFile) {
15709
+ const artifactTypeLabel = ARTIFACT_TYPE_LABELS2[artefactResult.artifactType];
15710
+ logErrorConsole(`This ${artifactTypeLabel} does not come from Packmind`);
15711
+ exit(1);
15712
+ return;
15713
+ }
15714
+ if (!deployedFile.artifactId || !deployedFile.spaceId) {
15715
+ logErrorConsole(
15716
+ "Missing artifact metadata. Cannot create change proposal for removal."
15717
+ );
15718
+ exit(1);
15719
+ return;
15720
+ }
15721
+ if (!deployedContent.targetId || !deployedFile.packageIds) {
15722
+ logErrorConsole(
15723
+ "Missing target or package information. Cannot create change proposal for removal."
15724
+ );
15725
+ exit(1);
15726
+ return;
15727
+ }
15728
+ let message;
15729
+ if (messageFlag !== void 0) {
15730
+ const validation = validateMessage(messageFlag);
15731
+ if (!validation.valid) {
15732
+ logErrorConsole(validation.error);
15733
+ exit(1);
15734
+ return;
15735
+ }
15736
+ message = validation.message;
15737
+ } else if (process.stdin.isTTY) {
15738
+ const editorMessage = openEditorForMessage();
15739
+ const validation = validateMessage(editorMessage);
15740
+ if (!validation.valid) {
15741
+ logErrorConsole(
15742
+ "Aborting submission: empty message. Use -m to provide a message."
15743
+ );
15744
+ exit(1);
15745
+ return;
15746
+ }
15747
+ message = validation.message;
15748
+ } else {
15749
+ logErrorConsole(
15750
+ 'Non-interactive mode requires -m flag. Usage: packmind-cli diff remove <path> -m "your message"'
15751
+ );
15752
+ exit(1);
15753
+ return;
15754
+ }
15755
+ const changeProposalType = artefactResult.artifactType === "standard" ? "removeStandard" /* removeStandard */ : artefactResult.artifactType === "command" ? "removeCommand" /* removeCommand */ : "removeSkill" /* removeSkill */;
15756
+ const diff = {
15757
+ filePath: absolutePath,
15758
+ type: changeProposalType,
15759
+ payload: {
15760
+ targetId: deployedContent.targetId,
15761
+ packageIds: deployedFile.packageIds.map(createPackageId)
15762
+ },
15763
+ artifactName: deployedFile.artifactName || artefactResult.artifactType,
15764
+ artifactType: artefactResult.artifactType,
15765
+ artifactId: deployedFile.artifactId,
15766
+ spaceId: deployedFile.spaceId,
15767
+ targetId: deployedContent.targetId
15768
+ };
15769
+ const result = await packmindCliHexa.submitDiffs([[diff]], message);
15770
+ for (const err of result.errors) {
15771
+ logErrorConsole(`Failed to submit removal "${err.name}": ${err.message}`);
15772
+ }
15773
+ if (result.errors.length > 0) {
15774
+ exit(1);
15775
+ return;
15776
+ }
15777
+ if (result.submitted > 0) {
15778
+ logSuccessConsole("Change proposal for removal submitted successfully");
15779
+ } else if (result.alreadySubmitted > 0) {
15780
+ logWarningConsole("Change proposal for removal already submitted");
15781
+ }
15782
+ try {
15783
+ if (skillDirPath) {
15784
+ rmSync2(skillDirPath, { recursive: true });
15785
+ logSuccessConsole(`Directory deleted: ${skillDirPath}`);
15786
+ } else {
15787
+ unlinkSync5(absolutePath);
15788
+ logSuccessConsole(`File deleted: ${filePath}`);
15789
+ }
15790
+ } catch (err) {
15791
+ logErrorConsole(
15792
+ `Failed to delete file: ${err instanceof Error ? err.message : String(err)}`
15793
+ );
15794
+ exit(1);
15795
+ return;
15796
+ }
15797
+ exit(0);
15798
+ }
15799
+
15527
15800
  // apps/cli/src/infra/commands/DiffCommand.ts
15528
15801
  var diffCommand = (0, import_cmd_ts19.command)({
15529
15802
  name: "diff",
@@ -15546,7 +15819,7 @@ var diffCommand = (0, import_cmd_ts19.command)({
15546
15819
  positionals: (0, import_cmd_ts19.restPositionals)({
15547
15820
  type: import_cmd_ts19.string,
15548
15821
  displayName: "args",
15549
- description: "Subcommand and arguments (e.g., add <path>)"
15822
+ description: "Subcommand and arguments (e.g., add <path>, remove <path>)"
15550
15823
  })
15551
15824
  },
15552
15825
  handler: async ({ submit, includeSubmitted, message, positionals }) => {
@@ -15564,6 +15837,19 @@ var diffCommand = (0, import_cmd_ts19.command)({
15564
15837
  });
15565
15838
  return;
15566
15839
  }
15840
+ if (positionals[0] === "remove" || positionals[0] === "rm") {
15841
+ await diffRemoveHandler({
15842
+ packmindCliHexa,
15843
+ filePath: positionals[1],
15844
+ message,
15845
+ exit: process.exit,
15846
+ getCwd: () => process.cwd(),
15847
+ existsSync: (p) => (0, import_fs20.existsSync)(p),
15848
+ unlinkSync: (p) => (0, import_fs20.unlinkSync)(p),
15849
+ rmSync: (p, opts) => (0, import_fs20.rmSync)(p, opts)
15850
+ });
15851
+ return;
15852
+ }
15567
15853
  await diffArtefactsHandler({
15568
15854
  packmindCliHexa,
15569
15855
  exit: process.exit,
@@ -15951,7 +16237,7 @@ var import_cmd_ts24 = __toESM(require_cjs());
15951
16237
 
15952
16238
  // apps/cli/src/application/services/AgentArtifactDetectionService.ts
15953
16239
  var fs18 = __toESM(require("fs/promises"));
15954
- var path18 = __toESM(require("path"));
16240
+ var path19 = __toESM(require("path"));
15955
16241
  var AGENT_ARTIFACT_CHECKS = [
15956
16242
  { agent: "claude", paths: [".claude"] },
15957
16243
  { agent: "cursor", paths: [".cursor"] },
@@ -15969,7 +16255,7 @@ var AgentArtifactDetectionService = class {
15969
16255
  const detected = [];
15970
16256
  for (const check of AGENT_ARTIFACT_CHECKS) {
15971
16257
  for (const relativePath of check.paths) {
15972
- const fullPath = path18.join(baseDirectory, relativePath);
16258
+ const fullPath = path19.join(baseDirectory, relativePath);
15973
16259
  const exists = await this.pathExists(fullPath);
15974
16260
  if (exists) {
15975
16261
  detected.push({
@@ -16066,7 +16352,7 @@ async function promptAgentsWithReadline2(choices) {
16066
16352
  output.write("\n");
16067
16353
  const preselected = choices.map((c, i) => c.checked ? i + 1 : null).filter((i) => i !== null);
16068
16354
  const defaultValue = preselected.length > 0 ? preselected.join(",") : "1,2,3";
16069
- return new Promise((resolve8) => {
16355
+ return new Promise((resolve9) => {
16070
16356
  rl.question(
16071
16357
  `Enter numbers separated by commas (default: ${defaultValue}): `,
16072
16358
  (answer) => {
@@ -16075,7 +16361,7 @@ async function promptAgentsWithReadline2(choices) {
16075
16361
  const numbersStr = trimmed === "" ? defaultValue : trimmed;
16076
16362
  const numbers = numbersStr.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n) && n >= 1 && n <= choices.length);
16077
16363
  const selectedAgents = numbers.map((n) => choices[n - 1].value);
16078
- resolve8(selectedAgents);
16364
+ resolve9(selectedAgents);
16079
16365
  }
16080
16366
  );
16081
16367
  });
@@ -16334,6 +16620,14 @@ function isLocalNpmPackage(scriptPath) {
16334
16620
  if (!scriptPath) return false;
16335
16621
  return scriptPath.includes(import_path5.default.join("node_modules", "@packmind", "cli"));
16336
16622
  }
16623
+ function isHomebrewInstall(executablePath) {
16624
+ try {
16625
+ const realPath = (0, import_fs21.realpathSync)(executablePath);
16626
+ return realPath.includes("/Cellar/");
16627
+ } catch {
16628
+ return false;
16629
+ }
16630
+ }
16337
16631
  async function updateHandler(deps) {
16338
16632
  const execBasename = import_path5.default.basename(deps.executablePath).replace(/\.exe$/, "");
16339
16633
  const jsRuntimes = ["node", "bun", "deno"];
@@ -16350,6 +16644,13 @@ async function updateHandler(deps) {
16350
16644
  process.exit(1);
16351
16645
  return;
16352
16646
  }
16647
+ if (isHomebrewInstall(deps.executablePath)) {
16648
+ logInfoConsole(
16649
+ "This CLI was installed via Homebrew.\nTo update, run: brew upgrade packmind-cli"
16650
+ );
16651
+ process.exit(0);
16652
+ return;
16653
+ }
16353
16654
  logInfoConsole(
16354
16655
  `Current version: ${deps.currentVersion} (${deps.isExecutableMode ? "standalone executable" : "npm package"})`
16355
16656
  );
@@ -16431,12 +16732,12 @@ function findEnvFile() {
16431
16732
  const currentDir = process.cwd();
16432
16733
  const gitService = new GitService();
16433
16734
  const gitRoot = gitService.getGitRepositoryRootSync(currentDir);
16434
- const filesystemRoot = path20.parse(currentDir).root;
16735
+ const filesystemRoot = path21.parse(currentDir).root;
16435
16736
  const stopDir = gitRoot ?? filesystemRoot;
16436
16737
  let searchDir = currentDir;
16437
- let parentDir = path20.dirname(searchDir);
16738
+ let parentDir = path21.dirname(searchDir);
16438
16739
  while (searchDir !== parentDir) {
16439
- const envPath2 = path20.join(searchDir, ".env");
16740
+ const envPath2 = path21.join(searchDir, ".env");
16440
16741
  if (fs19.existsSync(envPath2)) {
16441
16742
  return envPath2;
16442
16743
  }
@@ -16444,7 +16745,7 @@ function findEnvFile() {
16444
16745
  return null;
16445
16746
  }
16446
16747
  searchDir = parentDir;
16447
- parentDir = path20.dirname(searchDir);
16748
+ parentDir = path21.dirname(searchDir);
16448
16749
  }
16449
16750
  return null;
16450
16751
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@packmind/cli",
3
- "version": "0.20.0",
3
+ "version": "0.21.1",
4
4
  "description": "A command-line interface for Packmind linting and code quality checks",
5
5
  "private": false,
6
6
  "bin": {
@@ -47,9 +47,9 @@
47
47
  "axios": "1.13.5",
48
48
  "bcrypt": "6.0.0",
49
49
  "bullmq": "5.63.0",
50
- "diff": "8.0.3",
50
+ "diff": "^8.0.3",
51
51
  "dotenv": "16.4.7",
52
- "express": "5.1.0",
52
+ "express": "5.2.1",
53
53
  "inquirer": "^13.0.2",
54
54
  "minimatch": "9.0.3",
55
55
  "open": "11.0.0",