@defend-tech/opencode-optima 0.1.54 → 0.1.55

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
@@ -9830,12 +9830,170 @@ function normalizeOpenCodeSessionMessages(result) {
9830
9830
  if (Array.isArray(data?.items)) return [...data.items];
9831
9831
  return [];
9832
9832
  }
9833
+ function clampOpenCodeMessageLimit(limit) {
9834
+ const value = Number(limit);
9835
+ if (!Number.isFinite(value)) return 20;
9836
+ return Math.min(50, Math.max(1, Math.floor(value)));
9837
+ }
9838
+ function clampOpenCodeSessionText(text = "", maxLength = 12e3) {
9839
+ const value = String(text ?? "");
9840
+ return value.length > maxLength ? value.slice(0, maxLength) : value;
9841
+ }
9842
+ function hashOpenCodeSessionText(text = "") {
9843
+ return crypto.createHash("sha256").update(String(text ?? "")).digest("hex");
9844
+ }
9833
9845
  async function readOpenCodeSessionMessages(client, { sessionId, directory, limit = 20 } = {}) {
9834
9846
  if (typeof client?.session?.messages !== "function") return null;
9835
- const query = { limit };
9847
+ const query = { limit: clampOpenCodeMessageLimit(limit) };
9836
9848
  if (directory) query.directory = directory;
9837
9849
  return normalizeOpenCodeSessionMessages(await client.session.messages({ path: { id: sessionId }, query }));
9838
9850
  }
9851
+ function openCodeResultSummary(result) {
9852
+ const data = result?.data ?? result;
9853
+ return {
9854
+ type: Array.isArray(data) ? "array" : typeof data,
9855
+ id: data?.id || data?.sessionID || data?.sessionId || result?.id || result?.sessionID || result?.sessionId || null,
9856
+ keys: data && typeof data === "object" && !Array.isArray(data) ? Object.keys(data).slice(0, 20) : [],
9857
+ dataKeys: result?.data && typeof result.data === "object" && !Array.isArray(result.data) ? Object.keys(result.data).slice(0, 20) : [],
9858
+ status: result?.status || result?.response?.status || null
9859
+ };
9860
+ }
9861
+ function normalizeOpenCodeMessageRole(message = {}) {
9862
+ return message.role || message.info?.role || message.author?.role || message.type || "";
9863
+ }
9864
+ function normalizeOpenCodeMessageAgent(message = {}) {
9865
+ return message.agent || message.info?.agent || message.mode?.agent || message.author?.agent || "";
9866
+ }
9867
+ function normalizeOpenCodeMessageMode(message = {}) {
9868
+ return message.mode || message.info?.mode || message.metadata?.mode || "";
9869
+ }
9870
+ function normalizeOpenCodeMessageId(message = {}) {
9871
+ return message.id || message.messageID || message.messageId || message.info?.id || message.data?.id || null;
9872
+ }
9873
+ function summarizeOpenCodeMessages(messages = [], { snippetLength = 160, maxMessages = 50 } = {}) {
9874
+ const list = Array.isArray(messages) ? messages.slice(0, maxMessages) : [];
9875
+ const safeSnippetLength = Math.min(240, Math.max(20, Number(snippetLength) || 160));
9876
+ return list.map((message, index) => {
9877
+ const text = openCodeMessageText(message).replace(/\s+/g, " ").trim();
9878
+ return {
9879
+ index,
9880
+ id: normalizeOpenCodeMessageId(message),
9881
+ role: normalizeOpenCodeMessageRole(message),
9882
+ agent: normalizeOpenCodeMessageAgent(message),
9883
+ mode: normalizeOpenCodeMessageMode(message),
9884
+ text_length: text.length,
9885
+ text_hash: hashOpenCodeSessionText(text),
9886
+ snippet: text.length > safeSnippetLength ? `${text.slice(0, safeSnippetLength)}...` : text
9887
+ };
9888
+ });
9889
+ }
9890
+ function promptResultAssistantReturned(result) {
9891
+ const parts = normalizePromptResponseParts(result);
9892
+ const text = extractTextParts(parts);
9893
+ const data = result?.data ?? result;
9894
+ return Boolean(text || data?.role === "assistant" || data?.info?.role === "assistant");
9895
+ }
9896
+ async function createOpenCodeSessionControl(client, { directory, title, agent } = {}) {
9897
+ if (typeof client?.session?.create !== "function") throw new Error("OpenCode client does not expose session.create.");
9898
+ const body = { title };
9899
+ if (agent) body.agent = agent;
9900
+ const result = await client.session.create({ query: { directory }, body });
9901
+ const sessionId = extractOpenCodeSessionId(result);
9902
+ if (!sessionId) throw new Error("OpenCode session create response did not include a session id.");
9903
+ return {
9904
+ ok: true,
9905
+ session_id: sessionId,
9906
+ title,
9907
+ directory,
9908
+ agent: agent || null,
9909
+ result_summary: openCodeResultSummary(result)
9910
+ };
9911
+ }
9912
+ async function promptOpenCodeSessionControl(client, { sessionId, directory, text, agent, omitAgent = false, requireReadable = true } = {}) {
9913
+ if (typeof client?.session?.prompt !== "function") throw new Error("OpenCode client does not expose session.prompt.");
9914
+ if (requireReadable) await assertOpenCodeSessionReadableForDirectory(client, { sessionId, directory });
9915
+ const safeText = clampOpenCodeSessionText(text);
9916
+ const body = { parts: [{ type: "text", text: safeText }] };
9917
+ if (!omitAgent && agent) body.agent = agent;
9918
+ const result = await client.session.prompt({ path: { id: sessionId }, query: { directory }, body });
9919
+ return {
9920
+ ok: true,
9921
+ session_id: sessionId,
9922
+ directory,
9923
+ agent: omitAgent ? null : agent || null,
9924
+ omit_agent: Boolean(omitAgent),
9925
+ text_length: safeText.length,
9926
+ text_truncated: String(text ?? "").length > safeText.length,
9927
+ text_hash: hashOpenCodeSessionText(safeText),
9928
+ assistant_returned: promptResultAssistantReturned(result),
9929
+ returned_parts_count: normalizePromptResponseParts(result).length,
9930
+ result_summary: openCodeResultSummary(result)
9931
+ };
9932
+ }
9933
+ async function assertOpenCodeSessionReadableForDirectory(client, { sessionId, directory } = {}) {
9934
+ try {
9935
+ await readOpenCodeSessionMessages(client, { sessionId, directory, limit: 1 });
9936
+ return true;
9937
+ } catch (error) {
9938
+ throw new Error(`OpenCode session '${sessionId}' is not readable for the requested safe directory.`);
9939
+ }
9940
+ }
9941
+ async function readOpenCodeSessionControl(client, { sessionId, directory, limit = 20 } = {}) {
9942
+ const boundedLimit = clampOpenCodeMessageLimit(limit);
9943
+ const messages = await readOpenCodeSessionMessages(client, { sessionId, directory, limit: boundedLimit });
9944
+ if (!messages) throw new Error("OpenCode client does not expose session.messages.");
9945
+ return {
9946
+ ok: true,
9947
+ session_id: sessionId,
9948
+ directory: directory || null,
9949
+ limit: boundedLimit,
9950
+ count: messages.length,
9951
+ messages: summarizeOpenCodeMessages(messages)
9952
+ };
9953
+ }
9954
+ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgentOnPrompt = false, text = "" } = {}) {
9955
+ const requestedMarker = text || `optima-session-probe-${crypto.randomUUID()}`;
9956
+ const marker = clampOpenCodeSessionText(requestedMarker);
9957
+ const create = await createOpenCodeSessionControl(client, {
9958
+ directory,
9959
+ title: `Optima session probe ${(/* @__PURE__ */ new Date()).toISOString()}`,
9960
+ agent
9961
+ });
9962
+ const prompt = await promptOpenCodeSessionControl(client, {
9963
+ sessionId: create.session_id,
9964
+ directory,
9965
+ text: marker,
9966
+ agent,
9967
+ omitAgent: omitAgentOnPrompt,
9968
+ requireReadable: false
9969
+ });
9970
+ const rawMessages = await readOpenCodeSessionMessages(client, { sessionId: create.session_id, directory, limit: 50 });
9971
+ if (!rawMessages) throw new Error("OpenCode client does not expose session.messages.");
9972
+ const fullMessageText = rawMessages.map(openCodeMessageText).join("\n");
9973
+ const messages = {
9974
+ ok: true,
9975
+ session_id: create.session_id,
9976
+ directory,
9977
+ limit: 50,
9978
+ count: rawMessages.length,
9979
+ messages: summarizeOpenCodeMessages(rawMessages)
9980
+ };
9981
+ return {
9982
+ ok: true,
9983
+ session_id: create.session_id,
9984
+ directory,
9985
+ agent: agent || null,
9986
+ omit_agent_on_prompt: Boolean(omitAgentOnPrompt),
9987
+ marker_length: marker.length,
9988
+ marker_truncated: requestedMarker.length > marker.length,
9989
+ marker_hash: hashOpenCodeSessionText(marker),
9990
+ marker_visible: fullMessageText.includes(marker),
9991
+ assistant_visible: rawMessages.some((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant" || Boolean(normalizeOpenCodeMessageAgent(message) && openCodeMessageText(message))),
9992
+ create,
9993
+ prompt,
9994
+ messages
9995
+ };
9996
+ }
9839
9997
  function openCodeMessageText(message) {
9840
9998
  const parts = [message?.text, message?.content, message?.message, message?.body?.text, message?.data?.text];
9841
9999
  const partList = Array.isArray(message?.parts) ? message.parts : Array.isArray(message?.body?.parts) ? message.body.parts : [];
@@ -11481,6 +11639,21 @@ function shouldRegisterWorkflowProductManager(options = {}, worktree = process.c
11481
11639
  const validation = options.clickUpWebhookValidation;
11482
11640
  return validation?.complete === true && validation?.ok !== false && isSameOrNestedPath(worktree, validation.config?.basePath);
11483
11641
  }
11642
+ function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
11643
+ const safe = safeWorktreeOrFailure(context, pluginWorktree);
11644
+ if (!safe.ok) return { ok: false, error: safe.message };
11645
+ const requested = String(requestedDirectory || "").trim() ? path2.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
11646
+ if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
11647
+ if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
11648
+ const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
11649
+ if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
11650
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path2.resolve(clickUpBasePath) };
11651
+ }
11652
+ return {
11653
+ ok: false,
11654
+ error: `Directory '${requested}' is outside the safe worktree '${safe.worktree}' and configured ClickUp base path.`
11655
+ };
11656
+ }
11484
11657
  function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, options = {}) {
11485
11658
  const optimaActive = repoCfg && repoCfg.enabled === true;
11486
11659
  const clickUpWebhookActive = shouldRegisterWorkflowProductManager(options, worktree);
@@ -11767,6 +11940,100 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
11767
11940
  Restart or reload OpenCode manually if the newly scaffolded config or agents are not visible in this session. Optima did not dispose or reload the active OpenCode instance automatically to avoid aborting the current session.`;
11768
11941
  }
11769
11942
  }),
11943
+ optima_session_create: tool({
11944
+ description: "Create an OpenCode session through the installed structured SDK shape",
11945
+ args: {
11946
+ directory: tool.schema.string().describe("Project directory for the OpenCode session"),
11947
+ title: tool.schema.string().describe("Session title"),
11948
+ agent: tool.schema.string().describe("Optional agent id for session creation")
11949
+ },
11950
+ async execute(args, context) {
11951
+ try {
11952
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
11953
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
11954
+ const result = await createOpenCodeSessionControl(input.client, {
11955
+ directory: directory.directory,
11956
+ title: args.title,
11957
+ agent: args.agent
11958
+ });
11959
+ return JSON.stringify(result, null, 2);
11960
+ } catch (error) {
11961
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
11962
+ }
11963
+ }
11964
+ }),
11965
+ optima_session_prompt: tool({
11966
+ description: "Prompt an existing OpenCode session through the installed structured SDK shape",
11967
+ args: {
11968
+ session_id: tool.schema.string().describe("OpenCode session id"),
11969
+ directory: tool.schema.string().describe("Project directory for the OpenCode session"),
11970
+ text: tool.schema.string().describe("Text prompt to send"),
11971
+ agent: tool.schema.string().describe("Optional agent id for the prompt body"),
11972
+ omit_agent: tool.schema.string().describe("Set to 'true' to omit agent from the prompt body")
11973
+ },
11974
+ async execute(args, context) {
11975
+ try {
11976
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
11977
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
11978
+ const result = await promptOpenCodeSessionControl(input.client, {
11979
+ sessionId: args.session_id,
11980
+ directory: directory.directory,
11981
+ text: args.text,
11982
+ agent: args.agent,
11983
+ omitAgent: String(args.omit_agent || "").toLowerCase() === "true"
11984
+ });
11985
+ return JSON.stringify(result, null, 2);
11986
+ } catch (error) {
11987
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
11988
+ }
11989
+ }
11990
+ }),
11991
+ optima_session_messages: tool({
11992
+ description: "Read and summarize OpenCode session messages through the installed structured SDK shape",
11993
+ args: {
11994
+ session_id: tool.schema.string().describe("OpenCode session id"),
11995
+ directory: tool.schema.string().describe("Optional project directory for the OpenCode session"),
11996
+ limit: tool.schema.number().describe("Optional message limit")
11997
+ },
11998
+ async execute(args, context) {
11999
+ try {
12000
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
12001
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
12002
+ const result = await readOpenCodeSessionControl(input.client, {
12003
+ sessionId: args.session_id,
12004
+ directory: directory.directory,
12005
+ limit: args.limit
12006
+ });
12007
+ return JSON.stringify(result, null, 2);
12008
+ } catch (error) {
12009
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
12010
+ }
12011
+ }
12012
+ }),
12013
+ optima_session_probe: tool({
12014
+ description: "Create, prompt, and read an OpenCode session without touching ClickUp state",
12015
+ args: {
12016
+ directory: tool.schema.string().describe("Project directory for the OpenCode session"),
12017
+ agent: tool.schema.string().describe("Optional agent id to probe"),
12018
+ omit_agent_on_prompt: tool.schema.string().describe("Set to 'true' to omit agent from the prompt body"),
12019
+ text: tool.schema.string().describe("Optional marker text to send")
12020
+ },
12021
+ async execute(args, context) {
12022
+ try {
12023
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
12024
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
12025
+ const result = await probeOpenCodeSessionControl(input.client, {
12026
+ directory: directory.directory,
12027
+ agent: args.agent,
12028
+ omitAgentOnPrompt: String(args.omit_agent_on_prompt || "").toLowerCase() === "true",
12029
+ text: args.text
12030
+ });
12031
+ return JSON.stringify(result, null, 2);
12032
+ } catch (error) {
12033
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
12034
+ }
12035
+ }
12036
+ }),
11770
12037
  optima_clickup_sync_summary: tool({
11771
12038
  description: "Generate a dry-run ClickUp summary/comment payload from Optima Markdown task and evidence artifacts",
11772
12039
  args: {
@@ -12235,7 +12502,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
12235
12502
  }
12236
12503
  };
12237
12504
  }
12238
- OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, createOpenCodeSession, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionMessages, reconcileClickUpStartup, scheduleClickUpStartupReconciliation, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
12505
+ OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, scheduleClickUpStartupReconciliation, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
12239
12506
  export {
12240
12507
  OptimaPlugin as default
12241
12508
  };
@@ -9837,12 +9837,170 @@ function normalizeOpenCodeSessionMessages(result) {
9837
9837
  if (Array.isArray(data?.items)) return [...data.items];
9838
9838
  return [];
9839
9839
  }
9840
+ function clampOpenCodeMessageLimit(limit) {
9841
+ const value = Number(limit);
9842
+ if (!Number.isFinite(value)) return 20;
9843
+ return Math.min(50, Math.max(1, Math.floor(value)));
9844
+ }
9845
+ function clampOpenCodeSessionText(text = "", maxLength = 12e3) {
9846
+ const value = String(text ?? "");
9847
+ return value.length > maxLength ? value.slice(0, maxLength) : value;
9848
+ }
9849
+ function hashOpenCodeSessionText(text = "") {
9850
+ return crypto.createHash("sha256").update(String(text ?? "")).digest("hex");
9851
+ }
9840
9852
  async function readOpenCodeSessionMessages(client, { sessionId, directory, limit = 20 } = {}) {
9841
9853
  if (typeof client?.session?.messages !== "function") return null;
9842
- const query = { limit };
9854
+ const query = { limit: clampOpenCodeMessageLimit(limit) };
9843
9855
  if (directory) query.directory = directory;
9844
9856
  return normalizeOpenCodeSessionMessages(await client.session.messages({ path: { id: sessionId }, query }));
9845
9857
  }
9858
+ function openCodeResultSummary(result) {
9859
+ const data = result?.data ?? result;
9860
+ return {
9861
+ type: Array.isArray(data) ? "array" : typeof data,
9862
+ id: data?.id || data?.sessionID || data?.sessionId || result?.id || result?.sessionID || result?.sessionId || null,
9863
+ keys: data && typeof data === "object" && !Array.isArray(data) ? Object.keys(data).slice(0, 20) : [],
9864
+ dataKeys: result?.data && typeof result.data === "object" && !Array.isArray(result.data) ? Object.keys(result.data).slice(0, 20) : [],
9865
+ status: result?.status || result?.response?.status || null
9866
+ };
9867
+ }
9868
+ function normalizeOpenCodeMessageRole(message = {}) {
9869
+ return message.role || message.info?.role || message.author?.role || message.type || "";
9870
+ }
9871
+ function normalizeOpenCodeMessageAgent(message = {}) {
9872
+ return message.agent || message.info?.agent || message.mode?.agent || message.author?.agent || "";
9873
+ }
9874
+ function normalizeOpenCodeMessageMode(message = {}) {
9875
+ return message.mode || message.info?.mode || message.metadata?.mode || "";
9876
+ }
9877
+ function normalizeOpenCodeMessageId(message = {}) {
9878
+ return message.id || message.messageID || message.messageId || message.info?.id || message.data?.id || null;
9879
+ }
9880
+ function summarizeOpenCodeMessages(messages = [], { snippetLength = 160, maxMessages = 50 } = {}) {
9881
+ const list = Array.isArray(messages) ? messages.slice(0, maxMessages) : [];
9882
+ const safeSnippetLength = Math.min(240, Math.max(20, Number(snippetLength) || 160));
9883
+ return list.map((message, index) => {
9884
+ const text = openCodeMessageText(message).replace(/\s+/g, " ").trim();
9885
+ return {
9886
+ index,
9887
+ id: normalizeOpenCodeMessageId(message),
9888
+ role: normalizeOpenCodeMessageRole(message),
9889
+ agent: normalizeOpenCodeMessageAgent(message),
9890
+ mode: normalizeOpenCodeMessageMode(message),
9891
+ text_length: text.length,
9892
+ text_hash: hashOpenCodeSessionText(text),
9893
+ snippet: text.length > safeSnippetLength ? `${text.slice(0, safeSnippetLength)}...` : text
9894
+ };
9895
+ });
9896
+ }
9897
+ function promptResultAssistantReturned(result) {
9898
+ const parts = normalizePromptResponseParts(result);
9899
+ const text = extractTextParts(parts);
9900
+ const data = result?.data ?? result;
9901
+ return Boolean(text || data?.role === "assistant" || data?.info?.role === "assistant");
9902
+ }
9903
+ async function createOpenCodeSessionControl(client, { directory, title, agent } = {}) {
9904
+ if (typeof client?.session?.create !== "function") throw new Error("OpenCode client does not expose session.create.");
9905
+ const body = { title };
9906
+ if (agent) body.agent = agent;
9907
+ const result = await client.session.create({ query: { directory }, body });
9908
+ const sessionId = extractOpenCodeSessionId(result);
9909
+ if (!sessionId) throw new Error("OpenCode session create response did not include a session id.");
9910
+ return {
9911
+ ok: true,
9912
+ session_id: sessionId,
9913
+ title,
9914
+ directory,
9915
+ agent: agent || null,
9916
+ result_summary: openCodeResultSummary(result)
9917
+ };
9918
+ }
9919
+ async function promptOpenCodeSessionControl(client, { sessionId, directory, text, agent, omitAgent = false, requireReadable = true } = {}) {
9920
+ if (typeof client?.session?.prompt !== "function") throw new Error("OpenCode client does not expose session.prompt.");
9921
+ if (requireReadable) await assertOpenCodeSessionReadableForDirectory(client, { sessionId, directory });
9922
+ const safeText = clampOpenCodeSessionText(text);
9923
+ const body = { parts: [{ type: "text", text: safeText }] };
9924
+ if (!omitAgent && agent) body.agent = agent;
9925
+ const result = await client.session.prompt({ path: { id: sessionId }, query: { directory }, body });
9926
+ return {
9927
+ ok: true,
9928
+ session_id: sessionId,
9929
+ directory,
9930
+ agent: omitAgent ? null : agent || null,
9931
+ omit_agent: Boolean(omitAgent),
9932
+ text_length: safeText.length,
9933
+ text_truncated: String(text ?? "").length > safeText.length,
9934
+ text_hash: hashOpenCodeSessionText(safeText),
9935
+ assistant_returned: promptResultAssistantReturned(result),
9936
+ returned_parts_count: normalizePromptResponseParts(result).length,
9937
+ result_summary: openCodeResultSummary(result)
9938
+ };
9939
+ }
9940
+ async function assertOpenCodeSessionReadableForDirectory(client, { sessionId, directory } = {}) {
9941
+ try {
9942
+ await readOpenCodeSessionMessages(client, { sessionId, directory, limit: 1 });
9943
+ return true;
9944
+ } catch (error) {
9945
+ throw new Error(`OpenCode session '${sessionId}' is not readable for the requested safe directory.`);
9946
+ }
9947
+ }
9948
+ async function readOpenCodeSessionControl(client, { sessionId, directory, limit = 20 } = {}) {
9949
+ const boundedLimit = clampOpenCodeMessageLimit(limit);
9950
+ const messages = await readOpenCodeSessionMessages(client, { sessionId, directory, limit: boundedLimit });
9951
+ if (!messages) throw new Error("OpenCode client does not expose session.messages.");
9952
+ return {
9953
+ ok: true,
9954
+ session_id: sessionId,
9955
+ directory: directory || null,
9956
+ limit: boundedLimit,
9957
+ count: messages.length,
9958
+ messages: summarizeOpenCodeMessages(messages)
9959
+ };
9960
+ }
9961
+ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgentOnPrompt = false, text = "" } = {}) {
9962
+ const requestedMarker = text || `optima-session-probe-${crypto.randomUUID()}`;
9963
+ const marker = clampOpenCodeSessionText(requestedMarker);
9964
+ const create = await createOpenCodeSessionControl(client, {
9965
+ directory,
9966
+ title: `Optima session probe ${(/* @__PURE__ */ new Date()).toISOString()}`,
9967
+ agent
9968
+ });
9969
+ const prompt = await promptOpenCodeSessionControl(client, {
9970
+ sessionId: create.session_id,
9971
+ directory,
9972
+ text: marker,
9973
+ agent,
9974
+ omitAgent: omitAgentOnPrompt,
9975
+ requireReadable: false
9976
+ });
9977
+ const rawMessages = await readOpenCodeSessionMessages(client, { sessionId: create.session_id, directory, limit: 50 });
9978
+ if (!rawMessages) throw new Error("OpenCode client does not expose session.messages.");
9979
+ const fullMessageText = rawMessages.map(openCodeMessageText).join("\n");
9980
+ const messages = {
9981
+ ok: true,
9982
+ session_id: create.session_id,
9983
+ directory,
9984
+ limit: 50,
9985
+ count: rawMessages.length,
9986
+ messages: summarizeOpenCodeMessages(rawMessages)
9987
+ };
9988
+ return {
9989
+ ok: true,
9990
+ session_id: create.session_id,
9991
+ directory,
9992
+ agent: agent || null,
9993
+ omit_agent_on_prompt: Boolean(omitAgentOnPrompt),
9994
+ marker_length: marker.length,
9995
+ marker_truncated: requestedMarker.length > marker.length,
9996
+ marker_hash: hashOpenCodeSessionText(marker),
9997
+ marker_visible: fullMessageText.includes(marker),
9998
+ assistant_visible: rawMessages.some((message) => normalizeLooseToken(normalizeOpenCodeMessageRole(message)) === "assistant" || Boolean(normalizeOpenCodeMessageAgent(message) && openCodeMessageText(message))),
9999
+ create,
10000
+ prompt,
10001
+ messages
10002
+ };
10003
+ }
9846
10004
  function openCodeMessageText(message) {
9847
10005
  const parts = [message?.text, message?.content, message?.message, message?.body?.text, message?.data?.text];
9848
10006
  const partList = Array.isArray(message?.parts) ? message.parts : Array.isArray(message?.body?.parts) ? message.body.parts : [];
@@ -11488,6 +11646,21 @@ function shouldRegisterWorkflowProductManager(options = {}, worktree = process.c
11488
11646
  const validation = options.clickUpWebhookValidation;
11489
11647
  return validation?.complete === true && validation?.ok !== false && isSameOrNestedPath(worktree, validation.config?.basePath);
11490
11648
  }
11649
+ function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
11650
+ const safe = safeWorktreeOrFailure(context, pluginWorktree);
11651
+ if (!safe.ok) return { ok: false, error: safe.message };
11652
+ const requested = String(requestedDirectory || "").trim() ? path2.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
11653
+ if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
11654
+ if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
11655
+ const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
11656
+ if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
11657
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path2.resolve(clickUpBasePath) };
11658
+ }
11659
+ return {
11660
+ ok: false,
11661
+ error: `Directory '${requested}' is outside the safe worktree '${safe.worktree}' and configured ClickUp base path.`
11662
+ };
11663
+ }
11491
11664
  function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, options = {}) {
11492
11665
  const optimaActive = repoCfg && repoCfg.enabled === true;
11493
11666
  const clickUpWebhookActive = shouldRegisterWorkflowProductManager(options, worktree);
@@ -11774,6 +11947,100 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
11774
11947
  Restart or reload OpenCode manually if the newly scaffolded config or agents are not visible in this session. Optima did not dispose or reload the active OpenCode instance automatically to avoid aborting the current session.`;
11775
11948
  }
11776
11949
  }),
11950
+ optima_session_create: tool({
11951
+ description: "Create an OpenCode session through the installed structured SDK shape",
11952
+ args: {
11953
+ directory: tool.schema.string().describe("Project directory for the OpenCode session"),
11954
+ title: tool.schema.string().describe("Session title"),
11955
+ agent: tool.schema.string().describe("Optional agent id for session creation")
11956
+ },
11957
+ async execute(args, context) {
11958
+ try {
11959
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
11960
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
11961
+ const result = await createOpenCodeSessionControl(input.client, {
11962
+ directory: directory.directory,
11963
+ title: args.title,
11964
+ agent: args.agent
11965
+ });
11966
+ return JSON.stringify(result, null, 2);
11967
+ } catch (error) {
11968
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
11969
+ }
11970
+ }
11971
+ }),
11972
+ optima_session_prompt: tool({
11973
+ description: "Prompt an existing OpenCode session through the installed structured SDK shape",
11974
+ args: {
11975
+ session_id: tool.schema.string().describe("OpenCode session id"),
11976
+ directory: tool.schema.string().describe("Project directory for the OpenCode session"),
11977
+ text: tool.schema.string().describe("Text prompt to send"),
11978
+ agent: tool.schema.string().describe("Optional agent id for the prompt body"),
11979
+ omit_agent: tool.schema.string().describe("Set to 'true' to omit agent from the prompt body")
11980
+ },
11981
+ async execute(args, context) {
11982
+ try {
11983
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
11984
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
11985
+ const result = await promptOpenCodeSessionControl(input.client, {
11986
+ sessionId: args.session_id,
11987
+ directory: directory.directory,
11988
+ text: args.text,
11989
+ agent: args.agent,
11990
+ omitAgent: String(args.omit_agent || "").toLowerCase() === "true"
11991
+ });
11992
+ return JSON.stringify(result, null, 2);
11993
+ } catch (error) {
11994
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
11995
+ }
11996
+ }
11997
+ }),
11998
+ optima_session_messages: tool({
11999
+ description: "Read and summarize OpenCode session messages through the installed structured SDK shape",
12000
+ args: {
12001
+ session_id: tool.schema.string().describe("OpenCode session id"),
12002
+ directory: tool.schema.string().describe("Optional project directory for the OpenCode session"),
12003
+ limit: tool.schema.number().describe("Optional message limit")
12004
+ },
12005
+ async execute(args, context) {
12006
+ try {
12007
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
12008
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
12009
+ const result = await readOpenCodeSessionControl(input.client, {
12010
+ sessionId: args.session_id,
12011
+ directory: directory.directory,
12012
+ limit: args.limit
12013
+ });
12014
+ return JSON.stringify(result, null, 2);
12015
+ } catch (error) {
12016
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
12017
+ }
12018
+ }
12019
+ }),
12020
+ optima_session_probe: tool({
12021
+ description: "Create, prompt, and read an OpenCode session without touching ClickUp state",
12022
+ args: {
12023
+ directory: tool.schema.string().describe("Project directory for the OpenCode session"),
12024
+ agent: tool.schema.string().describe("Optional agent id to probe"),
12025
+ omit_agent_on_prompt: tool.schema.string().describe("Set to 'true' to omit agent from the prompt body"),
12026
+ text: tool.schema.string().describe("Optional marker text to send")
12027
+ },
12028
+ async execute(args, context) {
12029
+ try {
12030
+ const directory = resolveSessionToolDirectory({ requestedDirectory: args.directory, context, pluginWorktree: worktree, clickUpWebhookValidation });
12031
+ if (!directory.ok) return JSON.stringify({ ok: false, error: directory.error }, null, 2);
12032
+ const result = await probeOpenCodeSessionControl(input.client, {
12033
+ directory: directory.directory,
12034
+ agent: args.agent,
12035
+ omitAgentOnPrompt: String(args.omit_agent_on_prompt || "").toLowerCase() === "true",
12036
+ text: args.text
12037
+ });
12038
+ return JSON.stringify(result, null, 2);
12039
+ } catch (error) {
12040
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
12041
+ }
12042
+ }
12043
+ }),
11777
12044
  optima_clickup_sync_summary: tool({
11778
12045
  description: "Generate a dry-run ClickUp summary/comment payload from Optima Markdown task and evidence artifacts",
11779
12046
  args: {
@@ -12242,7 +12509,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
12242
12509
  }
12243
12510
  };
12244
12511
  }
12245
- OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, createOpenCodeSession, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionMessages, reconcileClickUpStartup, scheduleClickUpStartupReconciliation, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
12512
+ OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, createClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpWebhookStateActive, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, scheduleClickUpStartupReconciliation, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
12246
12513
 
12247
12514
  // src/sanitize_cli.js
12248
12515
  var { migrateLegacyOptimaLayout: migrateLegacyOptimaLayout2 } = OptimaPlugin.__internals;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defend-tech/opencode-optima",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/defend-tech/opencode-optima.git"