moodle-cli 0.7.0-alpha.2 → 0.7.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -174,7 +174,7 @@ moodle mcp bridge
174
174
 
175
175
  The default client connection uses `moodle mcp bridge`, which keeps the Bearer token out of client configuration. Use `moodle mcp connect CLIENT --mode remote` for clients that support authenticated remote MCP headers.
176
176
 
177
- Alpha version `0.7.0-alpha.2` supports MCP `2026-07-28` and a stateless compatibility lane for `2025-11-25` clients.
177
+ Alpha version `0.7.0-alpha.3` supports MCP `2026-07-28` and a stateless compatibility lane for `2025-11-25` clients.
178
178
 
179
179
  ### Configuration
180
180
 
package/dist/moodle.js CHANGED
@@ -3700,7 +3700,7 @@ function escapeXml(value) {
3700
3700
  }
3701
3701
 
3702
3702
  // src/version.ts
3703
- var VERSION = "0.7.0-alpha.2";
3703
+ var VERSION = "0.7.0-alpha.3";
3704
3704
 
3705
3705
  // src/forum.ts
3706
3706
  function parseDiscussionReference(value) {
@@ -4519,6 +4519,61 @@ import { chmod as chmod3, mkdir as mkdir5, readFile as readFile4, rename as rena
4519
4519
  import { homedir as homedir6 } from "os";
4520
4520
  import { dirname as dirname5, join as join6, win32 as windowsPath } from "path";
4521
4521
  var SERVICE = "moodle-cli-mcp";
4522
+ var MACOS_KEYCHAIN_SCRIPT = `
4523
+ ObjC.import("Foundation")
4524
+ ObjC.import("Security")
4525
+
4526
+ function main() {
4527
+ const input = $.NSFileHandle.fileHandleWithStandardInput.readDataToEndOfFile
4528
+ const text = $.NSString.alloc.initWithDataEncoding(input, $.NSUTF8StringEncoding)
4529
+ const payload = JSON.parse(ObjC.unwrap(text))
4530
+ const keys = {
4531
+ class: "class",
4532
+ genericPassword: "genp",
4533
+ service: "svce",
4534
+ account: "acct",
4535
+ valueData: "v_Data",
4536
+ returnData: "r_Data",
4537
+ }
4538
+ const query = $.NSMutableDictionary.alloc.init
4539
+ query.setObjectForKey(keys.genericPassword, keys.class)
4540
+ query.setObjectForKey(payload.service, keys.service)
4541
+ query.setObjectForKey(payload.profile, keys.account)
4542
+
4543
+ if (payload.operation === "read") {
4544
+ query.setObjectForKey(true, keys.returnData)
4545
+ const result = $()
4546
+ const status = Number($.SecItemCopyMatching(query, result))
4547
+ if (status === -25300) return
4548
+ if (status !== 0) throw new Error("Keychain read failed: " + status)
4549
+ $.NSFileHandle.fileHandleWithStandardOutput.writeData(result)
4550
+ return
4551
+ }
4552
+
4553
+ if (payload.operation === "write") {
4554
+ const value = $(payload.credentials).dataUsingEncoding($.NSUTF8StringEncoding)
4555
+ const attributes = $.NSMutableDictionary.alloc.init
4556
+ attributes.setObjectForKey(value, keys.valueData)
4557
+ let status = Number($.SecItemUpdate(query, attributes))
4558
+ if (status === -25300) {
4559
+ query.setObjectForKey(value, keys.valueData)
4560
+ status = Number($.SecItemAdd(query, null))
4561
+ }
4562
+ if (status !== 0) throw new Error("Keychain write failed: " + status)
4563
+ return
4564
+ }
4565
+
4566
+ if (payload.operation === "delete") {
4567
+ const status = Number($.SecItemDelete(query))
4568
+ if (status !== 0 && status !== -25300) throw new Error("Keychain delete failed: " + status)
4569
+ return
4570
+ }
4571
+
4572
+ throw new Error("Unsupported Keychain operation")
4573
+ }
4574
+
4575
+ main()
4576
+ `;
4522
4577
  var WINDOWS_CREDENTIAL_READ = `
4523
4578
  $ErrorActionPreference = "Stop"
4524
4579
  [Console]::InputEncoding = [Text.UTF8Encoding]::new($false)
@@ -4623,24 +4678,30 @@ var MacOSKeychainCredentialBackend = class {
4623
4678
  name = "macOS Login Keychain";
4624
4679
  async read(profile) {
4625
4680
  try {
4626
- const result = await this.runner.run("security", ["find-generic-password", "-s", SERVICE, "-a", profile, "-w"]);
4627
- return parseCredentials(result.stdout.trim());
4681
+ const result = await this.runner.run(
4682
+ "osascript",
4683
+ ["-l", "JavaScript", "-e", MACOS_KEYCHAIN_SCRIPT],
4684
+ macosKeychainInput("read", profile)
4685
+ );
4686
+ const value = result.stdout.trim();
4687
+ if (value) {
4688
+ return parseCredentials(value);
4689
+ }
4690
+ await this.deleteEmptyLegacyEntry(profile);
4691
+ return null;
4628
4692
  } catch (error) {
4629
4693
  if (commandNotFound(error)) {
4630
4694
  throw new CredentialBackendUnavailableError(this.name, error);
4631
4695
  }
4632
- if (commandExitCode(error) === 44) {
4633
- return null;
4634
- }
4635
4696
  throw error;
4636
4697
  }
4637
4698
  }
4638
4699
  async write(profile, credentials) {
4639
4700
  try {
4640
4701
  await this.runner.run(
4641
- "security",
4642
- ["add-generic-password", "-s", SERVICE, "-a", profile, "-U", "-w"],
4643
- JSON.stringify(credentials)
4702
+ "osascript",
4703
+ ["-l", "JavaScript", "-e", MACOS_KEYCHAIN_SCRIPT],
4704
+ macosKeychainInput("write", profile, credentials)
4644
4705
  );
4645
4706
  } catch (error) {
4646
4707
  if (commandNotFound(error)) {
@@ -4651,14 +4712,26 @@ var MacOSKeychainCredentialBackend = class {
4651
4712
  }
4652
4713
  async delete(profile) {
4653
4714
  try {
4654
- await this.runner.run("security", ["delete-generic-password", "-s", SERVICE, "-a", profile]);
4715
+ await this.runner.run(
4716
+ "osascript",
4717
+ ["-l", "JavaScript", "-e", MACOS_KEYCHAIN_SCRIPT],
4718
+ macosKeychainInput("delete", profile)
4719
+ );
4655
4720
  } catch (error) {
4656
4721
  if (commandNotFound(error)) {
4657
4722
  throw new CredentialBackendUnavailableError(this.name, error);
4658
4723
  }
4659
- if (commandExitCode(error) !== 44) {
4660
- throw error;
4724
+ throw error;
4725
+ }
4726
+ }
4727
+ async deleteEmptyLegacyEntry(profile) {
4728
+ try {
4729
+ await this.runner.run("security", ["delete-generic-password", "-s", SERVICE, "-a", profile]);
4730
+ } catch (error) {
4731
+ if (commandNotFound(error) || commandExitCode(error) === 44) {
4732
+ return;
4661
4733
  }
4734
+ throw error;
4662
4735
  }
4663
4736
  }
4664
4737
  };
@@ -4883,6 +4956,14 @@ function parseCredentials(value) {
4883
4956
  function powershellArgs(script) {
4884
4957
  return ["-NoProfile", "-NonInteractive", "-Command", script];
4885
4958
  }
4959
+ function macosKeychainInput(operation, profile, credentials) {
4960
+ return JSON.stringify({
4961
+ operation,
4962
+ service: SERVICE,
4963
+ profile,
4964
+ ...credentials ? { credentials: JSON.stringify(credentials) } : {}
4965
+ });
4966
+ }
4886
4967
  function windowsCredentialInput(profile, credentials) {
4887
4968
  return JSON.stringify({
4888
4969
  service: SERVICE,
@@ -5996,7 +5996,7 @@ function problemResponse(status, code, title, detail, headers) {
5996
5996
  }
5997
5997
 
5998
5998
  // src/version.ts
5999
- var VERSION = "0.7.0-alpha.2";
5999
+ var VERSION = "0.7.0-alpha.3";
6000
6000
 
6001
6001
  // src/worker/http.ts
6002
6002
  var HEALTH_PATH = "/healthz";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moodle-cli",
3
- "version": "0.7.0-alpha.2",
3
+ "version": "0.7.0-alpha.3",
4
4
  "description": "Terminal-first CLI for Moodle LMS",
5
5
  "license": "MIT",
6
6
  "type": "module",