From 7b87b0e9fe8fa88c43e2debff44592a907d4323b Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Fri, 19 Jun 2026 16:37:07 +0530 Subject: [PATCH 01/12] style(logger): remove code style emoji comment from ConsoleLogger (#147) From e2781c3c7406efed73001c3c6176bfeedc6e3f94 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Fri, 19 Jun 2026 16:39:31 +0530 Subject: [PATCH 02/12] style(logger): remove code style emoji comment from JsonLogger (#147) From 3593aaa492d4045fb9211be9d45b33ac99261642 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 10:55:15 +0530 Subject: [PATCH 03/12] feat(github-desktop): define configuration provider plugin manifest (#466) --- github-desktop/plugin.yaml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 github-desktop/plugin.yaml diff --git a/github-desktop/plugin.yaml b/github-desktop/plugin.yaml new file mode 100644 index 00000000..ab2ef725 --- /dev/null +++ b/github-desktop/plugin.yaml @@ -0,0 +1,37 @@ +name: github-desktop +type: config_provider +description: Manage GitHub Desktop application settings stored in config.json. +supported_os: + - windows +settings: + theme: + type: string + description: UI theme (light, dark, system) + defaultBranchName: + type: string + description: Default branch name for new repos + confirmRemovedFiles: + type: boolean + description: Confirmation on file removal + confirmDiscardChanges: + type: boolean + description: Confirmation on discard + usageStats: + type: boolean + description: Telemetry opt-in/out + signCommits: + type: boolean + description: Sign commits by default + selectedTheme: + type: string + description: Accent/theme selection + externalEditor: + type: string + description: Default external editor config + shell: + type: string + description: Default shell config + hideWhitespaceInStorybook: + type: boolean + description: Whitespace display setting + From 2c8534be3b0120abb8993de77dfa53a41d0df1ae Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 10:56:32 +0530 Subject: [PATCH 04/12] feat(github-desktop): implement atomic json config deep merging handler (#466) --- src/plugin.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/plugin.py diff --git a/src/plugin.py b/src/plugin.py new file mode 100644 index 00000000..8349cf09 --- /dev/null +++ b/src/plugin.py @@ -0,0 +1,73 @@ +import sys +import os +import json +import tempfile + +def deep_merge(base, update): + if not isinstance(base, dict) or not isinstance(update, dict): + return update + for key, val in update.items(): + if key in base and isinstance(base[key], dict) and isinstance(val, dict): + base[key] = deep_merge(base[key], val) + else: + base[key] = val + return base + +def main(): + raw_input = sys.stdin.read().strip() + if not raw_input: + print(json.dumps({"error": "Empty stdin context payload received"}), file=sys.stderr) + sys.exit(1) + + try: + args = json.loads(raw_input) + except json.JSONDecodeError: + print(json.dumps({"error": "Invalid JSON format payload structure"}), file=sys.stderr) + sys.exit(1) + + request_id = args.get("requestId", "") + + if args.get("check_installed", False): + appdata = os.environ.get("APPDATA", "") + config_path = os.path.join(appdata, "GitHub Desktop", "config.json") if appdata else "" + installed = bool(config_path and os.path.exists(config_path)) + print(json.dumps({"requestId": request_id, "installed": installed})) + sys.exit(0) + + settings = args.get("settings", {}) + dry_run = args.get("dryRun", False) + + appdata = os.environ.get("APPDATA", "") + if not appdata: + print(json.dumps({"requestId": request_id, "error": "APPDATA environment variable missing"}), file=sys.stderr) + sys.exit(1) + + config_dir = os.path.join(appdata, "GitHub Desktop") + config_path = os.path.join(config_dir, "config.json") + + current_config = {} + if os.path.exists(config_path): + try: + with open(config_path, "r", encoding="utf-8") as f: + current_config = json.load(f) + except Exception: + current_config = {} + + updated_config = deep_merge(current_config, settings) + + if not dry_run: + if not os.path.exists(config_dir): + os.makedirs(config_dir, exist_ok=True) + try: + fd, temp_path = tempfile.mkstemp(dir=config_dir, prefix="config_", suffix=".json") + with os.fdopen(fd, "w", encoding="utf-8") as f: + json.dump(updated_config, f, indent=2) + os.replace(temp_path, config_path) + except Exception as e: + print(json.dumps({"requestId": request_id, "error": f"Atomic write operation exception: {str(e)}"}), file=sys.stderr) + sys.exit(1) + + print(json.dumps({"requestId": request_id})) + +if __name__ == "__main__": + main() From b95cbd6d84092b6e156bc6a345136a0cdc312bf7 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 10:57:43 +0530 Subject: [PATCH 05/12] test(github-desktop): author robust protocol compliance regression test suite (#466) --- test/test_github_desktop.py | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/test_github_desktop.py diff --git a/test/test_github_desktop.py b/test/test_github_desktop.py new file mode 100644 index 00000000..36005004 --- /dev/null +++ b/test/test_github_desktop.py @@ -0,0 +1,64 @@ +import unittest +import json +import sys +import os +from unittest.mock import patch, mock_open + +# Compliance constraint: Leveraging sys.path.append instead of sys.path.insert(0) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src"))) + +import plugin + +class TestGitHubDesktopPlugin(unittest.TestCase): + + @patch("sys.stdin") + @patch("sys.stderr") + def test_empty_stdin_throws_json_error(self, mock_stderr, mock_stdin): + mock_stdin.read.return_value = " " + with self.assertRaises(SystemExit) as cm: + plugin.main() + self.assertEqual(cm.exception.code, 1) + + @patch("sys.stdin") + @patch("os.environ", {"APPDATA": "C:\\MockAppData"}) + @patch("os.path.exists") + def test_check_installed_protocol_parity(self, mock_exists, mock_stdin): + mock_stdin.read.return_value = json.dumps({"requestId": "test-req-123", "check_installed": True}) + mock_exists.return_value = True + + with patch("sys.stdout") as mock_stdout: + with self.assertRaises(SystemExit) as cm: + plugin.main() + self.assertEqual(cm.exception.code, 0) + output = json.loads(mock_stdout.write.call_args[0][0]) + self.assertEqual(output["requestId"], "test-req-123") + self.assertTrue(output["installed"]) + + @patch("sys.stdin") + @patch("os.environ", {"APPDATA": "C:\\MockAppData"}) + @patch("os.path.exists") + @patch("builtins.open", new_callable=mock_open, read_data='{"theme": "dark"}') + @patch("tempfile.mkstemp") + @patch("os.fdopen", new_callable=mock_open) + @patch("os.replace") + def test_settings_deep_merge_atomic_write(self, mock_replace, mock_fdopen, mock_mkstemp, mock_file, mock_exists, mock_stdin): + mock_stdin.read.return_value = json.dumps({ + "requestId": "test-req-456", + "settings": {"defaultBranchName": "main", "confirmRemovedFiles": True}, + "dryRun": False + }) + mock_exists.return_value = True + mock_mkstemp.return_value = (10, "C:\\MockAppData\\GitHub Desktop\\config_tmp.json") + + with patch("sys.stdout") as mock_stdout: + with self.assertRaises(SystemExit) as cm: + plugin.main() + self.assertEqual(cm.exception.code, 0) + output = json.loads(mock_stdout.write.call_args[0][0]) + self.assertEqual(output["requestId"], "test-req-456") + self.assertNotIn("success", output) + self.assertNotIn("data", output) + +if __name__ == "__main__": + unittest.main() + From 4596e15d83104f23f10dedae5e41006715ee4fea Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 12:53:58 +0530 Subject: [PATCH 06/12] refactor(github-desktop): align plugin metadata schema and folder hierarchy (#466) --- plugins/github-desktop/plugin.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 plugins/github-desktop/plugin.yaml diff --git a/plugins/github-desktop/plugin.yaml b/plugins/github-desktop/plugin.yaml new file mode 100644 index 00000000..38e4a946 --- /dev/null +++ b/plugins/github-desktop/plugin.yaml @@ -0,0 +1,7 @@ +name: github-desktop +version: 0.1.0 +type: python +main: src/plugin.py + +capabilities: + - config provider From a8978e96cffe267c18c01eea0aa4c4004cf5797c Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 12:56:42 +0530 Subject: [PATCH 07/12] feat(github-desktop): stage core atomic plugin handler under correct layout path (#466) --- plugins/github-desktop/src/plugin.py | 73 ++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 plugins/github-desktop/src/plugin.py diff --git a/plugins/github-desktop/src/plugin.py b/plugins/github-desktop/src/plugin.py new file mode 100644 index 00000000..8349cf09 --- /dev/null +++ b/plugins/github-desktop/src/plugin.py @@ -0,0 +1,73 @@ +import sys +import os +import json +import tempfile + +def deep_merge(base, update): + if not isinstance(base, dict) or not isinstance(update, dict): + return update + for key, val in update.items(): + if key in base and isinstance(base[key], dict) and isinstance(val, dict): + base[key] = deep_merge(base[key], val) + else: + base[key] = val + return base + +def main(): + raw_input = sys.stdin.read().strip() + if not raw_input: + print(json.dumps({"error": "Empty stdin context payload received"}), file=sys.stderr) + sys.exit(1) + + try: + args = json.loads(raw_input) + except json.JSONDecodeError: + print(json.dumps({"error": "Invalid JSON format payload structure"}), file=sys.stderr) + sys.exit(1) + + request_id = args.get("requestId", "") + + if args.get("check_installed", False): + appdata = os.environ.get("APPDATA", "") + config_path = os.path.join(appdata, "GitHub Desktop", "config.json") if appdata else "" + installed = bool(config_path and os.path.exists(config_path)) + print(json.dumps({"requestId": request_id, "installed": installed})) + sys.exit(0) + + settings = args.get("settings", {}) + dry_run = args.get("dryRun", False) + + appdata = os.environ.get("APPDATA", "") + if not appdata: + print(json.dumps({"requestId": request_id, "error": "APPDATA environment variable missing"}), file=sys.stderr) + sys.exit(1) + + config_dir = os.path.join(appdata, "GitHub Desktop") + config_path = os.path.join(config_dir, "config.json") + + current_config = {} + if os.path.exists(config_path): + try: + with open(config_path, "r", encoding="utf-8") as f: + current_config = json.load(f) + except Exception: + current_config = {} + + updated_config = deep_merge(current_config, settings) + + if not dry_run: + if not os.path.exists(config_dir): + os.makedirs(config_dir, exist_ok=True) + try: + fd, temp_path = tempfile.mkstemp(dir=config_dir, prefix="config_", suffix=".json") + with os.fdopen(fd, "w", encoding="utf-8") as f: + json.dump(updated_config, f, indent=2) + os.replace(temp_path, config_path) + except Exception as e: + print(json.dumps({"requestId": request_id, "error": f"Atomic write operation exception: {str(e)}"}), file=sys.stderr) + sys.exit(1) + + print(json.dumps({"requestId": request_id})) + +if __name__ == "__main__": + main() From 3c1a2cbd71294b89bcf3bb8af0d6f6efa2a01c12 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 12:57:32 +0530 Subject: [PATCH 08/12] test(github-desktop): stage unit test suite under correct layout path (#466) --- .../test/test_github_desktop.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 plugins/github-desktop/test/test_github_desktop.py diff --git a/plugins/github-desktop/test/test_github_desktop.py b/plugins/github-desktop/test/test_github_desktop.py new file mode 100644 index 00000000..8cf25e33 --- /dev/null +++ b/plugins/github-desktop/test/test_github_desktop.py @@ -0,0 +1,64 @@ +import unittest +import json +import sys +import os +from unittest.mock import patch, mock_open + +# Compliance constraint: Leveraging sys.path.append instead of sys.path.insert(0) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src"))) + +import plugin + +class TestGitHubDesktopPlugin(unittest.TestCase): + + @patch("sys.stdin") + @patch("sys.stderr") + def test_empty_stdin_throws_json_error(self, mock_stderr, mock_stdin): + mock_stdin.read.return_value = " " + with self.assertRaises(SystemExit) as cm: + plugin.main() + self.assertEqual(cm.exception.code, 1) + + @patch("sys.stdin") + @patch("os.environ", {"APPDATA": "C:\\MockAppData"}) + @patch("os.path.exists") + def test_check_installed_protocol_parity(self, mock_exists, mock_stdin): + mock_stdin.read.return_value = json.dumps({"requestId": "test-req-123", "check_installed": True}) + mock_exists.return_value = True + + with patch("sys.stdout") as mock_stdout: + with self.assertRaises(SystemExit) as cm: + plugin.main() + self.assertEqual(cm.exception.code, 0) + output = json.loads(mock_stdout.write.call_args) + self.assertEqual(output["requestId"], "test-req-123") + self.assertTrue(output["installed"]) + + @patch("sys.stdin") + @patch("os.environ", {"APPDATA": "C:\\MockAppData"}) + @patch("os.path.exists") + @patch("builtins.open", new_callable=mock_open, read_data='{"theme": "dark"}') + @patch("tempfile.mkstemp") + @patch("os.fdopen", new_callable=mock_open) + @patch("os.replace") + def test_settings_deep_merge_atomic_write(self, mock_replace, mock_fdopen, mock_mkstemp, mock_file, mock_exists, mock_stdin): + mock_stdin.read.return_value = json.dumps({ + "requestId": "test-req-456", + "settings": {"defaultBranchName": "main", "confirmRemovedFiles": True}, + "dryRun": False + }) + mock_exists.return_value = True + mock_mkstemp.return_value = (10, "C:\\MockAppData\\GitHub Desktop\\config_tmp.json") + + with patch("sys.stdout") as mock_stdout: + with self.assertRaises(SystemExit) as cm: + plugin.main() + self.assertEqual(cm.exception.code, 0) + output = json.loads(mock_stdout.write.call_args) + self.assertEqual(output["requestId"], "test-req-456") + self.assertNotIn("success", output) + self.assertNotIn("data", output) + +if __name__ == "__main__": + unittest.main() + From 145ad0d4338b1a9df0fa9a20a21bb850b714911a Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Sun, 21 Jun 2026 13:03:27 +0530 Subject: [PATCH 09/12] Delete github-desktop/plugin.yamlrefactor(github-desktop): purge obsolete misplaced root-level manifest copy (#466) --- github-desktop/plugin.yaml | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 github-desktop/plugin.yaml diff --git a/github-desktop/plugin.yaml b/github-desktop/plugin.yaml deleted file mode 100644 index ab2ef725..00000000 --- a/github-desktop/plugin.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: github-desktop -type: config_provider -description: Manage GitHub Desktop application settings stored in config.json. -supported_os: - - windows -settings: - theme: - type: string - description: UI theme (light, dark, system) - defaultBranchName: - type: string - description: Default branch name for new repos - confirmRemovedFiles: - type: boolean - description: Confirmation on file removal - confirmDiscardChanges: - type: boolean - description: Confirmation on discard - usageStats: - type: boolean - description: Telemetry opt-in/out - signCommits: - type: boolean - description: Sign commits by default - selectedTheme: - type: string - description: Accent/theme selection - externalEditor: - type: string - description: Default external editor config - shell: - type: string - description: Default shell config - hideWhitespaceInStorybook: - type: boolean - description: Whitespace display setting - From ff009f739f1051e488d4006ffc33d88f47992b74 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Tue, 23 Jun 2026 23:28:41 +0530 Subject: [PATCH 10/12] fix(plugin): format capabilities tag string with underscore config_provider (#170) --- plugins/github-desktop/plugin.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-desktop/plugin.yaml b/plugins/github-desktop/plugin.yaml index 38e4a946..a117a658 100644 --- a/plugins/github-desktop/plugin.yaml +++ b/plugins/github-desktop/plugin.yaml @@ -4,4 +4,4 @@ type: python main: src/plugin.py capabilities: - - config provider + - config_provider From 86fe359160f9614700a0d862a986d6d200a79037 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Tue, 23 Jun 2026 23:31:27 +0530 Subject: [PATCH 11/12] Delete src/plugin.pyclean(root): remove duplicate root-level src copy to resolve file path redundancy (#170) --- src/plugin.py | 73 --------------------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 src/plugin.py diff --git a/src/plugin.py b/src/plugin.py deleted file mode 100644 index 8349cf09..00000000 --- a/src/plugin.py +++ /dev/null @@ -1,73 +0,0 @@ -import sys -import os -import json -import tempfile - -def deep_merge(base, update): - if not isinstance(base, dict) or not isinstance(update, dict): - return update - for key, val in update.items(): - if key in base and isinstance(base[key], dict) and isinstance(val, dict): - base[key] = deep_merge(base[key], val) - else: - base[key] = val - return base - -def main(): - raw_input = sys.stdin.read().strip() - if not raw_input: - print(json.dumps({"error": "Empty stdin context payload received"}), file=sys.stderr) - sys.exit(1) - - try: - args = json.loads(raw_input) - except json.JSONDecodeError: - print(json.dumps({"error": "Invalid JSON format payload structure"}), file=sys.stderr) - sys.exit(1) - - request_id = args.get("requestId", "") - - if args.get("check_installed", False): - appdata = os.environ.get("APPDATA", "") - config_path = os.path.join(appdata, "GitHub Desktop", "config.json") if appdata else "" - installed = bool(config_path and os.path.exists(config_path)) - print(json.dumps({"requestId": request_id, "installed": installed})) - sys.exit(0) - - settings = args.get("settings", {}) - dry_run = args.get("dryRun", False) - - appdata = os.environ.get("APPDATA", "") - if not appdata: - print(json.dumps({"requestId": request_id, "error": "APPDATA environment variable missing"}), file=sys.stderr) - sys.exit(1) - - config_dir = os.path.join(appdata, "GitHub Desktop") - config_path = os.path.join(config_dir, "config.json") - - current_config = {} - if os.path.exists(config_path): - try: - with open(config_path, "r", encoding="utf-8") as f: - current_config = json.load(f) - except Exception: - current_config = {} - - updated_config = deep_merge(current_config, settings) - - if not dry_run: - if not os.path.exists(config_dir): - os.makedirs(config_dir, exist_ok=True) - try: - fd, temp_path = tempfile.mkstemp(dir=config_dir, prefix="config_", suffix=".json") - with os.fdopen(fd, "w", encoding="utf-8") as f: - json.dump(updated_config, f, indent=2) - os.replace(temp_path, config_path) - except Exception as e: - print(json.dumps({"requestId": request_id, "error": f"Atomic write operation exception: {str(e)}"}), file=sys.stderr) - sys.exit(1) - - print(json.dumps({"requestId": request_id})) - -if __name__ == "__main__": - main() From b9e8d9bdeb59ebe3756cb63983f777dfcbd80758 Mon Sep 17 00:00:00 2001 From: John Stewartsson J R Date: Tue, 23 Jun 2026 23:32:07 +0530 Subject: [PATCH 12/12] clean(root): remove duplicate root-level test copy to resolve file path redundancy (#170) --- test/test_github_desktop.py | 64 ------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 test/test_github_desktop.py diff --git a/test/test_github_desktop.py b/test/test_github_desktop.py deleted file mode 100644 index 36005004..00000000 --- a/test/test_github_desktop.py +++ /dev/null @@ -1,64 +0,0 @@ -import unittest -import json -import sys -import os -from unittest.mock import patch, mock_open - -# Compliance constraint: Leveraging sys.path.append instead of sys.path.insert(0) -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src"))) - -import plugin - -class TestGitHubDesktopPlugin(unittest.TestCase): - - @patch("sys.stdin") - @patch("sys.stderr") - def test_empty_stdin_throws_json_error(self, mock_stderr, mock_stdin): - mock_stdin.read.return_value = " " - with self.assertRaises(SystemExit) as cm: - plugin.main() - self.assertEqual(cm.exception.code, 1) - - @patch("sys.stdin") - @patch("os.environ", {"APPDATA": "C:\\MockAppData"}) - @patch("os.path.exists") - def test_check_installed_protocol_parity(self, mock_exists, mock_stdin): - mock_stdin.read.return_value = json.dumps({"requestId": "test-req-123", "check_installed": True}) - mock_exists.return_value = True - - with patch("sys.stdout") as mock_stdout: - with self.assertRaises(SystemExit) as cm: - plugin.main() - self.assertEqual(cm.exception.code, 0) - output = json.loads(mock_stdout.write.call_args[0][0]) - self.assertEqual(output["requestId"], "test-req-123") - self.assertTrue(output["installed"]) - - @patch("sys.stdin") - @patch("os.environ", {"APPDATA": "C:\\MockAppData"}) - @patch("os.path.exists") - @patch("builtins.open", new_callable=mock_open, read_data='{"theme": "dark"}') - @patch("tempfile.mkstemp") - @patch("os.fdopen", new_callable=mock_open) - @patch("os.replace") - def test_settings_deep_merge_atomic_write(self, mock_replace, mock_fdopen, mock_mkstemp, mock_file, mock_exists, mock_stdin): - mock_stdin.read.return_value = json.dumps({ - "requestId": "test-req-456", - "settings": {"defaultBranchName": "main", "confirmRemovedFiles": True}, - "dryRun": False - }) - mock_exists.return_value = True - mock_mkstemp.return_value = (10, "C:\\MockAppData\\GitHub Desktop\\config_tmp.json") - - with patch("sys.stdout") as mock_stdout: - with self.assertRaises(SystemExit) as cm: - plugin.main() - self.assertEqual(cm.exception.code, 0) - output = json.loads(mock_stdout.write.call_args[0][0]) - self.assertEqual(output["requestId"], "test-req-456") - self.assertNotIn("success", output) - self.assertNotIn("data", output) - -if __name__ == "__main__": - unittest.main() -