@aspectlylabs/mikka 0.0.9 → 0.0.11

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/client.js CHANGED
@@ -2843,6 +2843,7 @@ var heartbeatResultSchema = z13.object({
2843
2843
  cloudCredential: z13.string().regex(/^orv_[A-Za-z0-9_-]{43}$/).optional()
2844
2844
  });
2845
2845
  var RUN_CHECKPOINT_MAX_BYTES = 8 * 1024 * 1024;
2846
+ var RUN_CHECKPOINT_RECOVERY_MAX_AGE_MS = 30 * 6e4;
2846
2847
  var runCheckpointSchema = z13.object({
2847
2848
  /** The commit the run's worktree started from. */
2848
2849
  baseCommit: z13.string().regex(/^[0-9a-f]{40,64}$/),
@@ -2854,7 +2855,9 @@ var runCheckpointSchema = z13.object({
2854
2855
  patch: z13.string().max(Math.ceil(RUN_CHECKPOINT_MAX_BYTES * 4 / 3) + 4),
2855
2856
  /** Files the patch touches. */
2856
2857
  files: z13.number().int().nonnegative(),
2857
- takenAt: isoTime
2858
+ takenAt: isoTime,
2859
+ /** The latest tree could not be checkpointed; it supersedes older patches. */
2860
+ unavailableReason: z13.literal("too_large").optional()
2858
2861
  });
2859
2862
  var setupRecipeSchema = z13.object({
2860
2863
  /** Paths relative to the main checkout copied into each new worktree. */
@@ -2959,6 +2962,12 @@ var runAssignmentSchema = z13.object({
2959
2962
  * one, and the run goes ahead without it.
2960
2963
  */
2961
2964
  mcp: z13.object({ url: z13.url(), token: z13.string().min(1).max(200), mailbox: z13.literal(true).optional() }).optional(),
2965
+ /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
2966
+ github: z13.object({
2967
+ endpoint: z13.url(),
2968
+ repository: z13.string().regex(/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/),
2969
+ branch: z13.string().regex(/^mikka\/[a-z0-9-]+-[1-9][0-9]*$/)
2970
+ }).strict().optional(),
2962
2971
  /** Question continuation must not silently open a different session. */
2963
2972
  /**
2964
2973
  * What the orchestrator dispatched this run for (ADR 0023). `plan` writes a
@@ -2971,11 +2980,14 @@ var runAssignmentSchema = z13.object({
2971
2980
  * branch, so nothing the earlier run left uncommitted is lost.
2972
2981
  */
2973
2982
  continuesRunId: id.optional(),
2983
+ /** A same-device retry with no usable snapshot must reuse its real worktree. */
2984
+ requireWorktreeContinuation: z13.literal(true).optional(),
2974
2985
  /**
2975
2986
  * The latest checkpoint of the attempt this run takes over after its
2976
2987
  * machine went offline. Used only for a new worktree (another machine, or
2977
2988
  * the earlier worktree is gone): it starts at `baseCommit` (the base
2978
- * branch when that commit is not here) with the patch applied.
2989
+ * commit with the patch applied. Missing or unusable recovery data blocks
2990
+ * the attempt rather than silently starting again from the base branch.
2979
2991
  */
2980
2992
  resumeFrom: runCheckpointSchema.optional(),
2981
2993
  /**
@@ -3621,7 +3633,7 @@ import { join } from "node:path";
3621
3633
  // package.json
3622
3634
  var package_default = {
3623
3635
  name: "@mikka/daemon",
3624
- version: "0.0.9",
3636
+ version: "0.0.11",
3625
3637
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3626
3638
  type: "module",
3627
3639
  private: true,
@@ -3645,14 +3657,15 @@ var package_default = {
3645
3657
  daemon: "tsx bin/mikka.ts daemon",
3646
3658
  dev: "tsx watch bin/mikka.ts daemon --dev --server memory",
3647
3659
  typecheck: "tsgo --noEmit -p tsconfig.json",
3648
- test: "vitest run && pnpm test:mailbox-cli && pnpm test:repository-identity",
3660
+ test: "vitest run && pnpm test:mailbox-cli && pnpm test:repository-identity && pnpm test:github-credentials",
3649
3661
  "test:mailbox-cli": "node --import tsx --test --test-timeout=60000 test/run-mailbox.node-test.ts",
3650
3662
  "codex:types": 'codex app-server generate-ts --out "${TMPDIR:-/tmp}/mikka-codex-types" && echo "Generated; compare v2/ with src/adapters/codex-protocol.ts"',
3651
3663
  "test:real": "MIKKA_REAL_AGENTS=${MIKKA_REAL_AGENTS:-claude_code,codex,cursor} vitest run test/real-agents.test.ts",
3652
3664
  "test:changed": "vitest run --changed origin/main --passWithNoTests",
3653
3665
  build: "node scripts/build.mjs",
3654
3666
  "test:package": "node --test test/package.test.mjs",
3655
- "test:repository-identity": "node --experimental-strip-types --test test/repository-identity-pure.node-test.ts"
3667
+ "test:repository-identity": "node --experimental-strip-types --test test/repository-identity-pure.node-test.ts",
3668
+ "test:github-credentials": "node --test test/github-credentials.node-test.mjs"
3656
3669
  },
3657
3670
  dependencies: {
3658
3671
  "@agentclientprotocol/sdk": "1.9.0",
@@ -3679,7 +3692,7 @@ var package_default = {
3679
3692
  engines: {
3680
3693
  node: ">=24"
3681
3694
  },
3682
- gitHead: "c00e7bfb748f5e9bf2ee344e5c031b4a6ac0fed6"
3695
+ gitHead: "375d670937ca06c53e47f336870481d38520c1fe"
3683
3696
  };
3684
3697
 
3685
3698
  // src/paths.ts
@@ -0,0 +1,94 @@
1
+ // Run-local credentials only. The App key and the daemon's credentials never
2
+ // enter this process. stdout in `git` mode is the git credential protocol.
3
+ import { readFile, writeFile, rename, lstat } from 'node:fs/promises'
4
+ import { randomUUID } from 'node:crypto'
5
+ import { spawn } from 'node:child_process'
6
+ import { pathToFileURL } from 'node:url'
7
+
8
+ const MAX_CACHE_AGE = 50 * 60_000
9
+
10
+ export function matchesGitRepository(input, repository) {
11
+ return input.protocol === 'https' && input.host === 'github.com' &&
12
+ [repository, `${repository}.git`].some(path => input.path?.toLowerCase() === path.toLowerCase())
13
+ }
14
+
15
+ export async function getRunGitHubToken(config, { fetcher = fetch, now = Date.now, minValidityMs = 60_000 } = {}) {
16
+ const cachePath = `${config.file}.cache`
17
+ try {
18
+ const stat = await lstat(cachePath)
19
+ if (stat.isFile() && (stat.mode & 0o077) === 0) {
20
+ const cached = JSON.parse(await readFile(cachePath, 'utf8'))
21
+ if (cached.repository === config.repository && cached.token &&
22
+ cached.createdAt <= now() && now() - cached.createdAt < MAX_CACHE_AGE && Date.parse(cached.expiresAt) - now() > minValidityMs) return cached.token
23
+ }
24
+ } catch { /* No reusable run-local token. */ }
25
+ const response = await fetcher(config.endpoint, {
26
+ method: 'POST', redirect: 'error', cache: 'no-store',
27
+ headers: { authorization: `Bearer ${config.runToken}` }, signal: AbortSignal.timeout(15_000),
28
+ })
29
+ if (!response.ok) throw new Error('Run GitHub credentials unavailable')
30
+ const result = await response.json()
31
+ if (result.repository?.toLowerCase() !== config.repository.toLowerCase() || typeof result.token !== 'string' || !result.token ||
32
+ !Number.isFinite(Date.parse(result.expiresAt)) || Date.parse(result.expiresAt) - now() <= minValidityMs) throw new Error('Invalid run GitHub credentials')
33
+ const temporary = `${cachePath}.${randomUUID()}`
34
+ await writeFile(temporary, JSON.stringify({ ...result, createdAt: now() }), { mode: 0o600, flag: 'wx' })
35
+ await rename(temporary, cachePath)
36
+ return result.token
37
+ }
38
+
39
+ const WATCH_SEGMENT_MS = 40 * 60_000
40
+
41
+ function cli(config, args, token, timeoutMs) {
42
+ return new Promise((resolve, reject) => {
43
+ const child = spawn(config.gh, args, {
44
+ env: { ...process.env, GH_HOST: 'github.com', GH_TOKEN: token, GITHUB_TOKEN: '', GH_ENTERPRISE_TOKEN: '', GITHUB_ENTERPRISE_TOKEN: '', GH_PROMPT_DISABLED: '1' },
45
+ stdio: 'inherit',
46
+ })
47
+ let timedOut = false, hardStop
48
+ const timer = timeoutMs ? setTimeout(() => {
49
+ timedOut = true
50
+ child.kill('SIGTERM')
51
+ hardStop = setTimeout(() => child.kill('SIGKILL'), 2000)
52
+ hardStop.unref()
53
+ }, timeoutMs) : undefined
54
+ timer?.unref()
55
+ const clear = () => { clearTimeout(timer); clearTimeout(hardStop) }
56
+ child.on('error', () => { clear(); reject(new Error('GitHub CLI could not start')) })
57
+ child.on('close', code => { clear(); resolve({ code: code ?? 1, timedOut }) })
58
+ })
59
+ }
60
+
61
+ /** Native gh owns check semantics, output and --required/--fail-fast flags.
62
+ * Renew only the read-only watch process before its token can expire. This
63
+ * also works with gh versions predating `pr checks --json` support. */
64
+ export async function runGh(config, args, deps = {}) {
65
+ const watch = args[0] === 'pr' && args[1] === 'checks' && args.includes('--watch')
66
+ const token = deps.token ?? (minValidityMs => getRunGitHubToken(config, { minValidityMs }))
67
+ const invoke = deps.invoke ?? ((args, token, timeoutMs) => cli(config, args, token, timeoutMs))
68
+ for (;;) {
69
+ const credential = await token(watch ? WATCH_SEGMENT_MS + 60_000 : 60_000)
70
+ const result = await invoke(args, credential, watch ? WATCH_SEGMENT_MS : undefined)
71
+ if (!watch || !result.timedOut) return result.code
72
+ }
73
+ }
74
+
75
+ async function main() {
76
+ const [mode, file, ...args] = process.argv.slice(2)
77
+ const config = { ...JSON.parse(await readFile(file, 'utf8')), file }
78
+ if (mode === 'git') {
79
+ if (args[0] !== 'get') return
80
+ let text = ''
81
+ for await (const chunk of process.stdin) {
82
+ text += chunk
83
+ if (text.length > 8192) throw new Error('Invalid git credential request')
84
+ }
85
+ const input = Object.fromEntries(text.trim().split('\n').map(line => { const index = line.indexOf('='); return [line.slice(0, index), line.slice(index + 1)] }))
86
+ if (!matchesGitRepository(input, config.repository)) return
87
+ process.stdout.write(`username=x-access-token\npassword=${await getRunGitHubToken(config)}\n\n`)
88
+ } else if (mode === 'gh') process.exitCode = await runGh(config, args)
89
+ else throw new Error('Invalid credential helper mode')
90
+ }
91
+
92
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
93
+ main().catch(() => { process.stderr.write('Mikka GitHub credentials or CI status unavailable.\n'); process.exitCode = 1 })
94
+ }
package/http-link.js CHANGED
@@ -3251,6 +3251,8 @@ var heartbeatResultSchema = z17.object({
3251
3251
  cloudCredential: z17.string().regex(/^orv_[A-Za-z0-9_-]{43}$/).optional()
3252
3252
  });
3253
3253
  var RUN_CHECKPOINT_MAX_BYTES = 8 * 1024 * 1024;
3254
+ var RECOVERY_WORKTREE_HEADER = "x-mikka-recovery-worktree";
3255
+ var RUN_CHECKPOINT_RECOVERY_MAX_AGE_MS = 30 * 6e4;
3254
3256
  var runCheckpointSchema = z17.object({
3255
3257
  /** The commit the run's worktree started from. */
3256
3258
  baseCommit: z17.string().regex(/^[0-9a-f]{40,64}$/),
@@ -3262,7 +3264,9 @@ var runCheckpointSchema = z17.object({
3262
3264
  patch: z17.string().max(Math.ceil(RUN_CHECKPOINT_MAX_BYTES * 4 / 3) + 4),
3263
3265
  /** Files the patch touches. */
3264
3266
  files: z17.number().int().nonnegative(),
3265
- takenAt: isoTime
3267
+ takenAt: isoTime,
3268
+ /** The latest tree could not be checkpointed; it supersedes older patches. */
3269
+ unavailableReason: z17.literal("too_large").optional()
3266
3270
  });
3267
3271
  var setupRecipeSchema = z17.object({
3268
3272
  /** Paths relative to the main checkout copied into each new worktree. */
@@ -3368,6 +3372,12 @@ var runAssignmentSchema = z17.object({
3368
3372
  * one, and the run goes ahead without it.
3369
3373
  */
3370
3374
  mcp: z17.object({ url: z17.url(), token: z17.string().min(1).max(200), mailbox: z17.literal(true).optional() }).optional(),
3375
+ /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3376
+ github: z17.object({
3377
+ endpoint: z17.url(),
3378
+ repository: z17.string().regex(/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/),
3379
+ branch: z17.string().regex(/^mikka\/[a-z0-9-]+-[1-9][0-9]*$/)
3380
+ }).strict().optional(),
3371
3381
  /** Question continuation must not silently open a different session. */
3372
3382
  /**
3373
3383
  * What the orchestrator dispatched this run for (ADR 0023). `plan` writes a
@@ -3380,11 +3390,14 @@ var runAssignmentSchema = z17.object({
3380
3390
  * branch, so nothing the earlier run left uncommitted is lost.
3381
3391
  */
3382
3392
  continuesRunId: id2.optional(),
3393
+ /** A same-device retry with no usable snapshot must reuse its real worktree. */
3394
+ requireWorktreeContinuation: z17.literal(true).optional(),
3383
3395
  /**
3384
3396
  * The latest checkpoint of the attempt this run takes over after its
3385
3397
  * machine went offline. Used only for a new worktree (another machine, or
3386
3398
  * the earlier worktree is gone): it starts at `baseCommit` (the base
3387
- * branch when that commit is not here) with the patch applied.
3399
+ * commit with the patch applied. Missing or unusable recovery data blocks
3400
+ * the attempt rather than silently starting again from the base branch.
3388
3401
  */
3389
3402
  resumeFrom: runCheckpointSchema.optional(),
3390
3403
  /**
@@ -3921,7 +3934,7 @@ var InvalidIdError = class extends DaemonError {
3921
3934
  // package.json
3922
3935
  var package_default = {
3923
3936
  name: "@mikka/daemon",
3924
- version: "0.0.9",
3937
+ version: "0.0.11",
3925
3938
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3926
3939
  type: "module",
3927
3940
  private: true,
@@ -3945,14 +3958,15 @@ var package_default = {
3945
3958
  daemon: "tsx bin/mikka.ts daemon",
3946
3959
  dev: "tsx watch bin/mikka.ts daemon --dev --server memory",
3947
3960
  typecheck: "tsgo --noEmit -p tsconfig.json",
3948
- test: "vitest run && pnpm test:mailbox-cli && pnpm test:repository-identity",
3961
+ test: "vitest run && pnpm test:mailbox-cli && pnpm test:repository-identity && pnpm test:github-credentials",
3949
3962
  "test:mailbox-cli": "node --import tsx --test --test-timeout=60000 test/run-mailbox.node-test.ts",
3950
3963
  "codex:types": 'codex app-server generate-ts --out "${TMPDIR:-/tmp}/mikka-codex-types" && echo "Generated; compare v2/ with src/adapters/codex-protocol.ts"',
3951
3964
  "test:real": "MIKKA_REAL_AGENTS=${MIKKA_REAL_AGENTS:-claude_code,codex,cursor} vitest run test/real-agents.test.ts",
3952
3965
  "test:changed": "vitest run --changed origin/main --passWithNoTests",
3953
3966
  build: "node scripts/build.mjs",
3954
3967
  "test:package": "node --test test/package.test.mjs",
3955
- "test:repository-identity": "node --experimental-strip-types --test test/repository-identity-pure.node-test.ts"
3968
+ "test:repository-identity": "node --experimental-strip-types --test test/repository-identity-pure.node-test.ts",
3969
+ "test:github-credentials": "node --test test/github-credentials.node-test.mjs"
3956
3970
  },
3957
3971
  dependencies: {
3958
3972
  "@agentclientprotocol/sdk": "1.9.0",
@@ -3979,7 +3993,7 @@ var package_default = {
3979
3993
  engines: {
3980
3994
  node: ">=24"
3981
3995
  },
3982
- gitHead: "c00e7bfb748f5e9bf2ee344e5c031b4a6ac0fed6"
3996
+ gitHead: "375d670937ca06c53e47f336870481d38520c1fe"
3983
3997
  };
3984
3998
 
3985
3999
  // src/paths.ts
@@ -4299,6 +4313,7 @@ var HttpServerLink = class {
4299
4313
  [CLIENT_VERSION_HEADER]: this.clientVersion,
4300
4314
  [SKILL_ARTIFACT_HEADER]: "1",
4301
4315
  [REPO_ORIGIN_HEADER]: "1",
4316
+ [RECOVERY_WORKTREE_HEADER]: "1",
4302
4317
  ...token ? { authorization: `Bearer ${token}` } : {},
4303
4318
  ...this.protectionBypass ? { "x-vercel-protection-bypass": this.protectionBypass } : {}
4304
4319
  },
package/login.js CHANGED
@@ -2839,6 +2839,7 @@ var heartbeatResultSchema = z13.object({
2839
2839
  cloudCredential: z13.string().regex(/^orv_[A-Za-z0-9_-]{43}$/).optional()
2840
2840
  });
2841
2841
  var RUN_CHECKPOINT_MAX_BYTES = 8 * 1024 * 1024;
2842
+ var RUN_CHECKPOINT_RECOVERY_MAX_AGE_MS = 30 * 6e4;
2842
2843
  var runCheckpointSchema = z13.object({
2843
2844
  /** The commit the run's worktree started from. */
2844
2845
  baseCommit: z13.string().regex(/^[0-9a-f]{40,64}$/),
@@ -2850,7 +2851,9 @@ var runCheckpointSchema = z13.object({
2850
2851
  patch: z13.string().max(Math.ceil(RUN_CHECKPOINT_MAX_BYTES * 4 / 3) + 4),
2851
2852
  /** Files the patch touches. */
2852
2853
  files: z13.number().int().nonnegative(),
2853
- takenAt: isoTime
2854
+ takenAt: isoTime,
2855
+ /** The latest tree could not be checkpointed; it supersedes older patches. */
2856
+ unavailableReason: z13.literal("too_large").optional()
2854
2857
  });
2855
2858
  var setupRecipeSchema = z13.object({
2856
2859
  /** Paths relative to the main checkout copied into each new worktree. */
@@ -2955,6 +2958,12 @@ var runAssignmentSchema = z13.object({
2955
2958
  * one, and the run goes ahead without it.
2956
2959
  */
2957
2960
  mcp: z13.object({ url: z13.url(), token: z13.string().min(1).max(200), mailbox: z13.literal(true).optional() }).optional(),
2961
+ /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
2962
+ github: z13.object({
2963
+ endpoint: z13.url(),
2964
+ repository: z13.string().regex(/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/),
2965
+ branch: z13.string().regex(/^mikka\/[a-z0-9-]+-[1-9][0-9]*$/)
2966
+ }).strict().optional(),
2958
2967
  /** Question continuation must not silently open a different session. */
2959
2968
  /**
2960
2969
  * What the orchestrator dispatched this run for (ADR 0023). `plan` writes a
@@ -2967,11 +2976,14 @@ var runAssignmentSchema = z13.object({
2967
2976
  * branch, so nothing the earlier run left uncommitted is lost.
2968
2977
  */
2969
2978
  continuesRunId: id.optional(),
2979
+ /** A same-device retry with no usable snapshot must reuse its real worktree. */
2980
+ requireWorktreeContinuation: z13.literal(true).optional(),
2970
2981
  /**
2971
2982
  * The latest checkpoint of the attempt this run takes over after its
2972
2983
  * machine went offline. Used only for a new worktree (another machine, or
2973
2984
  * the earlier worktree is gone): it starts at `baseCommit` (the base
2974
- * branch when that commit is not here) with the patch applied.
2985
+ * commit with the patch applied. Missing or unusable recovery data blocks
2986
+ * the attempt rather than silently starting again from the base branch.
2975
2987
  */
2976
2988
  resumeFrom: runCheckpointSchema.optional(),
2977
2989
  /**
@@ -3628,7 +3640,7 @@ var ServerUnreachableError = class extends DaemonError {
3628
3640
  // package.json
3629
3641
  var package_default = {
3630
3642
  name: "@mikka/daemon",
3631
- version: "0.0.9",
3643
+ version: "0.0.11",
3632
3644
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3633
3645
  type: "module",
3634
3646
  private: true,
@@ -3652,14 +3664,15 @@ var package_default = {
3652
3664
  daemon: "tsx bin/mikka.ts daemon",
3653
3665
  dev: "tsx watch bin/mikka.ts daemon --dev --server memory",
3654
3666
  typecheck: "tsgo --noEmit -p tsconfig.json",
3655
- test: "vitest run && pnpm test:mailbox-cli && pnpm test:repository-identity",
3667
+ test: "vitest run && pnpm test:mailbox-cli && pnpm test:repository-identity && pnpm test:github-credentials",
3656
3668
  "test:mailbox-cli": "node --import tsx --test --test-timeout=60000 test/run-mailbox.node-test.ts",
3657
3669
  "codex:types": 'codex app-server generate-ts --out "${TMPDIR:-/tmp}/mikka-codex-types" && echo "Generated; compare v2/ with src/adapters/codex-protocol.ts"',
3658
3670
  "test:real": "MIKKA_REAL_AGENTS=${MIKKA_REAL_AGENTS:-claude_code,codex,cursor} vitest run test/real-agents.test.ts",
3659
3671
  "test:changed": "vitest run --changed origin/main --passWithNoTests",
3660
3672
  build: "node scripts/build.mjs",
3661
3673
  "test:package": "node --test test/package.test.mjs",
3662
- "test:repository-identity": "node --experimental-strip-types --test test/repository-identity-pure.node-test.ts"
3674
+ "test:repository-identity": "node --experimental-strip-types --test test/repository-identity-pure.node-test.ts",
3675
+ "test:github-credentials": "node --test test/github-credentials.node-test.mjs"
3663
3676
  },
3664
3677
  dependencies: {
3665
3678
  "@agentclientprotocol/sdk": "1.9.0",
@@ -3686,7 +3699,7 @@ var package_default = {
3686
3699
  engines: {
3687
3700
  node: ">=24"
3688
3701
  },
3689
- gitHead: "c00e7bfb748f5e9bf2ee344e5c031b4a6ac0fed6"
3702
+ gitHead: "375d670937ca06c53e47f336870481d38520c1fe"
3690
3703
  };
3691
3704
 
3692
3705
  // src/paths.ts