archondev 2.19.29 → 2.19.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 +4 -0
- package/dist/index.js +177 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,6 +121,10 @@ pnpm exec tsx scripts/init-governance-db.ts
|
|
|
121
121
|
- Content-only requests (stories, outlines, lessons, visuals) use lightweight planning to avoid blocking.
|
|
122
122
|
- BYOK shows per‑model usage and cost by today/week/month/year in `archon preferences` → “View usage details.”
|
|
123
123
|
- You can paste multi‑line requests into interactive prompts; Archon captures them as a single response.
|
|
124
|
+
- Proposal approvals like `approve plan` now bind to the pending proposal context in chat mode.
|
|
125
|
+
- Governance boundary/path checks in execute now steer with actionable guidance and set atoms to `BLOCKED` rather than hard failing.
|
|
126
|
+
- Analysis-first requests now return recommendations first and require explicit `create atom` before task creation.
|
|
127
|
+
- Chat execution now requires explicit execute intent (for example, `execute atom`) instead of generic `continue`.
|
|
124
128
|
|
|
125
129
|
**Tip:** Use `archon plan --edit` to adjust title and acceptance criteria before planning.
|
|
126
130
|
**Web Checks:** If Archon detects a web project, it prompts to run A11y/SEO/GEO checks and stores your preference in `.archon/config.yaml`.
|
package/dist/index.js
CHANGED
|
@@ -203,7 +203,7 @@ async function saveAtomEnvironmentState(atomId, cwd, state) {
|
|
|
203
203
|
import chalk5 from "chalk";
|
|
204
204
|
import readline from "readline";
|
|
205
205
|
import { existsSync as existsSync6, readFileSync as readFileSync3, readdirSync as readdirSync3, appendFileSync } from "fs";
|
|
206
|
-
import { join as join6 } from "path";
|
|
206
|
+
import { join as join6, relative } from "path";
|
|
207
207
|
|
|
208
208
|
// src/core/context/manager.ts
|
|
209
209
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -2616,6 +2616,8 @@ function detectWebProject(cwd) {
|
|
|
2616
2616
|
// src/cli/start.ts
|
|
2617
2617
|
var PAID_TIER_DEFAULT_CHAT_MODEL = "gemini-3.1-pro-preview";
|
|
2618
2618
|
var pendingProposalRequest = null;
|
|
2619
|
+
var pendingProposalMode = "atom";
|
|
2620
|
+
var pendingAnalysisToAtomRequest = null;
|
|
2619
2621
|
function uiText(rich, plain) {
|
|
2620
2622
|
return isTerminalSafeMode() ? plain : rich;
|
|
2621
2623
|
}
|
|
@@ -3676,11 +3678,21 @@ async function runAgentMode(cwd, state) {
|
|
|
3676
3678
|
async function handleAgentConversationInput(cwd, input) {
|
|
3677
3679
|
const normalized = input.trim().toLowerCase();
|
|
3678
3680
|
if (!normalized) return false;
|
|
3681
|
+
if (pendingAnalysisToAtomRequest && isCreateAtomDirective(normalized)) {
|
|
3682
|
+
const request = pendingAnalysisToAtomRequest;
|
|
3683
|
+
pendingAnalysisToAtomRequest = null;
|
|
3684
|
+
console.log(chalk5.dim("\n> Great. Creating a governed task from the approved analysis plan.\n"));
|
|
3685
|
+
const { plan: plan3 } = await import("./plan-RHDFDSZE.js");
|
|
3686
|
+
await plan3(request, { conversational: true });
|
|
3687
|
+
await showLatestPlannedAtom(cwd);
|
|
3688
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3689
|
+
return true;
|
|
3690
|
+
}
|
|
3679
3691
|
if (pendingProposalRequest && isPlanApprovalDirective(normalized)) {
|
|
3680
3692
|
await applyApprovedProposal(cwd);
|
|
3681
3693
|
return true;
|
|
3682
3694
|
}
|
|
3683
|
-
if (
|
|
3695
|
+
if (isExecutionDirective(normalized)) {
|
|
3684
3696
|
await continueWithCurrentTask(cwd);
|
|
3685
3697
|
return true;
|
|
3686
3698
|
}
|
|
@@ -3689,6 +3701,10 @@ async function handleAgentConversationInput(cwd, input) {
|
|
|
3689
3701
|
return true;
|
|
3690
3702
|
}
|
|
3691
3703
|
if (wantsProposalBeforeExecution(input)) {
|
|
3704
|
+
if (shouldDoAnalysisBeforeAtom(input)) {
|
|
3705
|
+
await provideAnalysisFirstPlan(cwd, input);
|
|
3706
|
+
return true;
|
|
3707
|
+
}
|
|
3692
3708
|
await showProposalForApproval(input);
|
|
3693
3709
|
return true;
|
|
3694
3710
|
}
|
|
@@ -3706,7 +3722,7 @@ async function handleAgentConversationInput(cwd, input) {
|
|
|
3706
3722
|
return true;
|
|
3707
3723
|
}
|
|
3708
3724
|
await showLatestPlannedAtom(cwd);
|
|
3709
|
-
console.log(chalk5.dim('\nReply "
|
|
3725
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3710
3726
|
return true;
|
|
3711
3727
|
}
|
|
3712
3728
|
function isReadOnlyExploreRequest(input) {
|
|
@@ -3733,6 +3749,7 @@ function wantsProposalBeforeExecution(input) {
|
|
|
3733
3749
|
}
|
|
3734
3750
|
async function showProposalForApproval(input) {
|
|
3735
3751
|
pendingProposalRequest = input.trim();
|
|
3752
|
+
pendingProposalMode = shouldDoAnalysisBeforeAtom(input) ? "analysis" : "atom";
|
|
3736
3753
|
console.log(chalk5.dim("\n> Understood. I will not create atoms yet.\n"));
|
|
3737
3754
|
console.log(chalk5.bold("Proposed plan (for your approval):"));
|
|
3738
3755
|
console.log(chalk5.dim(" 1. Review project files and locate the capsule markdown/source for day 1."));
|
|
@@ -3766,18 +3783,32 @@ Showing latest planned atom (${latest.externalId})...
|
|
|
3766
3783
|
const { show: show2 } = await import("./show-7A3FACN6.js");
|
|
3767
3784
|
await show2(latest.externalId);
|
|
3768
3785
|
}
|
|
3769
|
-
function
|
|
3786
|
+
function isPlanApprovalDirective(input) {
|
|
3770
3787
|
const normalized = input.trim().toLowerCase();
|
|
3771
|
-
return normalized === "
|
|
3788
|
+
return normalized === "approve" || normalized === "approve plan" || normalized === "approved" || normalized === "yes" || normalized === "yes, proceed" || normalized === "proceed";
|
|
3772
3789
|
}
|
|
3773
|
-
function
|
|
3790
|
+
function isExecutionDirective(input) {
|
|
3774
3791
|
const normalized = input.trim().toLowerCase();
|
|
3775
|
-
return normalized === "
|
|
3792
|
+
return normalized === "execute" || normalized === "execute atom" || normalized === "run atom" || normalized === "run it now" || normalized === "implement now" || normalized === "start execution" || normalized === "go ahead and execute";
|
|
3793
|
+
}
|
|
3794
|
+
function isCreateAtomDirective(input) {
|
|
3795
|
+
const normalized = input.trim().toLowerCase();
|
|
3796
|
+
return normalized === "create atom" || normalized === "save this" || normalized === "make atom" || normalized === "save as atom" || normalized === "turn this into a task" || normalized === "create task";
|
|
3797
|
+
}
|
|
3798
|
+
function shouldDoAnalysisBeforeAtom(input) {
|
|
3799
|
+
const normalized = input.toLowerCase();
|
|
3800
|
+
const hasAnalysisIntent = /\b(review|analy[sz]e|inspect|read)\b/.test(normalized) && /\b(files?|folder|project|markdown|lesson|capsule)\b/.test(normalized);
|
|
3801
|
+
const asksForPlan = /\b(let me know|what your plan is|plan is|how to implement|before creating|before you implement)\b/.test(normalized);
|
|
3802
|
+
return hasAnalysisIntent && asksForPlan;
|
|
3776
3803
|
}
|
|
3777
3804
|
async function applyApprovedProposal(cwd) {
|
|
3778
3805
|
const approvedRequest = pendingProposalRequest;
|
|
3779
3806
|
if (!approvedRequest) return;
|
|
3780
3807
|
pendingProposalRequest = null;
|
|
3808
|
+
if (pendingProposalMode === "analysis") {
|
|
3809
|
+
await provideAnalysisFirstPlan(cwd, approvedRequest);
|
|
3810
|
+
return;
|
|
3811
|
+
}
|
|
3781
3812
|
console.log(chalk5.dim("\n> Great. I will create the task from your approved request.\n"));
|
|
3782
3813
|
const { plan: plan2 } = await import("./plan-RHDFDSZE.js");
|
|
3783
3814
|
await plan2(approvedRequest, { conversational: true });
|
|
@@ -3786,7 +3817,140 @@ async function applyApprovedProposal(cwd) {
|
|
|
3786
3817
|
return;
|
|
3787
3818
|
}
|
|
3788
3819
|
await showLatestPlannedAtom(cwd);
|
|
3789
|
-
console.log(chalk5.dim('\nReply "
|
|
3820
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3821
|
+
}
|
|
3822
|
+
async function provideAnalysisFirstPlan(cwd, request) {
|
|
3823
|
+
console.log(chalk5.dim("\n> I analyzed your request and generated a recommendation + sample draft first.\n"));
|
|
3824
|
+
const markdownFiles = collectMarkdownFiles(cwd);
|
|
3825
|
+
const dayOneCandidates = markdownFiles.filter((file) => isDayOnePath(file));
|
|
3826
|
+
const capsuleCandidates = markdownFiles.filter((file) => /capsule/i.test(file));
|
|
3827
|
+
const primaryCandidates = dayOneCandidates.length > 0 ? dayOneCandidates : capsuleCandidates;
|
|
3828
|
+
const reviewedFiles = primaryCandidates.slice(0, 8);
|
|
3829
|
+
const stats = computeContentStats(cwd, reviewedFiles);
|
|
3830
|
+
const recommendSplit = stats.totalWords > 900 || stats.totalHeadings >= 6;
|
|
3831
|
+
const capsuleCount = recommendSplit ? 2 : 1;
|
|
3832
|
+
console.log(chalk5.bold("Analysis summary (no atoms created):"));
|
|
3833
|
+
if (reviewedFiles.length === 0) {
|
|
3834
|
+
console.log(chalk5.dim(" - I did not find obvious day-1 capsule markdown files automatically."));
|
|
3835
|
+
console.log(chalk5.dim(" - Share the target file path and I will evaluate it directly."));
|
|
3836
|
+
} else {
|
|
3837
|
+
console.log(chalk5.dim(" Files reviewed:"));
|
|
3838
|
+
for (const file of reviewedFiles) {
|
|
3839
|
+
console.log(chalk5.dim(` - ${file}`));
|
|
3840
|
+
}
|
|
3841
|
+
console.log(chalk5.dim(` Content signals: ~${stats.totalWords} words, ${stats.totalHeadings} section headings.`));
|
|
3842
|
+
}
|
|
3843
|
+
console.log();
|
|
3844
|
+
console.log(chalk5.bold("Recommendation:"));
|
|
3845
|
+
if (reviewedFiles.length === 0) {
|
|
3846
|
+
console.log(chalk5.dim(" I need the exact day-1 capsule file path to make a reliable one-vs-many capsule recommendation."));
|
|
3847
|
+
} else if (recommendSplit) {
|
|
3848
|
+
console.log(chalk5.dim(` Split day 1 into ${capsuleCount} capsules for clarity and lower cognitive load.`));
|
|
3849
|
+
} else {
|
|
3850
|
+
console.log(chalk5.dim(" Keep day 1 as one capsule to preserve continuity and reduce context switching."));
|
|
3851
|
+
}
|
|
3852
|
+
console.log();
|
|
3853
|
+
console.log(chalk5.bold("Implementation plan (proposed):"));
|
|
3854
|
+
console.log(chalk5.dim(" 1. Confirm target source file(s) for day 1 content."));
|
|
3855
|
+
console.log(chalk5.dim(` 2. Define capsule boundaries and titles (${capsuleCount} capsule${capsuleCount > 1 ? "s" : ""}).`));
|
|
3856
|
+
console.log(chalk5.dim(" 3. Draft capsule markdown(s) with consistent template and learning objective per capsule."));
|
|
3857
|
+
console.log(chalk5.dim(" 4. Add index/manifest links and quick validation checks for user flow."));
|
|
3858
|
+
const sampleDraft = buildSampleCapsuleDraft(cwd, reviewedFiles, capsuleCount);
|
|
3859
|
+
if (sampleDraft) {
|
|
3860
|
+
console.log();
|
|
3861
|
+
console.log(chalk5.bold("Sample output for day 1 (draft):"));
|
|
3862
|
+
console.log(sampleDraft);
|
|
3863
|
+
}
|
|
3864
|
+
pendingAnalysisToAtomRequest = request;
|
|
3865
|
+
console.log();
|
|
3866
|
+
console.log(chalk5.dim('Reply "save this" (or "create atom") if you want me to implement this in governed mode.'));
|
|
3867
|
+
}
|
|
3868
|
+
function collectMarkdownFiles(cwd) {
|
|
3869
|
+
const results = [];
|
|
3870
|
+
const queue = ["."];
|
|
3871
|
+
const skipDirs = /* @__PURE__ */ new Set([".git", "node_modules", ".archon", "dist", "build", ".next", ".turbo"]);
|
|
3872
|
+
while (queue.length > 0 && results.length < 200) {
|
|
3873
|
+
const current = queue.shift();
|
|
3874
|
+
if (!current) break;
|
|
3875
|
+
const abs = join6(cwd, current);
|
|
3876
|
+
let entries;
|
|
3877
|
+
try {
|
|
3878
|
+
entries = readdirSync3(abs, { withFileTypes: true });
|
|
3879
|
+
} catch {
|
|
3880
|
+
continue;
|
|
3881
|
+
}
|
|
3882
|
+
for (const entry of entries) {
|
|
3883
|
+
const rel = current === "." ? entry.name : join6(current, entry.name);
|
|
3884
|
+
if (entry.isDirectory()) {
|
|
3885
|
+
if (!skipDirs.has(entry.name)) {
|
|
3886
|
+
queue.push(rel);
|
|
3887
|
+
}
|
|
3888
|
+
continue;
|
|
3889
|
+
}
|
|
3890
|
+
if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
|
|
3891
|
+
results.push(relative(cwd, join6(cwd, rel)).replace(/\\/g, "/"));
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
return results;
|
|
3896
|
+
}
|
|
3897
|
+
function computeContentStats(cwd, files) {
|
|
3898
|
+
let totalWords = 0;
|
|
3899
|
+
let totalHeadings = 0;
|
|
3900
|
+
for (const relPath of files) {
|
|
3901
|
+
try {
|
|
3902
|
+
const content = readFileSync3(join6(cwd, relPath), "utf-8");
|
|
3903
|
+
totalWords += content.split(/\s+/).filter(Boolean).length;
|
|
3904
|
+
totalHeadings += content.split("\n").filter((line) => line.trim().startsWith("#")).length;
|
|
3905
|
+
} catch {
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
return { totalWords, totalHeadings };
|
|
3909
|
+
}
|
|
3910
|
+
function isDayOnePath(path2) {
|
|
3911
|
+
const normalized = path2.toLowerCase();
|
|
3912
|
+
return /\b(day[-_ ]?0*1|lesson[-_ ]?0*1|email[-_ ]?day[-_ ]?0*1)\b/.test(normalized) && !/\b(day[-_ ]?(?:1[0-9]|[2-9])|lesson[-_ ]?(?:1[0-9]|[2-9]))\b/.test(normalized);
|
|
3913
|
+
}
|
|
3914
|
+
function buildSampleCapsuleDraft(cwd, files, capsuleCount) {
|
|
3915
|
+
if (files.length === 0) return null;
|
|
3916
|
+
const primary = files[0];
|
|
3917
|
+
if (!primary) return null;
|
|
3918
|
+
let content = "";
|
|
3919
|
+
try {
|
|
3920
|
+
content = readFileSync3(join6(cwd, primary), "utf-8");
|
|
3921
|
+
} catch {
|
|
3922
|
+
return null;
|
|
3923
|
+
}
|
|
3924
|
+
const lines = content.split("\n").map((line) => line.trim());
|
|
3925
|
+
const heading = lines.find((line) => line.startsWith("#"))?.replace(/^#+\s*/, "") || "Day 1 Lesson";
|
|
3926
|
+
const paragraphs = content.split("\n\n").map((p) => p.replace(/\s+/g, " ").trim()).filter((p) => p.length > 40 && !p.startsWith("#") && !p.startsWith("- ") && !p.startsWith("* "));
|
|
3927
|
+
const objective = paragraphs[0] ?? "Introduce the day-1 core idea with a clear, practical framing.";
|
|
3928
|
+
const concept = paragraphs[1] ?? "Explain the key concept in plain language with one relatable example.";
|
|
3929
|
+
const practice = paragraphs[2] ?? "Give one guided prompt so the learner can apply the idea immediately.";
|
|
3930
|
+
if (capsuleCount <= 1) {
|
|
3931
|
+
return [
|
|
3932
|
+
chalk5.dim(" ---"),
|
|
3933
|
+
chalk5.dim(` title: "${heading} - Core Capsule"`),
|
|
3934
|
+
chalk5.dim(' type: "lesson_capsule"'),
|
|
3935
|
+
chalk5.dim(" day: 1"),
|
|
3936
|
+
chalk5.dim(" ---"),
|
|
3937
|
+
chalk5.dim(" ## Objective"),
|
|
3938
|
+
chalk5.dim(` ${objective}`),
|
|
3939
|
+
chalk5.dim(" ## Core Concept"),
|
|
3940
|
+
chalk5.dim(` ${concept}`),
|
|
3941
|
+
chalk5.dim(" ## Practice"),
|
|
3942
|
+
chalk5.dim(` ${practice}`)
|
|
3943
|
+
].join("\n");
|
|
3944
|
+
}
|
|
3945
|
+
return [
|
|
3946
|
+
chalk5.dim(" Capsule 1: Foundation"),
|
|
3947
|
+
chalk5.dim(` - Objective: ${objective}`),
|
|
3948
|
+
chalk5.dim(` - Core Concept: ${concept}`),
|
|
3949
|
+
chalk5.dim(""),
|
|
3950
|
+
chalk5.dim(" Capsule 2: Application"),
|
|
3951
|
+
chalk5.dim(` - Guided Practice: ${practice}`),
|
|
3952
|
+
chalk5.dim(" - Reflection Prompt: What changed in your understanding after this exercise?")
|
|
3953
|
+
].join("\n");
|
|
3790
3954
|
}
|
|
3791
3955
|
async function continueWithCurrentTask(cwd) {
|
|
3792
3956
|
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-RHDFDSZE.js");
|
|
@@ -3922,6 +4086,10 @@ function containsActionIntent(input) {
|
|
|
3922
4086
|
async function handlePostExploreAction(cwd, request, options = {}) {
|
|
3923
4087
|
const sourceInput = options.originalInput?.trim() || request;
|
|
3924
4088
|
if (wantsProposalBeforeExecution(sourceInput)) {
|
|
4089
|
+
if (shouldDoAnalysisBeforeAtom(sourceInput)) {
|
|
4090
|
+
await provideAnalysisFirstPlan(cwd, sourceInput);
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
3925
4093
|
await showProposalForApproval(sourceInput);
|
|
3926
4094
|
return;
|
|
3927
4095
|
}
|
|
@@ -3944,7 +4112,7 @@ async function handlePostExploreAction(cwd, request, options = {}) {
|
|
|
3944
4112
|
return;
|
|
3945
4113
|
}
|
|
3946
4114
|
await showLatestPlannedAtom(cwd);
|
|
3947
|
-
console.log(chalk5.dim('\nReply "
|
|
4115
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3948
4116
|
}
|
|
3949
4117
|
}
|
|
3950
4118
|
async function planTask() {
|