@tryaura/aura-cli 0.1.0 → 0.1.1

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 CHANGED
@@ -4,8 +4,9 @@ Composable CLI runtime for Aura distributions. The package exports `runCli` from
4
4
  official plugin composition from `@tryaura/aura-cli/plugins`. Installing it globally also provides
5
5
  the official `aura` command.
6
6
 
7
- The packages are prepared at `0.1.0` but are not published to npm yet. Until the first release,
8
- use the repository's `pnpm verify:packages` command to build and exercise local tarballs.
7
+ ```sh
8
+ npm install -g @tryaura/aura-cli
9
+ ```
9
10
 
10
11
  See the [distro authoring guide](https://tryaura.sh/docs/guides/distributions) for branding, plugin
11
12
  composition, distribution defaults, bundled runtime presets, compiled binaries, and testkit usage.
package/dist/bin/aura.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as OFFICIAL_REGISTRY_OPTIONS, t as OFFICIAL_PLUGINS } from "../plugins-n3DS8XXi.js";
3
- import { t as runCli } from "../run-pMPxJqFQ.js";
2
+ import { n as OFFICIAL_REGISTRY_OPTIONS, t as OFFICIAL_PLUGINS } from "../plugins-DDfc7XT9.js";
3
+ import { t as runCli } from "../run-ZDkvqvZb.js";
4
4
  //#endregion
5
5
  //#region src/bin.ts
6
6
  await runCli({
@@ -8,7 +8,7 @@ await runCli({
8
8
  command: "aura",
9
9
  description: "Agent Unification & Repair Assistant",
10
10
  displayName: "Aura",
11
- version: "0.1.0"
11
+ version: "0.1.1"
12
12
  },
13
13
  plugins: OFFICIAL_PLUGINS,
14
14
  registry: OFFICIAL_REGISTRY_OPTIONS
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as vetHttpUrl, n as clampHttpTimeout, r as failureReason, t as runCli } from "./run-pMPxJqFQ.js";
1
+ import { i as vetHttpUrl, n as clampHttpTimeout, r as failureReason, t as runCli } from "./run-ZDkvqvZb.js";
2
2
  //#region ../core/src/http-post.ts
3
3
  /**
4
4
  * Creates a bounded, TLS-only JSON POST that never rejects.
@@ -1,2 +1,2 @@
1
- import { a as codexPlugin, i as claudeCodePlugin, n as OFFICIAL_REGISTRY_OPTIONS, o as cursorPlugin, r as checksCorePlugin, s as officialContentPlugin, t as OFFICIAL_PLUGINS } from "../plugins-n3DS8XXi.js";
1
+ import { a as codexPlugin, i as claudeCodePlugin, n as OFFICIAL_REGISTRY_OPTIONS, o as cursorPlugin, r as checksCorePlugin, s as officialContentPlugin, t as OFFICIAL_PLUGINS } from "../plugins-DDfc7XT9.js";
2
2
  export { OFFICIAL_PLUGINS, OFFICIAL_REGISTRY_OPTIONS, checksCorePlugin, claudeCodePlugin, codexPlugin, cursorPlugin, officialContentPlugin };
@@ -1,4 +1,4 @@
1
- import { H as src_default$4, N as createAuraManifestWriteOperation, U as pluralize, V as SHARED_INSTRUCTIONS_TEMPLATE, _ as managedSnippetContentProblems, a as planSharedInstructionLink, b as canonicalizeManagedSnippet, c as planMcpSecretRemediation, f as planManifestMcpConvergence, i as skillDeploymentStatus, n as planSkillDeployment, o as canPlanMcpSecretRemediation, p as planMcpServerRemoval, r as sharedSkillsRoot, t as isAuraOwnedSkillTarget, u as mcpConvergenceBlockers, v as readManagedBlock, x as hashCanonicalManagedSnippet, y as AURA_MANAGED_SNIPPET_BEGIN_PREFIX } from "./skill-deployment-plan-C4GTrVSy.js";
1
+ import { G as src_default$4, I as createAuraManifestWriteOperation, K as pluralize, S as readManagedBlock, W as SHARED_INSTRUCTIONS_TEMPLATE, _ as planSharedSkillTreeUpdate, b as reconcileManagedSnippet, c as planManifestMcpConvergence, f as isAuraOwnedSkillTarget, g as managedContentRevisionStatus, h as skillDeploymentStatus, i as planMcpSecretRemediation, l as planMcpServerRemoval, m as sharedSkillsRoot, n as canPlanMcpSecretRemediation, o as mcpConvergenceBlockers, p as planSkillDeployment, t as planSharedInstructionLink, v as reconcileParsedManagedBlock, y as diffManagedSnippet } from "./shared-link-plan-BigeLxDX.js";
2
2
  import { EMPTY_COLLECTION, McpWriteError, SHARED_INSTRUCTIONS_TEMPLATE_TOKEN, TIMEOUT_EXIT_CODE, collectJsonMcpServers, collectMcpServers, configStringArray, configStringRecord, defineAdapter, defineCheck, definePlugin, detectExecutable, detectLineEnding, inspectJsonMcpSecrets, isConfigRecord, isFileReference, jsonMcpEntry, jsonMcpSecretTransform, maskMarkdownCode, mcpCommandEntry, mcpEnvironmentVariableNames, mcpWriteResult, normalizeMcpServerDefinition, parseAtImports, parseConfigObject, parseInstalledSkills, parseJsonMcpConfig, redactMcpArguments, referenceTargetPath, sanitizeMcpUrl, skillDirectorySpecs, splitSourceLines, stdioTransport, writeJsonMcpServers } from "@tryaura/aura-sdk";
3
3
  import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { parse, stringify } from "smol-toml";
@@ -6,7 +6,6 @@ import { Buffer } from "node:buffer";
6
6
  import { parseTOML } from "toml-eslint-parser";
7
7
  import ignore from "ignore";
8
8
  import { createHash } from "node:crypto";
9
- import { createTwoFilesPatch } from "diff";
10
9
  import { isDeepStrictEqual } from "node:util";
11
10
  //#region ../../plugins/adapter-claude-code/src/contract.ts
12
11
  /**
@@ -4015,59 +4014,6 @@ function findingForProjectSignals(document, report, model) {
4015
4014
  };
4016
4015
  }
4017
4016
  //#endregion
4018
- //#region ../core/src/managed-block/reconcile-snippet.ts
4019
- /** Reconciles exactly one snippet while preserving every other source byte. */
4020
- function reconcileManagedSnippet(source, snippetId, resolution) {
4021
- const current = readManagedBlock(source);
4022
- if (current.status === "invalid") return invalidResult(source, current.notes, current.problems);
4023
- if (current.status === "absent") return missingSnippet(source, current.notes, snippetId, "an Aura-managed block");
4024
- const snippet = current.block.snippets.find((candidate) => candidate.id === snippetId);
4025
- if (snippet === void 0) return missingSnippet(source, current.notes, snippetId, "the Aura-managed block");
4026
- const lineEnding = markerLineEnding(source, snippet.startOffset, snippet.contentStartOffset);
4027
- const canonical = resolution.kind === "restore" ? canonicalizeManagedSnippet(resolution.content) : void 0;
4028
- if (canonical !== void 0) {
4029
- const problems = managedSnippetContentProblems(snippet.id, canonical);
4030
- if (problems.length > 0) return invalidResult(source, current.notes, problems);
4031
- }
4032
- const content = canonical === void 0 ? snippet.content : withLineEnding(canonical, lineEnding);
4033
- const hash = canonical === void 0 ? snippet.computedHash : hashCanonicalManagedSnippet(canonical);
4034
- const opening = `${AURA_MANAGED_SNIPPET_BEGIN_PREFIX}${snippet.id} sha256=${hash} -->${lineEnding}`;
4035
- const updated = source.slice(0, snippet.startOffset) + opening + content + source.slice(snippet.contentEndOffset);
4036
- return updated === source ? Object.freeze({
4037
- content: source,
4038
- notes: current.notes,
4039
- status: "unchanged"
4040
- }) : Object.freeze({
4041
- content: updated,
4042
- notes: current.notes,
4043
- status: "updated"
4044
- });
4045
- }
4046
- /** Creates the opt-in edited-versus-canonical detail used by the merge choice. */
4047
- function diffManagedSnippet(path, editedContent, canonicalContent) {
4048
- return createTwoFilesPatch(`${path} (edited)`, `${path} (canonical)`, canonicalizeManagedSnippet(editedContent), canonicalizeManagedSnippet(canonicalContent), "edited", "canonical", { context: 3 });
4049
- }
4050
- function missingSnippet(source, notes, snippetId, location) {
4051
- return invalidResult(source, notes, [Object.freeze({
4052
- code: "missing-snippet",
4053
- message: `Snippet "${snippetId}" does not exist in ${location}.`
4054
- })]);
4055
- }
4056
- function invalidResult(source, notes, problems) {
4057
- return Object.freeze({
4058
- content: source,
4059
- notes,
4060
- problems,
4061
- status: "invalid"
4062
- });
4063
- }
4064
- function markerLineEnding(source, startOffset, contentStartOffset) {
4065
- return source.slice(startOffset, contentStartOffset).endsWith("\r\n") ? "\r\n" : "\n";
4066
- }
4067
- function withLineEnding(content, lineEnding) {
4068
- return lineEnding === "\n" ? content : content.replaceAll("\n", lineEnding);
4069
- }
4070
- //#endregion
4071
4017
  //#region ../../plugins/checks-core/src/instructions.ts
4072
4018
  const READY = "Aura can add the missing link with check --fix.";
4073
4019
  const sharedInstructionsCheck = defineCheck({
@@ -4323,9 +4269,9 @@ function isSymlinkDocument(document, model) {
4323
4269
  }
4324
4270
  //#endregion
4325
4271
  //#region ../../plugins/checks-core/src/mgd-001-fixes.ts
4326
- const CHECK_ID$3 = "MGD-001";
4272
+ const CHECK_ID$5 = "MGD-001";
4327
4273
  function guidedFixes$2(finding, model) {
4328
- if (finding.checkId !== CHECK_ID$3) return [];
4274
+ if (finding.checkId !== CHECK_ID$5) return [];
4329
4275
  const kind = finding.metadata?.["kind"];
4330
4276
  if (kind === "malformed") return [malformedMergeChoice(finding)];
4331
4277
  if (kind === "unterminated-fence") return [unterminatedFenceChoice(finding)];
@@ -4576,6 +4522,297 @@ function manifestSnippetHashes(model) {
4576
4522
  return hashes;
4577
4523
  }
4578
4524
  //#endregion
4525
+ //#region ../../plugins/checks-core/src/mgd-002-fixes.ts
4526
+ function managedContentUpdateChoices(finding, model) {
4527
+ if (finding.checkId !== "MGD-002") return [];
4528
+ const kind = finding.metadata?.["kind"];
4529
+ if (kind === "snippet-update" || kind === "snippet-diverged") return snippetUpdateChoices(finding, model);
4530
+ if (kind === "snippet-missing") return missingSnippetChoices(finding, model);
4531
+ return kind === "skill-update" || kind === "skill-diverged" ? skillUpdateChoices(finding, model) : [];
4532
+ }
4533
+ /**
4534
+ * How a choice names the revision it would apply.
4535
+ *
4536
+ * A diverged revision is a deliberate move to content that is not newer, so calling it an update
4537
+ * would misdescribe what the user is accepting.
4538
+ */
4539
+ function applyLabel(finding, version) {
4540
+ return `${finding.metadata?.["kind"] === "snippet-update" || finding.metadata?.["kind"] === "skill-update" ? "Update to" : "Switch to"} ${version}`;
4541
+ }
4542
+ function snippetUpdateChoices(finding, model) {
4543
+ const context = readyFindingContext(finding, model);
4544
+ if (context === void 0) return [];
4545
+ const { contentId, manifest: manifestState } = context;
4546
+ const installed = manifestState.value.snippets.find((snippet) => snippet.id === contentId);
4547
+ const available = model.availableSnippets.find((snippet) => snippet.id === contentId);
4548
+ const located = locateManagedSnippet(model, contentId);
4549
+ if (installed === void 0 || available === void 0 || located === void 0) return [];
4550
+ if (!located.snippet.hashMatches || located.snippet.computedHash !== installed.hash) return [resolveDriftFirst(contentId)];
4551
+ const reconciled = reconcileManagedSnippet(located.document.content, contentId, {
4552
+ content: available.content,
4553
+ kind: "restore"
4554
+ });
4555
+ if (reconciled.status === "invalid") return [resolveDriftFirst(contentId)];
4556
+ const manifest = {
4557
+ ...manifestState.value,
4558
+ snippets: manifestState.value.snippets.map((snippet) => snippet === installed ? {
4559
+ ...snippet,
4560
+ hash: available.hash,
4561
+ pinned: false,
4562
+ version: available.version
4563
+ } : snippet)
4564
+ };
4565
+ return [{
4566
+ details: () => diffManagedSnippet(located.document.path, located.snippet.content, available.content),
4567
+ id: "update",
4568
+ label: applyLabel(finding, available.version),
4569
+ plan: {
4570
+ operations: [{
4571
+ content: reconciled.content,
4572
+ path: located.document.path,
4573
+ type: "write"
4574
+ }, createAuraManifestWriteOperation(manifestState, manifest)],
4575
+ summary: `Set managed snippet ${contentId} to ${available.version}.`
4576
+ }
4577
+ }];
4578
+ }
4579
+ function missingSnippetChoices(finding, model) {
4580
+ const context = readyFindingContext(finding, model);
4581
+ if (context === void 0) return [];
4582
+ const { contentId, manifest } = context;
4583
+ const installed = manifest.value.snippets.find((snippet) => snippet.id === contentId);
4584
+ if (installed === void 0) return [];
4585
+ const pinnedManifest = {
4586
+ ...manifest.value,
4587
+ snippets: manifest.value.snippets.map((snippet) => snippet === installed ? {
4588
+ ...snippet,
4589
+ pinned: true
4590
+ } : snippet)
4591
+ };
4592
+ const choices = [{
4593
+ id: "pin",
4594
+ label: "Keep as pinned",
4595
+ plan: {
4596
+ operations: [createAuraManifestWriteOperation(manifest, pinnedManifest)],
4597
+ summary: `Keep unavailable snippet ${contentId} at its installed revision.`
4598
+ }
4599
+ }];
4600
+ const removal = removeSnippetPlan(model, contentId, installed);
4601
+ if (removal !== void 0) choices.push({
4602
+ id: "remove",
4603
+ label: "Remove",
4604
+ plan: removal
4605
+ });
4606
+ return choices;
4607
+ }
4608
+ function removeSnippetPlan(model, contentId, installed) {
4609
+ if (model.manifest.status !== "ready") return;
4610
+ const located = locateManagedSnippet(model, contentId);
4611
+ if (located === void 0) return;
4612
+ const preserve = located.document.parsed.status === "present" ? located.document.parsed.block.snippets.map((snippet) => snippet.id).filter((id) => id !== contentId) : [];
4613
+ const reconciled = reconcileParsedManagedBlock(located.document.content, located.document.parsed, [], {
4614
+ ownedSnippetIds: model.manifest.value.snippets.map((snippet) => snippet.id),
4615
+ preserveSnippetIds: preserve,
4616
+ previousSnippetHashes: new Map(model.manifest.value.snippets.map((snippet) => [snippet.id, snippet.hash]))
4617
+ });
4618
+ if (reconciled.status === "invalid") return;
4619
+ const manifest = {
4620
+ ...model.manifest.value,
4621
+ snippets: model.manifest.value.snippets.filter((snippet) => snippet !== installed)
4622
+ };
4623
+ return {
4624
+ operations: [{
4625
+ content: reconciled.content,
4626
+ path: located.document.path,
4627
+ type: "write"
4628
+ }, createAuraManifestWriteOperation(model.manifest, manifest)],
4629
+ summary: `Remove unavailable managed snippet ${contentId}.`
4630
+ };
4631
+ }
4632
+ function skillUpdateChoices(finding, model) {
4633
+ const context = readyFindingContext(finding, model);
4634
+ const sourceId = finding.metadata?.["sourceId"];
4635
+ if (context === void 0 || typeof sourceId !== "string") return [];
4636
+ const { contentId, manifest: manifestState } = context;
4637
+ const installed = manifestState.value.skills.find((skill) => skill.id === contentId && skill.source === sourceId);
4638
+ const available = model.availableSkills?.find((skill) => skill.id === contentId && skill.source.id === sourceId);
4639
+ const shared = model.sharedSkills?.find((skill) => skill.id === contentId);
4640
+ if (installed === void 0 || available === void 0 || shared === void 0) return [];
4641
+ if (shared.problem !== void 0 || shared.treeHash !== installed.treeHash) return [resolveSkillDriftFirst(contentId)];
4642
+ const manifest = {
4643
+ ...manifestState.value,
4644
+ skills: manifestState.value.skills.map((skill) => skill === installed ? updatedSkill(skill, available) : skill)
4645
+ };
4646
+ return [{
4647
+ id: "update",
4648
+ label: applyLabel(finding, available.version),
4649
+ plan: {
4650
+ operations: [...planSharedSkillTreeUpdate(shared.path, shared.entries, available), createAuraManifestWriteOperation(manifestState, manifest)],
4651
+ summary: `Set managed skill ${contentId} to ${available.version}.`
4652
+ }
4653
+ }];
4654
+ }
4655
+ function readyFindingContext(finding, model) {
4656
+ const contentId = finding.metadata?.["contentId"];
4657
+ return typeof contentId === "string" && model.manifest.status === "ready" ? {
4658
+ contentId,
4659
+ manifest: model.manifest
4660
+ } : void 0;
4661
+ }
4662
+ function updatedSkill(installed, available) {
4663
+ return {
4664
+ ...installed,
4665
+ pinned: false,
4666
+ treeHash: available.treeHash,
4667
+ version: available.version
4668
+ };
4669
+ }
4670
+ function locateManagedSnippet(model, contentId) {
4671
+ for (const document of managedDocuments(model)) {
4672
+ if (document.parsed.status !== "present") continue;
4673
+ const snippet = document.parsed.block.snippets.find((candidate) => candidate.id === contentId);
4674
+ if (snippet !== void 0) return {
4675
+ document,
4676
+ snippet
4677
+ };
4678
+ }
4679
+ }
4680
+ function resolveDriftFirst(contentId) {
4681
+ return {
4682
+ id: "resolve-drift",
4683
+ label: "Resolve local edits first",
4684
+ plan: {
4685
+ manualSteps: [`Run \`aura check --only MGD-001 --fix --interactive\` and resolve edits to ${contentId}, then review this update again.`],
4686
+ operations: [],
4687
+ summary: `Resolve local edits to ${contentId} before updating it.`
4688
+ }
4689
+ };
4690
+ }
4691
+ function resolveSkillDriftFirst(contentId) {
4692
+ return {
4693
+ id: "resolve-drift",
4694
+ label: "Review local edits first",
4695
+ plan: {
4696
+ manualSteps: [`Review the locally changed shared skill ${contentId}; pin or reconcile it before applying the source update.`],
4697
+ operations: [],
4698
+ summary: `Review local edits to skill ${contentId} before updating it.`
4699
+ }
4700
+ };
4701
+ }
4702
+ const managedContentUpdateCheck = defineCheck({
4703
+ defaultSeverity: "info",
4704
+ detect: detectManagedContentUpdates,
4705
+ explain: "Aura records the exact version and content hash of each managed snippet and skill. When an installed plugin offers a different revision, Aura reports it and waits for a reviewed change instead of silently replacing managed content. A revision that is not newer — a rollback, or one this build cannot order — is reported too, because Aura keeps the recorded revision either way and an unreported hold would look like nothing to do. Pinned selections remain quiet until they are unpinned.\n\nRun `aura check --fix --interactive` to review bundled revisions and vanished snippets. Locally edited content must be resolved first; directory-sourced skill updates stay in `aura setup`, where network and credential approval are explicit.",
4706
+ fix: () => void 0,
4707
+ fixability: "guided",
4708
+ guidedFixes: managedContentUpdateChoices,
4709
+ id: "MGD-002",
4710
+ scope: "global",
4711
+ title: "Managed snippets and skills are at their reviewed source revisions"
4712
+ });
4713
+ function detectManagedContentUpdates(model) {
4714
+ if (model.manifest.status !== "ready") return [];
4715
+ return [...model.manifest.value.snippets.flatMap((snippet) => snippetFinding(snippet, model)), ...model.manifest.value.skills.flatMap((skill) => skillFinding(skill, model))];
4716
+ }
4717
+ function snippetFinding(installed, model) {
4718
+ if (installed.pinned) return [];
4719
+ const available = model.availableSnippets.find((snippet) => snippet.id === installed.id);
4720
+ if (available === void 0) return [{
4721
+ id: `snippet:${installed.id}:missing`,
4722
+ message: `Managed snippet ${installed.id} at version ${installed.version} is no longer provided by an installed plugin.`,
4723
+ metadata: {
4724
+ contentId: installed.id,
4725
+ kind: "snippet-missing"
4726
+ }
4727
+ }];
4728
+ const status = managedContentRevisionStatus(installed.version, installed.hash, available.version, available.hash);
4729
+ if (status === "current") return [];
4730
+ if (status === "diverged") return [{
4731
+ details: "Aura keeps the recorded revision because the offered one is not newer. Re-run `aura setup` interactively to switch to it deliberately, or pin this snippet to stop the comparison.",
4732
+ id: `snippet:${installed.id}:diverged`,
4733
+ message: `Managed snippet ${installed.id} is recorded at version ${installed.version}, but the installed plugin offers ${available.version}, which is not newer.`,
4734
+ metadata: {
4735
+ availableVersion: available.version,
4736
+ contentId: installed.id,
4737
+ installedVersion: installed.version,
4738
+ kind: "snippet-diverged"
4739
+ }
4740
+ }];
4741
+ return [{
4742
+ id: `snippet:${installed.id}:update`,
4743
+ message: `Managed snippet ${installed.id} can update from version ${installed.version} to ${available.version}.`,
4744
+ metadata: {
4745
+ availableVersion: available.version,
4746
+ contentId: installed.id,
4747
+ installedVersion: installed.version,
4748
+ kind: "snippet-update"
4749
+ }
4750
+ }];
4751
+ }
4752
+ function skillFinding(installed, model) {
4753
+ if (installed.pinned || !installed.source.startsWith("plugin:")) return [];
4754
+ const available = model.availableSkills?.find((skill) => skill.id === installed.id && skill.source.id === installed.source);
4755
+ if (available === void 0) return [];
4756
+ const status = managedContentRevisionStatus(installed.version, installed.treeHash, available.version, available.treeHash);
4757
+ if (status === "current") return [];
4758
+ const location = { path: join(sharedSkillsRoot(model.homeDir), installed.id) };
4759
+ if (status === "diverged") return [{
4760
+ details: "Aura keeps the recorded revision because the offered one is not newer. Re-run `aura setup` interactively to switch to it deliberately, or pin this skill to stop the comparison.",
4761
+ id: `skill:${installed.source}:${installed.id}:diverged`,
4762
+ locations: [location],
4763
+ message: `Managed skill ${installed.id} is recorded at version ${installed.version}, but the installed plugin offers ${available.version}, which is not newer.`,
4764
+ metadata: {
4765
+ availableVersion: available.version,
4766
+ contentId: installed.id,
4767
+ installedVersion: installed.version,
4768
+ kind: "skill-diverged",
4769
+ sourceId: installed.source
4770
+ }
4771
+ }];
4772
+ return [{
4773
+ id: `skill:${installed.source}:${installed.id}:update`,
4774
+ locations: [location],
4775
+ message: `Managed skill ${installed.id} can update from version ${installed.version} to ${available.version}.`,
4776
+ metadata: {
4777
+ availableVersion: available.version,
4778
+ contentId: installed.id,
4779
+ installedVersion: installed.version,
4780
+ kind: "skill-update",
4781
+ sourceId: installed.source
4782
+ }
4783
+ }];
4784
+ }
4785
+ /**
4786
+ * Deliberately manual: the only resolution is a full `setup` run.
4787
+ *
4788
+ * Recording the decision means asking the apps picker, and this check must never start a nested
4789
+ * command. Declaring it fixable would open an interactive fix on a single choice that changes
4790
+ * nothing — a prompt whose only answer leaves the finding exactly where it was — so the next step
4791
+ * is carried on the finding itself instead.
4792
+ */
4793
+ const unmanagedDetectedAppCheck = defineCheck({
4794
+ defaultSeverity: "info",
4795
+ detect: detectUnmanagedApps,
4796
+ explain: "Aura can inspect an installed agent application without managing it. This informational check highlights detected applications that have never been accepted or ignored in the Aura manifest.\n\nRun `aura setup` to add the application, or leave it unchecked once to record that Aura should ignore it. There is no automatic fix: the decision belongs to the apps step, and this check never starts a nested command.",
4797
+ fixability: "manual",
4798
+ id: "MGD-003",
4799
+ scope: "global",
4800
+ title: "Detected applications have an explicit Aura management decision"
4801
+ });
4802
+ function detectUnmanagedApps(model) {
4803
+ const apps = model.manifest.status === "ready" ? model.manifest.value.apps : {};
4804
+ const ignored = new Set(model.manifest.status === "ready" ? model.manifest.value.ignoredApps ?? [] : []);
4805
+ return model.apps.flatMap((app) => {
4806
+ if (app.synthetic === true || Object.hasOwn(apps, app.adapterId) || ignored.has(app.adapterId)) return [];
4807
+ return [{
4808
+ details: `Run \`aura setup\` and select ${app.displayName} to manage it, or leave it unchecked to record an ignored-app decision.`,
4809
+ id: app.adapterId,
4810
+ message: `${app.displayName} detected but not managed — run \`aura setup\` to add it.`,
4811
+ metadata: { appId: app.adapterId }
4812
+ }];
4813
+ });
4814
+ }
4815
+ //#endregion
4579
4816
  //#region ../../plugins/checks-core/src/mcp-common.ts
4580
4817
  /**
4581
4818
  * The servers the manifest selects for applications this scan can actually converge.
@@ -4681,7 +4918,17 @@ function detectParity(model) {
4681
4918
  if (model.manifest.status !== "ready") return [];
4682
4919
  const desired = desiredMcpTargets(model);
4683
4920
  const desiredByApp = /* @__PURE__ */ new Map();
4684
- const findings = [];
4921
+ const findings = (model.overriddenRequiredMcpServers ?? []).map((override) => ({
4922
+ details: "The omission was explicitly confirmed during setup and remains recorded in the Aura manifest. Run `aura setup` to add the server or keep the documented deviation.",
4923
+ id: `override:${override.catalogId}`,
4924
+ message: `MCP server ${override.catalogId} required by ${override.requiredBy} is explicitly omitted; this machine deviates from the team preset.`,
4925
+ metadata: {
4926
+ catalogId: override.catalogId,
4927
+ kind: "preset-override",
4928
+ requiredBy: override.requiredBy
4929
+ },
4930
+ severity: "info"
4931
+ }));
4685
4932
  const affected = /* @__PURE__ */ new Set();
4686
4933
  for (const target of desired) {
4687
4934
  const names = desiredByApp.get(target.appId) ?? /* @__PURE__ */ new Set();
@@ -5652,6 +5899,8 @@ const checksCorePlugin = definePlugin({
5652
5899
  instructionContextBudgetCheck,
5653
5900
  instructionPrecedenceCheck,
5654
5901
  managedBlockHashCheck,
5902
+ managedContentUpdateCheck,
5903
+ unmanagedDetectedAppCheck,
5655
5904
  mcp001,
5656
5905
  mcp002,
5657
5906
  mcp003,