@goodandready/dsh-cron 0.3.16 → 0.3.18

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/lib/cron-tool.js CHANGED
@@ -152,6 +152,10 @@ export const cronToolParameters = {
152
152
  enum: ['default', 'read-only', 'workspace-write', 'full'],
153
153
  description: 'Permission preset applied to the task session (only used for agent session tasks: llm, skill, workflow)',
154
154
  },
155
+ sessionTitle: {
156
+ type: 'string',
157
+ description: 'Custom session title template for isolated agent runs (supports {{date}} placeholder, e.g. "{{date}} [Daily] Report")',
158
+ },
155
159
  requireApproval: {
156
160
  type: 'boolean',
157
161
  description: 'Require explicit human approval before execution (#318)',
package/lib/http-utils.js CHANGED
@@ -78,10 +78,16 @@ export function parseJsonBody(req, limit = MAX_BODY_BYTES) {
78
78
 
79
79
  /**
80
80
  * Safe helper to get the DSH connection service from context or request (#357).
81
+ * Defensively degrades when context is a Cordis proxy throwing without inject (#366, GH #13).
81
82
  */
82
83
  export function getConnection(ctx) {
83
84
  if (!ctx) return null;
84
- return Reflect.get(ctx, 'connection') || ctx.connection || null;
85
+ try {
86
+ return Reflect.get(ctx, 'connection') || ctx.connection || null;
87
+ } catch (_err) {
88
+ // Degrade gracefully if context is a Cordis proxy throwing without inject (GH #13)
89
+ return null;
90
+ }
85
91
  }
86
92
 
87
93
  export function getDshConnection(req, options = {}) {
package/lib/runner.js CHANGED
@@ -38,15 +38,19 @@ export {
38
38
  * Resolves the effective target session ID taking into account rotation policies (#143).
39
39
  * Supports {{date}} interpolation, 'daily' rotation (adds -YYYY-MM-DD), and 'weekly' rotation (-YYYY-Www).
40
40
  */
41
+ export function formatDateYmd(date = new Date()) {
42
+ const yyyy = date.getFullYear();
43
+ const mm = String(date.getMonth() + 1).padStart(2, '0');
44
+ const dd = String(date.getDate()).padStart(2, '0');
45
+ return `${yyyy}-${mm}-${dd}`;
46
+ }
47
+
41
48
  export function resolveTargetSessionId(targetSessionId, resetPolicy = 'never', date = new Date()) {
42
49
  if (!targetSessionId || typeof targetSessionId !== 'string') return null;
43
50
  let baseId = targetSessionId.trim();
44
51
  if (!baseId) return null;
45
52
 
46
- const yyyy = date.getFullYear();
47
- const mm = String(date.getMonth() + 1).padStart(2, '0');
48
- const dd = String(date.getDate()).padStart(2, '0');
49
- const yyyymmdd = `${yyyy}-${mm}-${dd}`;
53
+ const yyyymmdd = formatDateYmd(date);
50
54
 
51
55
  if (baseId.includes('{{date}}')) {
52
56
  return baseId.replaceAll('{{date}}', yyyymmdd);
@@ -282,8 +286,11 @@ export class SessionRunner {
282
286
  /** Legacy session service path; falls back to the bare report. */
283
287
  async _runLegacySession(task) {
284
288
  try {
289
+ const ymd = formatDateYmd();
290
+ const explicit = task.sessionTitle ? String(task.sessionTitle).trim().replaceAll('{{date}}', ymd) : '';
291
+ const legacyTitle = explicit || `[Cron] ${ymd} ${task.title}`;
285
292
  const session = await this.ctx.session.create({
286
- title: `[Cron] ${task.title}`,
293
+ title: legacyTitle,
287
294
  ephemeral: task.delivery === 'isolated',
288
295
  });
289
296
  if (session && typeof session.send === 'function') {
@@ -659,13 +666,22 @@ export class SessionRunner {
659
666
 
660
667
  const explicitTitle = task.sessionTitle ? String(task.sessionTitle).trim() : '';
661
668
  const taskTitle = task.title ? String(task.title).trim() : '';
662
- const label = explicitTitle || (taskTitle.startsWith('[') ? taskTitle : '');
669
+ const ymd = formatDateYmd();
670
+
671
+ let label = '';
672
+ if (explicitTitle) {
673
+ label = explicitTitle.replaceAll('{{date}}', ymd);
674
+ } else if (taskTitle.startsWith('[')) {
675
+ label = taskTitle.replaceAll('{{date}}', ymd);
676
+ } else if (taskTitle) {
677
+ label = `${ymd} ${taskTitle}`;
678
+ }
663
679
 
664
- if (!label) return;
680
+ if (!label.trim()) return;
665
681
  if (isResumed && !explicitTitle) return;
666
682
 
667
- sessionTitle.rename(session, label);
668
- logger.info(`[dsh-cron] assigned session title "${label}" for session ${session.id}`);
683
+ sessionTitle.rename(session, label.trim());
684
+ logger.info(`[dsh-cron] assigned session title "${label.trim()}" for session ${session.id}`);
669
685
  } catch (titleErr) {
670
686
  logger.debug?.(`[dsh-cron] could not rename session ${session?.id}: ${titleErr.message}`);
671
687
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-cron",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Background automation runner for DSH: isolated agent runs, script/HTTP/SSH/Docker runtimes, cost guard, notifications, heartbeats.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",