knodin 0.8.7 → 0.10.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/dist/bin/cli.js +341 -91
- package/dist/fixtures/update-verification/config/application.xml +4 -0
- package/dist/fixtures/update-verification/dbt/manifest.json +17 -0
- package/dist/fixtures/update-verification/dbt/models/accounts.sql +1 -0
- package/dist/fixtures/update-verification/dbt/models/contacts.sql +1 -0
- package/dist/fixtures/update-verification/fixture.json +147 -0
- package/dist/fixtures/update-verification/force-app/main/default/classes/UpdateFixture.cls +14 -0
- package/dist/fixtures/update-verification/force-app/main/default/flows/Update_Verification.flow-meta.xml +9 -0
- package/dist/fixtures/update-verification/package.json +5 -0
- package/dist/fixtures/update-verification/prisma/schema.prisma +10 -0
- package/dist/fixtures/update-verification/sql/functions.sql +16 -0
- package/dist/fixtures/update-verification/src/CsharpFixture.cs +6 -0
- package/dist/fixtures/update-verification/src/JavaFixture.java +9 -0
- package/dist/fixtures/update-verification/src/javascript.js +7 -0
- package/dist/fixtures/update-verification/src/python_fixture.py +6 -0
- package/dist/fixtures/update-verification/src/typescript.ts +7 -0
- package/dist/fixtures/update-verification/terraform/main.tf +7 -0
- package/dist/fixtures/update-verification/terraform/modules/verified-child/main.tf +3 -0
- package/dist/src/agent-integration.js +26 -3
- package/dist/src/backup-retention.js +811 -0
- package/dist/src/cli-model.js +49 -8
- package/dist/src/docs-sections.js +1 -0
- package/dist/src/doctor.js +142 -12
- package/dist/src/engine/embeddings.js +8 -1
- package/dist/src/engine/index.js +1272 -645
- package/dist/src/engine/parse-pool-resources.js +96 -0
- package/dist/src/engine/parse-pool.js +352 -0
- package/dist/src/engine/parse-protocol.js +1 -0
- package/dist/src/engine/parse-worker.js +51 -0
- package/dist/src/engine/reflink-copy.js +23 -0
- package/dist/src/engine/seal-command.js +116 -0
- package/dist/src/engine/seal.js +270 -0
- package/dist/src/engine/sealed-open.js +116 -0
- package/dist/src/engine/sealed-query.js +49 -0
- package/dist/src/init.js +251 -183
- package/dist/src/manager-update.js +455 -0
- package/dist/src/release-preflight.js +106 -95
- package/dist/src/repair-lease.js +77 -8
- package/dist/src/response-budget.js +5 -1
- package/dist/src/server.js +18 -5
- package/dist/src/shared-index/compatibility.js +4 -2
- package/dist/src/shared-index/selection.js +1 -1
- package/dist/src/tools/knodin-tools.js +85 -13
- package/dist/src/update-ceremony.js +20 -24
- package/dist/src/update-coordination.js +158 -0
- package/dist/src/update-executor.js +355 -0
- package/dist/src/update-verifier.js +358 -0
- package/dist/src/worktree-seed.js +172 -0
- package/docs/BACKUP-RETENTION.md +54 -0
- package/docs/CLI.md +6 -0
- package/docs/DOCTOR-AND-UPDATES.md +44 -12
- package/docs/SHARED-INDEX-CONTRACT.md +9 -0
- package/docs/SIGNED-UPDATES.md +29 -22
- package/docs/releases/0.10.0.md +127 -0
- package/docs/releases/0.9.0.md +43 -0
- package/package.json +8 -1
- package/roadmap/competitive-roadmap.md +8 -0
package/dist/bin/cli.js
CHANGED
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
import { spawn, spawnSync } from "node:child_process";
|
|
15
15
|
import fs from "node:fs";
|
|
16
16
|
import path from "node:path";
|
|
17
|
-
import readline from "node:readline/promises";
|
|
18
17
|
import { fileURLToPath } from "node:url";
|
|
19
18
|
import { canUseSessionContextCache, parseClaudeHookPayload, readSessionContextCache, recordClaudeLifecycleEvent, renderSessionContext, SESSION_CONTEXT_BUDGET_LINE, sessionStartHookOutput, writeSessionContextCache, } from "../src/agent-events.js";
|
|
20
19
|
import { inspectClaudeAgentHooks, installClaudeAgentHooks, uninstallClaudeAgentHooks, } from "../src/agent-hooks.js";
|
|
21
20
|
import { detectSupportedAgents, parseInitScope, } from "../src/agent-integration.js";
|
|
22
21
|
import { refreshExternalGraphArtifacts, writeArtifactRefreshRecord, } from "../src/artifact-refresh.js";
|
|
22
|
+
import { formatBackupHuman, installBackupRetention, listBackups, maybeRunOpportunisticRetention, pruneBackups, removeBackupRetention, retentionDoctor, retentionStatus, runInstalledRetention, } from "../src/backup-retention.js";
|
|
23
23
|
import { checkIndexed, extractPositionals, extractRepoFlag, parseReviewArgs, planIndex, resolveCliRuntimeCommand, resolveRepo, } from "../src/cli-args.js";
|
|
24
24
|
import { helpCommandPath, parseCliInvocation, renderCliHelp } from "../src/cli-model.js";
|
|
25
25
|
import { buildKnodinContext } from "../src/context.js";
|
|
@@ -27,20 +27,24 @@ import { exportContext, grepPackedArtifact, readPackedArtifact } from "../src/co
|
|
|
27
27
|
import { clearDiagnostics, collectDiagnostics, diagnosticsStatus, disableDiagnostics, enableDiagnostics, inspectDiagnosticsBundle, persistDiagnosticsPreview, recordDiagnosticFailure, } from "../src/diagnostics.js";
|
|
28
28
|
import { getDocSection, listDocTopics } from "../src/docs-sections.js";
|
|
29
29
|
import { diagnoseInstallation } from "../src/doctor.js";
|
|
30
|
-
import { createEngine, REPO_WIDE_QUERY_PATTERNS, } from "../src/engine/index.js";
|
|
30
|
+
import { createEngine, KNODIN_SCHEMA_VERSION, REPO_WIDE_QUERY_PATTERNS, } from "../src/engine/index.js";
|
|
31
|
+
import { runSeal } from "../src/engine/seal-command.js";
|
|
32
|
+
import { runSealedQuery } from "../src/engine/sealed-query.js";
|
|
31
33
|
import { resolveDbPath } from "../src/engine/state-paths.js";
|
|
32
34
|
import { diagnoseFailure, } from "../src/failure-diagnosis.js";
|
|
33
35
|
import { gitExecutable } from "../src/git-executable.js";
|
|
34
36
|
import { decorateGraphQueryResult, inspectGraphQueryHealth } from "../src/graph-query-health.js";
|
|
35
37
|
import { createIndexActivityReporter } from "../src/index-activity.js";
|
|
36
|
-
import {
|
|
38
|
+
import { InitializationHealthError, initializeRepository, inspectRepositoryIntegrationStatus, readRepositoryIntegrationConfig, refreshFromGitEvent, } from "../src/init.js";
|
|
37
39
|
import { createInitProgressRenderer } from "../src/init-progress.js";
|
|
38
40
|
import { attachLifecycleHealth, attachRepairLifecycle } from "../src/lifecycle-health.js";
|
|
41
|
+
import { acknowledgeUpdateFailure, queryOwnerAvailability, readManagerUpdateState, readUpdateJournal, resolveManagerOwnership, setManualPin, unpinUpdate, updateAttention, writeManagerUpdateState, } from "../src/manager-update.js";
|
|
39
42
|
import { addMirror, listMirrors, refreshMirror, removeMirror } from "../src/mirror.js";
|
|
40
43
|
import { compressOutput, compressOutputFile, deleteOutputArtifact, readOutputArtifact, } from "../src/output-compression.js";
|
|
41
44
|
import { clearTelemetry, exportTelemetry, readTelemetryRecords, telemetryStatus, writeTelemetryReport, } from "../src/output-telemetry.js";
|
|
42
45
|
import { auditPullRequests } from "../src/pr-triage.js";
|
|
43
46
|
import { deliverProgressiveEvidence, } from "../src/progressive-evidence.js";
|
|
47
|
+
import { acquireRepairLease } from "../src/repair-lease.js";
|
|
44
48
|
import { createRepairPlan, createRepairProgressRenderer, parseRepairCliArgs, resolveRepairProgressMode, serializeRepairJsonlRecord, } from "../src/repair-progress.js";
|
|
45
49
|
import { runRepositoryInitializationProcess } from "../src/repository-init-process.js";
|
|
46
50
|
import { detectRepositorySignals, discoverRepositories, formatRepositoryHuman, initializeRepositories, inventoryRepository, parseFleetInitArgs, parseRepositoryCommandArgs, repositorySignalInspectionLimit, searchRepositories, withRepositorySignals, } from "../src/repository-management.js";
|
|
@@ -49,11 +53,14 @@ import { appendSessionEvent, clearSessionTelemetry, disableSessionTelemetry, ena
|
|
|
49
53
|
import { inspectKnodinSkills, installKnodinSkills, KNODIN_SKILLS, removeKnodinSkills, } from "../src/skill-management.js";
|
|
50
54
|
import { configuredRepositoryInitMemoryLimitBytes, enrichSystemRelationships, incorporateSystemQueryEvidence, indexModeForPath, loadSystemConfiguration, queryConfiguredSystem, systemMembershipsForPath, validateSystemHealth, } from "../src/system-config.js";
|
|
51
55
|
import { applySystemPlan, planSystemImport, planSystemLink, planSystemRelate, planSystemUnlink, planSystemUnrelate, } from "../src/system-management.js";
|
|
56
|
+
import { coordinationStatus } from "../src/update-coordination.js";
|
|
57
|
+
import { certifyAutomaticUpdates, executeManagerUpdate, recoverInterruptedUpdate, } from "../src/update-executor.js";
|
|
52
58
|
import { applyTrustedUpdate, checkTrustedUpdate, claimScheduledUpdateCheck, detectUpdateInstallMethod, explainTrustedUpdate, releaseScheduledUpdateCheck, rollbackTrustedUpdate, trustedUpdateStatus, } from "../src/update-policy.js";
|
|
53
59
|
import { KNODIN_VERSION } from "../src/version.js";
|
|
54
60
|
import { writeVisualization, } from "../src/visualization.js";
|
|
55
61
|
import { waitForFresh } from "../src/wait-for-fresh.js";
|
|
56
62
|
import { inspectWorktrees, reconcileWorktrees, removeManagedWorktree, } from "../src/worktree-lifecycle.js";
|
|
63
|
+
import { indexOrSeed } from "../src/worktree-seed.js";
|
|
57
64
|
function explicitScope(args) {
|
|
58
65
|
const index = args.indexOf("--scope");
|
|
59
66
|
if (index >= 0) {
|
|
@@ -65,44 +72,6 @@ function explicitScope(args) {
|
|
|
65
72
|
const equals = args.find((argument) => argument.startsWith("--scope="));
|
|
66
73
|
return equals ? parseInitScope(equals.slice("--scope=".length)) : null;
|
|
67
74
|
}
|
|
68
|
-
async function chooseInitScope(args, repo) {
|
|
69
|
-
const selected = explicitScope(args);
|
|
70
|
-
if (selected)
|
|
71
|
-
return selected;
|
|
72
|
-
if (detectTrackedTeamIntegration(repo)) {
|
|
73
|
-
process.stderr.write("[init:scope] Detected tracked knodin team integration; preserving team scope\n");
|
|
74
|
-
return "team";
|
|
75
|
-
}
|
|
76
|
-
if (!process.stdin.isTTY || !process.stderr.isTTY)
|
|
77
|
-
return "personal";
|
|
78
|
-
const prompt = readline.createInterface({
|
|
79
|
-
input: process.stdin,
|
|
80
|
-
output: process.stderr,
|
|
81
|
-
});
|
|
82
|
-
try {
|
|
83
|
-
const answer = await prompt.question([
|
|
84
|
-
"How should knodin integrate with coding agents?",
|
|
85
|
-
" 1. Personal (recommended) — all detected agents; Git stays clean",
|
|
86
|
-
" 2. Team — create commit-ready shared configuration",
|
|
87
|
-
" 3. CLI-only — agents will not discover or invoke knodin automatically",
|
|
88
|
-
"Select [1]: ",
|
|
89
|
-
].join("\n"));
|
|
90
|
-
if (!answer.trim() || answer.trim() === "1")
|
|
91
|
-
return "personal";
|
|
92
|
-
if (answer.trim() === "2")
|
|
93
|
-
return "team";
|
|
94
|
-
if (answer.trim() === "3") {
|
|
95
|
-
const confirmation = await prompt.question("CLI-only requires manual knodin commands. Continue? [y/N] ");
|
|
96
|
-
if (!/^y(?:es)?$/i.test(confirmation.trim()))
|
|
97
|
-
throw new Error("knodin init: CLI-only selection cancelled");
|
|
98
|
-
return "cli-only";
|
|
99
|
-
}
|
|
100
|
-
return parseInitScope(answer.trim());
|
|
101
|
-
}
|
|
102
|
-
finally {
|
|
103
|
-
prompt.close();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
75
|
function integrationAgents(repo) {
|
|
107
76
|
const previous = readRepositoryIntegrationConfig(repo)?.agents ?? [];
|
|
108
77
|
const repositoryDetected = inspectRepositoryIntegrationStatus(repo)?.agents ?? [];
|
|
@@ -151,7 +120,7 @@ function formatConfigureHuman(result) {
|
|
|
151
120
|
const externalOutcomeLines = result.paths.externalConfigurationOutcomes
|
|
152
121
|
.map(({ system, state }) => `\nExternal configuration outcome: ${system} ${state} (external mutation not locally observable)`)
|
|
153
122
|
.join("");
|
|
154
|
-
return `${result.message}\nAgent integration: ${result.paths.scope} — ${configured}${failures}${filesystemMutationLines}${externalOutcomeLines}\nGraph initialization:
|
|
123
|
+
return `${result.message}\nAgent integration: ${result.paths.scope} — ${configured}${failures}${filesystemMutationLines}${externalOutcomeLines}\nGraph initialization: refreshed and verified\nLifecycle refresh: ${refresh}\nNext: ${result.nextAction}\n`;
|
|
155
124
|
}
|
|
156
125
|
function formatRepairHuman(result) {
|
|
157
126
|
const coverage = result.after.coverage;
|
|
@@ -652,7 +621,7 @@ async function main() {
|
|
|
652
621
|
depth: 0,
|
|
653
622
|
include: [repository],
|
|
654
623
|
command: resolveCliRuntimeCommand(process),
|
|
655
|
-
index: (
|
|
624
|
+
index: indexOrSeed(engine, KNODIN_SCHEMA_VERSION),
|
|
656
625
|
status: (target) => engine.status(target),
|
|
657
626
|
agents: detectSupportedAgents(),
|
|
658
627
|
indexMode: (target) => indexModeForPath(loadSystemConfiguration(target), target),
|
|
@@ -705,6 +674,26 @@ async function main() {
|
|
|
705
674
|
// `--json` is a shared output flag. Repair owns its richer --json/--jsonl
|
|
706
675
|
// parser; all other commands receive their original arguments minus it.
|
|
707
676
|
const rest = cmd === "repair" ? rawRest : rawRest.filter((argument) => argument !== "--json");
|
|
677
|
+
let recoveryJournal = readUpdateJournal();
|
|
678
|
+
const recoverySafeStates = new Set(["planned", "candidate-verified", "rollback-verified"]);
|
|
679
|
+
if (recoveryJournal && !recoverySafeStates.has(recoveryJournal.state) && cmd !== "doctor") {
|
|
680
|
+
const recovery = await recoverInterruptedUpdate({ runtimeCommand, env: process.env });
|
|
681
|
+
recoveryJournal = readUpdateJournal();
|
|
682
|
+
if (recovery?.status === "terminal-unhealthy" && cmd !== "update") {
|
|
683
|
+
throw new Error(`knodin update recovery is terminal-unhealthy: ${recovery.reason ?? "candidate and rollback verification failed"}`);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (recoveryJournal &&
|
|
687
|
+
!recoverySafeStates.has(recoveryJournal.state) &&
|
|
688
|
+
cmd !== "update" &&
|
|
689
|
+
cmd !== "doctor") {
|
|
690
|
+
throw new Error(`knodin is in unverified update state ${recoveryJournal.state}; run \`knodin update status\` for recovery guidance`);
|
|
691
|
+
}
|
|
692
|
+
if (!jsonOutput && cmd !== "update") {
|
|
693
|
+
const attention = updateAttention(readManagerUpdateState());
|
|
694
|
+
if (attention)
|
|
695
|
+
process.stderr.write(`${attention}\n`);
|
|
696
|
+
}
|
|
708
697
|
const selector = {
|
|
709
698
|
identity: selectorValue("--identity"),
|
|
710
699
|
file: selectorValue("--file"),
|
|
@@ -776,7 +765,7 @@ async function main() {
|
|
|
776
765
|
depth: plan.depth,
|
|
777
766
|
dryRun: plan.dryRun,
|
|
778
767
|
worktrees: plan.worktrees,
|
|
779
|
-
index: (
|
|
768
|
+
index: indexOrSeed(engine, KNODIN_SCHEMA_VERSION),
|
|
780
769
|
status: (target) => engine.status(target),
|
|
781
770
|
agents: detectSupportedAgents(),
|
|
782
771
|
indexMode: (target) => indexModeForPath(systemConfig, target),
|
|
@@ -826,7 +815,11 @@ async function main() {
|
|
|
826
815
|
repositories,
|
|
827
816
|
};
|
|
828
817
|
const boundedOutput = plan.signals
|
|
829
|
-
? applyResponseBudget(output, "repositories:discover", {
|
|
818
|
+
? applyResponseBudget(output, "repositories:discover", {
|
|
819
|
+
bytes: plan.byteBudget,
|
|
820
|
+
tokens: plan.tokenBudget,
|
|
821
|
+
items: plan.itemBudget,
|
|
822
|
+
}, { bytes: 65_536, tokens: 16_384, items: 100 })
|
|
830
823
|
: output;
|
|
831
824
|
process.stdout.write(`${JSON.stringify(boundedOutput, null, plan.json ? 0 : 2)}\n`);
|
|
832
825
|
process.exitCode = discovery.issues.length > 0 ? 1 : 0;
|
|
@@ -880,7 +873,7 @@ async function main() {
|
|
|
880
873
|
manifestPath: plan.manifestPath,
|
|
881
874
|
include: plan.include,
|
|
882
875
|
exclude: plan.exclude,
|
|
883
|
-
index: (
|
|
876
|
+
index: indexOrSeed(engine, KNODIN_SCHEMA_VERSION),
|
|
884
877
|
status: (target) => engine.status(target),
|
|
885
878
|
agents: detectSupportedAgents(),
|
|
886
879
|
indexMode: (target) => indexModeForPath(systemConfig, target),
|
|
@@ -903,7 +896,12 @@ async function main() {
|
|
|
903
896
|
}));
|
|
904
897
|
}
|
|
905
898
|
await engine.close();
|
|
906
|
-
const output = {
|
|
899
|
+
const output = {
|
|
900
|
+
schemaVersion: 1,
|
|
901
|
+
command: "init",
|
|
902
|
+
...summary,
|
|
903
|
+
repositories,
|
|
904
|
+
};
|
|
907
905
|
process.stdout.write(plan.json ? `${JSON.stringify(output)}\n` : formatRepositoryHuman(summary));
|
|
908
906
|
process.exitCode = summary.exitCode;
|
|
909
907
|
return;
|
|
@@ -1010,13 +1008,15 @@ async function main() {
|
|
|
1010
1008
|
if (cmd === "update") {
|
|
1011
1009
|
if (repoFlag !== undefined)
|
|
1012
1010
|
throw new Error("knodin update does not accept --repo");
|
|
1013
|
-
const [action, ...
|
|
1014
|
-
if (!action
|
|
1015
|
-
throw new Error("knodin update requires
|
|
1016
|
-
}
|
|
1017
|
-
if (unsupported.length > 0)
|
|
1018
|
-
throw new Error(`knodin update ${action}: unknown argument ${unsupported[0]}`);
|
|
1011
|
+
const [action, ...actionArguments] = rest;
|
|
1012
|
+
if (!action)
|
|
1013
|
+
throw new Error("knodin update requires an action");
|
|
1019
1014
|
const method = detectUpdateInstallMethod(runtimeCommand);
|
|
1015
|
+
const owner = resolveManagerOwnership({
|
|
1016
|
+
runtimeCommand,
|
|
1017
|
+
executablePath: runtimeCommand.at(-1),
|
|
1018
|
+
env: process.env,
|
|
1019
|
+
});
|
|
1020
1020
|
const runManager = async (argv) => {
|
|
1021
1021
|
const [executable, ...arguments_] = argv;
|
|
1022
1022
|
if (!executable)
|
|
@@ -1052,8 +1052,16 @@ async function main() {
|
|
|
1052
1052
|
healthCheck,
|
|
1053
1053
|
};
|
|
1054
1054
|
let output;
|
|
1055
|
-
if (action === "status")
|
|
1056
|
-
output =
|
|
1055
|
+
if (action === "status") {
|
|
1056
|
+
output = {
|
|
1057
|
+
...trustedUpdateStatus(options),
|
|
1058
|
+
owner,
|
|
1059
|
+
managerState: readManagerUpdateState(),
|
|
1060
|
+
journal: readUpdateJournal(),
|
|
1061
|
+
coordination: coordinationStatus(),
|
|
1062
|
+
attention: updateAttention(readManagerUpdateState()),
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1057
1065
|
else if (action === "check") {
|
|
1058
1066
|
try {
|
|
1059
1067
|
output = await checkTrustedUpdate(options);
|
|
@@ -1067,11 +1075,178 @@ async function main() {
|
|
|
1067
1075
|
output = explainTrustedUpdate(options);
|
|
1068
1076
|
else if (action === "apply")
|
|
1069
1077
|
output = await applyTrustedUpdate(options);
|
|
1070
|
-
else
|
|
1078
|
+
else if (action === "rollback")
|
|
1071
1079
|
output = await rollbackTrustedUpdate(options);
|
|
1080
|
+
else if (action === "available") {
|
|
1081
|
+
output = await queryOwnerAvailability({ installedVersion: KNODIN_VERSION, owner });
|
|
1082
|
+
const availability = output;
|
|
1083
|
+
const state = readManagerUpdateState();
|
|
1084
|
+
if (availability.latestVersion &&
|
|
1085
|
+
state.pin?.kind === "automatic-rollback" &&
|
|
1086
|
+
state.pin.acknowledgedFailedVersion === state.pin.failedVersion &&
|
|
1087
|
+
availability.latestVersion !== state.pin.failedVersion) {
|
|
1088
|
+
writeManagerUpdateState({
|
|
1089
|
+
...state,
|
|
1090
|
+
lastAvailableVersion: availability.latestVersion,
|
|
1091
|
+
pin: { ...state.pin, newerAvailableVersion: availability.latestVersion },
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
else if (action === "upgrade") {
|
|
1096
|
+
const apply = actionArguments.includes("--apply");
|
|
1097
|
+
const explicitVersion = actionArguments.find((argument) => argument !== "--apply");
|
|
1098
|
+
let targetVersion = explicitVersion;
|
|
1099
|
+
if (!targetVersion) {
|
|
1100
|
+
const availability = await queryOwnerAvailability({
|
|
1101
|
+
installedVersion: KNODIN_VERSION,
|
|
1102
|
+
owner,
|
|
1103
|
+
});
|
|
1104
|
+
if (!availability.latestVersion)
|
|
1105
|
+
output = availability;
|
|
1106
|
+
else
|
|
1107
|
+
targetVersion = availability.latestVersion;
|
|
1108
|
+
}
|
|
1109
|
+
if (targetVersion)
|
|
1110
|
+
output = await executeManagerUpdate({
|
|
1111
|
+
currentVersion: KNODIN_VERSION,
|
|
1112
|
+
targetVersion,
|
|
1113
|
+
runtimeCommand,
|
|
1114
|
+
env: process.env,
|
|
1115
|
+
apply,
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
else if (action === "pin") {
|
|
1119
|
+
const apply = actionArguments.includes("--apply");
|
|
1120
|
+
const version = actionArguments.find((argument) => argument !== "--apply");
|
|
1121
|
+
if (!version)
|
|
1122
|
+
throw new Error("knodin update pin requires a version");
|
|
1123
|
+
output = apply
|
|
1124
|
+
? await executeManagerUpdate({
|
|
1125
|
+
currentVersion: KNODIN_VERSION,
|
|
1126
|
+
targetVersion: version,
|
|
1127
|
+
runtimeCommand,
|
|
1128
|
+
env: process.env,
|
|
1129
|
+
apply: true,
|
|
1130
|
+
pinKind: "manual",
|
|
1131
|
+
})
|
|
1132
|
+
: setManualPin(version);
|
|
1133
|
+
}
|
|
1134
|
+
else if (action === "unpin")
|
|
1135
|
+
output = unpinUpdate();
|
|
1136
|
+
else if (action === "acknowledge")
|
|
1137
|
+
output = acknowledgeUpdateFailure();
|
|
1138
|
+
else if (action === "auto") {
|
|
1139
|
+
const subaction = actionArguments[0];
|
|
1140
|
+
if (!subaction || !["status", "enable", "disable", "run"].includes(subaction))
|
|
1141
|
+
throw new Error("knodin update auto requires status, enable, disable, or run");
|
|
1142
|
+
const state = readManagerUpdateState();
|
|
1143
|
+
if (subaction === "status")
|
|
1144
|
+
output = state;
|
|
1145
|
+
else if (subaction === "disable") {
|
|
1146
|
+
output = { ...state, autoEnabled: false };
|
|
1147
|
+
writeManagerUpdateState(output);
|
|
1148
|
+
}
|
|
1149
|
+
else if (subaction === "enable") {
|
|
1150
|
+
if (state.platformAutoEligible) {
|
|
1151
|
+
output = { ...state, autoEnabled: true };
|
|
1152
|
+
writeManagerUpdateState(output);
|
|
1153
|
+
}
|
|
1154
|
+
else
|
|
1155
|
+
output = await certifyAutomaticUpdates({
|
|
1156
|
+
currentVersion: KNODIN_VERSION,
|
|
1157
|
+
runtimeCommand,
|
|
1158
|
+
env: process.env,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
else if (!state.autoEnabled || !state.platformAutoEligible) {
|
|
1162
|
+
output = { ...state, status: "disabled" };
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
const availability = await queryOwnerAvailability({
|
|
1166
|
+
installedVersion: KNODIN_VERSION,
|
|
1167
|
+
owner,
|
|
1168
|
+
});
|
|
1169
|
+
output =
|
|
1170
|
+
availability.status === "available" &&
|
|
1171
|
+
availability.autoEligible &&
|
|
1172
|
+
availability.latestVersion
|
|
1173
|
+
? await executeManagerUpdate({
|
|
1174
|
+
currentVersion: KNODIN_VERSION,
|
|
1175
|
+
targetVersion: availability.latestVersion,
|
|
1176
|
+
runtimeCommand,
|
|
1177
|
+
env: process.env,
|
|
1178
|
+
apply: true,
|
|
1179
|
+
})
|
|
1180
|
+
: availability;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
else
|
|
1184
|
+
throw new Error(`knodin update: unknown action ${action}`);
|
|
1072
1185
|
process.stdout.write(jsonOutput ? `${JSON.stringify(output)}\n` : formatGenericHuman("update", output));
|
|
1073
1186
|
return;
|
|
1074
1187
|
}
|
|
1188
|
+
if (cmd === "backups") {
|
|
1189
|
+
const action = invocation.commandPath[1];
|
|
1190
|
+
const retentionAction = invocation.commandPath[2];
|
|
1191
|
+
const roots = invocation.positionals;
|
|
1192
|
+
const defaultRoots = () => {
|
|
1193
|
+
if (roots.length > 0)
|
|
1194
|
+
return roots;
|
|
1195
|
+
const target = resolveRepo(repoFlag, process.cwd());
|
|
1196
|
+
if (!target.ok)
|
|
1197
|
+
throw new Error(target.error);
|
|
1198
|
+
return [target.repo];
|
|
1199
|
+
};
|
|
1200
|
+
const depth = invocation.options.depth;
|
|
1201
|
+
const retentionDays = invocation.options.retentionDays;
|
|
1202
|
+
const keepNewest = invocation.options.keepNewest;
|
|
1203
|
+
let output;
|
|
1204
|
+
if (action === "list")
|
|
1205
|
+
output = listBackups(defaultRoots(), { depth });
|
|
1206
|
+
else if (action === "prune") {
|
|
1207
|
+
output = pruneBackups(defaultRoots(), {
|
|
1208
|
+
depth,
|
|
1209
|
+
retentionDays,
|
|
1210
|
+
keepNewest,
|
|
1211
|
+
apply: invocation.options.apply === true,
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
else if (action === "retention" && retentionAction === "install") {
|
|
1215
|
+
output = installBackupRetention(roots, {
|
|
1216
|
+
depth,
|
|
1217
|
+
retentionDays,
|
|
1218
|
+
keepNewest,
|
|
1219
|
+
schedule: invocation.options.schedule,
|
|
1220
|
+
dryRun: invocation.options.dryRun === true,
|
|
1221
|
+
launcher: runtimeCommand,
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
else if (action === "retention" && retentionAction === "status") {
|
|
1225
|
+
output = retentionStatus();
|
|
1226
|
+
}
|
|
1227
|
+
else if (action === "retention" && retentionAction === "doctor") {
|
|
1228
|
+
output = retentionDoctor();
|
|
1229
|
+
}
|
|
1230
|
+
else if (action === "retention" && retentionAction === "remove") {
|
|
1231
|
+
output = removeBackupRetention();
|
|
1232
|
+
}
|
|
1233
|
+
else if (action === "retention" && retentionAction === "run") {
|
|
1234
|
+
output = runInstalledRetention();
|
|
1235
|
+
}
|
|
1236
|
+
else {
|
|
1237
|
+
throw new Error("knodin backups requires list, prune, or retention install|status|doctor|remove");
|
|
1238
|
+
}
|
|
1239
|
+
if (invocation.options.jsonl === true) {
|
|
1240
|
+
const records = output.backups ??
|
|
1241
|
+
output.candidates ?? [output];
|
|
1242
|
+
for (const record of records)
|
|
1243
|
+
process.stdout.write(`${JSON.stringify(record)}\n`);
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
process.stdout.write(jsonOutput ? `${JSON.stringify(output)}\n` : formatBackupHuman("backups", output));
|
|
1247
|
+
}
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1075
1250
|
if (process.stdout.isTTY &&
|
|
1076
1251
|
claimScheduledUpdateCheck({
|
|
1077
1252
|
currentVersion: KNODIN_VERSION,
|
|
@@ -1123,6 +1298,14 @@ async function main() {
|
|
|
1123
1298
|
process.exit(1);
|
|
1124
1299
|
}
|
|
1125
1300
|
const repo = resolved.repo;
|
|
1301
|
+
if (cmd !== "doctor") {
|
|
1302
|
+
try {
|
|
1303
|
+
maybeRunOpportunisticRetention(repo);
|
|
1304
|
+
}
|
|
1305
|
+
catch {
|
|
1306
|
+
// Best-effort cleanup must never make an ordinary command fail.
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1126
1309
|
if (cmd === "agent-event" && !fs.existsSync(resolveDbPath(repo)))
|
|
1127
1310
|
return;
|
|
1128
1311
|
if (cmd === "doctor") {
|
|
@@ -1246,7 +1429,10 @@ async function main() {
|
|
|
1246
1429
|
const input = positionals[0] === "create" ? (positionals[1] ?? "-") : (positionals[0] ?? "-");
|
|
1247
1430
|
compressionResult =
|
|
1248
1431
|
input === "-"
|
|
1249
|
-
? compressOutput(repo, {
|
|
1432
|
+
? compressOutput(repo, {
|
|
1433
|
+
...request,
|
|
1434
|
+
text: await readBoundedStdin(maxInputBytes),
|
|
1435
|
+
})
|
|
1250
1436
|
: compressOutputFile(repo, input, request);
|
|
1251
1437
|
}
|
|
1252
1438
|
if (action === "diagnose" &&
|
|
@@ -1325,7 +1511,10 @@ async function main() {
|
|
|
1325
1511
|
if (existing.state !== "configured")
|
|
1326
1512
|
throw new Error("knodin shared configure --disable requires a valid existing configuration");
|
|
1327
1513
|
writeSharedIndexConfig(repo, { ...existing.config, enabled: false });
|
|
1328
|
-
result = {
|
|
1514
|
+
result = {
|
|
1515
|
+
state: "configured",
|
|
1516
|
+
config: { ...existing.config, enabled: false },
|
|
1517
|
+
};
|
|
1329
1518
|
break;
|
|
1330
1519
|
}
|
|
1331
1520
|
const required = (name) => {
|
|
@@ -1360,7 +1549,11 @@ async function main() {
|
|
|
1360
1549
|
},
|
|
1361
1550
|
};
|
|
1362
1551
|
const target = writeSharedIndexConfig(repo, config);
|
|
1363
|
-
result = {
|
|
1552
|
+
result = {
|
|
1553
|
+
state: "configured",
|
|
1554
|
+
path: target,
|
|
1555
|
+
config: loadSharedIndexConfig(repo),
|
|
1556
|
+
};
|
|
1364
1557
|
break;
|
|
1365
1558
|
}
|
|
1366
1559
|
if (action === "publisher-metadata") {
|
|
@@ -1394,7 +1587,10 @@ async function main() {
|
|
|
1394
1587
|
if (!bundlePath)
|
|
1395
1588
|
throw new Error("knodin shared publisher-finalize requires <bundle>");
|
|
1396
1589
|
const bundle = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), bundlePath), "utf8"));
|
|
1397
|
-
const pointer = finalizeSharedPublisherBundle({
|
|
1590
|
+
const pointer = finalizeSharedPublisherBundle({
|
|
1591
|
+
config: configuration.config,
|
|
1592
|
+
bundle,
|
|
1593
|
+
});
|
|
1398
1594
|
result = { bundle, pointer: JSON.parse(pointer.toString("utf8")) };
|
|
1399
1595
|
break;
|
|
1400
1596
|
}
|
|
@@ -1421,12 +1617,19 @@ async function main() {
|
|
|
1421
1617
|
let credentialProbe = "not-requested";
|
|
1422
1618
|
if (invocation.options.probe === true) {
|
|
1423
1619
|
if (configuration.state !== "configured" || !configuration.config.enabled) {
|
|
1424
|
-
credentialProbe = {
|
|
1620
|
+
credentialProbe = {
|
|
1621
|
+
state: "unavailable",
|
|
1622
|
+
category: "configuration",
|
|
1623
|
+
};
|
|
1425
1624
|
}
|
|
1426
1625
|
else {
|
|
1427
1626
|
const store = createSharedObjectStore(configuration.config);
|
|
1428
1627
|
try {
|
|
1429
|
-
const current = spawnSync(gitExecutable(), ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
1628
|
+
const current = spawnSync(gitExecutable(), ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
1629
|
+
cwd: repo,
|
|
1630
|
+
encoding: "utf8",
|
|
1631
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1632
|
+
}).stdout.trim();
|
|
1430
1633
|
const branch = configuredBranchCandidates(configuration.config, current || undefined)[0];
|
|
1431
1634
|
if (!store || !branch)
|
|
1432
1635
|
throw new SharedIndexError("configuration", "shared-index probe has no configured local branch candidate");
|
|
@@ -1667,7 +1870,7 @@ async function main() {
|
|
|
1667
1870
|
continue;
|
|
1668
1871
|
await initializeRepository(checkout, {
|
|
1669
1872
|
command: runtimeCommand,
|
|
1670
|
-
index: (
|
|
1873
|
+
index: indexOrSeed(engine, KNODIN_SCHEMA_VERSION),
|
|
1671
1874
|
scope: "personal",
|
|
1672
1875
|
agents: [],
|
|
1673
1876
|
});
|
|
@@ -1703,7 +1906,11 @@ async function main() {
|
|
|
1703
1906
|
const [systemId, ...repositories] = invocation.positionals;
|
|
1704
1907
|
if (!systemId)
|
|
1705
1908
|
throw new Error("knodin system unlink requires <system-id>");
|
|
1706
|
-
const plan = planSystemUnlink({
|
|
1909
|
+
const plan = planSystemUnlink({
|
|
1910
|
+
systemId,
|
|
1911
|
+
repositories,
|
|
1912
|
+
repoPath: repo,
|
|
1913
|
+
});
|
|
1707
1914
|
result = invocation.options.dryRun === true ? plan : applySystemPlan(plan);
|
|
1708
1915
|
break;
|
|
1709
1916
|
}
|
|
@@ -1822,32 +2029,39 @@ async function main() {
|
|
|
1822
2029
|
break;
|
|
1823
2030
|
}
|
|
1824
2031
|
case "hook-refresh": {
|
|
1825
|
-
const
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
event
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2032
|
+
const lifecycleLease = acquireRepairLease(repo, "lifecycle-hook");
|
|
2033
|
+
try {
|
|
2034
|
+
const [kind, first, second] = rest;
|
|
2035
|
+
let event;
|
|
2036
|
+
if (kind === "commit")
|
|
2037
|
+
event = { kind };
|
|
2038
|
+
else if (kind === "checkout" && first && second) {
|
|
2039
|
+
event = { kind, before: first, after: second };
|
|
2040
|
+
}
|
|
2041
|
+
else if (kind === "merge" && first && second) {
|
|
2042
|
+
event = { kind, before: first, after: second };
|
|
2043
|
+
}
|
|
2044
|
+
else if (kind === "rewrite" && first) {
|
|
2045
|
+
event = { kind, inputPath: first };
|
|
2046
|
+
}
|
|
2047
|
+
else {
|
|
2048
|
+
throw new Error("knodin hook-refresh: invalid lifecycle event");
|
|
2049
|
+
}
|
|
2050
|
+
const shared = await opportunisticSharedRestore();
|
|
2051
|
+
const indexed = shared?.restored
|
|
2052
|
+
? []
|
|
2053
|
+
: await refreshFromGitEvent(repo, event, (target, files) => engine.index(target, files));
|
|
2054
|
+
result = { indexed, ...(shared ? { sharedRestore: shared } : {}) };
|
|
1837
2055
|
}
|
|
1838
|
-
|
|
1839
|
-
|
|
2056
|
+
finally {
|
|
2057
|
+
lifecycleLease.release();
|
|
1840
2058
|
}
|
|
1841
|
-
const shared = await opportunisticSharedRestore();
|
|
1842
|
-
const indexed = shared?.restored
|
|
1843
|
-
? []
|
|
1844
|
-
: await refreshFromGitEvent(repo, event, (target, files) => engine.index(target, files));
|
|
1845
|
-
result = { indexed, ...(shared ? { sharedRestore: shared } : {}) };
|
|
1846
2059
|
break;
|
|
1847
2060
|
}
|
|
1848
2061
|
case "init": {
|
|
1849
|
-
const
|
|
1850
|
-
const
|
|
2062
|
+
const requestedScope = explicitScope(rawRest);
|
|
2063
|
+
const scope = requestedScope ?? readRepositoryIntegrationConfig(repo)?.scope ?? "cli-only";
|
|
2064
|
+
const agents = requestedScope && scope !== "team" ? integrationAgents(repo) : [];
|
|
1851
2065
|
const renderer = createInitRenderer();
|
|
1852
2066
|
const activity = createIndexActivityReporter(repo);
|
|
1853
2067
|
activity.start();
|
|
@@ -1862,9 +2076,10 @@ async function main() {
|
|
|
1862
2076
|
}
|
|
1863
2077
|
paths = await initializeRepository(repo, {
|
|
1864
2078
|
command: runtimeCommand,
|
|
1865
|
-
index: (
|
|
2079
|
+
index: indexOrSeed(engine, KNODIN_SCHEMA_VERSION),
|
|
1866
2080
|
scope,
|
|
1867
2081
|
agents,
|
|
2082
|
+
configureIntegration: requestedScope !== null,
|
|
1868
2083
|
onProgress: (event) => {
|
|
1869
2084
|
activity.update(event);
|
|
1870
2085
|
renderer.onProgress(event);
|
|
@@ -1909,16 +2124,17 @@ async function main() {
|
|
|
1909
2124
|
const agents = scope === "team" ? [] : integrationAgents(repo);
|
|
1910
2125
|
const paths = await initializeRepository(repo, {
|
|
1911
2126
|
command: runtimeCommand,
|
|
1912
|
-
index:
|
|
2127
|
+
index: indexOrSeed(engine, KNODIN_SCHEMA_VERSION),
|
|
1913
2128
|
scope,
|
|
1914
2129
|
agents,
|
|
1915
2130
|
allowTrackedTransition: true,
|
|
1916
2131
|
auditConfigurationChanges: true,
|
|
2132
|
+
configureIntegration: true,
|
|
1917
2133
|
});
|
|
1918
2134
|
result = {
|
|
1919
2135
|
status: "success",
|
|
1920
2136
|
message: `knodin agent integration changed to ${scope}.`,
|
|
1921
|
-
graphInitialization: "
|
|
2137
|
+
graphInitialization: "refreshed",
|
|
1922
2138
|
nextAction: "run `knodin status` and reload the configured client",
|
|
1923
2139
|
paths,
|
|
1924
2140
|
};
|
|
@@ -2068,7 +2284,9 @@ async function main() {
|
|
|
2068
2284
|
}
|
|
2069
2285
|
const progressMode = resolveRepairProgressMode(options, process.env, process.stderr.isTTY);
|
|
2070
2286
|
const renderer = progressMode === "tty"
|
|
2071
|
-
? createProgressWorkerRenderer("repair-progress-worker", {
|
|
2287
|
+
? createProgressWorkerRenderer("repair-progress-worker", {
|
|
2288
|
+
type: "start",
|
|
2289
|
+
})
|
|
2072
2290
|
: (() => {
|
|
2073
2291
|
const direct = createRepairProgressRenderer({
|
|
2074
2292
|
mode: progressMode,
|
|
@@ -2211,6 +2429,29 @@ async function main() {
|
|
|
2211
2429
|
}));
|
|
2212
2430
|
break;
|
|
2213
2431
|
}
|
|
2432
|
+
case "seal": {
|
|
2433
|
+
const output = selectorValue("--output");
|
|
2434
|
+
if (!output)
|
|
2435
|
+
throw new Error("knodin seal requires --output <path.sqlite>");
|
|
2436
|
+
result = await runSeal({
|
|
2437
|
+
repoPath: repo,
|
|
2438
|
+
outputPath: output,
|
|
2439
|
+
// Embeddings dominate artifact size and code lookup is served
|
|
2440
|
+
// lexically plus by graph traversal, so they are stripped unless
|
|
2441
|
+
// asked for.
|
|
2442
|
+
stripEmbeddings: !rest.includes("--keep-embeddings"),
|
|
2443
|
+
includeExcluded: rest.includes("--include-excluded"),
|
|
2444
|
+
});
|
|
2445
|
+
break;
|
|
2446
|
+
}
|
|
2447
|
+
case "sealed": {
|
|
2448
|
+
if (!rest[0])
|
|
2449
|
+
throw new Error("knodin sealed requires an artifact path");
|
|
2450
|
+
result = await runSealedQuery(rest[0], rest[1], {
|
|
2451
|
+
strictCompat: rest.includes("--strict-compat"),
|
|
2452
|
+
});
|
|
2453
|
+
break;
|
|
2454
|
+
}
|
|
2214
2455
|
case "pack": {
|
|
2215
2456
|
const action = rest[0];
|
|
2216
2457
|
const diffScope = selectorValue("--diff-scope");
|
|
@@ -2509,7 +2750,10 @@ async function main() {
|
|
|
2509
2750
|
else if (action === "export")
|
|
2510
2751
|
result = exportTelemetry(repo, readTelemetryRecords(repo, input, retentionDays), selectorValue("--output"), readSessionEvents(repo, retentionDays));
|
|
2511
2752
|
else if (action === "clear")
|
|
2512
|
-
result = {
|
|
2753
|
+
result = {
|
|
2754
|
+
...clearTelemetry(repo, input),
|
|
2755
|
+
session: clearSessionTelemetry(repo),
|
|
2756
|
+
};
|
|
2513
2757
|
else
|
|
2514
2758
|
throw new Error("knodin telemetry requires enable, disable, status, report, export, or clear");
|
|
2515
2759
|
break;
|
|
@@ -2581,7 +2825,11 @@ async function main() {
|
|
|
2581
2825
|
result =
|
|
2582
2826
|
action === "preview"
|
|
2583
2827
|
? persistDiagnosticsPreview(repo, options)
|
|
2584
|
-
: collectDiagnostics(repo, {
|
|
2828
|
+
: collectDiagnostics(repo, {
|
|
2829
|
+
...options,
|
|
2830
|
+
outputPath: outputOption,
|
|
2831
|
+
previewId,
|
|
2832
|
+
});
|
|
2585
2833
|
}
|
|
2586
2834
|
else {
|
|
2587
2835
|
throw new Error("knodin diagnostics requires enable, status, preview, archive, inspect, clear, or disable");
|
|
@@ -2717,6 +2965,8 @@ catch (err) {
|
|
|
2717
2965
|
"wiki",
|
|
2718
2966
|
"visualize",
|
|
2719
2967
|
"pack",
|
|
2968
|
+
"seal",
|
|
2969
|
+
"sealed",
|
|
2720
2970
|
"compress",
|
|
2721
2971
|
"prs",
|
|
2722
2972
|
"worktrees",
|