@cjhyy/code-shell-core 0.8.5 → 0.8.6

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.
@@ -62,11 +62,15 @@ export interface CronJob {
62
62
  * job_error carries the message `fire()` would otherwise swallow.
63
63
  */
64
64
  export interface CronJobLifecycleEvent {
65
- type: "job_start" | "job_end" | "job_stopped" | "job_cancelled" | "job_error";
65
+ type: "job_start" | "job_end" | "job_stopped" | "job_cancelled" | "job_error" | "job_missed";
66
66
  job: CronJob;
67
67
  durationMs?: number;
68
68
  reason?: string;
69
69
  error?: string;
70
+ /** Planned wall-clock instant that was skipped after the host woke too late. */
71
+ scheduledFor?: number;
72
+ /** Time the scheduler observed the skipped occurrence. */
73
+ observedAt?: number;
70
74
  }
71
75
  /** Optional semantic outcome returned by an executor after a non-throwing run. */
72
76
  export interface CronExecutionOutcome {
@@ -128,10 +132,10 @@ export declare class CronScheduler {
128
132
  setStore(store: CronStore): void;
129
133
  setExecutor(fn: (job: CronJob, signal: AbortSignal) => Promise<void | CronExecutionOutcome>): void;
130
134
  /**
131
- * Observe job execution lifecycle
132
- * (job_start job_end | job_stopped | job_cancelled | job_error). Hosts
133
- * wire this to their notification surface so scheduled runs — especially
134
- * failures, which `fire()` otherwise swallows — are no longer silent.
135
+ * Observe job execution lifecycle. A real execution emits job_start followed
136
+ * by one terminal event; a sleep/wake skip emits job_missed without pretending
137
+ * the job started. Hosts wire this to their notification surface so failures
138
+ * and intentionally skipped occurrences are no longer silent.
135
139
  * Listener errors are swallowed; observation never affects scheduling.
136
140
  */
137
141
  setJobEventListener(listener: ((event: CronJobLifecycleEvent) => void) | undefined): void;
@@ -88,10 +88,10 @@ export class CronScheduler {
88
88
  this.onExecute = fn;
89
89
  }
90
90
  /**
91
- * Observe job execution lifecycle
92
- * (job_start job_end | job_stopped | job_cancelled | job_error). Hosts
93
- * wire this to their notification surface so scheduled runs — especially
94
- * failures, which `fire()` otherwise swallows — are no longer silent.
91
+ * Observe job execution lifecycle. A real execution emits job_start followed
92
+ * by one terminal event; a sleep/wake skip emits job_missed without pretending
93
+ * the job started. Hosts wire this to their notification surface so failures
94
+ * and intentionally skipped occurrences are no longer silent.
95
95
  * Listener errors are swallowed; observation never affects scheduling.
96
96
  */
97
97
  setJobEventListener(listener) {
@@ -167,6 +167,14 @@ export class CronScheduler {
167
167
  if (Number.isFinite(n) && n > maxId)
168
168
  maxId = n;
169
169
  if (!prev) {
170
+ const observedAt = Date.now();
171
+ const missedWhileStopped = arm &&
172
+ this.executionEnabled &&
173
+ job.enabled &&
174
+ typeof job.nextRun === "number" &&
175
+ isCronMisfire(job.nextRun, observedAt)
176
+ ? job.nextRun
177
+ : undefined;
170
178
  this.jobs.set(job.id, job);
171
179
  if (arm && job.enabled) {
172
180
  this.arm(job);
@@ -174,6 +182,15 @@ export class CronScheduler {
174
182
  else {
175
183
  this.refreshNextRunForDisplay(job);
176
184
  }
185
+ if (missedWhileStopped !== undefined) {
186
+ this.persistRunStats(job);
187
+ this.emitJobEvent({
188
+ type: "job_missed",
189
+ job,
190
+ scheduledFor: missedWhileStopped,
191
+ observedAt,
192
+ });
193
+ }
177
194
  continue;
178
195
  }
179
196
  const definitionChanged = this.jobDefinitionChanged(prev, job);
@@ -600,8 +617,11 @@ export class CronScheduler {
600
617
  // Interval jobs get the same misfire semantics cron already had: if we
601
618
  // wake far PAST the target (host slept through it), skip this occurrence
602
619
  // and re-arm on the next absolute slot instead of firing late.
603
- if (isCronMisfire(scheduledFor, Date.now())) {
620
+ const observedAt = Date.now();
621
+ if (isCronMisfire(scheduledFor, observedAt)) {
604
622
  rearm();
623
+ this.persistRunStats(job);
624
+ this.emitJobEvent({ type: "job_missed", job, scheduledFor, observedAt });
605
625
  return;
606
626
  }
607
627
  void this.fire(job, rearm).then((ran) => {
@@ -636,9 +656,12 @@ export class CronScheduler {
636
656
  // resume). If we wake too far PAST the scheduled instant, this is a
637
657
  // misfire: skip running and re-arm to the next correct occurrence rather
638
658
  // than running at the wrong time.
639
- if (isCronMisfire(scheduledFor, Date.now())) {
659
+ const observedAt = Date.now();
660
+ if (isCronMisfire(scheduledFor, observedAt)) {
640
661
  if (job.enabled)
641
662
  this.armCron(job);
663
+ this.persistRunStats(job);
664
+ this.emitJobEvent({ type: "job_missed", job, scheduledFor, observedAt });
642
665
  return;
643
666
  }
644
667
  const rearm = () => {
@@ -1956,7 +1956,11 @@ export class Engine {
1956
1956
  disabledPlugins,
1957
1957
  skillAllowlist: this.config.skillAllowlist,
1958
1958
  memoriesMaxAgeDays: this.readMemoriesConfig()?.maxAge,
1959
- goalToolState: { hasGoal: hasRunnableGoal },
1959
+ goalToolState: !profile?.allowedToolNames ||
1960
+ profile.allowedToolNames.has("complete_goal") ||
1961
+ profile.allowedToolNames.has("cancel_goal")
1962
+ ? { hasGoal: hasRunnableGoal }
1963
+ : undefined,
1960
1964
  capabilityPromptSections: this.capabilityPromptSections,
1961
1965
  dynamicContextProviders: this.capabilityDynamicContextProviders,
1962
1966
  getSettingsManager: () => this.getSettingsManager(),
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Public API exports.
5
5
  */
6
- export declare const VERSION = "0.8.5";
6
+ export declare const VERSION = "0.8.6";
7
7
  export type { Message, ContentBlock, ToolDefinition, ToolCall, ToolResult, RegisteredTool, TranscriptEvent, TranscriptEventType, SessionState, SessionKind, SessionWorkspace, SessionForkLineage, ContextUsageAnchor, SessionStatus, TokenUsage, CompiledInput, PermissionDecision, PermissionMode, PermissionRule, TurnPhase, TurnResult, TerminalReason, TurnCompletionKind, StreamEvent, StreamCallback, LLMConfig, ClientDefaults, LLMResponse, Settings, MCPServerConfig, } from "./types.js";
8
8
  export type { GoalConfig, GoalLifecycleConfig, GoalLifecyclePhase, GoalLifecycleTerminalReason, GoalLifecycleV1, } from "./goal/lifecycle.js";
9
9
  export { FrameworkError, LLMError, LLMRateLimitError, ContextLimitError, ToolError, ToolNotFoundError, ToolExecutionError, ToolTimeoutError, PermissionDeniedError, SessionError, TranscriptError, ConfigError, SandboxUnavailableError, } from "./exceptions.js";
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Public API exports.
5
5
  */
6
- export const VERSION = "0.8.5";
6
+ export const VERSION = "0.8.6";
7
7
  // ─── Exceptions ──────────────────────────────────────────────────
8
8
  export { FrameworkError, LLMError, LLMRateLimitError, ContextLimitError, ToolError, ToolNotFoundError, ToolExecutionError, ToolTimeoutError, PermissionDeniedError, SessionError, TranscriptError, ConfigError, SandboxUnavailableError, } from "./exceptions.js";
9
9
  // ─── Engine (primary API) ────────────────────────────────────────
@@ -134,8 +134,8 @@ export class PromptComposer {
134
134
  if (!this.options.goalToolState)
135
135
  return "";
136
136
  return this.options.goalToolState.hasGoal
137
- ? "当前存在 active goal。只有在目标完全完成时才可调用 complete_goal;只有用户明确要求取消/停止/放弃该目标时才可调用 cancel_goal"
138
- : "当前没有 active goal。不要调用 complete_goal/cancel_goal;如果误调用,系统会拒绝。";
137
+ ? "Goal 工具状态:本会话存在一个持久 Goal。只有在该 Goal 完全完成时才可调用 complete_goal;只有用户明确要求取消/停止/放弃该 Goal 时才可调用 cancel_goal。此状态不代表后台任务或其他 Session 的运行状态,不要把它改写成系统是否空闲。"
138
+ : "Goal 工具状态:本会话没有持久 Goal,因此不要调用 complete_goal/cancel_goal;如果误调用,系统会拒绝。这只描述 Goal 工具的可用状态,不代表没有后台任务、没有运行中的 Session 或系统正在待命,也不要向用户复述为任务状态。";
139
139
  }
140
140
  invalidateCache(sectionName) {
141
141
  this.sectionCache.invalidate(sectionName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cjhyy/code-shell-core",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "description": "Core engine for code-shell — agent orchestration, tool execution, hooks, protocol. UI-agnostic.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",