Skip to content

Commit ebd3c60

Browse files
committed
Merge PR darrenhinde#296: fix(plugin): register skills/commands and harden plugin-abilities
2 parents ef3836e + 9e33583 commit ebd3c60

12 files changed

Lines changed: 633 additions & 64 deletions

File tree

packages/plugin-abilities/bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/plugin-abilities/src/executor/execution-manager.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ import { executeAbility } from './index.js'
33

44
/**
55
* Minimal ExecutionManager
6-
*
6+
*
77
* Simplified to track SINGLE execution at a time.
88
* No session management, no cleanup timers, no multi-execution.
9-
*
9+
*
1010
* This is the bare minimum to test the core concept.
1111
*/
1212
export class ExecutionManager {
1313
private activeExecution: AbilityExecution | null = null
14+
private executionHistory: AbilityExecution[] = []
15+
private maxHistory = 50
16+
private abortController: AbortController | null = null
1417

1518
async execute(
1619
ability: Ability,
@@ -23,10 +26,33 @@ export class ExecutionManager {
2326
}
2427

2528
console.log(`[abilities] Starting execution: ${ability.name}`)
26-
27-
const execution = await executeAbility(ability, inputs, ctx)
29+
30+
this.abortController = new AbortController()
31+
32+
// Set activeExecution BEFORE awaiting so getActive() returns a live
33+
// reference during execution (needed for chat-context injection and
34+
// concurrent-execution guards).
35+
this.activeExecution = {
36+
id: `exec_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
37+
ability,
38+
inputs,
39+
status: 'running',
40+
currentStep: null,
41+
currentStepIndex: -1,
42+
completedSteps: [],
43+
pendingSteps: [...ability.steps],
44+
startedAt: Date.now(),
45+
}
46+
47+
const execution = await executeAbility(ability, inputs, ctx, this.abortController.signal)
2848
this.activeExecution = execution
2949

50+
// Track in history
51+
this.executionHistory.push(execution)
52+
if (this.executionHistory.length > this.maxHistory) {
53+
this.executionHistory = this.executionHistory.slice(-this.maxHistory)
54+
}
55+
3056
// Clear active if completed/failed
3157
if (execution.status !== 'running') {
3258
this.activeExecution = null
@@ -35,14 +61,24 @@ export class ExecutionManager {
3561
return execution
3662
}
3763

64+
get(id: string): AbilityExecution | undefined {
65+
return this.executionHistory.find((e) => e.id === id)
66+
}
67+
68+
list(): AbilityExecution[] {
69+
return [...this.executionHistory]
70+
}
71+
3872
getActive(): AbilityExecution | null {
3973
return this.activeExecution
4074
}
4175

4276
cancel(): boolean {
4377
if (!this.activeExecution) return false
44-
78+
4579
if (this.activeExecution.status === 'running') {
80+
this.abortController?.abort()
81+
this.abortController = null
4682
this.activeExecution.status = 'failed'
4783
this.activeExecution.error = 'Cancelled by user'
4884
this.activeExecution.completedAt = Date.now()
@@ -53,7 +89,24 @@ export class ExecutionManager {
5389
return false
5490
}
5591

92+
cancelActive(): boolean {
93+
return this.cancel()
94+
}
95+
96+
onSessionDeleted(sessionId: string): void {
97+
if (this.activeExecution && this.activeExecution.status === 'running') {
98+
this.abortController?.abort()
99+
this.abortController = null
100+
this.activeExecution.status = 'failed'
101+
this.activeExecution.error = `Session ${sessionId} deleted`
102+
this.activeExecution.completedAt = Date.now()
103+
this.activeExecution = null
104+
}
105+
}
106+
56107
cleanup(): void {
108+
this.abortController?.abort()
109+
this.abortController = null
57110
this.activeExecution = null
58111
}
59112
}

0 commit comments

Comments
 (0)