knodin 0.8.7 → 0.9.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 +307 -85
- 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 +35 -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 +355 -292
- package/dist/src/init.js +222 -179
- 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/tools/knodin-tools.js +69 -10
- package/dist/src/update-ceremony.js +20 -24
- package/dist/src/update-coordination.js +158 -0
- package/dist/src/update-executor.js +336 -0
- package/dist/src/update-verifier.js +358 -0
- package/docs/BACKUP-RETENTION.md +54 -0
- package/docs/CLI.md +6 -0
- package/docs/DOCTOR-AND-UPDATES.md +44 -12
- package/docs/SIGNED-UPDATES.md +29 -22
- package/docs/releases/0.9.0.md +43 -0
- package/package.json +7 -1
- package/roadmap/competitive-roadmap.md +8 -0
package/dist/src/init.js
CHANGED
|
@@ -7,6 +7,7 @@ import { compareBytes } from "./compare.js";
|
|
|
7
7
|
import { isIndexableSourcePath } from "./engine/source-policy.js";
|
|
8
8
|
import { lookupMirror } from "./engine/state-paths.js";
|
|
9
9
|
import { inspectLefthookIntegration, installHookManagerIntegration, isActiveLefthookHook, } from "./hook-manager-integration.js";
|
|
10
|
+
import { acquireRepairLease } from "./repair-lease.js";
|
|
10
11
|
import { installKnodinSkills, removeKnodinSkills } from "./skill-management.js";
|
|
11
12
|
import { registerInitializedWorktree } from "./worktree-lifecycle.js";
|
|
12
13
|
const MANAGED_MARKER = "KNODIN MANAGED HOOK";
|
|
@@ -153,7 +154,10 @@ function configureMutationAuditTargets(repo) {
|
|
|
153
154
|
});
|
|
154
155
|
}
|
|
155
156
|
for (const hookName of HOOK_NAMES) {
|
|
156
|
-
add({
|
|
157
|
+
add({
|
|
158
|
+
absolute: path.join(effectiveHooks, hookName),
|
|
159
|
+
label: `${effectiveLabel}/${hookName}`,
|
|
160
|
+
});
|
|
157
161
|
add({
|
|
158
162
|
absolute: path.join(effectiveHooks, `${hookName}.knodin-original`),
|
|
159
163
|
label: `${effectiveLabel}/${hookName}.knodin-original`,
|
|
@@ -385,11 +389,11 @@ while :; do
|
|
|
385
389
|
ARG1="$(sed -n '2p' "$EVENT")"
|
|
386
390
|
ARG2="$(sed -n '3p' "$EVENT")"
|
|
387
391
|
if [ "$KIND" = "commit" ]; then
|
|
388
|
-
${invocation} --repo "$REPO_ROOT" hook-refresh commit --json >> "$LOG_PATH" 2
|
|
392
|
+
${invocation} --repo "$REPO_ROOT" hook-refresh commit --json >> "$LOG_PATH" 2>> "$LOG_PATH.stderr"
|
|
389
393
|
elif [ "$KIND" = "checkout" ] || [ "$KIND" = "merge" ]; then
|
|
390
|
-
${invocation} --repo "$REPO_ROOT" hook-refresh "$KIND" "$ARG1" "$ARG2" --json >> "$LOG_PATH" 2
|
|
394
|
+
${invocation} --repo "$REPO_ROOT" hook-refresh "$KIND" "$ARG1" "$ARG2" --json >> "$LOG_PATH" 2>> "$LOG_PATH.stderr"
|
|
391
395
|
elif [ "$KIND" = "rewrite" ]; then
|
|
392
|
-
${invocation} --repo "$REPO_ROOT" hook-refresh rewrite "$ARG1" --json >> "$LOG_PATH" 2
|
|
396
|
+
${invocation} --repo "$REPO_ROOT" hook-refresh rewrite "$ARG1" --json >> "$LOG_PATH" 2>> "$LOG_PATH.stderr"
|
|
393
397
|
else
|
|
394
398
|
printf 'knodin background refresh: invalid queued event %s\n' "$KIND" >> "$LOG_PATH"
|
|
395
399
|
false
|
|
@@ -701,6 +705,7 @@ This repository is indexed locally by knodin. Start with \`knodin status\`; if i
|
|
|
701
705
|
- Use gateway operations \`explain\`, \`review\`, and \`query\` for source-evidenced context. CLI fallbacks are \`knodin explain\`, \`knodin review --scope compare\`, and \`knodin rename\`.
|
|
702
706
|
- Direct reads are appropriate for files just authored in the current session; do not force a graph round trip when the agent already has fresh source context.
|
|
703
707
|
- Run \`knodin index <changed-files>\` while working when you need immediately fresh graph evidence. Managed Git hooks installed by \`knodin init\` refresh the graph after commits, checkouts, merges, and rewrites.
|
|
708
|
+
- When indexing is active, run \`knodin wait --fresh\` and recheck status before falling back to direct traversal.
|
|
704
709
|
- Keep output truthful: local graph evidence can be stale or ambiguous; say so and repair/reindex instead of claiming certainty.
|
|
705
710
|
|
|
706
711
|
<!-- knodin:end -->
|
|
@@ -960,9 +965,17 @@ export function inspectRepositoryIntegrationStatus(repo) {
|
|
|
960
965
|
const receipt = readRepositoryIntegrationConfig(repo);
|
|
961
966
|
const candidates = [
|
|
962
967
|
{ agent: "claude", path: ".mcp.json", marker: '"knodin"' },
|
|
963
|
-
{
|
|
968
|
+
{
|
|
969
|
+
agent: "codex",
|
|
970
|
+
path: ".codex/config.toml",
|
|
971
|
+
marker: 'mcp_servers."knodin"',
|
|
972
|
+
},
|
|
964
973
|
{ agent: "gemini", path: ".gemini/settings.json", marker: '"knodin"' },
|
|
965
|
-
{
|
|
974
|
+
{
|
|
975
|
+
agent: "antigravity",
|
|
976
|
+
path: ".agents/mcp_config.json",
|
|
977
|
+
marker: '"knodin"',
|
|
978
|
+
},
|
|
966
979
|
{
|
|
967
980
|
agent: "codex",
|
|
968
981
|
path: "AGENTS.md",
|
|
@@ -1047,6 +1060,7 @@ export function detectTrackedTeamIntegration(repo) {
|
|
|
1047
1060
|
export async function initializeRepository(repo, options) {
|
|
1048
1061
|
const resolvedRepo = path.resolve(repo);
|
|
1049
1062
|
const scope = options.scope ?? "personal";
|
|
1063
|
+
const configureIntegration = options.configureIntegration ?? true;
|
|
1050
1064
|
const priorIntegration = readRepositoryIntegrationConfig(resolvedRepo);
|
|
1051
1065
|
if (runGit(resolvedRepo, ["rev-parse", "--is-inside-work-tree"]).trim() !== "true") {
|
|
1052
1066
|
throw new Error(`knodin init: not a Git worktree: ${resolvedRepo}`);
|
|
@@ -1065,188 +1079,217 @@ export async function initializeRepository(repo, options) {
|
|
|
1065
1079
|
if (!path.isAbsolute(options.command[0])) {
|
|
1066
1080
|
throw new Error("knodin init: packaged runtime command must be an absolute path");
|
|
1067
1081
|
}
|
|
1068
|
-
const
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
const hooksDir = hookInstallation.hooksDir;
|
|
1080
|
-
await Promise.all([
|
|
1081
|
-
fs.promises.mkdir(knodinHooksDir, { recursive: true }),
|
|
1082
|
-
fs.promises.mkdir(hooksDir, { recursive: true }),
|
|
1083
|
-
]);
|
|
1084
|
-
const backgroundPath = path.join(knodinHooksDir, "background-index.sh");
|
|
1085
|
-
await fs.promises.writeFile(backgroundPath, backgroundScript(options.command), {
|
|
1086
|
-
encoding: "utf-8",
|
|
1087
|
-
mode: 0o755,
|
|
1088
|
-
});
|
|
1089
|
-
await fs.promises.chmod(backgroundPath, 0o755);
|
|
1090
|
-
const hookManagerIntegration = installHookManagerIntegration(resolvedRepo);
|
|
1091
|
-
for (const hookName of HOOK_NAMES) {
|
|
1092
|
-
let preservedOriginal;
|
|
1093
|
-
if (hookInstallation.trackedHooksDir) {
|
|
1094
|
-
const relativeHook = `${hookInstallation.trackedHooksDir}/${hookName}`;
|
|
1095
|
-
const sourceHook = path.join(resolvedRepo, relativeHook);
|
|
1096
|
-
try {
|
|
1097
|
-
const stat = await fs.promises.stat(sourceHook);
|
|
1098
|
-
preservedOriginal =
|
|
1099
|
-
stat.isFile() && (stat.mode & 0o111) !== 0 ? `repo:${relativeHook}` : null;
|
|
1100
|
-
}
|
|
1101
|
-
catch {
|
|
1102
|
-
preservedOriginal = null;
|
|
1103
|
-
}
|
|
1082
|
+
const lifecycleLease = acquireRepairLease(resolvedRepo, options.configureIntegration ? "configure" : "init");
|
|
1083
|
+
try {
|
|
1084
|
+
const mutationTargets = options.auditConfigurationChanges
|
|
1085
|
+
? configureMutationAuditTargets(resolvedRepo)
|
|
1086
|
+
: [];
|
|
1087
|
+
const beforeMutation = mutationSnapshot(mutationTargets);
|
|
1088
|
+
if (configureIntegration &&
|
|
1089
|
+
scope !== "team" &&
|
|
1090
|
+
!options.allowTrackedTransition &&
|
|
1091
|
+
detectTrackedTeamIntegration(resolvedRepo)) {
|
|
1092
|
+
throw new Error("knodin init: tracked team integration is active; use `knodin configure --scope personal` or `--scope cli-only` for an explicit commit-ready transition");
|
|
1104
1093
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
await preventLefthookAutoInstall(path.join(hooksDir, entry.name));
|
|
1112
|
-
}
|
|
1113
|
-
const indexResult = await options.index(resolvedRepo, {
|
|
1114
|
-
onProgress: options.onProgress,
|
|
1115
|
-
});
|
|
1116
|
-
if (isIndexResult(indexResult) && indexResult.verification.status !== "healthy") {
|
|
1117
|
-
throw new InitializationHealthError(indexResult);
|
|
1118
|
-
}
|
|
1119
|
-
const lifecycleRefresh = drainQueuedLifecycleEvents(resolvedRepo, backgroundPath);
|
|
1120
|
-
await fs.promises.rm(path.join(knodinHooksDir, HOOK_FAILURE_FILE), { force: true });
|
|
1121
|
-
let agentInstructionChanges = [];
|
|
1122
|
-
if (scope === "team") {
|
|
1123
|
-
const installed = await Promise.all([
|
|
1124
|
-
installManagedAgentInstructions(resolvedRepo, "AGENTS.md"),
|
|
1125
|
-
installManagedAgentInstructions(resolvedRepo, "GEMINI.md"),
|
|
1094
|
+
const knodinHooksDir = path.join(resolvedRepo, ".knodin", "hooks");
|
|
1095
|
+
const hookInstallation = await prepareHookInstallation(resolvedRepo);
|
|
1096
|
+
const hooksDir = hookInstallation.hooksDir;
|
|
1097
|
+
await Promise.all([
|
|
1098
|
+
fs.promises.mkdir(knodinHooksDir, { recursive: true }),
|
|
1099
|
+
fs.promises.mkdir(hooksDir, { recursive: true }),
|
|
1126
1100
|
]);
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
}
|
|
1132
|
-
const requestedAgents = options.agents ?? [];
|
|
1133
|
-
const projectPathByAgent = {
|
|
1134
|
-
codex: ".codex/config.toml",
|
|
1135
|
-
gemini: ".gemini/settings.json",
|
|
1136
|
-
copilot: ".vscode/mcp.json",
|
|
1137
|
-
antigravity: ".agents/mcp_config.json",
|
|
1138
|
-
};
|
|
1139
|
-
const blockedAgents = [];
|
|
1140
|
-
const externalConfigurationOutcomes = [];
|
|
1141
|
-
if (scope === "personal" &&
|
|
1142
|
-
options.allowTrackedTransition &&
|
|
1143
|
-
priorIntegration?.scope === "team") {
|
|
1144
|
-
const cleanup = configureProjectAgents({
|
|
1145
|
-
repo: resolvedRepo,
|
|
1146
|
-
scope: "cli-only",
|
|
1147
|
-
agents: ["claude", "codex", "gemini", "copilot", "antigravity"],
|
|
1148
|
-
run: options.runAgentCommand,
|
|
1101
|
+
const backgroundPath = path.join(knodinHooksDir, "background-index.sh");
|
|
1102
|
+
await fs.promises.writeFile(backgroundPath, backgroundScript(options.command), {
|
|
1103
|
+
encoding: "utf-8",
|
|
1104
|
+
mode: 0o755,
|
|
1149
1105
|
});
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1106
|
+
await fs.promises.chmod(backgroundPath, 0o755);
|
|
1107
|
+
const hookManagerIntegration = installHookManagerIntegration(resolvedRepo);
|
|
1108
|
+
for (const hookName of HOOK_NAMES) {
|
|
1109
|
+
let preservedOriginal;
|
|
1110
|
+
if (hookInstallation.trackedHooksDir) {
|
|
1111
|
+
const relativeHook = `${hookInstallation.trackedHooksDir}/${hookName}`;
|
|
1112
|
+
const sourceHook = path.join(resolvedRepo, relativeHook);
|
|
1113
|
+
try {
|
|
1114
|
+
const stat = await fs.promises.stat(sourceHook);
|
|
1115
|
+
preservedOriginal =
|
|
1116
|
+
stat.isFile() && (stat.mode & 0o111) !== 0 ? `repo:${relativeHook}` : null;
|
|
1117
|
+
}
|
|
1118
|
+
catch {
|
|
1119
|
+
preservedOriginal = null;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
await installManagedHook(hooksDir, hookName, preservedOriginal);
|
|
1123
|
+
}
|
|
1124
|
+
for (const entry of await fs.promises.readdir(hooksDir, {
|
|
1125
|
+
withFileTypes: true,
|
|
1126
|
+
})) {
|
|
1127
|
+
if (entry.isFile())
|
|
1128
|
+
await preventLefthookAutoInstall(path.join(hooksDir, entry.name));
|
|
1129
|
+
}
|
|
1130
|
+
let agentInstructionChanges = [];
|
|
1131
|
+
let agentIntegration = {
|
|
1132
|
+
configured: [],
|
|
1133
|
+
removed: [],
|
|
1134
|
+
failed: [],
|
|
1135
|
+
projectFiles: [],
|
|
1136
|
+
};
|
|
1137
|
+
const externalConfigurationOutcomes = [];
|
|
1138
|
+
let excluded = [];
|
|
1139
|
+
if (configureIntegration && scope === "team") {
|
|
1140
|
+
const installed = await Promise.all([
|
|
1141
|
+
installManagedAgentInstructions(resolvedRepo, "AGENTS.md"),
|
|
1142
|
+
installManagedAgentInstructions(resolvedRepo, "GEMINI.md"),
|
|
1143
|
+
]);
|
|
1144
|
+
agentInstructionChanges = installed.filter((change) => change !== null);
|
|
1145
|
+
}
|
|
1146
|
+
else if (configureIntegration) {
|
|
1147
|
+
agentInstructionChanges = await removeManagedPersonalArtifacts(resolvedRepo, options.allowTrackedTransition);
|
|
1148
|
+
}
|
|
1149
|
+
const requestedAgents = options.agents ?? [];
|
|
1150
|
+
const projectPathByAgent = {
|
|
1151
|
+
codex: ".codex/config.toml",
|
|
1152
|
+
gemini: ".gemini/settings.json",
|
|
1153
|
+
copilot: ".vscode/mcp.json",
|
|
1154
|
+
antigravity: ".agents/mcp_config.json",
|
|
1155
|
+
};
|
|
1156
|
+
const blockedAgents = [];
|
|
1157
|
+
if (configureIntegration) {
|
|
1158
|
+
if (scope === "personal" &&
|
|
1159
|
+
options.allowTrackedTransition &&
|
|
1160
|
+
priorIntegration?.scope === "team") {
|
|
1161
|
+
const cleanup = configureProjectAgents({
|
|
1162
|
+
repo: resolvedRepo,
|
|
1163
|
+
scope: "cli-only",
|
|
1164
|
+
agents: ["claude", "codex", "gemini", "copilot", "antigravity"],
|
|
1165
|
+
run: options.runAgentCommand,
|
|
1166
|
+
});
|
|
1167
|
+
if (cleanup.failed.length > 0)
|
|
1168
|
+
throw new Error(`knodin configure: could not remove tracked team integration: ${cleanup.failed[0]?.message}`);
|
|
1169
|
+
if (cleanup.removed.includes("claude"))
|
|
1170
|
+
externalConfigurationOutcomes.push({
|
|
1171
|
+
system: "claude-local-mcp",
|
|
1172
|
+
state: "removal-attempted",
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
const eligibleAgents = scope === "team"
|
|
1176
|
+
? requestedAgents
|
|
1177
|
+
: requestedAgents.filter((agent) => {
|
|
1178
|
+
const projectPath = agent === "claude" ? ".mcp.json" : projectPathByAgent[agent];
|
|
1179
|
+
if (!projectPath ||
|
|
1180
|
+
!isTracked(resolvedRepo, projectPath) ||
|
|
1181
|
+
(scope === "cli-only" && options.allowTrackedTransition))
|
|
1182
|
+
return true;
|
|
1183
|
+
if (options.allowTrackedTransition && priorIntegration?.scope === "team")
|
|
1184
|
+
return false;
|
|
1185
|
+
blockedAgents.push({
|
|
1186
|
+
agent,
|
|
1187
|
+
message: `${projectPath} is tracked; personal mode left it unchanged and did not exclude it`,
|
|
1188
|
+
});
|
|
1189
|
+
return false;
|
|
1190
|
+
});
|
|
1191
|
+
agentIntegration = configureProjectAgents({
|
|
1192
|
+
repo: resolvedRepo,
|
|
1193
|
+
scope,
|
|
1194
|
+
agents: eligibleAgents,
|
|
1195
|
+
run: options.runAgentCommand,
|
|
1156
1196
|
});
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1197
|
+
const skillClients = (scope === "team"
|
|
1198
|
+
? ["codex", "claude", "gemini"]
|
|
1199
|
+
: agentIntegration.configured.filter((agent) => ["codex", "claude", "gemini"].includes(agent)));
|
|
1200
|
+
const skillIntegration = scope === "cli-only"
|
|
1201
|
+
? removeKnodinSkills({
|
|
1202
|
+
repo: resolvedRepo,
|
|
1203
|
+
scope: "team",
|
|
1204
|
+
clients: ["codex", "claude", "gemini"],
|
|
1205
|
+
})
|
|
1206
|
+
: installKnodinSkills({
|
|
1207
|
+
repo: resolvedRepo,
|
|
1208
|
+
scope,
|
|
1209
|
+
clients: skillClients,
|
|
1210
|
+
});
|
|
1211
|
+
for (const issue of skillIntegration.issues)
|
|
1212
|
+
agentIntegration.failed.push({
|
|
1213
|
+
agent: skillClients.find((client) => issue.path.includes(`.${client}`)) ?? "codex",
|
|
1214
|
+
message: `${issue.path}: ${issue.message}`,
|
|
1215
|
+
});
|
|
1216
|
+
if (scope === "personal" && agentIntegration.configured.includes("claude"))
|
|
1217
|
+
externalConfigurationOutcomes.push({
|
|
1218
|
+
system: "claude-local-mcp",
|
|
1219
|
+
state: "configured-or-present",
|
|
1220
|
+
});
|
|
1221
|
+
if (scope === "cli-only" &&
|
|
1222
|
+
agentIntegration.removed.includes("claude") &&
|
|
1223
|
+
!externalConfigurationOutcomes.some(({ system, state }) => system === "claude-local-mcp" && state === "removal-attempted"))
|
|
1224
|
+
externalConfigurationOutcomes.push({
|
|
1225
|
+
system: "claude-local-mcp",
|
|
1226
|
+
state: "removal-attempted",
|
|
1227
|
+
});
|
|
1228
|
+
agentIntegration.failed.push(...blockedAgents);
|
|
1229
|
+
await writeRepositoryIntegrationConfig(resolvedRepo, {
|
|
1230
|
+
scope,
|
|
1231
|
+
agents: agentIntegration.configured,
|
|
1171
1232
|
});
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1233
|
+
if (scope === "team") {
|
|
1234
|
+
await ensureTeamGitIgnore(resolvedRepo);
|
|
1235
|
+
await removeManagedExcludes(resolvedRepo);
|
|
1236
|
+
}
|
|
1237
|
+
else if (scope === "cli-only") {
|
|
1238
|
+
await removeManagedExcludes(resolvedRepo);
|
|
1239
|
+
}
|
|
1240
|
+
excluded =
|
|
1241
|
+
scope === "team"
|
|
1242
|
+
? []
|
|
1243
|
+
: await excludeUntrackedPaths(resolvedRepo, [
|
|
1244
|
+
...(isTracked(resolvedRepo, ".knodin") ? [] : [".knodin/"]),
|
|
1245
|
+
...agentIntegration.projectFiles,
|
|
1246
|
+
]);
|
|
1247
|
+
}
|
|
1248
|
+
if (!configureIntegration && !isTracked(resolvedRepo, ".knodin")) {
|
|
1249
|
+
excluded = await excludeUntrackedPaths(resolvedRepo, [".knodin/"]);
|
|
1250
|
+
}
|
|
1251
|
+
if (hookManagerIntegration) {
|
|
1252
|
+
const managerExcludes = await excludeUntrackedPaths(resolvedRepo, [
|
|
1253
|
+
hookManagerIntegration.localConfig,
|
|
1254
|
+
]);
|
|
1255
|
+
excluded = [...new Set([...excluded, ...managerExcludes])].sort(compareBytes);
|
|
1256
|
+
}
|
|
1257
|
+
registerInitializedWorktree(resolvedRepo);
|
|
1258
|
+
// Configuration is graph-visible, so explicit configuration must complete
|
|
1259
|
+
// before the final index and health verification. Plain init reaches this
|
|
1260
|
+
// point without touching agent instructions, MCP files, skills, or receipts.
|
|
1261
|
+
const indexResult = await options.index(resolvedRepo, {
|
|
1262
|
+
onProgress: options.onProgress,
|
|
1199
1263
|
});
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1264
|
+
if (isIndexResult(indexResult) && indexResult.verification.status !== "healthy") {
|
|
1265
|
+
throw new InitializationHealthError(indexResult);
|
|
1266
|
+
}
|
|
1267
|
+
const lifecycleRefresh = drainQueuedLifecycleEvents(resolvedRepo, backgroundPath);
|
|
1268
|
+
await fs.promises.rm(path.join(knodinHooksDir, HOOK_FAILURE_FILE), {
|
|
1269
|
+
force: true,
|
|
1206
1270
|
});
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1271
|
+
const detectedFilesystemChanges = filesystemChanges(beforeMutation, mutationSnapshot(mutationTargets, true));
|
|
1272
|
+
return {
|
|
1273
|
+
scope,
|
|
1274
|
+
knodin: ".knodin",
|
|
1275
|
+
database: ".knodin/db.sqlite",
|
|
1276
|
+
backgroundIndexer: ".knodin/hooks/background-index.sh",
|
|
1277
|
+
hooksDirectory: path.relative(resolvedRepo, hooksDir) || ".",
|
|
1278
|
+
gitHooks: [...HOOK_NAMES],
|
|
1279
|
+
claudeSettings: null,
|
|
1280
|
+
agentInstructions: scope === "team" ? "AGENTS.md" : null,
|
|
1281
|
+
agentIntegration,
|
|
1282
|
+
agentInstructionChanges,
|
|
1283
|
+
filesystemChanges: detectedFilesystemChanges,
|
|
1284
|
+
externalConfigurationOutcomes,
|
|
1285
|
+
excluded,
|
|
1286
|
+
lifecycleRefresh,
|
|
1287
|
+
hookManagerIntegration,
|
|
1288
|
+
};
|
|
1218
1289
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
: await excludeUntrackedPaths(resolvedRepo, [
|
|
1222
|
-
...(isTracked(resolvedRepo, ".knodin") ? [] : [".knodin/"]),
|
|
1223
|
-
...agentIntegration.projectFiles,
|
|
1224
|
-
]);
|
|
1225
|
-
if (hookManagerIntegration) {
|
|
1226
|
-
const managerExcludes = await excludeUntrackedPaths(resolvedRepo, [
|
|
1227
|
-
hookManagerIntegration.localConfig,
|
|
1228
|
-
]);
|
|
1229
|
-
excluded = [...new Set([...excluded, ...managerExcludes])].sort(compareBytes);
|
|
1290
|
+
finally {
|
|
1291
|
+
lifecycleLease.release();
|
|
1230
1292
|
}
|
|
1231
|
-
registerInitializedWorktree(resolvedRepo);
|
|
1232
|
-
const detectedFilesystemChanges = filesystemChanges(beforeMutation, mutationSnapshot(mutationTargets, true));
|
|
1233
|
-
return {
|
|
1234
|
-
scope,
|
|
1235
|
-
knodin: ".knodin",
|
|
1236
|
-
database: ".knodin/db.sqlite",
|
|
1237
|
-
backgroundIndexer: ".knodin/hooks/background-index.sh",
|
|
1238
|
-
hooksDirectory: path.relative(resolvedRepo, hooksDir) || ".",
|
|
1239
|
-
gitHooks: [...HOOK_NAMES],
|
|
1240
|
-
claudeSettings: null,
|
|
1241
|
-
agentInstructions: scope === "team" ? "AGENTS.md" : null,
|
|
1242
|
-
agentIntegration,
|
|
1243
|
-
agentInstructionChanges,
|
|
1244
|
-
filesystemChanges: detectedFilesystemChanges,
|
|
1245
|
-
externalConfigurationOutcomes,
|
|
1246
|
-
excluded,
|
|
1247
|
-
lifecycleRefresh,
|
|
1248
|
-
hookManagerIntegration,
|
|
1249
|
-
};
|
|
1250
1293
|
}
|
|
1251
1294
|
async function matchesManagedFile(filePath, expected, executable) {
|
|
1252
1295
|
try {
|