agent-dealer 0.2.0 → 1.0.0
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/bundle/server/dist/adapters/agent-deck-bind.js +443 -0
- package/bundle/server/dist/adapters/agent-deck-bind.test.js +454 -0
- package/bundle/server/dist/adapters/agent-deck.js +38 -50
- package/bundle/server/dist/adapters/agent-deck.test.js +63 -0
- package/bundle/server/dist/adapters/agent-health.js +230 -33
- package/bundle/server/dist/adapters/agent-health.test.js +237 -0
- package/bundle/server/dist/adapters/authority-lifecycle.js +289 -0
- package/bundle/server/dist/adapters/codex-scoped-config.js +103 -0
- package/bundle/server/dist/adapters/execution-authority.js +103 -0
- package/bundle/server/dist/adapters/execution-authority.test.js +166 -0
- package/bundle/server/dist/adapters/external.js +0 -1
- package/bundle/server/dist/adapters/git-worktree.js +514 -0
- package/bundle/server/dist/adapters/git-worktree.test.js +502 -0
- package/bundle/server/dist/adapters/github.js +170 -0
- package/bundle/server/dist/adapters/github.test.js +205 -0
- package/bundle/server/dist/adapters/linear-inbox.js +199 -30
- package/bundle/server/dist/adapters/linear-inbox.test.js +35 -0
- package/bundle/server/dist/adapters/linear-sync.js +3 -101
- package/bundle/server/dist/adapters/managed-repo.js +168 -0
- package/bundle/server/dist/adapters/managed-repo.test.js +63 -0
- package/bundle/server/dist/adapters/outbound-delivery.js +83 -0
- package/bundle/server/dist/adapters/outbound-delivery.test.js +53 -0
- package/bundle/server/dist/adapters/reflect-authority.js +43 -0
- package/bundle/server/dist/cli-env.js +26 -0
- package/bundle/server/dist/cli-env.test.js +14 -1
- package/bundle/server/dist/coordinator/abort.integration.test.js +74 -0
- package/bundle/server/dist/coordinator/admission.js +330 -0
- package/bundle/server/dist/coordinator/admission.test.js +338 -0
- package/bundle/server/dist/coordinator/args.js +128 -0
- package/bundle/server/dist/coordinator/args.test.js +132 -0
- package/bundle/server/dist/coordinator/authority-recovery.integration.test.js +661 -0
- package/bundle/server/dist/coordinator/auto-merge.integration.test.js +363 -0
- package/bundle/server/dist/coordinator/auto-merge.js +286 -0
- package/bundle/server/dist/coordinator/auto-merge.timeout.test.js +14 -0
- package/bundle/server/dist/coordinator/branch-progress.js +81 -0
- package/bundle/server/dist/coordinator/clock-jump.js +98 -0
- package/bundle/server/dist/coordinator/commands.js +1088 -0
- package/bundle/server/dist/coordinator/commands.test.js +554 -0
- package/bundle/server/dist/coordinator/deck-outage-config.js +32 -0
- package/bundle/server/dist/coordinator/deck-outage.integration.test.js +200 -0
- package/bundle/server/dist/coordinator/dependencies.js +242 -0
- package/bundle/server/dist/coordinator/dependency-readiness.integration.test.js +535 -0
- package/bundle/server/dist/coordinator/developer-effect.js +959 -0
- package/bundle/server/dist/coordinator/developer-effect.test.js +1143 -0
- package/bundle/server/dist/coordinator/dispatcher.js +58 -0
- package/bundle/server/dist/coordinator/dispatcher.test.js +81 -0
- package/bundle/server/dist/coordinator/effect-registry.js +17 -0
- package/bundle/server/dist/coordinator/execution-env.integration.test.js +122 -0
- package/bundle/server/dist/coordinator/failure-reason.js +273 -0
- package/bundle/server/dist/coordinator/failure-reason.test.js +234 -0
- package/bundle/server/dist/coordinator/guidance.js +33 -0
- package/bundle/server/dist/coordinator/guidance.test.js +110 -0
- package/bundle/server/dist/coordinator/human-resolution.js +88 -0
- package/bundle/server/dist/coordinator/human-resolution.test.js +72 -0
- package/bundle/server/dist/coordinator/intent-forecast.js +13 -0
- package/bundle/server/dist/coordinator/intent-forecast.test.js +34 -0
- package/bundle/server/dist/coordinator/latest-failure.js +100 -0
- package/bundle/server/dist/coordinator/latest-failure.test.js +125 -0
- package/bundle/server/dist/coordinator/metrics.js +35 -0
- package/bundle/server/dist/coordinator/metrics.test.js +52 -0
- package/bundle/server/dist/coordinator/permissions.js +127 -0
- package/bundle/server/dist/coordinator/permissions.test.js +184 -0
- package/bundle/server/dist/coordinator/presumed-dead-budget.integration.test.js +146 -0
- package/bundle/server/dist/coordinator/process-liveness.js +191 -0
- package/bundle/server/dist/coordinator/profile-snapshot.js +20 -0
- package/bundle/server/dist/coordinator/profile-snapshot.test.js +118 -0
- package/bundle/server/dist/coordinator/projection.js +147 -0
- package/bundle/server/dist/coordinator/projection.test.js +121 -0
- package/bundle/server/dist/coordinator/prompts.js +164 -0
- package/bundle/server/dist/coordinator/prompts.test.js +177 -0
- package/bundle/server/dist/coordinator/queue-by-default.integration.test.js +271 -0
- package/bundle/server/dist/coordinator/reclaim-republish.integration.test.js +372 -0
- package/bundle/server/dist/coordinator/recovery.js +466 -0
- package/bundle/server/dist/coordinator/recovery.test.js +164 -0
- package/bundle/server/dist/coordinator/reflect-trigger.js +218 -0
- package/bundle/server/dist/coordinator/reflect-trigger.test.js +324 -0
- package/bundle/server/dist/coordinator/repair-cycle.integration.test.js +234 -0
- package/bundle/server/dist/coordinator/restart-recovery.integration.test.js +363 -0
- package/bundle/server/dist/coordinator/reviewer-effect.js +507 -0
- package/bundle/server/dist/coordinator/reviewer-effect.test.js +612 -0
- package/bundle/server/dist/coordinator/reviewer-result.js +38 -0
- package/bundle/server/dist/coordinator/reviewer-result.test.js +45 -0
- package/bundle/server/dist/coordinator/routing.js +160 -0
- package/bundle/server/dist/coordinator/routing.test.js +336 -0
- package/bundle/server/dist/coordinator/session-lifecycle.integration.test.js +127 -0
- package/bundle/server/dist/coordinator/session-lifecycle.js +280 -0
- package/bundle/server/dist/coordinator/session-lifecycle.test.js +121 -0
- package/bundle/server/dist/coordinator/session-progress.js +351 -0
- package/bundle/server/dist/coordinator/session-progress.test.js +190 -0
- package/bundle/server/dist/coordinator/session-timeouts.js +33 -0
- package/bundle/server/dist/coordinator/sleep-recovery.integration.test.js +233 -0
- package/bundle/server/dist/coordinator/spawn.js +49 -0
- package/bundle/server/dist/coordinator/sync-issue-base-branch.js +18 -0
- package/bundle/server/dist/coordinator/usage-cap-config.js +10 -0
- package/bundle/server/dist/coordinator/usage-cap-defer.js +189 -0
- package/bundle/server/dist/coordinator/usage-cap.integration.test.js +193 -0
- package/bundle/server/dist/coordinator/usage.js +40 -0
- package/bundle/server/dist/coordinator/usage.test.js +69 -0
- package/bundle/server/dist/coordinator/verification-receipt.js +333 -0
- package/bundle/server/dist/coordinator/verification-receipt.test.js +382 -0
- package/bundle/server/dist/coordinator/worker-loop.js +363 -0
- package/bundle/server/dist/coordinator/worker-loop.test.js +327 -0
- package/bundle/server/dist/coordinator/workflow-instances.test.js +45 -0
- package/bundle/server/dist/coordinator/worktree-owner-liveness.js +82 -0
- package/bundle/server/dist/coordinator/worktree-owner-liveness.test.js +199 -0
- package/bundle/server/dist/db/artifacts-issue-columns.test.js +18 -0
- package/bundle/server/dist/db/authority-attempts-stale-at-migration.test.js +65 -0
- package/bundle/server/dist/db/idempotency-index-migration.test.js +57 -0
- package/bundle/server/dist/db/index.js +359 -7
- package/bundle/server/dist/db/linear-inbox-unlock.test.js +67 -0
- package/bundle/server/dist/db/migrate-to-issues.js +824 -0
- package/bundle/server/dist/db/migrate-to-issues.test.js +842 -0
- package/bundle/server/dist/db/schema.sql +311 -1
- package/bundle/server/dist/db/schema.test.js +66 -0
- package/bundle/server/dist/db/worker-session-pid-migration.test.js +112 -0
- package/bundle/server/dist/dev-review-cli-happy-path.integration.test.js +338 -0
- package/bundle/server/dist/direct-start-liveness.integration.test.js +350 -0
- package/bundle/server/dist/index.js +58 -5
- package/bundle/server/dist/paths.js +40 -4
- package/bundle/server/dist/paths.test.js +42 -0
- package/bundle/server/dist/pid-marker-claim-child.js +18 -0
- package/bundle/server/dist/pid-marker-hold-arbiter-child.js +24 -0
- package/bundle/server/dist/pid-marker.js +141 -0
- package/bundle/server/dist/pid-marker.test.js +208 -0
- package/bundle/server/dist/queue/approve-deliver.js +128 -28
- package/bundle/server/dist/queue/reflect-schedule.js +25 -0
- package/bundle/server/dist/queue/result-qa.js +1 -1
- package/bundle/server/dist/queue/send-gate.test.js +172 -36
- package/bundle/server/dist/repository/agents.js +55 -18
- package/bundle/server/dist/repository/artifacts-for-issue.js +42 -0
- package/bundle/server/dist/repository/artifacts-for-issue.test.js +48 -0
- package/bundle/server/dist/repository/artifacts.js +47 -0
- package/bundle/server/dist/repository/artifacts.test.js +48 -0
- package/bundle/server/dist/repository/authority-attempts.js +189 -0
- package/bundle/server/dist/repository/findings.js +70 -0
- package/bundle/server/dist/repository/findings.test.js +68 -0
- package/bundle/server/dist/repository/human-actions.js +142 -0
- package/bundle/server/dist/repository/human-actions.test.js +123 -0
- package/bundle/server/dist/repository/intake-settings.js +5 -59
- package/bundle/server/dist/repository/issues.js +305 -0
- package/bundle/server/dist/repository/issues.test.js +69 -0
- package/bundle/server/dist/repository/outbound-drafts.js +28 -0
- package/bundle/server/dist/repository/queue-entries.js +162 -0
- package/bundle/server/dist/repository/review-publications.js +153 -0
- package/bundle/server/dist/repository/review-publications.test.js +78 -0
- package/bundle/server/dist/repository/runs-external-id.test.js +5 -3
- package/bundle/server/dist/repository/runs.js +4 -211
- package/bundle/server/dist/repository/runtime-availability.js +54 -0
- package/bundle/server/dist/repository/usage-events.js +60 -0
- package/bundle/server/dist/repository/usage-events.test.js +56 -0
- package/bundle/server/dist/repository/work-items.js +305 -0
- package/bundle/server/dist/repository/work-items.test.js +142 -0
- package/bundle/server/dist/repository/worker-sessions.js +219 -0
- package/bundle/server/dist/repository/worker-sessions.test.js +60 -0
- package/bundle/server/dist/repository/workflow-events.js +193 -0
- package/bundle/server/dist/repository/workflow-events.test.js +89 -0
- package/bundle/server/dist/resolve-tsx-bin.js +19 -0
- package/bundle/server/dist/routes/human-actions.js +68 -0
- package/bundle/server/dist/routes/human-actions.test.js +284 -0
- package/bundle/server/dist/routes/index.js +29 -496
- package/bundle/server/dist/routes/issues.js +240 -0
- package/bundle/server/dist/routes/issues.test.js +451 -0
- package/bundle/server/dist/routes/queue.js +41 -0
- package/bundle/server/dist/routes/queue.test.js +78 -0
- package/bundle/server/dist/runners/claude-args.js +18 -30
- package/bundle/server/dist/runners/claude.js +19 -163
- package/bundle/server/dist/runners/claude.test.js +15 -70
- package/bundle/server/dist/runners/codex-args.js +59 -0
- package/bundle/server/dist/runners/codex-args.test.js +72 -0
- package/bundle/server/dist/runners/codex-jsonl.js +150 -0
- package/bundle/server/dist/runners/codex-jsonl.test.js +36 -0
- package/bundle/server/dist/runners/codex-resume.test.js +19 -0
- package/bundle/server/dist/runners/codex.js +46 -0
- package/bundle/server/dist/runners/models-codex.test.js +14 -0
- package/bundle/server/dist/runners/models.js +53 -1
- package/bundle/server/dist/runners/persist.js +4 -1
- package/bundle/server/dist/runners/process-registry.js +11 -0
- package/bundle/server/dist/runners/prompts.js +13 -280
- package/bundle/server/dist/runners/prompts.test.js +22 -153
- package/bundle/server/dist/runners/qa.js +17 -1
- package/bundle/server/dist/runners/reflect.js +4 -16
- package/bundle/server/dist/runners/spawn-cli.js +197 -0
- package/bundle/server/dist/runners/spawn-cli.test.js +130 -0
- package/bundle/server/dist/runners/stream-json.js +0 -141
- package/bundle/server/dist/runners/usage-cap.js +242 -0
- package/bundle/server/dist/runners/usage-cap.test.js +97 -0
- package/bundle/server/dist/server-liveness.js +37 -0
- package/bundle/server/dist/server-liveness.test.js +82 -0
- package/bundle/server/dist/static-ui.test.js +44 -0
- package/bundle/server/package.json +4 -2
- package/bundle/server/static-ui/assets/index-BTtPGYpY.js +60 -0
- package/bundle/server/static-ui/assets/index-BxTx4b1d.css +1 -0
- package/bundle/server/static-ui/index.html +2 -2
- package/bundle/shared/dist/agents.d.ts +262 -133
- package/bundle/shared/dist/agents.js +85 -19
- package/bundle/shared/dist/cursor-auth-health.d.ts +12 -0
- package/bundle/shared/dist/cursor-auth-health.js +36 -0
- package/bundle/shared/dist/cursor-auth-health.test.d.ts +1 -0
- package/bundle/shared/dist/cursor-auth-health.test.js +40 -0
- package/bundle/shared/dist/findings.d.ts +46 -0
- package/bundle/shared/dist/findings.js +17 -0
- package/bundle/shared/dist/findings.test.d.ts +1 -0
- package/bundle/shared/dist/findings.test.js +20 -0
- package/bundle/shared/dist/github-repo.d.ts +28 -0
- package/bundle/shared/dist/github-repo.js +98 -0
- package/bundle/shared/dist/github-repo.test.d.ts +1 -0
- package/bundle/shared/dist/github-repo.test.js +32 -0
- package/bundle/shared/dist/human-actions.d.ts +66 -0
- package/bundle/shared/dist/human-actions.js +51 -0
- package/bundle/shared/dist/human-actions.test.d.ts +1 -0
- package/bundle/shared/dist/human-actions.test.js +57 -0
- package/bundle/shared/dist/index.d.ts +567 -757
- package/bundle/shared/dist/index.js +22 -36
- package/bundle/shared/dist/issues.d.ts +385 -0
- package/bundle/shared/dist/issues.js +169 -0
- package/bundle/shared/dist/issues.test.d.ts +1 -0
- package/bundle/shared/dist/issues.test.js +72 -0
- package/bundle/shared/dist/outbound-draft.d.ts +6 -0
- package/bundle/shared/dist/outbound-draft.js +4 -0
- package/bundle/shared/dist/plan-triage.d.ts +6 -6
- package/bundle/shared/dist/profile-snapshot.d.ts +154 -0
- package/bundle/shared/dist/profile-snapshot.js +145 -0
- package/bundle/shared/dist/profile-snapshot.test.d.ts +1 -0
- package/bundle/shared/dist/profile-snapshot.test.js +67 -0
- package/bundle/shared/dist/queue-entries.d.ts +89 -0
- package/bundle/shared/dist/queue-entries.js +19 -0
- package/bundle/shared/dist/result-qa.d.ts +2 -2
- package/bundle/shared/dist/runtime-auth-health.d.ts +66 -0
- package/bundle/shared/dist/runtime-auth-health.js +186 -0
- package/bundle/shared/dist/runtime-auth-health.test.d.ts +1 -0
- package/bundle/shared/dist/runtime-auth-health.test.js +200 -0
- package/bundle/shared/dist/runtime-availability.d.ts +51 -0
- package/bundle/shared/dist/runtime-availability.js +13 -0
- package/bundle/shared/dist/runtime.d.ts +1 -1
- package/bundle/shared/dist/runtime.js +1 -1
- package/bundle/shared/dist/usage-events.d.ts +36 -0
- package/bundle/shared/dist/usage-events.js +13 -0
- package/bundle/shared/dist/worker-sessions.d.ts +140 -0
- package/bundle/shared/dist/worker-sessions.js +70 -0
- package/bundle/shared/dist/worker-sessions.test.d.ts +1 -0
- package/bundle/shared/dist/worker-sessions.test.js +39 -0
- package/bundle/shared/dist/workflow.d.ts +78 -0
- package/bundle/shared/dist/workflow.js +59 -0
- package/bundle/shared/dist/workflow.test.d.ts +1 -0
- package/bundle/shared/dist/workflow.test.js +61 -0
- package/bundle/shared/package.json +1 -1
- package/dist/action.d.ts +1 -0
- package/dist/action.js +50 -0
- package/dist/action.test.d.ts +1 -0
- package/dist/action.test.js +70 -0
- package/dist/agent.d.ts +1 -0
- package/dist/agent.js +17 -0
- package/dist/agent.test.d.ts +1 -0
- package/dist/agent.test.js +19 -0
- package/dist/cli-check.d.ts +7 -0
- package/dist/cli-check.js +40 -0
- package/dist/doctor.js +59 -1
- package/dist/http.d.ts +5 -0
- package/dist/http.js +19 -0
- package/dist/index.js +28 -0
- package/dist/issue.d.ts +35 -0
- package/dist/issue.js +143 -0
- package/dist/issue.test.d.ts +1 -0
- package/dist/issue.test.js +240 -0
- package/dist/lifecycle.contract.test.d.ts +1 -0
- package/dist/lifecycle.contract.test.js +135 -0
- package/dist/queue.d.ts +11 -0
- package/dist/queue.js +60 -0
- package/dist/queue.test.d.ts +1 -0
- package/dist/queue.test.js +46 -0
- package/dist/test-fetch-stub.d.ts +6 -0
- package/dist/test-fetch-stub.js +31 -0
- package/package.json +2 -1
- package/templates/prod.env.example +1 -1
- package/bundle/server/static-ui/assets/index-B_7S7xJb.js +0 -79
- package/bundle/server/static-ui/assets/index-QYv3zmE6.css +0 -1
|
@@ -1,33 +1,79 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { PhaseBudget } from "./budget.js";
|
|
2
|
+
import { PhaseBudget, parsePhaseBudget, serializePhaseBudget } from "./budget.js";
|
|
3
3
|
import { Runtime } from "./runtime.js";
|
|
4
|
+
import { PermissionPolicyOverride, ReasoningEffort } from "./profile-snapshot.js";
|
|
4
5
|
/** Built-in agent IDs — stable across installs. */
|
|
5
6
|
export const BUILTIN_AGENT_CLAUDE_ID = "00000000-0000-4000-a000-000000000001";
|
|
6
7
|
export const BUILTIN_AGENT_CURSOR_ID = "00000000-0000-4000-a000-000000000002";
|
|
8
|
+
export const BUILTIN_AGENT_CODEX_ID = "00000000-0000-4000-a000-000000000003";
|
|
7
9
|
/** Cursor CLI model id for Auto + Composer subscription pool (not IDE default). */
|
|
8
10
|
export const CURSOR_DEFAULT_MODEL = "auto";
|
|
9
11
|
/** Cursor models that draw from the Auto + Composer pool on individual Pro plans. */
|
|
10
12
|
export const CURSOR_SUBSCRIPTION_MODEL_IDS = ["auto", "composer-2.5", "composer-2.5-fast"];
|
|
11
13
|
export const AgentHealthIssue = z.object({
|
|
12
|
-
code: z.enum([
|
|
14
|
+
code: z.enum([
|
|
15
|
+
"cli_missing",
|
|
16
|
+
"runtime_auth",
|
|
17
|
+
/**
|
|
18
|
+
* Cursor macOS keychain stuck (errSecDuplicateItem / exit 45) — sessions die mid-run
|
|
19
|
+
* even when status briefly looked logged-in (NOT-114 / NOT-103).
|
|
20
|
+
*/
|
|
21
|
+
"cursor_keychain",
|
|
22
|
+
"usage_capped",
|
|
23
|
+
"deck_offline",
|
|
24
|
+
"deck_unauthorized",
|
|
25
|
+
/** @deprecated NOT-149 — no longer emitted; workspace is not an Agent concept. */
|
|
26
|
+
"workspace_missing",
|
|
27
|
+
/** Agent has no Deck — Dealer workers are fail-closed without one (NOT-149). */
|
|
28
|
+
"deck_missing",
|
|
29
|
+
"mcp_not_registered",
|
|
30
|
+
/** GitHub CLI missing — issue workflows need `gh` to open/update draft PRs. */
|
|
31
|
+
"github_cli_missing",
|
|
32
|
+
/** `gh auth status` failed / token invalid — PR create will burn a developer round. */
|
|
33
|
+
"github_auth",
|
|
34
|
+
]),
|
|
13
35
|
message: z.string(),
|
|
14
36
|
});
|
|
15
37
|
export const AgentProfile = z.object({
|
|
16
38
|
id: z.string().uuid(),
|
|
17
39
|
name: z.string(),
|
|
18
40
|
runtime: Runtime,
|
|
41
|
+
/**
|
|
42
|
+
* Dead legacy storage (NOT-149). Retained so existing rows migrate safely; never shown
|
|
43
|
+
* in UI, never required by health/admission, and never copied into new profile snapshots.
|
|
44
|
+
*/
|
|
19
45
|
workspaceRoot: z.string().nullable(),
|
|
46
|
+
/** Required for any Agent used for execution — Dealer never starts without a Deck. */
|
|
20
47
|
deckId: z.string().uuid().nullable(),
|
|
21
48
|
deckName: z.string().nullable(),
|
|
49
|
+
/** Dead legacy storage (NOT-149) — playbooks are chosen dynamically inside the Deck. */
|
|
22
50
|
playbookId: z.string().nullable(),
|
|
23
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Legacy phase defaults, read-only since NOT-71: nothing writes these any more, but
|
|
53
|
+
* profile-snapshot.ts still falls back to them so profiles saved before `defaultModel` /
|
|
54
|
+
* `defaultBudgetJson` existed keep their configured model and caps.
|
|
55
|
+
*/
|
|
24
56
|
defaultPlanModel: z.string().nullable(),
|
|
25
|
-
/** CLI model id for execution; null = runtime default */
|
|
26
57
|
defaultExecuteModel: z.string().nullable(),
|
|
27
|
-
/** Serialized PhaseBudget; null = runtime default (no CLI caps) */
|
|
28
58
|
defaultPlanBudgetJson: z.string().nullable(),
|
|
29
|
-
/** Serialized PhaseBudget; null = runtime default (no CLI caps) */
|
|
30
59
|
defaultExecuteBudgetJson: z.string().nullable(),
|
|
60
|
+
/** Role-neutral CLI model id for issue-centric developer/reviewer sessions; null = runtime default. */
|
|
61
|
+
defaultModel: z.string().nullable(),
|
|
62
|
+
/**
|
|
63
|
+
* Default reasoning effort (NOT-81). Null = runtime default. Applied only for runtimes
|
|
64
|
+
* that expose a CLI-level effort control (Codex / Claude Code); Cursor ignores it.
|
|
65
|
+
*/
|
|
66
|
+
defaultEffort: ReasoningEffort.nullable(),
|
|
67
|
+
/** Serialized PhaseBudget for issue-centric sessions; null = runtime default. */
|
|
68
|
+
defaultBudgetJson: z.string().nullable(),
|
|
69
|
+
/** Free-text description of what this profile is for (shown in the picker, snapshotted). */
|
|
70
|
+
purpose: z.string().nullable(),
|
|
71
|
+
/** Dead legacy storage (NOT-149). */
|
|
72
|
+
playbookIdsJson: z.string().nullable(),
|
|
73
|
+
/** Dead legacy storage (NOT-149). */
|
|
74
|
+
externalMemoryRefsJson: z.string().nullable(),
|
|
75
|
+
/** Serialized PermissionPolicyOverride — may only tighten the role's capabilities. */
|
|
76
|
+
permissionPolicyJson: z.string().nullable(),
|
|
31
77
|
isBuiltin: z.boolean(),
|
|
32
78
|
createdAt: z.string(),
|
|
33
79
|
updatedAt: z.string(),
|
|
@@ -39,26 +85,46 @@ export const AgentWithHealth = AgentProfile.extend({
|
|
|
39
85
|
export const CreateAgentInput = z.object({
|
|
40
86
|
name: z.string().min(1),
|
|
41
87
|
runtime: Runtime,
|
|
42
|
-
|
|
43
|
-
deckId: z.string().uuid()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
88
|
+
/** Exactly one Agent Deck — required; workers never start in no-Deck/degraded mode. */
|
|
89
|
+
deckId: z.string().uuid(),
|
|
90
|
+
defaultModel: z.string().nullable().optional(),
|
|
91
|
+
defaultEffort: ReasoningEffort.nullable().optional(),
|
|
92
|
+
defaultBudget: PhaseBudget.nullable().optional(),
|
|
93
|
+
purpose: z.string().nullable().optional(),
|
|
94
|
+
permissionPolicy: PermissionPolicyOverride.nullable().optional(),
|
|
49
95
|
});
|
|
50
96
|
export const UpdateAgentInput = z.object({
|
|
51
97
|
name: z.string().min(1).optional(),
|
|
52
98
|
runtime: Runtime.optional(),
|
|
53
|
-
|
|
99
|
+
/** Null clears the deck (unhealthy until set again); omit leaves unchanged. */
|
|
54
100
|
deckId: z.string().uuid().nullable().optional(),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
101
|
+
defaultModel: z.string().nullable().optional(),
|
|
102
|
+
defaultEffort: ReasoningEffort.nullable().optional(),
|
|
103
|
+
defaultBudget: PhaseBudget.nullable().optional(),
|
|
104
|
+
purpose: z.string().nullable().optional(),
|
|
105
|
+
permissionPolicy: PermissionPolicyOverride.nullable().optional(),
|
|
60
106
|
});
|
|
61
107
|
export const AgentsSnapshot = z.object({
|
|
62
108
|
agents: z.array(AgentWithHealth),
|
|
63
109
|
issueCount: z.number(),
|
|
64
110
|
});
|
|
111
|
+
// The effective execution defaults for a profile.
|
|
112
|
+
//
|
|
113
|
+
// NOT-71 collapsed the plan/execute pair into one role-neutral column, but profiles
|
|
114
|
+
// persisted before that still carry values only in the legacy columns. This is the
|
|
115
|
+
// narrow read-compatibility path for those rows: it is the single definition of
|
|
116
|
+
// "what this profile actually runs with", shared by the snapshot builder and the
|
|
117
|
+
// agent edit form so the UI can never show blank while a hidden legacy value is in
|
|
118
|
+
// force. updateAgent() normalizes the legacy columns away on the next write, so a
|
|
119
|
+
// profile only takes this fallback until it is next edited.
|
|
120
|
+
/** Role-neutral model, falling back through the legacy phase columns (execute → plan). */
|
|
121
|
+
export function resolveProfileModel(agent) {
|
|
122
|
+
return agent.defaultModel ?? agent.defaultExecuteModel ?? agent.defaultPlanModel ?? null;
|
|
123
|
+
}
|
|
124
|
+
/** Role-neutral budget JSON, same fallback order as the model. */
|
|
125
|
+
export function resolveProfileBudgetJson(agent) {
|
|
126
|
+
const budget = parsePhaseBudget(agent.defaultBudgetJson) ??
|
|
127
|
+
parsePhaseBudget(agent.defaultExecuteBudgetJson) ??
|
|
128
|
+
parsePhaseBudget(agent.defaultPlanBudgetJson);
|
|
129
|
+
return serializePhaseBudget(budget);
|
|
130
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentHealthIssue } from "./agents.js";
|
|
2
|
+
/** Shared remediation for Cursor macOS keychain stuck-auth (NOT-114 / NOT-103). */
|
|
3
|
+
export declare const CURSOR_KEYCHAIN_REMEDIATION: string;
|
|
4
|
+
export declare const CURSOR_KEYCHAIN_HEALTH_ISSUE: AgentHealthIssue;
|
|
5
|
+
/** True when Cursor status/login/stderr indicates a stuck macOS keychain item. */
|
|
6
|
+
export declare function isCursorKeychainStuckOutput(output: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Classify Cursor auth health from status/login/stderr text.
|
|
9
|
+
* Keychain stuck wins over generic "not logged in" (same remediations differ).
|
|
10
|
+
* Also usable by session failure classifiers (NOT-113) for the same remediation string.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cursorAuthIssueFromOutput(output: string): AgentHealthIssue | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Shared remediation for Cursor macOS keychain stuck-auth (NOT-114 / NOT-103). */
|
|
2
|
+
export const CURSOR_KEYCHAIN_REMEDIATION = "Cursor macOS keychain auth is stuck (errSecDuplicateItem). Delete the item and sign in again: " +
|
|
3
|
+
"`security delete-generic-password -s cursor-access-token -a cursor-user` then `agent login` " +
|
|
4
|
+
"(or `cursor-agent login`). See docs/TROUBLESHOOTING.md#cursor-macos-keychain-auth.";
|
|
5
|
+
export const CURSOR_KEYCHAIN_HEALTH_ISSUE = {
|
|
6
|
+
code: "cursor_keychain",
|
|
7
|
+
message: CURSOR_KEYCHAIN_REMEDIATION,
|
|
8
|
+
};
|
|
9
|
+
const KEYCHAIN_STUCK_PATTERNS = [
|
|
10
|
+
/errsecduplicateitem/i,
|
|
11
|
+
/security exit code 45/i,
|
|
12
|
+
/keychain item is stuck/i,
|
|
13
|
+
/couldn't save your login to the macOS keychain/i,
|
|
14
|
+
/could not save your login to the macOS keychain/i,
|
|
15
|
+
];
|
|
16
|
+
/** True when Cursor status/login/stderr indicates a stuck macOS keychain item. */
|
|
17
|
+
export function isCursorKeychainStuckOutput(output) {
|
|
18
|
+
return KEYCHAIN_STUCK_PATTERNS.some((re) => re.test(output));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Classify Cursor auth health from status/login/stderr text.
|
|
22
|
+
* Keychain stuck wins over generic "not logged in" (same remediations differ).
|
|
23
|
+
* Also usable by session failure classifiers (NOT-113) for the same remediation string.
|
|
24
|
+
*/
|
|
25
|
+
export function cursorAuthIssueFromOutput(output) {
|
|
26
|
+
if (isCursorKeychainStuckOutput(output)) {
|
|
27
|
+
return { ...CURSOR_KEYCHAIN_HEALTH_ISSUE };
|
|
28
|
+
}
|
|
29
|
+
const out = output.toLowerCase();
|
|
30
|
+
if (out.includes("not logged in") ||
|
|
31
|
+
out.includes("login required") ||
|
|
32
|
+
out.includes("not authenticated")) {
|
|
33
|
+
return { code: "runtime_auth", message: "Run cursor-agent login" };
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { CURSOR_KEYCHAIN_HEALTH_ISSUE, cursorAuthIssueFromOutput, isCursorKeychainStuckOutput, } from "./cursor-auth-health.js";
|
|
4
|
+
const STUCK_STDERR = `Cursor couldn't save your login to the macOS keychain (errSecDuplicateItem, security exit code 45).
|
|
5
|
+
The keychain item is stuck. Delete it and sign in again:
|
|
6
|
+
security delete-generic-password -s cursor-access-token -a cursor-user
|
|
7
|
+
agent login
|
|
8
|
+
`;
|
|
9
|
+
test("isCursorKeychainStuckOutput detects errSecDuplicateItem", () => {
|
|
10
|
+
assert.equal(isCursorKeychainStuckOutput(STUCK_STDERR), true);
|
|
11
|
+
});
|
|
12
|
+
test("isCursorKeychainStuckOutput detects security exit code 45", () => {
|
|
13
|
+
assert.equal(isCursorKeychainStuckOutput("security exit code 45 while saving token"), true);
|
|
14
|
+
});
|
|
15
|
+
test("isCursorKeychainStuckOutput detects keychain item is stuck prose", () => {
|
|
16
|
+
assert.equal(isCursorKeychainStuckOutput("The keychain item is stuck."), true);
|
|
17
|
+
});
|
|
18
|
+
test("isCursorKeychainStuckOutput ignores healthy status", () => {
|
|
19
|
+
assert.equal(isCursorKeychainStuckOutput("Logged in as user@example.com\n"), false);
|
|
20
|
+
assert.equal(isCursorKeychainStuckOutput("not logged in"), false);
|
|
21
|
+
});
|
|
22
|
+
test("cursorAuthIssueFromOutput maps stuck stderr to cursor_keychain issue code", () => {
|
|
23
|
+
const issue = cursorAuthIssueFromOutput(STUCK_STDERR);
|
|
24
|
+
assert.ok(issue);
|
|
25
|
+
assert.equal(issue?.code, "cursor_keychain");
|
|
26
|
+
assert.equal(issue?.message, CURSOR_KEYCHAIN_HEALTH_ISSUE.message);
|
|
27
|
+
assert.match(issue.message, /security delete-generic-password/);
|
|
28
|
+
assert.match(issue.message, /cursor-access-token/);
|
|
29
|
+
assert.match(issue.message, /agent login|cursor-agent login/);
|
|
30
|
+
});
|
|
31
|
+
test("cursorAuthIssueFromOutput maps not-logged-in to runtime_auth", () => {
|
|
32
|
+
const issue = cursorAuthIssueFromOutput("Error: not logged in — run agent login");
|
|
33
|
+
assert.deepEqual(issue, {
|
|
34
|
+
code: "runtime_auth",
|
|
35
|
+
message: "Run cursor-agent login",
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
test("cursorAuthIssueFromOutput returns null for clean output", () => {
|
|
39
|
+
assert.equal(cursorAuthIssueFromOutput("✓ Logged in\n"), null);
|
|
40
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const FindingSeverity: z.ZodEnum<["blocking", "non_blocking"]>;
|
|
3
|
+
export type FindingSeverity = z.infer<typeof FindingSeverity>;
|
|
4
|
+
export declare const FindingStatus: z.ZodEnum<["open", "resolved", "recurring", "superseded"]>;
|
|
5
|
+
export type FindingStatus = z.infer<typeof FindingStatus>;
|
|
6
|
+
export declare const Finding: z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
issueId: z.ZodString;
|
|
9
|
+
fingerprint: z.ZodString;
|
|
10
|
+
severity: z.ZodEnum<["blocking", "non_blocking"]>;
|
|
11
|
+
title: z.ZodString;
|
|
12
|
+
rationale: z.ZodString;
|
|
13
|
+
evidenceRef: z.ZodNullable<z.ZodString>;
|
|
14
|
+
file: z.ZodNullable<z.ZodString>;
|
|
15
|
+
line: z.ZodNullable<z.ZodNumber>;
|
|
16
|
+
status: z.ZodEnum<["open", "resolved", "recurring", "superseded"]>;
|
|
17
|
+
firstRound: z.ZodNumber;
|
|
18
|
+
lastRound: z.ZodNumber;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
status: "open" | "resolved" | "recurring" | "superseded";
|
|
21
|
+
id: string;
|
|
22
|
+
issueId: string;
|
|
23
|
+
fingerprint: string;
|
|
24
|
+
severity: "blocking" | "non_blocking";
|
|
25
|
+
title: string;
|
|
26
|
+
rationale: string;
|
|
27
|
+
evidenceRef: string | null;
|
|
28
|
+
file: string | null;
|
|
29
|
+
line: number | null;
|
|
30
|
+
firstRound: number;
|
|
31
|
+
lastRound: number;
|
|
32
|
+
}, {
|
|
33
|
+
status: "open" | "resolved" | "recurring" | "superseded";
|
|
34
|
+
id: string;
|
|
35
|
+
issueId: string;
|
|
36
|
+
fingerprint: string;
|
|
37
|
+
severity: "blocking" | "non_blocking";
|
|
38
|
+
title: string;
|
|
39
|
+
rationale: string;
|
|
40
|
+
evidenceRef: string | null;
|
|
41
|
+
file: string | null;
|
|
42
|
+
line: number | null;
|
|
43
|
+
firstRound: number;
|
|
44
|
+
lastRound: number;
|
|
45
|
+
}>;
|
|
46
|
+
export type Finding = z.infer<typeof Finding>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const FindingSeverity = z.enum(["blocking", "non_blocking"]);
|
|
3
|
+
export const FindingStatus = z.enum(["open", "resolved", "recurring", "superseded"]);
|
|
4
|
+
export const Finding = z.object({
|
|
5
|
+
id: z.string().uuid(),
|
|
6
|
+
issueId: z.string().uuid(),
|
|
7
|
+
fingerprint: z.string(),
|
|
8
|
+
severity: FindingSeverity,
|
|
9
|
+
title: z.string(),
|
|
10
|
+
rationale: z.string(),
|
|
11
|
+
evidenceRef: z.string().nullable(),
|
|
12
|
+
file: z.string().nullable(),
|
|
13
|
+
line: z.number().int().nullable(),
|
|
14
|
+
status: FindingStatus,
|
|
15
|
+
firstRound: z.number().int().min(1),
|
|
16
|
+
lastRound: z.number().int().min(1),
|
|
17
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { Finding } from "./findings.js";
|
|
4
|
+
test("Finding schema parses an open finding", () => {
|
|
5
|
+
const finding = {
|
|
6
|
+
id: "88888888-8888-8888-8888-888888888888",
|
|
7
|
+
issueId: "11111111-1111-1111-1111-111111111111",
|
|
8
|
+
fingerprint: "missing-null-check-auth-ts-42",
|
|
9
|
+
severity: "blocking",
|
|
10
|
+
title: "Missing null check",
|
|
11
|
+
rationale: "user can be undefined here",
|
|
12
|
+
evidenceRef: "https://github.com/org/repo/pull/1#discussion_r1",
|
|
13
|
+
file: "src/auth.ts",
|
|
14
|
+
line: 42,
|
|
15
|
+
status: "open",
|
|
16
|
+
firstRound: 1,
|
|
17
|
+
lastRound: 1,
|
|
18
|
+
};
|
|
19
|
+
assert.deepStrictEqual(Finding.parse(finding), finding);
|
|
20
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical portable GitHub repository identity stored on issues (NOT-149).
|
|
4
|
+
* Form: `github.com/<owner>/<repo>` (no scheme, no `.git`, no trailing slash).
|
|
5
|
+
*/
|
|
6
|
+
export declare const GitHubRepoIdentity: z.ZodString;
|
|
7
|
+
export type GitHubRepoIdentity = z.infer<typeof GitHubRepoIdentity>;
|
|
8
|
+
export interface ParsedGitHubRepo {
|
|
9
|
+
owner: string;
|
|
10
|
+
repo: string;
|
|
11
|
+
/** Canonical identity: `github.com/owner/repo`. */
|
|
12
|
+
identity: GitHubRepoIdentity;
|
|
13
|
+
/** HTTPS clone URL without credentials. */
|
|
14
|
+
cloneUrl: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* True when the value looks like a local filesystem path (legacy issue.repo), not a
|
|
18
|
+
* portable GitHub identity or URL. Used for explicit compatibility routing — never
|
|
19
|
+
* silently guessed into a remote.
|
|
20
|
+
*/
|
|
21
|
+
export declare function looksLikeLocalRepoPath(value: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Normalize a GitHub repository URL or `owner/repo` shorthand into a portable identity.
|
|
24
|
+
* Rejects local filesystem paths — those need an explicit migration path, not guessing.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseGitHubRepoInput(raw: string): ParsedGitHubRepo;
|
|
27
|
+
/** Zod transform for Create/UpdateIssueInput.repo — accepts URL or owner/repo. */
|
|
28
|
+
export declare const GitHubRepoInput: z.ZodEffects<z.ZodString, string, string>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical portable GitHub repository identity stored on issues (NOT-149).
|
|
4
|
+
* Form: `github.com/<owner>/<repo>` (no scheme, no `.git`, no trailing slash).
|
|
5
|
+
*/
|
|
6
|
+
export const GitHubRepoIdentity = z
|
|
7
|
+
.string()
|
|
8
|
+
.regex(/^github\.com\/[^/]+\/[^/]+$/, "Expected github.com/<owner>/<repo>");
|
|
9
|
+
const OWNER_REPO = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?$/;
|
|
10
|
+
/**
|
|
11
|
+
* True when the value looks like a local filesystem path (legacy issue.repo), not a
|
|
12
|
+
* portable GitHub identity or URL. Used for explicit compatibility routing — never
|
|
13
|
+
* silently guessed into a remote.
|
|
14
|
+
*/
|
|
15
|
+
export function looksLikeLocalRepoPath(value) {
|
|
16
|
+
const trimmed = value.trim();
|
|
17
|
+
if (!trimmed)
|
|
18
|
+
return false;
|
|
19
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("~") || trimmed.startsWith("."))
|
|
20
|
+
return true;
|
|
21
|
+
// Windows drive / UNC
|
|
22
|
+
if (/^[A-Za-z]:[\\/]/.test(trimmed) || trimmed.startsWith("\\\\"))
|
|
23
|
+
return true;
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Normalize a GitHub repository URL or `owner/repo` shorthand into a portable identity.
|
|
28
|
+
* Rejects local filesystem paths — those need an explicit migration path, not guessing.
|
|
29
|
+
*/
|
|
30
|
+
export function parseGitHubRepoInput(raw) {
|
|
31
|
+
const trimmed = raw.trim();
|
|
32
|
+
if (!trimmed) {
|
|
33
|
+
throw new Error("Repository is required");
|
|
34
|
+
}
|
|
35
|
+
if (looksLikeLocalRepoPath(trimmed)) {
|
|
36
|
+
throw new Error("Local filesystem paths are no longer accepted. Pass a GitHub URL or owner/repo (e.g. https://github.com/acme/app or acme/app).");
|
|
37
|
+
}
|
|
38
|
+
let owner;
|
|
39
|
+
let repo;
|
|
40
|
+
// owner/repo shorthand
|
|
41
|
+
const short = OWNER_REPO.exec(trimmed);
|
|
42
|
+
if (short && !trimmed.includes("://") && !trimmed.toLowerCase().includes("github.com")) {
|
|
43
|
+
owner = short[1];
|
|
44
|
+
repo = short[2];
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Strip credentials and normalize to a URL we can parse
|
|
48
|
+
let urlText = trimmed;
|
|
49
|
+
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(urlText)) {
|
|
50
|
+
// github.com/owner/repo or git@github.com:owner/repo.git
|
|
51
|
+
if (urlText.startsWith("git@")) {
|
|
52
|
+
urlText = urlText.replace(/^git@([^:]+):/, "https://$1/");
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
urlText = `https://${urlText}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
let url;
|
|
59
|
+
try {
|
|
60
|
+
url = new URL(urlText);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new Error(`Unrecognized GitHub repository reference: ${raw}`);
|
|
64
|
+
}
|
|
65
|
+
if (!/^([^.]+\.)?github\.com$/i.test(url.hostname)) {
|
|
66
|
+
throw new Error(`Only github.com repositories are supported (got host ${url.hostname})`);
|
|
67
|
+
}
|
|
68
|
+
const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
|
|
69
|
+
if (parts.length < 2 || !parts[0] || !parts[1]) {
|
|
70
|
+
throw new Error(`Unrecognized GitHub repository reference: ${raw}`);
|
|
71
|
+
}
|
|
72
|
+
owner = parts[0];
|
|
73
|
+
repo = parts[1].replace(/\.git$/i, "");
|
|
74
|
+
}
|
|
75
|
+
if (!owner || !repo || owner.includes("..") || repo.includes("..")) {
|
|
76
|
+
throw new Error(`Unrecognized GitHub repository reference: ${raw}`);
|
|
77
|
+
}
|
|
78
|
+
const identity = GitHubRepoIdentity.parse(`github.com/${owner}/${repo}`);
|
|
79
|
+
return {
|
|
80
|
+
owner,
|
|
81
|
+
repo,
|
|
82
|
+
identity,
|
|
83
|
+
cloneUrl: `https://github.com/${owner}/${repo}.git`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Zod transform for Create/UpdateIssueInput.repo — accepts URL or owner/repo. */
|
|
87
|
+
export const GitHubRepoInput = z
|
|
88
|
+
.string()
|
|
89
|
+
.min(1)
|
|
90
|
+
.transform((value, ctx) => {
|
|
91
|
+
try {
|
|
92
|
+
return parseGitHubRepoInput(value).identity;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: err.message });
|
|
96
|
+
return z.NEVER;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { GitHubRepoInput, looksLikeLocalRepoPath, parseGitHubRepoInput, } from "./github-repo.js";
|
|
4
|
+
test("parseGitHubRepoInput normalizes HTTPS URL, SSH, and owner/repo", () => {
|
|
5
|
+
assert.deepEqual(parseGitHubRepoInput("https://github.com/acme/app"), {
|
|
6
|
+
owner: "acme",
|
|
7
|
+
repo: "app",
|
|
8
|
+
identity: "github.com/acme/app",
|
|
9
|
+
cloneUrl: "https://github.com/acme/app.git",
|
|
10
|
+
});
|
|
11
|
+
assert.equal(parseGitHubRepoInput("https://github.com/acme/app.git").identity, "github.com/acme/app");
|
|
12
|
+
assert.equal(parseGitHubRepoInput("git@github.com:acme/app.git").identity, "github.com/acme/app");
|
|
13
|
+
assert.equal(parseGitHubRepoInput("github.com/acme/app").identity, "github.com/acme/app");
|
|
14
|
+
assert.equal(parseGitHubRepoInput("acme/app").identity, "github.com/acme/app");
|
|
15
|
+
assert.equal(parseGitHubRepoInput(" acme/app ").identity, "github.com/acme/app");
|
|
16
|
+
});
|
|
17
|
+
test("parseGitHubRepoInput rejects local paths and non-GitHub hosts", () => {
|
|
18
|
+
assert.throws(() => parseGitHubRepoInput("/Users/me/projects/app"), /Local filesystem/);
|
|
19
|
+
assert.throws(() => parseGitHubRepoInput("~/projects/app"), /Local filesystem/);
|
|
20
|
+
assert.throws(() => parseGitHubRepoInput("./relative"), /Local filesystem/);
|
|
21
|
+
assert.throws(() => parseGitHubRepoInput("https://gitlab.com/acme/app"), /Only github.com/);
|
|
22
|
+
assert.throws(() => parseGitHubRepoInput(""), /required/);
|
|
23
|
+
});
|
|
24
|
+
test("looksLikeLocalRepoPath distinguishes legacy checkouts from portable refs", () => {
|
|
25
|
+
assert.equal(looksLikeLocalRepoPath("/tmp/repo"), true);
|
|
26
|
+
assert.equal(looksLikeLocalRepoPath("github.com/acme/app"), false);
|
|
27
|
+
assert.equal(looksLikeLocalRepoPath("acme/app"), false);
|
|
28
|
+
});
|
|
29
|
+
test("GitHubRepoInput zod transform stores the canonical identity", () => {
|
|
30
|
+
assert.equal(GitHubRepoInput.parse("acme/app"), "github.com/acme/app");
|
|
31
|
+
assert.throws(() => GitHubRepoInput.parse("/local/path"));
|
|
32
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const HumanActionType: z.ZodEnum<["product_scope_decision", "policy_escalation", "attempts_exhausted", "final_review", "deck_interaction_required", "reflection_interaction_required", "outbound_delivery_interaction_required"]>;
|
|
3
|
+
export type HumanActionType = z.infer<typeof HumanActionType>;
|
|
4
|
+
export declare const HumanActionStatus: z.ZodEnum<["open", "resolved"]>;
|
|
5
|
+
export type HumanActionStatus = z.infer<typeof HumanActionStatus>;
|
|
6
|
+
export declare const HumanAction: z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
/** Null for a Run-scoped action (`runId` set instead) — outbound-draft delivery parking
|
|
9
|
+
* (NOT-95) has no Issue. Exactly one of issueId/runId is set. */
|
|
10
|
+
issueId: z.ZodNullable<z.ZodString>;
|
|
11
|
+
/** Null for an Issue-scoped action. See `issueId`. */
|
|
12
|
+
runId: z.ZodNullable<z.ZodString>;
|
|
13
|
+
/** Nullable for pre-start product_scope_decision and imported legacy actions. */
|
|
14
|
+
workflowInstanceId: z.ZodNullable<z.ZodString>;
|
|
15
|
+
actionType: z.ZodEnum<["product_scope_decision", "policy_escalation", "attempts_exhausted", "final_review", "deck_interaction_required", "reflection_interaction_required", "outbound_delivery_interaction_required"]>;
|
|
16
|
+
reason: z.ZodString;
|
|
17
|
+
question: z.ZodString;
|
|
18
|
+
evidenceJson: z.ZodNullable<z.ZodString>;
|
|
19
|
+
responseOptionsJson: z.ZodNullable<z.ZodString>;
|
|
20
|
+
continuationPreviewJson: z.ZodNullable<z.ZodString>;
|
|
21
|
+
/** Agent Deck's own correlation id for the INTERACTION_REQUIRED response that raised
|
|
22
|
+
* this action (deck_interaction_required / reflection_interaction_required only) —
|
|
23
|
+
* null for every other action type and for one Deck raised without a correlation id
|
|
24
|
+
* (NOT-93). */
|
|
25
|
+
requestId: z.ZodNullable<z.ZodString>;
|
|
26
|
+
status: z.ZodEnum<["open", "resolved"]>;
|
|
27
|
+
resolutionJson: z.ZodNullable<z.ZodString>;
|
|
28
|
+
resolvedBy: z.ZodNullable<z.ZodString>;
|
|
29
|
+
requestedAt: z.ZodString;
|
|
30
|
+
resolvedAt: z.ZodNullable<z.ZodString>;
|
|
31
|
+
}, "strip", z.ZodTypeAny, {
|
|
32
|
+
status: "open" | "resolved";
|
|
33
|
+
id: string;
|
|
34
|
+
issueId: string | null;
|
|
35
|
+
runId: string | null;
|
|
36
|
+
workflowInstanceId: string | null;
|
|
37
|
+
actionType: "product_scope_decision" | "policy_escalation" | "attempts_exhausted" | "final_review" | "deck_interaction_required" | "reflection_interaction_required" | "outbound_delivery_interaction_required";
|
|
38
|
+
reason: string;
|
|
39
|
+
question: string;
|
|
40
|
+
evidenceJson: string | null;
|
|
41
|
+
responseOptionsJson: string | null;
|
|
42
|
+
continuationPreviewJson: string | null;
|
|
43
|
+
requestId: string | null;
|
|
44
|
+
resolutionJson: string | null;
|
|
45
|
+
resolvedBy: string | null;
|
|
46
|
+
requestedAt: string;
|
|
47
|
+
resolvedAt: string | null;
|
|
48
|
+
}, {
|
|
49
|
+
status: "open" | "resolved";
|
|
50
|
+
id: string;
|
|
51
|
+
issueId: string | null;
|
|
52
|
+
runId: string | null;
|
|
53
|
+
workflowInstanceId: string | null;
|
|
54
|
+
actionType: "product_scope_decision" | "policy_escalation" | "attempts_exhausted" | "final_review" | "deck_interaction_required" | "reflection_interaction_required" | "outbound_delivery_interaction_required";
|
|
55
|
+
reason: string;
|
|
56
|
+
question: string;
|
|
57
|
+
evidenceJson: string | null;
|
|
58
|
+
responseOptionsJson: string | null;
|
|
59
|
+
continuationPreviewJson: string | null;
|
|
60
|
+
requestId: string | null;
|
|
61
|
+
resolutionJson: string | null;
|
|
62
|
+
resolvedBy: string | null;
|
|
63
|
+
requestedAt: string;
|
|
64
|
+
resolvedAt: string | null;
|
|
65
|
+
}>;
|
|
66
|
+
export type HumanAction = z.infer<typeof HumanAction>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const HumanActionType = z.enum([
|
|
3
|
+
"product_scope_decision",
|
|
4
|
+
"policy_escalation",
|
|
5
|
+
"attempts_exhausted",
|
|
6
|
+
"final_review",
|
|
7
|
+
/** Agent Deck returned a typed control-plane requirement (INTERACTION_REQUIRED) for a
|
|
8
|
+
* mint/tool call under execution authority (NOT-87) — the worker was released rather
|
|
9
|
+
* than left holding an in-flight call. */
|
|
10
|
+
"deck_interaction_required",
|
|
11
|
+
/** Agent Deck returned INTERACTION_REQUIRED while a completed issue's post-review
|
|
12
|
+
* reflection tried to read/propose against a playbook under execution authority
|
|
13
|
+
* (NOT-94) — parks that reflection attempt only. Deliberately distinct from
|
|
14
|
+
* `deck_interaction_required`: reflection runs after the issue is already `done`, and
|
|
15
|
+
* resolving this action never reopens the issue or enqueues developer/reviewer work,
|
|
16
|
+
* unlike `deck_interaction_required`'s "resume" choice. */
|
|
17
|
+
"reflection_interaction_required",
|
|
18
|
+
/** Agent Deck returned INTERACTION_REQUIRED while minting or calling authority for an
|
|
19
|
+
* approved outbound draft's delivery (NOT-95) — parks that delivery attempt only, on the
|
|
20
|
+
* legacy Run model rather than an Issue (outbound drafts predate the issue/coordinator
|
|
21
|
+
* kernel and never go through it). Resolved outside `resolveHumanActionOutcome` by
|
|
22
|
+
* `resolveOutboundDeliveryAction`, same reasoning as `reflection_interaction_required`. */
|
|
23
|
+
"outbound_delivery_interaction_required",
|
|
24
|
+
]);
|
|
25
|
+
export const HumanActionStatus = z.enum(["open", "resolved"]);
|
|
26
|
+
export const HumanAction = z.object({
|
|
27
|
+
id: z.string().uuid(),
|
|
28
|
+
/** Null for a Run-scoped action (`runId` set instead) — outbound-draft delivery parking
|
|
29
|
+
* (NOT-95) has no Issue. Exactly one of issueId/runId is set. */
|
|
30
|
+
issueId: z.string().uuid().nullable(),
|
|
31
|
+
/** Null for an Issue-scoped action. See `issueId`. */
|
|
32
|
+
runId: z.string().uuid().nullable(),
|
|
33
|
+
/** Nullable for pre-start product_scope_decision and imported legacy actions. */
|
|
34
|
+
workflowInstanceId: z.string().uuid().nullable(),
|
|
35
|
+
actionType: HumanActionType,
|
|
36
|
+
reason: z.string(),
|
|
37
|
+
question: z.string(),
|
|
38
|
+
evidenceJson: z.string().nullable(),
|
|
39
|
+
responseOptionsJson: z.string().nullable(),
|
|
40
|
+
continuationPreviewJson: z.string().nullable(),
|
|
41
|
+
/** Agent Deck's own correlation id for the INTERACTION_REQUIRED response that raised
|
|
42
|
+
* this action (deck_interaction_required / reflection_interaction_required only) —
|
|
43
|
+
* null for every other action type and for one Deck raised without a correlation id
|
|
44
|
+
* (NOT-93). */
|
|
45
|
+
requestId: z.string().nullable(),
|
|
46
|
+
status: HumanActionStatus,
|
|
47
|
+
resolutionJson: z.string().nullable(),
|
|
48
|
+
resolvedBy: z.string().nullable(),
|
|
49
|
+
requestedAt: z.string(),
|
|
50
|
+
resolvedAt: z.string().nullable(),
|
|
51
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|