auxilo-mcp 0.9.11 → 0.9.12
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/bin/auxilo-cli.js +60 -0
- package/lib/installer.js +62 -2
- package/mcp-server.js +1 -1
- package/package.json +1 -1
- package/scripts/extract-local.js +27 -11
package/bin/auxilo-cli.js
CHANGED
|
@@ -493,6 +493,10 @@ async function cmdStatus() {
|
|
|
493
493
|
console.log(`Account mode: ${s.accountMode}`);
|
|
494
494
|
console.log(`Kill-switch sentinel: ${s.sentinel ? 'present (extraction enabled)' : 'absent (extraction disabled)'}`);
|
|
495
495
|
console.log(`Runner installed: ${s.runnerInstalled ? 'yes (~/.auxilo/bin)' : 'no'}`);
|
|
496
|
+
if (s.runnerInstalled) {
|
|
497
|
+
const line = runnerSkewLine(installer.runnerVersionSkew(HOME));
|
|
498
|
+
if (line) console.log(line);
|
|
499
|
+
}
|
|
496
500
|
console.log(`SessionEnd hook: ${s.hookInstalled ? 'installed' : 'not installed'}${s.hookRegistered ? ', registered in Claude Code settings' : ''}`);
|
|
497
501
|
for (const c of s.clients.filter((c) => c.captureHook)) {
|
|
498
502
|
console.log(`Capture hooks: ${c.name} (${c.captureEvent}, ${c.captureRegistered ? 'registered' : 'not registered'})`);
|
|
@@ -501,6 +505,17 @@ async function cmdStatus() {
|
|
|
501
505
|
console.log(`Pending upload queue: ${s.pendingCount} file(s)\n`);
|
|
502
506
|
}
|
|
503
507
|
|
|
508
|
+
/**
|
|
509
|
+
* CLEAN-LANE-FLIP Phase B: ONE line when ~/.auxilo/bin/VERSION is missing or
|
|
510
|
+
* differs from this CLI's package version; null when the stack is current.
|
|
511
|
+
* `setup` is idempotent and re-copies the stack, so that is the remedy.
|
|
512
|
+
*/
|
|
513
|
+
function runnerSkewLine(skew) {
|
|
514
|
+
if (!skew || !skew.skew) return null;
|
|
515
|
+
const installed = skew.installed ? `v${skew.installed}` : 'unstamped (pre-0.9.12)';
|
|
516
|
+
return ` ⚠ Installed runner is ${installed} (package v${skew.package}) — run: npx auxilo setup`;
|
|
517
|
+
}
|
|
518
|
+
|
|
504
519
|
// ─── auxilo disable ─────────────────────────────────────────────────────────
|
|
505
520
|
|
|
506
521
|
async function cmdDisable(flags) {
|
|
@@ -879,6 +894,20 @@ async function cmdReview(flags) {
|
|
|
879
894
|
// from GET /account/clean-lane (consent_version_current).
|
|
880
895
|
const CLEAN_LANE_AFFIRMATION = 'I understand and choose auto-publish for qualifying extracted learnings.';
|
|
881
896
|
const CLEAN_LANE_UNAVAILABLE = 'Auto-publish for clean learnings is not yet available on this account.';
|
|
897
|
+
// CLEAN-LANE-FLIP Phase B (legal; DRAFT pending Tyler): the full text of ToS
|
|
898
|
+
// §5.9.3(g) (plus its ratchet paragraph) prints ABOVE the affirmation prompt —
|
|
899
|
+
// counsel condition: the enrollment surface must show what "qualifying",
|
|
900
|
+
// revocation and the 7-day retraction mean, on both the dashboard and CLI
|
|
901
|
+
// paths. Same package-boundary reason as the affirmation: these literals are
|
|
902
|
+
// pinned byte-equal to docs/TERMS-OF-SERVICE.md and public/dashboard.html by
|
|
903
|
+
// test/clean-lane-phase-b-legal.test.js. Edit the Terms first, then mirror.
|
|
904
|
+
const CLEAN_LANE_TERMS_G = '(g) Standing publication consent (optional). Standing publication consent is off by default. A Builder may turn it on by an affirmative act — a dashboard setting, or a terminal command that requires typing the affirmation sentence shown on that screen. Auxilo records that act, the affirmation, and the consent-text version in a durable, hash-chained consent log, retained for the life of the account plus three (3) years under subsection (b). While it is on, a Learning submitted through Autonomous Extraction is published without separate per-item approval only if it passes every Platform screen and the quality threshold the Builder chose at activation. An account\'s first public Learning is never published this way; it is held for operator review under Section 4.1. Auxilo records each such publication in the Builder\'s dashboard and returns a notice in the response to the submission that produced it; each is retractable for seven (7) days under Section 5.9.4. If more than five percent (5%) of a Builder\'s Learnings published this way in any thirty (30) day period are retracted, Auxilo freezes the feature for that account until the Builder turns it on again. A Builder may turn it off at any time, effective immediately for later submissions; doing so does not affect Learnings already published. Subsection (c) applies in full to every Learning so published.';
|
|
905
|
+
const CLEAN_LANE_TERMS_G2 = 'The quality threshold in effect for a Builder is the one that Builder selected, and Auxilo will not broaden the conditions under which a Learning qualifies for publication under this subsection without recording a new consent; Auxilo may make those conditions stricter at any time.';
|
|
906
|
+
// CLEAN-LANE-FLIP Phase B (notice hardening): the no-email enrollment line —
|
|
907
|
+
// GOV-2 counsel draft §6 read #2 "move 3" — printed verbatim before the
|
|
908
|
+
// affirmation prompt on every enrollment surface. Byte-equal to the dashboard's
|
|
909
|
+
// #clean-lane-no-email-line (test/clean-lane-phase-b-notice.test.js).
|
|
910
|
+
const CLEAN_LANE_NO_EMAIL_LINE = 'You will not receive an email for these. Publications appear in your dashboard and in the response to the session that submitted them. The 7-day retraction window runs from publication.';
|
|
882
911
|
const CLEAN_LANE_MIN_QUALITY_MIN = 14;
|
|
883
912
|
const CLEAN_LANE_MIN_QUALITY_MAX = 20;
|
|
884
913
|
const CLEAN_LANE_MIN_QUALITY_DEFAULT = 16;
|
|
@@ -897,6 +926,18 @@ and anything after an auto-freeze. Every auto-published learning can be
|
|
|
897
926
|
retracted for 7 days (\`npx auxilo review\` or your dashboard).
|
|
898
927
|
`;
|
|
899
928
|
|
|
929
|
+
/** Word-wrap a single paragraph at `width` columns (whitespace only; no word is altered). */
|
|
930
|
+
function wrapForTerminal(paragraph, width = 78) {
|
|
931
|
+
const lines = [];
|
|
932
|
+
let line = '';
|
|
933
|
+
for (const word of paragraph.split(' ')) {
|
|
934
|
+
if (line && (line.length + 1 + word.length) > width) { lines.push(line); line = word; }
|
|
935
|
+
else line = line ? `${line} ${word}` : word;
|
|
936
|
+
}
|
|
937
|
+
if (line) lines.push(line);
|
|
938
|
+
return lines.map((l) => ` ${l}`).join('\n');
|
|
939
|
+
}
|
|
940
|
+
|
|
900
941
|
async function cleanLaneRequest({ apiKey, baseUrl, method, route, body }) {
|
|
901
942
|
const url = `${String(baseUrl).replace(/\/+$/, '')}${route}`;
|
|
902
943
|
const headers = { 'X-API-Key': apiKey };
|
|
@@ -927,6 +968,12 @@ function printCleanLaneStatus(data) {
|
|
|
927
968
|
console.log(` a grant exists under consent version ${data.consent_version_recorded} but the current version is ${data.consent_version_current}; re-grant to re-activate.`);
|
|
928
969
|
}
|
|
929
970
|
console.log(` current consent version: ${data.consent_version_current}`);
|
|
971
|
+
// CLEAN-LANE-FLIP Phase B (notice hardening): the unread count, printed only
|
|
972
|
+
// when > 0. Nothing here acknowledges it — only the dashboard button does.
|
|
973
|
+
const unread = data.unacknowledged_publications;
|
|
974
|
+
if (Number.isInteger(unread) && unread > 0) {
|
|
975
|
+
console.log(` auto-published since you last checked: ${unread} (review and acknowledge them in your dashboard)`);
|
|
976
|
+
}
|
|
930
977
|
}
|
|
931
978
|
|
|
932
979
|
async function cmdCleanLane(flags) {
|
|
@@ -1011,6 +1058,14 @@ async function cmdCleanLane(flags) {
|
|
|
1011
1058
|
console.log(`Enter a whole number from ${CLEAN_LANE_MIN_QUALITY_MIN} to ${CLEAN_LANE_MIN_QUALITY_MAX}.`);
|
|
1012
1059
|
}
|
|
1013
1060
|
|
|
1061
|
+
// The consent text itself, verbatim (word-wrapped for the terminal only), before the sentence.
|
|
1062
|
+
console.log('\nTerms of Service, Section 5.9.3(g): the consent you are giving\n');
|
|
1063
|
+
console.log(wrapForTerminal(CLEAN_LANE_TERMS_G));
|
|
1064
|
+
console.log('');
|
|
1065
|
+
console.log(wrapForTerminal(CLEAN_LANE_TERMS_G2));
|
|
1066
|
+
console.log(`\nFull Terms: ${baseUrl}/terms`);
|
|
1067
|
+
// The no-email line, verbatim, directly before the affirmation prompt.
|
|
1068
|
+
console.log(`\n${wrapForTerminal(CLEAN_LANE_NO_EMAIL_LINE)}`);
|
|
1014
1069
|
console.log('\nTo turn on auto-publish, type this sentence exactly as written, then press Enter:');
|
|
1015
1070
|
console.log(`\n ${CLEAN_LANE_AFFIRMATION}\n`);
|
|
1016
1071
|
const typed = await ask('> ');
|
|
@@ -1204,6 +1259,7 @@ if (require.main === module) {
|
|
|
1204
1259
|
|
|
1205
1260
|
module.exports = {
|
|
1206
1261
|
parseFlags,
|
|
1262
|
+
runnerSkewLine,
|
|
1207
1263
|
resolveBaseUrl,
|
|
1208
1264
|
shortFlags,
|
|
1209
1265
|
groupSummaryRows,
|
|
@@ -1212,4 +1268,8 @@ module.exports = {
|
|
|
1212
1268
|
run,
|
|
1213
1269
|
CLEAN_LANE_AFFIRMATION,
|
|
1214
1270
|
CLEAN_LANE_UNAVAILABLE,
|
|
1271
|
+
CLEAN_LANE_TERMS_G,
|
|
1272
|
+
CLEAN_LANE_TERMS_G2,
|
|
1273
|
+
CLEAN_LANE_NO_EMAIL_LINE,
|
|
1274
|
+
wrapForTerminal,
|
|
1215
1275
|
};
|
package/lib/installer.js
CHANGED
|
@@ -792,10 +792,18 @@ exit 0
|
|
|
792
792
|
* relative layout runner.js requires. Missing package files throw — the lib
|
|
793
793
|
* never calls process.exit.
|
|
794
794
|
*
|
|
795
|
+
* CLEAN-LANE-FLIP Phase B: the install also stamps <bin>/VERSION with the
|
|
796
|
+
* package version read from <packageRoot>/package.json at install time, so
|
|
797
|
+
* `auxilo status` can tell a stale copied stack from the CLI that is running
|
|
798
|
+
* (npx resolves a fresh auxilo-mcp; ~/.auxilo/bin keeps whatever setup last
|
|
799
|
+
* copied). VERSION is a stamp, not a stack row — it is deliberately NOT in
|
|
800
|
+
* RUNNER_STACK (test/runner-packaging-closure.test.js walks the require
|
|
801
|
+
* closure against the stack, and a version file is not code).
|
|
802
|
+
*
|
|
795
803
|
* @param {string} homeDir
|
|
796
804
|
* @param {object} [opts]
|
|
797
805
|
* @param {string} [opts.packageRoot=PACKAGE_ROOT]
|
|
798
|
-
* @returns {{ binRoot: string, hookPath: string, installed: string[] }}
|
|
806
|
+
* @returns {{ binRoot: string, hookPath: string, versionPath: string, version: string, installed: string[] }}
|
|
799
807
|
*/
|
|
800
808
|
function installRunner(homeDir, opts = {}) {
|
|
801
809
|
if (!homeDir) throw new Error('installRunner: homeDir is required');
|
|
@@ -820,7 +828,55 @@ function installRunner(homeDir, opts = {}) {
|
|
|
820
828
|
fs.chmodSync(hookPath, 0o755);
|
|
821
829
|
installed.push(hookPath);
|
|
822
830
|
|
|
823
|
-
|
|
831
|
+
const version = packageVersion(packageRoot);
|
|
832
|
+
const versionPath = runnerVersionPath(homeDir);
|
|
833
|
+
fs.writeFileSync(versionPath, `${version}\n`);
|
|
834
|
+
fs.chmodSync(versionPath, 0o644);
|
|
835
|
+
installed.push(versionPath);
|
|
836
|
+
|
|
837
|
+
return { binRoot, hookPath, versionPath, version, installed };
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// ─── Runner-stack freshness (CLEAN-LANE-FLIP Phase B) ───────────────────────
|
|
841
|
+
|
|
842
|
+
/** <home>/.auxilo/bin/VERSION — the package version installRunner last copied. */
|
|
843
|
+
function runnerVersionPath(homeDir) {
|
|
844
|
+
return path.join(binRootFor(homeDir), 'VERSION');
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/** Package version as shipped in <packageRoot>/package.json (throws if unreadable). */
|
|
848
|
+
function packageVersion(packageRoot = PACKAGE_ROOT) {
|
|
849
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
|
|
850
|
+
if (!pkg || typeof pkg.version !== 'string' || !pkg.version) {
|
|
851
|
+
throw new Error(`packageVersion: no version in ${path.join(packageRoot, 'package.json')}`);
|
|
852
|
+
}
|
|
853
|
+
return pkg.version;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/** Installed runner stamp, or null when the stamp is missing/unreadable (pre-0.9.12 installs). */
|
|
857
|
+
function installedRunnerVersion(homeDir) {
|
|
858
|
+
try {
|
|
859
|
+
const v = fs.readFileSync(runnerVersionPath(homeDir), 'utf-8').trim();
|
|
860
|
+
return v || null;
|
|
861
|
+
} catch {
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Compare the copied runner stack against the running package.
|
|
868
|
+
*
|
|
869
|
+
* @param {string} homeDir
|
|
870
|
+
* @param {object} [opts]
|
|
871
|
+
* @param {string} [opts.packageRoot=PACKAGE_ROOT]
|
|
872
|
+
* @returns {{ installed: string|null, package: string, skew: boolean }}
|
|
873
|
+
* skew is true when the stamp is missing OR differs from the package version.
|
|
874
|
+
*/
|
|
875
|
+
function runnerVersionSkew(homeDir, opts = {}) {
|
|
876
|
+
if (!homeDir) throw new Error('runnerVersionSkew: homeDir is required');
|
|
877
|
+
const installed = installedRunnerVersion(homeDir);
|
|
878
|
+
const pkg = packageVersion(opts.packageRoot || PACKAGE_ROOT);
|
|
879
|
+
return { installed, package: pkg, skew: installed !== pkg };
|
|
824
880
|
}
|
|
825
881
|
|
|
826
882
|
// ─── Claude Code hook registration (spec §LW-12 step 4) ─────────────────────
|
|
@@ -1704,6 +1760,10 @@ module.exports = {
|
|
|
1704
1760
|
hookScriptPathFor,
|
|
1705
1761
|
renderHookScript,
|
|
1706
1762
|
installRunner,
|
|
1763
|
+
runnerVersionPath,
|
|
1764
|
+
packageVersion,
|
|
1765
|
+
installedRunnerVersion,
|
|
1766
|
+
runnerVersionSkew,
|
|
1707
1767
|
registerClaudeCodeHook,
|
|
1708
1768
|
removeClaudeCodeHook,
|
|
1709
1769
|
captureShimPath,
|
package/mcp-server.js
CHANGED
|
@@ -198,7 +198,7 @@ async function postBulkChunks(headers, decisions) {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
const server = new Server(
|
|
201
|
-
{ name: 'auxilo', version: '0.9.
|
|
201
|
+
{ name: 'auxilo', version: '0.9.12' },
|
|
202
202
|
{
|
|
203
203
|
capabilities: { tools: {} },
|
|
204
204
|
instructions: `You are connected to Auxilo, a knowledge marketplace where AI agents buy and sell operational learnings.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auxilo-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"mcpName": "io.github.silent-architects/auxilo",
|
|
5
5
|
"description": "MCP server for Auxilo. Your agent stops solving the same problem twice: auto-extracted learnings, free self-unlocks, and earnings when other agents unlock yours.",
|
|
6
6
|
"main": "mcp-server.js",
|
package/scripts/extract-local.js
CHANGED
|
@@ -36,20 +36,36 @@ const PRIVATE_CATEGORIES = [...CATEGORIES, 'non-technical'];
|
|
|
36
36
|
const RETIRED_CATEGORIES = ['communication', 'content-generation'];
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* SPEC3 slice A1 gate — score-at-extraction,
|
|
39
|
+
* SPEC3 slice A1 gate — score-at-extraction, ON BY DEFAULT since 0.9.12
|
|
40
|
+
* (CLEAN-LANE-FLIP Phase B). Explicit opt-out only: AUXILO_SCORE_EXTRACTION=0
|
|
41
|
+
* (or 'false') disables scoring; any other value, including unset, scores.
|
|
40
42
|
*
|
|
41
|
-
* ┌─
|
|
42
|
-
* │
|
|
43
|
-
* │
|
|
44
|
-
* │
|
|
45
|
-
* │
|
|
46
|
-
* │
|
|
47
|
-
* │
|
|
48
|
-
* │
|
|
49
|
-
*
|
|
43
|
+
* ┌─ SEQUENCING CONSTRAINT — SATISFIED (SPEC3-BUILDER-REVIEW-LOOP §3.1/§8) ──┐
|
|
44
|
+
* │ This gate shipped dark (opt-in via AUXILO_SCORE_EXTRACTION=1) because │
|
|
45
|
+
* │ under a server WITHOUT the B1 extraction-channel hold, a clean /learn │
|
|
46
|
+
* │ submission carrying a floor-passing quality_self_assessment published │
|
|
47
|
+
* │ IMMEDIATELY (seamlessEligible) — arming scoring would have silently │
|
|
48
|
+
* │ flipped hook extraction from "everything held" to "clean items │
|
|
49
|
+
* │ auto-publish", an unrecorded consent change (2026-06-10 class). │
|
|
50
|
+
* │ │
|
|
51
|
+
* │ B1 SHIPPED (lib/clean-lane.js; server.js /learn): every submission │
|
|
52
|
+
* │ carrying submission_channel:'extraction' (runner.js stamps it │
|
|
53
|
+
* │ unconditionally) is HELD with reason 'standing_consent_off' unless the │
|
|
54
|
+
* │ account holds an active standing-consent grant — regardless of the │
|
|
55
|
+
* │ score. The server brake, not the absence of a score, is what keeps │
|
|
56
|
+
* │ unconsented items out of the catalog, so default-on scoring is safe: │
|
|
57
|
+
* │ the score can only move a held item into the ready_to_publish lane (one │
|
|
58
|
+
* │ counted approve away) or, under an active grant, into the clean lane the │
|
|
59
|
+
* │ contributor explicitly opted into. Without a score every extraction │
|
|
60
|
+
* │ submission held awaiting_quality forever, so a stock install could never │
|
|
61
|
+
* │ enter the clean lane at all — that was the Phase B defect this closes. │
|
|
62
|
+
* └──────────────────────────────────────────────────────────────────────────┘
|
|
50
63
|
*/
|
|
51
64
|
function scoreExtractionEnabled(env = process.env) {
|
|
52
|
-
|
|
65
|
+
const raw = env.AUXILO_SCORE_EXTRACTION;
|
|
66
|
+
if (raw === undefined || raw === null) return true;
|
|
67
|
+
const v = String(raw).trim().toLowerCase();
|
|
68
|
+
return !(v === '0' || v === 'false');
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
const EXTRACTION_PROMPT_BASE = `You are extracting reusable OPERATIONAL LEARNINGS from an AI agent's session transcript, to publish to a PUBLIC knowledge marketplace read by other AI agents.
|