@defend-tech/opencode-optima 0.1.20 → 0.1.21

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/dist/index.js CHANGED
@@ -9255,8 +9255,10 @@ async function openCodeSessionExists(client, sessionId) {
9255
9255
  }
9256
9256
  return false;
9257
9257
  }
9258
- async function createOpenCodeSession(client, { title, directory } = {}) {
9259
- const result = await client.session.create({ query: { directory }, body: { title } });
9258
+ async function createOpenCodeSession(client, { title, directory, agent } = {}) {
9259
+ const body = { title };
9260
+ if (agent) body.agent = agent;
9261
+ const result = await client.session.create({ query: { directory }, body });
9260
9262
  return result?.data?.id || result?.id;
9261
9263
  }
9262
9264
  function assertOpenCodePromptAccepted(result) {
@@ -9293,35 +9295,21 @@ async function sendOpenCodeSessionEventDirect({ baseUrl, sessionId, text, fetchI
9293
9295
  if (!data?.data?.id) throw new Error("OpenCode prompt response did not include data.id.");
9294
9296
  return { ok: true, method: "http", status: response.status, data: data.data, response: data };
9295
9297
  }
9296
- async function callOpenCodePromptWithFallbacks(method, sessionId, flatPayload, structuredPayload) {
9297
- const attempts = [
9298
- { id: sessionId, ...flatPayload },
9299
- { sessionID: sessionId, ...flatPayload },
9300
- { ...structuredPayload, path: { sessionID: sessionId } },
9301
- { ...structuredPayload, path: { id: sessionId } }
9302
- ];
9303
- let firstError = null;
9304
- for (const attempt of attempts) {
9305
- try {
9306
- return assertOpenCodePromptAccepted(await method(attempt));
9307
- } catch (error) {
9308
- firstError ??= error;
9309
- }
9310
- }
9311
- throw firstError;
9312
- }
9313
- async function sendOpenCodeSessionEvent(client, { sessionId, agent, text, directory, opencodeBaseUrl, baseUrl, fetchImpl } = {}) {
9298
+ async function sendOpenCodeSessionEvent(client, { sessionId, agent, text, directory, opencodeBaseUrl, baseUrl, fetchImpl, direct = false } = {}) {
9314
9299
  const directBaseUrl = opencodeBaseUrl || baseUrl;
9315
- if (directBaseUrl) return sendOpenCodeSessionEventDirect({ baseUrl: directBaseUrl, sessionId, text, fetchImpl });
9316
9300
  const parts = [{ type: "text", text }];
9317
- const flatPayload = { directory, agent, parts };
9318
- const structuredPayload = { query: { directory }, body: { agent, parts } };
9319
- if (typeof client?.session?.prompt === "function") {
9320
- return callOpenCodePromptWithFallbacks(client.session.prompt.bind(client.session), sessionId, flatPayload, structuredPayload);
9301
+ const structuredPayload = {
9302
+ path: { id: sessionId },
9303
+ query: { directory },
9304
+ body: { agent, parts }
9305
+ };
9306
+ if (!direct && typeof client?.session?.promptAsync === "function") {
9307
+ return assertOpenCodePromptAccepted(await client.session.promptAsync(structuredPayload));
9321
9308
  }
9322
- if (typeof client?.session?.promptAsync === "function") {
9323
- return callOpenCodePromptWithFallbacks(client.session.promptAsync.bind(client.session), sessionId, flatPayload, structuredPayload);
9309
+ if (!direct && typeof client?.session?.prompt === "function") {
9310
+ return assertOpenCodePromptAccepted(await client.session.prompt(structuredPayload));
9324
9311
  }
9312
+ if (directBaseUrl) return sendOpenCodeSessionEventDirect({ baseUrl: directBaseUrl, sessionId, text, fetchImpl });
9325
9313
  throw new Error("OpenCode client does not expose session.prompt or session.promptAsync.");
9326
9314
  }
9327
9315
  function formatClickUpWebhookPrompt({ eventType, taskId, payload }) {
@@ -9550,7 +9538,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
9550
9538
  if (!existingSessionId) {
9551
9539
  let pendingSessionId = getNestedMetadataValue(metadata, clickUpPendingSessionKey(config.routing.metadataKey)) || state.pendingSessions?.[taskId];
9552
9540
  if (!pendingSessionId) {
9553
- pendingSessionId = await createSession(openCodeClient, { title: `ClickUp PM: ${taskId}`, directory: config.basePath });
9541
+ pendingSessionId = await createSession(openCodeClient, { title: `ClickUp PM: ${taskId}`, directory: config.basePath, agent: config.routing.targetAgent });
9554
9542
  if (!String(pendingSessionId || "").startsWith("ses_")) return { ok: false, action: "error", reason: "session_create_failed", taskId };
9555
9543
  if (saveState) {
9556
9544
  saveState({
@@ -10604,9 +10592,21 @@ function getModePromptFragment(agentId, operatingTeamMode, worktree) {
10604
10592
  if (!fragmentPath) return "";
10605
10593
  return readResolvedFile(fragmentPath, worktree, { preferCompactPromptDocs: true });
10606
10594
  }
10595
+ function isSameOrNestedPath(candidate, root) {
10596
+ if (typeof candidate !== "string" || typeof root !== "string" || !candidate.trim() || !root.trim()) return false;
10597
+ const resolvedCandidate = path2.resolve(candidate);
10598
+ const resolvedRoot = path2.resolve(root);
10599
+ const relative = path2.relative(resolvedRoot, resolvedCandidate);
10600
+ return relative === "" || !!relative && !relative.startsWith("..") && !path2.isAbsolute(relative);
10601
+ }
10602
+ function shouldRegisterWorkflowProductManager(options = {}, worktree = process.cwd()) {
10603
+ if (options.clickUpWebhookActive === true) return true;
10604
+ const validation = options.clickUpWebhookValidation;
10605
+ return validation?.complete === true && isSameOrNestedPath(worktree, validation.config?.basePath);
10606
+ }
10607
10607
  function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, options = {}) {
10608
10608
  const optimaActive = repoCfg && repoCfg.enabled === true;
10609
- const clickUpWebhookActive = options.clickUpWebhookActive === true;
10609
+ const clickUpWebhookActive = shouldRegisterWorkflowProductManager(options, worktree);
10610
10610
  const repoAgentDefinitions = repoAgentsDir(worktree);
10611
10611
  const repoAgentAdditions = repoAgentAdditionsDir(worktree);
10612
10612
  const legacyAgentsDir = legacyRepoAgentsDir(worktree);
@@ -11308,7 +11308,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
11308
11308
  },
11309
11309
  async config(cfg) {
11310
11310
  cfg.agent ??= {};
11311
- const ourAgents = buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, { clickUpWebhookActive });
11311
+ const ourAgents = buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, { clickUpWebhookActive, clickUpWebhookValidation });
11312
11312
  const builtInAgents = ["build", "plan", "general", "explore"];
11313
11313
  const preserveExistingAgents = repoCfg.features?.preserve_existing_agents ?? DEFAULT_PRESERVE_EXISTING_AGENTS;
11314
11314
  const allToDisable = preserveExistingAgents ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([...builtInAgents, ...Object.keys(cfg.agent)]);
@@ -9262,8 +9262,10 @@ async function openCodeSessionExists(client, sessionId) {
9262
9262
  }
9263
9263
  return false;
9264
9264
  }
9265
- async function createOpenCodeSession(client, { title, directory } = {}) {
9266
- const result = await client.session.create({ query: { directory }, body: { title } });
9265
+ async function createOpenCodeSession(client, { title, directory, agent } = {}) {
9266
+ const body = { title };
9267
+ if (agent) body.agent = agent;
9268
+ const result = await client.session.create({ query: { directory }, body });
9267
9269
  return result?.data?.id || result?.id;
9268
9270
  }
9269
9271
  function assertOpenCodePromptAccepted(result) {
@@ -9300,35 +9302,21 @@ async function sendOpenCodeSessionEventDirect({ baseUrl, sessionId, text, fetchI
9300
9302
  if (!data?.data?.id) throw new Error("OpenCode prompt response did not include data.id.");
9301
9303
  return { ok: true, method: "http", status: response.status, data: data.data, response: data };
9302
9304
  }
9303
- async function callOpenCodePromptWithFallbacks(method, sessionId, flatPayload, structuredPayload) {
9304
- const attempts = [
9305
- { id: sessionId, ...flatPayload },
9306
- { sessionID: sessionId, ...flatPayload },
9307
- { ...structuredPayload, path: { sessionID: sessionId } },
9308
- { ...structuredPayload, path: { id: sessionId } }
9309
- ];
9310
- let firstError = null;
9311
- for (const attempt of attempts) {
9312
- try {
9313
- return assertOpenCodePromptAccepted(await method(attempt));
9314
- } catch (error) {
9315
- firstError ??= error;
9316
- }
9317
- }
9318
- throw firstError;
9319
- }
9320
- async function sendOpenCodeSessionEvent(client, { sessionId, agent, text, directory, opencodeBaseUrl, baseUrl, fetchImpl } = {}) {
9305
+ async function sendOpenCodeSessionEvent(client, { sessionId, agent, text, directory, opencodeBaseUrl, baseUrl, fetchImpl, direct = false } = {}) {
9321
9306
  const directBaseUrl = opencodeBaseUrl || baseUrl;
9322
- if (directBaseUrl) return sendOpenCodeSessionEventDirect({ baseUrl: directBaseUrl, sessionId, text, fetchImpl });
9323
9307
  const parts = [{ type: "text", text }];
9324
- const flatPayload = { directory, agent, parts };
9325
- const structuredPayload = { query: { directory }, body: { agent, parts } };
9326
- if (typeof client?.session?.prompt === "function") {
9327
- return callOpenCodePromptWithFallbacks(client.session.prompt.bind(client.session), sessionId, flatPayload, structuredPayload);
9308
+ const structuredPayload = {
9309
+ path: { id: sessionId },
9310
+ query: { directory },
9311
+ body: { agent, parts }
9312
+ };
9313
+ if (!direct && typeof client?.session?.promptAsync === "function") {
9314
+ return assertOpenCodePromptAccepted(await client.session.promptAsync(structuredPayload));
9328
9315
  }
9329
- if (typeof client?.session?.promptAsync === "function") {
9330
- return callOpenCodePromptWithFallbacks(client.session.promptAsync.bind(client.session), sessionId, flatPayload, structuredPayload);
9316
+ if (!direct && typeof client?.session?.prompt === "function") {
9317
+ return assertOpenCodePromptAccepted(await client.session.prompt(structuredPayload));
9331
9318
  }
9319
+ if (directBaseUrl) return sendOpenCodeSessionEventDirect({ baseUrl: directBaseUrl, sessionId, text, fetchImpl });
9332
9320
  throw new Error("OpenCode client does not expose session.prompt or session.promptAsync.");
9333
9321
  }
9334
9322
  function formatClickUpWebhookPrompt({ eventType, taskId, payload }) {
@@ -9557,7 +9545,7 @@ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, w
9557
9545
  if (!existingSessionId) {
9558
9546
  let pendingSessionId = getNestedMetadataValue(metadata, clickUpPendingSessionKey(config.routing.metadataKey)) || state.pendingSessions?.[taskId];
9559
9547
  if (!pendingSessionId) {
9560
- pendingSessionId = await createSession(openCodeClient, { title: `ClickUp PM: ${taskId}`, directory: config.basePath });
9548
+ pendingSessionId = await createSession(openCodeClient, { title: `ClickUp PM: ${taskId}`, directory: config.basePath, agent: config.routing.targetAgent });
9561
9549
  if (!String(pendingSessionId || "").startsWith("ses_")) return { ok: false, action: "error", reason: "session_create_failed", taskId };
9562
9550
  if (saveState) {
9563
9551
  saveState({
@@ -10611,9 +10599,21 @@ function getModePromptFragment(agentId, operatingTeamMode, worktree) {
10611
10599
  if (!fragmentPath) return "";
10612
10600
  return readResolvedFile(fragmentPath, worktree, { preferCompactPromptDocs: true });
10613
10601
  }
10602
+ function isSameOrNestedPath(candidate, root) {
10603
+ if (typeof candidate !== "string" || typeof root !== "string" || !candidate.trim() || !root.trim()) return false;
10604
+ const resolvedCandidate = path2.resolve(candidate);
10605
+ const resolvedRoot = path2.resolve(root);
10606
+ const relative = path2.relative(resolvedRoot, resolvedCandidate);
10607
+ return relative === "" || !!relative && !relative.startsWith("..") && !path2.isAbsolute(relative);
10608
+ }
10609
+ function shouldRegisterWorkflowProductManager(options = {}, worktree = process.cwd()) {
10610
+ if (options.clickUpWebhookActive === true) return true;
10611
+ const validation = options.clickUpWebhookValidation;
10612
+ return validation?.complete === true && isSameOrNestedPath(worktree, validation.config?.basePath);
10613
+ }
10614
10614
  function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, options = {}) {
10615
10615
  const optimaActive = repoCfg && repoCfg.enabled === true;
10616
- const clickUpWebhookActive = options.clickUpWebhookActive === true;
10616
+ const clickUpWebhookActive = shouldRegisterWorkflowProductManager(options, worktree);
10617
10617
  const repoAgentDefinitions = repoAgentsDir(worktree);
10618
10618
  const repoAgentAdditions = repoAgentAdditionsDir(worktree);
10619
10619
  const legacyAgentsDir = legacyRepoAgentsDir(worktree);
@@ -11315,7 +11315,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
11315
11315
  },
11316
11316
  async config(cfg) {
11317
11317
  cfg.agent ??= {};
11318
- const ourAgents = buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, { clickUpWebhookActive });
11318
+ const ourAgents = buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, { clickUpWebhookActive, clickUpWebhookValidation });
11319
11319
  const builtInAgents = ["build", "plan", "general", "explore"];
11320
11320
  const preserveExistingAgents = repoCfg.features?.preserve_existing_agents ?? DEFAULT_PRESERVE_EXISTING_AGENTS;
11321
11321
  const allToDisable = preserveExistingAgents ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([...builtInAgents, ...Object.keys(cfg.agent)]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defend-tech/opencode-optima",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"