@alisio/alisio-code 0.1.0-alpha.6 → 0.1.0-alpha.8
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/dist/main.js +5 -1
- package/dist/tui/app.js +112 -16
- package/dist/tui/state.d.ts +5 -5
- package/dist/tui/state.js +5 -4
- package/dist/version.d.ts +5 -3
- package/dist/version.js +11 -5
- package/package.json +8 -8
package/dist/main.js
CHANGED
|
@@ -127,6 +127,8 @@ async function run(cmd, prompt, sessionId) {
|
|
|
127
127
|
process.stderr.write(`\n→ ${event.data.name}\n`);
|
|
128
128
|
},
|
|
129
129
|
});
|
|
130
|
+
for (const failure of app.mcpStartupFailures())
|
|
131
|
+
process.stderr.write(`[startup] ${failure}\n`);
|
|
130
132
|
const controller = new AbortController();
|
|
131
133
|
const interrupt = () => controller.abort(new Error("Interrupted"));
|
|
132
134
|
process.on("SIGINT", interrupt);
|
|
@@ -253,7 +255,7 @@ program
|
|
|
253
255
|
console.log('To generate AGENTS.md for this project, run /init inside alisio (or: alisio run "/init" --allow-write).');
|
|
254
256
|
});
|
|
255
257
|
program.command("doctor").action(async (_opts, cmd) => {
|
|
256
|
-
const { findWorkspace, loadConfigWithProvenance, overridesSavedProviderProfile, ProviderSettingsStore, which, } = await import("@alisio/core");
|
|
258
|
+
const { findWorkspace, loadConfigWithProvenance, overridesSavedProviderProfile, ProviderSettingsStore, RIPGREP_INSTALL_HINT, which, } = await import("@alisio/core");
|
|
257
259
|
const o = options(cmd);
|
|
258
260
|
const workspace = await findWorkspace(o.cwd ?? process.cwd());
|
|
259
261
|
const { config, provenance } = await loadConfigWithProvenance(workspace, {
|
|
@@ -292,6 +294,8 @@ program.command("doctor").action(async (_opts, cmd) => {
|
|
|
292
294
|
},
|
|
293
295
|
};
|
|
294
296
|
console.log(JSON.stringify(status, null, 2));
|
|
297
|
+
if (!status.ripgrep)
|
|
298
|
+
process.stderr.write(`\nWarning: ripgrep (rg) is not installed; search_text and list_files will not work. ${RIPGREP_INSTALL_HINT}\n`);
|
|
295
299
|
if (!model || model === "YOUR_MODEL_ID")
|
|
296
300
|
console.error("\nNo model configured yet: set provider.model in your config, --model, or ALISIO_MODEL " +
|
|
297
301
|
"before starting a real conversation (it will otherwise fail on the first turn).");
|
package/dist/tui/app.js
CHANGED
|
@@ -102,6 +102,17 @@ export async function runTui(options) {
|
|
|
102
102
|
modelList = undefined;
|
|
103
103
|
throw e;
|
|
104
104
|
}));
|
|
105
|
+
/**
|
|
106
|
+
* Reloads the active-provider catalog and repaints when it lands, so the context bar learns
|
|
107
|
+
* the ACTIVE model's real window (previously only the first /model picker or autocomplete
|
|
108
|
+
* call loaded it, leaving a fabricated 40k total on screen). Called at startup and after
|
|
109
|
+
* every provider/model switch; the bar honestly shows `?` until the catalog arrives.
|
|
110
|
+
*/
|
|
111
|
+
const primeModels = () => {
|
|
112
|
+
void models()
|
|
113
|
+
.then(() => tui.requestRender())
|
|
114
|
+
.catch(() => { });
|
|
115
|
+
};
|
|
105
116
|
const terminal = new ProcessTerminal();
|
|
106
117
|
const copy = async (text) => copyText(text, {
|
|
107
118
|
platform: process.platform,
|
|
@@ -184,7 +195,7 @@ export async function runTui(options) {
|
|
|
184
195
|
const siblings = nodes.filter((n) => n.parentId === node.parentId);
|
|
185
196
|
const child = viewedState();
|
|
186
197
|
const budget = app.contextBudget(child?.model ?? view.model);
|
|
187
|
-
const pct = child?.context && budget
|
|
198
|
+
const pct = child?.context && budget?.total
|
|
188
199
|
? ` · ctx ${Math.round((child.context.used / budget.total) * 100)}%`
|
|
189
200
|
: "";
|
|
190
201
|
const tokens = child
|
|
@@ -239,6 +250,9 @@ export async function runTui(options) {
|
|
|
239
250
|
},
|
|
240
251
|
{ component: bottom, basis: "auto", shrink: 1, minSize: 3 },
|
|
241
252
|
]));
|
|
253
|
+
// Prime the active provider's catalog so the context bar shows the model's real window
|
|
254
|
+
// (or an honest `?`) instead of a fabricated total; repaint when the catalog lands.
|
|
255
|
+
primeModels();
|
|
242
256
|
const sync = () => {
|
|
243
257
|
main.sync(view.items);
|
|
244
258
|
tui.requestRender();
|
|
@@ -600,10 +614,34 @@ export async function runTui(options) {
|
|
|
600
614
|
placeholder: "provider-model-id",
|
|
601
615
|
hint: "The provider returned no model catalog",
|
|
602
616
|
step: inputFields.length + 1,
|
|
603
|
-
steps: inputFields.length +
|
|
617
|
+
steps: inputFields.length + 2,
|
|
604
618
|
});
|
|
605
619
|
if (!model)
|
|
606
620
|
return;
|
|
621
|
+
// Local servers like llama.cpp omit `context_window` from GET /models, so the bar would show
|
|
622
|
+
// an honest `?`. When the discovered catalog cannot name the window (or is empty), ask ONE
|
|
623
|
+
// optional numeric override and persist it in the profile values when provided.
|
|
624
|
+
const catalogEntry = discovered.find((candidate) => candidate.id === model);
|
|
625
|
+
if (!catalogEntry?.contextWindow) {
|
|
626
|
+
const windowStep = discovered.length ? inputFields.length + 1 : inputFields.length + 2;
|
|
627
|
+
const entered = await askInput({
|
|
628
|
+
provider: registration.name,
|
|
629
|
+
label: "Context window in tokens (optional)",
|
|
630
|
+
initial: profile.contextWindow === undefined ? "" : String(profile.contextWindow),
|
|
631
|
+
placeholder: "131072",
|
|
632
|
+
hint: "For local servers that omit context_window; leave empty to keep the saved value or stay unknown",
|
|
633
|
+
step: windowStep,
|
|
634
|
+
steps: windowStep,
|
|
635
|
+
});
|
|
636
|
+
if (entered === undefined)
|
|
637
|
+
return;
|
|
638
|
+
if (entered.trim()) {
|
|
639
|
+
const parsed = Number(entered.trim());
|
|
640
|
+
if (!Number.isInteger(parsed) || parsed <= 0)
|
|
641
|
+
return error("Context window must be a positive number of tokens");
|
|
642
|
+
profile.contextWindow = parsed;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
607
645
|
await app.activateProvider(providerId, profile, credentials, model);
|
|
608
646
|
activeProvider = app.providerInfo;
|
|
609
647
|
modelList = undefined;
|
|
@@ -611,6 +649,7 @@ export async function runTui(options) {
|
|
|
611
649
|
reset(initialViewState(model));
|
|
612
650
|
notice(`Connected to ${registration.name} with model ${model}. Started a fresh session.`);
|
|
613
651
|
refreshEstimate();
|
|
652
|
+
primeModels();
|
|
614
653
|
};
|
|
615
654
|
const chooseModel = async () => {
|
|
616
655
|
const catalogs = await app.configuredProviderCatalogs(AbortSignal.timeout(20_000));
|
|
@@ -635,6 +674,7 @@ export async function runTui(options) {
|
|
|
635
674
|
reset(initialViewState(selected.model));
|
|
636
675
|
notice(`Provider changed to ${app.providers.get(selected.provider)?.name ?? selected.provider} with model ${selected.model}. Started a fresh session.`);
|
|
637
676
|
refreshEstimate();
|
|
677
|
+
primeModels();
|
|
638
678
|
})
|
|
639
679
|
.catch(error);
|
|
640
680
|
}, closePicker, true));
|
|
@@ -719,9 +759,45 @@ export async function runTui(options) {
|
|
|
719
759
|
const manageMcp = () => {
|
|
720
760
|
const openCatalog = () => {
|
|
721
761
|
const entries = app.mcp.list();
|
|
722
|
-
|
|
762
|
+
const serverItems = mcpServerItems(entries);
|
|
763
|
+
const items = [
|
|
764
|
+
...serverItems,
|
|
765
|
+
...(app.mcpAllowPersisted()
|
|
766
|
+
? [
|
|
767
|
+
{
|
|
768
|
+
value: "!revoke-global",
|
|
769
|
+
label: "Revoke global MCP consent",
|
|
770
|
+
description: "Clear mcp.allow from your user configuration and disconnect servers",
|
|
771
|
+
},
|
|
772
|
+
]
|
|
773
|
+
: []),
|
|
774
|
+
];
|
|
775
|
+
if (!items.length)
|
|
723
776
|
return notice("No MCP servers are configured");
|
|
724
|
-
showPicker(new Picker(`MCP servers (${entries.length})`,
|
|
777
|
+
showPicker(new Picker(`MCP servers (${entries.length})`, items, (item) => {
|
|
778
|
+
if (item.value === "!revoke-global") {
|
|
779
|
+
showPicker(new Picker("Revoke global MCP consent?", [
|
|
780
|
+
{
|
|
781
|
+
value: "revoke",
|
|
782
|
+
label: "Revoke and disconnect",
|
|
783
|
+
description: "Clears mcp.allow; future Alisio starts will not auto-grant or auto-connect MCP servers",
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
value: "cancel",
|
|
787
|
+
label: "Cancel",
|
|
788
|
+
description: "Keep global MCP consent enabled",
|
|
789
|
+
},
|
|
790
|
+
], (choice) => {
|
|
791
|
+
if (choice.value !== "revoke")
|
|
792
|
+
return openCatalog();
|
|
793
|
+
void app
|
|
794
|
+
.revokeGlobalMcpConsent()
|
|
795
|
+
.then(() => notice("Global MCP consent revoked. Runtime permission dropped and configured servers disconnected."))
|
|
796
|
+
.catch(error)
|
|
797
|
+
.finally(openCatalog);
|
|
798
|
+
}, openCatalog, false, "Removes mcp.allow from your user configuration (~/.config/alisio/config.json) atomically. This run's --allow-mcp flag, if given, keeps permission for this session."));
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
725
801
|
const selected = app.mcp.info(item.value);
|
|
726
802
|
const source = selected.source.kind === "global"
|
|
727
803
|
? "User"
|
|
@@ -801,11 +877,16 @@ export async function runTui(options) {
|
|
|
801
877
|
const run = () => void action().catch(error).finally(openCatalog);
|
|
802
878
|
if (app.mcpRuntimePermission() === "granted")
|
|
803
879
|
return run();
|
|
804
|
-
showPicker(new Picker("Grant MCP access
|
|
880
|
+
showPicker(new Picker("Grant MCP access?", [
|
|
881
|
+
{
|
|
882
|
+
value: "grant-session",
|
|
883
|
+
label: "Grant for this session only",
|
|
884
|
+
description: "May start the configured process or network connection; not saved",
|
|
885
|
+
},
|
|
805
886
|
{
|
|
806
|
-
value: "grant",
|
|
807
|
-
label: "Grant and
|
|
808
|
-
description: "
|
|
887
|
+
value: "grant-remember",
|
|
888
|
+
label: "Grant and remember for this user (global)",
|
|
889
|
+
description: "Persists mcp.allow in your user configuration for every session",
|
|
809
890
|
},
|
|
810
891
|
{
|
|
811
892
|
value: "cancel",
|
|
@@ -813,18 +894,31 @@ export async function runTui(options) {
|
|
|
813
894
|
description: "Make no permission or server changes",
|
|
814
895
|
},
|
|
815
896
|
], (choice) => {
|
|
816
|
-
if (choice.value
|
|
897
|
+
if (choice.value === "cancel")
|
|
817
898
|
return openCatalog();
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
899
|
+
if (choice.value === "grant-session") {
|
|
900
|
+
try {
|
|
901
|
+
app.grantMcpRuntimePermission({ source: "interactive-tui", confirmed: true });
|
|
902
|
+
notice("MCP process/network access granted for this Alisio session only.");
|
|
903
|
+
run();
|
|
904
|
+
}
|
|
905
|
+
catch (cause) {
|
|
906
|
+
error(cause);
|
|
907
|
+
openCatalog();
|
|
908
|
+
}
|
|
909
|
+
return;
|
|
822
910
|
}
|
|
823
|
-
|
|
911
|
+
void app
|
|
912
|
+
.rememberGlobalMcpConsent()
|
|
913
|
+
.then(() => {
|
|
914
|
+
notice("MCP process/network access granted globally (mcp.allow) for this user. Enabled servers will auto-connect on every start.");
|
|
915
|
+
run();
|
|
916
|
+
})
|
|
917
|
+
.catch((cause) => {
|
|
824
918
|
error(cause);
|
|
825
919
|
openCatalog();
|
|
826
|
-
}
|
|
827
|
-
}, openCatalog, false, "
|
|
920
|
+
});
|
|
921
|
+
}, openCatalog, false, "Session-only lasts until Alisio exits. Remembering writes mcp.allow=true to your user configuration so every start grants MCP access and auto-connects enabled servers, including headless runs. MCP servers and their tools run with your user privileges."));
|
|
828
922
|
};
|
|
829
923
|
openCatalog();
|
|
830
924
|
};
|
|
@@ -1296,6 +1390,8 @@ export async function runTui(options) {
|
|
|
1296
1390
|
transcript.addChild(banner);
|
|
1297
1391
|
}
|
|
1298
1392
|
tui.start();
|
|
1393
|
+
for (const failure of app.mcpStartupFailures())
|
|
1394
|
+
notice(failure);
|
|
1299
1395
|
sync();
|
|
1300
1396
|
refreshEstimate();
|
|
1301
1397
|
// Discover context windows in the background; failures only mean "unknown".
|
package/dist/tui/state.d.ts
CHANGED
|
@@ -89,14 +89,14 @@ export declare function contextLevel(pct: number, compactionAt?: number): Level;
|
|
|
89
89
|
export declare function contextPercent(used: number, total: number | undefined): number | undefined;
|
|
90
90
|
/** The effective total the context bar measures against, and what it is derived from. */
|
|
91
91
|
export interface ContextBudget {
|
|
92
|
-
/** Effective total in tokens
|
|
93
|
-
total
|
|
94
|
-
/** Basis of the total: the model's context window, or
|
|
95
|
-
basis: "window" | "
|
|
92
|
+
/** Effective total in tokens: the model's context window, or absent when it is unknown. */
|
|
93
|
+
total?: number;
|
|
94
|
+
/** Basis of the total: the model's context window, or unknown (no fabricated total). */
|
|
95
|
+
basis: "window" | "unknown";
|
|
96
96
|
/** Percentage of `total` at which the engine auto-compacts; the bar turns red there. */
|
|
97
97
|
compactionAt: number;
|
|
98
98
|
}
|
|
99
|
-
export declare function formatContext(used: number, total: number | undefined, estimated: boolean, basis?: "window" | "
|
|
99
|
+
export declare function formatContext(used: number, total: number | undefined, estimated: boolean, basis?: "window" | "unknown"): string;
|
|
100
100
|
export declare function formatDuration(ms: number): string;
|
|
101
101
|
export declare const textWidth: (text: string) => number;
|
|
102
102
|
export declare function truncatePlain(text: string, width: number): string;
|
package/dist/tui/state.js
CHANGED
|
@@ -133,13 +133,14 @@ export function contextPercent(used, total) {
|
|
|
133
133
|
}
|
|
134
134
|
export function formatContext(used, total, estimated, basis) {
|
|
135
135
|
const prefix = `${estimated ? "~" : ""}${formatTokens(used)} / `;
|
|
136
|
+
// Honest unknown: the model window could not be known, so the bar shows `?` instead of a
|
|
137
|
+
// fabricated total or percentage.
|
|
138
|
+
if (basis === "unknown")
|
|
139
|
+
return `${prefix}?`;
|
|
136
140
|
const pct = contextPercent(used, total);
|
|
137
141
|
if (pct === undefined || !total)
|
|
138
142
|
return `${prefix}unknown`;
|
|
139
|
-
|
|
140
|
-
// against the fallback (est. tokens from limits.maxContextChars), not a model window.
|
|
141
|
-
const basisSuffix = basis === "chars" ? " char budget" : "";
|
|
142
|
-
return `${prefix}${formatTokens(total)} (${Math.round(pct)}%)${basisSuffix}`;
|
|
143
|
+
return `${prefix}${formatTokens(total)} (${Math.round(pct)}%)`;
|
|
143
144
|
}
|
|
144
145
|
export function formatDuration(ms) {
|
|
145
146
|
if (ms < 1000)
|
package/dist/version.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reads the package version at runtime so --version, doctor and MCP client
|
|
3
|
-
* stay in sync with the published package without a build-time constant to update.
|
|
4
|
-
*
|
|
2
|
+
* Reads the package version at runtime so --version, doctor, plugin metadata and MCP client
|
|
3
|
+
* metadata stay in sync with the published package without a build-time constant to update.
|
|
4
|
+
* The manifest is resolved relative to the module (`src/version.ts` → `../package.json` in the
|
|
5
|
+
* source tree; `dist/version.js` → `../package.json` of the installed package). Standalone
|
|
6
|
+
* binaries inject the version at build time via ALISIO_PACKAGE_VERSION (scripts/binary-build.ts).
|
|
5
7
|
*/
|
|
6
8
|
export declare function loadVersion(fromHere: string): string;
|
package/dist/version.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
/** Fallback used when package.json is not readable (e.g. standalone binaries). */
|
|
5
|
-
const FALLBACK = "0.1.0-alpha.1";
|
|
6
4
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Fallback used when neither the build-time injection nor the package manifest is readable
|
|
6
|
+
* (e.g. an unpackaged embed). Keep it a development marker, never a publish literal, so it
|
|
7
|
+
* cannot silently desync from the published package.
|
|
8
|
+
*/
|
|
9
|
+
const FALLBACK = "dev";
|
|
10
|
+
/**
|
|
11
|
+
* Reads the package version at runtime so --version, doctor, plugin metadata and MCP client
|
|
12
|
+
* metadata stay in sync with the published package without a build-time constant to update.
|
|
13
|
+
* The manifest is resolved relative to the module (`src/version.ts` → `../package.json` in the
|
|
14
|
+
* source tree; `dist/version.js` → `../package.json` of the installed package). Standalone
|
|
15
|
+
* binaries inject the version at build time via ALISIO_PACKAGE_VERSION (scripts/binary-build.ts).
|
|
10
16
|
*/
|
|
11
17
|
export function loadVersion(fromHere) {
|
|
12
18
|
if (process.env.ALISIO_PACKAGE_VERSION)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alisio/alisio-code",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"description": "Alisio: an extensible, provider-agnostic coding-agent harness for your terminal. TUI, OpenAI-compatible providers, permissioned local tools, context compaction, persistent memory and a typed plugin SDK.",
|
|
5
5
|
"author": "Gustavo Gutiérrez",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,13 +45,13 @@
|
|
|
45
45
|
"alisio": "./dist/main.js"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@alisio/core": "0.1.0-alpha.
|
|
49
|
-
"@alisio/plugin-deepseek": "0.1.0-alpha.
|
|
50
|
-
"@alisio/plugin-memory": "0.1.0-alpha.
|
|
51
|
-
"@alisio/plugin-openai-compatible": "0.1.0-alpha.
|
|
52
|
-
"@alisio/plugin-opencode": "0.1.0-alpha.
|
|
53
|
-
"@alisio/plugin-opencode-go": "0.1.0-alpha.
|
|
54
|
-
"@alisio/plugin-subagents": "0.1.0-alpha.
|
|
48
|
+
"@alisio/core": "0.1.0-alpha.6",
|
|
49
|
+
"@alisio/plugin-deepseek": "0.1.0-alpha.6",
|
|
50
|
+
"@alisio/plugin-memory": "0.1.0-alpha.6",
|
|
51
|
+
"@alisio/plugin-openai-compatible": "0.1.0-alpha.6",
|
|
52
|
+
"@alisio/plugin-opencode": "0.1.0-alpha.6",
|
|
53
|
+
"@alisio/plugin-opencode-go": "0.1.0-alpha.6",
|
|
54
|
+
"@alisio/plugin-subagents": "0.1.0-alpha.6",
|
|
55
55
|
"@alisio/sdk": "0.1.0-alpha.5",
|
|
56
56
|
"@earendil-works/pi-tui": "0.87.1",
|
|
57
57
|
"commander": "15.0.0"
|