opencode-api-security-testing 5.4.2 → 5.4.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +61 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-api-security-testing",
3
- "version": "5.4.2",
3
+ "version": "5.4.3",
4
4
  "description": "API Security Testing Plugin for OpenCode - Automated vulnerability scanning and penetration testing",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -334,9 +334,40 @@ const CYBER_SUPERVISOR = DEFAULT_CONFIG.cyber_supervisor;
334
334
  const modelFailureCounts = new Map<string, Map<string, number>>();
335
335
  const sessionFailures = new Map<string, number>();
336
336
 
337
- // 追踪已注入 agents promptsession (只注入一次)
337
+ // 首条消息追踪 (参考 oh-my-opencodeFirstMessageVariantGate 模式)
338
+ const pendingFirstMessages = new Set<string>();
338
339
  const injectedSessions = new Set<string>();
339
340
 
341
+ // 标记新会话创建(由 event hook 调用)
342
+ function markSessionCreated(sessionID: string | undefined): void {
343
+ if (sessionID) {
344
+ pendingFirstMessages.add(sessionID);
345
+ console.log(`[api-security-testing] Session marked for first message injection: ${sessionID}`);
346
+ }
347
+ }
348
+
349
+ // 检查是否是首条消息(由 chat.message hook 调用)
350
+ function isFirstMessage(sessionID: string | undefined): boolean {
351
+ if (!sessionID) return false;
352
+ return pendingFirstMessages.has(sessionID);
353
+ }
354
+
355
+ // 标记首条消息已处理(由 chat.message hook 调用,注入后立即调用)
356
+ function markFirstMessageApplied(sessionID: string | undefined): void {
357
+ if (sessionID) {
358
+ pendingFirstMessages.delete(sessionID);
359
+ injectedSessions.add(sessionID); // 记录已注入
360
+ }
361
+ }
362
+
363
+ // 清理会话状态(由 event hook 在 session.deleted 时调用)
364
+ function clearSessionState(sessionID: string | undefined): void {
365
+ if (sessionID) {
366
+ pendingFirstMessages.delete(sessionID);
367
+ injectedSessions.delete(sessionID);
368
+ }
369
+ }
370
+
340
371
  function getConfigPath(ctx: { directory: string }): string {
341
372
  return join(ctx.directory, SKILL_DIR, "assets", CONFIG_FILE);
342
373
  }
@@ -1269,11 +1300,24 @@ print(json.dumps(result, ensure_ascii=False))
1269
1300
  },
1270
1301
 
1271
1302
  // 赛博监工 Hook - chat.message
1272
- // 注意:已禁用自动注入 agents prompt,避免重复注入问题
1273
- // 如需使用 agents,请在需要时手动调用相关工具
1303
+ // 参考 oh-my-opencode 的 FirstMessageVariantGate 模式:只在首条消息注入一次
1274
1304
  "chat.message": async (input, output) => {
1275
1305
  const sessionID = input.sessionID;
1276
1306
 
1307
+ // 只在首条消息时注入 agents prompt (参考 oh-my-opencode 的 firstMessageVariantGate)
1308
+ if (isFirstMessage(sessionID)) {
1309
+ const agentsPrompt = getInjectedAgentsPrompt();
1310
+ if (agentsPrompt) {
1311
+ const parts = output.parts as Array<{ type: string; text?: string }>;
1312
+ const textPart = parts.find(p => p.type === "text");
1313
+ if (textPart && textPart.text) {
1314
+ textPart.text += agentsPrompt;
1315
+ }
1316
+ }
1317
+ // 标记该 session 已注入 (参考 oh-my-opencode 的 markApplied)
1318
+ markFirstMessageApplied(sessionID);
1319
+ }
1320
+
1277
1321
  // 赛博监工压力注入(仅在失败时)
1278
1322
  if (config.cyber_supervisor.enabled && config.cyber_supervisor.auto_trigger) {
1279
1323
  const failures = getFailureCount(sessionID);
@@ -1348,10 +1392,22 @@ ${LEVEL_PROMPTS[level]}
1348
1392
  return output;
1349
1393
  },
1350
1394
 
1351
- // 会话清理
1395
+ // 会话事件处理
1352
1396
  event: async (input) => {
1353
1397
  const { event } = input;
1354
1398
 
1399
+ // 新会话创建 - 标记为首条消息待注入 (参考 oh-my-opencode)
1400
+ if (event.type === "session.created") {
1401
+ const props = event.properties as Record<string, unknown> | undefined;
1402
+ const sessionInfo = props?.info as { id?: string; parentID?: string } | undefined;
1403
+ // 只有主会话(非 fork)才注入
1404
+ if (sessionInfo?.id && !sessionInfo.parentID) {
1405
+ markSessionCreated(sessionInfo.id);
1406
+ console.log(`[api-security-testing] New session created: ${sessionInfo.id}`);
1407
+ }
1408
+ }
1409
+
1410
+ // 会话删除或压缩 - 清理状态
1355
1411
  if (event.type === "session.deleted" || event.type === "session.compacted") {
1356
1412
  const props = event.properties as Record<string, unknown> | undefined;
1357
1413
  let sessionID: string | undefined;
@@ -1363,6 +1419,7 @@ ${LEVEL_PROMPTS[level]}
1363
1419
  }
1364
1420
 
1365
1421
  if (sessionID) {
1422
+ clearSessionState(sessionID);
1366
1423
  resetFailureCount(sessionID);
1367
1424
  resetModelFailures(sessionID);
1368
1425
  }