archondev 2.19.29 → 2.19.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.js +118 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,6 +121,8 @@ 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.
|
|
124
126
|
|
|
125
127
|
**Tip:** Use `archon plan --edit` to adjust title and acceptance criteria before planning.
|
|
126
128
|
**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
|
}
|
|
@@ -3706,7 +3718,7 @@ async function handleAgentConversationInput(cwd, input) {
|
|
|
3706
3718
|
return true;
|
|
3707
3719
|
}
|
|
3708
3720
|
await showLatestPlannedAtom(cwd);
|
|
3709
|
-
console.log(chalk5.dim('\nReply "
|
|
3721
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3710
3722
|
return true;
|
|
3711
3723
|
}
|
|
3712
3724
|
function isReadOnlyExploreRequest(input) {
|
|
@@ -3733,6 +3745,7 @@ function wantsProposalBeforeExecution(input) {
|
|
|
3733
3745
|
}
|
|
3734
3746
|
async function showProposalForApproval(input) {
|
|
3735
3747
|
pendingProposalRequest = input.trim();
|
|
3748
|
+
pendingProposalMode = shouldDoAnalysisBeforeAtom(input) ? "analysis" : "atom";
|
|
3736
3749
|
console.log(chalk5.dim("\n> Understood. I will not create atoms yet.\n"));
|
|
3737
3750
|
console.log(chalk5.bold("Proposed plan (for your approval):"));
|
|
3738
3751
|
console.log(chalk5.dim(" 1. Review project files and locate the capsule markdown/source for day 1."));
|
|
@@ -3766,18 +3779,32 @@ Showing latest planned atom (${latest.externalId})...
|
|
|
3766
3779
|
const { show: show2 } = await import("./show-7A3FACN6.js");
|
|
3767
3780
|
await show2(latest.externalId);
|
|
3768
3781
|
}
|
|
3769
|
-
function
|
|
3782
|
+
function isPlanApprovalDirective(input) {
|
|
3770
3783
|
const normalized = input.trim().toLowerCase();
|
|
3771
|
-
return normalized === "
|
|
3784
|
+
return normalized === "approve" || normalized === "approve plan" || normalized === "approved" || normalized === "yes" || normalized === "yes, proceed" || normalized === "proceed";
|
|
3772
3785
|
}
|
|
3773
|
-
function
|
|
3786
|
+
function isExecutionDirective(input) {
|
|
3774
3787
|
const normalized = input.trim().toLowerCase();
|
|
3775
|
-
return normalized === "
|
|
3788
|
+
return normalized === "execute" || normalized === "execute atom" || normalized === "run atom" || normalized === "run it now" || normalized === "implement now" || normalized === "start execution" || normalized === "go ahead and execute";
|
|
3789
|
+
}
|
|
3790
|
+
function isCreateAtomDirective(input) {
|
|
3791
|
+
const normalized = input.trim().toLowerCase();
|
|
3792
|
+
return normalized === "create atom" || normalized === "make atom" || normalized === "save as atom" || normalized === "turn this into a task" || normalized === "create task";
|
|
3793
|
+
}
|
|
3794
|
+
function shouldDoAnalysisBeforeAtom(input) {
|
|
3795
|
+
const normalized = input.toLowerCase();
|
|
3796
|
+
const hasAnalysisIntent = /\b(review|analy[sz]e|inspect|read)\b/.test(normalized) && /\b(files?|folder|project|markdown|lesson|capsule)\b/.test(normalized);
|
|
3797
|
+
const asksForPlan = /\b(let me know|what your plan is|plan is|how to implement|before creating|before you implement)\b/.test(normalized);
|
|
3798
|
+
return hasAnalysisIntent && asksForPlan;
|
|
3776
3799
|
}
|
|
3777
3800
|
async function applyApprovedProposal(cwd) {
|
|
3778
3801
|
const approvedRequest = pendingProposalRequest;
|
|
3779
3802
|
if (!approvedRequest) return;
|
|
3780
3803
|
pendingProposalRequest = null;
|
|
3804
|
+
if (pendingProposalMode === "analysis") {
|
|
3805
|
+
await provideAnalysisFirstPlan(cwd, approvedRequest);
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3781
3808
|
console.log(chalk5.dim("\n> Great. I will create the task from your approved request.\n"));
|
|
3782
3809
|
const { plan: plan2 } = await import("./plan-RHDFDSZE.js");
|
|
3783
3810
|
await plan2(approvedRequest, { conversational: true });
|
|
@@ -3786,7 +3813,89 @@ async function applyApprovedProposal(cwd) {
|
|
|
3786
3813
|
return;
|
|
3787
3814
|
}
|
|
3788
3815
|
await showLatestPlannedAtom(cwd);
|
|
3789
|
-
console.log(chalk5.dim('\nReply "
|
|
3816
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3817
|
+
}
|
|
3818
|
+
async function provideAnalysisFirstPlan(cwd, request) {
|
|
3819
|
+
console.log(chalk5.dim("\n> Great. I will analyze first and return a concrete recommendation before creating atoms.\n"));
|
|
3820
|
+
const markdownFiles = collectMarkdownFiles(cwd);
|
|
3821
|
+
const dayOneCandidates = markdownFiles.filter((file) => /(day[-_ ]?0?1|lesson[-_ ]?0?1|first)/i.test(file));
|
|
3822
|
+
const capsuleCandidates = markdownFiles.filter((file) => /capsule/i.test(file));
|
|
3823
|
+
const primaryCandidates = dayOneCandidates.length > 0 ? dayOneCandidates : capsuleCandidates;
|
|
3824
|
+
const reviewedFiles = primaryCandidates.slice(0, 8);
|
|
3825
|
+
const stats = computeContentStats(cwd, reviewedFiles);
|
|
3826
|
+
const recommendSplit = stats.totalWords > 900 || stats.totalHeadings >= 6;
|
|
3827
|
+
const capsuleCount = recommendSplit ? 2 : 1;
|
|
3828
|
+
console.log(chalk5.bold("Analysis summary (no atoms created):"));
|
|
3829
|
+
if (reviewedFiles.length === 0) {
|
|
3830
|
+
console.log(chalk5.dim(" - I did not find obvious day-1 capsule markdown files automatically."));
|
|
3831
|
+
console.log(chalk5.dim(" - Share the target file path and I will evaluate it directly."));
|
|
3832
|
+
} else {
|
|
3833
|
+
console.log(chalk5.dim(" Files reviewed:"));
|
|
3834
|
+
for (const file of reviewedFiles) {
|
|
3835
|
+
console.log(chalk5.dim(` - ${file}`));
|
|
3836
|
+
}
|
|
3837
|
+
console.log(chalk5.dim(` Content signals: ~${stats.totalWords} words, ${stats.totalHeadings} section headings.`));
|
|
3838
|
+
}
|
|
3839
|
+
console.log();
|
|
3840
|
+
console.log(chalk5.bold("Recommendation:"));
|
|
3841
|
+
if (reviewedFiles.length === 0) {
|
|
3842
|
+
console.log(chalk5.dim(" I need the exact day-1 capsule file path to make a reliable one-vs-many capsule recommendation."));
|
|
3843
|
+
} else if (recommendSplit) {
|
|
3844
|
+
console.log(chalk5.dim(` Split day 1 into ${capsuleCount} capsules for clarity and lower cognitive load.`));
|
|
3845
|
+
} else {
|
|
3846
|
+
console.log(chalk5.dim(" Keep day 1 as one capsule to preserve continuity and reduce context switching."));
|
|
3847
|
+
}
|
|
3848
|
+
console.log();
|
|
3849
|
+
console.log(chalk5.bold("Implementation plan (proposed):"));
|
|
3850
|
+
console.log(chalk5.dim(" 1. Confirm target source file(s) for day 1 content."));
|
|
3851
|
+
console.log(chalk5.dim(` 2. Define capsule boundaries and titles (${capsuleCount} capsule${capsuleCount > 1 ? "s" : ""}).`));
|
|
3852
|
+
console.log(chalk5.dim(" 3. Draft capsule markdown(s) with consistent template and learning objective per capsule."));
|
|
3853
|
+
console.log(chalk5.dim(" 4. Add index/manifest links and quick validation checks for user flow."));
|
|
3854
|
+
pendingAnalysisToAtomRequest = request;
|
|
3855
|
+
console.log();
|
|
3856
|
+
console.log(chalk5.dim('Reply "create atom" to save this as a governed task, or tell me what to adjust first.'));
|
|
3857
|
+
}
|
|
3858
|
+
function collectMarkdownFiles(cwd) {
|
|
3859
|
+
const results = [];
|
|
3860
|
+
const queue = ["."];
|
|
3861
|
+
const skipDirs = /* @__PURE__ */ new Set([".git", "node_modules", ".archon", "dist", "build", ".next", ".turbo"]);
|
|
3862
|
+
while (queue.length > 0 && results.length < 200) {
|
|
3863
|
+
const current = queue.shift();
|
|
3864
|
+
if (!current) break;
|
|
3865
|
+
const abs = join6(cwd, current);
|
|
3866
|
+
let entries;
|
|
3867
|
+
try {
|
|
3868
|
+
entries = readdirSync3(abs, { withFileTypes: true });
|
|
3869
|
+
} catch {
|
|
3870
|
+
continue;
|
|
3871
|
+
}
|
|
3872
|
+
for (const entry of entries) {
|
|
3873
|
+
const rel = current === "." ? entry.name : join6(current, entry.name);
|
|
3874
|
+
if (entry.isDirectory()) {
|
|
3875
|
+
if (!skipDirs.has(entry.name)) {
|
|
3876
|
+
queue.push(rel);
|
|
3877
|
+
}
|
|
3878
|
+
continue;
|
|
3879
|
+
}
|
|
3880
|
+
if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
|
|
3881
|
+
results.push(relative(cwd, join6(cwd, rel)).replace(/\\/g, "/"));
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
return results;
|
|
3886
|
+
}
|
|
3887
|
+
function computeContentStats(cwd, files) {
|
|
3888
|
+
let totalWords = 0;
|
|
3889
|
+
let totalHeadings = 0;
|
|
3890
|
+
for (const relPath of files) {
|
|
3891
|
+
try {
|
|
3892
|
+
const content = readFileSync3(join6(cwd, relPath), "utf-8");
|
|
3893
|
+
totalWords += content.split(/\s+/).filter(Boolean).length;
|
|
3894
|
+
totalHeadings += content.split("\n").filter((line) => line.trim().startsWith("#")).length;
|
|
3895
|
+
} catch {
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
return { totalWords, totalHeadings };
|
|
3790
3899
|
}
|
|
3791
3900
|
async function continueWithCurrentTask(cwd) {
|
|
3792
3901
|
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-RHDFDSZE.js");
|
|
@@ -3944,7 +4053,7 @@ async function handlePostExploreAction(cwd, request, options = {}) {
|
|
|
3944
4053
|
return;
|
|
3945
4054
|
}
|
|
3946
4055
|
await showLatestPlannedAtom(cwd);
|
|
3947
|
-
console.log(chalk5.dim('\nReply "
|
|
4056
|
+
console.log(chalk5.dim('\nReply "execute atom" when you want implementation to start, or tell me what to change.'));
|
|
3948
4057
|
}
|
|
3949
4058
|
}
|
|
3950
4059
|
async function planTask() {
|