vgxness 0.1.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/LICENSE +9 -0
- package/README.md +110 -0
- package/dist/agents/agent-activation-service.js +144 -0
- package/dist/agents/agent-registry-service.js +46 -0
- package/dist/agents/agent-resolver.js +249 -0
- package/dist/agents/agent-seed-service.js +146 -0
- package/dist/agents/manager-profile-overlay-service.js +34 -0
- package/dist/agents/profile-model-routing.js +26 -0
- package/dist/agents/renderers/claude-renderer.js +98 -0
- package/dist/agents/renderers/index.js +16 -0
- package/dist/agents/renderers/json-renderer.js +87 -0
- package/dist/agents/renderers/opencode-renderer.js +100 -0
- package/dist/agents/renderers/provider-adapter.js +6 -0
- package/dist/agents/repositories/agents.js +185 -0
- package/dist/agents/repositories/manager-profile-overlays.js +81 -0
- package/dist/agents/schema.js +1 -0
- package/dist/cli/dashboard-operational-read-models.js +153 -0
- package/dist/cli/dashboard-renderer.js +109 -0
- package/dist/cli/dashboard-screen-renderers.js +332 -0
- package/dist/cli/dashboard-tui-read-model.js +71 -0
- package/dist/cli/dashboard-tui-state.js +218 -0
- package/dist/cli/dispatcher.js +2880 -0
- package/dist/cli/index.js +27 -0
- package/dist/cli/interactive-dashboard.js +29 -0
- package/dist/cli/mcp-start-path.js +21 -0
- package/dist/cli/setup-status-renderer.js +29 -0
- package/dist/cli/setup-wizard-read-model.js +56 -0
- package/dist/cli/setup-wizard-renderer.js +148 -0
- package/dist/cli/setup-wizard-state.js +82 -0
- package/dist/cli/tui-render-helpers.js +192 -0
- package/dist/export/redaction.js +71 -0
- package/dist/harness/tools/agents.js +245 -0
- package/dist/harness/tools/memory.js +29 -0
- package/dist/mcp/client-install-opencode-contract.js +227 -0
- package/dist/mcp/client-install-opencode.js +194 -0
- package/dist/mcp/client-setup-preview.js +38 -0
- package/dist/mcp/control-plane.js +175 -0
- package/dist/mcp/doctor.js +193 -0
- package/dist/mcp/index.js +10 -0
- package/dist/mcp/opencode-default-agent-config.js +156 -0
- package/dist/mcp/opencode-visibility.js +102 -0
- package/dist/mcp/schema.js +234 -0
- package/dist/mcp/stdio-server.js +56 -0
- package/dist/mcp/validation.js +761 -0
- package/dist/memory/import/dry-run-planner.js +58 -0
- package/dist/memory/import/index.js +3 -0
- package/dist/memory/import/observation-writer.js +220 -0
- package/dist/memory/import/package.js +178 -0
- package/dist/memory/memory-service.js +126 -0
- package/dist/memory/repositories/artifacts.js +41 -0
- package/dist/memory/repositories/observations.js +133 -0
- package/dist/memory/repositories/sessions.js +105 -0
- package/dist/memory/repositories/traces.js +58 -0
- package/dist/memory/schema.js +1 -0
- package/dist/memory/search.js +11 -0
- package/dist/memory/sqlite/database.js +97 -0
- package/dist/memory/sqlite/migrations/001_initial.sql +128 -0
- package/dist/memory/sqlite/migrations/002_observation_revisions.sql +14 -0
- package/dist/memory/sqlite/migrations/003_agent_registry.sql +26 -0
- package/dist/memory/sqlite/migrations/004_run_runtime.sql +62 -0
- package/dist/memory/sqlite/migrations/005_run_approvals.sql +20 -0
- package/dist/memory/sqlite/migrations/006_run_operation_attempts.sql +32 -0
- package/dist/memory/sqlite/migrations/007_abandoned_operation_attempts.sql +46 -0
- package/dist/memory/sqlite/migrations/008_run_execution_plan_events.sql +105 -0
- package/dist/memory/sqlite/migrations/009_multiple_operation_attempts.sql +73 -0
- package/dist/memory/sqlite/migrations/010_skill_registry.sql +66 -0
- package/dist/memory/sqlite/migrations/011_skill_usage_resolution_outcomes.sql +21 -0
- package/dist/memory/sqlite/migrations/012_skill_improvement_proposals.sql +37 -0
- package/dist/memory/sqlite/migrations/013_skill_evaluation_scenarios.sql +43 -0
- package/dist/memory/sqlite/migrations/014_manager_profile_overlays.sql +14 -0
- package/dist/memory/storage-paths.js +72 -0
- package/dist/orchestrator/natural-language-planner.js +191 -0
- package/dist/orchestrator/schema.js +1 -0
- package/dist/permissions/index.js +2 -0
- package/dist/permissions/policy-evaluator.js +109 -0
- package/dist/permissions/schema.js +1 -0
- package/dist/providers/opencode/injection-preview.js +134 -0
- package/dist/providers/opencode/manager-payload.js +129 -0
- package/dist/runs/execution-planning.js +117 -0
- package/dist/runs/operation-execution.js +1 -0
- package/dist/runs/operation-retry.js +124 -0
- package/dist/runs/repositories/runs.js +611 -0
- package/dist/runs/run-insights.js +145 -0
- package/dist/runs/run-service.js +713 -0
- package/dist/runs/run-snapshot-export-service.js +31 -0
- package/dist/runs/sandbox-process-execution.js +218 -0
- package/dist/runs/sandbox-worktree-planning.js +59 -0
- package/dist/runs/schema.js +1 -0
- package/dist/sdd/artifact-portability-service.js +118 -0
- package/dist/sdd/schema.js +17 -0
- package/dist/sdd/sdd-workflow-service.js +217 -0
- package/dist/setup/backup-rollback-service.js +76 -0
- package/dist/setup/index.js +3 -0
- package/dist/setup/providers/antigravity-setup-adapter.js +18 -0
- package/dist/setup/providers/claude-setup-adapter.js +30 -0
- package/dist/setup/providers/custom-setup-adapter.js +18 -0
- package/dist/setup/providers/index.js +6 -0
- package/dist/setup/providers/opencode-setup-adapter.js +104 -0
- package/dist/setup/providers/provider-setup-adapter.js +15 -0
- package/dist/setup/providers/provider-setup-registry.js +11 -0
- package/dist/setup/schema.js +1 -0
- package/dist/setup/setup-defaults.js +11 -0
- package/dist/setup/setup-lifecycle-service.js +175 -0
- package/dist/setup/setup-plan.js +105 -0
- package/dist/skills/repositories/skill-evaluation-scenarios.js +289 -0
- package/dist/skills/repositories/skill-improvement-proposals.js +288 -0
- package/dist/skills/repositories/skills.js +430 -0
- package/dist/skills/schema.js +1 -0
- package/dist/skills/skill-payload.js +94 -0
- package/dist/skills/skill-registry-service.js +92 -0
- package/dist/skills/skill-resolver.js +191 -0
- package/dist/workflows/command-allowlist-adapter.js +70 -0
- package/dist/workflows/schema.js +4 -0
- package/dist/workflows/workflow-executor.js +345 -0
- package/dist/workflows/workflow-registry.js +66 -0
- package/docs/architecture.md +698 -0
- package/docs/cli.md +741 -0
- package/docs/funcionamiento-del-sistema.md +868 -0
- package/docs/harness-gap-analysis.md +229 -0
- package/docs/prd.md +372 -0
- package/package.json +57 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { planWorktreeSandbox } from './sandbox-worktree-planning.js';
|
|
4
|
+
const filesystemCategories = new Set(['read', 'edit', 'external-directory']);
|
|
5
|
+
export function planExecutionIsolation(input) {
|
|
6
|
+
const { operation, decision } = input;
|
|
7
|
+
const strategy = selectStrategy(operation, decision);
|
|
8
|
+
const sandbox = worktreeSandboxPlan(operation, strategy, input.gitBoundaryInspector);
|
|
9
|
+
const realpathHardeningRequired = requiresRealpathHardening(operation);
|
|
10
|
+
const requiredApprovals = approvalRequirements(operation, decision);
|
|
11
|
+
const requiredConditions = conditionRequirements(operation, decision, realpathHardeningRequired, sandbox);
|
|
12
|
+
const limitations = planLimitations(operation, decision, strategy, sandbox);
|
|
13
|
+
return {
|
|
14
|
+
strategy,
|
|
15
|
+
pathConstraints: pathConstraints(operation),
|
|
16
|
+
...(sandbox === undefined ? {} : { sandbox }),
|
|
17
|
+
realpathHardeningRequired,
|
|
18
|
+
requiredApprovals,
|
|
19
|
+
requiredConditions,
|
|
20
|
+
limitations,
|
|
21
|
+
executable: decision.decision === 'allow' && sandbox?.decision !== 'rejected',
|
|
22
|
+
executesProvider: false,
|
|
23
|
+
createsWorktree: false,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function selectStrategy(operation, decision) {
|
|
27
|
+
if (operation.sandboxStrategy === 'worktree')
|
|
28
|
+
return 'worktree';
|
|
29
|
+
if (decision.decision === 'deny') {
|
|
30
|
+
return operation.category === 'external-directory' || operation.external === true
|
|
31
|
+
? 'process-sandbox'
|
|
32
|
+
: 'workspace';
|
|
33
|
+
}
|
|
34
|
+
if (operation.category === 'shell' || operation.category === 'network' || operation.category === 'provider-tool' || operation.privileged === true) {
|
|
35
|
+
return 'process-sandbox';
|
|
36
|
+
}
|
|
37
|
+
if (operation.category === 'edit' || operation.category === 'git' || operation.destructive === true) {
|
|
38
|
+
return 'worktree';
|
|
39
|
+
}
|
|
40
|
+
return 'workspace';
|
|
41
|
+
}
|
|
42
|
+
function pathConstraints(operation) {
|
|
43
|
+
return {
|
|
44
|
+
...(operation.workspaceRoot === undefined ? {} : { workspaceRoot: operation.workspaceRoot }),
|
|
45
|
+
...(operation.targetPath === undefined ? {} : { targetPath: operation.targetPath }),
|
|
46
|
+
enforceWorkspaceBoundary: operation.category !== 'external-directory',
|
|
47
|
+
allowExternalPaths: false,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function requiresRealpathHardening(operation) {
|
|
51
|
+
return filesystemCategories.has(operation.category)
|
|
52
|
+
|| operation.workspaceRoot !== undefined
|
|
53
|
+
|| operation.targetPath !== undefined;
|
|
54
|
+
}
|
|
55
|
+
function approvalRequirements(operation, decision) {
|
|
56
|
+
const approvals = [];
|
|
57
|
+
if (decision.decision === 'ask')
|
|
58
|
+
approvals.push(`human-approval:${decision.reason}`);
|
|
59
|
+
if (operation.destructive === true)
|
|
60
|
+
approvals.push('destructive-operation-approval');
|
|
61
|
+
if (operation.external === true || operation.category === 'external-directory')
|
|
62
|
+
approvals.push('external-access-approval');
|
|
63
|
+
if (operation.privileged === true)
|
|
64
|
+
approvals.push('privileged-operation-approval');
|
|
65
|
+
if (operation.ambiguous === true)
|
|
66
|
+
approvals.push('clarify-ambiguous-operation');
|
|
67
|
+
return [...new Set(approvals)];
|
|
68
|
+
}
|
|
69
|
+
function conditionRequirements(operation, decision, realpathHardeningRequired, sandbox) {
|
|
70
|
+
const conditions = ['permission-decision-recorded'];
|
|
71
|
+
if (decision.decision === 'deny')
|
|
72
|
+
conditions.push('blocked-by-policy-before-execution');
|
|
73
|
+
if (sandbox?.decision === 'rejected')
|
|
74
|
+
conditions.push(`blocked-by-sandbox-planning:${sandbox.reason ?? 'unknown'}`);
|
|
75
|
+
if (decision.decision === 'ask')
|
|
76
|
+
conditions.push('approved-before-execution');
|
|
77
|
+
if (realpathHardeningRequired)
|
|
78
|
+
conditions.push('resolve-realpath-and-recheck-workspace-boundary-before-execution');
|
|
79
|
+
if (operation.category === 'edit' || operation.category === 'git' || operation.destructive === true)
|
|
80
|
+
conditions.push('isolated-worktree-or-equivalent-before-mutation');
|
|
81
|
+
if (operation.category === 'shell' || operation.category === 'network' || operation.category === 'provider-tool')
|
|
82
|
+
conditions.push('sandboxed-process-or-equivalent-before-provider-execution');
|
|
83
|
+
return conditions;
|
|
84
|
+
}
|
|
85
|
+
function planLimitations(operation, decision, strategy, sandbox) {
|
|
86
|
+
const limitations = [
|
|
87
|
+
'planning-only: no command, provider tool, worktree, sandbox, directory, or filesystem mutation is performed',
|
|
88
|
+
];
|
|
89
|
+
if (strategy === 'worktree')
|
|
90
|
+
limitations.push('worktree is a planned isolation target only; creation is future executor work');
|
|
91
|
+
if (strategy === 'process-sandbox')
|
|
92
|
+
limitations.push('process-sandbox is a planned isolation target only; launch/enforcement is future executor work');
|
|
93
|
+
if (decision.decision === 'deny')
|
|
94
|
+
limitations.push(`permission policy denies execution: ${decision.reason}`);
|
|
95
|
+
if (sandbox?.decision === 'rejected')
|
|
96
|
+
limitations.push(`sandbox planning rejects execution: ${sandbox.audit.validationSummary}`);
|
|
97
|
+
if (operation.category === 'external-directory')
|
|
98
|
+
limitations.push('external directory execution remains denied by default even when a stronger future sandbox is selected');
|
|
99
|
+
return limitations;
|
|
100
|
+
}
|
|
101
|
+
function worktreeSandboxPlan(operation, strategy, gitBoundaryInspector) {
|
|
102
|
+
if (strategy !== 'worktree')
|
|
103
|
+
return undefined;
|
|
104
|
+
if (operation.workspaceRoot === undefined || operation.targetPath === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
return planWorktreeSandbox({
|
|
107
|
+
workspaceRoot: operation.workspaceRoot,
|
|
108
|
+
targetPath: operation.targetPath,
|
|
109
|
+
gitBoundaryInspector: gitBoundaryInspector ?? defaultGitBoundaryInspector,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const defaultGitBoundaryInspector = ({ workspaceRoot }) => {
|
|
113
|
+
if (existsSync(join(workspaceRoot, '.git'))) {
|
|
114
|
+
return { status: 'compatible', reason: 'workspace git metadata is present' };
|
|
115
|
+
}
|
|
116
|
+
return { status: 'uncertain', reason: 'workspace git metadata could not be proven safe without shell execution' };
|
|
117
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const defaultRetryPolicy = { mode: 'never' };
|
|
2
|
+
const operationRetryPolicyModes = ['never', 'after-abandoned', 'after-failure', 'after-failure-or-abandoned'];
|
|
3
|
+
const allowedRetryableStatuses = ['failed', 'abandoned'];
|
|
4
|
+
export function defaultOperationRetryPolicy() {
|
|
5
|
+
return defaultRetryPolicy;
|
|
6
|
+
}
|
|
7
|
+
export function parseOperationRetryPolicy(input) {
|
|
8
|
+
if (input === undefined) {
|
|
9
|
+
return { ok: true, policy: defaultRetryPolicy };
|
|
10
|
+
}
|
|
11
|
+
if (!isRecord(input) || Array.isArray(input)) {
|
|
12
|
+
return { ok: false, errors: ['Retry policy must be an object'] };
|
|
13
|
+
}
|
|
14
|
+
const allowedKeys = new Set(['mode', 'retryableStatuses']);
|
|
15
|
+
const unknownKeys = Object.keys(input).filter((key) => !allowedKeys.has(key));
|
|
16
|
+
const errors = unknownKeys.map((key) => `Unknown retry policy field: ${key}`);
|
|
17
|
+
const mode = input.mode;
|
|
18
|
+
if (!isOperationRetryPolicyMode(mode)) {
|
|
19
|
+
errors.push('Retry policy mode must be one of: never, after-abandoned, after-failure, after-failure-or-abandoned');
|
|
20
|
+
}
|
|
21
|
+
if ('retryableStatuses' in input) {
|
|
22
|
+
const retryableStatuses = input.retryableStatuses;
|
|
23
|
+
if (!Array.isArray(retryableStatuses)) {
|
|
24
|
+
errors.push('Retry policy retryableStatuses must be an array');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const invalidStatuses = retryableStatuses.filter((status) => !isAllowedRetryableStatus(status));
|
|
28
|
+
if (invalidStatuses.length > 0) {
|
|
29
|
+
errors.push(`Retry policy retryableStatuses contains invalid retryable status: ${invalidStatuses.map(String).join(', ')}`);
|
|
30
|
+
}
|
|
31
|
+
if (new Set(retryableStatuses).size !== retryableStatuses.length) {
|
|
32
|
+
errors.push('Retry policy retryableStatuses must not contain duplicates');
|
|
33
|
+
}
|
|
34
|
+
if (isOperationRetryPolicyMode(mode) && invalidStatuses.length === 0) {
|
|
35
|
+
const expectedStatuses = retryableStatusesFor({ mode });
|
|
36
|
+
if (!sameStatuses(retryableStatuses, expectedStatuses)) {
|
|
37
|
+
errors.push(`Retry policy retryableStatuses must match mode ${mode}: ${expectedStatuses.length === 0 ? '[]' : expectedStatuses.join(', ')}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (errors.length > 0 || !isOperationRetryPolicyMode(mode)) {
|
|
43
|
+
return { ok: false, errors };
|
|
44
|
+
}
|
|
45
|
+
return { ok: true, policy: { mode } };
|
|
46
|
+
}
|
|
47
|
+
export function evaluateOperationRetry(input) {
|
|
48
|
+
const policy = input.policy ?? defaultRetryPolicy;
|
|
49
|
+
const retryableStatuses = retryableStatusesFor(policy);
|
|
50
|
+
const attempts = [...input.attempts].sort(compareAttempts);
|
|
51
|
+
const activeAttempt = attempts.find((attempt) => attempt.status === 'reserved');
|
|
52
|
+
if (activeAttempt !== undefined) {
|
|
53
|
+
const latestAttempt = attempts.at(-1);
|
|
54
|
+
return {
|
|
55
|
+
allowed: false,
|
|
56
|
+
policy,
|
|
57
|
+
reasonCode: 'active_attempt_reserved',
|
|
58
|
+
reason: `Retry blocked because attempt ${activeAttempt.id} is still reserved`,
|
|
59
|
+
evaluatedAttemptCount: attempts.length,
|
|
60
|
+
retryableStatuses,
|
|
61
|
+
activeAttempt,
|
|
62
|
+
...(latestAttempt === undefined ? {} : { latestAttempt }),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const latestAttempt = attempts.at(-1);
|
|
66
|
+
if (latestAttempt === undefined) {
|
|
67
|
+
return {
|
|
68
|
+
allowed: true,
|
|
69
|
+
policy,
|
|
70
|
+
reasonCode: 'initial_attempt_allowed',
|
|
71
|
+
reason: 'No previous operation attempt exists for this approval',
|
|
72
|
+
evaluatedAttemptCount: 0,
|
|
73
|
+
retryableStatuses,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (latestAttempt.status === 'succeeded') {
|
|
77
|
+
return block(policy, retryableStatuses, attempts.length, latestAttempt, 'already_succeeded', `Retry blocked because latest attempt ${latestAttempt.id} already succeeded`);
|
|
78
|
+
}
|
|
79
|
+
if (policy.mode === 'never') {
|
|
80
|
+
return block(policy, retryableStatuses, attempts.length, latestAttempt, 'retry_disabled', `Retry blocked by policy never after ${latestAttempt.status}`);
|
|
81
|
+
}
|
|
82
|
+
if (retryableStatuses.includes(latestAttempt.status)) {
|
|
83
|
+
return {
|
|
84
|
+
allowed: true,
|
|
85
|
+
policy,
|
|
86
|
+
reasonCode: 'status_allowed_by_policy',
|
|
87
|
+
reason: `Retry allowed by policy ${policy.mode} after ${latestAttempt.status}`,
|
|
88
|
+
evaluatedAttemptCount: attempts.length,
|
|
89
|
+
retryableStatuses,
|
|
90
|
+
latestAttempt,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return block(policy, retryableStatuses, attempts.length, latestAttempt, 'status_not_allowed_by_policy', `Retry blocked by policy ${policy.mode} after ${latestAttempt.status}`);
|
|
94
|
+
}
|
|
95
|
+
function block(policy, retryableStatuses, evaluatedAttemptCount, latestAttempt, reasonCode, reason) {
|
|
96
|
+
return { allowed: false, policy, reasonCode, reason, evaluatedAttemptCount, retryableStatuses, latestAttempt };
|
|
97
|
+
}
|
|
98
|
+
function retryableStatusesFor(policy) {
|
|
99
|
+
switch (policy.mode) {
|
|
100
|
+
case 'after-abandoned':
|
|
101
|
+
return ['abandoned'];
|
|
102
|
+
case 'after-failure':
|
|
103
|
+
return ['failed'];
|
|
104
|
+
case 'after-failure-or-abandoned':
|
|
105
|
+
return ['failed', 'abandoned'];
|
|
106
|
+
case 'never':
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function isRecord(value) {
|
|
111
|
+
return typeof value === 'object' && value !== null;
|
|
112
|
+
}
|
|
113
|
+
function isOperationRetryPolicyMode(value) {
|
|
114
|
+
return typeof value === 'string' && operationRetryPolicyModes.includes(value);
|
|
115
|
+
}
|
|
116
|
+
function isAllowedRetryableStatus(value) {
|
|
117
|
+
return typeof value === 'string' && allowedRetryableStatuses.includes(value);
|
|
118
|
+
}
|
|
119
|
+
function sameStatuses(actual, expected) {
|
|
120
|
+
return actual.length === expected.length && actual.every((status) => expected.includes(status));
|
|
121
|
+
}
|
|
122
|
+
function compareAttempts(a, b) {
|
|
123
|
+
return a.attemptSequence - b.attemptSequence || a.reservedAt.localeCompare(b.reservedAt) || a.id.localeCompare(b.id);
|
|
124
|
+
}
|