@oisincoveney/pipeline 3.11.18 → 3.11.20

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.
@@ -21,6 +21,9 @@ const RUNNER_RETRY_STRATEGY = {
21
21
  const RUNNER_OPENCODE_ENV = [{
22
22
  name: "CODEX_AUTH_PER_PROJECT_ACCOUNTS",
23
23
  value: "0"
24
+ }, {
25
+ name: "PIPELINE_AGENT_TIMEOUT_MS",
26
+ value: "1200000"
24
27
  }];
25
28
  const DEFAULT_RUNNER_RESOURCES = {
26
29
  limits: {
@@ -32,7 +35,7 @@ const DEFAULT_RUNNER_RESOURCES = {
32
35
  memory: "5Gi"
33
36
  }
34
37
  };
35
- const DEFAULT_RUNNER_DEADLINE_SECONDS = 3600;
38
+ const DEFAULT_RUNNER_DEADLINE_SECONDS = 5400;
36
39
  const kubernetesNameSchema = z.string().min(1);
37
40
  const labelValueSchema = z.string().min(1);
38
41
  const stringMapSchema = z.record(z.string().min(1), z.string().min(1));
@@ -5,13 +5,13 @@ import { z } from "zod";
5
5
  //#region src/moka-submit.d.ts
6
6
  declare const mokaSubmitDirectHooksSchema: z.ZodRecord<z.ZodEnum<{
7
7
  "workflow.start": "workflow.start";
8
+ "node.finish": "node.finish";
9
+ "node.start": "node.start";
8
10
  "workflow.success": "workflow.success";
9
11
  "workflow.failure": "workflow.failure";
10
12
  "workflow.complete": "workflow.complete";
11
- "node.start": "node.start";
12
13
  "node.success": "node.success";
13
14
  "node.error": "node.error";
14
- "node.finish": "node.finish";
15
15
  "gate.failure": "gate.failure";
16
16
  }> & z.core.$partial, z.ZodDiscriminatedUnion<[z.ZodObject<{
17
17
  failure: z.ZodDefault<z.ZodEnum<{
@@ -94,13 +94,13 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
94
94
  }, z.core.$strict>>;
95
95
  hooks: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
96
96
  "workflow.start": "workflow.start";
97
+ "node.finish": "node.finish";
98
+ "node.start": "node.start";
97
99
  "workflow.success": "workflow.success";
98
100
  "workflow.failure": "workflow.failure";
99
101
  "workflow.complete": "workflow.complete";
100
- "node.start": "node.start";
101
102
  "node.success": "node.success";
102
103
  "node.error": "node.error";
103
- "node.finish": "node.finish";
104
104
  "gate.failure": "gate.failure";
105
105
  }> & z.core.$partial, z.ZodDiscriminatedUnion<[z.ZodObject<{
106
106
  failure: z.ZodDefault<z.ZodEnum<{
@@ -207,13 +207,13 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
207
207
  }, z.core.$strict>>;
208
208
  hooks: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
209
209
  "workflow.start": "workflow.start";
210
+ "node.finish": "node.finish";
211
+ "node.start": "node.start";
210
212
  "workflow.success": "workflow.success";
211
213
  "workflow.failure": "workflow.failure";
212
214
  "workflow.complete": "workflow.complete";
213
- "node.start": "node.start";
214
215
  "node.success": "node.success";
215
216
  "node.error": "node.error";
216
- "node.finish": "node.finish";
217
217
  "gate.failure": "gate.failure";
218
218
  }> & z.core.$partial, z.ZodDiscriminatedUnion<[z.ZodObject<{
219
219
  failure: z.ZodDefault<z.ZodEnum<{
@@ -1,26 +1,30 @@
1
- import { chmodSync, copyFileSync, existsSync, mkdirSync } from "node:fs";
1
+ import { isRecord } from "../safe-json.js";
2
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
3
  import { homedir } from "node:os";
3
4
  import { basename, dirname, join } from "node:path";
4
5
  //#region src/run-state/opencode-accounts.ts
5
6
  const OPENCODE_OPENAI_ACCOUNTS_STAGING_DIR = "/etc/pipeline/opencode-openai-accounts";
6
7
  const OPENCODE_AUTH_STAGING_DIR = "/etc/pipeline/opencode-auth";
8
+ const ACCOUNTS_FILE_NAME = "oc-codex-multi-auth-accounts.json";
9
+ const AUTH_FILE_NAME = "auth.json";
10
+ const HOST_OPENAI_PROVIDER = "openai";
7
11
  const WRITABLE_OPENCODE_CREDENTIAL_FILES = [{
8
- destFromHome: [".opencode", "oc-codex-multi-auth-accounts.json"],
12
+ destFromHome: [".opencode", ACCOUNTS_FILE_NAME],
9
13
  stagedPath: join(OPENCODE_OPENAI_ACCOUNTS_STAGING_DIR, "accounts.json")
10
14
  }, {
11
15
  destFromHome: [
12
16
  ".local",
13
17
  "share",
14
18
  "opencode",
15
- "auth.json"
19
+ AUTH_FILE_NAME
16
20
  ],
17
- stagedPath: join(OPENCODE_AUTH_STAGING_DIR, "auth.json")
21
+ stagedPath: join(OPENCODE_AUTH_STAGING_DIR, AUTH_FILE_NAME)
18
22
  }];
19
23
  /**
20
- * Copy each staged opencode credential secret to its writable live path so the
21
- * plugin can rewrite tokens. Only files whose staged source exists are copied
22
- * (local dev / tests / configs without a given secret keep whatever store is
23
- * already present). Returns the basenames copied, for run-log evidence.
24
+ * Copy each staged opencode credential secret to its writable live path, then
25
+ * sync the account pool's active openai token into auth.json's openai entry.
26
+ * Only files whose staged source exists are copied (local dev / tests / configs
27
+ * without a given secret keep whatever store is already present).
24
28
  */
25
29
  function prepareOpencodeCredentials(options = {}) {
26
30
  const home = homedir();
@@ -36,7 +40,53 @@ function prepareOpencodeCredentials(options = {}) {
36
40
  chmodSync(destPath, 384);
37
41
  copied.push(basename(destPath));
38
42
  }
39
- return { copied };
43
+ const accountsPath = files.find((file) => basename(file.destPath) === ACCOUNTS_FILE_NAME)?.destPath;
44
+ const authPath = files.find((file) => basename(file.destPath) === AUTH_FILE_NAME)?.destPath;
45
+ return {
46
+ copied,
47
+ hostOpenaiTokenSynced: accountsPath !== void 0 && authPath !== void 0 && syncHostOpenaiToken(accountsPath, authPath)
48
+ };
49
+ }
50
+ function activeAccountOAuth(accountsRaw) {
51
+ if (!isRecord(accountsRaw)) return;
52
+ const accounts = accountsRaw.accounts;
53
+ if (!Array.isArray(accounts)) return;
54
+ const account = accounts[activeAccountIndex(accountsRaw)] ?? accounts[0];
55
+ return isRecord(account) ? oauthFromAccount(account) : void 0;
56
+ }
57
+ function nonEmptyString(value) {
58
+ return typeof value === "string" && value.length > 0;
59
+ }
60
+ function oauthFromAccount(account) {
61
+ const { accessToken, refreshToken, expiresAt } = account;
62
+ if (nonEmptyString(accessToken) && nonEmptyString(refreshToken) && typeof expiresAt === "number") return {
63
+ access: accessToken,
64
+ expires: expiresAt,
65
+ refresh: refreshToken
66
+ };
67
+ }
68
+ function activeAccountIndex(accountsRaw) {
69
+ const byFamily = accountsRaw.activeIndexByFamily;
70
+ if (isRecord(byFamily) && typeof byFamily.codex === "number") return byFamily.codex;
71
+ return typeof accountsRaw.activeIndex === "number" ? accountsRaw.activeIndex : 0;
72
+ }
73
+ function syncHostOpenaiToken(accountsPath, authPath) {
74
+ if (!(existsSync(accountsPath) && existsSync(authPath))) return false;
75
+ const token = activeAccountOAuth(JSON.parse(readFileSync(accountsPath, "utf8")));
76
+ if (!token) return false;
77
+ const auth = JSON.parse(readFileSync(authPath, "utf8"));
78
+ if (!isRecord(auth)) return false;
79
+ const next = {
80
+ ...auth,
81
+ [HOST_OPENAI_PROVIDER]: {
82
+ access: token.access,
83
+ expires: token.expires,
84
+ refresh: token.refresh,
85
+ type: "oauth"
86
+ }
87
+ };
88
+ writeFileSync(authPath, `${JSON.stringify(next, null, 2)}\n`, { mode: 384 });
89
+ return true;
40
90
  }
41
91
  //#endregion
42
92
  export { OPENCODE_AUTH_STAGING_DIR, OPENCODE_OPENAI_ACCOUNTS_STAGING_DIR, prepareOpencodeCredentials };
@@ -107,6 +107,7 @@ function runRunnerCommandEffect(options, runtime) {
107
107
  const credentialsPrep = yield* io.prepareOpencodeCredentials();
108
108
  logger.info({
109
109
  copied: credentialsPrep.copied,
110
+ hostOpenaiTokenSynced: credentialsPrep.hostOpenaiTokenSynced,
110
111
  phase: "opencode.credentials.prepare",
111
112
  status: "finish"
112
113
  }, "opencode.credentials.prepare finish");
@@ -11,8 +11,8 @@ declare const runnerEventRecordSchema: z.ZodUnion<readonly [z.ZodObject<{
11
11
  runId: z.ZodString;
12
12
  sequence: z.ZodNumber;
13
13
  type: z.ZodEnum<{
14
- "workflow.start": "workflow.start";
15
14
  "workflow.planned": "workflow.planned";
15
+ "workflow.start": "workflow.start";
16
16
  }>;
17
17
  workflowPlan: z.ZodObject<{
18
18
  edges: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -58,10 +58,10 @@ declare const runnerEventRecordSchema: z.ZodUnion<readonly [z.ZodObject<{
58
58
  }>;
59
59
  }, z.core.$strip>;
60
60
  type: z.ZodEnum<{
61
- "node.start": "node.start";
62
- "node.finish": "node.finish";
63
61
  "agent.finish": "agent.finish";
64
62
  "agent.start": "agent.start";
63
+ "node.finish": "node.finish";
64
+ "node.start": "node.start";
65
65
  }>;
66
66
  }, z.core.$strip>, z.ZodObject<{
67
67
  at: z.ZodOptional<z.ZodString>;
@@ -189,8 +189,8 @@ declare const runnerEventBatchSchema: z.ZodObject<{
189
189
  runId: z.ZodString;
190
190
  sequence: z.ZodNumber;
191
191
  type: z.ZodEnum<{
192
- "workflow.start": "workflow.start";
193
192
  "workflow.planned": "workflow.planned";
193
+ "workflow.start": "workflow.start";
194
194
  }>;
195
195
  workflowPlan: z.ZodObject<{
196
196
  edges: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -236,10 +236,10 @@ declare const runnerEventBatchSchema: z.ZodObject<{
236
236
  }>;
237
237
  }, z.core.$strip>;
238
238
  type: z.ZodEnum<{
239
- "node.start": "node.start";
240
- "node.finish": "node.finish";
241
239
  "agent.finish": "agent.finish";
242
240
  "agent.start": "agent.start";
241
+ "node.finish": "node.finish";
242
+ "node.start": "node.start";
243
243
  }>;
244
244
  }, z.core.$strip>, z.ZodObject<{
245
245
  at: z.ZodOptional<z.ZodString>;
@@ -1,5 +1,5 @@
1
- import { flattenNodes } from "../../planning/graph.js";
2
1
  import { isRecord } from "../../safe-json.js";
2
+ import { flattenNodes } from "../../planning/graph.js";
3
3
  import { runtimeActorId } from "../actor-ids.js";
4
4
  import { parseRuntimeOutput, validateJsonSchemaSource } from "../json-validation/json-validation.js";
5
5
  import "../json-validation/index.js";
@@ -1,5 +1,5 @@
1
- import { standardOutputSchemaJson, standardOutputSchemaNameFromPath } from "../../standard-output-schemas.js";
2
1
  import { isRecord, parseJson, parseJsonRecord } from "../../safe-json.js";
2
+ import { standardOutputSchemaJson, standardOutputSchemaNameFromPath } from "../../standard-output-schemas.js";
3
3
  import { FileSystemService, FileSystemServiceLive, runFileSystemSync } from "../services/file-system-service.js";
4
4
  import { Effect } from "effect";
5
5
  import { join } from "node:path";
@@ -24,7 +24,17 @@ function executeOpencodeEffect(deps, plan, options) {
24
24
  function executeOpencodeSession(deps, plan, options) {
25
25
  return Effect.gen(function* () {
26
26
  return successResult(plan, yield* driveSession(deps, plan, options));
27
- }).pipe(Effect.catchAll((error) => Effect.succeed(failureResult(plan, error))));
27
+ }).pipe(withAgentTimeout(plan), Effect.catchAll((error) => Effect.succeed(failureResult(plan, error))));
28
+ }
29
+ function withAgentTimeout(plan) {
30
+ return (effect) => {
31
+ const timeoutMs = plan.timeoutMs;
32
+ if (!timeoutMs || timeoutMs <= 0) return effect;
33
+ return Effect.timeoutFail(effect, {
34
+ duration: Duration.millis(timeoutMs),
35
+ onTimeout: () => /* @__PURE__ */ new Error(`agent session timed out after ${timeoutMs}ms`)
36
+ });
37
+ };
28
38
  }
29
39
  function validateOpencodePlan(plan) {
30
40
  if (plan.type === "opencode") return Effect.void;
package/package.json CHANGED
@@ -128,7 +128,7 @@
128
128
  "prepack": "bun run build:cli"
129
129
  },
130
130
  "type": "module",
131
- "version": "3.11.18",
131
+ "version": "3.11.20",
132
132
  "description": "Config-driven multi-agent pipeline runner for repository work",
133
133
  "main": "./dist/index.js",
134
134
  "types": "./dist/index.d.ts",