specrails-desktop 2.11.9 → 2.11.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specrails-desktop",
3
- "version": "2.11.9",
3
+ "version": "2.11.10",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -94,22 +94,32 @@ function prepareContractRefineSpawn(deps, conversation) {
94
94
  /* default false */
95
95
  }
96
96
  }
97
- // Relocate-artifacts: when mcp is on, the spawn cwd is the project's spec root,
98
- // which becomes the workspace when relocated (else project.path). When mcp is
99
- // off the explore-cwd is used as before. Env carries SPECRAILS_REPO_DIR for the
100
- // relocated case so source/openspec I/O re-points into the repo.
97
+ // The refine `--resume`s the Explore conversation's session, so it MUST spawn
98
+ // from the SAME cwd the Explore turn used otherwise claude looks in a
99
+ // different per-cwd session store and fails with "No conversation found with
100
+ // session ID …" (the Desktop-tier bug). chat-manager `_resolveSpawnCwd` for an
101
+ // Explore turn uses:
102
+ // - mcp ON → `project.path` (NOT the relocated workspace),
103
+ // - mcp OFF → the app-managed explore-cwd.
104
+ // We mirror that EXACTLY here. The refine uses no file tools (`--disallowedTools
105
+ // Read,Grep,Glob,Bash`) and its prompt rides on `--system-prompt`, so it needs
106
+ // neither the workspace's `.mcp.json` nor its `.claude/commands`. Env still
107
+ // carries SPECRAILS_REPO_DIR when relocated (harmless; no tools consume it).
101
108
  const exec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: deps.projectSlug, path: deps.projectPath });
102
- let cwd = exec.cwd;
103
109
  let env = exec.relocated ? { ...process.env, ...exec.env } : undefined;
104
- if (!mcpEnabled) {
110
+ let cwd;
111
+ if (mcpEnabled) {
112
+ // Match the Explore mcp-on spawn cwd (`this._cwd` = project.path), even when
113
+ // relocated (where exec.cwd would be the workspace ≠ project.path).
114
+ cwd = deps.projectPath;
115
+ }
116
+ else {
105
117
  try {
106
118
  cwd = (0, explore_cwd_manager_1.ensureExploreCwd)({
107
119
  slug: deps.projectSlug,
108
120
  projectPath: deps.projectPath,
109
121
  projectName: deps.projectName,
110
122
  });
111
- // explore-cwd reaches the repo via its own `./project` link; keep the
112
- // relocation env so SPECRAILS_REPO_DIR is still exported when relocated.
113
123
  }
114
124
  catch {
115
125
  cwd = exec.cwd;
@@ -28,6 +28,7 @@ const interactive_job_session_1 = require("./interactive-job-session");
28
28
  const attachment_manager_1 = require("./attachment-manager");
29
29
  const ticket_store_1 = require("./ticket-store");
30
30
  const binary_probe_1 = require("./binary-probe");
31
+ const workspace_manager_1 = require("./workspace-manager");
31
32
  const workspace_resolution_1 = require("./workspace-resolution");
32
33
  const framework_manager_1 = require("./framework-manager");
33
34
  const openspec_shim_1 = require("./openspec-shim");
@@ -976,6 +977,19 @@ class QueueManager {
976
977
  const execution = this._resolveExecution();
977
978
  this._jobExecution.set(jobId, execution);
978
979
  const spawnCwd = execution.cwd;
980
+ // Windows repair: a relocated workspace whose `.claude/agents` was left empty
981
+ // by the broken `current`-junction read during assemble has no sr-* agents,
982
+ // so the implement pipeline can't delegate and runs inline. Self-heal here
983
+ // (per rail spawn) by copying the agents from the real version dir. NO-OP on
984
+ // POSIX (assemble's per-file symlinks already populate them).
985
+ if (execution.relocated) {
986
+ try {
987
+ (0, workspace_manager_1.ensureFrameworkAgents)(execution.cwd, adapter.projectDirName);
988
+ }
989
+ catch {
990
+ /* best-effort — never block a rail spawn on the repair */
991
+ }
992
+ }
979
993
  job.status = 'running';
980
994
  job.startedAt = new Date().toISOString();
981
995
  job.queuePosition = null;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ensureFrameworkAgents = ensureFrameworkAgents;
6
7
  exports.workspacePathFor = workspacePathFor;
7
8
  exports.ensureWorkspace = ensureWorkspace;
8
9
  exports.assembleWorkspaceFramework = assembleWorkspaceFramework;
@@ -12,6 +13,85 @@ const path_1 = __importDefault(require("path"));
12
13
  const framework_manager_1 = require("./framework-manager");
13
14
  const framework_migration_1 = require("./framework-migration");
14
15
  const artifact_registry_1 = require("./artifact-registry");
16
+ /** Highest-first semver-ish sort for framework version dir names. */
17
+ function compareFrameworkVersionDesc(a, b) {
18
+ const pa = a.split('.').map((n) => parseInt(n, 10));
19
+ const pb = b.split('.').map((n) => parseInt(n, 10));
20
+ for (let i = 0; i < 3; i++) {
21
+ const x = pa[i] ?? 0;
22
+ const y = pb[i] ?? 0;
23
+ if (x !== y)
24
+ return y - x;
25
+ }
26
+ return 0;
27
+ }
28
+ /**
29
+ * Windows repair: ensure the workspace's `<providerDir>/agents` holds the
30
+ * framework's `sr-*` agent definitions, copied from the REAL versioned framework
31
+ * dir (`~/.specrails/framework/<version>/<providerDir>/agents`).
32
+ *
33
+ * Why: on Windows the `framework/current` JUNCTION can be untraversable by Node's
34
+ * `fs` ("UNKNOWN: scandir" / "untrusted mount point"); the bundled core's
35
+ * `assemble` sources the agents THROUGH `current`, so `linkAgentFiles` reads
36
+ * nothing and the workspace ends up with NO `sr-*` agents — the implement
37
+ * pipeline then has no sub-agents to delegate to (architect/developer/reviewer)
38
+ * and silently runs everything inline. The versioned dir is a real, traversable
39
+ * directory, so we read it directly. (The proper fix lives in core's `assemble`;
40
+ * this repairs already-broken installs without waiting for a core republish, and
41
+ * mirrors exactly what the fixed core does on Windows — copy from the version
42
+ * dir.) `assemble` never re-runs on a rail spawn, so a workspace broken at setup
43
+ * stays broken; this runs per rail spawn to self-heal it.
44
+ *
45
+ * NO-OP on POSIX (per-file symlinks already populate the workspace correctly;
46
+ * byte-identical). Additive (never touches user `custom-*.md`) + idempotent.
47
+ * Returns the number of agents copied.
48
+ */
49
+ function ensureFrameworkAgents(workspaceDir, providerDir, home) {
50
+ if (process.platform !== 'win32')
51
+ return 0;
52
+ const root = (0, framework_manager_1.frameworkRoot)(home);
53
+ // Resolve the framework version by listing REAL version dirs — NOT via the
54
+ // `current` junction (which is the very thing that may be untraversable here).
55
+ let version;
56
+ try {
57
+ version = fs_1.default
58
+ .readdirSync(root)
59
+ .filter((n) => /^\d+\.\d+\.\d+$/.test(n))
60
+ .sort(compareFrameworkVersionDesc)[0];
61
+ }
62
+ catch {
63
+ return 0;
64
+ }
65
+ if (!version)
66
+ return 0;
67
+ const src = path_1.default.join(root, version, providerDir, 'agents');
68
+ let entries;
69
+ try {
70
+ entries = fs_1.default.readdirSync(src);
71
+ }
72
+ catch {
73
+ return 0; // framework agents not materialized for this provider
74
+ }
75
+ const dest = path_1.default.join(workspaceDir, providerDir, 'agents');
76
+ let copied = 0;
77
+ for (const name of entries) {
78
+ // Framework agents only; never clobber a user/plugin `custom-*.md`.
79
+ if (!name.endsWith('.md') || name.startsWith('custom-'))
80
+ continue;
81
+ const destFile = path_1.default.join(dest, name);
82
+ if (fs_1.default.existsSync(destFile))
83
+ continue;
84
+ try {
85
+ fs_1.default.mkdirSync(dest, { recursive: true });
86
+ fs_1.default.copyFileSync(path_1.default.join(src, name), destFile);
87
+ copied += 1;
88
+ }
89
+ catch {
90
+ /* best-effort per file — one failure must never abort the rail spawn */
91
+ }
92
+ }
93
+ return copied;
94
+ }
15
95
  /**
16
96
  * WorkspaceManager — a reusable materializer for the per-project workspace dir
17
97
  * under `~/.specrails/projects/<slug>/workspace`. This is the relocation target