0
0
Fork 0
Commit graph

3 commits

Author SHA1 Message Date
Karstein Phobic Nyvold Kvistad
e6cfa5730b fix(git_*): persist binding/state with project.save() after every mutating op
Second RTFM remediation. The helpme-codesys.com Git scripting page
(https://content.helpme-codesys.com/en/CODESYS%20Git/_git_using_scripting.html)
says explicitly:

  "Project Save: Call project.save() after operations to persist
   changes. Appears after operations like push() and merge() to
   persist changes."

The example flows on that page show project.save() interleaved with
init / commit / push / merge. None of the git_* wrappers shipped so
far called save(), which means binding info, configured remotes,
upstream tracking, and post-commit state could fail to persist when
the IDE closes -- silently degrading every flow that spans more than
one CODESYS session.

This commit adds a soft-fail primary_project.save() after every
mutating op:

  git_init                    after git.init(...)
  git_commit                  after git.commit_complete(...)
  git_remote_add              after git.remote_add(...)
  git_branch_set_upstream_to  after git.branch_set_upstream_to(...)
  git_push                    after git.push(...)

git_status is unchanged -- it's read-only.

Soft-fail rationale: a save() failure does NOT undo a successful git
op. We log a WARNING and continue, so the visible result still
reflects what actually happened in the repo. Bubbling save errors
would risk telling the user "init failed" when in fact the .git/ is
on disk and the only loss is the in-memory binding. The honest
failure mode is "git op succeeded, persistence may not have."
2026-04-25 20:46:57 +02:00
Karstein Phobic Nyvold Kvistad
3623c45d31 feat(git_*): hard-stop with clear PDE-subscription message on HasGitLicense
The 3 git_* tools previously surfaced the raw CODESYS exception
"Permission denied: Rule 'HasGitLicense' failed with state 'False'."
which is opaque to anyone who does not already know that CODESYS Git
scripting is gated behind the Professional Developer Edition
subscription. Verified 2026-04-25 on this workstation that the
plug-in is installed (PlugIns/GitIntegration.plugin.dll v1.7.0.0,
ScriptDriverGit.plugin.dll, full ScriptLib/Stubs/scriptengine/Git*.pyi
set, and the Git menu visible in the IDE) but the runtime rule still
returns False because no PDE subscription is active. Per the CODESYS
Git store page the subscription is the actual gate (Additional
Requirements / Licensing).

Each script now detects 'HasGitLicense' in the exception or traceback
and rewrites SCRIPT_ERROR to a clean, actionable message pointing at
https://store.codesys.com/en/codesys-git.html with a "what to activate"
hint, falling back to the original generic error formatting on any
non-license failure.

git_status: also adds an early license probe via project.git.has_working_tree()
(license-gated per the SP22 stubs) so the rewrite triggers reliably
instead of being swallowed by the per-method probe loop further down.

Tool descriptions in server.ts updated to advertise the PDE
subscription requirement up front, so MCP clients see it without
having to fail first.
2026-04-25 19:25:58 +02:00
Karstein Phobic Nyvold Kvistad
e236a0cfad feat: add git_status / git_init / git_commit MCP tools (CODESYS Git plug-in)
Cross-references the official Git scripting docs at
https://content.helpme-codesys.com/en/CODESYS%20Git/_git_using_scripting.html
which exposes a project-bound git API as 'primary_project.git' (when the
CODESYS Git plug-in is loaded). Confirmed earlier today via dir(scriptengine)
that 'git' is one of the top-level scriptengine modules on this install.

Three tools in this commit, ordered shallow-to-deep:

  git_status        Read-only. Returns current branch via
                    project.git.branch_show_current() AND a defensive probe
                    of any status/changes/diff/changed_files methods on
                    project.git (the docs page lists the call patterns by
                    example but does not enumerate the full API surface, so
                    the probe + diagnostic dump is how we'll discover the
                    rest in the next iteration).

  git_init          Wraps project.git.init(local_repo_path). Defaults the
                    repo path to the project file's parent directory so a
                    plain 'init this project's folder' call needs no extra
                    args. One-shot setup; pair with git_status afterwards.

  git_commit        Wraps project.git.commit_complete(message, user, mail).
                    Required: message + authorName + authorEmail (latter
                    validated as email by zod). Stages all working-tree
                    changes and commits in one shot per the docs. Multi-line
                    messages handled via triple-quoted Python injection with
                    standard backslash + triple-quote escaping.

Defensive checks across all three:
  - hasattr(script_engine, 'git') so we can distinguish "Git plug-in not
    installed" from "project not in a repo".
  - project.git is None handled with a clear 'run git_init first' message.
  - On missing methods the script dumps sorted(dir(project.git)) so the
    next debug session sees the exact surface.

Out of scope for this commit (deliberate -- one feature per commit per
the project rule, more git ops can land separately):
  - branch ops (branch_copy, checkout)
  - remote ops (remote_add, push, pull, fetch, branch_set_upstream_to)
  - merge
  - clone (script_engine.git.clone -- top-level, not project-bound)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:01:09 +02:00