salmon-loop 0.3.2 → 0.5.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/cli/authorization/non-interactive.js +9 -13
- package/dist/cli/authorization/provider.js +2 -10
- package/dist/cli/chat.js +12 -6
- package/dist/cli/commands/allowlist.js +1 -1
- package/dist/cli/commands/chat.js +13 -13
- package/dist/cli/commands/config.js +2 -2
- package/dist/cli/commands/mode.js +2 -2
- package/dist/cli/commands/parallel.js +1 -1
- package/dist/cli/commands/run/handler.js +9 -4
- package/dist/cli/commands/run/loop-params.js +2 -0
- package/dist/cli/commands/run/parse-options.js +14 -26
- package/dist/cli/commands/run/runtime-llm.js +15 -12
- package/dist/cli/commands/run/runtime-options.js +3 -1
- package/dist/cli/config.js +0 -8
- package/dist/cli/headless/openai-responses-canonical-applier.js +1 -7
- package/dist/cli/locales/en.js +2 -2
- package/dist/cli/reporters/standard.js +12 -3
- package/dist/cli/reporters/stream-json.js +2 -1
- package/dist/cli/slash/runtime.js +2 -2
- package/dist/cli/ui/hooks/useLoopEvents.js +1 -1
- package/dist/cli/ui/hooks/useLoopState.js +1 -1
- package/dist/core/adapters/fs/file-adapter.js +3 -1
- package/dist/core/adapters/git/git-adapter.js +6 -3
- package/dist/core/adapters/git/git-runner.js +5 -2
- package/dist/core/adapters/git/lock-manager.js +7 -4
- package/dist/core/ast/parser.js +18 -9
- package/dist/core/checkpoint-domain/manifest-store.js +21 -13
- package/dist/core/checkpoint-domain/service.js +3 -1
- package/dist/core/config/limits.js +1 -1
- package/dist/core/config/model-pricing.js +61 -0
- package/dist/core/config/schema.js +738 -0
- package/dist/core/config/validate.js +11 -922
- package/dist/core/context/ast/skeleton-extractor.js +225 -0
- package/dist/core/context/ast/source-outline.js +24 -1
- package/dist/core/context/budget/dynamic-adjuster.js +20 -5
- package/dist/core/context/builder.js +7 -3
- package/dist/core/context/cache/store-factory.js +3 -1
- package/dist/core/context/dependencies.js +2 -1
- package/dist/core/context/effectiveness/persistence.js +50 -0
- package/dist/core/context/effectiveness/tracker.js +24 -0
- package/dist/core/context/gatherers/architecture-gatherer.js +2 -1
- package/dist/core/context/gatherers/artifact-gatherer.js +7 -4
- package/dist/core/context/gatherers/ast-gatherer.js +34 -40
- package/dist/core/context/gatherers/ghost-dependency-gatherer.js +0 -1
- package/dist/core/context/gatherers/git-history-gatherer.js +3 -1
- package/dist/core/context/gatherers/knowledge-gatherer.js +21 -2
- package/dist/core/context/gatherers/metadata-gatherer.js +12 -7
- package/dist/core/context/gatherers/ripgrep-gatherer.js +6 -3
- package/dist/core/context/service.js +12 -2
- package/dist/core/context/steps/context-gather.js +14 -3
- package/dist/core/context/steps/context-targets.js +1 -0
- package/dist/core/context/targeting/target-resolver.js +29 -11
- package/dist/core/context/token/cache.js +5 -2
- package/dist/core/context/token/encoding-registry.js +7 -6
- package/dist/core/context/truncation/strategies/json.js +5 -2
- package/dist/core/context/truncation/type-detector.js +3 -1
- package/dist/core/extensions/index.js +48 -3
- package/dist/core/extensions/load.js +3 -2
- package/dist/core/extensions/merge.js +5 -1
- package/dist/core/extensions/paths.js +8 -2
- package/dist/core/extensions/schemas.js +21 -0
- package/dist/core/facades/cli-authorization-provider.js +1 -0
- package/dist/core/facades/cli-command-chat.js +2 -0
- package/dist/core/facades/cli-run-handler.js +1 -0
- package/dist/core/facades/cli-utils-serialize.js +2 -0
- package/dist/core/feedback/parsers.js +290 -1
- package/dist/core/grizzco/dsl/llm-strategy.js +4 -3
- package/dist/core/grizzco/engine/observability/loop-telemetry.js +5 -2
- package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +30 -13
- package/dist/core/grizzco/engine/pipeline/pipeline.js +149 -240
- package/dist/core/grizzco/engine/transaction/attempt-failure.js +49 -24
- package/dist/core/grizzco/engine/transaction/authorization-summary.js +2 -1
- package/dist/core/grizzco/engine/transaction/transaction-runner.js +40 -34
- package/dist/core/grizzco/execution/RejectionManager.js +7 -5
- package/dist/core/grizzco/runtime/apply-back-runtime.js +5 -2
- package/dist/core/grizzco/services/implementations/default/GitConfigService.js +2 -1
- package/dist/core/grizzco/services/registry.js +18 -0
- package/dist/core/grizzco/steps/audit.js +20 -10
- package/dist/core/grizzco/steps/autopilot.js +21 -32
- package/dist/core/grizzco/steps/display-report.js +4 -11
- package/dist/core/grizzco/steps/explore.js +14 -4
- package/dist/core/grizzco/steps/generateReview.js +3 -1
- package/dist/core/grizzco/steps/patch/prompt-input.js +4 -1
- package/dist/core/grizzco/steps/patch.js +1 -0
- package/dist/core/grizzco/steps/plan.js +58 -49
- package/dist/core/grizzco/steps/research.js +3 -1
- package/dist/core/grizzco/steps/tool-runtime.js +3 -0
- package/dist/core/grizzco/steps/verify.js +7 -1
- package/dist/core/grizzco/validation/AstValidationService.js +3 -1
- package/dist/core/grizzco/workers/strata-sync-worker.js +2 -1
- package/dist/core/history/input-history.js +3 -1
- package/dist/core/intent/chat-intent.js +3 -1
- package/dist/core/llm/ai-sdk/message-mapper.js +37 -26
- package/dist/core/llm/ai-sdk/request-params.js +2 -6
- package/dist/core/llm/ai-sdk/result-mapper.js +14 -8
- package/dist/core/llm/ai-sdk/retry-classifier.js +17 -7
- package/dist/core/llm/ai-sdk/retry-executor.js +1 -1
- package/dist/core/llm/contracts/repair.js +16 -8
- package/dist/core/llm/errors.js +18 -14
- package/dist/core/llm/output-policy.js +8 -0
- package/dist/core/llm/redact.js +1 -3
- package/dist/core/llm/retry-utils.js +8 -2
- package/dist/core/llm/stream-utils.js +5 -3
- package/dist/core/llm/sub-agent-factory.js +51 -0
- package/dist/core/llm/tool-calling-stub.js +48 -0
- package/dist/core/llm/utils.js +17 -6
- package/dist/core/mcp/bridge/prompt-command-provider.js +4 -3
- package/dist/core/mcp/bridge/resource-context-provider.js +3 -1
- package/dist/core/mcp/bridge/tool-bridge.js +5 -14
- package/dist/core/mcp/catalog/discovery.js +3 -1
- package/dist/core/mcp/client/connection-manager.js +7 -4
- package/dist/core/mcp/client/transport-factory.js +7 -3
- package/dist/core/mcp/host/sampling-provider.js +1 -1
- package/dist/core/mcp/schema/json-schema-to-zod.js +2 -1
- package/dist/core/memory/relevant-retrieval.js +6 -4
- package/dist/core/observability/audit-file.js +2 -1
- package/dist/core/observability/audit-trail.js +3 -1
- package/dist/core/observability/authorization-decisions.js +13 -12
- package/dist/core/observability/error-mapping.js +2 -1
- package/dist/core/observability/logger.js +2 -1
- package/dist/core/observability/monitor.js +24 -0
- package/dist/core/observability/run-outcome-reporter.js +1 -0
- package/dist/core/observability/token-usage.js +5 -4
- package/dist/core/permission-gate/default-gate.js +5 -8
- package/dist/core/plan/storage.js +7 -4
- package/dist/core/plugin/loader.js +8 -5
- package/dist/core/prompts/registry.js +12 -30
- package/dist/core/prompts/runtime.js +3 -1
- package/dist/core/prompts/templates/system/autopilot_system.hbs +28 -4
- package/dist/core/protocols/a2a/sdk/executor.js +3 -1
- package/dist/core/protocols/a2a/sdk/server.js +5 -4
- package/dist/core/protocols/acp/acp-command-runner.js +7 -6
- package/dist/core/protocols/acp/acp-session-persistence.js +13 -10
- package/dist/core/protocols/acp/formal-agent.js +13 -6
- package/dist/core/protocols/acp/permission-provider.js +3 -2
- package/dist/core/protocols/acp/stdio-server.js +6 -6
- package/dist/core/reflection/engine.js +114 -14
- package/dist/core/runtime/agent-server-runtime.js +3 -2
- package/dist/core/runtime/batch-runner.js +81 -0
- package/dist/core/runtime/initialize.js +71 -6
- package/dist/core/runtime/loop-finalize.js +3 -0
- package/dist/core/runtime/loop-session-runner.js +5 -0
- package/dist/core/runtime/loop.js +4 -0
- package/dist/core/runtime/paths.js +9 -6
- package/dist/core/runtime/spawn-interactive.js +5 -4
- package/dist/core/security/redaction.js +3 -2
- package/dist/core/session/compaction/index.js +4 -3
- package/dist/core/session/compression.js +3 -1
- package/dist/core/session/manager.js +26 -38
- package/dist/core/session/pruning-strategy.js +2 -1
- package/dist/core/session/token-tracker.js +27 -9
- package/dist/core/skills/parser.js +3 -2
- package/dist/core/skills/permissions.js +2 -2
- package/dist/core/skills/runtime/MicroTaskRunner.js +1 -1
- package/dist/core/skills/runtime/SkillRunner.js +5 -2
- package/dist/core/slash/steps/slash-execute.js +7 -5
- package/dist/core/slash/strategy.js +1 -1
- package/dist/core/strata/checkpoint/manager.js +16 -10
- package/dist/core/strata/checkpoint/snapshot-create.js +5 -4
- package/dist/core/strata/checkpoint/snapshot-write-tree.js +7 -3
- package/dist/core/strata/engine/shadow-merge-engine.js +4 -2
- package/dist/core/strata/interaction/file-system-provider.js +2 -1
- package/dist/core/strata/layers/file-state-resolver.js +9 -7
- package/dist/core/strata/layers/immutable-git-layer.js +3 -1
- package/dist/core/strata/layers/shadow-driver/readonly-lock.js +8 -6
- package/dist/core/strata/layers/shadow-driver/shadow-driver.js +2 -1
- package/dist/core/strata/layers/worktree.js +9 -10
- package/dist/core/strata/runtime/environment.js +2 -1
- package/dist/core/strata/runtime/synchronizer.js +28 -26
- package/dist/core/streaming/canonical/parts-from-llm-stream-chunk.js +1 -11
- package/dist/core/structured-output/json-extract.js +3 -1
- package/dist/core/structured-output/json-schema-validator.js +1 -13
- package/dist/core/sub-agent/artifacts/store.js +2 -1
- package/dist/core/sub-agent/context-snapshot.js +12 -6
- package/dist/core/sub-agent/controller.js +70 -1
- package/dist/core/sub-agent/core/loop.js +25 -3
- package/dist/core/sub-agent/core/manager.js +343 -117
- package/dist/core/sub-agent/registry-defaults.js +12 -0
- package/dist/core/sub-agent/registry.js +8 -0
- package/dist/core/sub-agent/summary.js +96 -0
- package/dist/core/sub-agent/team.js +98 -0
- package/dist/core/sub-agent/tools/task-await.js +109 -0
- package/dist/core/sub-agent/tools/task-spawn.js +52 -7
- package/dist/core/sub-agent/tools/team.js +92 -0
- package/dist/core/sub-agent/types.js +11 -2
- package/dist/core/target-runtime/profile.js +3 -1
- package/dist/core/tools/audit.js +3 -2
- package/dist/core/tools/budget.js +7 -12
- package/dist/core/tools/builtin/ast.js +144 -0
- package/dist/core/tools/builtin/code-search/backends/powershell.js +3 -1
- package/dist/core/tools/builtin/code-search/backends/rg.js +3 -1
- package/dist/core/tools/builtin/code-search/executor.js +46 -43
- package/dist/core/tools/builtin/code-search/parse/plain-grep.js +3 -1
- package/dist/core/tools/builtin/code-search/parse/rg-json.js +3 -1
- package/dist/core/tools/builtin/fs.js +90 -7
- package/dist/core/tools/builtin/git.js +242 -0
- package/dist/core/tools/builtin/glob.js +79 -0
- package/dist/core/tools/builtin/index.js +53 -111
- package/dist/core/tools/builtin/interaction.js +13 -15
- package/dist/core/tools/builtin/knowledge.js +146 -4
- package/dist/core/tools/builtin/proposal.js +14 -3
- package/dist/core/tools/builtin/verify.js +35 -3
- package/dist/core/tools/capability/executor.js +5 -5
- package/dist/core/tools/headless-payload.js +1 -3
- package/dist/core/tools/mapper.js +8 -42
- package/dist/core/tools/parallel/persistence.js +17 -5
- package/dist/core/tools/parallel/scheduler.js +23 -21
- package/dist/core/tools/permissions/permission-rules.js +69 -115
- package/dist/core/tools/plugins/loader.js +4 -3
- package/dist/core/tools/router.js +112 -58
- package/dist/core/tools/session.js +64 -102
- package/dist/core/tools/streaming/ToolCallAccumulator.js +1 -3
- package/dist/core/tools/tool-visibility.js +2 -1
- package/dist/core/tools/types.js +10 -0
- package/dist/core/types/batch.js +2 -0
- package/dist/core/utils/error.js +79 -0
- package/dist/core/utils/sanitizer.js +5 -2
- package/dist/core/utils/serialize.js +66 -0
- package/dist/core/utils/zod.js +29 -0
- package/dist/core/verification/detect-runner.js +86 -0
- package/dist/core/verification/runner.js +76 -0
- package/dist/core/version.js +3 -1
- package/dist/core/workspace/capabilities.js +3 -2
- package/dist/integrations/langfuse/litellm-langfuse-outcome-reporter.js +9 -8
- package/dist/languages/python/index.js +154 -0
- package/dist/locales/en.js +8 -1
- package/package.json +2 -1
|
@@ -178,7 +178,8 @@ export class SessionArchiver {
|
|
|
178
178
|
})),
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
|
-
catch {
|
|
181
|
+
catch (error) {
|
|
182
|
+
getLogger().debug(`[SessionPruning] Failed to restore session from archive: ${error instanceof Error ? error.message : String(error)}`);
|
|
182
183
|
return null;
|
|
183
184
|
}
|
|
184
185
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { FileAdapter } from '../adapters/fs/index.js';
|
|
3
|
+
import { estimateCost } from '../config/model-pricing.js';
|
|
3
4
|
import { logIgnoredError } from '../observability/ignored-error.js';
|
|
5
|
+
import { getLogger } from '../observability/logger.js';
|
|
6
|
+
import { isRecord } from '../utils/serialize.js';
|
|
4
7
|
/**
|
|
5
8
|
* Token usage tracker for chat sessions.
|
|
6
9
|
* Extracts and accumulates token statistics from LLM execution results.
|
|
@@ -21,26 +24,36 @@ export class TokenTracker {
|
|
|
21
24
|
try {
|
|
22
25
|
const auditRaw = await this.fileAdapter.readFile(result.auditPath, 'utf8');
|
|
23
26
|
const audit = JSON.parse(auditRaw);
|
|
24
|
-
|
|
27
|
+
if (!isRecord(audit))
|
|
28
|
+
return null;
|
|
29
|
+
const context = isRecord(audit.context) ? audit.context : null;
|
|
30
|
+
const eventsRef = isRecord(context?.eventsRef) ? context.eventsRef : null;
|
|
25
31
|
if (!eventsRef || typeof eventsRef.path !== 'string')
|
|
26
32
|
return null;
|
|
27
33
|
const eventsPath = path.isAbsolute(eventsRef.path)
|
|
28
34
|
? eventsRef.path
|
|
29
35
|
: path.join(path.dirname(result.auditPath), eventsRef.path);
|
|
30
36
|
const eventsRaw = await this.fileAdapter.readFile(eventsPath, 'utf8');
|
|
31
|
-
const events =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
const events = [];
|
|
38
|
+
for (const line of eventsRaw.split('\n')) {
|
|
39
|
+
if (line.trim().length === 0)
|
|
40
|
+
continue;
|
|
41
|
+
try {
|
|
42
|
+
events.push(JSON.parse(line));
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
getLogger().debug(`[TokenTracker] Skipping malformed JSON line in events file: ${error instanceof Error ? error.message : String(error)}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
35
48
|
let inputTokens = 0;
|
|
36
49
|
let outputTokens = 0;
|
|
37
50
|
for (const event of events) {
|
|
38
|
-
if (!event
|
|
51
|
+
if (!isRecord(event))
|
|
39
52
|
continue;
|
|
40
53
|
if (event.action !== 'llm.usage')
|
|
41
54
|
continue;
|
|
42
55
|
const details = event.details;
|
|
43
|
-
if (!details
|
|
56
|
+
if (!isRecord(details))
|
|
44
57
|
continue;
|
|
45
58
|
const promptTokens = details.promptTokens;
|
|
46
59
|
const completionTokens = details.completionTokens;
|
|
@@ -65,11 +78,16 @@ export class TokenTracker {
|
|
|
65
78
|
}
|
|
66
79
|
}
|
|
67
80
|
/**
|
|
68
|
-
* Accumulate tokens into session metadata
|
|
81
|
+
* Accumulate tokens into session metadata.
|
|
82
|
+
* Computes estimated cost if model pricing is available.
|
|
69
83
|
*/
|
|
70
|
-
static accumulate(session, usage) {
|
|
84
|
+
static accumulate(session, usage, modelId) {
|
|
71
85
|
session.meta.totalTokens.input += usage.inputTokens;
|
|
72
86
|
session.meta.totalTokens.output += usage.outputTokens;
|
|
87
|
+
const cost = usage.estimatedCost ?? estimateCost(usage.inputTokens, usage.outputTokens, modelId);
|
|
88
|
+
if (cost !== undefined) {
|
|
89
|
+
session.meta.totalTokens.estimatedCost = (session.meta.totalTokens.estimatedCost ?? 0) + cost;
|
|
90
|
+
}
|
|
73
91
|
}
|
|
74
92
|
/**
|
|
75
93
|
* Estimate token count based on text length
|
|
@@ -3,6 +3,7 @@ import { parse as parseYaml } from 'yaml';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { text } from '../../locales/index.js';
|
|
5
5
|
import { tryGetLogger } from '../observability/logger.js';
|
|
6
|
+
import { errorMessage } from '../utils/error.js';
|
|
6
7
|
/**
|
|
7
8
|
* Safe logger accessor that never throws when the logger is not yet initialized.
|
|
8
9
|
*
|
|
@@ -129,7 +130,7 @@ export class SkillParser {
|
|
|
129
130
|
parsed = parseYaml(yamlRaw);
|
|
130
131
|
}
|
|
131
132
|
catch (error) {
|
|
132
|
-
const reason =
|
|
133
|
+
const reason = errorMessage(error);
|
|
133
134
|
const msg = text.skills.yamlParseError(filePath, reason);
|
|
134
135
|
safeLogger().error(msg);
|
|
135
136
|
throw new Error(msg);
|
|
@@ -188,7 +189,7 @@ export class SkillParser {
|
|
|
188
189
|
parsed = parseYaml(yamlRaw);
|
|
189
190
|
}
|
|
190
191
|
catch (error) {
|
|
191
|
-
const reason =
|
|
192
|
+
const reason = errorMessage(error);
|
|
192
193
|
const msg = text.skills.yamlParseError(filePath, reason);
|
|
193
194
|
safeLogger().error(msg);
|
|
194
195
|
throw new Error(msg);
|
|
@@ -89,9 +89,9 @@ export class SkillPermissionManager {
|
|
|
89
89
|
this.policies = [];
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
catch {
|
|
92
|
+
catch (error) {
|
|
93
93
|
const logger = tryGetLogger();
|
|
94
|
-
logger?.warn(text.skills.permissionFileLoadError(this.filePath));
|
|
94
|
+
logger?.warn(`${text.skills.permissionFileLoadError(this.filePath)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
95
95
|
this.policies = [];
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -2,6 +2,7 @@ import * as crypto from 'crypto';
|
|
|
2
2
|
import { MicroTaskRunner } from '../../grizzco/dsl/MicroTaskRunner.js';
|
|
3
3
|
import { tryGetLogger } from '../../observability/logger.js';
|
|
4
4
|
import { Phase } from '../../types/index.js';
|
|
5
|
+
import { isRecord } from '../../utils/serialize.js';
|
|
5
6
|
import { emitSkillAuditEvent, generateSkillTraceId, hashSkillArgs } from '../audit.js';
|
|
6
7
|
import { SkillParser } from '../parser.js';
|
|
7
8
|
import { SkillStrategyDSL } from '../strategy.js';
|
|
@@ -227,7 +228,9 @@ export async function executeSkill(options) {
|
|
|
227
228
|
argsHash,
|
|
228
229
|
traceId,
|
|
229
230
|
denyReason: result.error?.code || 'unknown',
|
|
230
|
-
denySource: result.meta
|
|
231
|
+
denySource: isRecord(result.meta) && isRecord(result.meta.authorization)
|
|
232
|
+
? result.meta.authorization.source
|
|
233
|
+
: 'policy',
|
|
231
234
|
durationMs: Date.now() - startedAt,
|
|
232
235
|
});
|
|
233
236
|
}
|
|
@@ -264,7 +267,7 @@ export async function executeSkill(options) {
|
|
|
264
267
|
cmd,
|
|
265
268
|
output: String(output),
|
|
266
269
|
})),
|
|
267
|
-
injectedPrompt: String(inject?.params
|
|
270
|
+
injectedPrompt: String((isRecord(inject?.params) ? inject.params.prompt : undefined) ?? ''),
|
|
268
271
|
status,
|
|
269
272
|
};
|
|
270
273
|
}
|
|
@@ -2,12 +2,13 @@ function planToDecision(plan, options) {
|
|
|
2
2
|
const action = plan.actions[0];
|
|
3
3
|
if (!action)
|
|
4
4
|
return { kind: 'consumed' };
|
|
5
|
+
const p = action.params ?? {};
|
|
5
6
|
if (action.type === 'FORWARD_TEXT') {
|
|
6
|
-
const next = String(
|
|
7
|
+
const next = String(p.input ?? '');
|
|
7
8
|
return { kind: 'forward', input: next };
|
|
8
9
|
}
|
|
9
10
|
if (action.type === 'UNKNOWN_SLASH') {
|
|
10
|
-
const cmd = String(
|
|
11
|
+
const cmd = String(p.commandName ?? '');
|
|
11
12
|
if (options.unknownSlashPolicy === 'forward_as_text') {
|
|
12
13
|
return { kind: 'forward', input: cmd };
|
|
13
14
|
}
|
|
@@ -31,7 +32,8 @@ export function buildSlashExecuteStep(options, meta) {
|
|
|
31
32
|
const decision = planToDecision(plan, { unknownSlashPolicy: options.unknownSlashPolicy });
|
|
32
33
|
return { ...context, data: { ...data, __decision: decision } };
|
|
33
34
|
}
|
|
34
|
-
const
|
|
35
|
+
const p = action.params ?? {};
|
|
36
|
+
const commandName = String(p.commandName ?? '');
|
|
35
37
|
const spec = options.registry.find(commandName);
|
|
36
38
|
if (!spec) {
|
|
37
39
|
const decision = planToDecision({ ...plan, actions: [{ type: 'UNKNOWN_SLASH', params: { commandName } }] }, { unknownSlashPolicy: options.unknownSlashPolicy });
|
|
@@ -50,8 +52,8 @@ export function buildSlashExecuteStep(options, meta) {
|
|
|
50
52
|
const req = {
|
|
51
53
|
rawInput: context.input.raw,
|
|
52
54
|
command: spec,
|
|
53
|
-
argsText: String(
|
|
54
|
-
tokens: Array.isArray(
|
|
55
|
+
argsText: String(p.argsText ?? ''),
|
|
56
|
+
tokens: Array.isArray(p.tokens) ? p.tokens : [],
|
|
55
57
|
meta,
|
|
56
58
|
};
|
|
57
59
|
const result = await handler.execute(req);
|
|
@@ -18,7 +18,7 @@ export const SlashStrategyDSL = (engine) => {
|
|
|
18
18
|
.when((c) => c.input.isSlash && Boolean(c.resolved?.command), (p) => {
|
|
19
19
|
p.setWorker('slash.execute');
|
|
20
20
|
p.addAction('EXECUTE_SLASH', {
|
|
21
|
-
commandName: engine.ctx.resolved
|
|
21
|
+
commandName: engine.ctx.resolved?.command?.name ?? '',
|
|
22
22
|
argsText: engine.ctx.input.argsText ?? '',
|
|
23
23
|
tokens: engine.ctx.input.tokens ?? [],
|
|
24
24
|
});
|
|
@@ -63,7 +63,8 @@ export class CheckpointManager {
|
|
|
63
63
|
try {
|
|
64
64
|
writeTreeProbe = await probeWriteTreeFailure(git);
|
|
65
65
|
}
|
|
66
|
-
catch {
|
|
66
|
+
catch (probeError) {
|
|
67
|
+
getLogger().debug(`[CheckpointManager] probeWriteTreeFailure failed: ${probeError instanceof Error ? probeError.message : String(probeError)}`);
|
|
67
68
|
writeTreeProbe = {};
|
|
68
69
|
}
|
|
69
70
|
}
|
|
@@ -129,7 +130,8 @@ export class CheckpointManager {
|
|
|
129
130
|
try {
|
|
130
131
|
meta = JSON.parse(msg);
|
|
131
132
|
}
|
|
132
|
-
catch {
|
|
133
|
+
catch (error) {
|
|
134
|
+
getLogger().debug(`[CheckpointManager] Invalid snapshot metadata for ${snapshotHash}: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
135
|
throw new Error(`Invalid snapshot metadata for ${snapshotHash}`);
|
|
134
136
|
}
|
|
135
137
|
if (!meta.staged) {
|
|
@@ -268,8 +270,8 @@ export class CheckpointManager {
|
|
|
268
270
|
try {
|
|
269
271
|
await rm(tempIndexFile, { force: true });
|
|
270
272
|
}
|
|
271
|
-
catch {
|
|
272
|
-
|
|
273
|
+
catch (error) {
|
|
274
|
+
getLogger().debug(`[CheckpointManager] Failed to cleanup temp index: ${error instanceof Error ? error.message : String(error)}`);
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
}
|
|
@@ -292,7 +294,8 @@ export class CheckpointManager {
|
|
|
292
294
|
try {
|
|
293
295
|
meta = JSON.parse(msg);
|
|
294
296
|
}
|
|
295
|
-
catch {
|
|
297
|
+
catch (error) {
|
|
298
|
+
getLogger().debug(`[CheckpointManager] Invalid snapshot metadata for ${snapshotHash}: ${error instanceof Error ? error.message : String(error)}`);
|
|
296
299
|
throw new Error(`Invalid snapshot metadata for ${snapshotHash}`);
|
|
297
300
|
}
|
|
298
301
|
// 3. Get Parent Commit (Original HEAD)
|
|
@@ -339,7 +342,8 @@ export class CheckpointManager {
|
|
|
339
342
|
return { hash, timestamp, message, ref };
|
|
340
343
|
});
|
|
341
344
|
}
|
|
342
|
-
catch {
|
|
345
|
+
catch (error) {
|
|
346
|
+
getLogger().debug(`[CheckpointManager] Failed to list snapshots: ${error instanceof Error ? error.message : String(error)}`);
|
|
343
347
|
return [];
|
|
344
348
|
}
|
|
345
349
|
}
|
|
@@ -354,8 +358,8 @@ export class CheckpointManager {
|
|
|
354
358
|
await git.exec(['update-ref', '-d', `refs/s8p/snapshots/${snapshotHash}`]);
|
|
355
359
|
return;
|
|
356
360
|
}
|
|
357
|
-
catch {
|
|
358
|
-
|
|
361
|
+
catch (error) {
|
|
362
|
+
getLogger().debug(`[CheckpointManager] Direct snapshot deletion failed, trying ref search: ${error instanceof Error ? error.message : String(error)}`);
|
|
359
363
|
}
|
|
360
364
|
// Fallback: find the ref pointing to this hash
|
|
361
365
|
// Note: This is expensive if there are many snapshots, but safe.
|
|
@@ -392,7 +396,8 @@ export class CheckpointManager {
|
|
|
392
396
|
try {
|
|
393
397
|
meta = JSON.parse(msg);
|
|
394
398
|
}
|
|
395
|
-
catch {
|
|
399
|
+
catch (error) {
|
|
400
|
+
getLogger().debug(`[CheckpointManager] Invalid snapshot metadata for ${snapshotHash}: ${error instanceof Error ? error.message : String(error)}`);
|
|
396
401
|
throw new Error(`Invalid snapshot metadata for ${snapshotHash}`);
|
|
397
402
|
}
|
|
398
403
|
// Staged files: Diff between Parent (HEAD at time of snapshot) and Staged Tree
|
|
@@ -475,7 +480,8 @@ export class CheckpointManager {
|
|
|
475
480
|
try {
|
|
476
481
|
meta = JSON.parse(msg);
|
|
477
482
|
}
|
|
478
|
-
catch {
|
|
483
|
+
catch (error) {
|
|
484
|
+
getLogger().debug(`[CheckpointManager] Invalid backup metadata for ${backupHash}: ${error instanceof Error ? error.message : String(error)}`);
|
|
479
485
|
throw new Error(`Invalid backup metadata for ${backupHash}`);
|
|
480
486
|
}
|
|
481
487
|
// 2. Restore Worktree and Index to the T1 state
|
|
@@ -2,6 +2,7 @@ import { randomBytes } from 'crypto';
|
|
|
2
2
|
import { tmpdir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { rm } from '../../adapters/fs/node-fs.js';
|
|
5
|
+
import { getLogger } from '../../observability/logger.js';
|
|
5
6
|
import { normalizePath } from '../../utils/path.js';
|
|
6
7
|
async function getSafeUntrackedFiles(git) {
|
|
7
8
|
// --exclude-standard: Respect .gitignore
|
|
@@ -50,8 +51,8 @@ export async function createSnapshotCommitFromStagedTree(input) {
|
|
|
50
51
|
await git.exec(['add', '--', file], { env });
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
|
-
catch {
|
|
54
|
-
|
|
54
|
+
catch (error) {
|
|
55
|
+
getLogger().debug(`[SnapshotCreate] Failed to add file ${file} to snapshot index: ${error instanceof Error ? error.message : String(error)}`);
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
}
|
|
@@ -71,8 +72,8 @@ export async function createSnapshotCommitFromStagedTree(input) {
|
|
|
71
72
|
try {
|
|
72
73
|
await rm(tempIndexFile, { force: true });
|
|
73
74
|
}
|
|
74
|
-
catch {
|
|
75
|
-
|
|
75
|
+
catch (error) {
|
|
76
|
+
getLogger().debug(`[SnapshotCreate] Failed to clean up temp index file: ${error instanceof Error ? error.message : String(error)}`);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { join } from 'path';
|
|
2
2
|
import { stat } from '../../adapters/fs/node-fs.js';
|
|
3
|
+
import { getLogger } from '../../observability/logger.js';
|
|
3
4
|
import { classifyGitFailureHint } from './snapshot-audit.js';
|
|
4
5
|
export async function tryWriteTreeWithRetry(git, retryDelaysMs) {
|
|
5
6
|
let attempts = 0;
|
|
@@ -28,7 +29,8 @@ export async function probeWriteTreeFailure(git) {
|
|
|
28
29
|
details.indexLockPresent = true;
|
|
29
30
|
details.indexLockAgeMs = Math.max(0, Math.floor(Date.now() - lockStat.mtimeMs));
|
|
30
31
|
}
|
|
31
|
-
catch {
|
|
32
|
+
catch (error) {
|
|
33
|
+
getLogger().debug(`[SnapshotWriteTree] Index lock not present or unreadable: ${error instanceof Error ? error.message : String(error)}`);
|
|
32
34
|
details.indexLockPresent = false;
|
|
33
35
|
}
|
|
34
36
|
try {
|
|
@@ -39,7 +41,8 @@ export async function probeWriteTreeFailure(git) {
|
|
|
39
41
|
.filter(Boolean).length;
|
|
40
42
|
details.unmergedCount = count;
|
|
41
43
|
}
|
|
42
|
-
catch {
|
|
44
|
+
catch (error) {
|
|
45
|
+
getLogger().debug(`[SnapshotWriteTree] Failed to list unmerged files: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
46
|
details.unmergedCount = undefined;
|
|
44
47
|
}
|
|
45
48
|
try {
|
|
@@ -64,7 +67,8 @@ export async function probeWriteTreeFailure(git) {
|
|
|
64
67
|
});
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
|
-
catch {
|
|
70
|
+
catch (error) {
|
|
71
|
+
getLogger().debug(`[SnapshotWriteTree] Failed to probe work tree status: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
72
|
details.isInsideWorkTree = undefined;
|
|
69
73
|
}
|
|
70
74
|
return details;
|
|
@@ -269,7 +269,8 @@ export class ShadowMergeEngine {
|
|
|
269
269
|
return false;
|
|
270
270
|
return this.guardian.inspect(buffer).isBinary;
|
|
271
271
|
}
|
|
272
|
-
catch {
|
|
272
|
+
catch (error) {
|
|
273
|
+
getLogger().debug(`[ShadowMergeEngine] Binary detection failed for ${relativePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
273
274
|
return false;
|
|
274
275
|
}
|
|
275
276
|
}
|
|
@@ -282,7 +283,8 @@ export class ShadowMergeEngine {
|
|
|
282
283
|
try {
|
|
283
284
|
return await git.show(ref, relativePath);
|
|
284
285
|
}
|
|
285
|
-
catch {
|
|
286
|
+
catch (error) {
|
|
287
|
+
getLogger().debug(`[ShadowMergeEngine] git show failed for ${relativePath}@${ref}: ${error instanceof Error ? error.message : String(error)}`);
|
|
286
288
|
return null;
|
|
287
289
|
}
|
|
288
290
|
}
|
|
@@ -81,7 +81,8 @@ export class StrataFileSystemProvider {
|
|
|
81
81
|
const buffer = await fs.readFile(safePath);
|
|
82
82
|
return this.guardian.inspect(buffer).isBinary;
|
|
83
83
|
}
|
|
84
|
-
catch {
|
|
84
|
+
catch (error) {
|
|
85
|
+
getLogger().debug(`[StrataFileSystem] Binary detection failed for ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
85
86
|
return false;
|
|
86
87
|
}
|
|
87
88
|
}
|
|
@@ -3,6 +3,7 @@ import * as path from 'path';
|
|
|
3
3
|
import * as fs from '../../adapters/fs/node-fs.js';
|
|
4
4
|
import { LIMITS } from '../../config/limits.js';
|
|
5
5
|
import { FileStatus } from '../../grizzco/domain/grizzco-types.js';
|
|
6
|
+
import { getLogger } from '../../observability/logger.js';
|
|
6
7
|
/**
|
|
7
8
|
* FileStateResolver
|
|
8
9
|
* Responsibilities: Accurately scan workspace and index state, implementing the data foundation for Zero Index Access.
|
|
@@ -43,9 +44,8 @@ export class FileStateResolver {
|
|
|
43
44
|
state.stagedContent = await this.git.show(':0', normalizedPath);
|
|
44
45
|
state.workingContent = await fs.readFile(absolutePath);
|
|
45
46
|
}
|
|
46
|
-
catch {
|
|
47
|
-
|
|
48
|
-
// But proceed with what we have; strategy layer will handle missing content if needed.
|
|
47
|
+
catch (error) {
|
|
48
|
+
getLogger().debug(`[FileStateResolver] Failed to capture MM content for ${normalizedPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
return state;
|
|
@@ -124,8 +124,8 @@ export class FileStateResolver {
|
|
|
124
124
|
await fd.close();
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
catch {
|
|
128
|
-
|
|
127
|
+
catch (error) {
|
|
128
|
+
getLogger().debug(`[FileStateResolver] Binary detection failed for ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
129
129
|
return false;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
@@ -137,7 +137,8 @@ export class FileStateResolver {
|
|
|
137
137
|
const stats = await fs.lstat(filePath);
|
|
138
138
|
return stats.isSymbolicLink();
|
|
139
139
|
}
|
|
140
|
-
catch {
|
|
140
|
+
catch (error) {
|
|
141
|
+
getLogger().debug(`[FileStateResolver] Symlink detection failed for ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
141
142
|
return false;
|
|
142
143
|
}
|
|
143
144
|
}
|
|
@@ -149,7 +150,8 @@ export class FileStateResolver {
|
|
|
149
150
|
const stats = await fs.stat(filePath);
|
|
150
151
|
return stats.size;
|
|
151
152
|
}
|
|
152
|
-
catch {
|
|
153
|
+
catch (error) {
|
|
154
|
+
getLogger().debug(`[FileStateResolver] File size check failed for ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
153
155
|
return 0;
|
|
154
156
|
}
|
|
155
157
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Wraps existing CheckpointManager to provide StrataSystem interface
|
|
5
5
|
* for L1 Git snapshot and worktree operations.
|
|
6
6
|
*/
|
|
7
|
+
import { getLogger } from '../../observability/logger.js';
|
|
7
8
|
import { CheckpointManager } from '../checkpoint/manager.js';
|
|
8
9
|
/**
|
|
9
10
|
* ImmutableGitLayer Implementation
|
|
@@ -34,7 +35,8 @@ export class ImmutableGitLayerImpl {
|
|
|
34
35
|
const content = await this.checkpointManager.getSnapshotFileContent(process.cwd(), 'HEAD', path);
|
|
35
36
|
return Buffer.from(content);
|
|
36
37
|
}
|
|
37
|
-
catch {
|
|
38
|
+
catch (error) {
|
|
39
|
+
getLogger().debug(`[ImmutableGitLayer] Failed to get file from snapshot: ${error instanceof Error ? error.message : String(error)}`);
|
|
38
40
|
return null;
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -129,7 +129,8 @@ async function removeLockByToken(lockPath, expectedToken) {
|
|
|
129
129
|
try {
|
|
130
130
|
await rename(lockPath, swapPath);
|
|
131
131
|
}
|
|
132
|
-
catch {
|
|
132
|
+
catch (error) {
|
|
133
|
+
getLogger().debug(`[ReadonlyLock] Failed to rename lock file for atomic swap: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
134
|
return false;
|
|
134
135
|
}
|
|
135
136
|
try {
|
|
@@ -141,18 +142,19 @@ async function removeLockByToken(lockPath, expectedToken) {
|
|
|
141
142
|
try {
|
|
142
143
|
await rename(swapPath, lockPath);
|
|
143
144
|
}
|
|
144
|
-
catch {
|
|
145
|
-
|
|
145
|
+
catch (rollbackError) {
|
|
146
|
+
getLogger().debug(`[ReadonlyLock] Failed to rollback lock swap (token mismatch): ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
146
147
|
await unlink(swapPath).catch(() => null);
|
|
147
148
|
}
|
|
148
149
|
return false;
|
|
149
150
|
}
|
|
150
|
-
catch {
|
|
151
|
+
catch (error) {
|
|
152
|
+
getLogger().debug(`[ReadonlyLock] Failed to verify lock token after swap: ${error instanceof Error ? error.message : String(error)}`);
|
|
151
153
|
try {
|
|
152
154
|
await rename(swapPath, lockPath);
|
|
153
155
|
}
|
|
154
|
-
catch {
|
|
155
|
-
|
|
156
|
+
catch (rollbackError) {
|
|
157
|
+
getLogger().debug(`[ReadonlyLock] Failed to rollback lock swap (verification error): ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
156
158
|
await unlink(swapPath).catch(() => null);
|
|
157
159
|
}
|
|
158
160
|
return false;
|
|
@@ -36,7 +36,8 @@ async function pointsToExpectedDependency(sourcePath, targetPath) {
|
|
|
36
36
|
]);
|
|
37
37
|
return arePathsEquivalent(resolvedSourcePath, resolvedTargetPath);
|
|
38
38
|
}
|
|
39
|
-
catch {
|
|
39
|
+
catch (error) {
|
|
40
|
+
getLogger().debug(`[ShadowDriver] Failed to verify dependency path equivalence: ${error instanceof Error ? error.message : String(error)}`);
|
|
40
41
|
return false;
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -5,7 +5,9 @@ import { text } from '../../../locales/index.js';
|
|
|
5
5
|
import { access, readdir, realpath, rm } from '../../adapters/fs/node-fs.js';
|
|
6
6
|
import { GitAdapter } from '../../adapters/git/git-adapter.js';
|
|
7
7
|
import { getLogger } from '../../observability/logger.js';
|
|
8
|
+
import { errorMessage } from '../../utils/error.js';
|
|
8
9
|
import { isPathWithinDirectory, normalizePath } from '../../utils/path.js';
|
|
10
|
+
import { isRecord } from '../../utils/serialize.js';
|
|
9
11
|
import { detectDependencyPaths } from './shadow-driver/strategy.js';
|
|
10
12
|
function resolveEnvironmentMode(options) {
|
|
11
13
|
return options.environmentMode === 'parity' ? 'parity' : 'strict';
|
|
@@ -46,7 +48,8 @@ async function tryRealpath(value) {
|
|
|
46
48
|
try {
|
|
47
49
|
return await realpath(value);
|
|
48
50
|
}
|
|
49
|
-
catch {
|
|
51
|
+
catch (error) {
|
|
52
|
+
getLogger().debug(`[Worktree] Failed to resolve realpath for ${value}: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
53
|
return null;
|
|
51
54
|
}
|
|
52
55
|
}
|
|
@@ -73,14 +76,14 @@ async function removeProjectedWorktreeEntries(workPath) {
|
|
|
73
76
|
worktreeRealPath = await realpath(workPath);
|
|
74
77
|
}
|
|
75
78
|
catch (error) {
|
|
76
|
-
throw new Error(`Failed to resolve worktree path before git cleanup (${workPath}): ${
|
|
79
|
+
throw new Error(`Failed to resolve worktree path before git cleanup (${workPath}): ${errorMessage(error)}`);
|
|
77
80
|
}
|
|
78
81
|
let entries = [];
|
|
79
82
|
try {
|
|
80
83
|
entries = (await readdir(workPath, { withFileTypes: true }));
|
|
81
84
|
}
|
|
82
85
|
catch (error) {
|
|
83
|
-
throw new Error(`Failed to enumerate worktree entries before git cleanup (${workPath}): ${
|
|
86
|
+
throw new Error(`Failed to enumerate worktree entries before git cleanup (${workPath}): ${errorMessage(error)}`);
|
|
84
87
|
}
|
|
85
88
|
for (const entry of entries) {
|
|
86
89
|
const name = entry?.name;
|
|
@@ -116,7 +119,7 @@ async function pruneWorktreeDependencyRoots(baseRepoPath, worktreePath) {
|
|
|
116
119
|
getLogger().debug(`Pruned disposable dependency root before worktree cleanup: ${dependencyRoot}`);
|
|
117
120
|
}
|
|
118
121
|
catch (error) {
|
|
119
|
-
getLogger().debug(`Failed to prune dependency root before worktree cleanup (${dependencyRoot}): ${
|
|
122
|
+
getLogger().debug(`Failed to prune dependency root before worktree cleanup (${dependencyRoot}): ${errorMessage(error)}`);
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
}
|
|
@@ -243,7 +246,7 @@ export class WorkspaceManager {
|
|
|
243
246
|
return true;
|
|
244
247
|
}
|
|
245
248
|
catch (error) {
|
|
246
|
-
if (error &&
|
|
249
|
+
if (isRecord(error) && error.code === 'ENOENT') {
|
|
247
250
|
return false;
|
|
248
251
|
}
|
|
249
252
|
return true;
|
|
@@ -268,11 +271,7 @@ export class WorkspaceManager {
|
|
|
268
271
|
}
|
|
269
272
|
}
|
|
270
273
|
catch (error) {
|
|
271
|
-
const msg = error
|
|
272
|
-
? error instanceof Error
|
|
273
|
-
? error.message
|
|
274
|
-
: String(error)
|
|
275
|
-
: String(error);
|
|
274
|
+
const msg = errorMessage(error);
|
|
276
275
|
onEvent?.({
|
|
277
276
|
type: 'action.fallback',
|
|
278
277
|
tool: 'git',
|
|
@@ -20,7 +20,8 @@ async function pathExists(target) {
|
|
|
20
20
|
await stat(target);
|
|
21
21
|
return true;
|
|
22
22
|
}
|
|
23
|
-
catch {
|
|
23
|
+
catch (error) {
|
|
24
|
+
getLogger().debug(`[RuntimeEnvironment] pathExists check failed for ${target}: ${error instanceof Error ? error.message : String(error)}`);
|
|
24
25
|
return false;
|
|
25
26
|
}
|
|
26
27
|
}
|