@inneranimalmedia/agentsam-sdk 2.6.8 → 2.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/apps/README.md +25 -0
- package/apps/cad-creator/shared/cad/package.json +1 -1
- package/apps/client-cms-editor/backend/package.json +5 -7
- package/apps/client-cms-editor/frontend/package.json +5 -7
- package/apps/client-cms-editor/frontend/tsconfig.json +27 -8
- package/apps/client-cms-editor/package-lock.json +8 -8
- package/apps/client-cms-editor/package.json +1 -1
- package/apps/client-cms-editor/shared/cms/package.json +3 -5
- package/docs/LOCAL_ENGINE_COMPUTE_AUDIT_PLAN.md +299 -0
- package/docs/architecture/HOOKS-MODELS-SELF-HOSTING-PLAN.md +199 -0
- package/examples/hyperspace-demo/index.html +16 -0
- package/examples/hyperspace-demo/package.json +21 -0
- package/examples/hyperspace-demo/src/main.tsx +160 -0
- package/examples/hyperspace-demo/tsconfig.json +9 -0
- package/examples/hyperspace-demo/vite.config.ts +24 -0
- package/migrations/runtime/0005_agentsam_hooks.sql +87 -0
- package/package.json +37 -10
- package/packages/agentsam-brand/package.json +1 -1
- package/packages/agentsam-brand/src/core/v2/compile.js +1 -1
- package/packages/agentsam-brand/src/core/v2/schema.js +1 -1
- package/packages/agentsam-contracts/package.json +71 -20
- package/packages/agentsam-contracts/scripts/build.mjs +18 -0
- package/packages/agentsam-contracts/src/errors.ts +19 -10
- package/packages/agentsam-contracts/test/contracts.test.mjs +4 -1
- package/packages/agentsam-contracts/test/repository.test.mjs +4 -1
- package/packages/agentsam-contracts/tsconfig.build.json +10 -0
- package/packages/agentsam-errors/package.json +13 -4
- package/packages/agentsam-errors/protocol/agentsam.error.v2.schema.json +821 -0
- package/packages/agentsam-errors/protocol/error-catalog.json +3512 -0
- package/packages/agentsam-errors/src/envelope.js +63 -11
- package/packages/agentsam-errors/src/error.js +6 -0
- package/packages/agentsam-errors/src/fingerprint.js +9 -1
- package/packages/agentsam-errors/src/normalize.js +51 -6
- package/packages/agentsam-errors/src/recovery.js +9 -35
- package/packages/agentsam-errors/src/transport.js +6 -1
- package/packages/agentsam-errors/src/vocabulary.js +515 -126
- package/packages/agentsam-errors/test/catalog-v2.test.mjs +106 -0
- package/packages/agentsam-errors/types/index.d.ts +157 -0
- package/packages/agentsam-goap/package.json +2 -2
- package/packages/agentsam-hooks/README.md +206 -0
- package/packages/agentsam-hooks/bin/agentsam-hooks.mjs +64 -0
- package/packages/agentsam-hooks/bindings/go/command.go +55 -0
- package/packages/agentsam-hooks/bindings/go/errors_generated.go +402 -0
- package/packages/agentsam-hooks/bindings/go/go.mod +3 -0
- package/packages/agentsam-hooks/bindings/go/hooks.go +285 -0
- package/packages/agentsam-hooks/bindings/go/hooks_test.go +48 -0
- package/packages/agentsam-hooks/bindings/rust/Cargo.toml +11 -0
- package/packages/agentsam-hooks/bindings/rust/src/errors_generated.rs +396 -0
- package/packages/agentsam-hooks/bindings/rust/src/lib.rs +397 -0
- package/packages/agentsam-hooks/package.json +69 -0
- package/packages/agentsam-hooks/schema/manifest.json +54 -0
- package/packages/agentsam-hooks/scripts/clean-protocol.mjs +17 -0
- package/packages/agentsam-hooks/scripts/sync-protocol.mjs +27 -0
- package/packages/agentsam-hooks/src/adapters/agents.js +82 -0
- package/packages/agentsam-hooks/src/adapters/callback.js +4 -0
- package/packages/agentsam-hooks/src/adapters/capability.js +122 -0
- package/packages/agentsam-hooks/src/adapters/command.js +104 -0
- package/packages/agentsam-hooks/src/adapters/composite.js +31 -0
- package/packages/agentsam-hooks/src/adapters/http.js +58 -0
- package/packages/agentsam-hooks/src/adapters/lsp.js +116 -0
- package/packages/agentsam-hooks/src/adapters/mcp.js +76 -0
- package/packages/agentsam-hooks/src/adapters/provider.js +129 -0
- package/packages/agentsam-hooks/src/config.js +143 -0
- package/packages/agentsam-hooks/src/contracts.js +284 -0
- package/packages/agentsam-hooks/src/errors-generated.js +2732 -0
- package/packages/agentsam-hooks/src/index.d.ts +193 -0
- package/packages/agentsam-hooks/src/index.js +14 -0
- package/packages/agentsam-hooks/src/policy.js +34 -0
- package/packages/agentsam-hooks/src/runtime.js +312 -0
- package/packages/agentsam-hooks/src/store.js +264 -0
- package/packages/agentsam-hooks/test/adapters.test.mjs +216 -0
- package/packages/agentsam-hooks/test/runtime.test.mjs +258 -0
- package/packages/agentsam-knowledge/package.json +3 -2
- package/packages/agentsam-nav/package.json +1 -1
- package/packages/agentsam-queue-control/package.json +1 -1
- package/packages/agentsam-rapid-rust/src/main.rs +1 -0
- package/packages/agentsam-repository/package.json +3 -2
- package/packages/agentsam-vault/package.json +8 -5
- package/packages/agentsam-workbench/package.json +45 -18
- package/packages/connectors/cloudflare/package.json +1 -1
- package/packages/heuristic-theme/package.json +1 -1
- package/packages/identity/package.json +3 -2
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +9 -1
- package/packages/providers/completeful/package.json +1 -1
- package/packages/theme-church-site/README.md +2 -2
- package/packages/theme-church-site/package.json +2 -3
- package/packages/theme-church-site/src/index.js +1 -1
- package/packages/theme-church-site/test/theme.test.mjs +1 -1
- package/packages/theme-companions-site/README.md +2 -2
- package/packages/theme-companions-site/package.json +2 -3
- package/packages/theme-companions-site/src/index.js +1 -1
- package/packages/theme-companions-site/test/theme.test.mjs +1 -1
- package/packages/theme-floors-site/README.md +2 -2
- package/packages/theme-floors-site/package.json +2 -3
- package/packages/theme-floors-site/src/index.js +1 -1
- package/packages/theme-floors-site/test/theme.test.mjs +1 -1
- package/packages/theme-fuelnfree-site/README.md +2 -2
- package/packages/theme-fuelnfree-site/package.json +2 -3
- package/packages/theme-fuelnfree-site/src/index.js +1 -1
- package/packages/theme-fuelnfree-site/test/theme.test.mjs +1 -1
- package/packages/theme-handyman-site/README.md +2 -2
- package/packages/theme-handyman-site/package.json +2 -3
- package/packages/theme-handyman-site/src/index.js +1 -1
- package/packages/theme-handyman-site/test/theme.test.mjs +1 -1
- package/packages/theme-insurance-site/README.md +2 -2
- package/packages/theme-insurance-site/package.json +2 -3
- package/packages/theme-insurance-site/src/index.js +1 -1
- package/packages/theme-insurance-site/test/theme.test.mjs +1 -1
- package/packages/theme-scenes/package.json +1 -1
- package/packages/theme-shinshu-site/README.md +2 -2
- package/packages/theme-shinshu-site/package.json +2 -3
- package/packages/theme-shinshu-site/src/index.js +1 -1
- package/packages/theme-shinshu-site/test/theme.test.mjs +1 -1
- package/packages/work-graph/package.json +3 -2
- package/protocol/apps/agentsam.app.v1.schema.json +1 -1
- package/protocol/apps/agentsam.host-install.v1.schema.json +1 -1
- package/protocol/assets/asset-record.v1.schema.json +1 -1
- package/protocol/brand/brandpack.v1.schema.json +1 -1
- package/protocol/capabilities/capability-manifest.schema.json +1 -1
- package/protocol/capabilities/knowledge-search-input.schema.json +1 -0
- package/protocol/credentials/issue.v1.schema.json +1 -1
- package/protocol/database/agentsam.schema-pack.v1.schema.json +1 -1
- package/protocol/database/connection.v1.schema.json +1 -1
- package/protocol/embeddings/embedding-profile.v1.schema.json +1 -1
- package/protocol/errors/README.md +36 -0
- package/protocol/errors/agentsam.error.v2.schema.json +821 -0
- package/protocol/errors/error-catalog.json +3506 -158
- package/protocol/errors/error-envelope.schema.json +195 -52
- package/protocol/errors/recovery.v1.schema.json +1 -1
- package/protocol/features/agentsam.feature.v1.schema.json +1 -1
- package/protocol/hooks/README.md +18 -0
- package/protocol/hooks/agentsam.hook.output.v1.schema.json +27 -0
- package/protocol/hooks/agentsam.hook.receipt.v1.schema.json +61 -0
- package/protocol/hooks/agentsam.hook.v1.schema.json +35 -0
- package/protocol/hooks/agentsam.hooks.config.v1.schema.json +78 -0
- package/protocol/local-engine/benchmark.v1.schema.json +14 -0
- package/protocol/local-engine/engine.v1.schema.json +17 -0
- package/protocol/models/model-inventory-v2.schema.json +1 -1
- package/protocol/models/provider-model-snapshot.v1.schema.json +22 -0
- package/protocol/rpc/v1/errors.proto +1 -0
- package/protocol/runtime/agentsam.runtime.v1.schema.json +1 -1
- package/protocol/runtime/workspace-fs.v1.schema.json +1 -1
- package/protocol/sam/activity.v1.schema.json +1 -1
- package/protocol/sam/answer.v1.schema.json +1 -1
- package/protocol/sam/calibration.v1.schema.json +1 -1
- package/protocol/sam/decision-receipt.v1.schema.json +1 -1
- package/protocol/sam/evaluation.v1.schema.json +1 -1
- package/protocol/sam/operation.schema.json +1 -1
- package/protocol/sam/outcome.v1.schema.json +1 -1
- package/protocol/sam/question.v1.schema.json +1 -1
- package/protocol/sam/result.schema.json +1 -1
- package/protocol/sam/state.v1.schema.json +1 -1
- package/protocol/scoring/scorecard.v1.schema.json +1 -1
- package/protocol/skills/agentsam.interaction.v1.schema.json +1 -1
- package/protocol/skills/agentsam.skill.v1.schema.json +1 -1
- package/protocol/theme-refinery/product-metadata.schema.json +1 -1
- package/protocol/theme-refinery/reconciliation-receipt.schema.json +1 -1
- package/protocol/ui/icon.v1.schema.json +1 -1
- package/python/README.md +20 -0
- package/python/agentsam_sdk/errors/__init__.py +4 -0
- package/python/agentsam_sdk/errors/vocabulary.py +2730 -0
- package/python/agentsam_sdk/hooks/__init__.py +32 -0
- package/python/agentsam_sdk/hooks/adapters.py +132 -0
- package/python/agentsam_sdk/hooks/contracts.py +121 -0
- package/python/agentsam_sdk/hooks/runtime.py +253 -0
- package/python/tests/test_hooks.py +115 -0
- package/src/agent/responses-runner.js +145 -1
- package/src/cli/command-catalog.js +2 -0
- package/src/cli.js +19 -0
- package/src/commands/app.js +10 -0
- package/src/commands/cheat-sheet.js +1 -0
- package/src/commands/engine.js +10 -0
- package/src/commands/hooks.js +260 -0
- package/src/commands/machine.js +71 -38
- package/src/commands/models.js +1 -1
- package/src/commands/package.js +10 -3
- package/src/commands/runtime.js +25 -10
- package/src/commands/setup.js +30 -6
- package/src/commands/shell.js +114 -9
- package/src/commands/terminal.js +20 -8
- package/src/errors/contract.js +4 -4
- package/src/errors/diagnostic.js +10 -10
- package/src/errors/index.js +1 -1
- package/src/index.js +52 -0
- package/src/indexing/ingest/materials.js +237 -30
- package/src/knowledge/service/grpc-codec.js +2 -0
- package/src/lib/setup/runtime.js +4 -2
- package/src/lib/slash-commands.js +1 -0
- package/src/local/runtime-store.js +46 -0
- package/src/local-engine/assets.js +37 -0
- package/src/local-engine/audit.js +133 -0
- package/src/local-engine/benchmark.js +26 -0
- package/src/local-engine/contracts.js +101 -0
- package/src/local-engine/engines.js +142 -0
- package/src/local-engine/index.js +18 -0
- package/src/local-engine/runtime.js +39 -0
- package/src/models/catalog.js +0 -49
- package/src/models/inventory-core.js +69 -0
- package/src/plugins/index.js +8 -1
- package/src/plugins/registry.js +56 -0
- package/src/rpc/generated/errors_pb.js +49 -1
- package/src/tools/runtime.js +13 -5
|
@@ -7,6 +7,11 @@ import { searchToolCards, hydrateToolSchemas } from '../tools/index.js';
|
|
|
7
7
|
import { createAgentEvent } from '../telemetry/index.js';
|
|
8
8
|
import { diagnosticFromError } from '../errors/index.js';
|
|
9
9
|
import { runAgentSamModelTurn } from './model-turn.js';
|
|
10
|
+
import {
|
|
11
|
+
createHookedCapabilityAdapter,
|
|
12
|
+
createHookedProviderAdapter,
|
|
13
|
+
ensureHookRuntime,
|
|
14
|
+
} from '../../packages/agentsam-hooks/src/index.js';
|
|
10
15
|
|
|
11
16
|
const RUNTIME_OWNED_KEYS = new Set(['account_id', 'user_id', 'tenant_id', 'workspace_id', 'connection_id', 'runtime_lease_id', 'execution_id']);
|
|
12
17
|
|
|
@@ -229,7 +234,7 @@ function toolOutputInput(outputs) {
|
|
|
229
234
|
}));
|
|
230
235
|
}
|
|
231
236
|
|
|
232
|
-
|
|
237
|
+
async function runAgentSamTurnCore(options = {}) {
|
|
233
238
|
const provider = options.provider;
|
|
234
239
|
if (!provider?.create || !provider?.continueWithToolOutputs) throw new TypeError('Responses provider adapter is required');
|
|
235
240
|
if (!options.capabilityAdapter) throw new TypeError('capabilityAdapter is required');
|
|
@@ -615,5 +620,144 @@ export async function runAgentSamTurn(options = {}) {
|
|
|
615
620
|
});
|
|
616
621
|
}
|
|
617
622
|
|
|
623
|
+
function hookInvocation(options = {}) {
|
|
624
|
+
return {
|
|
625
|
+
session_id: options.sessionId,
|
|
626
|
+
run_id: options.runId,
|
|
627
|
+
turn_id: options.turnId,
|
|
628
|
+
message_id: options.messageId,
|
|
629
|
+
agent_id: options.agentId,
|
|
630
|
+
source: options.source || 'agentsam-sdk',
|
|
631
|
+
metadata: options.hookMetadata,
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Provider-neutral AgentSam turn with optional lifecycle instrumentation.
|
|
637
|
+
*
|
|
638
|
+
* Passing `hookRuntime` (or a plain `hooks` registry) instruments the model
|
|
639
|
+
* and capability adapters without teaching the orchestration loop any
|
|
640
|
+
* provider, MCP, LSP, or sub-agent wire format. An agent_stop hook may request
|
|
641
|
+
* another bounded turn; continuation reuses provider state and cumulative
|
|
642
|
+
* usage instead of constructing a hidden second session.
|
|
643
|
+
*/
|
|
644
|
+
export async function runAgentSamTurn(options = {}) {
|
|
645
|
+
const hookSource = options.hookRuntime || options.hooks;
|
|
646
|
+
if (!hookSource) return runAgentSamTurnCore(options);
|
|
647
|
+
|
|
648
|
+
const hooks = ensureHookRuntime(hookSource);
|
|
649
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
650
|
+
const invocation = hookInvocation(options);
|
|
651
|
+
const submitted = await hooks.dispatch('user_prompt_submitted', {
|
|
652
|
+
prompt: clean(options.prompt),
|
|
653
|
+
cwd,
|
|
654
|
+
}, invocation, { cwd });
|
|
655
|
+
const submittedPrompt = clean(submitted.input.prompt);
|
|
656
|
+
if (!submittedPrompt) throw new TypeError('prompt is required');
|
|
657
|
+
const transformed = await hooks.dispatch('user_prompt_transformed', {
|
|
658
|
+
original_prompt: clean(options.prompt),
|
|
659
|
+
transformed_prompt: submittedPrompt,
|
|
660
|
+
cwd,
|
|
661
|
+
}, invocation, { cwd });
|
|
662
|
+
const prompt = clean(transformed.input.transformed_prompt);
|
|
663
|
+
if (!prompt) throw new TypeError('transformed prompt is required');
|
|
664
|
+
const additionalContext = [submitted.output.additional_context, transformed.output.additional_context]
|
|
665
|
+
.filter(Boolean).join('\n\n');
|
|
666
|
+
const instrumented = {
|
|
667
|
+
...options,
|
|
668
|
+
prompt,
|
|
669
|
+
provider: createHookedProviderAdapter(options.provider, {
|
|
670
|
+
hookRuntime: hooks,
|
|
671
|
+
invocation,
|
|
672
|
+
cwd,
|
|
673
|
+
requestPermission: options.requestPermission,
|
|
674
|
+
maxRetries: options.maxHookRetries,
|
|
675
|
+
}),
|
|
676
|
+
capabilityAdapter: createHookedCapabilityAdapter(options.capabilityAdapter, {
|
|
677
|
+
hookRuntime: hooks,
|
|
678
|
+
invocation,
|
|
679
|
+
cwd,
|
|
680
|
+
requestPermission: options.requestPermission,
|
|
681
|
+
maxRetries: options.maxHookRetries,
|
|
682
|
+
}),
|
|
683
|
+
...(additionalContext && options.instructions != null
|
|
684
|
+
? { instructions: [String(options.instructions), additionalContext].filter(Boolean).join('\n\n') }
|
|
685
|
+
: {}),
|
|
686
|
+
...(additionalContext && options.instructions == null
|
|
687
|
+
? {
|
|
688
|
+
contextItems: [
|
|
689
|
+
...(options.contextItems || []),
|
|
690
|
+
{ kind: 'hook', ref: 'hook://user-prompt/context', priority: 95, content: additionalContext },
|
|
691
|
+
],
|
|
692
|
+
}
|
|
693
|
+
: {}),
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const maxContinuations = Number.isInteger(options.maxHookContinuations)
|
|
697
|
+
? Math.max(0, Math.min(options.maxHookContinuations, 8))
|
|
698
|
+
: 4;
|
|
699
|
+
const continuationReceipts = [];
|
|
700
|
+
let current = instrumented;
|
|
701
|
+
let result;
|
|
702
|
+
let totalCost = 0;
|
|
703
|
+
let totalRounds = 0;
|
|
704
|
+
let totalCalls = 0;
|
|
705
|
+
let totalElapsedMs = 0;
|
|
706
|
+
let hookContinuations = 0;
|
|
707
|
+
const costBreakdown = { input: 0, cached_input: 0, cache_write: 0, output: 0 };
|
|
708
|
+
const allToolReceipts = [];
|
|
709
|
+
const allContinuationCompactions = [];
|
|
710
|
+
|
|
711
|
+
for (let continuationIndex = 0; ; continuationIndex += 1) {
|
|
712
|
+
result = await runAgentSamTurnCore(current);
|
|
713
|
+
totalCost += Number(result.total_cost_usd || 0);
|
|
714
|
+
totalRounds += Number(result.run_budget?.tool_rounds || 0);
|
|
715
|
+
totalCalls += Number(result.run_budget?.tool_calls || 0);
|
|
716
|
+
totalElapsedMs += Number(result.run_budget?.elapsed_ms || 0);
|
|
717
|
+
for (const key of Object.keys(costBreakdown)) costBreakdown[key] += Number(result.cost_breakdown_usd?.[key] || 0);
|
|
718
|
+
allToolReceipts.push(...(result.tool_receipts || []));
|
|
719
|
+
allContinuationCompactions.push(...(result.continuation_compactions || []));
|
|
720
|
+
const stopped = await hooks.dispatch('agent_stop', {
|
|
721
|
+
stop_reason: result.output_text ? 'completed' : 'no_output',
|
|
722
|
+
stop_hook_active: continuationIndex > 0,
|
|
723
|
+
output_text: result.output_text,
|
|
724
|
+
continuation_index: continuationIndex,
|
|
725
|
+
run_budget: result.run_budget,
|
|
726
|
+
}, invocation, { cwd });
|
|
727
|
+
continuationReceipts.push(...stopped.receipts);
|
|
728
|
+
if (stopped.output.decision !== 'block') break;
|
|
729
|
+
if (continuationIndex >= maxContinuations) throw new Error(`hook_continuation_limit_exceeded:${maxContinuations}`);
|
|
730
|
+
const reason = clean(stopped.output.reason);
|
|
731
|
+
if (!reason) throw new Error('hook_continuation_reason_required');
|
|
732
|
+
hookContinuations += 1;
|
|
733
|
+
current = {
|
|
734
|
+
...instrumented,
|
|
735
|
+
prompt: reason,
|
|
736
|
+
previousProviderState: result.provider_state,
|
|
737
|
+
previousUsageSnapshot: result.usage_snapshot,
|
|
738
|
+
cumulativeUsage: result.cumulative_usage,
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return Object.freeze({
|
|
743
|
+
...result,
|
|
744
|
+
...(submitted.output.suppress_output === true || transformed.output.suppress_output === true
|
|
745
|
+
? { output_text: '', suppressed_by_hook: true } : {}),
|
|
746
|
+
total_cost_usd: totalCost,
|
|
747
|
+
cost_breakdown_usd: Object.freeze(costBreakdown),
|
|
748
|
+
tool_receipts: Object.freeze(allToolReceipts),
|
|
749
|
+
continuation_compactions: Object.freeze(allContinuationCompactions),
|
|
750
|
+
run_budget: Object.freeze({
|
|
751
|
+
...result.run_budget,
|
|
752
|
+
tool_rounds: totalRounds,
|
|
753
|
+
tool_calls: totalCalls,
|
|
754
|
+
elapsed_ms: totalElapsedMs,
|
|
755
|
+
hook_continuations: hookContinuations,
|
|
756
|
+
max_hook_continuations: maxContinuations,
|
|
757
|
+
}),
|
|
758
|
+
hook_receipts: Object.freeze([...submitted.receipts, ...transformed.receipts, ...continuationReceipts]),
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
|
|
618
762
|
/** @deprecated Use runAgentSamTurn(). */
|
|
619
763
|
export const runResponsesAgent = runAgentSamTurn;
|
|
@@ -14,6 +14,7 @@ export const CLI_COMMAND_CATALOG = Object.freeze([
|
|
|
14
14
|
{ id: 'dev', summary: 'Run this project’s npm dev script', topic: 'work', skill: 'agentsam-app-fundamentals' },
|
|
15
15
|
{ id: 'inspect', summary: 'Bounded repository inspect / authority view', topic: 'work', skill: 'agentsam-app-fundamentals', operation: 'repository.inspect', common: true },
|
|
16
16
|
{ id: 'machine', summary: 'Deterministic local machine perception (inspect / asset discovery)', topic: 'work', skill: 'agentsam-app-fundamentals', operation: 'machine.inspect', common: true },
|
|
17
|
+
{ id: 'engine', summary: 'Discover, audit, benchmark, and govern local AI engines', topic: 'runtime', skill: 'agentsam-app-fundamentals', operation: 'engine.audit', common: true },
|
|
17
18
|
{ id: 'package', summary: 'Audit, verify, and plan publication of distributable packages', topic: 'work', skill: 'agentsam-progression-guard', operation: 'package.audit', common: true, usage: ['agentsam package audit [--public] [--offline] [--json]', 'agentsam package status <name> [--offline] [--json]', 'agentsam package verify <name> [--offline] [--json]', 'agentsam package publish-plan [--offline] [--json]'] },
|
|
18
19
|
{ id: 'capabilities', summary: 'Inspect capability contracts', topic: 'create', skill: 'agentsam-app-fundamentals' },
|
|
19
20
|
{
|
|
@@ -46,6 +47,7 @@ export const CLI_COMMAND_CATALOG = Object.freeze([
|
|
|
46
47
|
},
|
|
47
48
|
{ id: 'db', summary: 'Project-local SQLite status/init', topic: 'runtime', skill: 'agentsam-app-fundamentals' },
|
|
48
49
|
{ id: 'models', summary: 'Probe hosted/local model availability', topic: 'start', skill: 'agentsam-app-fundamentals', common: true },
|
|
50
|
+
{ id: 'hooks', aliases: ['hook'], summary: 'Inspect lifecycle hooks, sources, and execution receipts', topic: 'runtime', skill: 'agentsam-app-fundamentals', common: true, usage: ['agentsam hooks status', 'agentsam hooks list', 'agentsam hooks executions [--limit N]', 'agentsam hooks init'] },
|
|
49
51
|
{ id: 'providers', summary: 'Configure machine provider credentials', topic: 'start', skill: 'agentsam-app-fundamentals' },
|
|
50
52
|
{ id: 'credentials', aliases: ['credential'], summary: 'Audit credentials, drift, and failure remediation (never prints secrets)', topic: 'start', skill: 'agentsam-app-fundamentals', common: true },
|
|
51
53
|
{ id: 'cheat-sheet', aliases: ['cheatsheet'], summary: 'Organized command groups (gcloud-like)', topic: 'start', skill: 'agentsam-app-fundamentals', common: true },
|
package/src/cli.js
CHANGED
|
@@ -36,6 +36,7 @@ import { runPackage } from './commands/package.js';
|
|
|
36
36
|
import { runRecon } from './commands/recon.js';
|
|
37
37
|
import { runCad } from './commands/cad.js';
|
|
38
38
|
import { runMachine } from './commands/machine.js';
|
|
39
|
+
import { runEngine } from './commands/engine.js';
|
|
39
40
|
import { runSkills } from './commands/skills.js';
|
|
40
41
|
import { runSkill } from './commands/skill.js';
|
|
41
42
|
import { runEval } from './commands/eval.js';
|
|
@@ -51,6 +52,7 @@ import { runLogin, runLogout } from './commands/account-auth.js';
|
|
|
51
52
|
import { runPlugins } from './commands/plugins.js';
|
|
52
53
|
import { runCredentials } from './commands/credentials.js';
|
|
53
54
|
import { runCheatSheet } from './commands/cheat-sheet.js';
|
|
55
|
+
import { runHooks } from './commands/hooks.js';
|
|
54
56
|
import { runCompute } from './commands/compute.js';
|
|
55
57
|
import { runGoogleCloud } from './commands/google-cloud.js';
|
|
56
58
|
import { runBilling } from './commands/billing.js';
|
|
@@ -99,6 +101,7 @@ function printLegacyHelp() {
|
|
|
99
101
|
agentsam dev Run this project's existing npm dev script
|
|
100
102
|
agentsam inspect [--json] Bounded repository index by default; use --view full for authority envelope
|
|
101
103
|
agentsam machine inspect Native deterministic perception + asset discovery (--json)
|
|
104
|
+
agentsam engine status|audit|benchmark|assets Local AI engine + compute tooling
|
|
102
105
|
agentsam brand [scan|…] Deterministic brand intelligence on repository.snapshot authority
|
|
103
106
|
agentsam plan brand Composable brand normalization plan (--goap optional)
|
|
104
107
|
agentsam deploy Graduate an AgentSam project intentionally
|
|
@@ -454,6 +457,14 @@ if (command === '--version' || command === '-v') {
|
|
|
454
457
|
} else if (command === 'inspect') {
|
|
455
458
|
try { await runInspect(rest); }
|
|
456
459
|
catch (e) { reportCliError(e); process.exitCode = 1; }
|
|
460
|
+
} else if (command === 'engine') {
|
|
461
|
+
try {
|
|
462
|
+
const code = await runEngine(rest);
|
|
463
|
+
if (typeof code === 'number' && code !== 0) process.exitCode = code;
|
|
464
|
+
} catch (e) {
|
|
465
|
+
reportCliError(e);
|
|
466
|
+
process.exitCode = e?.exitCode || 1;
|
|
467
|
+
}
|
|
457
468
|
} else if (command === 'machine') {
|
|
458
469
|
try {
|
|
459
470
|
const code = await runMachine(rest);
|
|
@@ -493,6 +504,14 @@ if (command === '--version' || command === '-v') {
|
|
|
493
504
|
reportCliError(e);
|
|
494
505
|
process.exit(1);
|
|
495
506
|
}
|
|
507
|
+
} else if (command === 'hooks' || command === 'hook') {
|
|
508
|
+
try {
|
|
509
|
+
const code = await runHooks(rest);
|
|
510
|
+
if (typeof code === 'number' && code !== 0) process.exitCode = code;
|
|
511
|
+
} catch (e) {
|
|
512
|
+
reportCliError(e);
|
|
513
|
+
process.exitCode = 1;
|
|
514
|
+
}
|
|
496
515
|
} else if (command === 'app' || command === 'apps') {
|
|
497
516
|
try {
|
|
498
517
|
await runApp(rest);
|
package/src/commands/app.js
CHANGED
|
@@ -365,6 +365,7 @@ export async function runApp(argv = [], options = {}) {
|
|
|
365
365
|
'agentsam app doctor <id>',
|
|
366
366
|
'agentsam app preview <id>',
|
|
367
367
|
'agentsam app scaffold <id> <dir>',
|
|
368
|
+
'agentsam app package <id> [--dry-run]',
|
|
368
369
|
'',
|
|
369
370
|
].join('\n'));
|
|
370
371
|
return;
|
|
@@ -424,6 +425,15 @@ export async function runApp(argv = [], options = {}) {
|
|
|
424
425
|
write(' app_id is stable product identity. Pass --app-id explicitly; no AGENTSAM_DEFAULT_APP.\n\n');
|
|
425
426
|
return { id: app.id, curl, command: npmCmd };
|
|
426
427
|
}
|
|
428
|
+
if (command === 'package') {
|
|
429
|
+
const dryRun = rest.includes('--dry-run') || !rest.includes('--write');
|
|
430
|
+
const packArgs = ['pack', ...(dryRun ? ['--dry-run', '--ignore-scripts'] : []), '--json'];
|
|
431
|
+
const result = spawnSync('npm', packArgs, { cwd: app.dir, encoding: 'utf8', env: process.env });
|
|
432
|
+
if (result.status !== 0) throw new Error(String(result.stderr || result.stdout || `npm pack failed for ${app.id}`).trim());
|
|
433
|
+
const metadata = JSON.parse(result.stdout)[0];
|
|
434
|
+
write(`${JSON.stringify({ app_id: app.id, package: metadata.name, version: metadata.version, filename: metadata.filename, size: metadata.size, dry_run: dryRun }, null, 2)}\n`);
|
|
435
|
+
return metadata;
|
|
436
|
+
}
|
|
427
437
|
if (command === 'doctor' || command === 'preview') {
|
|
428
438
|
runAppBin(app, [command, ...rest], options);
|
|
429
439
|
return;
|
|
@@ -75,6 +75,7 @@ const GROUPS = Object.freeze([
|
|
|
75
75
|
label: 'AI',
|
|
76
76
|
commands: [
|
|
77
77
|
['models', 'Hosted + local model probes'],
|
|
78
|
+
['hooks', 'Lifecycle sources, dispatch order, and receipts'],
|
|
78
79
|
['skills', 'Portable skill vocabulary'],
|
|
79
80
|
['context', 'Context economics + git bridge'],
|
|
80
81
|
['usage / session', 'Spend and resume receipts'],
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { createLocalEngineRegistry } from '../local-engine/index.js';
|
|
3
|
+
import { auditLocalCompute } from '../local-engine/audit.js';
|
|
4
|
+
import { auditAssets } from '../local-engine/assets.js';
|
|
5
|
+
import { benchmarkEngine } from '../local-engine/benchmark.js';
|
|
6
|
+
|
|
7
|
+
function parse(argv = []) { const out = { action: argv[0] || 'status', engine: null, model: null, json: argv.includes('--json'), runs: 1, cwd: process.cwd() }; for (let i = 1; i < argv.length; i += 1) { const arg = argv[i]; if (arg === '--model') out.model = argv[++i]; else if (arg === '--runs') out.runs = Number(argv[++i]) || 1; else if (arg === '--cwd') out.cwd = path.resolve(argv[++i] || out.cwd); else if (arg === '--engine') out.engine = argv[++i]; } return out; }
|
|
8
|
+
function emit(value, json) { if (json) console.log(JSON.stringify(value)); else console.log(JSON.stringify(value, null, 2)); }
|
|
9
|
+
function usage() { return `agentsam engine <status|audit|benchmark|assets> [options]\n\n status Discover local engines and models\n audit Read-only Apple hardware + engine inventory\n benchmark Measure a selected engine/model\n assets audit Audit adopted model references without copying weights\n\n --engine <id> ollama | mlx-lm | llama.cpp\n --model <id> Engine model identifier\n --runs <n> Benchmark repetitions (default 1)\n --cwd <path> Project context\n --json Machine-readable output\n`; }
|
|
10
|
+
export async function runEngine(argv = []) { const args = parse(argv); if (args.action === '--help' || args.action === 'help') { console.log(usage()); return 0; } const registry = createLocalEngineRegistry(); if (args.action === 'status') { emit({ schema_version: 'agentsam.local-engine.v1', engines: await registry.discover() }, args.json); return 0; } if (args.action === 'audit') { emit(auditLocalCompute(), args.json); return 0; } if (args.action === 'assets' && argv[1] === 'audit') { emit(auditAssets(), args.json); return 0; } if (args.action === 'benchmark') { if (!args.engine || !args.model) throw new Error('engine benchmark requires --engine <id> and --model <id>'); const result = await benchmarkEngine(registry.get(args.engine), { model: args.model, runs: args.runs }); emit(result, args.json); return 0; } console.log(usage()); return 1; }
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
HOOK_CONFIG_SCHEMA,
|
|
5
|
+
createHookRuntime,
|
|
6
|
+
createHookRuntimeFromConfig,
|
|
7
|
+
findHookConfig,
|
|
8
|
+
loadHookConfig,
|
|
9
|
+
registerStoredHooks,
|
|
10
|
+
} from '../../packages/agentsam-hooks/src/index.js';
|
|
11
|
+
import { findCliProjectRoot } from '../lib/cli-preferences.js';
|
|
12
|
+
import { readAccountSession } from '../lib/account-session.js';
|
|
13
|
+
import {
|
|
14
|
+
listRuntimeHooks,
|
|
15
|
+
listRuntimeHookExecutions,
|
|
16
|
+
recordRuntimeHookReceipt,
|
|
17
|
+
setRuntimeHookActive,
|
|
18
|
+
} from '../local/runtime-store.js';
|
|
19
|
+
|
|
20
|
+
function clean(value) { return value == null ? '' : String(value).trim(); }
|
|
21
|
+
function writeLine(write, value = '') { write(`${value}\n`); }
|
|
22
|
+
function countConfigured(config) {
|
|
23
|
+
return Object.values(config?.hooks || {}).reduce((sum, rows) => sum + rows.length, 0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function registerCodeHooks(runtime, hooks = {}) {
|
|
27
|
+
for (const [event, definitions] of Object.entries(hooks || {})) {
|
|
28
|
+
for (const definition of Array.isArray(definitions) ? definitions : [definitions]) {
|
|
29
|
+
if (typeof definition === 'function') {
|
|
30
|
+
runtime.register(event, { handler: definition, metadata: { hook_source: 'code' } });
|
|
31
|
+
} else {
|
|
32
|
+
runtime.register(event, {
|
|
33
|
+
...definition,
|
|
34
|
+
metadata: { ...(definition?.metadata || {}), hook_source: 'code' },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve code, project config, and stored definitions into one ordered runtime.
|
|
43
|
+
* The source changes authoring/ownership only; dispatch semantics stay identical.
|
|
44
|
+
*/
|
|
45
|
+
export async function createProjectHookRuntime(options = {}) {
|
|
46
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
47
|
+
const projectRoot = path.resolve(options.projectRoot || findCliProjectRoot(cwd));
|
|
48
|
+
const accountId = clean(options.ownerId || readAccountSession({ home: options.home })?.account_id) || 'local';
|
|
49
|
+
const sourceByHook = new Map();
|
|
50
|
+
const persistReceipts = options.persistReceipts !== false;
|
|
51
|
+
const runtime = createHookRuntime({
|
|
52
|
+
clock: options.clock,
|
|
53
|
+
async onReceipt(receipt) {
|
|
54
|
+
const definition = sourceByHook.get(`${receipt.hook}:${receipt.hook_id}`) || { source: 'code', stored_hook_id: null };
|
|
55
|
+
if (persistReceipts) {
|
|
56
|
+
await recordRuntimeHookReceipt({
|
|
57
|
+
projectRoot,
|
|
58
|
+
owner_id: accountId,
|
|
59
|
+
receipt,
|
|
60
|
+
source_kind: definition.source,
|
|
61
|
+
hook_id: definition.stored_hook_id,
|
|
62
|
+
session_id: options.sessionId,
|
|
63
|
+
conversation_id: options.conversationId,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (typeof options.onReceipt === 'function') await options.onReceipt(receipt);
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
registerCodeHooks(runtime, options.hooks);
|
|
71
|
+
const configFile = options.configFile || findHookConfig(cwd, { stopAt: projectRoot });
|
|
72
|
+
let config = null;
|
|
73
|
+
if (configFile) {
|
|
74
|
+
({ config } = createHookRuntimeFromConfig(configFile, {
|
|
75
|
+
runtime,
|
|
76
|
+
cwd,
|
|
77
|
+
env: options.env,
|
|
78
|
+
fetchImpl: options.fetchImpl,
|
|
79
|
+
restrictCommandCwd: options.restrictCommandCwd,
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const stored = await registerStoredHooks(runtime, {
|
|
84
|
+
listHooks: (query) => listRuntimeHooks({
|
|
85
|
+
projectRoot,
|
|
86
|
+
owner_id: accountId,
|
|
87
|
+
...query,
|
|
88
|
+
}),
|
|
89
|
+
}, {
|
|
90
|
+
cwd: projectRoot,
|
|
91
|
+
env: options.env,
|
|
92
|
+
fetchImpl: options.fetchImpl,
|
|
93
|
+
restrictCommandCwd: options.restrictCommandCwd,
|
|
94
|
+
resolveHandler: options.resolveHandler,
|
|
95
|
+
context: {
|
|
96
|
+
owner_id: accountId,
|
|
97
|
+
account_id: accountId,
|
|
98
|
+
project_id: options.projectId,
|
|
99
|
+
project_root: projectRoot,
|
|
100
|
+
repository_id: options.repositoryId,
|
|
101
|
+
session_id: options.sessionId,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
for (const definition of runtime.list()) {
|
|
106
|
+
sourceByHook.set(`${definition.hook}:${definition.id}`, {
|
|
107
|
+
source: clean(definition.metadata?.hook_source) || (definition.metadata?.stored_hook_id ? 'stored' : definition.metadata?.config_source ? 'config' : 'code'),
|
|
108
|
+
stored_hook_id: clean(definition.metadata?.stored_hook_id) || null,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return Object.freeze({
|
|
112
|
+
runtime,
|
|
113
|
+
owner_id: accountId,
|
|
114
|
+
project_root: projectRoot,
|
|
115
|
+
config,
|
|
116
|
+
config_file: configFile || null,
|
|
117
|
+
stored,
|
|
118
|
+
definitions: runtime.list(),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hookTemplate() {
|
|
123
|
+
return {
|
|
124
|
+
schema: HOOK_CONFIG_SCHEMA,
|
|
125
|
+
adapters: {},
|
|
126
|
+
hooks: {},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function parseLimit(argv, fallback = 30) {
|
|
131
|
+
const index = argv.indexOf('--limit');
|
|
132
|
+
if (index === -1) return fallback;
|
|
133
|
+
const value = Number(argv[index + 1]);
|
|
134
|
+
if (!Number.isInteger(value) || value < 1 || value > 500) throw new Error('hooks_limit_must_be_between_1_and_500');
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function renderHookRows(rows, write) {
|
|
139
|
+
if (!rows.length) {
|
|
140
|
+
writeLine(write, ' No hooks configured. Run `agentsam hooks init` or add a stored hook.');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
for (const row of rows) {
|
|
144
|
+
const source = clean(row.metadata?.hook_source || row.source_kind) || 'code';
|
|
145
|
+
const state = row.enabled === false || row.is_active === false ? 'disabled' : 'active';
|
|
146
|
+
const handler = clean(row.handler_type || row.metadata?.adapter) || 'callback';
|
|
147
|
+
writeLine(write, ` ${String(row.hook || row.event_type).padEnd(25)} ${String(row.id || row.hook_key).padEnd(28)} ${source.padEnd(7)} ${handler.padEnd(10)} ${state} · p${row.priority ?? 100}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function runHooks(argv = [], options = {}) {
|
|
152
|
+
const write = options.write || ((text) => process.stdout.write(text));
|
|
153
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
154
|
+
const projectRoot = findCliProjectRoot(cwd);
|
|
155
|
+
const jsonOutput = argv.includes('--json');
|
|
156
|
+
const command = argv.find((arg) => !arg.startsWith('-')) || 'status';
|
|
157
|
+
if (argv.includes('--help') || argv.includes('-h') || command === 'help') {
|
|
158
|
+
write([
|
|
159
|
+
'agentsam hooks [status|list|executions|validate|init|enable|disable] [--json]',
|
|
160
|
+
'',
|
|
161
|
+
'One hook concept, three authoring sources: code, project config, and stored rows.',
|
|
162
|
+
' status Show active sources and execution evidence',
|
|
163
|
+
' list Show the merged dispatch order with source badges',
|
|
164
|
+
' executions [--limit N] Show recent value-free receipts',
|
|
165
|
+
' validate [config] Validate a portable hook config',
|
|
166
|
+
' init Create .agentsam/hooks.json (idempotent)',
|
|
167
|
+
' enable|disable <key> Toggle a stored hook without editing code/config',
|
|
168
|
+
'',
|
|
169
|
+
].join('\n'));
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (command === 'init') {
|
|
174
|
+
const filename = path.join(projectRoot, '.agentsam', 'hooks.json');
|
|
175
|
+
fs.mkdirSync(path.dirname(filename), { recursive: true });
|
|
176
|
+
const created = !fs.existsSync(filename);
|
|
177
|
+
if (created) fs.writeFileSync(filename, `${JSON.stringify(hookTemplate(), null, 2)}\n`, { mode: 0o600 });
|
|
178
|
+
const loaded = loadHookConfig(filename);
|
|
179
|
+
const result = { ok: true, created, source: filename, schema: loaded.schema };
|
|
180
|
+
if (jsonOutput) writeLine(write, JSON.stringify(result, null, 2));
|
|
181
|
+
else writeLine(write, ` Hooks config ready · ${filename}`);
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (command === 'validate') {
|
|
186
|
+
const commandIndex = argv.indexOf(command);
|
|
187
|
+
const candidate = argv.slice(commandIndex + 1).find((arg) => !arg.startsWith('-'));
|
|
188
|
+
const filename = candidate || findHookConfig(cwd, { stopAt: projectRoot });
|
|
189
|
+
if (!filename) throw new Error('agentsam_hook_config_not_found');
|
|
190
|
+
const config = loadHookConfig(filename);
|
|
191
|
+
const result = { ok: true, schema: config.schema, source: config.source, adapters: Object.keys(config.adapters).length, hooks: countConfigured(config) };
|
|
192
|
+
if (jsonOutput) writeLine(write, JSON.stringify(result, null, 2));
|
|
193
|
+
else writeLine(write, ` Valid · ${result.hooks} hooks · ${result.adapters} adapters · ${result.source}`);
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const ownerId = clean(options.ownerId || readAccountSession({ home: options.home })?.account_id) || 'local';
|
|
198
|
+
if (command === 'enable' || command === 'disable') {
|
|
199
|
+
const key = argv[argv.indexOf(command) + 1];
|
|
200
|
+
if (!key || key.startsWith('-')) throw new Error(`hooks_${command}_requires_key`);
|
|
201
|
+
const changed = await setRuntimeHookActive({ projectRoot, owner_id: ownerId, hook_key: key, active: command === 'enable' });
|
|
202
|
+
if (!changed) throw new Error(`stored_hook_not_found:${key}`);
|
|
203
|
+
const result = { ok: true, hook_key: key, active: command === 'enable' };
|
|
204
|
+
if (jsonOutput) writeLine(write, JSON.stringify(result, null, 2));
|
|
205
|
+
else writeLine(write, ` ${key} → ${result.active ? 'enabled' : 'disabled'}`);
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (command === 'executions') {
|
|
210
|
+
const executions = await listRuntimeHookExecutions({ projectRoot, owner_id: ownerId, limit: parseLimit(argv) });
|
|
211
|
+
if (jsonOutput) writeLine(write, JSON.stringify({ schema: 'agentsam.hook.executions.v1', executions }, null, 2));
|
|
212
|
+
else {
|
|
213
|
+
writeLine(write, '\n Recent hook executions');
|
|
214
|
+
if (!executions.length) writeLine(write, ' No hook receipts recorded yet.');
|
|
215
|
+
for (const row of executions) {
|
|
216
|
+
const at = new Date(Number(row.ran_at_unix) * 1000).toISOString();
|
|
217
|
+
writeLine(write, ` ${at} ${String(row.status).padEnd(9)} ${String(row.event_type).padEnd(24)} ${row.hook_key} · ${row.duration_ms}ms`);
|
|
218
|
+
}
|
|
219
|
+
writeLine(write);
|
|
220
|
+
}
|
|
221
|
+
return executions;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (!['status', 'list'].includes(command)) throw new Error(`unknown_hooks_command:${command}`);
|
|
225
|
+
const resolved = await createProjectHookRuntime({
|
|
226
|
+
cwd,
|
|
227
|
+
projectRoot,
|
|
228
|
+
ownerId,
|
|
229
|
+
home: options.home,
|
|
230
|
+
hooks: options.hooks,
|
|
231
|
+
persistReceipts: false,
|
|
232
|
+
});
|
|
233
|
+
const storedAll = await listRuntimeHooks({ projectRoot, owner_id: ownerId, activeOnly: false });
|
|
234
|
+
const result = {
|
|
235
|
+
schema: 'agentsam.hooks.status.v1',
|
|
236
|
+
project_root: projectRoot,
|
|
237
|
+
owner_id: ownerId,
|
|
238
|
+
config: resolved.config ? { source: resolved.config_file, hooks: countConfigured(resolved.config), adapters: Object.keys(resolved.config.adapters).length } : null,
|
|
239
|
+
sources: {
|
|
240
|
+
code: resolved.definitions.filter((row) => row.metadata?.hook_source === 'code').length,
|
|
241
|
+
config: resolved.definitions.filter((row) => row.metadata?.hook_source === 'config').length,
|
|
242
|
+
stored_active: resolved.definitions.filter((row) => row.metadata?.hook_source === 'stored').length,
|
|
243
|
+
stored_total: storedAll.length,
|
|
244
|
+
},
|
|
245
|
+
hooks: resolved.definitions,
|
|
246
|
+
};
|
|
247
|
+
if (jsonOutput) writeLine(write, JSON.stringify(result, null, 2));
|
|
248
|
+
else {
|
|
249
|
+
writeLine(write, '\n Agent Sam · hooks');
|
|
250
|
+
writeLine(write, ' One ordered lifecycle contract · code is read-only · config/stored hooks are portable.');
|
|
251
|
+
writeLine(write, ` project ${projectRoot}`);
|
|
252
|
+
writeLine(write, ` config ${result.config ? `${result.config.hooks} hooks · ${result.config.source}` : 'not configured'}`);
|
|
253
|
+
writeLine(write, ` stored ${result.sources.stored_active} active · ${result.sources.stored_total} total`);
|
|
254
|
+
writeLine(write, '');
|
|
255
|
+
if (command === 'list') renderHookRows([...resolved.definitions, ...storedAll.filter((row) => !row.is_active)], write);
|
|
256
|
+
else writeLine(write, ' Use `agentsam hooks list` for dispatch order and `agentsam hooks executions` for receipts.');
|
|
257
|
+
writeLine(write);
|
|
258
|
+
}
|
|
259
|
+
return result;
|
|
260
|
+
}
|