sase-github 0.2.0__tar.gz → 0.2.2__tar.gz

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 (40) hide show
  1. sase_github-0.2.2/.release-please-manifest.json +3 -0
  2. {sase_github-0.2.0 → sase_github-0.2.2}/CHANGELOG.md +14 -0
  3. {sase_github-0.2.0 → sase_github-0.2.2}/PKG-INFO +1 -1
  4. {sase_github-0.2.0 → sase_github-0.2.2}/README.md +1 -1
  5. {sase_github-0.2.0 → sase_github-0.2.2}/docs/architecture.md +11 -11
  6. {sase_github-0.2.0 → sase_github-0.2.2}/docs/xprompts.md +4 -4
  7. {sase_github-0.2.0 → sase_github-0.2.2}/pyproject.toml +1 -1
  8. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/scripts/new_pr_desc_get_context.py +44 -13
  9. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/workspace_plugin.py +52 -45
  10. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/xprompts/gh.yml +9 -7
  11. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/xprompts/new_pr_desc.yml +3 -3
  12. {sase_github-0.2.0 → sase_github-0.2.2}/tests/test_submit_with_recorded_pr.py +1 -1
  13. {sase_github-0.2.0 → sase_github-0.2.2}/tests/test_workspace_plugin.py +5 -5
  14. sase_github-0.2.0/.release-please-manifest.json +0 -3
  15. {sase_github-0.2.0 → sase_github-0.2.2}/.github/workflows/ci.yml +0 -0
  16. {sase_github-0.2.0 → sase_github-0.2.2}/.github/workflows/pr-title.yml +0 -0
  17. {sase_github-0.2.0 → sase_github-0.2.2}/.github/workflows/publish.yml +0 -0
  18. {sase_github-0.2.0 → sase_github-0.2.2}/.sase_beads/beads.db +0 -0
  19. {sase_github-0.2.0 → sase_github-0.2.2}/.sase_beads/config.json +0 -0
  20. {sase_github-0.2.0 → sase_github-0.2.2}/.sase_beads/issues.jsonl +0 -0
  21. {sase_github-0.2.0 → sase_github-0.2.2}/CLAUDE.md +0 -0
  22. {sase_github-0.2.0 → sase_github-0.2.2}/Justfile +0 -0
  23. {sase_github-0.2.0 → sase_github-0.2.2}/LICENSE +0 -0
  24. {sase_github-0.2.0 → sase_github-0.2.2}/docs/configuration.md +0 -0
  25. {sase_github-0.2.0 → sase_github-0.2.2}/release-please-config.json +0 -0
  26. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/__init__.py +0 -0
  27. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/config.py +0 -0
  28. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/default_config.yml +0 -0
  29. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/errors.py +0 -0
  30. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/plugin.py +0 -0
  31. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/scripts/__init__.py +0 -0
  32. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/scripts/gh_setup.py +0 -0
  33. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/xprompts/pr_diff.yml +0 -0
  34. {sase_github-0.2.0 → sase_github-0.2.2}/src/sase_github/xprompts/prdd.yml +0 -0
  35. {sase_github-0.2.0 → sase_github-0.2.2}/tests/__init__.py +0 -0
  36. {sase_github-0.2.0 → sase_github-0.2.2}/tests/test_ci_install_contract.py +0 -0
  37. {sase_github-0.2.0 → sase_github-0.2.2}/tests/test_config.py +0 -0
  38. {sase_github-0.2.0 → sase_github-0.2.2}/tests/test_github_issues.py +0 -0
  39. {sase_github-0.2.0 → sase_github-0.2.2}/tests/test_github_plugin.py +0 -0
  40. {sase_github-0.2.0 → sase_github-0.2.2}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.2"
3
+ }
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.2](https://github.com/sase-org/sase-github/compare/v0.2.1...v0.2.2) (2026-08-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * adopt Patch terminology in GitHub integration ([bc4fec5](https://github.com/sase-org/sase-github/commit/bc4fec5d436853eb9b839339d855093d13ce83aa))
9
+
10
+ ## [0.2.1](https://github.com/sase-org/sase-github/compare/v0.2.0...v0.2.1) (2026-07-25)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * write handoff diff files under the managed temp root (sase-96.8.5) ([dd5deed](https://github.com/sase-org/sase-github/commit/dd5deedd25aeaccbb984b647c3abf60ea1d5afdc))
16
+
3
17
  ## [0.2.0](https://github.com/sase-org/sase-github/compare/v0.1.7...v0.2.0) (2026-07-16)
4
18
 
5
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sase-github
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: GitHub VCS plugin for sase
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -59,7 +59,7 @@ Requires `sase>=0.11.0` as a dependency. For GitHub Enterprise Server or self-ho
59
59
  ### Workspace Provider
60
60
 
61
61
  - **GitHubWorkspacePlugin** — Workspace provider that handles GitHub-specific workflow orchestration: reference
62
- resolution (repo paths, project names, changespec names), PR submission via `gh pr merge`, branch management, and
62
+ resolution (repo paths, project names, Patch names), PR submission via `gh pr merge`, branch management, and
63
63
  commit description formatting. It also owns GitHub SDD policy: every GitHub project requires a labeled sidecar
64
64
  repository, materialized before `#gh` work starts.
65
65
  - **Repo completion for `#gh:<owner>/` refs** — Supplies repository candidates to SASE prompt completion by calling
@@ -51,7 +51,7 @@ Handles higher-level workflow orchestration. Implements workspace hooks for GitH
51
51
  | `ws_create_sdd_remote()` | Verifies or creates `--sdd`, `--plans`, or `--research` and returns its metadata |
52
52
  | `ws_prepare_mail()` | Displays branch/description and prompts user before pushing |
53
53
  | `ws_format_commit_description()` | Prepends `[project]` prefix to commit messages |
54
- | `ws_submit()` | Submits a ChangeSpec by merging its PR via `gh pr merge --merge --delete-branch` |
54
+ | `ws_submit()` | Submits a Patch by merging its PR via `gh pr merge --merge --delete-branch` |
55
55
 
56
56
  The provider declares `separate_repo` SDD policy. Core supplies a unique staging path; the plugin finds or creates the
57
57
  selected sidecar, ensures its `sase--sdd` label, and clones with the normal SSH/HTTPS fallback. It returns only a
@@ -98,13 +98,13 @@ When the ref matches an existing project directory, `PROJECT_NAME`, or project a
98
98
  - Reads `WORKSPACE_DIR` from the project file
99
99
  - Checks out the default branch
100
100
 
101
- ### Mode 3: ChangeSpec Name
101
+ ### Mode 3: Patch Name
102
102
 
103
- When the ref matches an existing ChangeSpec:
103
+ When the ref matches an existing Patch:
104
104
 
105
- - Searches all changespecs for a matching name
106
- - Reads `WORKSPACE_DIR` from the changespec's project file
107
- - Checks out `origin/<name>` (the ChangeSpec's branch)
105
+ - Searches all Patches for a matching name
106
+ - Reads `WORKSPACE_DIR` from the Patch's project file
107
+ - Checks out `origin/<name>` (the Patch's branch)
108
108
 
109
109
  ## Ref Namespace Completion
110
110
 
@@ -119,14 +119,14 @@ deduplicated case-insensitively, with record-derived spellings preferred when bo
119
119
 
120
120
  ## Submission Flow
121
121
 
122
- When submitting a GitHub ChangeSpec (`ws_submit`):
122
+ When submitting a GitHub Patch (`ws_submit`):
123
123
 
124
- 1. Kill and persist all running processes on the ChangeSpec
125
- 2. Verify no active child ChangeSpecs exist
126
- 3. Claim a workspace and checkout the ChangeSpec branch
124
+ 1. Kill and persist all running processes on the Patch
125
+ 2. Verify no active child Patches exist
126
+ 3. Claim a workspace and checkout the Patch branch
127
127
  4. Check for an existing PR on the branch
128
128
  5. Merge via `gh pr merge --merge --delete-branch`
129
- 6. Finalize submission (update ChangeSpec status)
129
+ 6. Finalize submission (update Patch status)
130
130
  7. Release the workspace
131
131
 
132
132
  ## Config Helper
@@ -14,7 +14,7 @@ the target branch, and captures diffs.
14
14
 
15
15
  | Parameter | Type | Default | Description |
16
16
  |---|---|---|---|
17
- | `gh_ref` | word | (required) | Repo path (`user/project`), project name, or ChangeSpec name |
17
+ | `gh_ref` | word | (required) | Repo path (`user/project`), project name, or Patch name |
18
18
  | `n` | int | `null` | Workspace number override (auto-assigned if null) |
19
19
  | `release` | bool | `true` | Whether to release the workspace when done |
20
20
  | `workflow_label` | word | `null` | Optional label for the workflow |
@@ -41,7 +41,7 @@ the target branch, and captures diffs.
41
41
  # Work on a project by shorthand name
42
42
  #gh(sase) Add a new CLI command for status checking
43
43
 
44
- # Resume work on an existing ChangeSpec
44
+ # Resume work on an existing Patch
45
45
  #gh(fix-auth-bug) Continue implementing the OAuth flow
46
46
 
47
47
  # Work without releasing the workspace
@@ -58,12 +58,12 @@ Generates an AI-written PR title and body from the diff and commits on a branch,
58
58
 
59
59
  | Parameter | Type | Description |
60
60
  |---|---|---|
61
- | `name` | word | ChangeSpec name to generate the description for |
61
+ | `name` | word | Patch name to generate the description for |
62
62
 
63
63
  ### Steps
64
64
 
65
65
  1. **get_context** — Runs a Python script that retrieves the diff, commit history, workspace directory, default branch,
66
- and current branch name for the ChangeSpec.
66
+ and current branch name for the Patch.
67
67
  2. **generate** — Launches a sub-agent with the diff and commits, instructing it to produce a title (conventional
68
68
  commits format, under 72 chars) and a body (markdown with `## Summary` and bullet points).
69
69
  3. **apply** — Looks up the PR for the branch via `gh pr view` and updates it with `gh pr edit` using the generated
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sase-github"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "GitHub VCS plugin for sase"
9
9
  requires-python = ">=3.12"
10
10
  license = "MIT"
@@ -1,26 +1,51 @@
1
1
  """Get context step for the #new_pr_desc xprompt workflow."""
2
2
 
3
+ import os
3
4
  import subprocess
4
5
  import tempfile
6
+ from pathlib import Path
5
7
 
6
- from sase.ace.changespec import find_all_changespecs
7
8
  from sase.workspace_provider.utils import get_default_branch, parse_workspace_dir
8
9
 
10
+ try:
11
+ from sase.ace.patch import find_all_patches
12
+ except ImportError: # Older supported SASE releases expose only ChangeSpec names.
13
+ from sase.ace.changespec import find_all_changespecs as find_all_patches
14
+
15
+ try:
16
+ from sase.core.paths import ( # type: ignore[attr-defined]
17
+ get_sase_managed_tmpdir,
18
+ )
19
+ except ImportError: # sase < 0.11.2 does not ship the helper yet
20
+
21
+ def get_sase_managed_tmpdir(*parts: str) -> str:
22
+ """Fall back to the same managed root the sase helper resolves."""
23
+ sase_tmpdir = os.environ.get("SASE_TMPDIR")
24
+ if sase_tmpdir:
25
+ root = Path(sase_tmpdir).expanduser()
26
+ else:
27
+ sase_home = os.environ.get("SASE_HOME")
28
+ home = Path(sase_home).expanduser() if sase_home else Path.home() / ".sase"
29
+ root = home / "tmp"
30
+ for part in parts:
31
+ root /= part
32
+ root.mkdir(parents=True, exist_ok=True)
33
+ return str(root)
34
+
9
35
 
10
36
  def main(*, name: str) -> None:
11
- """Find changespec, get diff and commit info for PR description generation.
37
+ """Find a Patch, then get diff and commit subjects for PR description generation.
12
38
 
13
39
  Prints key=value output for the workflow executor.
14
40
  """
15
- # Find the ChangeSpec
16
- changespec = None
17
- for cs in find_all_changespecs():
18
- if cs.name == name:
19
- changespec = cs
41
+ patch = None
42
+ for candidate in find_all_patches():
43
+ if candidate.name == name:
44
+ patch = candidate
20
45
  break
21
46
 
22
- if changespec is None:
23
- print(f"error=ChangeSpec '{name}' not found")
47
+ if patch is None:
48
+ print(f"error=Patch '{name}' not found")
24
49
  print("description=")
25
50
  print("diff=")
26
51
  print("workspace_dir=")
@@ -28,7 +53,7 @@ def main(*, name: str) -> None:
28
53
  print("branch_name=")
29
54
  return
30
55
 
31
- project_file = changespec.file_path
56
+ project_file = patch.file_path
32
57
  workspace_dir = parse_workspace_dir(project_file)
33
58
  if not workspace_dir:
34
59
  print("error=WORKSPACE_DIR is not set for this project")
@@ -43,7 +68,7 @@ def main(*, name: str) -> None:
43
68
  default_branch = default_branch_ref.rsplit("/", 1)[-1]
44
69
 
45
70
  # Get description
46
- desc = changespec.description or "No description"
71
+ desc = patch.description or "No description"
47
72
 
48
73
  # Get diff against default branch
49
74
  try:
@@ -71,9 +96,15 @@ def main(*, name: str) -> None:
71
96
  except Exception:
72
97
  commits = ""
73
98
 
74
- # Save diff to temp file for the prompt
99
+ # Save diff to a managed temp file for the prompt. The downstream workflow
100
+ # interpolates this path, so it outlives this process and is reclaimed by
101
+ # the managed temp-root reaper rather than deleted here.
75
102
  diff_file = tempfile.NamedTemporaryFile(
76
- mode="w", suffix=".diff", prefix="pr_desc_", delete=False
103
+ mode="w",
104
+ suffix=".diff",
105
+ prefix="pr_desc_",
106
+ dir=get_sase_managed_tmpdir("gh-diffs"),
107
+ delete=False,
77
108
  )
78
109
  diff_file.write(diff)
79
110
  diff_file.close()
@@ -17,7 +17,17 @@ from collections.abc import Mapping, Sequence
17
17
  from pathlib import Path
18
18
  from typing import TYPE_CHECKING, Any, Literal
19
19
 
20
- from sase.ace.changespec.project_spec_path import preferred_project_spec_path
20
+ try:
21
+ from sase.ace.patch import Patch, find_all_patches
22
+ from sase.ace.patch.project_spec_path import preferred_project_spec_path
23
+ except ImportError: # Older supported SASE releases expose only ChangeSpec names.
24
+ from sase.ace.changespec import ( # type: ignore[no-redef]
25
+ ChangeSpec as Patch,
26
+ find_all_changespecs as find_all_patches,
27
+ )
28
+ from sase.ace.changespec.project_spec_path import ( # type: ignore[no-redef]
29
+ preferred_project_spec_path,
30
+ )
21
31
  from sase.workspace_provider import (
22
32
  ExternalRepoCloneResult,
23
33
  ResolvedRef,
@@ -456,17 +466,18 @@ class GitHubWorkspacePlugin:
456
466
  project_basename: str,
457
467
  console: object | None = None,
458
468
  ) -> tuple[bool, str | None] | None:
459
- """Submit a GitHub ChangeSpec by merging its PR."""
469
+ """Submit a GitHub Patch by merging its PR."""
460
470
  from sase.workspace_provider import detect_workflow_type
461
471
 
462
- vcs_type = detect_workflow_type(changespec_file)
472
+ patch_file = changespec_file
473
+ patch_name = changespec_name
474
+ vcs_type = detect_workflow_type(patch_file)
463
475
  if vcs_type != "gh":
464
476
  return None
465
477
 
466
478
  from rich.console import Console as RichConsole
467
479
  from rich.markup import escape as escape_markup
468
480
 
469
- from sase.ace.changespec import ChangeSpec, find_all_changespecs
470
481
  from sase.ace.hooks.processes import (
471
482
  kill_and_persist_all_running_processes,
472
483
  )
@@ -483,14 +494,13 @@ class GitHubWorkspacePlugin:
483
494
  console if isinstance(console, RichConsole) else None
484
495
  )
485
496
 
486
- # Find the ChangeSpec object
487
- changespec: ChangeSpec | None = None
488
- for cs in find_all_changespecs():
489
- if cs.name == changespec_name:
490
- changespec = cs
497
+ patch: Patch | None = None
498
+ for candidate in find_all_patches():
499
+ if candidate.name == patch_name:
500
+ patch = candidate
491
501
  break
492
- if changespec is None:
493
- return (False, f"ChangeSpec '{changespec_name}' not found")
502
+ if patch is None:
503
+ return (False, f"Patch '{patch_name}' not found")
494
504
 
495
505
  log_fn = (
496
506
  (lambda msg: rich_console.print(f"[cyan]{escape_markup(msg)}[/cyan]"))
@@ -498,31 +508,31 @@ class GitHubWorkspacePlugin:
498
508
  else None
499
509
  )
500
510
  kill_and_persist_all_running_processes(
501
- changespec,
502
- changespec_file,
503
- changespec_name,
511
+ patch,
512
+ patch_file,
513
+ patch_name,
504
514
  "Killed hook running on submitted PR.",
505
515
  log_fn=log_fn,
506
516
  )
507
517
 
508
- all_changespecs = find_all_changespecs()
518
+ all_patches = find_all_patches()
509
519
  if has_active_children(
510
- changespec,
511
- all_changespecs,
520
+ patch,
521
+ all_patches,
512
522
  terminal_statuses=("Submitted", "Reverted", "Archived"),
513
523
  ):
514
524
  return (
515
525
  False,
516
- "Cannot submit: other ChangeSpecs have this one as their "
526
+ "Cannot submit: other Patches have this one as their "
517
527
  "parent and are not Submitted, Reverted, or Archived",
518
528
  )
519
529
 
520
- workspace_dir = parse_workspace_dir(changespec_file)
530
+ workspace_dir = parse_workspace_dir(patch_file)
521
531
  if not workspace_dir:
522
532
  return (False, "WORKSPACE_DIR is not set for this project")
523
533
 
524
- workspace_num = get_first_available_axe_workspace(changespec_file)
525
- workflow_name = f"submit-{changespec_name}"
534
+ workspace_num = get_first_available_axe_workspace(patch_file)
535
+ workflow_name = f"submit-{patch_name}"
526
536
  pid = os.getpid()
527
537
 
528
538
  try:
@@ -534,11 +544,11 @@ class GitHubWorkspacePlugin:
534
544
  rich_console.print(f"[cyan]Claiming workspace #{workspace_num}[/cyan]")
535
545
 
536
546
  if not claim_workspace(
537
- changespec_file,
547
+ patch_file,
538
548
  workspace_num,
539
549
  workflow_name,
540
550
  pid,
541
- changespec_name,
551
+ patch_name,
542
552
  ):
543
553
  return (
544
554
  False,
@@ -548,12 +558,12 @@ class GitHubWorkspacePlugin:
548
558
  try:
549
559
  if rich_console:
550
560
  rich_console.print(
551
- f"[cyan]Checking out {escape_markup(changespec_name)}...[/cyan]"
561
+ f"[cyan]Checking out {escape_markup(patch_name)}...[/cyan]"
552
562
  )
553
563
 
554
564
  provider = get_vcs_provider(ws_dir)
555
565
  branch_name = provider.resolve_revision(
556
- changespec_name, project_basename, ws_dir
566
+ patch_name, project_basename, ws_dir
557
567
  )
558
568
  success, error = provider.checkout(branch_name, ws_dir)
559
569
  if not success:
@@ -564,47 +574,46 @@ class GitHubWorkspacePlugin:
564
574
 
565
575
  if rich_console:
566
576
  rich_console.print(
567
- f"[cyan]Merging {escape_markup(changespec_name)} into "
577
+ f"[cyan]Merging {escape_markup(patch_name)} into "
568
578
  f"{escape_markup(default_branch)}...[/cyan]"
569
579
  )
570
580
 
571
581
  # Prefer the recorded PR URL/number when available — this is
572
582
  # resilient to branch renames (e.g. suffix strip/append).
573
- pr_number = _extract_pr_number(changespec.pr_url)
583
+ pr_number = _extract_pr_number(patch.pr_url)
574
584
  if pr_number:
575
585
  pr_state = _check_pr_state(pr_number, ws_dir)
576
586
  if pr_state == "OPEN":
577
587
  return _submit_via_pr_merge(
578
- changespec, ws_dir, rich_console, pr_number=pr_number
588
+ patch, ws_dir, rich_console, pr_number=pr_number
579
589
  )
580
590
  elif pr_state == "CLOSED":
581
591
  return (
582
592
  False,
583
- f"PR #{pr_number} (from ChangeSpec PR field) is closed "
593
+ f"PR #{pr_number} (from Patch PR field) is closed "
584
594
  "and unmerged. Reopen it or create a new PR with #pr.",
585
595
  )
586
596
  elif pr_state == "MERGED":
587
597
  return (
588
598
  False,
589
- f"PR #{pr_number} (from ChangeSpec PR field) is already "
590
- "merged.",
599
+ f"PR #{pr_number} (from Patch PR field) is already merged.",
591
600
  )
592
601
  # pr_state is None — fall through to branch-based check
593
602
 
594
603
  # Fallback: check for a PR on the current branch
595
604
  has_pr = _check_existing_pr(ws_dir)
596
605
  if has_pr:
597
- return _submit_via_pr_merge(changespec, ws_dir, rich_console)
606
+ return _submit_via_pr_merge(patch, ws_dir, rich_console)
598
607
  return (
599
608
  False,
600
609
  "GitHub project has no PR for this branch. Create a PR first with #pr.",
601
610
  )
602
611
  finally:
603
612
  release_workspace(
604
- changespec_file,
613
+ patch_file,
605
614
  workspace_num,
606
615
  workflow_name,
607
- changespec_name,
616
+ patch_name,
608
617
  )
609
618
  if rich_console:
610
619
  rich_console.print(f"[cyan]Released workspace #{workspace_num}[/cyan]")
@@ -1650,8 +1659,6 @@ def _resolve_existing_named_ref(
1650
1659
  read_only: bool,
1651
1660
  strict: bool,
1652
1661
  ) -> ResolvedRef | None:
1653
- from sase.ace.changespec import find_all_changespecs
1654
-
1655
1662
  projects_base = _projects_base()
1656
1663
  alias_record = _find_project_record_for_alias(
1657
1664
  _list_project_records(projects_base),
@@ -1675,20 +1682,20 @@ def _resolve_existing_named_ref(
1675
1682
  checkout_target=checkout_target,
1676
1683
  )
1677
1684
 
1678
- for cs in find_all_changespecs():
1679
- if cs.name != gh_ref:
1685
+ for patch in find_all_patches():
1686
+ if patch.name != gh_ref:
1680
1687
  continue
1681
- workspace_dir = parse_workspace_dir(cs.file_path)
1688
+ workspace_dir = parse_workspace_dir(patch.file_path)
1682
1689
  if not workspace_dir:
1683
1690
  if strict:
1684
1691
  raise ValueError(
1685
- f"ChangeSpec '{gh_ref}' found in {cs.file_path} "
1692
+ f"Patch '{gh_ref}' found in {patch.file_path} "
1686
1693
  "but WORKSPACE_DIR is not set"
1687
1694
  )
1688
1695
  return None
1689
1696
  return ResolvedRef(
1690
- project_file=cs.file_path,
1691
- project_name=cs.project_basename,
1697
+ project_file=patch.file_path,
1698
+ project_name=patch.project_basename,
1692
1699
  primary_workspace_dir=workspace_dir,
1693
1700
  checkout_target=f"origin/{gh_ref}",
1694
1701
  )
@@ -1717,7 +1724,7 @@ def resolve_gh_ref(gh_ref: str) -> ResolvedRef:
1717
1724
  2. **Project shorthand** (no ``/``, matching project dir): look up
1718
1725
  WORKSPACE_DIR from ``~/.sase/projects/<name>/<name>.sase``
1719
1726
  (with legacy ``.gp`` fallback).
1720
- 3. **ChangeSpec name**: search all changespecs for a matching name,
1727
+ 3. **Patch name**: search all Patches for a matching name,
1721
1728
  read WORKSPACE_DIR from its project file.
1722
1729
 
1723
1730
  Raises:
@@ -1782,7 +1789,7 @@ def _check_existing_pr(cwd: str) -> bool:
1782
1789
 
1783
1790
 
1784
1791
  def _submit_via_pr_merge(
1785
- changespec: object,
1792
+ patch: object,
1786
1793
  ws_dir: str,
1787
1794
  console: object | None,
1788
1795
  *,
@@ -1838,7 +1845,7 @@ def _submit_via_pr_merge(
1838
1845
 
1839
1846
  from sase.workspace_provider.submission_utils import finalize_submission
1840
1847
 
1841
- return finalize_submission(changespec.file_path, changespec.name, console) # type: ignore[attr-defined, arg-type]
1848
+ return finalize_submission(patch.file_path, patch.name, console) # type: ignore[attr-defined, arg-type]
1842
1849
 
1843
1850
 
1844
1851
  def _non_interactive_gh_env(base: Mapping[str, str] | None = None) -> dict[str, str]:
@@ -5,7 +5,7 @@ tags: vcs, rollover
5
5
  input:
6
6
  - name: gh_ref
7
7
  type: word
8
- description: GitHub repo, PR, branch, or ChangeSpec reference to check out.
8
+ description: GitHub repo, PR, branch, or Patch reference to check out.
9
9
  - name: n
10
10
  type: int
11
11
  default: null
@@ -68,14 +68,14 @@ steps:
68
68
  provider = get_vcs_provider(os.getcwd())
69
69
 
70
70
  # Checkout the PR branch so that subsequent diffs are relative to the
71
- # PR tip rather than the default branch. Try checkout_target first
71
+ # PR tip rather than the default branch. Try checkout_target first
72
72
  # (works for default-branch refs like origin/main), then fall back to
73
- # ChangeSpec name -> branch name conversion.
74
- is_changespec = checkout_target == f"origin/{gh_ref}"
73
+ # Patch name -> branch name conversion.
74
+ is_patch = checkout_target == f"origin/{gh_ref}"
75
75
  ok, err = provider.checkout(checkout_target, os.getcwd())
76
76
  if not ok:
77
- if is_changespec:
78
- # ChangeSpec ref — resolve name to branch name
77
+ if is_patch:
78
+ # Patch ref — resolve name to branch name
79
79
  resolved = provider.resolve_revision(
80
80
  gh_ref, project_name, os.getcwd()
81
81
  )
@@ -138,7 +138,9 @@ steps:
138
138
  exit 0
139
139
  fi
140
140
  head_now=$(git rev-parse HEAD)
141
- diff_file=$(mktemp /tmp/sase-gh-XXXXXX.diff)
141
+ diff_dir="${SASE_TMPDIR:-${SASE_HOME:-$HOME/.sase}/tmp}/gh-diffs"
142
+ mkdir -p "$diff_dir"
143
+ diff_file=$(mktemp "$diff_dir/sase-gh-XXXXXX.diff")
142
144
  if [ "$head_now" != "$head_before" ]; then
143
145
  # Commits were made — show only the last commit's diff
144
146
  git diff HEAD~1 HEAD > "$diff_file" 2>/dev/null
@@ -1,9 +1,9 @@
1
- description: Generate and apply a GitHub pull request title and body from a ChangeSpec.
1
+ description: Generate and apply a GitHub pull request title and body from a Patch.
2
2
 
3
3
  input:
4
4
  - name: name
5
5
  type: word
6
- description: ChangeSpec name whose branch and diff should drive the PR description.
6
+ description: Patch name whose branch and diff should drive the PR description.
7
7
 
8
8
  steps:
9
9
  - name: get_context
@@ -24,7 +24,7 @@ steps:
24
24
  agent: |
25
25
  Generate a PR title and body for the following changes.
26
26
 
27
- ## ChangeSpec Description
27
+ ## Patch Description
28
28
  {{ get_context.description }}
29
29
 
30
30
  ## Commits
@@ -1,4 +1,4 @@
1
- """Tests for ws_submit using the recorded PR URL from ChangeSpec.pr_url.
1
+ """Tests for ws_submit using the recorded PR URL from Patch.pr_url.
2
2
 
3
3
  Covers:
4
4
  - _extract_pr_number extracts from GitHub PR URLs
@@ -1914,8 +1914,8 @@ class TestResolveGhRef:
1914
1914
  @patch(
1915
1915
  "sase_github.workspace_plugin.get_default_branch", return_value="origin/main"
1916
1916
  )
1917
- @patch("sase.ace.changespec.find_all_changespecs")
1918
- def test_changespec_name(
1917
+ @patch("sase_github.workspace_plugin.find_all_patches")
1918
+ def test_patch_name(
1919
1919
  self,
1920
1920
  mock_find: MagicMock,
1921
1921
  mock_branch: MagicMock,
@@ -1941,8 +1941,8 @@ class TestResolveGhRef:
1941
1941
  assert result.project_name == "proj"
1942
1942
  assert result.canonical_ref is None
1943
1943
 
1944
- @patch("sase.ace.changespec.find_all_changespecs")
1945
- def test_changespec_no_workspace_dir(self, mock_find: MagicMock) -> None:
1944
+ @patch("sase_github.workspace_plugin.find_all_patches")
1945
+ def test_patch_no_workspace_dir(self, mock_find: MagicMock) -> None:
1946
1946
  with tempfile.NamedTemporaryFile(mode="w", suffix=".sase", delete=False) as f:
1947
1947
  f.write("NAME: my-feature\n")
1948
1948
  f.flush()
@@ -1961,7 +1961,7 @@ class TestResolveGhRef:
1961
1961
  resolve_gh_ref("my-feature")
1962
1962
  os.unlink(f.name)
1963
1963
 
1964
- @patch("sase.ace.changespec.find_all_changespecs", return_value=[])
1964
+ @patch("sase_github.workspace_plugin.find_all_patches", return_value=[])
1965
1965
  def test_not_found(self, mock_find: MagicMock) -> None:
1966
1966
  with patch(
1967
1967
  "sase_github.workspace_plugin.Path.home",
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.2.0"
3
- }
File without changes
File without changes
File without changes
File without changes