@apexops/cli 0.10.0-next.3 → 0.10.0-next.5

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.
Files changed (33) hide show
  1. package/README.md +40 -0
  2. package/assets/client-projection-metadata/copilot-cli-agent-tools.json +12 -0
  3. package/assets/client-projections/github-copilot-cli/.github/agents/apex-architect.agent.md +9 -8
  4. package/assets/client-projections/github-copilot-cli/.github/agents/apex-planner.agent.md +11 -8
  5. package/assets/client-projections/github-copilot-cli/.github/agents/apex-requirements.agent.md +23 -12
  6. package/assets/client-projections/github-copilot-cli/.github/agents/apex.agent.md +4 -0
  7. package/assets/client-projections/github-copilot-cli/.github/mcp.json +7 -0
  8. package/assets/client-projections/github-copilot-cli/.github/skills/apex-requirements/SKILL.md +7 -4
  9. package/assets/client-projections/github-copilot-vscode/.github/agents/apex-architect.agent.md +9 -8
  10. package/assets/client-projections/github-copilot-vscode/.github/agents/apex-planner.agent.md +11 -8
  11. package/assets/client-projections/github-copilot-vscode/.github/agents/apex-requirements.agent.md +23 -12
  12. package/assets/client-projections/github-copilot-vscode/.github/agents/apex-reviewer.agent.md +9 -5
  13. package/assets/client-projections/github-copilot-vscode/.github/agents/apex.agent.md +4 -0
  14. package/assets/client-projections/github-copilot-vscode/.github/skills/apex-requirements/SKILL.md +7 -4
  15. package/assets/config/runtime-bundle.v1.json +7 -7
  16. package/assets/customizations/.github/agents/apex-architect.agent.md +9 -8
  17. package/assets/customizations/.github/agents/apex-planner.agent.md +11 -8
  18. package/assets/customizations/.github/agents/apex-requirements.agent.md +23 -12
  19. package/assets/customizations/.github/agents/apex-reviewer.agent.md +9 -5
  20. package/assets/customizations/.github/agents/apex.agent.md +4 -0
  21. package/assets/customizations/.github/mcp.json +7 -0
  22. package/assets/customizations/.github/skills/apex-requirements/SKILL.md +7 -4
  23. package/assets/customizations/manifest.json +1 -1
  24. package/assets/manifest.json +58 -58
  25. package/dist/cli.d.ts +1 -0
  26. package/dist/cli.js +42 -2
  27. package/dist/mcp.js +89 -16
  28. package/dist/service.d.ts +46 -1
  29. package/dist/service.js +466 -41
  30. package/dist/state-transfer.js +23 -6
  31. package/dist/version.d.ts +1 -1
  32. package/dist/version.js +1 -1
  33. package/package.json +5 -5
package/dist/mcp.js CHANGED
@@ -5,6 +5,14 @@ import { ApexService, SUPPORTED_ARTIFACT_KINDS } from "./service.js";
5
5
  import { APEX_VERSION } from "./version.js";
6
6
  const artifactKind = z.enum(SUPPORTED_ARTIFACT_KINDS);
7
7
  const taskOutput = z.object({ kind: artifactKind, value: z.unknown(), summary: z.string().optional() });
8
+ const reviewFinding = z
9
+ .object({
10
+ id: z.string().min(1),
11
+ severity: z.enum(["critical", "high", "medium", "low", "info"]),
12
+ title: z.string().min(1),
13
+ detail: z.string().min(1),
14
+ })
15
+ .strict();
8
16
  const uniqueStrings = z
9
17
  .array(z.string().min(1))
10
18
  .min(1)
@@ -65,6 +73,44 @@ const projectCreateInput = z
65
73
  const projectIdInput = z.object({ projectId: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/) }).strict();
66
74
  const projectUseInput = projectIdInput.extend({ runId: z.string().min(1).optional() });
67
75
  const projectDeleteInput = projectIdInput.extend({ confirm: z.literal(true) });
76
+ const planCompletionInput = z
77
+ .object({
78
+ taskId: z.string().min(1),
79
+ implementationIntent: z.unknown(),
80
+ iacBinding: z
81
+ .object({
82
+ schemaVersion: z.literal("1.0.0"),
83
+ projectId: z.string().min(1),
84
+ runId: z.string().min(1),
85
+ track: z.enum(["bicep", "terraform"]),
86
+ resourceBindings: z.record(z.string().min(1), z.unknown()),
87
+ })
88
+ .strict(),
89
+ environmentInputs: z.unknown(),
90
+ })
91
+ .strict();
92
+ const gateDecisionInput = z
93
+ .object({
94
+ gate: z.union([z.literal(1), z.literal(2), z.literal(3)]),
95
+ decision: z.enum(["approved", "rejected"]),
96
+ confirm: z.literal(true),
97
+ })
98
+ .strict();
99
+ const reviewDecisionInput = z
100
+ .object({
101
+ reviewHash: z.string().regex(/^[0-9a-f]{64}$/),
102
+ decisions: z
103
+ .array(z
104
+ .object({
105
+ findingId: z.string().min(1),
106
+ action: z.enum(["revise", "accept-risk"]),
107
+ rationale: z.string().min(1),
108
+ expiresAt: z.string().datetime().optional(),
109
+ })
110
+ .strict())
111
+ .min(1),
112
+ })
113
+ .strict();
68
114
  const normalizeOutputs = (outputs) => outputs.map(({ kind, value, summary }) => ({
69
115
  kind,
70
116
  value,
@@ -86,6 +132,14 @@ export function createMcpServer(service) {
86
132
  description: "Read context only for the exact task.taskId returned by nextTask with status=task.",
87
133
  inputSchema: { taskId: z.string() },
88
134
  }, async ({ taskId }) => result(await service.taskContext(taskId)));
135
+ server.registerTool("readTaskInput", {
136
+ description: "Read a bounded chunk of the accepted source artifact for an active review task.",
137
+ inputSchema: {
138
+ taskId: z.string(),
139
+ offset: z.number().int().nonnegative().optional(),
140
+ limit: z.number().int().min(1).max(6_000).optional(),
141
+ },
142
+ }, async ({ taskId, offset, limit }) => result(await service.readTaskInput(taskId, offset, limit)));
89
143
  server.registerTool("recordInput", { description: "Record answers for the exact pending kernel input request", inputSchema: inputSubmission }, async (input) => result(await service.recordInput(input)));
90
144
  server.registerTool("projectCreate", {
91
145
  description: "Create and select a new project with its initial environment run",
@@ -97,6 +151,17 @@ export function createMcpServer(service) {
97
151
  description: "Delete a project and all of its run-bound state after explicit confirmation",
98
152
  inputSchema: projectDeleteInput,
99
153
  }, async ({ projectId, confirm }) => result(await service.deleteProject(projectId, confirm)));
154
+ server.registerTool("gateDecide", {
155
+ description: "Record an explicitly confirmed human decision for Gate 1, 2, or 3 using the local OS username as actor. Gate 4 remains CLI-only.",
156
+ inputSchema: gateDecisionInput,
157
+ }, async ({ gate, decision }) => result(await service.decideInteractiveGate(gate, decision)));
158
+ server.registerTool("reviewDecide", {
159
+ description: "Resolve all current review findings atomically by requesting revision or accepting permitted time-bound risk.",
160
+ inputSchema: reviewDecisionInput,
161
+ }, async ({ reviewHash, decisions }) => result(await service.decideReview(reviewHash, decisions.map(({ expiresAt, ...decision }) => ({
162
+ ...decision,
163
+ ...(expiresAt === undefined ? {} : { expiresAt }),
164
+ })))));
100
165
  server.registerTool("stageArtifact", {
101
166
  inputSchema: {
102
167
  taskId: z.string(),
@@ -151,25 +216,33 @@ export function createMcpServer(service) {
151
216
  : { kind, value, ...(summary === undefined ? {} : { summary }) }
152
217
  : normalizeOutputs(outputs))));
153
218
  server.registerTool("completeTask", {
154
- description: "Complete a task atomically. Supply outputs[] for every task with multiple required output kinds.",
219
+ description: "Complete a task atomically with a nonempty outputs[] bundle.",
155
220
  inputSchema: {
156
221
  taskId: z.string(),
157
- kind: artifactKind.optional(),
158
- value: z.unknown().optional(),
159
- summary: z.string().optional(),
160
- outputs: z.array(taskOutput).optional(),
222
+ outputs: z.array(taskOutput).min(1),
161
223
  },
162
- }, async ({ taskId, kind, value, summary, outputs }) => {
163
- if (outputs !== undefined)
164
- return result(await service.completeTaskOutputs(taskId, normalizeOutputs(outputs)));
165
- if (kind === undefined)
166
- throw new Error("completeTask requires kind/value or outputs[]");
167
- const context = await service.taskContext(taskId);
168
- if (context.task.allowedOutputKinds.length > 1) {
169
- throw new Error("completeTask requires outputs[] when the task has multiple required output kinds");
170
- }
171
- return result(await service.completeTask(taskId, { kind, value, ...(summary === undefined ? {} : { summary }) }));
172
- });
224
+ }, async ({ taskId, outputs }) => result(await service.completeTaskOutputs(taskId, normalizeOutputs(outputs))));
225
+ server.registerTool("requirementsComplete", {
226
+ description: "Complete the active Requirements task atomically.",
227
+ inputSchema: { taskId: z.string(), requirements: z.unknown() },
228
+ }, async ({ taskId, requirements }) => result(await service.completeRequirements(taskId, requirements)));
229
+ server.registerTool("architectureComplete", {
230
+ description: "Complete the active Architecture task atomically with all required outputs.",
231
+ inputSchema: {
232
+ taskId: z.string(),
233
+ architecture: z.unknown(),
234
+ costEstimate: z.unknown(),
235
+ decisionManifest: z.unknown(),
236
+ },
237
+ }, async ({ taskId, architecture, costEstimate, decisionManifest }) => result(await service.completeArchitecture(taskId, architecture, costEstimate, decisionManifest)));
238
+ server.registerTool("reviewComplete", {
239
+ description: "Complete the active review task; APEX derives subject identity, hash, timestamp, and evidence binding.",
240
+ inputSchema: { taskId: z.string(), findings: z.array(reviewFinding) },
241
+ }, async ({ taskId, findings }) => result(await service.completeReview(taskId, findings)));
242
+ server.registerTool("planComplete", {
243
+ description: "Atomically complete a plan. Derives the canonical implementation intent hash for the binding; do not supply intentHash.",
244
+ inputSchema: planCompletionInput,
245
+ }, async ({ taskId, implementationIntent, iacBinding, environmentInputs }) => result(await service.completePlan(taskId, implementationIntent, iacBinding, environmentInputs)));
173
246
  server.registerTool("preview", { description: "Read the current operator-created deployment preview" }, async () => result(await service.currentPreview()));
174
247
  server.registerTool("reconcile", {}, async () => result(await service.reconcile()));
175
248
  server.registerTool("inventory", {}, async () => result(await service.inventory()));
package/dist/service.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type ApprovalEvidenceV1, type ArchitectureAvailabilityV1, type DeploymentPreviewV1, type InputRequestV1, type InputValueV1, type InputSubmissionV1, type ImprovementCategory, type ImprovementDecisionV1, type ImprovementObservationV1, type ImprovementPolicyV1, type ImprovementProposalV1, type ImprovementSource, type Operation, type ProjectId, type ResourceInventoryV1, type RunConfigV1, type RunId, type TaskEnvelopeV1 } from "@apexops/contracts";
1
+ import { type ApprovalEvidenceV1, type ArchitectureAvailabilityV1, type ArchitectureV1, type CostEstimateV1, type DeploymentPreviewV1, type EnvironmentInputsV1, type IacBindingV1, type InputRequestV1, type InputValueV1, type InputSubmissionV1, type ImprovementCategory, type ImprovementDecisionV1, type ImprovementObservationV1, type ImprovementPolicyV1, type ImprovementProposalV1, type ImprovementSource, type ImplementationIntentV1, type Operation, type ProjectId, type ResourceInventoryV1, type ReviewFindingsV1, type RequirementsV1, type RunConfigV1, type RunId, type WorkloadDecisionManifestV1, type TaskEnvelopeV1 } from "@apexops/contracts";
2
2
  import { type CapabilityPackInstallOptions, type IacProvider, type ProcessRunnerLike } from "@apexops/capabilities";
3
3
  import { type JsonValue } from "@apexops/kernel";
4
4
  import { type BundledClientProjection } from "./assets.js";
@@ -52,6 +52,12 @@ export interface ReviewResolution {
52
52
  expiresAt?: string;
53
53
  dependencyHash: string;
54
54
  }
55
+ export interface ReviewDecision {
56
+ findingId: string;
57
+ action: "revise" | "accept-risk";
58
+ rationale: string;
59
+ expiresAt?: string;
60
+ }
55
61
  export interface ServiceOptions {
56
62
  clock?: () => Date;
57
63
  idSource?: () => string;
@@ -618,6 +624,9 @@ export declare class ApexService {
618
624
  nextTask(): Promise<{
619
625
  status: "needs_input";
620
626
  request: InputRequestV1;
627
+ } | {
628
+ status: "needs_review";
629
+ review: Awaited<ReturnType<ApexService["pendingReview"]>>;
621
630
  } | {
622
631
  status: "task";
623
632
  task: TaskEnvelopeV1;
@@ -638,6 +647,13 @@ export declare class ApexService {
638
647
  status: string;
639
648
  blockers: string[];
640
649
  }>;
650
+ readTaskInput(taskId: string, offset?: number, limit?: number): Promise<{
651
+ subjectHash: string;
652
+ content: string;
653
+ offset: number;
654
+ nextOffset?: number;
655
+ outputTemplate?: unknown;
656
+ }>;
641
657
  stageArtifact(taskId: string, output: TaskOutput): Promise<StagedArtifact>;
642
658
  stageFile(taskId: string, relativePath: string, content: string | Uint8Array, expectedSha?: string): Promise<StagedFile>;
643
659
  generateIac(taskId: string, options?: GenerateIacOptions): Promise<{
@@ -658,6 +674,23 @@ export declare class ApexService {
658
674
  outputHashes: Partial<Record<ArtifactKind, string>>;
659
675
  summary: string;
660
676
  }>;
677
+ completeRequirements(taskId: string, requirements: RequirementsV1): Promise<{
678
+ outputHashes: Partial<Record<ArtifactKind, string>>;
679
+ summary: string;
680
+ }>;
681
+ completeArchitecture(taskId: string, architecture: ArchitectureV1, costEstimate: CostEstimateV1, decisionManifest: WorkloadDecisionManifestV1): Promise<{
682
+ outputHashes: Partial<Record<ArtifactKind, string>>;
683
+ summary: string;
684
+ }>;
685
+ completeReview(taskId: string, findings: Array<Pick<ReviewFindingsV1["findings"][number], "id" | "severity" | "title" | "detail">>): Promise<{
686
+ outputHashes: Partial<Record<ArtifactKind, string>>;
687
+ summary: string;
688
+ }>;
689
+ completePlan(taskId: string, intent: ImplementationIntentV1, binding: Omit<IacBindingV1, "intentHash">, environmentInputs: EnvironmentInputsV1): Promise<{
690
+ outputHashes: Partial<Record<ArtifactKind, string>>;
691
+ summary: string;
692
+ }>;
693
+ private assertTaskType;
661
694
  private acceptTaskOutputs;
662
695
  private renderRequirementsDocument;
663
696
  private requirementsReviewDirectory;
@@ -676,8 +709,14 @@ export declare class ApexService {
676
709
  private requirementsDocumentTemplateContent;
677
710
  cancelTask(taskId: string): Promise<void>;
678
711
  resolveReview(resolution: ReviewResolution): Promise<void>;
712
+ decideReview(reviewHash: string, decisions: ReviewDecision[]): Promise<{
713
+ status: "revision_requested" | "resolved";
714
+ }>;
715
+ private pendingReview;
716
+ private reviseReview;
679
717
  private assertReviewResolution;
680
718
  decideGateNumber(gateNumber: number, decision: "approved" | "rejected", actor: string, options?: GateDecisionOptions): Promise<ApprovalEvidenceV1>;
719
+ decideInteractiveGate(gateNumber: 1 | 2 | 3, decision: "approved" | "rejected"): Promise<ApprovalEvidenceV1>;
681
720
  preview(options: PreviewOptions): Promise<DeploymentPreviewV1>;
682
721
  private operationsReviewDirectory;
683
722
  private materializeOperationsPreviewPackage;
@@ -749,8 +788,12 @@ export declare class ApexService {
749
788
  private architectureDecisionValues;
750
789
  private issueArchitectureDecision;
751
790
  private nextRequirementsIntakeRound;
791
+ private requirementsIntakeCatalog;
752
792
  private issueRequirementsInput;
753
793
  private requirementsIntakeQuestions;
794
+ private recommendedWorkloadPattern;
795
+ private workloadScalePrompt;
796
+ private recommendedServiceCandidates;
754
797
  private append;
755
798
  private journal;
756
799
  private runPath;
@@ -801,6 +844,8 @@ export declare class ApexService {
801
844
  private customizationSelection;
802
845
  private assertCleanInitialization;
803
846
  private createRuntimeLock;
847
+ private installRuntimeGeneration;
848
+ private runtimeRootForRun;
804
849
  private capabilityPacks;
805
850
  private runtimeLockChecks;
806
851
  private ensureLocalGitBoundary;