@corenel/cli 0.4.2 → 0.4.3
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/cli.js +145 -67
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -18931,42 +18931,58 @@ function credentialFilePath(stateDir) {
|
|
|
18931
18931
|
}
|
|
18932
18932
|
var TOKEN_ENV = "CORENEL_TOKEN";
|
|
18933
18933
|
var API_BASE_ENV = "CORENEL_API_BASE";
|
|
18934
|
-
async function writeAuthToken(token, stateDir) {
|
|
18935
|
-
const dir = credentialDir(stateDir);
|
|
18936
|
-
const path = tokenFilePath(stateDir);
|
|
18937
|
-
await fs2.mkdir(dir, { recursive: true, mode: 448 });
|
|
18938
|
-
await fs2.writeFile(path, token.trim() + "\n", { mode: 384 });
|
|
18939
|
-
try {
|
|
18940
|
-
await fs2.chmod(path, 384);
|
|
18941
|
-
} catch {
|
|
18942
|
-
}
|
|
18943
|
-
try {
|
|
18944
|
-
await fs2.chmod(dir, 448);
|
|
18945
|
-
} catch {
|
|
18946
|
-
}
|
|
18947
|
-
}
|
|
18948
18934
|
async function writeLoginCredential(token, opts = {}) {
|
|
18949
18935
|
const cred = {
|
|
18950
18936
|
accessToken: token.trim(),
|
|
18951
18937
|
...opts.account ? { account: opts.account } : {},
|
|
18952
18938
|
...opts.apiBase ? { apiBase: opts.apiBase } : {}
|
|
18953
18939
|
};
|
|
18954
|
-
const
|
|
18955
|
-
|
|
18956
|
-
|
|
18940
|
+
const dir = credentialDir(opts.stateDir);
|
|
18941
|
+
const credPath = credentialFilePath(opts.stateDir);
|
|
18942
|
+
const tokPath = tokenFilePath(opts.stateDir);
|
|
18943
|
+
await fs2.mkdir(dir, { recursive: true, mode: 448 });
|
|
18944
|
+
const credTmp = `${credPath}.tmp-${process.pid.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
18945
|
+
const tokTmp = `${tokPath}.tmp-${process.pid.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
18946
|
+
await fs2.writeFile(credTmp, `${JSON.stringify(cred, null, 2)}
|
|
18947
|
+
`, { mode: 384 });
|
|
18948
|
+
await fs2.writeFile(tokTmp, `${cred.accessToken}
|
|
18957
18949
|
`, { mode: 384 });
|
|
18958
18950
|
try {
|
|
18959
|
-
await fs2.chmod(
|
|
18951
|
+
await fs2.chmod(credTmp, 384);
|
|
18960
18952
|
} catch {
|
|
18961
18953
|
}
|
|
18962
|
-
|
|
18954
|
+
try {
|
|
18955
|
+
await fs2.chmod(tokTmp, 384);
|
|
18956
|
+
} catch {
|
|
18957
|
+
}
|
|
18958
|
+
try {
|
|
18959
|
+
await fs2.rename(credTmp, credPath);
|
|
18960
|
+
await fs2.rename(tokTmp, tokPath);
|
|
18961
|
+
} catch (e) {
|
|
18962
|
+
try {
|
|
18963
|
+
await fs2.rm(credTmp, { force: true });
|
|
18964
|
+
} catch {
|
|
18965
|
+
}
|
|
18966
|
+
try {
|
|
18967
|
+
await fs2.rm(tokTmp, { force: true });
|
|
18968
|
+
} catch {
|
|
18969
|
+
}
|
|
18970
|
+
throw e;
|
|
18971
|
+
}
|
|
18972
|
+
try {
|
|
18973
|
+
await fs2.chmod(dir, 448);
|
|
18974
|
+
} catch {
|
|
18975
|
+
}
|
|
18976
|
+
}
|
|
18977
|
+
function isMissing(err) {
|
|
18978
|
+
return typeof err === "object" && err !== null && err.code === "ENOENT";
|
|
18963
18979
|
}
|
|
18964
|
-
async function
|
|
18980
|
+
async function readAuthTokenRead(stateDir) {
|
|
18965
18981
|
try {
|
|
18966
18982
|
const t = (await fs2.readFile(tokenFilePath(stateDir), "utf8")).trim();
|
|
18967
|
-
return t || null;
|
|
18968
|
-
} catch {
|
|
18969
|
-
return null;
|
|
18983
|
+
return { value: t || null, unreadable: false };
|
|
18984
|
+
} catch (err) {
|
|
18985
|
+
return { value: null, unreadable: !isMissing(err) };
|
|
18970
18986
|
}
|
|
18971
18987
|
}
|
|
18972
18988
|
async function clearAuthToken(stateDir) {
|
|
@@ -18975,27 +18991,30 @@ async function clearAuthToken(stateDir) {
|
|
|
18975
18991
|
} catch {
|
|
18976
18992
|
}
|
|
18977
18993
|
}
|
|
18978
|
-
async function
|
|
18994
|
+
async function readCredentialFileRead(stateDir) {
|
|
18979
18995
|
let raw;
|
|
18980
18996
|
try {
|
|
18981
18997
|
raw = await fs2.readFile(credentialFilePath(stateDir), "utf8");
|
|
18982
|
-
} catch {
|
|
18983
|
-
return null;
|
|
18998
|
+
} catch (err) {
|
|
18999
|
+
return { value: null, unreadable: !isMissing(err) };
|
|
18984
19000
|
}
|
|
18985
19001
|
try {
|
|
18986
19002
|
const parsed = JSON.parse(raw);
|
|
18987
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
19003
|
+
if (typeof parsed !== "object" || parsed === null) return { value: null, unreadable: false };
|
|
18988
19004
|
const c = parsed;
|
|
18989
|
-
if (typeof c.accessToken !== "string" || !c.accessToken) return null;
|
|
19005
|
+
if (typeof c.accessToken !== "string" || !c.accessToken) return { value: null, unreadable: false };
|
|
18990
19006
|
return {
|
|
18991
|
-
|
|
18992
|
-
|
|
18993
|
-
|
|
18994
|
-
|
|
18995
|
-
|
|
19007
|
+
value: {
|
|
19008
|
+
accessToken: c.accessToken,
|
|
19009
|
+
...typeof c.refreshToken === "string" ? { refreshToken: c.refreshToken } : {},
|
|
19010
|
+
...typeof c.expiresAt === "number" ? { expiresAt: c.expiresAt } : {},
|
|
19011
|
+
...typeof c.account === "string" ? { account: c.account } : {},
|
|
19012
|
+
...typeof c.apiBase === "string" && c.apiBase ? { apiBase: c.apiBase } : {}
|
|
19013
|
+
},
|
|
19014
|
+
unreadable: false
|
|
18996
19015
|
};
|
|
18997
19016
|
} catch {
|
|
18998
|
-
return null;
|
|
19017
|
+
return { value: null, unreadable: false };
|
|
18999
19018
|
}
|
|
19000
19019
|
}
|
|
19001
19020
|
async function clearAllCredentials(stateDir) {
|
|
@@ -19011,20 +19030,29 @@ async function resolveNodeCredential(opts = {}) {
|
|
|
19011
19030
|
const stateDir = opts.stateDir;
|
|
19012
19031
|
const fromEnv = env[TOKEN_ENV]?.trim();
|
|
19013
19032
|
if (fromEnv) return { token: fromEnv, source: "env" };
|
|
19014
|
-
const
|
|
19015
|
-
const
|
|
19033
|
+
const credRead = await readCredentialFileRead(stateDir);
|
|
19034
|
+
const tokenRead = await readAuthTokenRead(stateDir);
|
|
19035
|
+
const cred = credRead.value;
|
|
19036
|
+
const fileToken = tokenRead.value;
|
|
19037
|
+
const unreadable = credRead.unreadable || tokenRead.unreadable ? { unreadable: true } : {};
|
|
19016
19038
|
if (fileToken) {
|
|
19017
19039
|
const same = cred && cred.accessToken === fileToken ? cred : null;
|
|
19018
|
-
return
|
|
19040
|
+
return {
|
|
19041
|
+
...withExpiry({ token: fileToken, source: "token-file", path: tokenFilePath(stateDir) }, same, now),
|
|
19042
|
+
...unreadable
|
|
19043
|
+
};
|
|
19019
19044
|
}
|
|
19020
19045
|
if (cred) {
|
|
19021
|
-
return
|
|
19022
|
-
|
|
19023
|
-
|
|
19024
|
-
|
|
19025
|
-
|
|
19046
|
+
return {
|
|
19047
|
+
...withExpiry(
|
|
19048
|
+
{ token: cred.accessToken, source: "credential-file", path: credentialFilePath(stateDir) },
|
|
19049
|
+
cred,
|
|
19050
|
+
now
|
|
19051
|
+
),
|
|
19052
|
+
...unreadable
|
|
19053
|
+
};
|
|
19026
19054
|
}
|
|
19027
|
-
return { token: null, source: "none" };
|
|
19055
|
+
return { token: null, source: "none", ...unreadable };
|
|
19028
19056
|
}
|
|
19029
19057
|
function withExpiry(base, cred, now) {
|
|
19030
19058
|
if (!cred) return base;
|
|
@@ -22162,24 +22190,35 @@ import { PermissionService as PermissionService4 } from "@corenel/harness/guardr
|
|
|
22162
22190
|
import { ROOT_NODE_ID } from "@corenel/protocol";
|
|
22163
22191
|
import { makeSpawn } from "@corenel/harness/core/spawn";
|
|
22164
22192
|
function inMemoryMemory() {
|
|
22165
|
-
const items =
|
|
22166
|
-
let n = 0;
|
|
22193
|
+
const items = /* @__PURE__ */ new Map();
|
|
22167
22194
|
return {
|
|
22168
|
-
async save(
|
|
22169
|
-
const it = {
|
|
22170
|
-
|
|
22195
|
+
async save(input) {
|
|
22196
|
+
const it = {
|
|
22197
|
+
id: input.name,
|
|
22198
|
+
name: input.name,
|
|
22199
|
+
type: input.type,
|
|
22200
|
+
description: input.description,
|
|
22201
|
+
text: input.body,
|
|
22202
|
+
tags: [],
|
|
22203
|
+
createdAt: Date.now()
|
|
22204
|
+
};
|
|
22205
|
+
items.set(input.name, it);
|
|
22171
22206
|
return it;
|
|
22172
22207
|
},
|
|
22208
|
+
async read(name) {
|
|
22209
|
+
return items.get(name) ?? null;
|
|
22210
|
+
},
|
|
22173
22211
|
async recall(q) {
|
|
22174
|
-
return items.filter((i) => i.text.includes(q));
|
|
22212
|
+
return [...items.values()].filter((i) => i.text.includes(q) || i.description.includes(q));
|
|
22175
22213
|
},
|
|
22176
22214
|
async list() {
|
|
22177
|
-
return [...items];
|
|
22215
|
+
return [...items.values()];
|
|
22178
22216
|
},
|
|
22179
|
-
async forget(
|
|
22180
|
-
|
|
22181
|
-
if (i >= 0) items.splice(i, 1);
|
|
22217
|
+
async forget(name) {
|
|
22218
|
+
items.delete(name);
|
|
22182
22219
|
}
|
|
22220
|
+
// No core(): this stub has no tiers, and Task 9 injects nothing rather than
|
|
22221
|
+
// pretending it has a memory block.
|
|
22183
22222
|
};
|
|
22184
22223
|
}
|
|
22185
22224
|
function inMemoryKv() {
|
|
@@ -22252,6 +22291,42 @@ function tokenGuard(getToken) {
|
|
|
22252
22291
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
22253
22292
|
var MIN_POLL_MS = 1e3;
|
|
22254
22293
|
var DEFAULT_LIFETIME_S = 900;
|
|
22294
|
+
var ACCOUNT_LOOKUP_MS = 5e3;
|
|
22295
|
+
function deadlineSignal(ms, outer) {
|
|
22296
|
+
const ac = new AbortController();
|
|
22297
|
+
const onOuter = () => ac.abort();
|
|
22298
|
+
const timer = setTimeout(() => ac.abort(), ms);
|
|
22299
|
+
if (outer) {
|
|
22300
|
+
if (outer.aborted) ac.abort();
|
|
22301
|
+
else outer.addEventListener("abort", onOuter, { once: true });
|
|
22302
|
+
}
|
|
22303
|
+
return {
|
|
22304
|
+
signal: ac.signal,
|
|
22305
|
+
dispose: () => {
|
|
22306
|
+
clearTimeout(timer);
|
|
22307
|
+
outer?.removeEventListener("abort", onOuter);
|
|
22308
|
+
}
|
|
22309
|
+
};
|
|
22310
|
+
}
|
|
22311
|
+
async function whoIsThis(base, token, f, outer, deadlineMs = ACCOUNT_LOOKUP_MS) {
|
|
22312
|
+
const { signal, dispose } = deadlineSignal(deadlineMs, outer);
|
|
22313
|
+
try {
|
|
22314
|
+
const res = await f(`${base}/auth/me`, {
|
|
22315
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
22316
|
+
signal
|
|
22317
|
+
});
|
|
22318
|
+
if (!res.ok) return void 0;
|
|
22319
|
+
const body = JSON.parse(await res.text());
|
|
22320
|
+
const email = body?.user?.email;
|
|
22321
|
+
if (typeof email !== "string") return void 0;
|
|
22322
|
+
const trimmed = email.trim();
|
|
22323
|
+
return trimmed ? trimmed : void 0;
|
|
22324
|
+
} catch {
|
|
22325
|
+
return void 0;
|
|
22326
|
+
} finally {
|
|
22327
|
+
dispose();
|
|
22328
|
+
}
|
|
22329
|
+
}
|
|
22255
22330
|
function defaultOpen(uri, code2) {
|
|
22256
22331
|
process.stdout.write(`
|
|
22257
22332
|
To authorize, open: ${uri}
|
|
@@ -22300,7 +22375,9 @@ async function deviceLogin(opts) {
|
|
|
22300
22375
|
client_id: "corenel-cli"
|
|
22301
22376
|
});
|
|
22302
22377
|
if (tok.access_token) {
|
|
22303
|
-
|
|
22378
|
+
const claimed = typeof tok.account === "string" ? tok.account.trim() : "";
|
|
22379
|
+
const account = claimed || await whoIsThis(base, tok.access_token, f, opts.signal, opts.accountLookupMs);
|
|
22380
|
+
await opts.store(tok.access_token, account || void 0);
|
|
22304
22381
|
return tok.access_token;
|
|
22305
22382
|
}
|
|
22306
22383
|
if (tok.error === "authorization_pending") continue;
|
|
@@ -22566,7 +22643,10 @@ async function loadCrewAgentAtIfExists(files, root, name, scope = "workspace") {
|
|
|
22566
22643
|
// ../crew/runtime.ts
|
|
22567
22644
|
import { saveCustomPolicy } from "@corenel/harness/guardrail";
|
|
22568
22645
|
import { allTools } from "@corenel/harness/tools/builtins";
|
|
22646
|
+
import { registerSyncConfig, readConfigSyncRendered } from "@corenel/harness/prompts/syncConfig";
|
|
22569
22647
|
import { makeCallAgentTool } from "@corenel/harness/tools/callAgent";
|
|
22648
|
+
var MEMORY_BLOCK = registerSyncConfig("crew/memory.md");
|
|
22649
|
+
var SELF_DIRECTION_BLOCK = registerSyncConfig("crew/self-direction.md");
|
|
22570
22650
|
function buildSystemExtra(def, memoryLocation) {
|
|
22571
22651
|
const parts = [];
|
|
22572
22652
|
if (def.jobTitle?.trim()) parts.push(`--- Role ---
|
|
@@ -22580,11 +22660,7 @@ ${def.instructions.trim()}`);
|
|
|
22580
22660
|
const location = memoryLocation ?? "memory/";
|
|
22581
22661
|
const dir = location.replace(/\/+$/, "");
|
|
22582
22662
|
const index = `${dir}/MEMORY.md`;
|
|
22583
|
-
parts.push(
|
|
22584
|
-
`--- Memory ---
|
|
22585
|
-
You keep durable notes in your own memory folder, \`${dir}/\`, one Markdown file per note, alongside \`${index}\`, an index you maintain for yourself.
|
|
22586
|
-
Read \`${index}\` at the start of a run to recall what you already know, and call recall_memory to look up one note by name. If you can call save_memory, use it for what is worth knowing on a later run, and keep \`${index}\` current as you do. If a file tool you have takes a \`root\` argument, you can pass \`${dir}/\` as \`root\` to read and edit those files directly.`
|
|
22587
|
-
);
|
|
22663
|
+
parts.push(readConfigSyncRendered(MEMORY_BLOCK, { dir, index }));
|
|
22588
22664
|
const selfDirection = selfDirectionBlock(def);
|
|
22589
22665
|
if (selfDirection) parts.push(selfDirection);
|
|
22590
22666
|
return parts.join("\n\n");
|
|
@@ -22595,23 +22671,21 @@ function selfDirectionBlock(def) {
|
|
|
22595
22671
|
const raw = trigger.config?.fallbackMs;
|
|
22596
22672
|
const fallbackMs = typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : null;
|
|
22597
22673
|
const consequence = fallbackMs == null ? "If this run ends without that call, nothing will wake it again and your work stops here until someone starts you by hand." : `If this run ends without that call you will be woken anyway, about ${Math.round(fallbackMs / 6e4)} minutes from now -- but that is a backstop for a run that could not schedule itself, not a substitute for choosing when you should next run.`;
|
|
22598
|
-
return
|
|
22599
|
-
You run on your own schedule. You will not run again unless you call \`schedule_self\` with the time you should next wake, before this run ends.
|
|
22600
|
-
${consequence}
|
|
22601
|
-
So decide, before you finish, whether there is more to do and when it should happen.`;
|
|
22674
|
+
return readConfigSyncRendered(SELF_DIRECTION_BLOCK, { consequence });
|
|
22602
22675
|
}
|
|
22603
22676
|
|
|
22604
22677
|
// ../crew/memory.ts
|
|
22605
|
-
import {
|
|
22606
|
-
import { parseFact, renderFact, slugify, uniqueSlug, FACT_INDEX } from "@corenel/harness/core/factFile";
|
|
22678
|
+
import { makeFactStore } from "@corenel/harness/memory/store";
|
|
22607
22679
|
|
|
22608
22680
|
// ../crew/room/store.ts
|
|
22609
|
-
import { flattenFiles as
|
|
22681
|
+
import { flattenFiles as flattenFiles4 } from "@corenel/protocol";
|
|
22610
22682
|
import { encodeLine, foldSession } from "@corenel/harness/sessions/jsonl";
|
|
22611
22683
|
import { FINDINGS_FILE, encodeFindingLine, foldFindings } from "@corenel/harness/rooms/findings";
|
|
22612
22684
|
|
|
22613
22685
|
// ../crew/room/prompt.ts
|
|
22686
|
+
import { registerSyncConfig as registerSyncConfig2, readConfigSyncRendered as readConfigSyncRendered2 } from "@corenel/harness/prompts/syncConfig";
|
|
22614
22687
|
import { MAX_ROOM_FINDINGS, renderFindings } from "@corenel/harness/rooms/findings";
|
|
22688
|
+
var ROOM_BLOCK = registerSyncConfig2("crew/room.md");
|
|
22615
22689
|
|
|
22616
22690
|
// ../crew/room/turn.ts
|
|
22617
22691
|
import { readRoomOutcome } from "@corenel/harness/tools/roomTools";
|
|
@@ -24245,10 +24319,14 @@ async function main() {
|
|
|
24245
24319
|
}
|
|
24246
24320
|
case "login": {
|
|
24247
24321
|
const base = await apiBase(flag(rest, "base", ""));
|
|
24248
|
-
await deviceLogin({
|
|
24322
|
+
await deviceLogin({
|
|
24323
|
+
base,
|
|
24324
|
+
store: (token, account) => writeLoginCredential(token, { apiBase: base, ...account ? { account } : {} })
|
|
24325
|
+
});
|
|
24249
24326
|
process.stdout.write(`
|
|
24250
24327
|
Logged in. Token saved to ${authTokenPath()}
|
|
24251
24328
|
`);
|
|
24329
|
+
process.stdout.write("If a sidecar daemon is already running, restart it to sign it in as well.\n");
|
|
24252
24330
|
break;
|
|
24253
24331
|
}
|
|
24254
24332
|
case "auth":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corenel/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Corenel CLI — runs the harness in node, in-proc, no transport. The headless proof the kernel is host-agnostic. (corenel run/ask/chat/login + start --sidecar to follow.)",
|
|
6
6
|
"bin": {
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"openai": "^4.77.0",
|
|
11
11
|
"ws": "^8.18.0",
|
|
12
|
-
"@corenel/harness": "0.6.
|
|
13
|
-
"@corenel/
|
|
14
|
-
"@corenel/
|
|
12
|
+
"@corenel/harness": "0.6.1",
|
|
13
|
+
"@corenel/term": "0.2.3",
|
|
14
|
+
"@corenel/protocol": "0.6.1"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"esbuild": "^0.21.5",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"@types/ws": "^8.5.13",
|
|
20
20
|
"tsx": "^4.19.2",
|
|
21
21
|
"typescript": "^5.9.3",
|
|
22
|
-
"@corenel/
|
|
23
|
-
"@corenel/
|
|
22
|
+
"@corenel/crew": "0.0.0",
|
|
23
|
+
"@corenel/tools-node": "0.3.1"
|
|
24
24
|
},
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"access": "public"
|