@amistio/cli 0.1.29 → 0.1.31
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 +2 -2
- package/dist/index.js +321 -8
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,9 +15,9 @@ Runner lifecycle controls in the web app, such as update, restart, and remove, a
|
|
|
15
15
|
|
|
16
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. If replacement restart metadata is missing or restart fails after a successful install, the old runner still stops and reports manual restart guidance instead of continuing to heartbeat the stale runtime. Foreground `amistio run --watch` sessions stop after a successful install with restart guidance; start the command again to load the updated package.
|
|
17
17
|
|
|
18
|
-
Current runners advertise the work kinds they can claim. Older runners that do not send this capability can continue legacy brain generation, implementation, and plan revision work, but they will skip source-aware assistant, impact-preview, project-context refresh, issue-diagnosis, app-evaluation, security-posture, Test-quality, implementation-Test-gate, and implementation-verification work until updated.
|
|
18
|
+
Current runners advertise the work kinds they can claim. Older runners that do not send this capability can continue legacy brain generation, implementation, and plan revision work, but they will skip source-aware assistant, impact-preview, semantic brain consolidation, project-context refresh, issue-diagnosis, app-evaluation, security-posture, Test-quality, implementation-Test-gate, and implementation-verification work until updated.
|
|
19
19
|
|
|
20
|
-
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 and HTML
|
|
20
|
+
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 and explicit HTML artifacts under `docs/html/<area>/`, including local ADRs, plans, prompts, workflows, memory, context, architecture, and feature docs, to the app for review. Markdown is the default generation format; HTML appears only when a runner or user explicitly generated an HTML artifact. `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.
|
|
21
21
|
|
|
22
22
|
Repository autopilot is disabled until the repository link option is enabled in the app. When enabled, Amistio can attach an audited low-risk autopilot authorization to eligible runner work, including generated brain approval, impact preview, issue diagnosis, security posture scan, app evaluation cleanup, low-risk implementation handoff, requeue, and implementation verification. The Runner panel shows and updates safe work scopes, allowed candidate types, max risk, optional runner binding, daily/concurrent/failure budgets, expiry/review/cooldown windows, and pause state. The CLI shows authorization id, candidate id/type, outcome, policy version, and work kind in `amistio work list`, claim logs, runner prompts, and milestone activity. Autopilot does not widen local runner permissions: pairing, supported work kinds, runner identity, Git worktree isolation, redaction, local-tool permission controls, and unsafe/review-required/blocked/paused/budget stops still apply.
|
|
23
23
|
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,8 @@ var itemTypeSchema = z.enum([
|
|
|
30
30
|
"implementationTestGate",
|
|
31
31
|
"appEvaluationScan",
|
|
32
32
|
"appEvaluationFinding",
|
|
33
|
+
"brainConsolidationScan",
|
|
34
|
+
"brainConsolidationProposal",
|
|
33
35
|
"implementationVerification",
|
|
34
36
|
"projectContextMap",
|
|
35
37
|
"projectContextRefresh",
|
|
@@ -83,7 +85,7 @@ var workStatusSchema = z.enum([
|
|
|
83
85
|
]);
|
|
84
86
|
var sourceSchema = z.enum(["web", "repo", "generated", "runner"]);
|
|
85
87
|
var executionModeSchema = z.enum(["localRunner", "cloudSandbox"]);
|
|
86
|
-
var workKindSchema = z.enum(["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate", "runnerCommand"]);
|
|
88
|
+
var workKindSchema = z.enum(["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "brainConsolidationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate", "runnerCommand"]);
|
|
87
89
|
var autopilotModeSchema = z.enum(["disabled", "enabled", "paused"]);
|
|
88
90
|
var autopilotClassificationOutcomeSchema = z.enum(["safeAutopilotEligible", "requiresReview", "blocked", "unsafe"]);
|
|
89
91
|
var autopilotCandidateTypeSchema = z.enum([
|
|
@@ -224,6 +226,7 @@ var autopilotCandidateLinksSchema = z.object({
|
|
|
224
226
|
securityFindingId: z.string().min(1).optional(),
|
|
225
227
|
appEvaluationScanId: z.string().min(1).optional(),
|
|
226
228
|
appEvaluationFindingId: z.string().min(1).optional(),
|
|
229
|
+
brainConsolidationScanId: z.string().min(1).optional(),
|
|
227
230
|
implementationVerificationId: z.string().min(1).optional(),
|
|
228
231
|
testQualityScanId: z.string().min(1).optional(),
|
|
229
232
|
testQualityFindingId: z.string().min(1).optional(),
|
|
@@ -306,6 +309,14 @@ var appEvaluationFindingConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
|
306
309
|
var appEvaluationFindingStatusSchema = z.enum(["open", "planReady", "approved", "changesRequested", "dismissed", "acceptedRisk", "implementationQueued", "resolved", "failed"]);
|
|
307
310
|
var appEvaluationApprovalStateSchema = z.enum(["proposed", "approved", "changesRequested", "dismissed", "acceptedRisk", "implemented", "blocked"]);
|
|
308
311
|
var appEvaluationPlanLifecycleActionSchema = z.enum(["createPlan", "updatePlan", "markCompleted", "markImplemented", "markSuperseded", "markBlocked", "archive", "keepActive", "none"]);
|
|
312
|
+
var brainConsolidationScanStatusSchema = z.enum(["running", "completed", "failed"]);
|
|
313
|
+
var brainConsolidationScanSourceSchema = z.enum(["manual", "system", "runner"]);
|
|
314
|
+
var brainConsolidationProposalStatusSchema = z.enum(["open", "approved", "changesRequested", "dismissed", "acceptedRisk", "resolved", "failed"]);
|
|
315
|
+
var brainConsolidationProposalActionSchema = z.enum(["archiveDuplicates", "supersedeDuplicates", "keepCanonical", "manualReview"]);
|
|
316
|
+
var brainConsolidationRiskLevelSchema = z.enum(["low", "medium", "high", "critical"]);
|
|
317
|
+
var brainConsolidationRecommendationCoverageSchema = z.enum(["full", "partial", "notCovered", "ambiguous"]);
|
|
318
|
+
var brainConsolidationRecommendationConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
319
|
+
var brainConsolidationRecommendationActionSchema = z.enum(["archiveDuplicate", "proposeArchive", "manualReview", "skip"]);
|
|
309
320
|
var activityEventTypeSchema = z.enum([
|
|
310
321
|
"autopilotAuthorized",
|
|
311
322
|
"autopilotReviewRequired",
|
|
@@ -350,6 +361,11 @@ var activityEventTypeSchema = z.enum([
|
|
|
350
361
|
"appEvaluationFindingReviewed",
|
|
351
362
|
"appEvaluationPlanCreated",
|
|
352
363
|
"appEvaluationImplementationQueued",
|
|
364
|
+
"brainConsolidationStarted",
|
|
365
|
+
"brainConsolidationCompleted",
|
|
366
|
+
"brainConsolidationFailed",
|
|
367
|
+
"brainConsolidationProposalCreated",
|
|
368
|
+
"brainConsolidationProposalReviewed",
|
|
353
369
|
"testProfileDetected",
|
|
354
370
|
"testProfileUpdated",
|
|
355
371
|
"testQualityScanQueued",
|
|
@@ -615,6 +631,57 @@ var brainDocumentItemSchema = baseItemSchema.extend({
|
|
|
615
631
|
source: sourceSchema,
|
|
616
632
|
syncState: syncStateSchema
|
|
617
633
|
});
|
|
634
|
+
var brainConsolidationScanItemSchema = baseItemSchema.extend({
|
|
635
|
+
type: z.literal("brainConsolidationScan"),
|
|
636
|
+
projectId: z.string().min(1),
|
|
637
|
+
brainConsolidationScanId: z.string().min(1),
|
|
638
|
+
source: brainConsolidationScanSourceSchema,
|
|
639
|
+
status: brainConsolidationScanStatusSchema,
|
|
640
|
+
workItemId: z.string().min(1).optional(),
|
|
641
|
+
repositoryLinkId: z.string().min(1).optional(),
|
|
642
|
+
runnerId: z.string().min(1).optional(),
|
|
643
|
+
activeReviewCount: z.number().int().nonnegative(),
|
|
644
|
+
exactDuplicateGroupCount: z.number().int().nonnegative(),
|
|
645
|
+
autoArchivedCount: z.number().int().nonnegative(),
|
|
646
|
+
proposalCount: z.number().int().nonnegative(),
|
|
647
|
+
skippedCount: z.number().int().nonnegative(),
|
|
648
|
+
residualReviewCount: z.number().int().nonnegative(),
|
|
649
|
+
summary: z.string().trim().min(1).max(800),
|
|
650
|
+
startedAt: isoDateTimeSchema,
|
|
651
|
+
completedAt: isoDateTimeSchema.optional(),
|
|
652
|
+
error: z.string().trim().min(1).max(800).optional()
|
|
653
|
+
});
|
|
654
|
+
var brainConsolidationProposalItemSchema = baseItemSchema.extend({
|
|
655
|
+
type: z.literal("brainConsolidationProposal"),
|
|
656
|
+
projectId: z.string().min(1),
|
|
657
|
+
brainConsolidationProposalId: z.string().min(1),
|
|
658
|
+
brainConsolidationScanId: z.string().min(1).optional(),
|
|
659
|
+
status: brainConsolidationProposalStatusSchema,
|
|
660
|
+
action: brainConsolidationProposalActionSchema,
|
|
661
|
+
riskLevel: brainConsolidationRiskLevelSchema,
|
|
662
|
+
canonicalDocumentId: z.string().min(1),
|
|
663
|
+
candidateDocumentIds: z.array(z.string().min(1)).min(1).max(50),
|
|
664
|
+
evidence: z.array(z.string().trim().min(1).max(300)).min(1).max(20),
|
|
665
|
+
reason: z.string().trim().min(1).max(800),
|
|
666
|
+
reviewedByUserId: z.string().min(1).optional(),
|
|
667
|
+
reviewedAt: isoDateTimeSchema.optional()
|
|
668
|
+
});
|
|
669
|
+
var brainConsolidationRecommendationSchema = z.object({
|
|
670
|
+
recommendationId: z.string().trim().min(1).max(160).optional(),
|
|
671
|
+
canonicalDocumentId: z.string().min(1),
|
|
672
|
+
candidateDocumentIds: z.array(z.string().min(1)).min(1).max(25),
|
|
673
|
+
coverage: brainConsolidationRecommendationCoverageSchema,
|
|
674
|
+
confidence: brainConsolidationRecommendationConfidenceSchema.default("medium"),
|
|
675
|
+
recommendedAction: brainConsolidationRecommendationActionSchema,
|
|
676
|
+
riskLevel: brainConsolidationRiskLevelSchema.default("medium"),
|
|
677
|
+
evidence: z.array(z.string().trim().min(1).max(300)).min(1).max(10),
|
|
678
|
+
reason: z.string().trim().min(1).max(800)
|
|
679
|
+
});
|
|
680
|
+
var brainConsolidationScanResultSchema = z.object({
|
|
681
|
+
summary: z.string().trim().min(1).max(2e3),
|
|
682
|
+
recommendations: z.array(brainConsolidationRecommendationSchema).max(100).default([]),
|
|
683
|
+
warnings: z.array(z.string().trim().min(1).max(600)).default([])
|
|
684
|
+
});
|
|
618
685
|
var generatedDraftItemSchema = baseItemSchema.extend({
|
|
619
686
|
type: z.literal("generatedDraft"),
|
|
620
687
|
projectId: z.string().min(1),
|
|
@@ -665,6 +732,7 @@ var workItemSchema = baseItemSchema.extend({
|
|
|
665
732
|
securityFindingId: z.string().min(1).optional(),
|
|
666
733
|
appEvaluationScanId: z.string().min(1).optional(),
|
|
667
734
|
appEvaluationFindingId: z.string().min(1).optional(),
|
|
735
|
+
brainConsolidationScanId: z.string().min(1).optional(),
|
|
668
736
|
implementationVerificationId: z.string().min(1).optional(),
|
|
669
737
|
testQualityScanId: z.string().min(1).optional(),
|
|
670
738
|
testQualityFindingId: z.string().min(1).optional(),
|
|
@@ -1841,6 +1909,8 @@ var projectItemUnionSchema = z.discriminatedUnion("type", [
|
|
|
1841
1909
|
implementationTestGateItemSchema,
|
|
1842
1910
|
appEvaluationScanItemSchema,
|
|
1843
1911
|
appEvaluationFindingItemSchema,
|
|
1912
|
+
brainConsolidationScanItemSchema,
|
|
1913
|
+
brainConsolidationProposalItemSchema,
|
|
1844
1914
|
implementationVerificationItemSchema,
|
|
1845
1915
|
projectContextMapItemSchema,
|
|
1846
1916
|
projectContextRefreshItemSchema,
|
|
@@ -2929,6 +2999,16 @@ var ApiClient = class {
|
|
|
2929
2999
|
}
|
|
2930
3000
|
);
|
|
2931
3001
|
}
|
|
3002
|
+
async submitBrainConsolidationScanResult(projectId, workItemId, result) {
|
|
3003
|
+
return this.request(
|
|
3004
|
+
`/projects/${projectId}/work-items/${workItemId}/brain-consolidation-result`,
|
|
3005
|
+
z3.object({ scan: brainConsolidationScanItemSchema, proposals: z3.array(brainConsolidationProposalItemSchema), autoArchivedDocuments: z3.array(brainDocumentItemSchema), workItem: workItemSchema }),
|
|
3006
|
+
{
|
|
3007
|
+
method: "POST",
|
|
3008
|
+
body: JSON.stringify(result)
|
|
3009
|
+
}
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
2932
3012
|
async submitProjectContextRefreshResult(projectId, workItemId, result) {
|
|
2933
3013
|
return this.request(
|
|
2934
3014
|
`/projects/${projectId}/work-items/${workItemId}/project-context-result`,
|
|
@@ -3187,6 +3267,13 @@ var appEvaluationScanResultMutationSchema = z4.discriminatedUnion("status", [
|
|
|
3187
3267
|
}),
|
|
3188
3268
|
resultFinalizationFailureSchema
|
|
3189
3269
|
]);
|
|
3270
|
+
var brainConsolidationScanResultMutationSchema = z4.discriminatedUnion("status", [
|
|
3271
|
+
resultFinalizationTelemetrySchema.extend({
|
|
3272
|
+
status: z4.literal("completed"),
|
|
3273
|
+
result: brainConsolidationScanResultSchema
|
|
3274
|
+
}),
|
|
3275
|
+
resultFinalizationFailureSchema
|
|
3276
|
+
]);
|
|
3190
3277
|
var projectContextRefreshResultMutationSchema = z4.discriminatedUnion("status", [
|
|
3191
3278
|
resultFinalizationTelemetrySchema.extend({
|
|
3192
3279
|
status: z4.literal("completed"),
|
|
@@ -3221,6 +3308,7 @@ var durableResultMutationSchema = z4.discriminatedUnion("resultKind", [
|
|
|
3221
3308
|
z4.object({ resultKind: z4.literal("issueDiagnosisResult"), result: issueDiagnosisResultMutationSchema }),
|
|
3222
3309
|
z4.object({ resultKind: z4.literal("securityPostureScanResult"), result: securityPostureScanResultMutationSchema }),
|
|
3223
3310
|
z4.object({ resultKind: z4.literal("appEvaluationScanResult"), result: appEvaluationScanResultMutationSchema }),
|
|
3311
|
+
z4.object({ resultKind: z4.literal("brainConsolidationScanResult"), result: brainConsolidationScanResultMutationSchema }),
|
|
3224
3312
|
z4.object({ resultKind: z4.literal("projectContextRefreshResult"), result: projectContextRefreshResultMutationSchema }),
|
|
3225
3313
|
z4.object({ resultKind: z4.literal("implementationVerificationResult"), result: implementationVerificationResultMutationSchema }),
|
|
3226
3314
|
z4.object({ resultKind: z4.literal("testQualityScanResult"), result: testQualityScanResultMutationSchema }),
|
|
@@ -3235,7 +3323,7 @@ var durableResultFinalizationEntrySchema = z4.object({
|
|
|
3235
3323
|
repositoryLinkId: z4.string().min(1),
|
|
3236
3324
|
runnerId: z4.string().min(1),
|
|
3237
3325
|
workItemId: z4.string().min(1),
|
|
3238
|
-
workKind: z4.enum(["assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate"]),
|
|
3326
|
+
workKind: z4.enum(["assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "brainConsolidationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate"]),
|
|
3239
3327
|
attempt: z4.number().int().nonnegative(),
|
|
3240
3328
|
idempotencyKey: z4.string().min(1),
|
|
3241
3329
|
retryCount: z4.number().int().nonnegative(),
|
|
@@ -5358,6 +5446,8 @@ var securityPostureStart = "AMISTIO_SECURITY_POSTURE_START";
|
|
|
5358
5446
|
var securityPostureEnd = "AMISTIO_SECURITY_POSTURE_END";
|
|
5359
5447
|
var appEvaluationStart = "AMISTIO_APP_EVALUATION_START";
|
|
5360
5448
|
var appEvaluationEnd = "AMISTIO_APP_EVALUATION_END";
|
|
5449
|
+
var brainConsolidationStart = "AMISTIO_BRAIN_CONSOLIDATION_START";
|
|
5450
|
+
var brainConsolidationEnd = "AMISTIO_BRAIN_CONSOLIDATION_END";
|
|
5361
5451
|
var projectContextRefreshStart = "AMISTIO_PROJECT_CONTEXT_REFRESH_START";
|
|
5362
5452
|
var projectContextRefreshEnd = "AMISTIO_PROJECT_CONTEXT_REFRESH_END";
|
|
5363
5453
|
var implementationVerificationStart = "AMISTIO_IMPLEMENTATION_VERIFICATION_START";
|
|
@@ -5706,6 +5796,9 @@ function createWorkExecutionPrompt(workItem, context) {
|
|
|
5706
5796
|
if (workItem.workKind === "appEvaluationScan") {
|
|
5707
5797
|
return createAppEvaluationScanPrompt(workItem, context?.appEvaluationScan);
|
|
5708
5798
|
}
|
|
5799
|
+
if (workItem.workKind === "brainConsolidationScan") {
|
|
5800
|
+
return createBrainConsolidationScanPrompt(workItem, context?.brainConsolidationScan);
|
|
5801
|
+
}
|
|
5709
5802
|
if (workItem.workKind === "projectContextRefresh") {
|
|
5710
5803
|
return createProjectContextRefreshPrompt(workItem, context?.projectContextRefresh);
|
|
5711
5804
|
}
|
|
@@ -5938,8 +6031,10 @@ function createAppEvaluationScanPrompt(workItem, context) {
|
|
|
5938
6031
|
"",
|
|
5939
6032
|
"- Check app verification health: lint, typecheck, test, build, CI references, flaky or missing gates.",
|
|
5940
6033
|
"- Check product and docs drift between approved context, plans, prompts, and current implementation.",
|
|
5941
|
-
"- Check old plans and prompts for
|
|
5942
|
-
"- Treat active proposed, approved, ready, or in-progress plans/prompts with accepted controlling ADRs, features, or work artifacts as active
|
|
6034
|
+
"- Check old plans and prompts for lifecycle reconciliation, but only propose cleanup actions such as markCompleted, markSuperseded, or archive when direct controlling evidence shows they are completed, superseded, or obsolete.",
|
|
6035
|
+
"- Treat active proposed, approved, ready, or in-progress plans/prompts with accepted controlling ADRs, features, or work artifacts as active backlog. Do not classify them as cleanup material solely because they are older, unexecuted, or not yet fully implemented; use keepActive when they still describe valid pending or approved work.",
|
|
6036
|
+
"- Treat intentionally in-progress feature tracks as still-active work when their controlling plan/feature has unchecked requirements or explicit follow-up gaps. For example, a completed first implementation prompt does not make the broader feature stale if PLAN/FEAT evidence says remaining lifecycle work is still open; return proposedLifecycleAction keepActive with evidence instead of cleanup.",
|
|
6037
|
+
"- Treat prompt frontmatter status Ready as an active execution backlog state by default, not as stale review debt. Only flag a Ready prompt for metadata correction when its controlling plan, feature, prompt index, or verification evidence unambiguously proves the prompt has already completed or been superseded.",
|
|
5943
6038
|
"- When lifecycle metadata disagrees across indexes, frontmatter, feature specs, ADRs, and implementation evidence, cite the conflict and propose a metadata correction or verification step instead of archival/removal.",
|
|
5944
6039
|
"- Check missing memory or workflow updates when repeated lessons or operational rules are visible.",
|
|
5945
6040
|
"- Check release readiness, UX, accessibility, performance, reliability, and security-posture follow-through at a summary level.",
|
|
@@ -5968,6 +6063,91 @@ function createAppEvaluationScanPrompt(workItem, context) {
|
|
|
5968
6063
|
"Do not put Markdown fences around the markers. Do not implement improvements or cleanup."
|
|
5969
6064
|
].join("\n");
|
|
5970
6065
|
}
|
|
6066
|
+
function createBrainConsolidationScanPrompt(workItem, context) {
|
|
6067
|
+
const documents = context?.documents ?? [];
|
|
6068
|
+
const activeReviewDocuments = documents.filter(isActiveReviewPromptDocument).slice(0, 160);
|
|
6069
|
+
const canonicalDocuments = documents.filter(isCanonicalPromptDocument).slice(0, 120);
|
|
6070
|
+
const activeReviewContext = activeReviewDocuments.map((document) => formatBrainConsolidationDocument(document)).join("\n\n");
|
|
6071
|
+
const canonicalContext = canonicalDocuments.map((document) => formatBrainConsolidationDocument(document)).join("\n\n");
|
|
6072
|
+
return [
|
|
6073
|
+
"# Amistio Semantic Brain Consolidation Scan",
|
|
6074
|
+
"",
|
|
6075
|
+
"You are running locally through the Amistio CLI inside the user's repository.",
|
|
6076
|
+
"Run a read-only semantic duplicate and coverage scan for Project Brain review documents.",
|
|
6077
|
+
"Do not modify files, create branches, commit, push, archive documents, approve documents, or run implementation prompts.",
|
|
6078
|
+
"Return bounded recommendations only; the Amistio server decides what is safe to auto-archive.",
|
|
6079
|
+
"",
|
|
6080
|
+
"## Work Item",
|
|
6081
|
+
"",
|
|
6082
|
+
`Title: ${workItem.title}`,
|
|
6083
|
+
`Work item ID: ${workItem.workItemId}`,
|
|
6084
|
+
`Project ID: ${workItem.projectId}`,
|
|
6085
|
+
`Brain consolidation scan ID: ${workItem.brainConsolidationScanId ?? "unknown"}`,
|
|
6086
|
+
"",
|
|
6087
|
+
"## Scan Request",
|
|
6088
|
+
"",
|
|
6089
|
+
workItem.sourceWish ?? "Compare active generated review documents against approved or synced Project Brain documents and recommend safe consolidation actions.",
|
|
6090
|
+
"",
|
|
6091
|
+
"## Active Review Documents",
|
|
6092
|
+
"",
|
|
6093
|
+
activeReviewContext || "No active review documents were provided in the scan context.",
|
|
6094
|
+
"",
|
|
6095
|
+
"## Approved Or Synced Canonical Documents",
|
|
6096
|
+
"",
|
|
6097
|
+
canonicalContext || "No approved or synced canonical documents were provided in the scan context.",
|
|
6098
|
+
"",
|
|
6099
|
+
"## Requirements",
|
|
6100
|
+
"",
|
|
6101
|
+
"- Compare active review documents to approved or synced canonical documents by documentId, title, repoPath, documentType, source, syncState, frontmatter lineage, and content excerpt.",
|
|
6102
|
+
"- Recommend archiveDuplicate only when a generated draft is fully covered by a canonical approved/synced document and adds no distinct requirement, decision, plan step, or memory entry.",
|
|
6103
|
+
"- Use proposeArchive for partial, ambiguous, user-owned, repo-sourced, dirty, or medium-risk matches that need human review.",
|
|
6104
|
+
"- Use manualReview when the candidate appears related but may contain unique requirements or unresolved conflicts.",
|
|
6105
|
+
"- Use skip for documents that are not duplicates or cannot be evaluated safely from the available context.",
|
|
6106
|
+
"- Keep each recommendation focused on one canonical document and one or more candidate document IDs.",
|
|
6107
|
+
"",
|
|
6108
|
+
"## Data Safety",
|
|
6109
|
+
"",
|
|
6110
|
+
"- Persist only document IDs, short evidence, bounded summaries, and recommendations.",
|
|
6111
|
+
"- Do not include raw source dumps, secrets, env vars, process lists, absolute local paths, credential values, tokens, provider sessions, or destructive shell output.",
|
|
6112
|
+
"",
|
|
6113
|
+
"## Output Contract",
|
|
6114
|
+
"",
|
|
6115
|
+
"Print exactly one JSON object between the markers below. The CLI will submit only this structured consolidation result back to Amistio.",
|
|
6116
|
+
"Accepted coverage values: full, partial, notCovered, ambiguous.",
|
|
6117
|
+
"Accepted confidence values: low, medium, high.",
|
|
6118
|
+
"Accepted recommendedAction values: archiveDuplicate, proposeArchive, manualReview, skip.",
|
|
6119
|
+
"Accepted riskLevel values: low, medium, high, critical.",
|
|
6120
|
+
"",
|
|
6121
|
+
brainConsolidationStart,
|
|
6122
|
+
'{"summary":"Compared active generated review documents against approved canonical documents.","recommendations":[{"canonicalDocumentId":"doc_approved","candidateDocumentIds":["doc_review_duplicate"],"coverage":"full","confidence":"high","recommendedAction":"archiveDuplicate","riskLevel":"low","evidence":["The candidate repeats the accepted decision without adding requirements."],"reason":"The generated review draft is fully covered by the approved canonical document."}],"warnings":[]}',
|
|
6123
|
+
brainConsolidationEnd,
|
|
6124
|
+
"",
|
|
6125
|
+
"Do not put Markdown fences around the markers. Do not archive, approve, or edit documents."
|
|
6126
|
+
].join("\n");
|
|
6127
|
+
}
|
|
6128
|
+
function formatBrainConsolidationDocument(document) {
|
|
6129
|
+
return [
|
|
6130
|
+
`### ${document.title}`,
|
|
6131
|
+
`documentId: ${document.documentId}`,
|
|
6132
|
+
`documentType: ${document.documentType}`,
|
|
6133
|
+
`repoPath: ${document.repoPath}`,
|
|
6134
|
+
`contentFormat: ${document.contentFormat ?? "markdown"}`,
|
|
6135
|
+
`source: ${document.source}`,
|
|
6136
|
+
`status: ${document.status}`,
|
|
6137
|
+
`syncState: ${document.syncState}`,
|
|
6138
|
+
`revision: ${document.revision}`,
|
|
6139
|
+
`approvedRevision: ${document.approvedRevision ?? "none"}`,
|
|
6140
|
+
`contentHash: ${document.contentHash}`,
|
|
6141
|
+
`frontmatter: ${JSON.stringify(document.frontmatter)}`,
|
|
6142
|
+
document.content.slice(0, 1600)
|
|
6143
|
+
].join("\n");
|
|
6144
|
+
}
|
|
6145
|
+
function isActiveReviewPromptDocument(document) {
|
|
6146
|
+
return document.syncState === "draft" && ["draft", "drafted", "reviewing", "changesRequested"].includes(document.status);
|
|
6147
|
+
}
|
|
6148
|
+
function isCanonicalPromptDocument(document) {
|
|
6149
|
+
return document.syncState === "approved" || document.syncState === "synced" || document.status === "approved";
|
|
6150
|
+
}
|
|
5971
6151
|
function createIssueDiagnosisPrompt(workItem, context) {
|
|
5972
6152
|
const issue = context?.issue;
|
|
5973
6153
|
const approvedContext = (context?.documents ?? []).filter((document) => document.status === "approved" || document.syncState === "approved" || document.syncState === "synced").slice(0, 16).map((document) => [
|
|
@@ -6293,6 +6473,16 @@ function parseAppEvaluationScanResult(output) {
|
|
|
6293
6473
|
const normalized = normalizeAppEvaluationScanResultPaths(normalizeAppEvaluationScanResultEnums(parsed));
|
|
6294
6474
|
return appEvaluationScanResultSchema.parse(normalized);
|
|
6295
6475
|
}
|
|
6476
|
+
function parseBrainConsolidationScanResult(output) {
|
|
6477
|
+
const start = output.indexOf(brainConsolidationStart);
|
|
6478
|
+
const end = output.indexOf(brainConsolidationEnd, start + brainConsolidationStart.length);
|
|
6479
|
+
if (start === -1 || end === -1 || end <= start) {
|
|
6480
|
+
throw new Error("Local AI scan did not return an Amistio brain consolidation block.");
|
|
6481
|
+
}
|
|
6482
|
+
const payload = output.slice(start + brainConsolidationStart.length, end).trim();
|
|
6483
|
+
const parsed = JSON.parse(stripJsonFence(payload));
|
|
6484
|
+
return brainConsolidationScanResultSchema.parse(parsed);
|
|
6485
|
+
}
|
|
6296
6486
|
function parseProjectContextRefreshResult(output, options = {}) {
|
|
6297
6487
|
const start = output.indexOf(projectContextRefreshStart);
|
|
6298
6488
|
const end = output.indexOf(projectContextRefreshEnd, start + projectContextRefreshStart.length);
|
|
@@ -6445,7 +6635,7 @@ function createBrainGenerationPrompt(workItem) {
|
|
|
6445
6635
|
"- plan -> docs/plans/",
|
|
6446
6636
|
"- prompt -> docs/prompts/",
|
|
6447
6637
|
"- workflow -> docs/workflows/",
|
|
6448
|
-
"- HTML
|
|
6638
|
+
"- HTML artifacts -> docs/html/<same-folder>/ using .html, for example docs/html/plans/PLAN-example.html",
|
|
6449
6639
|
"",
|
|
6450
6640
|
artifactFormatPreferenceInstructions(artifactFormatPreference),
|
|
6451
6641
|
"",
|
|
@@ -6722,10 +6912,10 @@ function artifactFormatPreferenceInstructions(preference) {
|
|
|
6722
6912
|
return "The user chose HTML. Generate .html artifacts under docs/html/<folder>/ and set contentFormat to html.";
|
|
6723
6913
|
}
|
|
6724
6914
|
if (preference === "both") {
|
|
6725
|
-
return "The user chose both formats.
|
|
6915
|
+
return "The user chose both formats. Choose one format per artifact purpose; do not generate matching Markdown and HTML companion copies of the same document.";
|
|
6726
6916
|
}
|
|
6727
6917
|
if (preference === "auto") {
|
|
6728
|
-
return "Choose Markdown or HTML based on the artifact content. Use Markdown for text-first docs and HTML for visual or layout-sensitive artifacts.";
|
|
6918
|
+
return "Choose Markdown or HTML based on the artifact content. Use Markdown for text-first docs and HTML only for visual or layout-sensitive artifacts.";
|
|
6729
6919
|
}
|
|
6730
6920
|
return "The user chose Markdown. Generate Markdown artifacts under docs/<folder>/ and set contentFormat to markdown or omit it.";
|
|
6731
6921
|
}
|
|
@@ -7790,7 +7980,7 @@ var DEFAULT_TOOL_TIMEOUT_SECONDS = 30 * 60;
|
|
|
7790
7980
|
var RUNNER_WORK_LEASE_SECONDS = 300;
|
|
7791
7981
|
var RUNNER_WORK_LEASE_RENEWAL_MS = 12e4;
|
|
7792
7982
|
var MAX_CONCURRENT_RUNNER_WORK = 4;
|
|
7793
|
-
var runnerSupportedWorkKinds = ["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate"];
|
|
7983
|
+
var runnerSupportedWorkKinds = ["brainGeneration", "implementation", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "brainConsolidationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate"];
|
|
7794
7984
|
program.name("amistio").description("Amistio project brain CLI").version(CLI_VERSION);
|
|
7795
7985
|
program.command("init").description("Create Amistio control-plane folders for a new project").option("--root <path>", "Repository root", defaultRoot).action(async (options) => {
|
|
7796
7986
|
const created = await initControlPlane(options.root);
|
|
@@ -8871,6 +9061,24 @@ async function runNextWorkItem({
|
|
|
8871
9061
|
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
8872
9062
|
}
|
|
8873
9063
|
}
|
|
9064
|
+
if (result.workItem.workKind === "brainConsolidationScan") {
|
|
9065
|
+
try {
|
|
9066
|
+
return await finalizeBrainConsolidationScanWork({
|
|
9067
|
+
apiClient,
|
|
9068
|
+
durationMs: Date.now() - startedAt,
|
|
9069
|
+
projectId,
|
|
9070
|
+
repositoryLinkId,
|
|
9071
|
+
runnerId,
|
|
9072
|
+
sessionContext,
|
|
9073
|
+
toolConfig,
|
|
9074
|
+
toolName: preview.toolName,
|
|
9075
|
+
toolResult,
|
|
9076
|
+
workItem: result.workItem
|
|
9077
|
+
});
|
|
9078
|
+
} catch (error) {
|
|
9079
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
9080
|
+
}
|
|
9081
|
+
}
|
|
8874
9082
|
if (result.workItem.workKind === "projectContextRefresh") {
|
|
8875
9083
|
try {
|
|
8876
9084
|
return await finalizeProjectContextRefreshWork({
|
|
@@ -9473,6 +9681,9 @@ async function submitDurableResultMutation(apiClient, entry) {
|
|
|
9473
9681
|
if (entry.resultKind === "appEvaluationScanResult") {
|
|
9474
9682
|
return apiClient.submitAppEvaluationScanResult(entry.projectId, entry.workItemId, entry.result);
|
|
9475
9683
|
}
|
|
9684
|
+
if (entry.resultKind === "brainConsolidationScanResult") {
|
|
9685
|
+
return apiClient.submitBrainConsolidationScanResult(entry.projectId, entry.workItemId, entry.result);
|
|
9686
|
+
}
|
|
9476
9687
|
if (entry.resultKind === "projectContextRefreshResult") {
|
|
9477
9688
|
return apiClient.submitProjectContextRefreshResult(entry.projectId, entry.workItemId, entry.result);
|
|
9478
9689
|
}
|
|
@@ -9492,6 +9703,7 @@ function durableResultResponseWorkItem(response) {
|
|
|
9492
9703
|
}
|
|
9493
9704
|
function runnerResultFinalizationLabel(entry) {
|
|
9494
9705
|
if (entry.workKind === "appEvaluationScan") return "app evaluation scan";
|
|
9706
|
+
if (entry.workKind === "brainConsolidationScan") return "brain consolidation scan";
|
|
9495
9707
|
if (entry.workKind === "securityPostureScan") return "security posture scan";
|
|
9496
9708
|
if (entry.workKind === "projectContextRefresh") return "project context refresh";
|
|
9497
9709
|
if (entry.workKind === "implementationVerification") return "implementation verification";
|
|
@@ -10157,6 +10369,101 @@ ${toolResult.stderr}`);
|
|
|
10157
10369
|
console.error(scanError ?? "Local runner app evaluation scan failed.");
|
|
10158
10370
|
return { status: "failed", exitCode: toolResult.exitCode || 1 };
|
|
10159
10371
|
}
|
|
10372
|
+
async function finalizeBrainConsolidationScanWork({
|
|
10373
|
+
apiClient,
|
|
10374
|
+
durationMs,
|
|
10375
|
+
projectId,
|
|
10376
|
+
repositoryLinkId,
|
|
10377
|
+
runnerId,
|
|
10378
|
+
sessionContext,
|
|
10379
|
+
toolConfig,
|
|
10380
|
+
toolName,
|
|
10381
|
+
toolResult,
|
|
10382
|
+
workItem
|
|
10383
|
+
}) {
|
|
10384
|
+
let scanResult = void 0;
|
|
10385
|
+
let scanError;
|
|
10386
|
+
if (toolResult.exitCode === 0) {
|
|
10387
|
+
try {
|
|
10388
|
+
scanResult = parseBrainConsolidationScanResult(`${toolResult.stdout}
|
|
10389
|
+
${toolResult.stderr}`);
|
|
10390
|
+
} catch (error) {
|
|
10391
|
+
scanError = errorMessage3(error);
|
|
10392
|
+
}
|
|
10393
|
+
} else {
|
|
10394
|
+
scanError = truncateLogExcerpt(toolResult.stderr || toolResult.stdout) || `${toolName} exited with code ${toolResult.exitCode}.`;
|
|
10395
|
+
}
|
|
10396
|
+
const finalStatus = scanResult ? "completed" : "failed";
|
|
10397
|
+
const sessionTelemetry = pendingSessionTelemetry(sessionContext);
|
|
10398
|
+
if (scanResult) {
|
|
10399
|
+
const resultMutation = {
|
|
10400
|
+
status: "completed",
|
|
10401
|
+
runnerId,
|
|
10402
|
+
idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID()}`,
|
|
10403
|
+
result: scanResult,
|
|
10404
|
+
tool: toolName,
|
|
10405
|
+
durationMs,
|
|
10406
|
+
...sessionTelemetry,
|
|
10407
|
+
message: `${toolName} returned a semantic brain consolidation scan.`
|
|
10408
|
+
};
|
|
10409
|
+
const result = await submitPrimaryRunnerResult(apiClient, {
|
|
10410
|
+
accountId: workItem.accountId,
|
|
10411
|
+
projectId,
|
|
10412
|
+
repositoryLinkId,
|
|
10413
|
+
runnerId,
|
|
10414
|
+
workItemId: workItem.workItemId,
|
|
10415
|
+
workKind: "brainConsolidationScan",
|
|
10416
|
+
resultKind: "brainConsolidationScanResult",
|
|
10417
|
+
attempt: workItem.attempt,
|
|
10418
|
+
idempotencyKey: resultMutation.idempotencyKey,
|
|
10419
|
+
result: resultMutation
|
|
10420
|
+
});
|
|
10421
|
+
if (!result) return { status: "failed", exitCode: 1 };
|
|
10422
|
+
await finalizeToolSessionBestEffort({ apiClient, projectId, runnerId, sessionContext, status: finalStatus, toolResult, workItemId: workItem.workItemId });
|
|
10423
|
+
await recordRunnerMilestone(apiClient, projectId, workItem, runnerId, repositoryLinkId, {
|
|
10424
|
+
status: "completed",
|
|
10425
|
+
summary: `${toolName} returned a semantic brain consolidation scan.`,
|
|
10426
|
+
idempotencyKey: `runner_milestone_brain_consolidation_completed_${workItem.workItemId}_${result.workItem.idempotencyKey}`,
|
|
10427
|
+
metadata: { tool: toolName, durationMs, recommendationCount: scanResult.recommendations.length, autoArchivedCount: result.autoArchivedDocuments.length, proposalCount: result.proposals.length, verificationSummary: scanResult.summary }
|
|
10428
|
+
});
|
|
10429
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig));
|
|
10430
|
+
console.log(`Brain consolidation scan returned: archived ${result.autoArchivedDocuments.length}, opened ${result.proposals.length} proposal${result.proposals.length === 1 ? "" : "s"}.`);
|
|
10431
|
+
return { status: "completed", exitCode: 0 };
|
|
10432
|
+
}
|
|
10433
|
+
const failedMutation = {
|
|
10434
|
+
status: "failed",
|
|
10435
|
+
runnerId,
|
|
10436
|
+
idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID()}`,
|
|
10437
|
+
tool: toolName,
|
|
10438
|
+
durationMs,
|
|
10439
|
+
...sessionTelemetry,
|
|
10440
|
+
message: `${toolName} did not produce a valid semantic brain consolidation scan.`,
|
|
10441
|
+
...scanError ? { error: scanError } : {}
|
|
10442
|
+
};
|
|
10443
|
+
const failedResult = await submitPrimaryRunnerResult(apiClient, {
|
|
10444
|
+
accountId: workItem.accountId,
|
|
10445
|
+
projectId,
|
|
10446
|
+
repositoryLinkId,
|
|
10447
|
+
runnerId,
|
|
10448
|
+
workItemId: workItem.workItemId,
|
|
10449
|
+
workKind: "brainConsolidationScan",
|
|
10450
|
+
resultKind: "brainConsolidationScanResult",
|
|
10451
|
+
attempt: workItem.attempt,
|
|
10452
|
+
idempotencyKey: failedMutation.idempotencyKey,
|
|
10453
|
+
result: failedMutation
|
|
10454
|
+
});
|
|
10455
|
+
if (!failedResult) return { status: "failed", exitCode: 1 };
|
|
10456
|
+
await finalizeToolSessionBestEffort({ apiClient, projectId, runnerId, sessionContext, status: finalStatus, toolResult, workItemId: workItem.workItemId });
|
|
10457
|
+
await recordRunnerMilestone(apiClient, projectId, workItem, runnerId, repositoryLinkId, {
|
|
10458
|
+
status: "failed",
|
|
10459
|
+
summary: scanError ?? `${toolName} did not produce a valid semantic brain consolidation scan.`,
|
|
10460
|
+
idempotencyKey: `runner_milestone_brain_consolidation_failed_${workItem.workItemId}_${failedResult.workItem.idempotencyKey}`,
|
|
10461
|
+
metadata: { tool: toolName, durationMs, verificationSummary: "Brain consolidation output did not include valid structured JSON." }
|
|
10462
|
+
});
|
|
10463
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig));
|
|
10464
|
+
console.error(scanError ?? "Local runner brain consolidation scan failed.");
|
|
10465
|
+
return { status: "failed", exitCode: toolResult.exitCode || 1 };
|
|
10466
|
+
}
|
|
10160
10467
|
async function finalizeProjectContextRefreshWork({
|
|
10161
10468
|
apiClient,
|
|
10162
10469
|
durationMs,
|
|
@@ -10606,6 +10913,12 @@ async function createRunnerWorkPrompt(apiClient, projectId, workItem) {
|
|
|
10606
10913
|
appEvaluationScan: { documents: documents2 }
|
|
10607
10914
|
});
|
|
10608
10915
|
}
|
|
10916
|
+
if (workItem.workKind === "brainConsolidationScan") {
|
|
10917
|
+
const { documents: documents2 } = await apiClient.listBrainDocuments(projectId);
|
|
10918
|
+
return createWorkExecutionPrompt(workItem, {
|
|
10919
|
+
brainConsolidationScan: { documents: documents2 }
|
|
10920
|
+
});
|
|
10921
|
+
}
|
|
10609
10922
|
if (workItem.workKind === "testQualityScan") {
|
|
10610
10923
|
const { documents: documents2 } = await apiClient.listBrainDocuments(projectId);
|
|
10611
10924
|
return createWorkExecutionPrompt(workItem, {
|