@syntesseraai/opencode-feature-factory 0.1.15 → 0.1.17
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 +1 -1
- package/src/discovery.ts +0 -2
- package/src/index.ts +0 -6
- package/src/quality-gate-config.ts +0 -2
- package/src/stop-quality-gate.ts +13 -27
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@syntesseraai/opencode-feature-factory",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.17",
|
|
5
5
|
"description": "OpenCode plugin for Feature Factory agents - provides planning, implementation, review, testing, and validation agents",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
package/src/discovery.ts
CHANGED
|
@@ -6,8 +6,6 @@ import {
|
|
|
6
6
|
readJsonFile,
|
|
7
7
|
} from './quality-gate-config';
|
|
8
8
|
|
|
9
|
-
// Shell type - uses `any` to be compatible with OpenCode's BunShell
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
9
|
type BunShell = any;
|
|
12
10
|
|
|
13
11
|
// ============================================================================
|
package/src/index.ts
CHANGED
|
@@ -100,17 +100,11 @@ function mergeHooks(...hookSets: Partial<Hooks>[]): Hooks {
|
|
|
100
100
|
|
|
101
101
|
const existingHandler = merged[key as keyof Hooks];
|
|
102
102
|
if (existingHandler) {
|
|
103
|
-
// Chain handlers - run existing first, then new
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
103
|
merged[key as keyof Hooks] = (async (...args: any[]) => {
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
104
|
await (existingHandler as (...args: any[]) => Promise<void>)(...args);
|
|
108
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
105
|
await (handler as (...args: any[]) => Promise<void>)(...args);
|
|
110
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
106
|
}) as any;
|
|
112
107
|
} else {
|
|
113
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114
108
|
merged[key as keyof Hooks] = handler as any;
|
|
115
109
|
}
|
|
116
110
|
}
|
package/src/stop-quality-gate.ts
CHANGED
|
@@ -8,6 +8,7 @@ interface SessionState {
|
|
|
8
8
|
dirty: boolean;
|
|
9
9
|
qualityGatePassed: boolean;
|
|
10
10
|
idleDebounce: ReturnType<typeof setTimeout> | null;
|
|
11
|
+
running: boolean;
|
|
11
12
|
parentID?: string;
|
|
12
13
|
isReadOnly?: boolean;
|
|
13
14
|
}
|
|
@@ -23,6 +24,7 @@ function getSessionState(sessionId: string): SessionState {
|
|
|
23
24
|
dirty: true,
|
|
24
25
|
qualityGatePassed: false,
|
|
25
26
|
idleDebounce: null,
|
|
27
|
+
running: false,
|
|
26
28
|
};
|
|
27
29
|
sessions.set(sessionId, state);
|
|
28
30
|
return state;
|
|
@@ -75,7 +77,7 @@ export async function createQualityGateHooks(input: PluginInput): Promise<Partia
|
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
async function
|
|
80
|
+
async function _ensureSessionMetadata(sessionId: string, state: SessionState): Promise<void> {
|
|
79
81
|
if (state.isReadOnly !== undefined) return;
|
|
80
82
|
|
|
81
83
|
try {
|
|
@@ -104,6 +106,11 @@ export async function createQualityGateHooks(input: PluginInput): Promise<Partia
|
|
|
104
106
|
return;
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
if (state.running) {
|
|
110
|
+
await log(client, 'debug', 'quality-gate.skipped (already running)', { sessionId });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
const now = Date.now();
|
|
108
115
|
const cacheExpired = now - state.lastRunAt > 30 * 1000;
|
|
109
116
|
|
|
@@ -119,19 +126,9 @@ export async function createQualityGateHooks(input: PluginInput): Promise<Partia
|
|
|
119
126
|
return;
|
|
120
127
|
}
|
|
121
128
|
|
|
122
|
-
|
|
129
|
+
state.running = true;
|
|
123
130
|
|
|
124
|
-
await client.
|
|
125
|
-
path: { id: sessionId },
|
|
126
|
-
body: {
|
|
127
|
-
parts: [
|
|
128
|
-
{
|
|
129
|
-
type: 'text',
|
|
130
|
-
text: `🔄 Quality gate is running, please stand-by for results ...`,
|
|
131
|
-
},
|
|
132
|
-
],
|
|
133
|
-
},
|
|
134
|
-
});
|
|
131
|
+
await log(client, 'info', 'quality-gate.started', { sessionId, directory });
|
|
135
132
|
|
|
136
133
|
let ciOutput = '';
|
|
137
134
|
let ciPassed = false;
|
|
@@ -150,21 +147,9 @@ export async function createQualityGateHooks(input: PluginInput): Promise<Partia
|
|
|
150
147
|
state.lastRunAt = Date.now();
|
|
151
148
|
state.dirty = false;
|
|
152
149
|
state.qualityGatePassed = ciPassed;
|
|
150
|
+
state.running = false;
|
|
153
151
|
|
|
154
|
-
if (ciPassed) {
|
|
155
|
-
await client.session.prompt({
|
|
156
|
-
path: { id: sessionId },
|
|
157
|
-
body: {
|
|
158
|
-
parts: [
|
|
159
|
-
{
|
|
160
|
-
type: 'text',
|
|
161
|
-
text: `✅ Quality gate passed`,
|
|
162
|
-
},
|
|
163
|
-
],
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
await log(client, 'debug', 'quality-gate.passed', { sessionId });
|
|
167
|
-
} else {
|
|
152
|
+
if (!ciPassed) {
|
|
168
153
|
await client.session.prompt({
|
|
169
154
|
path: { id: sessionId },
|
|
170
155
|
body: {
|
|
@@ -201,6 +186,7 @@ export async function createQualityGateHooks(input: PluginInput): Promise<Partia
|
|
|
201
186
|
dirty: true,
|
|
202
187
|
qualityGatePassed: false,
|
|
203
188
|
idleDebounce: null,
|
|
189
|
+
running: false,
|
|
204
190
|
parentID: sessionInfo?.parentID,
|
|
205
191
|
isReadOnly,
|
|
206
192
|
});
|