@staff0rd/assist 0.962.0 → 0.963.0
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 +17 -15
- package/claude/commands/miro.md +1 -1
- package/dist/commands/sessions/web/bundle.js +521 -521
- package/dist/index.js +311 -224
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.963.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -6207,7 +6207,7 @@ var adviceConfigHelp = [
|
|
|
6207
6207
|
{
|
|
6208
6208
|
key: "advice.rules",
|
|
6209
6209
|
setter: "assist rules add '<text>' --title '<title>' --user",
|
|
6210
|
-
note: `listed under "Your rules"; user (db), user (node) and repo entries are concatenated in that order. --node writes ~/.assist.yml instead; 'assist config import-user' moves those into user (db)`
|
|
6210
|
+
note: `listed under "Your rules"; user (db), user (node), repo (db) and repo (git) entries are concatenated in that order. --node writes ~/.assist.yml instead; 'assist config import-user' moves those into user (db)`
|
|
6211
6211
|
}
|
|
6212
6212
|
];
|
|
6213
6213
|
|
|
@@ -6215,7 +6215,7 @@ var adviceConfigHelp = [
|
|
|
6215
6215
|
var askQuestionConfigHelp = [
|
|
6216
6216
|
{
|
|
6217
6217
|
key: "sessions.askQuestion",
|
|
6218
|
-
setter: "assist config set sessions.askQuestion true
|
|
6218
|
+
setter: "assist config set sessions.askQuestion true --node",
|
|
6219
6219
|
note: "opt in: assist ask-question answers AskUserQuestion questions from the session's web preview pane; when on, assist cli-hook denies AskUserQuestion in assist sessions and an advice fragment points Claude at assist ask-question; when off it exits non-zero so Claude uses the built-in tool (default off)"
|
|
6220
6220
|
}
|
|
6221
6221
|
];
|
|
@@ -6276,7 +6276,7 @@ var backupConfigHelp = [
|
|
|
6276
6276
|
var autoUpdateConfigHelp = [
|
|
6277
6277
|
{
|
|
6278
6278
|
key: "autoUpdate.enabled",
|
|
6279
|
-
setter: "assist config set autoUpdate.enabled false
|
|
6279
|
+
setter: "assist config set autoUpdate.enabled false --node",
|
|
6280
6280
|
note: "when this install is a git clone, the daemon pulls and builds it in the background as origin moves (assist watch wait --pull --build), logging each lap to ~/.assist/watchers/; a branch that cannot fast-forward starts a claude session to reconcile it and the loop resumes once it closes. Set false to stop it (default on)"
|
|
6281
6281
|
}
|
|
6282
6282
|
];
|
|
@@ -6317,8 +6317,8 @@ var complexityConfigHelp = [
|
|
|
6317
6317
|
var configConfigHelp = [
|
|
6318
6318
|
{
|
|
6319
6319
|
key: "repos",
|
|
6320
|
-
setter: "assist config set worktree.enabled true
|
|
6321
|
-
note: "per-repo overrides stored in the shared db, keyed by repo identity and seen by every node that uses it; written by 'config set
|
|
6320
|
+
setter: "assist config set worktree.enabled true --repo",
|
|
6321
|
+
note: "repo (db): per-repo overrides stored in the shared db, keyed by repo identity and seen by every node that uses it; written by 'config set --repo [name]' or the web /config repo (db) scope, and a yml repos: entry applies only until 'config import-repos' moves it"
|
|
6322
6322
|
}
|
|
6323
6323
|
];
|
|
6324
6324
|
|
|
@@ -6418,32 +6418,32 @@ var newsConfigHelp = [
|
|
|
6418
6418
|
var nextConfigHelp = [
|
|
6419
6419
|
{
|
|
6420
6420
|
key: "next.peers",
|
|
6421
|
-
setter: "assist config set next.peers alice,bob
|
|
6421
|
+
setter: "assist config set next.peers alice,bob --repo",
|
|
6422
6422
|
note: "GitHub logins whose open, non-draft PRs the web /next view lists for review alongside PRs requesting your review; PRs you approved with no newer commits are hidden"
|
|
6423
6423
|
},
|
|
6424
6424
|
{
|
|
6425
6425
|
key: "next.repos",
|
|
6426
|
-
setter: "assist config set next.repos my-org,other/web
|
|
6426
|
+
setter: "assist config set next.repos my-org,other/web --repo",
|
|
6427
6427
|
note: "GitHub repos the web /next view reads peer PRs and issues assigned to you from: owner/name for one repo, or a bare owner (org or user) for all its unarchived repos (default: the selected repo)"
|
|
6428
6428
|
},
|
|
6429
6429
|
{
|
|
6430
6430
|
key: "next.projects",
|
|
6431
|
-
setter: "assist config set next.projects my-org/3,my-org/5
|
|
6431
|
+
setter: "assist config set next.projects my-org/3,my-org/5 --repo",
|
|
6432
6432
|
note: "GitHub Projects (owner/number, from each URL) the web /next view suggests unassigned issues to pick up from; needs the gh project scope"
|
|
6433
6433
|
},
|
|
6434
6434
|
{
|
|
6435
6435
|
key: "next.pickStatuses",
|
|
6436
|
-
setter: "assist config set next.pickStatuses Ready,Todo
|
|
6436
|
+
setter: "assist config set next.pickStatuses Ready,Todo --repo",
|
|
6437
6437
|
note: "Project Status values whose unassigned items the web /next view offers to pick up (default: Ready, Todo)"
|
|
6438
6438
|
},
|
|
6439
6439
|
{
|
|
6440
6440
|
key: "next.excludeLabels",
|
|
6441
|
-
setter: "assist config set next.excludeLabels blocked,spike
|
|
6441
|
+
setter: "assist config set next.excludeLabels blocked,spike --repo",
|
|
6442
6442
|
note: "Labels whose project items the web /next view never offers to pick up (case-insensitive)"
|
|
6443
6443
|
},
|
|
6444
6444
|
{
|
|
6445
6445
|
key: "next.excludeTypes",
|
|
6446
|
-
setter: "assist config set next.excludeTypes Epic
|
|
6446
|
+
setter: "assist config set next.excludeTypes Epic --repo",
|
|
6447
6447
|
note: "GitHub issue types whose project items the web /next view never offers to pick up (case-insensitive)"
|
|
6448
6448
|
}
|
|
6449
6449
|
];
|
|
@@ -6577,7 +6577,7 @@ var reviewConfigHelp = [
|
|
|
6577
6577
|
|
|
6578
6578
|
// src/commands/sync/printAutoConfirmHint.ts
|
|
6579
6579
|
import chalk8 from "chalk";
|
|
6580
|
-
var autoConfirmHintCommand = "assist config set sync.autoConfirm true --
|
|
6580
|
+
var autoConfirmHintCommand = "assist config set sync.autoConfirm true --node";
|
|
6581
6581
|
function printAutoConfirmHint() {
|
|
6582
6582
|
console.log(
|
|
6583
6583
|
chalk8.dim(
|
|
@@ -6666,7 +6666,7 @@ var nodesConfigHelp = [
|
|
|
6666
6666
|
},
|
|
6667
6667
|
{
|
|
6668
6668
|
key: "sessions.linkVersionCheck",
|
|
6669
|
-
setter: "assist config set sessions.linkVersionCheck block
|
|
6669
|
+
setter: "assist config set sessions.linkVersionCheck block --node",
|
|
6670
6670
|
note: "reaction when a linked node's protocol range doesn't overlap this node's (app versions may differ; never restarts a peer): block (default) holds the link version-blocked until the older node is updated, warn proceeds, off skips the check"
|
|
6671
6671
|
}
|
|
6672
6672
|
];
|
|
@@ -6716,7 +6716,7 @@ var EXAMPLES = {
|
|
|
6716
6716
|
};
|
|
6717
6717
|
var hotkeysConfigHelp = Object.keys(ACTIONS).map((name) => ({
|
|
6718
6718
|
key: `sessions.hotkeys.${name}`,
|
|
6719
|
-
setter: `assist config set sessions.hotkeys.${name} ${EXAMPLES[name] ?? defaultHotkeys[name][0]}
|
|
6719
|
+
setter: `assist config set sessions.hotkeys.${name} ${EXAMPLES[name] ?? defaultHotkeys[name][0]} --node`,
|
|
6720
6720
|
note: `${ACTIONS[name]}; default ${defaultHotkeys[name].join(" / ")}`
|
|
6721
6721
|
}));
|
|
6722
6722
|
|
|
@@ -6724,52 +6724,52 @@ var hotkeysConfigHelp = Object.keys(ACTIONS).map((name) => ({
|
|
|
6724
6724
|
var sessionsConfigHelp = [
|
|
6725
6725
|
{
|
|
6726
6726
|
key: "sessions.nodeName",
|
|
6727
|
-
setter: "assist config set sessions.nodeName <name>
|
|
6727
|
+
setter: "assist config set sessions.nodeName <name> --node",
|
|
6728
6728
|
note: "this install's node label, shown in the web UI hamburger menu and reported by /api/health (default: OS hostname, with -wsl under WSL)"
|
|
6729
6729
|
},
|
|
6730
6730
|
{
|
|
6731
6731
|
key: "sessions.includeCommittedChanges",
|
|
6732
|
-
setter: "assist config set sessions.includeCommittedChanges false
|
|
6732
|
+
setter: "assist config set sessions.includeCommittedChanges false --node",
|
|
6733
6733
|
note: "default on: session card counts, /diff and the diff scope picker span the commits recorded against the session's backlog item as well as uncommitted work, so they survive the agent committing. Set false to show only uncommitted changes"
|
|
6734
6734
|
},
|
|
6735
6735
|
{
|
|
6736
6736
|
key: "sessions.maxLive",
|
|
6737
|
-
setter: "assist config set sessions.maxLive 24
|
|
6737
|
+
setter: "assist config set sessions.maxLive 24 --node",
|
|
6738
6738
|
note: "ceiling on concurrent live sessions one daemon holds; spawning past it is refused, and restore respawns at most this many persisted sessions (default: 24)"
|
|
6739
6739
|
},
|
|
6740
6740
|
{
|
|
6741
6741
|
key: "sessions.newSessionMode",
|
|
6742
|
-
setter: "assist config set sessions.newSessionMode bug
|
|
6742
|
+
setter: "assist config set sessions.newSessionMode bug --node",
|
|
6743
6743
|
note: "default mode pre-selected in the Ctrl+N new session dialog: draft | bug | prompt | design (default: draft)"
|
|
6744
6744
|
},
|
|
6745
6745
|
{
|
|
6746
6746
|
key: "worktree.enabled",
|
|
6747
|
-
setter: "assist config set worktree.enabled true
|
|
6747
|
+
setter: "assist config set worktree.enabled true --repo",
|
|
6748
6748
|
note: "opt in per repo: every session spills into a fresh adjacent <clone>-N worktree and the clone itself is never allocated; only inPlace launches (e.g. PR Review) and agents joining a stream stay in their tree (default off)"
|
|
6749
6749
|
},
|
|
6750
6750
|
{
|
|
6751
6751
|
key: "worktree.trunk",
|
|
6752
|
-
setter: "assist config set worktree.trunk true
|
|
6752
|
+
setter: "assist config set worktree.trunk true --repo",
|
|
6753
6753
|
note: "trunk-based: a worktree's branch tracks origin/<the clone's branch> so commits land on the mainline (default off: a worktree starts off the remote default with no mainline tracking, so the session raises its own branch and PR)"
|
|
6754
6754
|
},
|
|
6755
6755
|
{
|
|
6756
6756
|
key: "worktree.root",
|
|
6757
|
-
setter: "assist config set worktree.root ~/git
|
|
6757
|
+
setter: "assist config set worktree.root ~/git --repo",
|
|
6758
6758
|
note: "optional; parent dir for <clone>-N worktrees (default: the clone's parent)"
|
|
6759
6759
|
},
|
|
6760
6760
|
{
|
|
6761
6761
|
key: "worktree.install",
|
|
6762
|
-
setter: "assist config set worktree.install true
|
|
6762
|
+
setter: "assist config set worktree.install true --repo",
|
|
6763
6763
|
note: `per-worktree dep install: true auto-detects the package manager (npm ci when a package-lock.json exists), or give an explicit command; false to skip; or a JSON list of paths (e.g. '[".","packages/ui"]') to auto-detect and install in each, in order, stopping at the first failure`
|
|
6764
6764
|
},
|
|
6765
6765
|
{
|
|
6766
6766
|
key: "worktree.commitBeforePhaseEnd",
|
|
6767
|
-
setter: "assist config set worktree.commitBeforePhaseEnd true
|
|
6767
|
+
setter: "assist config set worktree.commitBeforePhaseEnd true --repo",
|
|
6768
6768
|
note: "phase prompts run /commit once verify passes \u2014 before asking the user to perform manual checks, or before phase-done when the phase has none \u2014 so work is not left uncommitted in a reapable worktree (default off)"
|
|
6769
6769
|
},
|
|
6770
6770
|
{
|
|
6771
6771
|
key: "worktree.copy",
|
|
6772
|
-
setter: "assist config set worktree.copy .env,.claude/settings.local.json
|
|
6772
|
+
setter: "assist config set worktree.copy .env,.claude/settings.local.json --repo",
|
|
6773
6773
|
note: "gitignored files copied into a new worktree so it can build/run"
|
|
6774
6774
|
}
|
|
6775
6775
|
];
|
|
@@ -6778,12 +6778,12 @@ var sessionsConfigHelp = [
|
|
|
6778
6778
|
var webConfigHelp = [
|
|
6779
6779
|
{
|
|
6780
6780
|
key: "sessions.tailscaleServe",
|
|
6781
|
-
setter: "assist config set sessions.tailscaleServe false
|
|
6781
|
+
setter: "assist config set sessions.tailscaleServe false --node",
|
|
6782
6782
|
note: "default on: the web server exposes its port on the tailnet with tailscale serve when it starts, so other nodes can link it by Tailscale name; set false to keep it off the tailnet"
|
|
6783
6783
|
},
|
|
6784
6784
|
{
|
|
6785
6785
|
key: "extension.redirects",
|
|
6786
|
-
setter: "assist config set extension.redirects.<owner>/<repo> <owner>/<repo>
|
|
6786
|
+
setter: "assist config set extension.redirects.<owner>/<repo> <owner>/<repo> --node",
|
|
6787
6787
|
note: "maps a GitHub owner/repo to the owner/repo whose clone under clone.baseDir hosts the browser extension's issue sessions; the prompt keeps the original link, and PR review sends are not redirected"
|
|
6788
6788
|
}
|
|
6789
6789
|
];
|
|
@@ -6907,6 +6907,20 @@ function isGlobalOnlyConfigKey(key) {
|
|
|
6907
6907
|
return GLOBAL_ONLY_KEYS.some((k) => key.startsWith(k));
|
|
6908
6908
|
}
|
|
6909
6909
|
|
|
6910
|
+
// src/commands/config/isNodeOnlyConfigKey.ts
|
|
6911
|
+
var DB_EXCLUDED_ROOTS = ["repos", "database"];
|
|
6912
|
+
function isNodeOnlyConfigKey(key) {
|
|
6913
|
+
const root2 = key.split(".")[0];
|
|
6914
|
+
return isGlobalOnlyConfigKey(key) || DB_EXCLUDED_ROOTS.includes(root2);
|
|
6915
|
+
}
|
|
6916
|
+
|
|
6917
|
+
// src/commands/config/configWritableScopes.ts
|
|
6918
|
+
function configWritableScopes(key) {
|
|
6919
|
+
if (isGlobalOnlyConfigKey(key)) return ["global"];
|
|
6920
|
+
if (isNodeOnlyConfigKey(key)) return ["project", "repo", "global"];
|
|
6921
|
+
return void 0;
|
|
6922
|
+
}
|
|
6923
|
+
|
|
6910
6924
|
// src/commands/config/resolveConfigSources.ts
|
|
6911
6925
|
function resolveConfigSources(key, layers) {
|
|
6912
6926
|
const sources = [];
|
|
@@ -6924,6 +6938,7 @@ function configEntryFor(leaf, { config, layers, globalConfigFile, schema: schema
|
|
|
6924
6938
|
const sources = resolveConfigSources(leaf.key, layers);
|
|
6925
6939
|
const node = configEntryNode(schema2, leaf.key);
|
|
6926
6940
|
const help = configHelpForKey(leaf.key);
|
|
6941
|
+
const writableScopes = configWritableScopes(leaf.key);
|
|
6927
6942
|
return {
|
|
6928
6943
|
...leaf,
|
|
6929
6944
|
...help ? { note: help.note, setter: help.setter } : {},
|
|
@@ -6935,7 +6950,7 @@ function configEntryFor(leaf, { config, layers, globalConfigFile, schema: schema
|
|
|
6935
6950
|
...layers.repoKey ? { repoKey: layers.repoKey } : {},
|
|
6936
6951
|
...layers.repoSource ? { repoSource: layers.repoSource } : {},
|
|
6937
6952
|
globalConfigFile,
|
|
6938
|
-
|
|
6953
|
+
...writableScopes ? { writableScopes } : {},
|
|
6939
6954
|
node
|
|
6940
6955
|
};
|
|
6941
6956
|
}
|
|
@@ -6977,7 +6992,7 @@ function isDbBackedConfigKey(key) {
|
|
|
6977
6992
|
return Object.hasOwn(dbBackedConfigKeys, key);
|
|
6978
6993
|
}
|
|
6979
6994
|
function dbBackedRepoError(key) {
|
|
6980
|
-
return `"${key}" is stored in
|
|
6995
|
+
return `"${key}" is stored in user (db) and shared by every repo; drop --repo`;
|
|
6981
6996
|
}
|
|
6982
6997
|
|
|
6983
6998
|
// src/commands/config/setNestedValue.ts
|
|
@@ -7048,17 +7063,15 @@ async function withDbBackedConfigValues(config, keys) {
|
|
|
7048
7063
|
}
|
|
7049
7064
|
|
|
7050
7065
|
// src/commands/config/withDbBackedConfigEntries.ts
|
|
7051
|
-
var DB_BACKED_CONFIG_FILE = "the shared db (all nodes)";
|
|
7052
7066
|
function dbBackedEntry(entry, value) {
|
|
7053
7067
|
const set = value !== void 0;
|
|
7054
7068
|
return {
|
|
7055
7069
|
...entry,
|
|
7056
7070
|
value: set ? value : entry.defaultValue,
|
|
7057
|
-
source: set ? "
|
|
7058
|
-
sources: set ? ["
|
|
7059
|
-
layers: set ? {
|
|
7060
|
-
|
|
7061
|
-
globalOnly: true
|
|
7071
|
+
source: set ? "user" : "default",
|
|
7072
|
+
sources: set ? ["user"] : [],
|
|
7073
|
+
layers: set ? { user: value } : {},
|
|
7074
|
+
writableScopes: ["user"]
|
|
7062
7075
|
};
|
|
7063
7076
|
}
|
|
7064
7077
|
async function withDbBackedConfigEntries(entries) {
|
|
@@ -10969,25 +10982,31 @@ async function nodeDoctor(req, res) {
|
|
|
10969
10982
|
respondJson(res, 200, { hop: await firstBrokenHop(link3) ?? null });
|
|
10970
10983
|
}
|
|
10971
10984
|
|
|
10985
|
+
// src/commands/config/configScopeNames.ts
|
|
10986
|
+
var configScopeNames = {
|
|
10987
|
+
project: "repo (git)",
|
|
10988
|
+
repo: "repo (db)",
|
|
10989
|
+
global: "user (node)",
|
|
10990
|
+
user: "user (db)"
|
|
10991
|
+
};
|
|
10992
|
+
|
|
10972
10993
|
// src/commands/config/applyDbBackedConfigWrite.ts
|
|
10973
10994
|
async function applyDbBackedConfigWrite(key, scope, write) {
|
|
10974
|
-
|
|
10995
|
+
const target = configScopeNames.user;
|
|
10996
|
+
if (scope !== "user")
|
|
10975
10997
|
return {
|
|
10976
10998
|
ok: false,
|
|
10977
|
-
errors: [`"${key}" is stored in
|
|
10999
|
+
errors: [`"${key}" is stored in ${target}; save it there`]
|
|
10978
11000
|
};
|
|
10979
11001
|
const handler = dbBackedConfigKeys[key];
|
|
10980
11002
|
const db = await getDb();
|
|
10981
11003
|
if ("unset" in write)
|
|
10982
11004
|
return {
|
|
10983
11005
|
ok: true,
|
|
10984
|
-
payload: {
|
|
10985
|
-
target: DB_BACKED_CONFIG_FILE,
|
|
10986
|
-
removed: await handler.unset(db)
|
|
10987
|
-
}
|
|
11006
|
+
payload: { target, removed: await handler.unset(db) }
|
|
10988
11007
|
};
|
|
10989
11008
|
await handler.write(db, write.value);
|
|
10990
|
-
return { ok: true, payload: { target
|
|
11009
|
+
return { ok: true, payload: { target } };
|
|
10991
11010
|
}
|
|
10992
11011
|
|
|
10993
11012
|
// src/commands/config/coerceConfigScalar.ts
|
|
@@ -11213,7 +11232,7 @@ function applyConfigSet(key, coerced, global, cwd = process.cwd(), globalConfigP
|
|
|
11213
11232
|
return {
|
|
11214
11233
|
ok: false,
|
|
11215
11234
|
errors: [
|
|
11216
|
-
`"${key}" is a
|
|
11235
|
+
`"${key}" is a user (node)-only key. Use --node to set it in ~/.assist.yml`
|
|
11217
11236
|
]
|
|
11218
11237
|
};
|
|
11219
11238
|
}
|
|
@@ -11235,7 +11254,7 @@ function globalOnlyRepoKeyError(key, verb) {
|
|
|
11235
11254
|
return {
|
|
11236
11255
|
ok: false,
|
|
11237
11256
|
errors: [
|
|
11238
|
-
`"${key}" is a
|
|
11257
|
+
`"${key}" is a user (node)-only key. ${verb} it in ~/.assist.yml with --node rather than in repo (db)`
|
|
11239
11258
|
]
|
|
11240
11259
|
};
|
|
11241
11260
|
}
|
|
@@ -11342,10 +11361,10 @@ async function applySharedRepoConfigSet(key, coerced, repoName, cwd = process.cw
|
|
|
11342
11361
|
|
|
11343
11362
|
// src/shared/db/updateUserConfig.ts
|
|
11344
11363
|
import { eq as eq24 } from "drizzle-orm";
|
|
11345
|
-
async function updateUserConfig(orm,
|
|
11364
|
+
async function updateUserConfig(orm, update4) {
|
|
11346
11365
|
return orm.transaction(async (tx) => {
|
|
11347
11366
|
const [row3] = await tx.select().from(userConfig).where(eq24(userConfig.id, 1)).for("update");
|
|
11348
|
-
const outcome =
|
|
11367
|
+
const outcome = update4(row3?.config ?? {});
|
|
11349
11368
|
if (!outcome.ok) return outcome;
|
|
11350
11369
|
if (Object.keys(outcome.config).length === 0) {
|
|
11351
11370
|
await tx.delete(userConfig).where(eq24(userConfig.id, 1));
|
|
@@ -11360,17 +11379,12 @@ async function updateUserConfig(orm, update3) {
|
|
|
11360
11379
|
}
|
|
11361
11380
|
|
|
11362
11381
|
// src/commands/config/userDbKeyError.ts
|
|
11363
|
-
var DB_EXCLUDED_ROOTS = ["repos", "database"];
|
|
11364
|
-
function isNodeOnlyKey(key) {
|
|
11365
|
-
const root2 = key.split(".")[0];
|
|
11366
|
-
return isGlobalOnlyConfigKey(key) || DB_EXCLUDED_ROOTS.includes(root2);
|
|
11367
|
-
}
|
|
11368
11382
|
function userDbKeyError(key, verb) {
|
|
11369
|
-
if (!
|
|
11383
|
+
if (!isNodeOnlyConfigKey(key)) return void 0;
|
|
11370
11384
|
return {
|
|
11371
11385
|
ok: false,
|
|
11372
11386
|
errors: [
|
|
11373
|
-
`"${key}" can't be stored in user (db); it stays in user (node). ${verb} it in ~/.assist.yml with
|
|
11387
|
+
`"${key}" can't be stored in user (db); it stays in user (node). ${verb} it in ~/.assist.yml with --node`
|
|
11374
11388
|
]
|
|
11375
11389
|
};
|
|
11376
11390
|
}
|
|
@@ -11430,7 +11444,10 @@ async function parseConfigWriteRequest(req) {
|
|
|
11430
11444
|
if (typeof cwd !== "string" || cwd === "")
|
|
11431
11445
|
return { ok: false, error: "Missing cwd" };
|
|
11432
11446
|
if (!isConfigWriteScope(scope))
|
|
11433
|
-
return {
|
|
11447
|
+
return {
|
|
11448
|
+
ok: false,
|
|
11449
|
+
error: 'scope must be "project", "repo", "global" or "user"'
|
|
11450
|
+
};
|
|
11434
11451
|
return { ok: true, key, value: body.value, cwd, scope };
|
|
11435
11452
|
}
|
|
11436
11453
|
|
|
@@ -11564,7 +11581,7 @@ function applyConfigUnset(key, global, cwd = process.cwd(), globalConfigPath) {
|
|
|
11564
11581
|
return {
|
|
11565
11582
|
ok: false,
|
|
11566
11583
|
errors: [
|
|
11567
|
-
`"${key}" is a
|
|
11584
|
+
`"${key}" is a user (node)-only key. Use --node to unset it in ~/.assist.yml`
|
|
11568
11585
|
]
|
|
11569
11586
|
};
|
|
11570
11587
|
}
|
|
@@ -21477,7 +21494,7 @@ function loadDenyConfig(global) {
|
|
|
21477
21494
|
|
|
21478
21495
|
// src/commands/deny/denyAdd.ts
|
|
21479
21496
|
function denyAdd(pattern2, message3, options2) {
|
|
21480
|
-
const { deny, saveDeny } = loadDenyConfig(options2.
|
|
21497
|
+
const { deny, saveDeny } = loadDenyConfig(options2.node);
|
|
21481
21498
|
if (deny.some((r) => r.pattern === pattern2)) {
|
|
21482
21499
|
console.log(chalk112.yellow(`Deny rule already exists for: ${pattern2}`));
|
|
21483
21500
|
return;
|
|
@@ -21515,7 +21532,7 @@ function denyList() {
|
|
|
21515
21532
|
// src/commands/deny/denyRemove.ts
|
|
21516
21533
|
import chalk114 from "chalk";
|
|
21517
21534
|
function denyRemove(pattern2, options2) {
|
|
21518
|
-
const { deny, saveDeny } = loadDenyConfig(options2.
|
|
21535
|
+
const { deny, saveDeny } = loadDenyConfig(options2.node);
|
|
21519
21536
|
const index2 = deny.findIndex((r) => r.pattern === pattern2);
|
|
21520
21537
|
if (index2 === -1) {
|
|
21521
21538
|
console.log(chalk114.yellow(`No deny rule found for: ${pattern2}`));
|
|
@@ -21530,8 +21547,8 @@ function denyRemove(pattern2, options2) {
|
|
|
21530
21547
|
function registerDeny(parent) {
|
|
21531
21548
|
const denyCommand = parent.command("deny").description("Manage command deny rules").action(denyList);
|
|
21532
21549
|
configHelp(denyCommand, denyConfigHelp);
|
|
21533
|
-
denyCommand.command("add").description("Add a deny rule for a command pattern").argument("<pattern>", "Command prefix to deny").argument("<message>", "Correction message shown to the agent").option("
|
|
21534
|
-
denyCommand.command("remove").description("Remove a deny rule by pattern").argument("<pattern>", "Command prefix to remove").option("
|
|
21550
|
+
denyCommand.command("add").description("Add a deny rule for a command pattern").argument("<pattern>", "Command prefix to deny").argument("<message>", "Correction message shown to the agent").option("--node", "Write to user (node): this node's ~/.assist.yml").action(denyAdd);
|
|
21551
|
+
denyCommand.command("remove").description("Remove a deny rule by pattern").argument("<pattern>", "Command prefix to remove").option("--node", "Remove from user (node): this node's ~/.assist.yml").action(denyRemove);
|
|
21535
21552
|
denyCommand.command("list").description("List all deny rules").action(denyList);
|
|
21536
21553
|
}
|
|
21537
21554
|
|
|
@@ -23427,25 +23444,25 @@ import chalk136 from "chalk";
|
|
|
23427
23444
|
async function setDbBackedConfigKey(key, value, useRepo) {
|
|
23428
23445
|
if (useRepo) exitWithConfigErrors([dbBackedRepoError(key)]);
|
|
23429
23446
|
await dbBackedConfigKeys[key].write(await getDb(), value);
|
|
23430
|
-
console.log(chalk136.green(`Set ${key} = ${JSON.stringify(value)} (
|
|
23447
|
+
console.log(chalk136.green(`Set ${key} = ${JSON.stringify(value)} (user (db))`));
|
|
23431
23448
|
}
|
|
23432
23449
|
|
|
23433
23450
|
// src/commands/config/setFileConfigKey.ts
|
|
23434
23451
|
import chalk137 from "chalk";
|
|
23435
|
-
async function setFileConfigKey({ key, useRepo, repoName,
|
|
23436
|
-
const target = useRepo ?
|
|
23452
|
+
async function setFileConfigKey({ key, useRepo, repoName, node, user }, coerced) {
|
|
23453
|
+
const target = useRepo ? `${configScopeNames.repo}: ${await applyRepoOrExit(key, coerced, repoName)}` : user ? await applyUserOrExit(key, coerced) : applyOrExit(key, coerced, node);
|
|
23437
23454
|
const shown = JSON.stringify(maskConfigKeySecrets(key, coerced));
|
|
23438
23455
|
console.log(chalk137.green(`Set ${key} = ${shown} (${target})`));
|
|
23439
23456
|
}
|
|
23440
|
-
function applyOrExit(key, coerced,
|
|
23441
|
-
const result = applyConfigSet(key, coerced,
|
|
23457
|
+
function applyOrExit(key, coerced, node) {
|
|
23458
|
+
const result = applyConfigSet(key, coerced, node);
|
|
23442
23459
|
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23443
|
-
return result.target;
|
|
23460
|
+
return configScopeNames[result.target];
|
|
23444
23461
|
}
|
|
23445
23462
|
async function applyUserOrExit(key, coerced) {
|
|
23446
23463
|
const result = await applyUserConfigSet(key, coerced);
|
|
23447
23464
|
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23448
|
-
return
|
|
23465
|
+
return configScopeNames.user;
|
|
23449
23466
|
}
|
|
23450
23467
|
async function applyRepoOrExit(key, coerced, repoName) {
|
|
23451
23468
|
const result = await applySharedRepoConfigSet(key, coerced, repoName);
|
|
@@ -23454,17 +23471,20 @@ async function applyRepoOrExit(key, coerced, repoName) {
|
|
|
23454
23471
|
}
|
|
23455
23472
|
|
|
23456
23473
|
// src/commands/config/scopeOptionsError.ts
|
|
23457
|
-
function scopeOptionsError(options2
|
|
23458
|
-
|
|
23459
|
-
|
|
23460
|
-
|
|
23461
|
-
|
|
23474
|
+
function scopeOptionsError(options2) {
|
|
23475
|
+
const chosen = [
|
|
23476
|
+
options2.repo !== void 0 && "--repo",
|
|
23477
|
+
options2.node && "--node",
|
|
23478
|
+
options2.user && "--user"
|
|
23479
|
+
].filter(Boolean);
|
|
23480
|
+
if (chosen.length > 1)
|
|
23481
|
+
return `${chosen.join(" and ")} pick different scopes; pass one: --repo for repo (db), --node for user (node), --user for user (db)`;
|
|
23462
23482
|
return void 0;
|
|
23463
23483
|
}
|
|
23464
23484
|
|
|
23465
23485
|
// src/commands/config/configSet.ts
|
|
23466
23486
|
async function configSet(key, value, options2 = {}) {
|
|
23467
|
-
const scopeError = scopeOptionsError(options2
|
|
23487
|
+
const scopeError = scopeOptionsError(options2);
|
|
23468
23488
|
if (scopeError) exitWithConfigErrors([scopeError]);
|
|
23469
23489
|
const resolved = resolveRepoTarget(key, value, options2.repo);
|
|
23470
23490
|
if (resolved.value === void 0) {
|
|
@@ -23478,7 +23498,7 @@ async function configSet(key, value, options2 = {}) {
|
|
|
23478
23498
|
await setFileConfigKey(
|
|
23479
23499
|
{
|
|
23480
23500
|
...resolved,
|
|
23481
|
-
|
|
23501
|
+
node: options2.node ?? false,
|
|
23482
23502
|
user: options2.user ?? false
|
|
23483
23503
|
},
|
|
23484
23504
|
coercion.value
|
|
@@ -23504,7 +23524,7 @@ async function unsetDbBackedConfigKey(key, useRepo) {
|
|
|
23504
23524
|
if (useRepo) exitWithConfigErrors([dbBackedRepoError(key)]);
|
|
23505
23525
|
const removed = await dbBackedConfigKeys[key].unset(await getDb());
|
|
23506
23526
|
console.log(
|
|
23507
|
-
removed ? chalk139.green(`Unset ${key} (
|
|
23527
|
+
removed ? chalk139.green(`Unset ${key} (user (db))`) : chalk139.yellow(`${key} is not set in user (db)`)
|
|
23508
23528
|
);
|
|
23509
23529
|
}
|
|
23510
23530
|
|
|
@@ -23514,31 +23534,26 @@ async function unsetFileConfigKey({
|
|
|
23514
23534
|
key,
|
|
23515
23535
|
useRepo,
|
|
23516
23536
|
repoName,
|
|
23517
|
-
|
|
23537
|
+
node,
|
|
23518
23538
|
user
|
|
23519
23539
|
}) {
|
|
23520
|
-
const result = useRepo ? await applySharedRepoConfigUnset(key, repoName) : user ? await applyUserConfigUnset(key) : applyConfigUnset(key,
|
|
23540
|
+
const result = useRepo ? await applySharedRepoConfigUnset(key, repoName) : user ? await applyUserConfigUnset(key) : applyConfigUnset(key, node);
|
|
23521
23541
|
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23522
23542
|
if (!result.removed) {
|
|
23523
|
-
console.log(chalk140.yellow(`${key} is not set in ${
|
|
23543
|
+
console.log(chalk140.yellow(`${key} is not set in ${targetLabel(result)}`));
|
|
23524
23544
|
return;
|
|
23525
23545
|
}
|
|
23526
23546
|
console.log(chalk140.green(`Unset ${key} (${targetLabel(result)})`));
|
|
23527
23547
|
}
|
|
23528
|
-
function whereLabel(result) {
|
|
23529
|
-
if (result.target === "repo") return `repos.${result.label}`;
|
|
23530
|
-
if (result.target === "user") return "user (db)";
|
|
23531
|
-
return `the ${result.target} config`;
|
|
23532
|
-
}
|
|
23533
23548
|
function targetLabel(result) {
|
|
23534
|
-
if (result.target === "repo")
|
|
23535
|
-
|
|
23536
|
-
return result.target;
|
|
23549
|
+
if (result.target === "repo")
|
|
23550
|
+
return `${configScopeNames.repo}: ${result.label}`;
|
|
23551
|
+
return configScopeNames[result.target];
|
|
23537
23552
|
}
|
|
23538
23553
|
|
|
23539
23554
|
// src/commands/config/configUnset.ts
|
|
23540
23555
|
async function configUnset(key, options2 = {}) {
|
|
23541
|
-
const scopeError = scopeOptionsError(options2
|
|
23556
|
+
const scopeError = scopeOptionsError(options2);
|
|
23542
23557
|
if (scopeError) exitWithConfigErrors([scopeError]);
|
|
23543
23558
|
const resolved = resolveRepoUnsetTarget(key, options2.repo);
|
|
23544
23559
|
if (resolved.key === void 0) {
|
|
@@ -23552,24 +23567,28 @@ async function configUnset(key, options2 = {}) {
|
|
|
23552
23567
|
key: resolved.key,
|
|
23553
23568
|
useRepo: resolved.useRepo,
|
|
23554
23569
|
repoName: resolved.repoName,
|
|
23555
|
-
|
|
23570
|
+
node: options2.node ?? false,
|
|
23556
23571
|
user: options2.user ?? false
|
|
23557
23572
|
});
|
|
23558
23573
|
}
|
|
23559
23574
|
|
|
23560
23575
|
// src/commands/config/registerConfigWrites.ts
|
|
23561
23576
|
function registerConfigWrites(configCommand) {
|
|
23562
|
-
configCommand.command("set <key> [value]").description(
|
|
23563
|
-
"
|
|
23564
|
-
"Requires -g: write a repo's override to the shared db, seen by every node (defaults to the current repo)"
|
|
23577
|
+
configCommand.command("set <key> [value]").description(
|
|
23578
|
+
"Set a config value (e.g. commit.push true); with no scope flag it writes repo (git), this repo's assist.yml"
|
|
23565
23579
|
).option(
|
|
23580
|
+
"-r, --repo [name]",
|
|
23581
|
+
"Write to repo (db): a repo's override in the shared db, seen by every node (defaults to the current repo)"
|
|
23582
|
+
).option("--node", "Write to user (node): this node's ~/.assist.yml").option(
|
|
23566
23583
|
"-u, --user",
|
|
23567
23584
|
"Write to user (db): the shared db, applied to every repo on every node"
|
|
23568
23585
|
).action((key, value, options2) => configSet(key, value, options2));
|
|
23569
|
-
configCommand.command("unset [key]").description(
|
|
23586
|
+
configCommand.command("unset [key]").description(
|
|
23587
|
+
"Remove a config value (e.g. commit.push); with no scope flag it removes it from repo (git), this repo's assist.yml"
|
|
23588
|
+
).option(
|
|
23570
23589
|
"-r, --repo [name]",
|
|
23571
|
-
"
|
|
23572
|
-
).option("-u, --user", "Remove from user (db) in the shared db").action((key, options2) => configUnset(key, options2));
|
|
23590
|
+
"Remove from repo (db): a repo's override in the shared db (defaults to the current repo)"
|
|
23591
|
+
).option("--node", "Remove from user (node): this node's ~/.assist.yml").option("-u, --user", "Remove from user (db) in the shared db").action((key, options2) => configUnset(key, options2));
|
|
23573
23592
|
}
|
|
23574
23593
|
|
|
23575
23594
|
// src/commands/registerConfig.ts
|
|
@@ -29917,9 +29936,9 @@ async function saveMiroExtract(name, extract2, options2, paths = {}) {
|
|
|
29917
29936
|
cwd: paths.cwd ?? process.cwd(),
|
|
29918
29937
|
globalConfigPath: paths.globalConfigPath ?? getGlobalConfigPath()
|
|
29919
29938
|
};
|
|
29920
|
-
if (options2.repo !== void 0 &&
|
|
29939
|
+
if (options2.repo !== void 0 && options2.node)
|
|
29921
29940
|
throw new MiroExtractError(
|
|
29922
|
-
"--repo writes
|
|
29941
|
+
"--repo writes repo (db) and --node writes user (node); pass one"
|
|
29923
29942
|
);
|
|
29924
29943
|
const key = `miro.extracts.${name}`;
|
|
29925
29944
|
if (options2.repo !== void 0)
|
|
@@ -29927,7 +29946,7 @@ async function saveMiroExtract(name, extract2, options2, paths = {}) {
|
|
|
29927
29946
|
const result = applyConfigSet(
|
|
29928
29947
|
key,
|
|
29929
29948
|
extract2,
|
|
29930
|
-
options2.
|
|
29949
|
+
options2.node ?? false,
|
|
29931
29950
|
resolved.cwd,
|
|
29932
29951
|
resolved.globalConfigPath
|
|
29933
29952
|
);
|
|
@@ -30194,9 +30213,12 @@ function registerMiro(program) {
|
|
|
30194
30213
|
).option(
|
|
30195
30214
|
"--save <name>",
|
|
30196
30215
|
"Save the selection as this named extract without asking"
|
|
30197
|
-
).option(
|
|
30216
|
+
).option(
|
|
30217
|
+
"--node",
|
|
30218
|
+
"Save the extract to user (node), this node's ~/.assist.yml"
|
|
30219
|
+
).option(
|
|
30198
30220
|
"-r, --repo [name]",
|
|
30199
|
-
"
|
|
30221
|
+
"Save the extract to repo (db), a repo's shared db override (defaults to the current repo)"
|
|
30200
30222
|
).action(
|
|
30201
30223
|
(name, options2) => runExtract(name, options2)
|
|
30202
30224
|
);
|
|
@@ -30651,8 +30673,8 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
|
|
|
30651
30673
|
}
|
|
30652
30674
|
|
|
30653
30675
|
// src/commands/netcap/collectVoyagerAttributes.ts
|
|
30654
|
-
function attributeDetails(
|
|
30655
|
-
const attrs = asObject(asObject(
|
|
30676
|
+
function attributeDetails(update4) {
|
|
30677
|
+
const attrs = asObject(asObject(update4.commentary)?.text)?.attributesV2;
|
|
30656
30678
|
if (!Array.isArray(attrs)) return [];
|
|
30657
30679
|
return attrs.map((a) => asObject(asObject(a)?.detailData)).filter((d) => d !== void 0);
|
|
30658
30680
|
}
|
|
@@ -30679,23 +30701,23 @@ function hashtagsFrom(details) {
|
|
|
30679
30701
|
function textLinksFrom(details) {
|
|
30680
30702
|
return details.map((detail) => asObject(detail.textLink)?.url).filter((url) => typeof url === "string");
|
|
30681
30703
|
}
|
|
30682
|
-
function articleCardLinksFrom(
|
|
30683
|
-
const article = asObject(asObject(
|
|
30704
|
+
function articleCardLinksFrom(update4) {
|
|
30705
|
+
const article = asObject(asObject(update4.content)?.articleComponent);
|
|
30684
30706
|
const url = asObject(article?.navigationContext)?.actionTarget;
|
|
30685
30707
|
return typeof url === "string" ? [url] : [];
|
|
30686
30708
|
}
|
|
30687
|
-
function linksFrom(
|
|
30709
|
+
function linksFrom(update4, details) {
|
|
30688
30710
|
return dedupeLinks([
|
|
30689
30711
|
...textLinksFrom(details),
|
|
30690
|
-
...articleCardLinksFrom(
|
|
30712
|
+
...articleCardLinksFrom(update4)
|
|
30691
30713
|
]);
|
|
30692
30714
|
}
|
|
30693
|
-
function collectVoyagerAttributes(
|
|
30694
|
-
const details = attributeDetails(
|
|
30715
|
+
function collectVoyagerAttributes(update4, profiles, authorSlug) {
|
|
30716
|
+
const details = attributeDetails(update4);
|
|
30695
30717
|
return {
|
|
30696
30718
|
mentions: mentionsFrom(details, profiles, authorSlug),
|
|
30697
30719
|
hashtags: hashtagsFrom(details),
|
|
30698
|
-
links: linksFrom(
|
|
30720
|
+
links: linksFrom(update4, details)
|
|
30699
30721
|
};
|
|
30700
30722
|
}
|
|
30701
30723
|
|
|
@@ -30706,8 +30728,8 @@ function profileSlug(actor) {
|
|
|
30706
30728
|
if (typeof target !== "string") return void 0;
|
|
30707
30729
|
return target.match(/\/in\/([^/?]+)/)?.[1];
|
|
30708
30730
|
}
|
|
30709
|
-
function resolveVoyagerAuthor(
|
|
30710
|
-
const actor = asObject(
|
|
30731
|
+
function resolveVoyagerAuthor(update4) {
|
|
30732
|
+
const actor = asObject(update4.actor);
|
|
30711
30733
|
const slug2 = profileSlug(actor);
|
|
30712
30734
|
if (!slug2) return void 0;
|
|
30713
30735
|
const name = asObject(actor?.name)?.text;
|
|
@@ -30717,24 +30739,24 @@ function resolveVoyagerAuthor(update3) {
|
|
|
30717
30739
|
}
|
|
30718
30740
|
|
|
30719
30741
|
// src/commands/netcap/buildVoyagerPost.ts
|
|
30720
|
-
function commentaryText(
|
|
30721
|
-
const body = asObject(asObject(
|
|
30742
|
+
function commentaryText(update4) {
|
|
30743
|
+
const body = asObject(asObject(update4.commentary)?.text)?.text;
|
|
30722
30744
|
return typeof body === "string" && body.trim() ? body.trim() : void 0;
|
|
30723
30745
|
}
|
|
30724
|
-
function activityUrnOf(
|
|
30725
|
-
const urn = asObject(
|
|
30746
|
+
function activityUrnOf(update4) {
|
|
30747
|
+
const urn = asObject(update4.metadata)?.backendUrn;
|
|
30726
30748
|
return typeof urn === "string" ? urn : void 0;
|
|
30727
30749
|
}
|
|
30728
|
-
function buildVoyagerPost(
|
|
30729
|
-
const text18 = commentaryText(
|
|
30750
|
+
function buildVoyagerPost(update4, profiles) {
|
|
30751
|
+
const text18 = commentaryText(update4);
|
|
30730
30752
|
if (!text18) return void 0;
|
|
30731
|
-
const author = resolveVoyagerAuthor(
|
|
30753
|
+
const author = resolveVoyagerAuthor(update4);
|
|
30732
30754
|
const { mentions, hashtags, links: links2 } = collectVoyagerAttributes(
|
|
30733
|
-
|
|
30755
|
+
update4,
|
|
30734
30756
|
profiles,
|
|
30735
30757
|
author?.slug
|
|
30736
30758
|
);
|
|
30737
|
-
const activityUrn = activityUrnOf(
|
|
30759
|
+
const activityUrn = activityUrnOf(update4);
|
|
30738
30760
|
return {
|
|
30739
30761
|
text: text18,
|
|
30740
30762
|
markdown: linkifyMentions(text18, mentions),
|
|
@@ -30802,9 +30824,9 @@ function extractVoyagerPosts(body) {
|
|
|
30802
30824
|
const profiles = voyagerProfileMentions(included);
|
|
30803
30825
|
const posts = [];
|
|
30804
30826
|
for (const ref of elementUrns(rootObj)) {
|
|
30805
|
-
const
|
|
30806
|
-
if (!
|
|
30807
|
-
const post2 = buildVoyagerPost(
|
|
30827
|
+
const update4 = byUrn.get(ref);
|
|
30828
|
+
if (!update4) continue;
|
|
30829
|
+
const post2 = buildVoyagerPost(update4, profiles);
|
|
30808
30830
|
if (post2) posts.push(post2);
|
|
30809
30831
|
}
|
|
30810
30832
|
return posts;
|
|
@@ -33971,7 +33993,7 @@ async function writeConfigKeys(writes, scope, cwd = process.cwd()) {
|
|
|
33971
33993
|
return {
|
|
33972
33994
|
ok: false,
|
|
33973
33995
|
errors: globalOnly.map(
|
|
33974
|
-
(write) => `"${write.key}" is a
|
|
33996
|
+
(write) => `"${write.key}" is a user (node)-only key. Set it with 'assist config set ${write.key} <value> --node'`
|
|
33975
33997
|
)
|
|
33976
33998
|
};
|
|
33977
33999
|
}
|
|
@@ -33979,7 +34001,7 @@ async function writeConfigKeys(writes, scope, cwd = process.cwd()) {
|
|
|
33979
34001
|
const applied = applyConfigWrites(loadProjectConfig(cwd), writes);
|
|
33980
34002
|
if (!applied.ok) return applied;
|
|
33981
34003
|
saveConfig(applied.updated, cwd);
|
|
33982
|
-
return { ok: true, target: "
|
|
34004
|
+
return { ok: true, target: "repo (git), this repo's assist.yml" };
|
|
33983
34005
|
}
|
|
33984
34006
|
async function writeRepoBlock(writes, cwd) {
|
|
33985
34007
|
const orm = await getDb();
|
|
@@ -33987,7 +34009,10 @@ async function writeRepoBlock(writes, cwd) {
|
|
|
33987
34009
|
const applied = applyConfigWrites(block, writes, repoConfigSchema);
|
|
33988
34010
|
if (!applied.ok) return applied;
|
|
33989
34011
|
await saveSharedRepoBlock(orm, label, applied.updated);
|
|
33990
|
-
return {
|
|
34012
|
+
return {
|
|
34013
|
+
ok: true,
|
|
34014
|
+
target: `repo (db), ${SHARED_REPO_CONFIG_SOURCE}, repo: ${label}`
|
|
34015
|
+
};
|
|
33991
34016
|
}
|
|
33992
34017
|
|
|
33993
34018
|
// src/commands/releases/declaredStreamsInScope.ts
|
|
@@ -37115,11 +37140,11 @@ async function promptConfigScope() {
|
|
|
37115
37140
|
choices: [
|
|
37116
37141
|
{
|
|
37117
37142
|
name: "repo",
|
|
37118
|
-
message: "this repo's override in the shared db \u2014 personal, seen by every node, as 'config set
|
|
37143
|
+
message: "repo (db): this repo's override in the shared db \u2014 personal, seen by every node, as 'config set --repo' writes it"
|
|
37119
37144
|
},
|
|
37120
37145
|
{
|
|
37121
37146
|
name: "project",
|
|
37122
|
-
message: "assist.yml in this repo \u2014 checked in, shared with the team"
|
|
37147
|
+
message: "repo (git): assist.yml in this repo \u2014 checked in, shared with the team"
|
|
37123
37148
|
}
|
|
37124
37149
|
]
|
|
37125
37150
|
}).run()
|
|
@@ -37840,15 +37865,15 @@ function checkDescriptionSections(body) {
|
|
|
37840
37865
|
}
|
|
37841
37866
|
|
|
37842
37867
|
// src/commands/review/highLevel/checkDescriptionWordCap.ts
|
|
37843
|
-
function checkDescriptionWordCap(body,
|
|
37868
|
+
function checkDescriptionWordCap(body, cap3) {
|
|
37844
37869
|
const { prose, code } = countReadingWords(body);
|
|
37845
37870
|
const words = prose + code;
|
|
37846
|
-
if (words >
|
|
37871
|
+
if (words > cap3)
|
|
37847
37872
|
return {
|
|
37848
37873
|
status: "fail",
|
|
37849
|
-
reason: `${words} words, ${words -
|
|
37874
|
+
reason: `${words} words, ${words - cap3} over the ${cap3}-word cap`
|
|
37850
37875
|
};
|
|
37851
|
-
return { status: "pass", reason: `${words} of ${
|
|
37876
|
+
return { status: "pass", reason: `${words} of ${cap3} words` };
|
|
37852
37877
|
}
|
|
37853
37878
|
|
|
37854
37879
|
// src/commands/review/highLevel/checkNoMergeConflicts.ts
|
|
@@ -45972,6 +45997,25 @@ function toSessionRunInfo({
|
|
|
45972
45997
|
};
|
|
45973
45998
|
}
|
|
45974
45999
|
|
|
46000
|
+
// src/commands/sessions/daemon/toSessionViewInfo.ts
|
|
46001
|
+
function toSessionViewInfo({
|
|
46002
|
+
lastUserMessage,
|
|
46003
|
+
lastAssistantMessage,
|
|
46004
|
+
cols,
|
|
46005
|
+
rows,
|
|
46006
|
+
activeViewer,
|
|
46007
|
+
activeViewerNode
|
|
46008
|
+
}) {
|
|
46009
|
+
return {
|
|
46010
|
+
lastUserMessage,
|
|
46011
|
+
lastAssistantMessage,
|
|
46012
|
+
cols,
|
|
46013
|
+
rows,
|
|
46014
|
+
activeViewer,
|
|
46015
|
+
activeViewerNode
|
|
46016
|
+
};
|
|
46017
|
+
}
|
|
46018
|
+
|
|
45975
46019
|
// src/commands/sessions/daemon/worktree/joinRefusal.ts
|
|
45976
46020
|
import { existsSync as existsSync85 } from "fs";
|
|
45977
46021
|
function joinRefusal(session) {
|
|
@@ -46006,13 +46050,11 @@ function toSessionInfo(session) {
|
|
|
46006
46050
|
seeding,
|
|
46007
46051
|
pendingPrPreview,
|
|
46008
46052
|
pendingShow,
|
|
46009
|
-
undurable
|
|
46010
|
-
lastUserMessage,
|
|
46011
|
-
activeViewer,
|
|
46012
|
-
activeViewerNode
|
|
46053
|
+
undurable
|
|
46013
46054
|
} = session;
|
|
46014
46055
|
return {
|
|
46015
46056
|
...toSessionRunInfo(session),
|
|
46057
|
+
...toSessionViewInfo(session),
|
|
46016
46058
|
id,
|
|
46017
46059
|
name,
|
|
46018
46060
|
title,
|
|
@@ -46035,9 +46077,6 @@ function toSessionInfo(session) {
|
|
|
46035
46077
|
pendingPrPreview,
|
|
46036
46078
|
pendingShow,
|
|
46037
46079
|
undurable,
|
|
46038
|
-
lastUserMessage,
|
|
46039
|
-
activeViewer,
|
|
46040
|
-
activeViewerNode,
|
|
46041
46080
|
promptIssue: promptIssueRef(session.initialPrompt),
|
|
46042
46081
|
promptPr: promptPrNumber(session.initialPrompt),
|
|
46043
46082
|
joinable: joinRefusal(session) === void 0
|
|
@@ -46550,10 +46589,13 @@ var SessionIo = class {
|
|
|
46550
46589
|
}
|
|
46551
46590
|
writeAsDaemon = (id, data) => this.write(id, data, {});
|
|
46552
46591
|
resize(id, cols, rows, viewer) {
|
|
46592
|
+
const s = this.sessions.get(id);
|
|
46593
|
+
const before = `${s?.cols}x${s?.rows}`;
|
|
46553
46594
|
resizeSession(this.sessions, id, cols, rows, {
|
|
46554
46595
|
...viewer,
|
|
46555
46596
|
onClaim: this.notify
|
|
46556
46597
|
});
|
|
46598
|
+
if (s && `${s.cols}x${s.rows}` !== before) this.notify();
|
|
46557
46599
|
}
|
|
46558
46600
|
};
|
|
46559
46601
|
|
|
@@ -48917,73 +48959,6 @@ function deriveTranscriptStatus(entries, opts = {}) {
|
|
|
48917
48959
|
return "running";
|
|
48918
48960
|
}
|
|
48919
48961
|
|
|
48920
|
-
// src/commands/sessions/shared/renderPrompt.ts
|
|
48921
|
-
function renderPrompt(raw) {
|
|
48922
|
-
const command = marker(raw, "command-name");
|
|
48923
|
-
if (command) {
|
|
48924
|
-
const args = marker(raw, "command-args");
|
|
48925
|
-
const name = `/${command.replace(/^\/+/, "")}`;
|
|
48926
|
-
return args ? `${name} ${args}` : name;
|
|
48927
|
-
}
|
|
48928
|
-
const bashInput = marker(raw, "bash-input");
|
|
48929
|
-
if (bashInput) return `! ${bashInput}`;
|
|
48930
|
-
return stripBlocks(raw);
|
|
48931
|
-
}
|
|
48932
|
-
function marker(raw, tag) {
|
|
48933
|
-
const match = raw.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
|
|
48934
|
-
return match ? match[1].trim() : "";
|
|
48935
|
-
}
|
|
48936
|
-
function stripBlocks(raw) {
|
|
48937
|
-
return raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").replace(/<task-notification>[\s\S]*?<\/task-notification>/g, "").replace(/<command-[^>]*>[\s\S]*?<\/command-[^>]*>/g, "").replace(/<local-command-[^>]*>[\s\S]*?<\/local-command-[^>]*>/g, "").replace(/<bash-(stdout|stderr)>[\s\S]*?<\/bash-\1>/g, "").trim();
|
|
48938
|
-
}
|
|
48939
|
-
|
|
48940
|
-
// src/commands/sessions/shared/renderUserPrompt.ts
|
|
48941
|
-
var MAX_LENGTH = 2048;
|
|
48942
|
-
var INTERRUPT_PREFIX2 = "[Request interrupted";
|
|
48943
|
-
function renderUserPrompt(entry, maxLength = MAX_LENGTH) {
|
|
48944
|
-
if (entry.isSidechain || entry.isMeta) return void 0;
|
|
48945
|
-
if (entry.type !== "user" || isTaskNotification(entry)) return void 0;
|
|
48946
|
-
const raw = promptTextOrNull(entry);
|
|
48947
|
-
if (raw === null) return void 0;
|
|
48948
|
-
const message3 = renderPrompt(raw);
|
|
48949
|
-
return message3 ? cap(message3, maxLength) : void 0;
|
|
48950
|
-
}
|
|
48951
|
-
function isTaskNotification(entry) {
|
|
48952
|
-
return asRecord4(entry.origin)?.kind === "task-notification";
|
|
48953
|
-
}
|
|
48954
|
-
function promptTextOrNull(entry) {
|
|
48955
|
-
const content = asRecord4(entry.message)?.content;
|
|
48956
|
-
if (typeof content === "string") return isInterrupt(content) ? null : content;
|
|
48957
|
-
if (!Array.isArray(content)) return null;
|
|
48958
|
-
const parts = [];
|
|
48959
|
-
for (const block of content) {
|
|
48960
|
-
const b = asRecord4(block);
|
|
48961
|
-
if (b?.type !== "text") continue;
|
|
48962
|
-
const text18 = typeof b.text === "string" ? b.text : "";
|
|
48963
|
-
if (isInterrupt(text18)) return null;
|
|
48964
|
-
parts.push(text18);
|
|
48965
|
-
}
|
|
48966
|
-
return parts.length === 0 ? null : parts.join("\n");
|
|
48967
|
-
}
|
|
48968
|
-
function cap(message3, maxLength) {
|
|
48969
|
-
return message3.length <= maxLength ? message3 : `${message3.slice(0, maxLength).trimEnd()}\u2026`;
|
|
48970
|
-
}
|
|
48971
|
-
function isInterrupt(value) {
|
|
48972
|
-
return value.trimStart().startsWith(INTERRUPT_PREFIX2);
|
|
48973
|
-
}
|
|
48974
|
-
function asRecord4(value) {
|
|
48975
|
-
return value && typeof value === "object" ? value : null;
|
|
48976
|
-
}
|
|
48977
|
-
|
|
48978
|
-
// src/commands/sessions/shared/extractLastUserMessage.ts
|
|
48979
|
-
function extractLastUserMessage(entries, maxLength) {
|
|
48980
|
-
for (let i = entries.length - 1; i >= 0; i--) {
|
|
48981
|
-
const message3 = renderUserPrompt(entries[i], maxLength);
|
|
48982
|
-
if (message3) return message3;
|
|
48983
|
-
}
|
|
48984
|
-
return void 0;
|
|
48985
|
-
}
|
|
48986
|
-
|
|
48987
48962
|
// src/commands/sessions/shared/readTranscriptTail.ts
|
|
48988
48963
|
import * as fs52 from "fs";
|
|
48989
48964
|
var DEFAULT_MAX_BYTES = 256 * 1024;
|
|
@@ -49058,16 +49033,128 @@ function transcriptTailFingerprint(entries) {
|
|
|
49058
49033
|
return null;
|
|
49059
49034
|
}
|
|
49060
49035
|
|
|
49061
|
-
// src/commands/sessions/
|
|
49062
|
-
|
|
49063
|
-
|
|
49064
|
-
|
|
49065
|
-
|
|
49036
|
+
// src/commands/sessions/shared/extractLastAssistantMessage.ts
|
|
49037
|
+
var MAX_LENGTH = 500;
|
|
49038
|
+
function extractLastAssistantMessage(entries) {
|
|
49039
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
49040
|
+
const entry = entries[i];
|
|
49041
|
+
if (entry.isSidechain || entry.type !== "assistant") continue;
|
|
49042
|
+
const text18 = assistantText(entry);
|
|
49043
|
+
if (text18) return cap(text18);
|
|
49044
|
+
}
|
|
49045
|
+
return void 0;
|
|
49046
|
+
}
|
|
49047
|
+
function assistantText(entry) {
|
|
49048
|
+
const content = asRecord4(entry.message)?.content;
|
|
49049
|
+
if (!Array.isArray(content)) return "";
|
|
49050
|
+
const parts = [];
|
|
49051
|
+
for (const block of content) {
|
|
49052
|
+
const b = asRecord4(block);
|
|
49053
|
+
if (b?.type === "text" && typeof b.text === "string" && b.text.trim())
|
|
49054
|
+
parts.push(b.text.trim());
|
|
49055
|
+
}
|
|
49056
|
+
return parts.join("\n");
|
|
49057
|
+
}
|
|
49058
|
+
function cap(text18) {
|
|
49059
|
+
return text18.length <= MAX_LENGTH ? text18 : `${text18.slice(0, MAX_LENGTH).trimEnd()}\u2026`;
|
|
49060
|
+
}
|
|
49061
|
+
function asRecord4(value) {
|
|
49062
|
+
return value && typeof value === "object" ? value : null;
|
|
49063
|
+
}
|
|
49064
|
+
|
|
49065
|
+
// src/commands/sessions/shared/renderPrompt.ts
|
|
49066
|
+
function renderPrompt(raw) {
|
|
49067
|
+
const command = marker(raw, "command-name");
|
|
49068
|
+
if (command) {
|
|
49069
|
+
const args = marker(raw, "command-args");
|
|
49070
|
+
const name = `/${command.replace(/^\/+/, "")}`;
|
|
49071
|
+
return args ? `${name} ${args}` : name;
|
|
49072
|
+
}
|
|
49073
|
+
const bashInput = marker(raw, "bash-input");
|
|
49074
|
+
if (bashInput) return `! ${bashInput}`;
|
|
49075
|
+
return stripBlocks(raw);
|
|
49076
|
+
}
|
|
49077
|
+
function marker(raw, tag) {
|
|
49078
|
+
const match = raw.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
|
|
49079
|
+
return match ? match[1].trim() : "";
|
|
49080
|
+
}
|
|
49081
|
+
function stripBlocks(raw) {
|
|
49082
|
+
return raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").replace(/<task-notification>[\s\S]*?<\/task-notification>/g, "").replace(/<command-[^>]*>[\s\S]*?<\/command-[^>]*>/g, "").replace(/<local-command-[^>]*>[\s\S]*?<\/local-command-[^>]*>/g, "").replace(/<bash-(stdout|stderr)>[\s\S]*?<\/bash-\1>/g, "").trim();
|
|
49083
|
+
}
|
|
49084
|
+
|
|
49085
|
+
// src/commands/sessions/shared/renderUserPrompt.ts
|
|
49086
|
+
var MAX_LENGTH2 = 2048;
|
|
49087
|
+
var INTERRUPT_PREFIX2 = "[Request interrupted";
|
|
49088
|
+
function renderUserPrompt(entry, maxLength = MAX_LENGTH2) {
|
|
49089
|
+
if (entry.isSidechain || entry.isMeta) return void 0;
|
|
49090
|
+
if (entry.type !== "user" || isTaskNotification(entry)) return void 0;
|
|
49091
|
+
const raw = promptTextOrNull(entry);
|
|
49092
|
+
if (raw === null) return void 0;
|
|
49093
|
+
const message3 = renderPrompt(raw);
|
|
49094
|
+
return message3 ? cap2(message3, maxLength) : void 0;
|
|
49095
|
+
}
|
|
49096
|
+
function isTaskNotification(entry) {
|
|
49097
|
+
return asRecord5(entry.origin)?.kind === "task-notification";
|
|
49098
|
+
}
|
|
49099
|
+
function promptTextOrNull(entry) {
|
|
49100
|
+
const content = asRecord5(entry.message)?.content;
|
|
49101
|
+
if (typeof content === "string") return isInterrupt(content) ? null : content;
|
|
49102
|
+
if (!Array.isArray(content)) return null;
|
|
49103
|
+
const parts = [];
|
|
49104
|
+
for (const block of content) {
|
|
49105
|
+
const b = asRecord5(block);
|
|
49106
|
+
if (b?.type !== "text") continue;
|
|
49107
|
+
const text18 = typeof b.text === "string" ? b.text : "";
|
|
49108
|
+
if (isInterrupt(text18)) return null;
|
|
49109
|
+
parts.push(text18);
|
|
49110
|
+
}
|
|
49111
|
+
return parts.length === 0 ? null : parts.join("\n");
|
|
49112
|
+
}
|
|
49113
|
+
function cap2(message3, maxLength) {
|
|
49114
|
+
return message3.length <= maxLength ? message3 : `${message3.slice(0, maxLength).trimEnd()}\u2026`;
|
|
49115
|
+
}
|
|
49116
|
+
function isInterrupt(value) {
|
|
49117
|
+
return value.trimStart().startsWith(INTERRUPT_PREFIX2);
|
|
49118
|
+
}
|
|
49119
|
+
function asRecord5(value) {
|
|
49120
|
+
return value && typeof value === "object" ? value : null;
|
|
49121
|
+
}
|
|
49122
|
+
|
|
49123
|
+
// src/commands/sessions/shared/extractLastUserMessage.ts
|
|
49124
|
+
function extractLastUserMessage(entries, maxLength) {
|
|
49125
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
49126
|
+
const message3 = renderUserPrompt(entries[i], maxLength);
|
|
49127
|
+
if (message3) return message3;
|
|
49128
|
+
}
|
|
49129
|
+
return void 0;
|
|
49130
|
+
}
|
|
49131
|
+
|
|
49132
|
+
// src/commands/sessions/daemon/updateLastMessages.ts
|
|
49133
|
+
function update3(session, field, message3, label) {
|
|
49134
|
+
if (message3 === session[field]) return false;
|
|
49135
|
+
session[field] = message3;
|
|
49066
49136
|
daemonLog(
|
|
49067
|
-
`session ${session.id} last
|
|
49137
|
+
`session ${session.id} last ${label} message: ${JSON.stringify(message3?.slice(0, 120) ?? null)}`
|
|
49068
49138
|
);
|
|
49069
|
-
|
|
49139
|
+
return true;
|
|
49070
49140
|
}
|
|
49141
|
+
function updateLastMessages(session, entries, notify2) {
|
|
49142
|
+
const user = update3(
|
|
49143
|
+
session,
|
|
49144
|
+
"lastUserMessage",
|
|
49145
|
+
extractLastUserMessage(entries),
|
|
49146
|
+
"user"
|
|
49147
|
+
);
|
|
49148
|
+
const assistant = update3(
|
|
49149
|
+
session,
|
|
49150
|
+
"lastAssistantMessage",
|
|
49151
|
+
extractLastAssistantMessage(entries),
|
|
49152
|
+
"assistant"
|
|
49153
|
+
);
|
|
49154
|
+
if (user || assistant) notify2?.();
|
|
49155
|
+
}
|
|
49156
|
+
|
|
49157
|
+
// src/commands/sessions/daemon/reconcileTranscriptStatus.ts
|
|
49071
49158
|
function isFinished(session) {
|
|
49072
49159
|
return session.status === "done" || session.status === "error" || session.status === "stopped";
|
|
49073
49160
|
}
|
|
@@ -49079,7 +49166,7 @@ async function reconcileTranscriptStatus(session, onStatusChange, notify2) {
|
|
|
49079
49166
|
if (fingerprint !== null && fingerprint === session.transcriptFingerprint)
|
|
49080
49167
|
return;
|
|
49081
49168
|
session.transcriptFingerprint = fingerprint ?? void 0;
|
|
49082
|
-
|
|
49169
|
+
updateLastMessages(session, entries, notify2);
|
|
49083
49170
|
if (isFinished(session)) return;
|
|
49084
49171
|
const derived = deriveTranscriptStatus(entries, {
|
|
49085
49172
|
permissionActive: session.permissionActive
|
|
@@ -49312,7 +49399,7 @@ var sessionLimits = {
|
|
|
49312
49399
|
`refusing to spawn: at ceiling of ${ceiling} live sessions (sessions.maxLive)`
|
|
49313
49400
|
);
|
|
49314
49401
|
throw new Error(
|
|
49315
|
-
`session ceiling of ${ceiling} reached \u2014 raise it with: assist config set sessions.maxLive <n>
|
|
49402
|
+
`session ceiling of ${ceiling} reached \u2014 raise it with: assist config set sessions.maxLive <n> --node`
|
|
49316
49403
|
);
|
|
49317
49404
|
}
|
|
49318
49405
|
return String(counter.next++);
|
|
@@ -50063,7 +50150,7 @@ function restoreBase(id, persisted) {
|
|
|
50063
50150
|
}
|
|
50064
50151
|
|
|
50065
50152
|
// src/commands/sessions/daemon/deferredSession.ts
|
|
50066
|
-
function deferredSession(id, persisted,
|
|
50153
|
+
function deferredSession(id, persisted, cap3) {
|
|
50067
50154
|
return {
|
|
50068
50155
|
...restoreBase(id, persisted),
|
|
50069
50156
|
status: "stopped",
|
|
@@ -50077,13 +50164,13 @@ function deferredSession(id, persisted, cap2) {
|
|
|
50077
50164
|
runArgs: persisted.runArgs,
|
|
50078
50165
|
activity: persisted.activity,
|
|
50079
50166
|
restored: false,
|
|
50080
|
-
scrollback: deferralNotice(persisted,
|
|
50167
|
+
scrollback: deferralNotice(persisted, cap3)
|
|
50081
50168
|
};
|
|
50082
50169
|
}
|
|
50083
|
-
function deferralNotice(persisted,
|
|
50170
|
+
function deferralNotice(persisted, cap3) {
|
|
50084
50171
|
return [
|
|
50085
50172
|
`\r
|
|
50086
|
-
\x1B[33mNot resumed: restore was already at its cap of ${
|
|
50173
|
+
\x1B[33mNot resumed: restore was already at its cap of ${cap3} session(s) (raise it with: assist config set sessions.maxLive <n> --node)\x1B[0m\r
|
|
50087
50174
|
`,
|
|
50088
50175
|
`This card is the handle for it. Its command, working directory (${persisted.cwd})\r
|
|
50089
50176
|
`,
|
|
@@ -50639,23 +50726,23 @@ function logRestoreError(persisted, error) {
|
|
|
50639
50726
|
// src/commands/sessions/daemon/restoreAll.ts
|
|
50640
50727
|
function restoreAll(spawner, sessions) {
|
|
50641
50728
|
const persisted = dropUnrestorableSessions(loadPersistedSessions());
|
|
50642
|
-
const
|
|
50729
|
+
const cap3 = sessionLimits.maxRestore();
|
|
50643
50730
|
const restoredIds = /* @__PURE__ */ new Map();
|
|
50644
|
-
const names = persisted.slice(0,
|
|
50731
|
+
const names = persisted.slice(0, cap3).map((entry) => {
|
|
50645
50732
|
const id = restoreOne(entry, spawner, sessions);
|
|
50646
50733
|
if (entry.id != null && id != null) restoredIds.set(entry.id, id);
|
|
50647
50734
|
return entry.name;
|
|
50648
50735
|
});
|
|
50649
|
-
for (const over of persisted.slice(
|
|
50650
|
-
deferOne(over, spawner.recoveryCard,
|
|
50736
|
+
for (const over of persisted.slice(cap3))
|
|
50737
|
+
deferOne(over, spawner.recoveryCard, cap3);
|
|
50651
50738
|
remapLaunchedFrom(sessions, restoredIds);
|
|
50652
50739
|
return names;
|
|
50653
50740
|
}
|
|
50654
|
-
function deferOne(persisted, spawnRecoveryCard,
|
|
50741
|
+
function deferOne(persisted, spawnRecoveryCard, cap3) {
|
|
50655
50742
|
try {
|
|
50656
|
-
const id = spawnRecoveryCard((sid) => deferredSession(sid, persisted,
|
|
50743
|
+
const id = spawnRecoveryCard((sid) => deferredSession(sid, persisted, cap3));
|
|
50657
50744
|
daemonLog(
|
|
50658
|
-
`restore capped at ${
|
|
50745
|
+
`restore capped at ${cap3} (sessions.maxLive): ${describePersistedSession(persisted)} deferred to stopped card ${id}`
|
|
50659
50746
|
);
|
|
50660
50747
|
} catch (error) {
|
|
50661
50748
|
logDroppedSession(persisted, error);
|