agentera 3.0.0-dev.76 → 3.0.0-dev.77
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 +23 -0
- package/bundle/.agentera-build-source.json +5 -5
- package/bundle/CHANGELOG.md +10 -1
- package/bundle/UPGRADE.md +24 -5
- package/bundle/references/adapters/package-publication.json +4 -4
- package/bundle/references/adapters/package-registry.yaml +153 -151
- package/bundle/references/adapters/product-v1-reset.yaml +101 -0
- package/bundle/references/artifacts/glossary-entry-contract.yaml +163 -9
- package/bundle/references/artifacts/state-storage-authority.yaml +0 -5
- package/bundle/references/cli/update-channels.yaml +1 -1
- package/bundle/references/cli/vocabulary-index.yaml +2 -2
- package/bundle/references/cli/vocabulary.md +2 -3
- package/bundle/references/meta/retained-reference-authority.yaml +5 -0
- package/bundle/skills/agentera/schemas/artifacts/decisions.yaml +1 -20
- package/bundle/skills/agentera/schemas/artifacts/docs.yaml +0 -31
- package/bundle/skills/agentera/schemas/artifacts/experiments.yaml +0 -25
- package/bundle/skills/agentera/schemas/artifacts/glossary.yaml +1 -1
- package/bundle/skills/agentera/schemas/artifacts/health.yaml +1 -36
- package/bundle/skills/agentera/schemas/artifacts/objective.yaml +0 -31
- package/bundle/skills/agentera/schemas/artifacts/plan.yaml +1 -35
- package/bundle/skills/agentera/schemas/artifacts/progress.yaml +1 -25
- package/bundle/skills/agentera/schemas/artifacts/vision.yaml +0 -19
- package/dist/.agentera-build-source.json +5 -5
- package/dist/analytics/personalGlossaryAdmission.js +1 -1
- package/dist/analytics/personalGlossaryCandidateProjection.js +96 -0
- package/dist/analytics/personalGlossaryCandidateProjectionModel.js +1 -0
- package/dist/analytics/personalGlossaryRefreshProjection.js +351 -0
- package/dist/capabilities/status/instructions.js +1 -1
- package/dist/cli/commands/personalGlossaryCandidateReads.js +12 -1
- package/dist/cli/commands/prime/briefOrientation.js +1 -1
- package/dist/cli/commands/prime/collectOrientationState.js +0 -7
- package/dist/cli/commands/prime/orientationOutput.js +3 -9
- package/dist/cli/commands/report.js +98 -8
- package/dist/cli/commands/upgrade.js +30 -0
- package/dist/cli/dispatch/index.js +7 -0
- package/dist/cli/dispatch/lifecycle.js +20 -0
- package/dist/cli/help.js +10 -3
- package/dist/cli/orientation/attention.js +1 -4
- package/dist/cli/productV1Eol.js +55 -0
- package/dist/cli/startupCompletenessContract.js +0 -1
- package/dist/cli/stateQuery.js +1 -1
- package/dist/registries/activationTuples.js +11 -2
- package/dist/registries/glossaryCandidateProjectionAuthority.js +154 -6
- package/dist/registries/glossaryCandidateProjectionContract.js +4 -0
- package/dist/registries/glossaryEntryContract.js +3 -3
- package/dist/registries/packagePublication.js +2 -2
- package/dist/runtime/nativeResourceCleanup.js +1 -0
- package/dist/upgrade/legacyAgentCleanup.js +1 -1
- package/dist/upgrade/migrateArtifactsV2ToV3.js +1 -27
- package/dist/upgrade/nextMajorDoctor.js +0 -21
- package/dist/upgrade/productV1Reset.js +515 -0
- package/dist/upgrade/productV1ResetAuthority.js +139 -0
- package/dist/upgrade/projectIntegration.js +4 -6
- package/dist/upgrade/upgradeOrchestrator.js +4 -12
- package/dist/validate/{v1LegacyCruft.js → glossaryVariantGuard.js} +3 -38
- package/package.json +2 -2
- package/dist/cli/commands/prime/v1Migration.js +0 -38
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Capability instructions for status (canonical per D57; D65 relocated from .md to .ts)
|
|
2
2
|
// Served via `agentera prime --context status --format json`. RFC 2119 modal vocab per D71.
|
|
3
|
-
export const instructions = JSON.parse(String.raw `"# STATUS\n\n**Holistic Entry Junction. Orient, Route, Activate**\n\nSingle entry point to the agentera suite. Detects fresh vs returning, delivers a situational briefing, routes to the right capability. Same path on first install and the 100th session.\n\nGlyph: **⌂** (SG1). Status reads suite state through \u0060agentera prime\u0060 and writes nothing. A bare user message of exactly \u0060/agentera\u0060 invokes this capability; it does not fall back to conversational smalltalk.\n\nStatus MUST source both instructions and bounded state from \u0060agentera prime --context status --format json\u0060 and write nothing. Read \u0060capability_context.instructions\u0060 in full, render from \u0060capability_context.context.status_context\u0060, and use the one \u0060capability_context.startup\u0060 aggregation. Its outcome is \u0060ok\u0060, \u0060degraded\u0060, or \u0060blocked\u0060; \u0060status_context.outcome\u0060 is the same value. For deferred detail, run only that availability row\u0027s exact \u0060detail_command\u0060. An \u0060ok\u0060 startup needs no second prime call. Status MUST NOT raw-read \u0060.agentera/*.yaml\u0060.\n\n---\n\n## Dashboard rendering\n\nStatus owns the prime dashboard contract. SKILL.md and other surfaces delegate here.\n\n\u0060\u0060\u0060text\n┌─┐┌─┐┌─┐┌┐┌┌─┐┌─┐┬─┐┌─┐\n├─┤│ ┬├┤ │││ │ ├┤ ├┬┘├─┤\n┴ ┴└─┘└─┘┘└┘ ┴ └─┘┴└─┴ ┴\n\n─── status ─────────────────────────────\n\n ⛶ health [⮉|⮋] [grade] ([worst dimension: grade])\n ⇶ todo N critical · M degraded · J annoying\n ≡ plan [██████▓░░░] N/M tasks\n ⎘ optim [metric] [current] → [target]\n ♾ profile [loaded | not found]\n\n [1-2 sentence narrative read: what shipped, what's moving, what needs eyes.\n Interpretation, not metrics. Closes the status section before attention.]\n\n─── attention ──────────────────────────\n\n ⇶ [critical items, triple arrow for critical]\n ⇉ [degraded items, double arrow for degraded]\n → [normal items, single arrow for normal]\n ⇢ [annoying items, dashed arrow for annoying]\n\n─── next ───────────────────────────────\n\n suggested → [glyph] [capability] ([reason])\n\u0060\u0060\u0060\n\nBuild the dashboard from \u0060agentera prime --format json\u0060 output. Source labels such as \u0060mode:\u0060, \u0060profile:\u0060, \u0060v1_migration:\u0060, \u0060health:\u0060, \u0060todo:\u0060, \u0060plan:\u0060, \u0060objective:\u0060, \u0060attention:\u0060, \u0060next_action:\u0060, and the \u0060app.status\u0060 installed-app status object are parsing aids, not dashboard lines. Do not relay raw CLI lines as the user-facing briefing.\n\n**Output constraint**: ≤120 words total briefing, ≤15 words per routing suggestion.\n\n**Exit marker**: after the closing code fence of the dashboard, emit \u0060⌂ status · <status>\u0060 on its own line, followed by a one-sentence summary of what you delivered. For \u0060waiting\u0060, \u0060flagged\u0060, or \u0060stuck\u0060, add a \u0060▸\u0060 bullet below the summary identifying what the user needs to decide or act on next. The exit marker MUST appear on every invocation regardless of mode (fresh welcome or returning briefing).\n\n**Formatting rules**:\n- Each status line uses the skill glyph that owns that data\n- Severity arrows (VT5-VT8) mark attention items by urgency\n- Trend arrows (VT12/VT13) show health trajectory; derive ⮉/⮋ from \u0060health.degrading\u0060 (false→⮉, true→⮋); omit when no audit history\n- Progress bars (VT18) show plan completion visually\n- The inline separator (VT16) joins counts on a single line\n- Lead with status metrics, then the narrative read inside the status section\n- The narrative read is colleague interpretation; metric lines above it are evidence\n- The todo summary line lists critical, degraded, and annoying counts only; normal-priority items belong in attention with → (SI3), not on the summary line\n- Omit any line whose source artifact is missing\n- Omit any section that would be empty (e.g., no attention items = no attention section)\n\nVisual token IDs live in \u0060skills/agentera/protocol.yaml\u0060; see VT, SI, EX, SG, PH families.\n\n---\n\n## Briefing\n\nUse the \u0060mode\u0060 field from \u0060agentera prime\u0060 to detect fresh vs returning:\n\n- **Fresh** (\u0060mode: fresh\u0060): render welcome language; lead with the suggested capability from \u0060next_action\u0060. Do not enumerate the full suite unless asked.\n- **Returning** (\u0060mode: returning\u0060): render the dashboard template above using \u0060mode\u0060, \u0060profile\u0060, \u0060health\u0060, \u0060todo\u0060, \u0060plan\u0060, \u0060objective\u0060, \u0060attention\u0060, and \u0060next_action\u0060 fields.\n\nNarration voice: warm, brief, unscripted.\n\n### Project integration rendering\n\nWhen \u0060project_integration.recommendation\u0060 is \u0060upgrade\u0060:\n1. Render the plain-language \u0060project_integration.message\u0060.\n2. Show \u0060project_integration.dry_run_command\u0060 preview; state that it changes nothing.\n3. Ask before running \u0060project_integration.apply_command\u0060.\n\nWhen \u0060recommendation\u0060 is \u0060stay\u0060, do not suggest upgrade.\n\n### App status rendering\n\nRender \u0060app.status\u0060 as a status line only when it is not \u0060up_to_date\u0060. Use the plain-language \u0060project_integration.message\u0060 if present. Status MUST NOT teach install-recovery procedure — that belongs to the upgrade capability and \u0060agentera doctor\u0060.\n\n### Profile rendering\n\nRender \u0060profile.status\u0060 (\u0060loaded\u0060 or \u0060not found\u0060). Render \u0060profile.suggested_action\u0060 or a missing-profile attention item only when prime supplies one.\n\n### Attention items\n\nPriority order with severity arrows (SI1-SI4):\n\n- ⇶ (SI1) Critical issues, degrading health dimensions\n- ⇉ (SI2) Blocked/overdue plan tasks, stale artifacts, overdue health audits (prime \u0060health.stale=true\u0060), loop stop-condition triggers\n- → (SI3) Standard work: features, improvements, routine tasks\n- ⇢ (SI4) Unresolved exploratory decisions\n\nA clean bill of health is useful — say so when nothing is flagged.\n\n---\n\n## Routing suggestion\n\nThe routing suggestion MUST name the artifact item it would act on. A skill name without a concrete object is not a valid suggestion.\n\nValid objects: \u0060PLAN Task N: <title>\u0060, \u0060TODO: <item>\u0060, \u0060DECISION N follow-up\u0060, \u0060OBJECTIVE: <metric>\u0060, or \u0060VISION refresh\u0060.\n\n**Priority order** (SG codes are internal protocol references; never render them in user-facing handoff labels):\n\n- Active PLAN with pending tasks → suggest ⎈ orchestrate for the first unblocked pending task.\n- Critical or degrading health → suggest ⛶ audit or ⧉ build for the named finding.\n- Stale health audit (CLI \u0060health.stale=true\u0060) with no higher-priority work → suggest ⛶ audit for \u0060HEALTH: Audit N stale\u0060.\n- Active non-closed OBJECTIVE with stalled or missing metric evidence → suggest ⎘ optimize for that metric.\n- todo open items → select the highest-severity open item, then route by shape: narrow one-cycle todo items suggest ⧉ build; contract-shaped, multi-surface, dependency-heavy, migration, schema, metadata, validation, or acceptance-risky todo items suggest ≡ plan first. Prefer items that unlock product evidence or future plans.\n- Pending decisions follow-up → suggest ❈ discuss for the named unresolved decision.\n- Vision exists but no plan, objective, decision follow-up, or TODO work is active → suggest ≡ plan.\n- No vision, no executable follow-ups, and no active plan → suggest ⛥ vision to choose a direction.\n\nDo not let \u0060healthy + plan complete → ⛥\u0060 override active TODO, OBJECTIVE, DECISIONS, or a newer active PLAN. A completed plan means \"look for the next executable follow-up,\" not automatically \"refresh vision.\"\n\n### Routing posture\n\n- Present one concrete suggestion and let the user choose. Coercion MUST NOT occur.\n- Do not list generic skill options unless the user asks for the full menu.\n- The waiting bullet should ask whether to run the named action, not ask the user to pick from skills.\n- On the initial status brief, use a free-form continuation prompt rather than a native question menu unless the user asked for bounded choices or the suggested next step is a state-changing Proceed/Cancel handoff.\n- Mid-conversation, use the native question tool only for at least two meaningful non-terminal next actions or a consequential Proceed/Cancel decision; \u0060Done\u0060 and free-form/custom answer affordances do not count as alternatives.\n- State-changing handoffs are consequential Proceed/Cancel decisions even when there is only one suggested action. State-changing means the proposed next step may write artifacts, edit code, run optimization or orchestration cycles, apply migrations, refresh app/runtime state, or otherwise mutate project/runtime state.\n- Use the behavior rule first, with common examples such as ⧉ build, ≡ plan when creating or updating plans, ▤ document when writing docs, ⎘ optimize when running or applying optimization cycles, and ⎈ orchestrate when dispatching cycles.\n- For one non-mutating suggested action, clear free-form acceptance such as \u0060yes\u0060, \u0060start\u0060, \u0060do it\u0060, or \u0060run <capability>\u0060 confirms that suggestion. Ambiguous replies get one clarifying question.\n\nUnclear mapping? Ask **one** clarifying question. Compound questions MUST NOT occur.\n\n---\n\n## Safety rails\n\n<critical>\n- NEVER execute implementation work. Status orients and routes; it MUST NOT build, audit, plan, or decide.\n- NEVER dump full artifact contents verbatim. Summarize concisely; the user can read the files themselves.\n- NEVER skip the briefing in returning mode. The user needs context before choosing a direction.\n- NEVER assume what the user wants without asking. Present the suggestion, then wait for confirmation.\n- NEVER modify any state artifact. Status is strictly read-only.\n- NEVER route to a capability without the user's consent. Suggest, don't force.\n</critical>\n\n---\n\n## Exit signals\n\nReport one of these statuses at workflow completion (protocol refs: EX1-EX4).\n\nFormat: emit \u0060⌂ status · <status>\u0060 on its own line below the dashboard's closing code fence, followed by a one-sentence summary of what was delivered. For \u0060flagged\u0060 (EX2), \u0060stuck\u0060 (EX3), and \u0060waiting\u0060 (EX4), add a \u0060▸\u0060 (VT15) bullet below the summary identifying what the user needs to decide or act on next. The exit marker MUST appear on every invocation regardless of mode and uses status's canonical glyph \u0060⌂\u0060 (SG1, U+2302).\n\n- **complete** (EX1): Briefing delivered (or welcome shown in fresh mode) and user successfully routed to a capability.\n- **flagged** (EX2): Briefing delivered but critical attention items were found: critical issues, degrading health, loop stop-condition triggers. Each concern MUST be listed explicitly.\n- **stuck** (EX3): Cannot orient: the working directory is not a code project, no readable files exist, or permissions prevent scanning.\n- **waiting** (EX4): Briefing or welcome delivered, suggestion made, awaiting user input on which direction to take.\n\n---\n\n## Cross-capability integration\n\nStatus is the suite entry point. It reads other capabilities' artifacts, produces no artifact, and outputs only a briefing plus routing suggestion.\n"`);
|
|
3
|
+
export const instructions = JSON.parse(String.raw `"# STATUS\n\n**Holistic Entry Junction. Orient, Route, Activate**\n\nSingle entry point to the agentera suite. Detects fresh vs returning, delivers a situational briefing, routes to the right capability. Same path on first install and the 100th session.\n\nGlyph: **⌂** (SG1). Status reads suite state through \u0060agentera prime\u0060 and writes nothing. A bare user message of exactly \u0060/agentera\u0060 invokes this capability; it does not fall back to conversational smalltalk.\n\nStatus MUST source both instructions and bounded state from \u0060agentera prime --context status --format json\u0060 and write nothing. Read \u0060capability_context.instructions\u0060 in full, render from \u0060capability_context.context.status_context\u0060, and use the one \u0060capability_context.startup\u0060 aggregation. Its outcome is \u0060ok\u0060, \u0060degraded\u0060, or \u0060blocked\u0060; \u0060status_context.outcome\u0060 is the same value. For deferred detail, run only that availability row\u0027s exact \u0060detail_command\u0060. An \u0060ok\u0060 startup needs no second prime call. Status MUST NOT raw-read \u0060.agentera/*.yaml\u0060.\n\n---\n\n## Dashboard rendering\n\nStatus owns the prime dashboard contract. SKILL.md and other surfaces delegate here.\n\n\u0060\u0060\u0060text\n┌─┐┌─┐┌─┐┌┐┌┌─┐┌─┐┬─┐┌─┐\n├─┤│ ┬├┤ │││ │ ├┤ ├┬┘├─┤\n┴ ┴└─┘└─┘┘└┘ ┴ └─┘┴└─┴ ┴\n\n─── status ─────────────────────────────\n\n ⛶ health [⮉|⮋] [grade] ([worst dimension: grade])\n ⇶ todo N critical · M degraded · J annoying\n ≡ plan [██████▓░░░] N/M tasks\n ⎘ optim [metric] [current] → [target]\n ♾ profile [loaded | not found]\n\n [1-2 sentence narrative read: what shipped, what's moving, what needs eyes.\n Interpretation, not metrics. Closes the status section before attention.]\n\n─── attention ──────────────────────────\n\n ⇶ [critical items, triple arrow for critical]\n ⇉ [degraded items, double arrow for degraded]\n → [normal items, single arrow for normal]\n ⇢ [annoying items, dashed arrow for annoying]\n\n─── next ───────────────────────────────\n\n suggested → [glyph] [capability] ([reason])\n\u0060\u0060\u0060\n\nBuild the dashboard from \u0060agentera prime --format json\u0060 output. Source labels such as \u0060mode:\u0060, \u0060profile:\u0060, \u0060health:\u0060, \u0060todo:\u0060, \u0060plan:\u0060, \u0060objective:\u0060, \u0060attention:\u0060, \u0060next_action:\u0060, and the \u0060app.status\u0060 installed-app status object are parsing aids, not dashboard lines. Do not relay raw CLI lines as the user-facing briefing.\n\n**Output constraint**: ≤120 words total briefing, ≤15 words per routing suggestion.\n\n**Exit marker**: after the closing code fence of the dashboard, emit \u0060⌂ status · <status>\u0060 on its own line, followed by a one-sentence summary of what you delivered. For \u0060waiting\u0060, \u0060flagged\u0060, or \u0060stuck\u0060, add a \u0060▸\u0060 bullet below the summary identifying what the user needs to decide or act on next. The exit marker MUST appear on every invocation regardless of mode (fresh welcome or returning briefing).\n\n**Formatting rules**:\n- Each status line uses the skill glyph that owns that data\n- Severity arrows (VT5-VT8) mark attention items by urgency\n- Trend arrows (VT12/VT13) show health trajectory; derive ⮉/⮋ from \u0060health.degrading\u0060 (false→⮉, true→⮋); omit when no audit history\n- Progress bars (VT18) show plan completion visually\n- The inline separator (VT16) joins counts on a single line\n- Lead with status metrics, then the narrative read inside the status section\n- The narrative read is colleague interpretation; metric lines above it are evidence\n- The todo summary line lists critical, degraded, and annoying counts only; normal-priority items belong in attention with → (SI3), not on the summary line\n- Omit any line whose source artifact is missing\n- Omit any section that would be empty (e.g., no attention items = no attention section)\n\nVisual token IDs live in \u0060skills/agentera/protocol.yaml\u0060; see VT, SI, EX, SG, PH families.\n\n---\n\n## Briefing\n\nUse the \u0060mode\u0060 field from \u0060agentera prime\u0060 to detect fresh vs returning:\n\n- **Fresh** (\u0060mode: fresh\u0060): render welcome language; lead with the suggested capability from \u0060next_action\u0060. Do not enumerate the full suite unless asked.\n- **Returning** (\u0060mode: returning\u0060): render the dashboard template above using \u0060mode\u0060, \u0060profile\u0060, \u0060health\u0060, \u0060todo\u0060, \u0060plan\u0060, \u0060objective\u0060, \u0060attention\u0060, and \u0060next_action\u0060 fields.\n\nNarration voice: warm, brief, unscripted.\n\n### Project integration rendering\n\nWhen \u0060project_integration.recommendation\u0060 is \u0060upgrade\u0060:\n1. Render the plain-language \u0060project_integration.message\u0060.\n2. Show \u0060project_integration.dry_run_command\u0060 preview; state that it changes nothing.\n3. Ask before running \u0060project_integration.apply_command\u0060.\n\nWhen \u0060recommendation\u0060 is \u0060stay\u0060, do not suggest upgrade.\n\n### App status rendering\n\nRender \u0060app.status\u0060 as a status line only when it is not \u0060up_to_date\u0060. Use the plain-language \u0060project_integration.message\u0060 if present. Status MUST NOT teach install-recovery procedure — that belongs to the upgrade capability and \u0060agentera doctor\u0060.\n\n### Profile rendering\n\nRender \u0060profile.status\u0060 (\u0060loaded\u0060 or \u0060not found\u0060). Render \u0060profile.suggested_action\u0060 or a missing-profile attention item only when prime supplies one.\n\n### Attention items\n\nPriority order with severity arrows (SI1-SI4):\n\n- ⇶ (SI1) Critical issues, degrading health dimensions\n- ⇉ (SI2) Blocked/overdue plan tasks, stale artifacts, overdue health audits (prime \u0060health.stale=true\u0060), loop stop-condition triggers\n- → (SI3) Standard work: features, improvements, routine tasks\n- ⇢ (SI4) Unresolved exploratory decisions\n\nA clean bill of health is useful — say so when nothing is flagged.\n\n---\n\n## Routing suggestion\n\nThe routing suggestion MUST name the artifact item it would act on. A skill name without a concrete object is not a valid suggestion.\n\nValid objects: \u0060PLAN Task N: <title>\u0060, \u0060TODO: <item>\u0060, \u0060DECISION N follow-up\u0060, \u0060OBJECTIVE: <metric>\u0060, or \u0060VISION refresh\u0060.\n\n**Priority order** (SG codes are internal protocol references; never render them in user-facing handoff labels):\n\n- Active PLAN with pending tasks → suggest ⎈ orchestrate for the first unblocked pending task.\n- Critical or degrading health → suggest ⛶ audit or ⧉ build for the named finding.\n- Stale health audit (CLI \u0060health.stale=true\u0060) with no higher-priority work → suggest ⛶ audit for \u0060HEALTH: Audit N stale\u0060.\n- Active non-closed OBJECTIVE with stalled or missing metric evidence → suggest ⎘ optimize for that metric.\n- todo open items → select the highest-severity open item, then route by shape: narrow one-cycle todo items suggest ⧉ build; contract-shaped, multi-surface, dependency-heavy, migration, schema, metadata, validation, or acceptance-risky todo items suggest ≡ plan first. Prefer items that unlock product evidence or future plans.\n- Pending decisions follow-up → suggest ❈ discuss for the named unresolved decision.\n- Vision exists but no plan, objective, decision follow-up, or TODO work is active → suggest ≡ plan.\n- No vision, no executable follow-ups, and no active plan → suggest ⛥ vision to choose a direction.\n\nDo not let \u0060healthy + plan complete → ⛥\u0060 override active TODO, OBJECTIVE, DECISIONS, or a newer active PLAN. A completed plan means \"look for the next executable follow-up,\" not automatically \"refresh vision.\"\n\n### Routing posture\n\n- Present one concrete suggestion and let the user choose. Coercion MUST NOT occur.\n- Do not list generic skill options unless the user asks for the full menu.\n- The waiting bullet should ask whether to run the named action, not ask the user to pick from skills.\n- On the initial status brief, use a free-form continuation prompt rather than a native question menu unless the user asked for bounded choices or the suggested next step is a state-changing Proceed/Cancel handoff.\n- Mid-conversation, use the native question tool only for at least two meaningful non-terminal next actions or a consequential Proceed/Cancel decision; \u0060Done\u0060 and free-form/custom answer affordances do not count as alternatives.\n- State-changing handoffs are consequential Proceed/Cancel decisions even when there is only one suggested action. State-changing means the proposed next step may write artifacts, edit code, run optimization or orchestration cycles, apply migrations, refresh app/runtime state, or otherwise mutate project/runtime state.\n- Use the behavior rule first, with common examples such as ⧉ build, ≡ plan when creating or updating plans, ▤ document when writing docs, ⎘ optimize when running or applying optimization cycles, and ⎈ orchestrate when dispatching cycles.\n- For one non-mutating suggested action, clear free-form acceptance such as \u0060yes\u0060, \u0060start\u0060, \u0060do it\u0060, or \u0060run <capability>\u0060 confirms that suggestion. Ambiguous replies get one clarifying question.\n\nUnclear mapping? Ask **one** clarifying question. Compound questions MUST NOT occur.\n\n---\n\n## Safety rails\n\n<critical>\n- NEVER execute implementation work. Status orients and routes; it MUST NOT build, audit, plan, or decide.\n- NEVER dump full artifact contents verbatim. Summarize concisely; the user can read the files themselves.\n- NEVER skip the briefing in returning mode. The user needs context before choosing a direction.\n- NEVER assume what the user wants without asking. Present the suggestion, then wait for confirmation.\n- NEVER modify any state artifact. Status is strictly read-only.\n- NEVER route to a capability without the user's consent. Suggest, don't force.\n</critical>\n\n---\n\n## Exit signals\n\nReport one of these statuses at workflow completion (protocol refs: EX1-EX4).\n\nFormat: emit \u0060⌂ status · <status>\u0060 on its own line below the dashboard's closing code fence, followed by a one-sentence summary of what was delivered. For \u0060flagged\u0060 (EX2), \u0060stuck\u0060 (EX3), and \u0060waiting\u0060 (EX4), add a \u0060▸\u0060 (VT15) bullet below the summary identifying what the user needs to decide or act on next. The exit marker MUST appear on every invocation regardless of mode and uses status's canonical glyph \u0060⌂\u0060 (SG1, U+2302).\n\n- **complete** (EX1): Briefing delivered (or welcome shown in fresh mode) and user successfully routed to a capability.\n- **flagged** (EX2): Briefing delivered but critical attention items were found: critical issues, degrading health, loop stop-condition triggers. Each concern MUST be listed explicitly.\n- **stuck** (EX3): Cannot orient: the working directory is not a code project, no readable files exist, or permissions prevent scanning.\n- **waiting** (EX4): Briefing or welcome delivered, suggestion made, awaiting user input on which direction to take.\n\n---\n\n## Cross-capability integration\n\nStatus is the suite entry point. It reads other capabilities' artifacts, produces no artifact, and outputs only a briefing plus routing suggestion.\n"`);
|
|
4
4
|
export default `${instructions
|
|
5
5
|
.replaceAll("loaded | not found", "valid | absent | repair_needed")
|
|
6
6
|
.replaceAll("loaded or not found", "valid, absent, or repair_needed")
|
|
@@ -376,6 +376,17 @@ function projectionSummary(view) {
|
|
|
376
376
|
source_families: report.source_families.map((family) => ({ ...family })),
|
|
377
377
|
projects: { ...report.projects },
|
|
378
378
|
coverage: { ...report.coverage, reasons: [...report.coverage.reasons] },
|
|
379
|
+
mining: {
|
|
380
|
+
...report.mining_summary,
|
|
381
|
+
explicit: {
|
|
382
|
+
...report.mining_summary.explicit,
|
|
383
|
+
abstentions_by_reason: { ...report.mining_summary.explicit.abstentions_by_reason },
|
|
384
|
+
},
|
|
385
|
+
recurring: {
|
|
386
|
+
...report.mining_summary.recurring,
|
|
387
|
+
abstentions_by_reason: { ...report.mining_summary.recurring.abstentions_by_reason },
|
|
388
|
+
},
|
|
389
|
+
},
|
|
379
390
|
abstentions: {
|
|
380
391
|
candidate_selection: {
|
|
381
392
|
count: report.dropped_count,
|
|
@@ -444,7 +455,7 @@ function currentProjection(io, value, operation) {
|
|
|
444
455
|
: {
|
|
445
456
|
class: "projection_unavailable",
|
|
446
457
|
message: "the current personal glossary candidate projection is unavailable or invalid",
|
|
447
|
-
recovery: "
|
|
458
|
+
recovery: "Run `npx -y agentera@next report refresh --consent local-history`, then retry; no projection bytes were changed.",
|
|
448
459
|
};
|
|
449
460
|
failure(io, `${value.command} ${operation}`, operation === "list" ? listSyntax(value) : exactSyntax(value), operation === "list"
|
|
450
461
|
? `${value.command} list --limit ${value.defaultLimit} --format json`
|
|
@@ -732,7 +732,7 @@ function degradedBody(payload, projection) {
|
|
|
732
732
|
out.source = briefSource(payload.source);
|
|
733
733
|
if ("docs" in payload)
|
|
734
734
|
out.docs = briefDocs(payload.docs, projection);
|
|
735
|
-
for (const conditional of ["
|
|
735
|
+
for (const conditional of ["objective"]) {
|
|
736
736
|
if (conditional in payload)
|
|
737
737
|
out[conditional] = payload[conditional];
|
|
738
738
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { detectV1ArtifactPairs } from "../../../upgrade/migrateArtifactsV2ToV3.js";
|
|
5
4
|
import { summarizeProjectIntegration } from "../../../upgrade/projectIntegration.js";
|
|
6
5
|
import { selectStatusReadiness, statePresence, } from "../../orientation.js";
|
|
7
6
|
import { buildOrientationAttention } from "../../orientation/attention.js";
|
|
8
7
|
import { corpusCoverageSummary } from "../../orientation/corpusCoverage.js";
|
|
9
8
|
import { profileSignalsStatus } from "../../../analytics/profileSignals.js";
|
|
10
9
|
import { statusBundleContext } from "./bundleStatus.js";
|
|
11
|
-
import { v1MigrationSummary } from "./v1Migration.js";
|
|
12
10
|
import { diagnoseCanonicalSkill } from "../../../setup/sharedSkill.js";
|
|
13
11
|
import { collectEntityOrientation } from "./collectEntityOrientation.js";
|
|
14
12
|
import { acquireProfile } from "../../profileAcquisition.js";
|
|
@@ -71,8 +69,6 @@ export function collectOrientationState(opts) {
|
|
|
71
69
|
const boundedSignals = profileSignalsStatus(env, process.platform);
|
|
72
70
|
const { tiers_dir: _tiersDir, signal_path: _signalPath, ...publicBoundedSignals } = boundedSignals;
|
|
73
71
|
profileDict.bounded_signals = publicBoundedSignals;
|
|
74
|
-
const v1Artifacts = detectV1ArtifactPairs(project);
|
|
75
|
-
const v1Migration = v1MigrationSummary(v1Artifacts, { sourceRoot, home, env });
|
|
76
72
|
const entity = collectEntityOrientation(project, sourceRoot);
|
|
77
73
|
const cutover = stateCutover(project, sourceRoot);
|
|
78
74
|
const plan = entity.plan;
|
|
@@ -101,7 +97,6 @@ export function collectOrientationState(opts) {
|
|
|
101
97
|
resolvedChannel: channel,
|
|
102
98
|
installClassification: install,
|
|
103
99
|
successorAnnounced,
|
|
104
|
-
precomputedV1Artifacts: v1Artifacts,
|
|
105
100
|
});
|
|
106
101
|
const readiness = selectStatusReadiness(plan, health, objective, todoItems, decision, savedContext, entity.todoReadiness);
|
|
107
102
|
const reconciliationReadiness = entity.todoReconciliation?.status === "action_required"
|
|
@@ -129,7 +124,6 @@ export function collectOrientationState(opts) {
|
|
|
129
124
|
profile_dict: profileDict,
|
|
130
125
|
profile_status: profileStatus,
|
|
131
126
|
profile,
|
|
132
|
-
v1_migration: v1Migration,
|
|
133
127
|
project_integration: projectIntegration,
|
|
134
128
|
state_cutover: cutover,
|
|
135
129
|
shared_skill: sharedSkill,
|
|
@@ -160,7 +154,6 @@ export function collectOrientationState(opts) {
|
|
|
160
154
|
profile_dict: profileDict,
|
|
161
155
|
profile_status: profileStatus,
|
|
162
156
|
profile,
|
|
163
|
-
v1_migration: v1Migration,
|
|
164
157
|
project_integration: projectIntegration,
|
|
165
158
|
state_cutover: cutover,
|
|
166
159
|
shared_skill: sharedSkill,
|
|
@@ -58,7 +58,6 @@ export function projectPublicOrientationAttention(state) {
|
|
|
58
58
|
* still populates them, so explicit `--fields <name>` selection, the text
|
|
59
59
|
* briefing, and downstream state consumers are unaffected. */
|
|
60
60
|
const OMITTABLE_DEFAULT_CONDITIONAL_TOP_FIELDS = [
|
|
61
|
-
"v1_migration",
|
|
62
61
|
"docs",
|
|
63
62
|
"objective",
|
|
64
63
|
];
|
|
@@ -73,10 +72,6 @@ function isConditionalFieldPresent(field, payload) {
|
|
|
73
72
|
if (typeof value !== "object" || Array.isArray(value))
|
|
74
73
|
return true;
|
|
75
74
|
const obj = value;
|
|
76
|
-
// v1_migration: present when v1 artifacts are detected (detected !== true is
|
|
77
|
-
// the default state; recover via `agentera upgrade --dry-run`).
|
|
78
|
-
if (field === "v1_migration")
|
|
79
|
-
return obj.detected === true;
|
|
80
75
|
// docs: present when a docs mapping artifact exists (exists !== true is the
|
|
81
76
|
// absent state; recover via the canonical docs list command).
|
|
82
77
|
if (field === "docs")
|
|
@@ -140,15 +135,14 @@ export function buildOrientationJsonPayload(state, command, options = {}) {
|
|
|
140
135
|
? "caller-owned README-style prime orientation dashboard"
|
|
141
136
|
: "caller-owned README-style prime orientation dashboard";
|
|
142
137
|
const access = command === "status"
|
|
143
|
-
? "single installed CLI call; app/
|
|
144
|
-
: "single installed CLI call; app/
|
|
138
|
+
? "single installed CLI call; app/reset/profile safety included; no preflight glob/read/import/doctor calls during normal prime"
|
|
139
|
+
: "single installed CLI call; app/reset/profile safety included; no preflight glob/read/import/doctor calls during normal prime";
|
|
145
140
|
return {
|
|
146
141
|
command,
|
|
147
142
|
outcome: startup.outcome,
|
|
148
143
|
app_home: appHome,
|
|
149
144
|
app: bundlePublic,
|
|
150
145
|
mode: state.mode,
|
|
151
|
-
v1_migration: state.v1_migration,
|
|
152
146
|
shared_skill: state.shared_skill,
|
|
153
147
|
project_integration: state.project_integration,
|
|
154
148
|
...(state.todo_reconciliation?.status === "action_required" ? { todo_reconciliation: state.todo_reconciliation } : {}),
|
|
@@ -263,7 +257,7 @@ export function emitPrime(command, payload, format, fieldsArg, out, err, options
|
|
|
263
257
|
return retiredRejection;
|
|
264
258
|
const requested = requestedFields(fieldsArg);
|
|
265
259
|
// The default bare briefing first omits inactive conditional top-level fields
|
|
266
|
-
// (
|
|
260
|
+
// (docs/objective when default) so startup does not carry
|
|
267
261
|
// default-only payload, then — for the bare default only — projects the full
|
|
268
262
|
// payload to a bounded decision brief (Plan Task 3). Explicit `--fields`
|
|
269
263
|
// selection and `--context` use their governed payloads. Dashboard history is
|
|
@@ -5,7 +5,8 @@ import { resolveProfileDirOverride, resolveXdgDataHome } from "../../core/envPat
|
|
|
5
5
|
import { expanduser } from "../../core/paths.js";
|
|
6
6
|
import { usageMain, corpusTooLargeReason } from "../../analytics/usageStats.js";
|
|
7
7
|
import { extractCorpusMain } from "../../analytics/extractCorpus.js";
|
|
8
|
-
import {
|
|
8
|
+
import { acquirePersonalGlossaryRefreshCommitLock, PersonalGlossaryRefreshCommitLockError, produceCurrentPersonalGlossaryProjection, releasePersonalGlossaryRefreshCommitLock, } from "../../analytics/personalGlossaryRefreshProjection.js";
|
|
9
|
+
import { tiersDirForCorpusPath, assessTiers, readBoundedMetadata, readCurrentGeneration, } from "../../analytics/extractCorpus/index.js";
|
|
9
10
|
function buildExtractArgv(args, corpusPath) {
|
|
10
11
|
// Refresh publishes bounded evidence tiers to the directory co-located with
|
|
11
12
|
// the canonical corpus path (`<dir>/tiers`); the extract engine no longer
|
|
@@ -222,13 +223,90 @@ export function cmdReport(args, io = {}) {
|
|
|
222
223
|
return 0;
|
|
223
224
|
}
|
|
224
225
|
// consent === "local-history": extract local history into bounded tiers.
|
|
226
|
+
const tiersDir = tiersDirForCorpusPath(corpusPath);
|
|
227
|
+
let refreshLock;
|
|
228
|
+
try {
|
|
229
|
+
refreshLock = acquirePersonalGlossaryRefreshCommitLock();
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
if (!(error instanceof PersonalGlossaryRefreshCommitLockError))
|
|
233
|
+
throw error;
|
|
234
|
+
const recovery = error.recovery;
|
|
235
|
+
const currentGeneration = readCurrentGeneration(tiersDir);
|
|
236
|
+
const projection = {
|
|
237
|
+
status: "failed",
|
|
238
|
+
reason: error.message,
|
|
239
|
+
recovery,
|
|
240
|
+
};
|
|
241
|
+
const payload = {
|
|
242
|
+
command: "stats refresh",
|
|
243
|
+
status: "fail",
|
|
244
|
+
exit_signal: null,
|
|
245
|
+
privacy: {
|
|
246
|
+
local_history_read: false,
|
|
247
|
+
local_history_write: false,
|
|
248
|
+
tier_write: false,
|
|
249
|
+
projection_write: false,
|
|
250
|
+
required_consent: "local-history",
|
|
251
|
+
provided_consent: "local-history",
|
|
252
|
+
historical_imports: args.importSources ?? [],
|
|
253
|
+
historical_import_warning: args.importSources?.includes("claude")
|
|
254
|
+
? "Claude transcripts can contain secrets, file contents, and command output. Import is local and read-only."
|
|
255
|
+
: null,
|
|
256
|
+
},
|
|
257
|
+
corpus_path: corpusPath,
|
|
258
|
+
tier_path: tiersDir,
|
|
259
|
+
evidence: {
|
|
260
|
+
status: currentGeneration ? "readable" : "unavailable",
|
|
261
|
+
...(currentGeneration ? {
|
|
262
|
+
generation: currentGeneration.manifest.generation,
|
|
263
|
+
published_at: currentGeneration.manifest.published_at,
|
|
264
|
+
} : {}),
|
|
265
|
+
},
|
|
266
|
+
projection,
|
|
267
|
+
engine: { command: engineCommand, exit_code: null, stdout: [], stderr: [] },
|
|
268
|
+
};
|
|
269
|
+
if (outputFormat === "json") {
|
|
270
|
+
out(JSON.stringify(payload, null, 2) + "\n");
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
out(`agentera stats refresh: fail\ncorpus=${corpusPath}\ntiers=${tiersDir}\n`);
|
|
274
|
+
err(`candidate projection failed: ${projection.reason}\nRecovery: ${recovery}\n`);
|
|
275
|
+
}
|
|
276
|
+
return 1;
|
|
277
|
+
}
|
|
225
278
|
let engineOut = "";
|
|
226
279
|
let engineErr = "";
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
280
|
+
let rc;
|
|
281
|
+
let projection = { status: "not_attempted" };
|
|
282
|
+
let finalRc;
|
|
283
|
+
let currentGeneration;
|
|
284
|
+
try {
|
|
285
|
+
rc = extractCorpusMain(engineArgv, {
|
|
286
|
+
out: (t) => (engineOut += t + "\n"),
|
|
287
|
+
err: (t) => (engineErr += t + "\n"),
|
|
288
|
+
});
|
|
289
|
+
finalRc = rc;
|
|
290
|
+
currentGeneration = rc === 0 ? readCurrentGeneration(tiersDir) : null;
|
|
291
|
+
if (rc === 0) {
|
|
292
|
+
try {
|
|
293
|
+
const produced = produceCurrentPersonalGlossaryProjection({ tiersDir });
|
|
294
|
+
projection = { ...produced, write_status: produced.status, status: "published" };
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
finalRc = 1;
|
|
298
|
+
projection = {
|
|
299
|
+
status: "failed",
|
|
300
|
+
reason: error.message,
|
|
301
|
+
recovery: "npx -y agentera@next report refresh --consent local-history",
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
releasePersonalGlossaryRefreshCommitLock(refreshLock);
|
|
308
|
+
}
|
|
309
|
+
const refreshStatus = finalRc === 0 ? "pass" : rc === 4 ? "flagged" : "fail";
|
|
232
310
|
const payload = {
|
|
233
311
|
command: "stats refresh",
|
|
234
312
|
status: refreshStatus,
|
|
@@ -237,6 +315,7 @@ export function cmdReport(args, io = {}) {
|
|
|
237
315
|
local_history_read: true,
|
|
238
316
|
local_history_write: false,
|
|
239
317
|
tier_write: rc === 0,
|
|
318
|
+
projection_write: projection.status === "published",
|
|
240
319
|
required_consent: "local-history",
|
|
241
320
|
provided_consent: "local-history",
|
|
242
321
|
historical_imports: args.importSources ?? [],
|
|
@@ -245,7 +324,15 @@ export function cmdReport(args, io = {}) {
|
|
|
245
324
|
: null,
|
|
246
325
|
},
|
|
247
326
|
corpus_path: corpusPath,
|
|
248
|
-
tier_path:
|
|
327
|
+
tier_path: tiersDir,
|
|
328
|
+
evidence: {
|
|
329
|
+
status: rc === 0 ? "published" : "failed",
|
|
330
|
+
...(currentGeneration ? {
|
|
331
|
+
generation: currentGeneration.manifest.generation,
|
|
332
|
+
published_at: currentGeneration.manifest.published_at,
|
|
333
|
+
} : {}),
|
|
334
|
+
},
|
|
335
|
+
projection,
|
|
249
336
|
engine: { command: engineCommand, exit_code: rc, stdout: engineOut.split("\n").filter((l) => l), stderr: engineErr.split("\n").filter((l) => l) },
|
|
250
337
|
};
|
|
251
338
|
if (outputFormat === "json") {
|
|
@@ -257,8 +344,11 @@ export function cmdReport(args, io = {}) {
|
|
|
257
344
|
out(engineOut);
|
|
258
345
|
if (engineErr)
|
|
259
346
|
err(engineErr);
|
|
347
|
+
if (projection.status === "failed") {
|
|
348
|
+
err(`candidate projection failed: ${String(projection.reason)}\nRecovery: ${String(projection.recovery)}\n`);
|
|
349
|
+
}
|
|
260
350
|
}
|
|
261
|
-
return
|
|
351
|
+
return finalRc;
|
|
262
352
|
}
|
|
263
353
|
if (action !== null) {
|
|
264
354
|
err(`Error: unsupported stats action '${action}'. ` +
|
|
@@ -3,6 +3,7 @@ import { renderVerifySummary, verifyOneWayUpgrade, verifyUpgrade, } from "./upgr
|
|
|
3
3
|
import { detectStateMode } from "../../state/stateMode.js";
|
|
4
4
|
import { UpgradeLockError } from "../../upgrade/upgradeLock.js";
|
|
5
5
|
import { fullEntityUpgradeCommand } from "../../upgrade/upgradeCommands.js";
|
|
6
|
+
import { applyProductV1Reset, previewProductV1Reset } from "../../upgrade/productV1Reset.js";
|
|
6
7
|
/** Canonical stable-channel update entry point. */
|
|
7
8
|
export const UPGRADE_COMMAND = "npx -y agentera@latest";
|
|
8
9
|
function toOrchestratorArgs(args) {
|
|
@@ -54,6 +55,35 @@ export function cmdUpgrade(args, io = {}, dependencies = {}) {
|
|
|
54
55
|
const out = io.out ?? ((t) => process.stdout.write(t));
|
|
55
56
|
const err = io.err ?? ((t) => process.stderr.write(t));
|
|
56
57
|
const orchestratorArgs = toOrchestratorArgs(args);
|
|
58
|
+
if (args.productV1Reset) {
|
|
59
|
+
const options = { project: args.project, installRoot: args.installRoot, home: args.home };
|
|
60
|
+
const result = args.yes
|
|
61
|
+
? applyProductV1Reset(options, args.authorization ?? "")
|
|
62
|
+
: previewProductV1Reset(options);
|
|
63
|
+
if (args.format === "json")
|
|
64
|
+
out(JSON.stringify(result, null, 2) + "\n");
|
|
65
|
+
else if ("deletions" in result) {
|
|
66
|
+
const lines = ["Product-v1 reset preview (no mutation)", `Authorization: ${result.authorization}`, "Roots:"];
|
|
67
|
+
for (const [name, root] of Object.entries(result.roots))
|
|
68
|
+
lines.push(` ${name}: ${root}`);
|
|
69
|
+
lines.push("Deletions:");
|
|
70
|
+
for (const item of result.deletions)
|
|
71
|
+
for (const target of item.targets) {
|
|
72
|
+
lines.push(` ${item.id}: ${target.path ?? target.declared}${target.selector ? ` (${target.selector.kind}:${target.selector.value})` : ""}`);
|
|
73
|
+
for (const entry of target.entries ?? [])
|
|
74
|
+
lines.push(` ${entry.type}: ${entry.path}`);
|
|
75
|
+
}
|
|
76
|
+
lines.push("Recreations:");
|
|
77
|
+
for (const item of result.recreations)
|
|
78
|
+
for (const target of item.targets)
|
|
79
|
+
lines.push(` ${item.id}: ${target.declared} under ${item.root}`);
|
|
80
|
+
lines.push("Irreversible loss:", ...result.irreversible_loss.map((loss) => ` ${loss}`));
|
|
81
|
+
out(lines.join("\n") + "\n");
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
out(`Product-v1 reset complete: ${result.authorization}\nFresh v3 state initialized.\n`);
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
57
87
|
if (orchestratorArgs.runtime) {
|
|
58
88
|
err(`upgrade error: --runtime ${orchestratorArgs.runtime} is retired; Agentera now uses the shared skill at ` +
|
|
59
89
|
"~/.agents/skills/agentera plus the CLI. Remove --runtime and rerun. " +
|
|
@@ -13,6 +13,7 @@ import { emitInvalidInput } from "../errors.js";
|
|
|
13
13
|
import { verbsForArtifact } from "../../state/write/operations.js";
|
|
14
14
|
import { REMOVED_TOP_LEVEL_CORRECTIONS } from "../commands/schema.js";
|
|
15
15
|
import { enforceCompletedEntityCutover, migrationProject, requestedMigrationFailureFormat, requiresCompletedEntityCutover, } from "../migrationRequired.js";
|
|
16
|
+
import { enforceProductV1Eol } from "../productV1Eol.js";
|
|
16
17
|
export function main(argv, io = {}) {
|
|
17
18
|
const err = io.err ?? ((t) => process.stderr.write(t));
|
|
18
19
|
const out = io.out ?? ((t) => process.stdout.write(t));
|
|
@@ -59,6 +60,12 @@ export function main(argv, io = {}) {
|
|
|
59
60
|
},
|
|
60
61
|
});
|
|
61
62
|
}
|
|
63
|
+
const productV1Reset = command === "upgrade" && rest.includes("--reset-product-v1");
|
|
64
|
+
if (command !== "--version" && command !== "version" && !productV1Reset) {
|
|
65
|
+
const failure = enforceProductV1Eol(migrationProject(args), requestedMigrationFailureFormat(args), io);
|
|
66
|
+
if (failure !== null)
|
|
67
|
+
return failure;
|
|
68
|
+
}
|
|
62
69
|
// Retained-reference validation audits package source, not project state. It
|
|
63
70
|
// must report its source-checkout boundary before project migration checks.
|
|
64
71
|
const sourceOnlyReferenceValidation = args[0] === "check" && args[1] === "validate" && ["retained-references", "activation-conjunction"].includes(args[2] ?? "");
|
|
@@ -263,6 +263,8 @@ export function runUpgrade(argv, io, prog) {
|
|
|
263
263
|
runtime: null,
|
|
264
264
|
legacyCleanup: null,
|
|
265
265
|
format: "text",
|
|
266
|
+
productV1Reset: false,
|
|
267
|
+
authorization: null,
|
|
266
268
|
};
|
|
267
269
|
let jsonFlag = false;
|
|
268
270
|
let i = 0;
|
|
@@ -311,6 +313,12 @@ export function runUpgrade(argv, io, prog) {
|
|
|
311
313
|
}
|
|
312
314
|
args.legacyCleanup = selectedResource.id;
|
|
313
315
|
}
|
|
316
|
+
else if (a === "--reset-product-v1") {
|
|
317
|
+
args.productV1Reset = true;
|
|
318
|
+
}
|
|
319
|
+
else if ((v = value("--authorization")) !== null) {
|
|
320
|
+
args.authorization = v;
|
|
321
|
+
}
|
|
314
322
|
else if ((v = value("--only")) !== null) {
|
|
315
323
|
if (v !== "artifacts" && v !== "runtime" && v !== "cleanup") {
|
|
316
324
|
return emitInvalidInput(io, {
|
|
@@ -365,6 +373,18 @@ export function runUpgrade(argv, io, prog) {
|
|
|
365
373
|
}
|
|
366
374
|
if (jsonFlag)
|
|
367
375
|
args.format = "json";
|
|
376
|
+
if (args.productV1Reset) {
|
|
377
|
+
const incompatible = args.channel !== null || (args.only?.length ?? 0) > 0 || args.force || args.verify || args.legacyCleanup !== null;
|
|
378
|
+
if (incompatible || args.dryRun === args.yes || (args.yes && !args.authorization) || (!args.yes && args.authorization)) {
|
|
379
|
+
return emitInvalidInput(io, {
|
|
380
|
+
format: asEnvelopeFormat(args.format),
|
|
381
|
+
body: {
|
|
382
|
+
class: "invalid_request",
|
|
383
|
+
message: "product-v1 reset requires either --dry-run preview or --yes --authorization TOKEN apply, without other upgrade modes",
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
368
388
|
try {
|
|
369
389
|
return cmdUpgrade(args, io);
|
|
370
390
|
}
|
package/dist/cli/help.js
CHANGED
|
@@ -54,7 +54,8 @@ export function printUpgradeHelp() {
|
|
|
54
54
|
return [
|
|
55
55
|
"usage: agentera upgrade [-h] [--project PROJECT] [--install-root INSTALL_ROOT]",
|
|
56
56
|
" [--home HOME] [--channel {stable,development}]",
|
|
57
|
-
" [--legacy-cleanup RESOURCE_ID]",
|
|
57
|
+
" [--legacy-cleanup RESOURCE_ID] [--reset-product-v1]",
|
|
58
|
+
" [--authorization TOKEN]",
|
|
58
59
|
" [--only {artifacts,runtime,cleanup}] [--dry-run] [--yes]",
|
|
59
60
|
" [--force] [--verify] [--format {text,json}]",
|
|
60
61
|
"",
|
|
@@ -65,9 +66,11 @@ export function printUpgradeHelp() {
|
|
|
65
66
|
" --home HOME Home directory for shared-skill detection and explicit native resource cleanup",
|
|
66
67
|
" --channel CHANNEL Update channel: stable (2.x) or development (3.x npm)",
|
|
67
68
|
" --legacy-cleanup ID Select one declared native Agentera resource for cleanup",
|
|
69
|
+
" --reset-product-v1 Preview or authorize the bounded destructive product-v1 reset",
|
|
70
|
+
" --authorization TOKEN Bind product-v1 apply to the exact reviewed preview scope",
|
|
68
71
|
" --only PHASE Upgrade phase to include; may be repeated",
|
|
69
72
|
" --dry-run Strict read-only preview; no files, locks, caches, native commands, or telemetry",
|
|
70
|
-
" --yes Explicitly approve
|
|
73
|
+
" --yes Explicitly approve migration, selected cleanup, or an authorized product-v1 reset",
|
|
71
74
|
" --force Replace only where the migration contract explicitly permits it",
|
|
72
75
|
" --verify Verify the current install; full v2-to-v3 apply verifies state and startup automatically",
|
|
73
76
|
" --format {text,json} Structured output format",
|
|
@@ -83,6 +86,10 @@ export function printUpgradeHelp() {
|
|
|
83
86
|
" Current runtime selectors and native plugin, hook, agent, command, descriptor, and marketplace writes are retired.",
|
|
84
87
|
` Native resource cleanup preview: ${preCutoverCommand("upgrade --legacy-cleanup RESOURCE_ID --dry-run")}`,
|
|
85
88
|
` Native resource cleanup apply: ${preCutoverCommand("upgrade --legacy-cleanup RESOURCE_ID --yes")}`,
|
|
89
|
+
"",
|
|
90
|
+
"product-v1 reset (irreversible, no backup or restore):",
|
|
91
|
+
` Preview: ${preCutoverCommand("upgrade --reset-product-v1 --dry-run --format json")}`,
|
|
92
|
+
` Authorize: ${preCutoverCommand("upgrade --reset-product-v1 --yes --authorization TOKEN --format json")}`,
|
|
86
93
|
].join("\n");
|
|
87
94
|
}
|
|
88
95
|
export function printAppHomeHelp() {
|
|
@@ -183,7 +190,7 @@ export function printStateHelp(sub) {
|
|
|
183
190
|
"",
|
|
184
191
|
"Build-owned publication validates one audit terminology proposal and proposal-specific user confirmation.",
|
|
185
192
|
"The writer revalidates cited source lines and atomically records a separate immutable approval and shared glossary entry.",
|
|
186
|
-
"Confirmed project variants are enforced by the
|
|
193
|
+
"Confirmed project variants are enforced by the glossary variant guard; profile and docs-mapping mutation remain outside publication.",
|
|
187
194
|
"Audit and discuss remain mutation-free. Discuss, Plan, and Build use read-only glossary advice with project precedence, proven-gap personal fallback, and host review for inferred equivalence.",
|
|
188
195
|
"",
|
|
189
196
|
"Discover writes: agentera state glossary explain --verb publish --format json",
|
|
@@ -3,7 +3,7 @@ import { corpusCoverageAttention } from "./corpusCoverage.js";
|
|
|
3
3
|
import { firstPresent } from "../stateQuery.js";
|
|
4
4
|
import { TODO_SEVERITY_ORDER } from "../todoSeverity.js";
|
|
5
5
|
export function buildOrientationAttention(state) {
|
|
6
|
-
const {
|
|
6
|
+
const { project_integration: projectIntegration, health, plan, decision_attention: decisionAttention, glossary_caveat_attention: glossaryCaveatAttention, corpus_coverage: corpusCoverage, todo_items: todoItems, todo_reconciliation: todoReconciliation, } = state;
|
|
7
7
|
const attention = [];
|
|
8
8
|
if (todoReconciliation?.status === "action_required") {
|
|
9
9
|
const label = todoReconciliation.state === "inactive" ? "inactive" : todoReconciliation.state === "unsafe_inactive" ? "unsafe inactive" : todoReconciliation.state === "unsafe_active" ? "unsafe active" : "invalid lifecycle";
|
|
@@ -25,9 +25,6 @@ export function buildOrientationAttention(state) {
|
|
|
25
25
|
if (coverageAttention) {
|
|
26
26
|
attention.push(coverageAttention);
|
|
27
27
|
}
|
|
28
|
-
if (v1Migration.detected && projectIntegration.recommendation !== "upgrade") {
|
|
29
|
-
attention.push(`degraded: v1 artifacts detected; preview \`${v1Migration.dry_run_command}\`; files=${v1Migration.affected_files.join(", ")}`);
|
|
30
|
-
}
|
|
31
28
|
if (health.stale) {
|
|
32
29
|
const auditId = health.id ?? "unknown";
|
|
33
30
|
const daysSince = health.days_since_audit ?? "?";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { resolveCandidate } from "../state/installRoot.js";
|
|
5
|
+
import { isProductV1PackageVersion, loadProductV1ResetAuthority, } from "../upgrade/productV1ResetAuthority.js";
|
|
6
|
+
import { emitStructured } from "./structured.js";
|
|
7
|
+
const authority = loadProductV1ResetAuthority();
|
|
8
|
+
function installedProductV1Evidence() {
|
|
9
|
+
const [installRoot] = resolveCandidate(null, { env: process.env, home: os.homedir() });
|
|
10
|
+
const manifest = path.join(installRoot, authority.installationPackage.manifest);
|
|
11
|
+
if (!fs.existsSync(manifest))
|
|
12
|
+
return null;
|
|
13
|
+
try {
|
|
14
|
+
const registry = JSON.parse(fs.readFileSync(manifest, "utf8"));
|
|
15
|
+
const version = registry.skills?.[0]?.version;
|
|
16
|
+
return typeof version === "string" && isProductV1PackageVersion(version) ? manifest : null;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function productV1Evidence(projectRoot) {
|
|
23
|
+
const evidence = authority.projectArtifacts
|
|
24
|
+
.filter(({ triggersReset, path: relativePath }) => triggersReset && fs.existsSync(path.join(projectRoot, relativePath)))
|
|
25
|
+
.map(({ path: relativePath }) => path.join(projectRoot, relativePath));
|
|
26
|
+
const installation = installedProductV1Evidence();
|
|
27
|
+
if (installation)
|
|
28
|
+
evidence.push(installation);
|
|
29
|
+
return evidence;
|
|
30
|
+
}
|
|
31
|
+
/** Read-only EOL gate. */
|
|
32
|
+
export function enforceProductV1Eol(projectRoot, format, io = {}) {
|
|
33
|
+
const evidence = productV1Evidence(path.resolve(projectRoot));
|
|
34
|
+
if (evidence.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
const error = {
|
|
37
|
+
class: "product_v1_eol",
|
|
38
|
+
message: "Agentera product v1 is end-of-life and cannot be used by the v3 CLI.",
|
|
39
|
+
evidence,
|
|
40
|
+
reset_workflow: [
|
|
41
|
+
"Run agentera upgrade --reset-product-v1 --dry-run --format json.",
|
|
42
|
+
"Review every deletion, recreation, and irreversible loss in that preview.",
|
|
43
|
+
"Explicitly approve apply to remove scoped Agentera state and initialize fresh v3 state.",
|
|
44
|
+
],
|
|
45
|
+
recovery: "Preview the product-v1 reset, then apply with --yes and the preview authorization; this command did not change state.",
|
|
46
|
+
};
|
|
47
|
+
if (format === "json" || format === "yaml") {
|
|
48
|
+
emitStructured({ schemaVersion: "agentera.stateFailure.v1", status: "fail", error }, format, io.out ?? ((text) => process.stdout.write(text)));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const err = io.err ?? ((text) => process.stderr.write(text));
|
|
52
|
+
err(`Error: ${error.message}\nReset workflow: ${error.reset_workflow.join(" ")}\nRecovery: ${error.recovery}\n`);
|
|
53
|
+
}
|
|
54
|
+
return 1;
|
|
55
|
+
}
|
package/dist/cli/stateQuery.js
CHANGED
|
@@ -29,7 +29,7 @@ export const ROUTINE_STRUCTURED_FIELDS = [
|
|
|
29
29
|
* `state_presence` (missing-vs-empty) and named recovery commands, not by
|
|
30
30
|
* trimming this set. */
|
|
31
31
|
export const PRIME_STRUCTURED_FIELDS = [
|
|
32
|
-
"command", "outcome", "app_home", "app", "mode", "
|
|
32
|
+
"command", "outcome", "app_home", "app", "mode", "health",
|
|
33
33
|
"todo", "plan", "docs", "progress", "objective", "state_presence", "shared_skill", "project_integration", "attention",
|
|
34
34
|
"history",
|
|
35
35
|
"decision_attention", "next_action", "orchestration_context", "closeout_context",
|
|
@@ -81,6 +81,15 @@ const addedTuples = [
|
|
|
81
81
|
{ class: "package", surface_id: "emitted:packages/cli/src/cli/commands/doctor.ts", owner_path: "packages/cli/src/registries/packageRegistry.ts", owner_symbol_or_selector: "loadRegistry", owner_selector: "packages/cli/src/cli/commands/doctor.ts", semantic_selector_if_any: JSON.stringify({ path: "packages/cli/src/cli/commands/doctor.ts", selector: null, format: null, classification: null, reason: "Doctor project-state signals publish bounded reconciliation preview and apply guidance." }), canonical_correction: "pnpm -C packages/cli run verify:package" },
|
|
82
82
|
{ class: "package", surface_id: "emitted:packages/cli/src/state/todoReconciliationInspection.ts", owner_path: "packages/cli/src/registries/packageRegistry.ts", owner_symbol_or_selector: "loadRegistry", owner_selector: "packages/cli/src/state/todoReconciliationInspection.ts", semantic_selector_if_any: JSON.stringify({ path: "packages/cli/src/state/todoReconciliationInspection.ts", selector: null, format: null, classification: null, reason: "TODO reconciliation inspection publishes bounded preview and effect-bound apply guidance." }), canonical_correction: "pnpm -C packages/cli run verify:package" },
|
|
83
83
|
{ class: "package", surface_id: "generated:build-source-identity", owner_path: "packages/cli/src/registries/packageRegistry.ts", owner_symbol_or_selector: "loadRegistry", owner_selector: ".agentera-build-source.json", semantic_selector_if_any: JSON.stringify({ path: ".agentera-build-source.json", selector: null, format: "json", classification: "active", reason: "Build-generated source identity binds constructed dist and bundle output to one Git commit, tree, and exact working-tree digest; no source copy exists." }), canonical_correction: "pnpm -C packages/cli run verify:package" },
|
|
84
|
+
{
|
|
85
|
+
class: "reference",
|
|
86
|
+
surface_id: "references/adapters/product-v1-reset.yaml",
|
|
87
|
+
owner_path: "packages/cli/src/upgrade/productV1ResetAuthority.ts",
|
|
88
|
+
owner_symbol_or_selector: "loadProductV1ResetAuthority",
|
|
89
|
+
owner_selector: "references/adapters/product-v1-reset.yaml",
|
|
90
|
+
semantic_selector_if_any: null,
|
|
91
|
+
canonical_correction: "node packages/cli/dist/bin/agentera.js check validate retained-references --format json",
|
|
92
|
+
},
|
|
84
93
|
{
|
|
85
94
|
class: "reference",
|
|
86
95
|
surface_id: "references/analysis/personal-glossary-evaluation-authority.yaml",
|
|
@@ -123,12 +132,12 @@ export const ACTIVATION_TUPLE_AUTHORITY = Object.freeze({
|
|
|
123
132
|
cli: { count: 27, sha256: "9d0db6cafe592da30ea3469c91dc514bdd1b3b22e8229a0519e680cbcb01c2fa" },
|
|
124
133
|
capability: { count: 12, sha256: "892e6e5e2a57b41064bc44fa2946453225f1b1195aff77aad05365fd0a1071c2" },
|
|
125
134
|
runtime: { count: 81, sha256: "99b2abff3ebff889b54b1781c563ab4b32609a479c4e90d6aad854f48fba7edc" },
|
|
126
|
-
reference: { count:
|
|
135
|
+
reference: { count: 26, sha256: "0daf0d131217064bb66d667be2b88c81bf928369fac321bce8023c9039d9ddfe" },
|
|
127
136
|
state: { count: 38, sha256: "697de8dcd13ac521124c35058ba222aa5cb6cae546f00bb54652ceaca4b662aa" },
|
|
128
137
|
package: { count: 67, sha256: "5dbe325af5ffb29a1ea50534070d08fcff647d4d9ef5654b4ce03d76eeaa8adb" },
|
|
129
138
|
bootstrap: { count: 34, sha256: "9a7dd7e27110d85cf5c08835fdd8f08119e75579858e63bc6d396c733961d0bc" },
|
|
130
139
|
},
|
|
131
|
-
total: { count:
|
|
140
|
+
total: { count: 285, sha256: "3be47d6d1928df8b7f16d494aaa57939404d690b35ef81254f2c62506fd5f984" },
|
|
132
141
|
});
|
|
133
142
|
export function canonicalTupleJson(value) { return JSON.stringify(value); }
|
|
134
143
|
export function digestCanonicalTuples(values) {
|