@goodandready/dsh-github-ops 0.3.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Fixed
6
+ - **Cordis Context CWD Guard & SCM Route Exception Shield** (#70, #76): Added `safeCwd(ctx)` helper across routes and tools to prevent `Error: cannot get property "cwd" without inject` when accessing undeclared context properties in Cordis 8+ / DSH 0.2 runtimes. Wrapped SCM HTTP route handler in top-level error handling.
7
+
3
8
  ## 0.3.0
4
9
 
5
10
  ### Features
package/lib/index.js CHANGED
@@ -63,6 +63,14 @@ function makeGitRunner() {
63
63
  }
64
64
  }
65
65
 
66
+ export function safeCwd(ctx) {
67
+ try {
68
+ return (typeof ctx?.cwd === 'string' && ctx.cwd) || process.cwd()
69
+ } catch {
70
+ return process.cwd()
71
+ }
72
+ }
73
+
66
74
  export const name = 'dsh-github-ops'
67
75
  export const inject = ['tools', 'credentials', 'settings']
68
76
 
@@ -279,7 +287,7 @@ export function apply(ctx, rawConfig) {
279
287
  const fallback = cfg.defaultRepository || ''
280
288
  let remoteUrl = ''
281
289
  if (!(explicit && explicit.includes('/')) && !fallback) {
282
- const cwd = (typeof ctx.cwd === 'string' && ctx.cwd) || process.cwd()
290
+ const cwd = safeCwd(ctx)
283
291
  const git = makeGitRunner()
284
292
  const origin = await git(['remote', 'get-url', 'origin'], { cwd })
285
293
  if (origin.code === 0) remoteUrl = origin.stdout.trim()
@@ -375,7 +383,7 @@ export function apply(ctx, rawConfig) {
375
383
  },
376
384
  }
377
385
 
378
- const deps = { tool, asRepo, client, liveConfig, reviewRules, auth: authSeam, defaultCwd: () => (typeof ctx.cwd === 'string' && ctx.cwd) || process.cwd() }
386
+ const deps = { tool, asRepo, client, liveConfig, reviewRules, auth: authSeam, defaultCwd: () => safeCwd(ctx) }
379
387
  registerCoreTools(deps)
380
388
  registerCollabTools(deps)
381
389
  registerOpsTools(deps)
@@ -384,7 +392,7 @@ export function apply(ctx, rawConfig) {
384
392
  registerMirrorTools({
385
393
  tool,
386
394
  git: makeGitRunner(),
387
- defaultCwd: () => (typeof ctx.cwd === 'string' && ctx.cwd) || process.cwd(),
395
+ defaultCwd: () => safeCwd(ctx),
388
396
  })
389
397
 
390
398
  // Background reviews: the host registry when the composition has one, our own records
@@ -454,7 +462,7 @@ export function apply(ctx, rawConfig) {
454
462
  try {
455
463
  const git = makeGitRunner()
456
464
  const readGitState = async () => {
457
- const cwd = (typeof ctx.cwd === 'string' && ctx.cwd) || process.cwd()
465
+ const cwd = safeCwd(ctx)
458
466
  const branch = await git(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd })
459
467
  const remote = await git(['remote', 'get-url', 'origin'], { cwd })
460
468
  const resolved = remote.code === 0
package/lib/routes.js CHANGED
@@ -31,6 +31,14 @@ export const PANEL_PATH = '/dsh-github-ops/panel'
31
31
  * @param deps - resolveToken, client, liveConfig, describeError, makeGitRunner and cacheStats,
32
32
  * injected so this module stays free of the host's own composition.
33
33
  */
34
+ function safeCwd(ctx) {
35
+ try {
36
+ return (typeof ctx?.cwd === 'string' && ctx.cwd) || process.cwd()
37
+ } catch {
38
+ return process.cwd()
39
+ }
40
+ }
41
+
34
42
  export function registerRoutes(ctx, deps = {}) {
35
43
  const {
36
44
  resolveToken = async () => ({ value: '', source: '', guidance: '' }),
@@ -93,6 +101,7 @@ export function registerRoutes(ctx, deps = {}) {
93
101
  kind: 'exact',
94
102
  path: SCM_PATH,
95
103
  handler: async (req, res) => {
104
+ try {
96
105
  if (req.method !== 'GET' && req.method !== 'POST') return sendJson(res, 405, { error: 'method not allowed' })
97
106
  if (req.method === 'POST') {
98
107
  if (!isTrustedWriteRequest(req)) return sendJson(res, 403, { error: 'forbidden' })
@@ -107,7 +116,7 @@ export function registerRoutes(ctx, deps = {}) {
107
116
  // The tab may look at another directory than the session workspace; the value is
108
117
  // validated, must exist and must be a directory.
109
118
  const requested = validateCwd(url.searchParams.get('cwd') || '')
110
- let cwd = (typeof ctx.cwd === 'string' && ctx.cwd) || process.cwd()
119
+ let cwd = safeCwd(ctx)
111
120
  if (requested) {
112
121
  if (!existsSync(requested) || !statSync(requested).isDirectory()) {
113
122
  return sendJson(res, 400, { error: `not a directory: ${requested}` })
@@ -224,6 +233,9 @@ export function registerRoutes(ctx, deps = {}) {
224
233
  worktrees: parseWorktrees(worktreesAnswer.code === 0 ? worktreesAnswer.stdout : ''),
225
234
  merge,
226
235
  }))
236
+ } catch (err) {
237
+ return sendJson(res, 500, { ok: false, error: String((err && err.message) || err) })
238
+ }
227
239
  },
228
240
  })
229
241
  if (typeof wctx.effect === 'function') wctx.effect(register, 'dsh-github-ops: scm route')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-github-ops",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "GitHub operations for DeepSeek Harness: releases, tags, a guarded generic API pass-through, workflow runs, secrets and sanitized mirror publication.",
5
5
  "license": "MIT",
6
6
  "type": "module",