@amistio/cli 0.1.10 → 0.1.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/README.md +4 -0
- package/dist/index.js +295 -2
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ The package install only installs the `amistio` command. Repository cloning, pro
|
|
|
13
13
|
|
|
14
14
|
Runner lifecycle controls in the web app, such as update, restart, and remove, apply only to the runner paired by that user unless the active organization role is an admin role. The runner API binds command polling, command status, logs, activity, and tool sessions to the local runner credential that produced them.
|
|
15
15
|
|
|
16
|
+
Runner Update installs the official `@amistio/cli` package and then refreshes the runner runtime. Background runners attempt a replacement restart so the next heartbeat reports the new CLI version. Foreground `amistio run --watch` sessions stop after a successful install with restart guidance; start the command again to load the updated package.
|
|
17
|
+
|
|
16
18
|
Repository brain auto-sync is disabled until the repository link option is enabled in the app. After pairing, run `amistio sync watch` from the paired checkout to push recognized external brain Markdown/MDX files, including local ADRs, plans, prompts, workflows, memory, context, architecture, and feature docs, to the app for review. `amistio run --watch` also runs the same cycle between work polls when the option is enabled. The CLI skips templates, unsupported paths, oversized files, unchanged managed docs, and conflicts instead of silently overwriting web state.
|
|
17
19
|
|
|
18
20
|
After pairing, confirm that at least one local AI tool is available:
|
|
@@ -37,6 +39,8 @@ When `--tool copilot` uses the GitHub Copilot SDK, Amistio approves read-only pe
|
|
|
37
39
|
|
|
38
40
|
`amistio runner status` reports local background runner state, latest heartbeat, and bounded resource usage when available. Resource usage is latest-sample runner process memory/CPU plus safe aggregate system memory/load signals; it does not include source files, environment variables, command lines, process lists, credentials, or arbitrary local paths.
|
|
39
41
|
|
|
42
|
+
The runner advertises its supported work kinds in heartbeats. Current runners can claim read-only issue diagnosis jobs from the web Issues panel, generate root-cause analysis and a proposed fix, and submit that result without modifying source. Implementation is queued separately only after the user approves the analysis in the app.
|
|
43
|
+
|
|
40
44
|
Runner setup and local-tool execution use bounded failure controls. `amistio run --watch` retries Git worktree preflight failures by releasing the claim for another attempt, then fails the work item after `--max-preflight-attempts` attempts, defaulting to 3. Active local-tool runs renew the work lease, and `--tool-timeout-seconds` caps tool execution, defaulting to 1800 seconds.
|
|
41
45
|
|
|
42
46
|
For headless startup after login on supported user-level service managers:
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var itemTypeSchema = z.enum([
|
|
|
20
20
|
"repositoryLink",
|
|
21
21
|
"brainDocument",
|
|
22
22
|
"generatedDraft",
|
|
23
|
+
"issue",
|
|
23
24
|
"syncCursor",
|
|
24
25
|
"syncConflict",
|
|
25
26
|
"workItem",
|
|
@@ -66,11 +67,15 @@ var workStatusSchema = z.enum([
|
|
|
66
67
|
]);
|
|
67
68
|
var sourceSchema = z.enum(["web", "repo", "generated", "runner"]);
|
|
68
69
|
var executionModeSchema = z.enum(["localRunner", "cloudSandbox"]);
|
|
69
|
-
var workKindSchema = z.enum(["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview"]);
|
|
70
|
+
var workKindSchema = z.enum(["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis"]);
|
|
70
71
|
var generatedDraftStatusSchema = z.enum(["queued", "generating", "reviewing", "approved", "rejected", "changesRequested", "failed"]);
|
|
71
72
|
var assistantQuestionModeSchema = z.enum(["brainOnly", "sourceAware"]);
|
|
72
73
|
var impactRiskLevelSchema = z.enum(["low", "medium", "high", "critical"]);
|
|
73
74
|
var impactReportStatusSchema = z.enum(["queued", "running", "completed", "failed", "stale"]);
|
|
75
|
+
var issueCategorySchema = z.enum(["bug", "regression", "brokenWorkflow", "security", "operational", "other"]);
|
|
76
|
+
var issueSeveritySchema = z.enum(["low", "medium", "high", "critical"]);
|
|
77
|
+
var issueStatusSchema = z.enum(["queued", "diagnosing", "analysisReady", "approved", "changesRequested", "rejected", "implementationQueued", "implemented", "failed"]);
|
|
78
|
+
var issueApprovalStateSchema = z.enum(["proposed", "approved", "changesRequested", "rejected", "implemented", "blocked"]);
|
|
74
79
|
var activityEventTypeSchema = z.enum([
|
|
75
80
|
"commandSubmitted",
|
|
76
81
|
"generationQueued",
|
|
@@ -89,6 +94,11 @@ var activityEventTypeSchema = z.enum([
|
|
|
89
94
|
"impactPreviewCompleted",
|
|
90
95
|
"impactPreviewFailed",
|
|
91
96
|
"impactPreviewStale",
|
|
97
|
+
"issueDiagnosisQueued",
|
|
98
|
+
"issueDiagnosisCompleted",
|
|
99
|
+
"issueDiagnosisFailed",
|
|
100
|
+
"issueReview",
|
|
101
|
+
"issueImplementationQueued",
|
|
92
102
|
"handoffExported"
|
|
93
103
|
]);
|
|
94
104
|
var activityEventActorSchema = z.enum(["webUser", "runner", "cli", "system"]);
|
|
@@ -338,6 +348,7 @@ var workItemSchema = baseItemSchema.extend({
|
|
|
338
348
|
approvedByUserId: z.string().min(1).optional(),
|
|
339
349
|
sourceWish: z.string().min(1).optional(),
|
|
340
350
|
generatedDraftId: z.string().min(1).optional(),
|
|
351
|
+
issueId: z.string().min(1).optional(),
|
|
341
352
|
repositoryLinkId: z.string().min(1).optional(),
|
|
342
353
|
reviewThreadId: z.string().min(1).optional(),
|
|
343
354
|
reviewDocumentId: z.string().min(1).optional(),
|
|
@@ -386,6 +397,7 @@ var runnerHeartbeatItemSchema = baseItemSchema.extend({
|
|
|
386
397
|
mode: z.enum(["foreground", "background"]).optional(),
|
|
387
398
|
hostname: z.string().min(1).optional(),
|
|
388
399
|
runnerName: z.string().min(1).optional(),
|
|
400
|
+
supportedWorkKinds: z.array(workKindSchema).optional(),
|
|
389
401
|
supportsBranchIsolation: z.boolean().optional(),
|
|
390
402
|
supportsGitWorktreeIsolation: z.boolean().optional(),
|
|
391
403
|
currentWorkItemId: z.string().min(1).optional(),
|
|
@@ -720,6 +732,47 @@ var impactPreviewResultSchema = z.object({
|
|
|
720
732
|
analyzedRepoRevision: z.number().int().nonnegative().optional(),
|
|
721
733
|
repoFingerprint: z.string().min(1).optional()
|
|
722
734
|
});
|
|
735
|
+
var issueDiagnosisResultSchema = z.object({
|
|
736
|
+
summary: z.string().trim().min(1),
|
|
737
|
+
impact: z.string().trim().min(1),
|
|
738
|
+
evidence: z.array(z.string().trim().min(1)).default([]),
|
|
739
|
+
affectedSurfaces: z.array(z.string().trim().min(1)).default([]),
|
|
740
|
+
rootCauseAnalysis: z.string().trim().min(1),
|
|
741
|
+
falsifiableHypothesis: z.string().trim().min(1).optional(),
|
|
742
|
+
nextCheck: z.string().trim().min(1).optional(),
|
|
743
|
+
proposedFix: z.string().trim().min(1),
|
|
744
|
+
expectedBehavior: z.string().trim().min(1),
|
|
745
|
+
verificationPlan: z.array(z.string().trim().min(1)).min(1),
|
|
746
|
+
riskLevel: impactRiskLevelSchema.default("medium"),
|
|
747
|
+
likelyPaths: z.array(impactPathSchema).default([]),
|
|
748
|
+
approvalState: issueApprovalStateSchema.default("proposed")
|
|
749
|
+
});
|
|
750
|
+
var issueItemSchema = baseItemSchema.extend({
|
|
751
|
+
type: z.literal("issue"),
|
|
752
|
+
projectId: z.string().min(1),
|
|
753
|
+
issueId: z.string().min(1),
|
|
754
|
+
title: z.string().trim().min(1).max(200),
|
|
755
|
+
description: z.string().trim().min(1).max(12e3),
|
|
756
|
+
category: issueCategorySchema.default("bug"),
|
|
757
|
+
severity: issueSeveritySchema.default("medium"),
|
|
758
|
+
status: issueStatusSchema,
|
|
759
|
+
approvalState: issueApprovalStateSchema.default("proposed"),
|
|
760
|
+
submittedByUserId: z.string().min(1).optional(),
|
|
761
|
+
repositoryLinkId: z.string().min(1).optional(),
|
|
762
|
+
diagnosisWorkItemId: z.string().min(1).optional(),
|
|
763
|
+
implementationWorkItemId: z.string().min(1).optional(),
|
|
764
|
+
diagnosis: issueDiagnosisResultSchema.optional(),
|
|
765
|
+
reviewNotes: z.string().trim().min(1).optional(),
|
|
766
|
+
approvedByUserId: z.string().min(1).optional(),
|
|
767
|
+
approvedAt: isoDateTimeSchema.optional(),
|
|
768
|
+
requestedChangesByUserId: z.string().min(1).optional(),
|
|
769
|
+
requestedChangesAt: isoDateTimeSchema.optional(),
|
|
770
|
+
rejectedByUserId: z.string().min(1).optional(),
|
|
771
|
+
rejectedAt: isoDateTimeSchema.optional(),
|
|
772
|
+
diagnosedAt: isoDateTimeSchema.optional(),
|
|
773
|
+
runnerId: z.string().min(1).optional(),
|
|
774
|
+
lastDiagnosisError: z.string().optional()
|
|
775
|
+
});
|
|
723
776
|
var activityEventItemSchema = baseItemSchema.extend({
|
|
724
777
|
type: z.literal("activityEvent"),
|
|
725
778
|
projectId: z.string().min(1),
|
|
@@ -734,6 +787,7 @@ var activityEventItemSchema = baseItemSchema.extend({
|
|
|
734
787
|
occurredAt: isoDateTimeSchema,
|
|
735
788
|
relatedWorkItemId: z.string().min(1).optional(),
|
|
736
789
|
relatedDocumentId: z.string().min(1).optional(),
|
|
790
|
+
relatedIssueId: z.string().min(1).optional(),
|
|
737
791
|
generatedDraftId: z.string().min(1).optional(),
|
|
738
792
|
runnerId: z.string().min(1).optional(),
|
|
739
793
|
repositoryLinkId: z.string().min(1).optional(),
|
|
@@ -790,6 +844,7 @@ var projectItemUnionSchema = z.discriminatedUnion("type", [
|
|
|
790
844
|
repositoryLinkItemSchema,
|
|
791
845
|
brainDocumentItemSchema,
|
|
792
846
|
generatedDraftItemSchema,
|
|
847
|
+
issueItemSchema,
|
|
793
848
|
syncCursorItemSchema,
|
|
794
849
|
syncConflictItemSchema,
|
|
795
850
|
workItemSchema,
|
|
@@ -1527,6 +1582,13 @@ var ApiClient = class {
|
|
|
1527
1582
|
{ method: "GET" }
|
|
1528
1583
|
);
|
|
1529
1584
|
}
|
|
1585
|
+
async listIssues(projectId) {
|
|
1586
|
+
return this.request(
|
|
1587
|
+
`/projects/${projectId}/issues`,
|
|
1588
|
+
z3.object({ issues: z3.array(issueItemSchema) }),
|
|
1589
|
+
{ method: "GET" }
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1530
1592
|
async pushBrainDocuments(projectId, documents) {
|
|
1531
1593
|
return this.request(
|
|
1532
1594
|
`/projects/${projectId}/brain-documents`,
|
|
@@ -1684,6 +1746,16 @@ var ApiClient = class {
|
|
|
1684
1746
|
}
|
|
1685
1747
|
);
|
|
1686
1748
|
}
|
|
1749
|
+
async submitIssueDiagnosisResult(projectId, workItemId, result) {
|
|
1750
|
+
return this.request(
|
|
1751
|
+
`/projects/${projectId}/work-items/${workItemId}/issue-result`,
|
|
1752
|
+
z3.object({ issue: issueItemSchema, workItem: workItemSchema }),
|
|
1753
|
+
{
|
|
1754
|
+
method: "POST",
|
|
1755
|
+
body: JSON.stringify(result)
|
|
1756
|
+
}
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1687
1759
|
async request(urlPath, schema, init) {
|
|
1688
1760
|
const response = await fetch(resolveApiUrl(this.options.apiUrl, urlPath), {
|
|
1689
1761
|
...init,
|
|
@@ -3652,6 +3724,8 @@ var assistantAnswerStart = "AMISTIO_ASSISTANT_ANSWER_START";
|
|
|
3652
3724
|
var assistantAnswerEnd = "AMISTIO_ASSISTANT_ANSWER_END";
|
|
3653
3725
|
var impactPreviewStart = "AMISTIO_IMPACT_PREVIEW_START";
|
|
3654
3726
|
var impactPreviewEnd = "AMISTIO_IMPACT_PREVIEW_END";
|
|
3727
|
+
var issueDiagnosisStart = "AMISTIO_ISSUE_DIAGNOSIS_START";
|
|
3728
|
+
var issueDiagnosisEnd = "AMISTIO_ISSUE_DIAGNOSIS_END";
|
|
3655
3729
|
function createWorkExecutionPrompt(workItem, context) {
|
|
3656
3730
|
if (workItem.workKind === "brainGeneration") {
|
|
3657
3731
|
return createBrainGenerationPrompt(workItem);
|
|
@@ -3665,6 +3739,9 @@ function createWorkExecutionPrompt(workItem, context) {
|
|
|
3665
3739
|
if (workItem.workKind === "impactPreview") {
|
|
3666
3740
|
return createImpactPreviewPrompt(workItem, context?.impactPreview);
|
|
3667
3741
|
}
|
|
3742
|
+
if (workItem.workKind === "issueDiagnosis") {
|
|
3743
|
+
return createIssueDiagnosisPrompt(workItem, context?.issueDiagnosis);
|
|
3744
|
+
}
|
|
3668
3745
|
return [
|
|
3669
3746
|
"# Amistio Work Execution",
|
|
3670
3747
|
"",
|
|
@@ -3693,6 +3770,56 @@ function createWorkExecutionPrompt(workItem, context) {
|
|
|
3693
3770
|
"- Run relevant verification commands when feasible and summarize results."
|
|
3694
3771
|
].join("\n");
|
|
3695
3772
|
}
|
|
3773
|
+
function createIssueDiagnosisPrompt(workItem, context) {
|
|
3774
|
+
const issue = context?.issue;
|
|
3775
|
+
const approvedContext = (context?.documents ?? []).filter((document) => document.status === "approved" || document.syncState === "approved" || document.syncState === "synced").slice(0, 16).map((document) => [
|
|
3776
|
+
`### ${document.title}`,
|
|
3777
|
+
`documentId: ${document.documentId}`,
|
|
3778
|
+
`documentType: ${document.documentType}`,
|
|
3779
|
+
`repoPath: ${document.repoPath}`,
|
|
3780
|
+
`revision: ${document.revision}`,
|
|
3781
|
+
document.content.slice(0, 3e3)
|
|
3782
|
+
].join("\n")).join("\n\n");
|
|
3783
|
+
return [
|
|
3784
|
+
"# Amistio Issue Diagnosis",
|
|
3785
|
+
"",
|
|
3786
|
+
"You are running locally through the Amistio CLI inside the user's repository.",
|
|
3787
|
+
"Diagnose the submitted bug or operational issue and prepare the approval-gated fix analysis.",
|
|
3788
|
+
"This is a diagnosis-only task. Do not modify files, create branches, run implementation commands, or commit changes.",
|
|
3789
|
+
"",
|
|
3790
|
+
"## Submitted Issue",
|
|
3791
|
+
"",
|
|
3792
|
+
`Issue ID: ${workItem.issueId ?? issue?.issueId ?? "unknown"}`,
|
|
3793
|
+
`Title: ${issue?.title ?? workItem.title}`,
|
|
3794
|
+
`Category: ${issue?.category ?? "bug"}`,
|
|
3795
|
+
`Severity: ${issue?.severity ?? "medium"}`,
|
|
3796
|
+
"",
|
|
3797
|
+
issue?.description ?? workItem.sourceWish ?? workItem.title,
|
|
3798
|
+
"",
|
|
3799
|
+
"## Approved Project Brain Context",
|
|
3800
|
+
"",
|
|
3801
|
+
approvedContext || "No approved project-brain records were loaded. Inspect local repository files as needed and explain the gap in evidence.",
|
|
3802
|
+
"",
|
|
3803
|
+
"## Analysis Requirements",
|
|
3804
|
+
"",
|
|
3805
|
+
"- Document user-visible impact and concrete evidence or reproduction status.",
|
|
3806
|
+
"- Name affected surfaces and likely paths using concise path summaries only.",
|
|
3807
|
+
"- Provide rootCauseAnalysis. If unconfirmed, include falsifiableHypothesis and nextCheck.",
|
|
3808
|
+
"- Propose the fix and expected behavior, then provide a verification plan.",
|
|
3809
|
+
"- Keep repository source and secrets local. Do not include raw source dumps, credentials, local secret paths, or provider session references.",
|
|
3810
|
+
"- Leave approvalState as proposed. Implementation must wait for user approval in Amistio.",
|
|
3811
|
+
"",
|
|
3812
|
+
"## Output Contract",
|
|
3813
|
+
"",
|
|
3814
|
+
"Print exactly one JSON object between the markers below. The CLI will submit only this structured diagnosis back to Amistio.",
|
|
3815
|
+
"",
|
|
3816
|
+
issueDiagnosisStart,
|
|
3817
|
+
'{"summary":"The issue is caused by a missing state transition in the workspace action flow.","impact":"Users see a submitted action but no follow-up analysis appears.","evidence":["Reproduced by submitting an issue from the workspace UI"],"affectedSurfaces":["Workspace UI","Runner claim API"],"rootCauseAnalysis":"The issue path queues normal implementation work instead of diagnosis work.","falsifiableHypothesis":"Adding issueDiagnosis work and a dedicated result route will produce analysis without source mutation.","nextCheck":"Run focused web and CLI typechecks after wiring the route.","proposedFix":"Add a first-class issue diagnosis work kind, result parser, and approval-gated implementation queue.","expectedBehavior":"Submitted issues show a complete analysis and only queue implementation after approval.","verificationPlan":["Run shared, web, and CLI typechecks","Submit an issue with a compatible runner and verify analysis appears"],"riskLevel":"medium","likelyPaths":[{"repoPath":"src/apps/web/legacy/api/projects/[projectId]/issues.ts","reason":"Issue submission and approval route"}],"approvalState":"proposed"}',
|
|
3818
|
+
issueDiagnosisEnd,
|
|
3819
|
+
"",
|
|
3820
|
+
"Do not put Markdown fences around the markers. Do not implement the fix."
|
|
3821
|
+
].join("\n");
|
|
3822
|
+
}
|
|
3696
3823
|
function createImpactPreviewPrompt(workItem, context) {
|
|
3697
3824
|
const implementationPrompt = context?.implementationPrompt;
|
|
3698
3825
|
const approvedContext = (context?.documents ?? []).filter((document) => document.status === "approved" || document.syncState === "approved" || document.syncState === "synced").slice(0, 16).map((document) => [
|
|
@@ -3869,6 +3996,16 @@ function parseImpactPreviewResult(output) {
|
|
|
3869
3996
|
const parsed = JSON.parse(stripJsonFence(payload));
|
|
3870
3997
|
return impactPreviewResultSchema.parse(parsed);
|
|
3871
3998
|
}
|
|
3999
|
+
function parseIssueDiagnosisResult(output) {
|
|
4000
|
+
const start = output.indexOf(issueDiagnosisStart);
|
|
4001
|
+
const end = output.indexOf(issueDiagnosisEnd, start + issueDiagnosisStart.length);
|
|
4002
|
+
if (start === -1 || end === -1 || end <= start) {
|
|
4003
|
+
throw new Error("Local AI diagnosis did not return an Amistio issue diagnosis block.");
|
|
4004
|
+
}
|
|
4005
|
+
const payload = output.slice(start + issueDiagnosisStart.length, end).trim();
|
|
4006
|
+
const parsed = JSON.parse(stripJsonFence(payload));
|
|
4007
|
+
return issueDiagnosisResultSchema.parse(parsed);
|
|
4008
|
+
}
|
|
3872
4009
|
function createBrainGenerationPrompt(workItem) {
|
|
3873
4010
|
const wish = workItem.sourceWish ?? workItem.title;
|
|
3874
4011
|
return [
|
|
@@ -4412,6 +4549,39 @@ async function runOfficialCliUpdate() {
|
|
|
4412
4549
|
}
|
|
4413
4550
|
return { succeeded: false, message: "Official Amistio CLI update command failed.", error: result.output || `npm exited with code ${result.exitCode}.` };
|
|
4414
4551
|
}
|
|
4552
|
+
async function runOfficialCliUpdateWithRuntimeRefresh(options) {
|
|
4553
|
+
const updateResult = await (options.runUpdate ?? runOfficialCliUpdate)();
|
|
4554
|
+
if (!updateResult.succeeded) {
|
|
4555
|
+
return updateResult;
|
|
4556
|
+
}
|
|
4557
|
+
if (options.mode === "foreground") {
|
|
4558
|
+
return {
|
|
4559
|
+
succeeded: true,
|
|
4560
|
+
stopRunner: true,
|
|
4561
|
+
message: `${updateResult.message} Restart the local runner command to load the updated CLI version.`
|
|
4562
|
+
};
|
|
4563
|
+
}
|
|
4564
|
+
if (!options.restartBackgroundRunner) {
|
|
4565
|
+
return {
|
|
4566
|
+
succeeded: false,
|
|
4567
|
+
message: `${updateResult.message} Background runner restart was not available after update. Restart the runner manually to load the updated CLI version.`,
|
|
4568
|
+
error: "Background runner restart hook was not provided."
|
|
4569
|
+
};
|
|
4570
|
+
}
|
|
4571
|
+
const restartResult = await options.restartBackgroundRunner();
|
|
4572
|
+
if (restartResult.succeeded) {
|
|
4573
|
+
return {
|
|
4574
|
+
succeeded: true,
|
|
4575
|
+
stopRunner: true,
|
|
4576
|
+
message: `${updateResult.message} ${restartResult.message}`
|
|
4577
|
+
};
|
|
4578
|
+
}
|
|
4579
|
+
return {
|
|
4580
|
+
succeeded: false,
|
|
4581
|
+
message: `${updateResult.message} Background runner restart failed after update. Restart the runner manually to load the updated CLI version.`,
|
|
4582
|
+
error: restartResult.error ?? restartResult.message
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4415
4585
|
function runOfficialUpdateProcess(command, args, timeoutMs) {
|
|
4416
4586
|
return new Promise((resolve) => {
|
|
4417
4587
|
const child = spawn4(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -4548,6 +4718,7 @@ var DEFAULT_MAX_PREFLIGHT_ATTEMPTS = 3;
|
|
|
4548
4718
|
var DEFAULT_TOOL_TIMEOUT_SECONDS = 30 * 60;
|
|
4549
4719
|
var RUNNER_WORK_LEASE_SECONDS = 300;
|
|
4550
4720
|
var RUNNER_WORK_LEASE_RENEWAL_MS = 12e4;
|
|
4721
|
+
var runnerSupportedWorkKinds = ["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis"];
|
|
4551
4722
|
program.name("amistio").description("Amistio project brain CLI").version(CLI_VERSION);
|
|
4552
4723
|
program.command("init").description("Create Amistio control-plane folders for a new project").option("--root <path>", "Repository root", defaultRoot).action(async (options) => {
|
|
4553
4724
|
const created = await initControlPlane(options.root);
|
|
@@ -5510,6 +5681,24 @@ async function runNextWorkItem({
|
|
|
5510
5681
|
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
5511
5682
|
}
|
|
5512
5683
|
}
|
|
5684
|
+
if (result.workItem.workKind === "issueDiagnosis") {
|
|
5685
|
+
try {
|
|
5686
|
+
return await finalizeIssueDiagnosisWork({
|
|
5687
|
+
apiClient,
|
|
5688
|
+
durationMs: Date.now() - startedAt,
|
|
5689
|
+
projectId,
|
|
5690
|
+
repositoryLinkId,
|
|
5691
|
+
runnerId,
|
|
5692
|
+
sessionContext,
|
|
5693
|
+
toolConfig,
|
|
5694
|
+
toolName: preview.toolName,
|
|
5695
|
+
toolResult,
|
|
5696
|
+
workItem: result.workItem
|
|
5697
|
+
});
|
|
5698
|
+
} catch (error) {
|
|
5699
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
5700
|
+
}
|
|
5701
|
+
}
|
|
5513
5702
|
const finalStatus = toolResult.exitCode === 0 ? "completed" : "failed";
|
|
5514
5703
|
const durationMs = Date.now() - startedAt;
|
|
5515
5704
|
const failureExcerpt = toolResult.exitCode === 0 ? void 0 : truncateLogExcerpt(toolResult.stderr || toolResult.stdout);
|
|
@@ -5712,6 +5901,7 @@ async function recordRunnerMilestone(apiClient, projectId, workItem, runnerId, r
|
|
|
5712
5901
|
repositoryLinkId,
|
|
5713
5902
|
relatedWorkItemId: workItem.workItemId,
|
|
5714
5903
|
...workItem.reviewDocumentId ? { relatedDocumentId: workItem.reviewDocumentId } : workItem.impactDocumentId ? { relatedDocumentId: workItem.impactDocumentId } : {},
|
|
5904
|
+
...workItem.issueId ? { relatedIssueId: workItem.issueId } : {},
|
|
5715
5905
|
...workItem.generatedDraftId ? { generatedDraftId: workItem.generatedDraftId } : {},
|
|
5716
5906
|
...input
|
|
5717
5907
|
}).catch(() => void 0);
|
|
@@ -5759,7 +5949,10 @@ async function executeRunnerCommand(command, context) {
|
|
|
5759
5949
|
if (command.commandKind === "restart") {
|
|
5760
5950
|
return restartCurrentRunner(context);
|
|
5761
5951
|
}
|
|
5762
|
-
return
|
|
5952
|
+
return runOfficialCliUpdateWithRuntimeRefresh({
|
|
5953
|
+
mode: currentRunnerMode(),
|
|
5954
|
+
restartBackgroundRunner: () => restartCurrentRunner(context)
|
|
5955
|
+
});
|
|
5763
5956
|
}
|
|
5764
5957
|
async function restartCurrentRunner(context) {
|
|
5765
5958
|
if (currentRunnerMode() !== "background") {
|
|
@@ -6047,6 +6240,92 @@ ${toolResult.stderr}`);
|
|
|
6047
6240
|
console.error(previewError ?? "Local runner impact preview failed.");
|
|
6048
6241
|
return { status: "failed", exitCode: toolResult.exitCode || 1 };
|
|
6049
6242
|
}
|
|
6243
|
+
async function finalizeIssueDiagnosisWork({
|
|
6244
|
+
apiClient,
|
|
6245
|
+
durationMs,
|
|
6246
|
+
projectId,
|
|
6247
|
+
repositoryLinkId,
|
|
6248
|
+
runnerId,
|
|
6249
|
+
sessionContext,
|
|
6250
|
+
toolConfig,
|
|
6251
|
+
toolName,
|
|
6252
|
+
toolResult,
|
|
6253
|
+
workItem
|
|
6254
|
+
}) {
|
|
6255
|
+
let diagnosis = void 0;
|
|
6256
|
+
let diagnosisError;
|
|
6257
|
+
if (toolResult.exitCode === 0) {
|
|
6258
|
+
try {
|
|
6259
|
+
diagnosis = parseIssueDiagnosisResult(`${toolResult.stdout}
|
|
6260
|
+
${toolResult.stderr}`);
|
|
6261
|
+
} catch (error) {
|
|
6262
|
+
diagnosisError = errorMessage3(error);
|
|
6263
|
+
}
|
|
6264
|
+
} else {
|
|
6265
|
+
diagnosisError = truncateLogExcerpt(toolResult.stderr || toolResult.stdout) || `${toolName} exited with code ${toolResult.exitCode}.`;
|
|
6266
|
+
}
|
|
6267
|
+
const finalStatus = diagnosis ? "completed" : "failed";
|
|
6268
|
+
const updatedToolSession = await finalizeToolSession({
|
|
6269
|
+
apiClient,
|
|
6270
|
+
projectId,
|
|
6271
|
+
status: finalStatus,
|
|
6272
|
+
runnerId,
|
|
6273
|
+
workItemId: workItem.workItemId,
|
|
6274
|
+
stdout: toolResult.stdout,
|
|
6275
|
+
...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
|
|
6276
|
+
...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
|
|
6277
|
+
...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
|
|
6278
|
+
...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
|
|
6279
|
+
...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
|
|
6280
|
+
});
|
|
6281
|
+
const sessionTelemetry = {
|
|
6282
|
+
sessionPolicy: sessionContext.policy,
|
|
6283
|
+
sessionDecision: sessionContext.decision,
|
|
6284
|
+
sessionDecisionReason: sessionContext.reason,
|
|
6285
|
+
...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
|
|
6286
|
+
...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {}
|
|
6287
|
+
};
|
|
6288
|
+
if (diagnosis) {
|
|
6289
|
+
const result = await apiClient.submitIssueDiagnosisResult(projectId, workItem.workItemId, {
|
|
6290
|
+
status: "completed",
|
|
6291
|
+
runnerId,
|
|
6292
|
+
idempotencyKey: `issue_${workItem.workItemId}_${randomUUID()}`,
|
|
6293
|
+
diagnosis,
|
|
6294
|
+
tool: toolName,
|
|
6295
|
+
durationMs,
|
|
6296
|
+
...sessionTelemetry,
|
|
6297
|
+
message: `${toolName} returned an issue root-cause analysis.`
|
|
6298
|
+
});
|
|
6299
|
+
await recordRunnerMilestone(apiClient, projectId, workItem, runnerId, repositoryLinkId, {
|
|
6300
|
+
status: "completed",
|
|
6301
|
+
summary: `${toolName} returned an issue root-cause analysis.`,
|
|
6302
|
+
idempotencyKey: `runner_milestone_issue_completed_${workItem.workItemId}_${result.workItem.idempotencyKey}`,
|
|
6303
|
+
metadata: { tool: toolName, durationMs, riskLevel: diagnosis.riskLevel, likelyPathCount: diagnosis.likelyPaths.length, verificationSummary: diagnosis.verificationPlan.join(" | ") }
|
|
6304
|
+
});
|
|
6305
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig));
|
|
6306
|
+
console.log("Issue diagnosis returned for approval.");
|
|
6307
|
+
return { status: "completed", exitCode: 0 };
|
|
6308
|
+
}
|
|
6309
|
+
const failedResult = await apiClient.submitIssueDiagnosisResult(projectId, workItem.workItemId, {
|
|
6310
|
+
status: "failed",
|
|
6311
|
+
runnerId,
|
|
6312
|
+
idempotencyKey: `issue_${workItem.workItemId}_${randomUUID()}`,
|
|
6313
|
+
tool: toolName,
|
|
6314
|
+
durationMs,
|
|
6315
|
+
...sessionTelemetry,
|
|
6316
|
+
message: `${toolName} did not produce a valid issue diagnosis.`,
|
|
6317
|
+
...diagnosisError ? { error: diagnosisError } : {}
|
|
6318
|
+
});
|
|
6319
|
+
await recordRunnerMilestone(apiClient, projectId, workItem, runnerId, repositoryLinkId, {
|
|
6320
|
+
status: "failed",
|
|
6321
|
+
summary: diagnosisError ?? `${toolName} did not produce a valid issue diagnosis.`,
|
|
6322
|
+
idempotencyKey: `runner_milestone_issue_failed_${workItem.workItemId}_${failedResult.workItem.idempotencyKey}`,
|
|
6323
|
+
metadata: { tool: toolName, durationMs, verificationSummary: "Issue diagnosis output did not include valid structured JSON." }
|
|
6324
|
+
});
|
|
6325
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig));
|
|
6326
|
+
console.error(diagnosisError ?? "Local runner issue diagnosis failed.");
|
|
6327
|
+
return { status: "failed", exitCode: toolResult.exitCode || 1 };
|
|
6328
|
+
}
|
|
6050
6329
|
async function createRunnerWorkPrompt(apiClient, projectId, workItem) {
|
|
6051
6330
|
if (workItem.workKind === "assistantQuestion") {
|
|
6052
6331
|
const [{ documents: documents2 }, { messages: messages2 }] = await Promise.all([
|
|
@@ -6068,6 +6347,19 @@ async function createRunnerWorkPrompt(apiClient, projectId, workItem) {
|
|
|
6068
6347
|
}
|
|
6069
6348
|
});
|
|
6070
6349
|
}
|
|
6350
|
+
if (workItem.workKind === "issueDiagnosis") {
|
|
6351
|
+
const [{ documents: documents2 }, { issues }] = await Promise.all([
|
|
6352
|
+
apiClient.listBrainDocuments(projectId),
|
|
6353
|
+
apiClient.listIssues(projectId)
|
|
6354
|
+
]);
|
|
6355
|
+
const issue = issues.find((item) => item.issueId === workItem.issueId || item.id === workItem.issueId);
|
|
6356
|
+
return createWorkExecutionPrompt(workItem, {
|
|
6357
|
+
issueDiagnosis: {
|
|
6358
|
+
documents: documents2,
|
|
6359
|
+
...issue ? { issue } : {}
|
|
6360
|
+
}
|
|
6361
|
+
});
|
|
6362
|
+
}
|
|
6071
6363
|
if (workItem.workKind !== "planRevision" || !workItem.reviewDocumentId) {
|
|
6072
6364
|
return createWorkExecutionPrompt(workItem);
|
|
6073
6365
|
}
|
|
@@ -6545,6 +6837,7 @@ function toRunnerToolCapabilities(tools) {
|
|
|
6545
6837
|
function runnerIsolationCapabilityMetadata() {
|
|
6546
6838
|
return {
|
|
6547
6839
|
machineId: runnerMachineId(),
|
|
6840
|
+
supportedWorkKinds: runnerSupportedWorkKinds,
|
|
6548
6841
|
supportsBranchIsolation: true,
|
|
6549
6842
|
supportsGitWorktreeIsolation: true
|
|
6550
6843
|
};
|