@inneranimalmedia/agentsam-sdk 2.6.3 → 2.6.4
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/AGENTSAM.md +6 -0
- package/README.md +16 -1
- package/bin/agentsam +16 -1
- package/docs/BRAND_INTELLIGENCE.md +1 -1
- package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
- package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
- package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
- package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
- package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
- package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +28 -0
- package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
- package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
- package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
- package/docs/architecture/SAM_KERNEL.md +181 -0
- package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
- package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
- package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
- package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
- package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
- package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
- package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
- package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
- package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
- package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
- package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
- package/migrations/d1/0013_identity_oauth_states.sql +15 -0
- package/migrations/d1/0014_auth_event_log.sql +20 -0
- package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
- package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
- package/package.json +19 -4
- package/packages/agentsam-contracts/src/errors.ts +16 -0
- package/packages/agentsam-errors/src/envelope.js +53 -0
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/recovery.js +301 -0
- package/packages/agentsam-knowledge/src/providers/index.js +18 -6
- package/packages/connectors/cloudflare/src/routes.js +9 -0
- package/packages/connectors/cloudflare/tests/connector.test.mjs +26 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +11 -2
- package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
- package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +31 -0
- package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
- package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
- package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
- package/packages/identity/package.json +2 -2
- package/packages/identity/src/adapters/cloudflare-d1/index.js +122 -22
- package/packages/identity/src/adapters/sqlite/index.js +319 -0
- package/packages/identity/src/app/verify-app.js +95 -0
- package/packages/identity/src/contracts/identity-store.js +115 -0
- package/packages/identity/src/contracts/route-ids.js +30 -0
- package/packages/identity/src/contracts/route-projection.js +218 -0
- package/packages/identity/src/contracts/routes.js +11 -0
- package/packages/identity/src/core/browser-paths.js +4 -5
- package/packages/identity/src/core/constants.js +13 -8
- package/packages/identity/src/core/session-policy.js +32 -0
- package/packages/identity/src/frontend/auth-portal/pages/login.html +10 -10
- package/packages/identity/src/frontend/auth-portal/pages/reset.html +3 -3
- package/packages/identity/src/frontend/auth-portal/pages/signup.html +3 -3
- package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
- package/packages/identity/src/index.js +25 -0
- package/packages/identity/src/oauth/README.md +10 -4
- package/packages/identity/src/oauth/credentials.js +20 -13
- package/packages/identity/src/oauth/finalize-inbound.js +1 -1
- package/packages/identity/src/oauth/iam-platform.js +8 -7
- package/packages/identity/src/oauth/redirect-paths.js +27 -36
- package/packages/identity/src/server/identity-service.js +30 -13
- package/packages/identity/src/server/mount-policy.js +30 -0
- package/packages/identity/src/server/post-auth.js +79 -0
- package/packages/identity/src/server/worker-router.js +104 -72
- package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
- package/packages/identity/tests/iam-provider.test.mjs +1 -1
- package/packages/identity/tests/identity-service.test.mjs +36 -5
- package/packages/identity/tests/oauth-credentials.test.mjs +3 -1
- package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
- package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
- package/packages/theme-church-site/package.json +2 -1
- package/packages/theme-church-site/src/index.js +1 -0
- package/packages/theme-companions-site/package.json +2 -1
- package/packages/theme-companions-site/src/index.js +1 -0
- package/packages/theme-floors-site/package.json +2 -1
- package/packages/theme-floors-site/src/index.js +1 -0
- package/packages/theme-fuelnfree-site/package.json +2 -1
- package/packages/theme-fuelnfree-site/src/index.js +1 -0
- package/packages/theme-handyman-site/package.json +2 -1
- package/packages/theme-handyman-site/src/index.js +1 -0
- package/packages/theme-insurance-site/package.json +2 -1
- package/packages/theme-insurance-site/src/index.js +1 -0
- package/packages/theme-shinshu-site/package.json +2 -1
- package/packages/theme-shinshu-site/src/index.js +1 -0
- package/protocol/apps/agentsam.app.v1.schema.json +51 -0
- package/protocol/brand/brandpack.v1.schema.json +43 -0
- package/protocol/credentials/issue.v1.schema.json +38 -0
- package/protocol/database/connection.v1.schema.json +41 -0
- package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
- package/protocol/errors/error-envelope.schema.json +135 -1
- package/protocol/errors/recovery.v1.schema.json +50 -0
- package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
- package/protocol/sam/activity.v1.schema.json +48 -0
- package/protocol/sam/answer.v1.schema.json +35 -0
- package/protocol/sam/calibration.v1.schema.json +21 -0
- package/protocol/sam/decision-receipt.v1.schema.json +29 -0
- package/protocol/sam/evaluation.v1.schema.json +19 -0
- package/protocol/sam/operation.schema.json +66 -0
- package/protocol/sam/outcome.v1.schema.json +36 -0
- package/protocol/sam/question.v1.schema.json +26 -0
- package/protocol/sam/registry.seed.json +153 -0
- package/protocol/sam/result.schema.json +53 -0
- package/protocol/sam/state.v1.schema.json +23 -0
- package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
- package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
- package/protocol/ui/icon-registry.mjs +226 -0
- package/protocol/ui/icon.v1.schema.json +51 -0
- package/skills/README.md +22 -9
- package/skills/agentsam-codebaseindex/SKILL.md +225 -0
- package/skills/catalog.json +14 -0
- package/src/cli/command-catalog.js +130 -0
- package/src/cli/dispatch.js +48 -0
- package/src/cli.js +43 -1
- package/src/commands/api-key.js +244 -0
- package/src/commands/app.js +60 -28
- package/src/commands/brand.js +17 -19
- package/src/commands/codebaseindex.js +688 -0
- package/src/commands/env.js +152 -25
- package/src/commands/go.js +366 -53
- package/src/commands/interaction-clack.js +115 -0
- package/src/commands/models.js +1 -1
- package/src/commands/providers.js +62 -14
- package/src/commands/shell.js +43 -2
- package/src/commands/skill.js +248 -0
- package/src/commands/skills.js +1 -1
- package/src/commands/start-local.js +4 -0
- package/src/commands/whoami.js +90 -18
- package/src/go/build.js +229 -39
- package/src/go/cloudflare.js +506 -105
- package/src/go/container.js +120 -0
- package/src/go/contract.js +9 -4
- package/src/go/discover.js +149 -33
- package/src/go/index.js +15 -3
- package/src/go/native-probe-runner.mjs +119 -0
- package/src/go/{registry.js → official-registry.js} +64 -7
- package/src/go/official-release.js +10 -0
- package/src/go/receipts.js +77 -10
- package/src/go/verify.js +9 -2
- package/src/index.js +27 -0
- package/src/indexing/ingest/discover-models.js +298 -0
- package/src/indexing/ingest/inventory.js +243 -0
- package/src/indexing/ingest/job-graph.js +181 -0
- package/src/indexing/ingest/materials.js +210 -0
- package/src/lib/provider-credentials.js +63 -21
- package/src/lib/slash-commands.js +1 -0
- package/src/local-fs/capability.js +121 -0
- package/src/local-fs/freshness.js +75 -0
- package/src/local-fs/index.js +385 -0
- package/src/local-fs/paths.js +100 -0
- package/src/local-pty/server.js +295 -19
- package/src/mcp/client.js +2 -2
- package/src/models/ai-access-onboarding.js +112 -0
- package/src/models/discovery.js +10 -2
- package/src/models/inventory-core.js +9 -1
- package/src/sam/activity/index.js +183 -0
- package/src/sam/client.js +252 -0
- package/src/sam/decision/calibration.js +109 -0
- package/src/sam/decision/confidence.js +126 -0
- package/src/sam/decision/evaluate.js +157 -0
- package/src/sam/decision/evaluators/deterministic.js +341 -0
- package/src/sam/decision/evaluators/heuristic.js +61 -0
- package/src/sam/decision/evaluators/select.js +50 -0
- package/src/sam/decision/evaluators/semantic.js +149 -0
- package/src/sam/decision/hierarchical.js +61 -0
- package/src/sam/decision/index.js +53 -0
- package/src/sam/decision/policy.js +86 -0
- package/src/sam/decision/questions.js +120 -0
- package/src/sam/decision/receipt.js +148 -0
- package/src/sam/decision/state.js +117 -0
- package/src/sam/decision/types.js +22 -0
- package/src/sam/decision/validate.js +200 -0
- package/src/sam/define.js +51 -0
- package/src/sam/index.js +65 -0
- package/src/sam/operations/brand-scan.js +62 -0
- package/src/sam/operations/cad-blender-inspect.js +36 -0
- package/src/sam/operations/codebaseindex-ingest.js +49 -0
- package/src/sam/operations/decision-evaluate.js +59 -0
- package/src/sam/operations/planning-astar.js +77 -0
- package/src/sam/operations/planning-goap.js +60 -0
- package/src/sam/operations/repository-inspect.js +72 -0
- package/src/sam/operations/security-scan.js +33 -0
- package/src/sam/operations/terminal-exec.js +29 -0
- package/src/sam/planning/astar.js +311 -0
- package/src/sam/planning/goap.js +177 -0
- package/src/sam/planning/index.js +21 -0
- package/src/sam/planning/state.js +84 -0
- package/src/sam/registry.js +48 -0
- package/src/sam/result.js +77 -0
- package/src/sam/seed.js +44 -0
- package/src/sam/types.js +91 -0
- package/src/skills/catalog.js +64 -0
- package/src/skills/content-resolver.js +124 -0
- package/src/skills/hosted-store.js +37 -0
- package/src/skills/index.js +29 -64
- package/src/skills/interaction.js +102 -0
- package/src/skills/local-store.js +228 -0
- package/src/skills/manifest.js +104 -0
- package/src/skills/metrics.js +31 -0
- package/src/skills/registry.js +184 -0
- package/src/skills/runtime.js +287 -0
- package/src/skills/slash.js +44 -0
- package/src/ui/cli/help.js +94 -101
- package/test/cli/api-key-env-whoami.test.mjs +129 -0
- package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
- package/test/cli/go.test.mjs +62 -5
- package/test/cli/skill-npm-and-env.test.mjs +52 -0
- package/test/cli/wireframes-go-registry.test.mjs +87 -2
- package/test/go/build-source-identity.test.mjs +31 -0
- package/test/go/cloudflare-probe.test.mjs +274 -10
- package/test/go/distribution.test.mjs +28 -0
- package/test/integration/ai-access-onboarding.test.mjs +47 -0
- package/test/integration/cli-help.test.mjs +1 -1
- package/test/integration/cms-site-tenancy-contract.test.mjs +6 -6
- package/test/integration/codebaseindex-ingest.test.mjs +166 -0
- package/test/integration/icon-registry.test.mjs +67 -0
- package/test/integration/ingest-discover-models.test.mjs +30 -0
- package/test/integration/install-script.test.mjs +12 -9
- package/test/integration/local-fs.test.mjs +113 -0
- package/test/integration/provider-env-cli.test.mjs +2 -1
- package/test/integration/sam-activity-recovery.test.mjs +147 -0
- package/test/integration/sam-decision.test.mjs +584 -0
- package/test/integration/sam-kernel.test.mjs +99 -0
- package/test/integration/sam-planning-astar.test.mjs +279 -0
- package/test/integration/skill-runtime.test.mjs +240 -0
- package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
- package/test/models.test.mjs +14 -7
- package/test/shell.test.mjs +4 -4
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agentsam codebaseindex | ingest — guided SAM primitive for indexing materials.
|
|
3
|
+
* Pipeline authority: sam.codebaseindex.index.run (IAM host) · local: knowledge index run.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import {
|
|
9
|
+
cancel, confirm, intro, isCancel, note, outro, select, text,
|
|
10
|
+
} from '@clack/prompts';
|
|
11
|
+
import pc from 'picocolors';
|
|
12
|
+
import {
|
|
13
|
+
CONFIG_PATH, repositoryRoot, readConfig, defaultConfig, validateConfig,
|
|
14
|
+
} from '../knowledge/config.js';
|
|
15
|
+
import { openSqliteStore } from '../knowledge/stores/sqlite.js';
|
|
16
|
+
import { openPostgresStore } from '../knowledge/stores/postgres.js';
|
|
17
|
+
import { planIndex, retrieve, runIndex } from '../knowledge/engine.js';
|
|
18
|
+
import { createProviderRegistry } from '../../packages/agentsam-knowledge/src/providers/index.js';
|
|
19
|
+
import { ensureProjectManifest, getRepositoryId, portableRepositoryIdFromGit, tryReadProjectConfig } from '../lib/project-config.js';
|
|
20
|
+
import { parsePastedPaths, stageMaterials } from '../indexing/ingest/materials.js';
|
|
21
|
+
import {
|
|
22
|
+
discoverIngestModelOptions,
|
|
23
|
+
parseEmbeddingChoice,
|
|
24
|
+
suggestScopeWithLocalModel,
|
|
25
|
+
} from '../indexing/ingest/discover-models.js';
|
|
26
|
+
import {
|
|
27
|
+
assessAiAccess,
|
|
28
|
+
formatAiAccessOnboarding,
|
|
29
|
+
LOCAL_STUDIO_LOGIN,
|
|
30
|
+
CF_OAUTH_LOGIN_START,
|
|
31
|
+
} from '../models/ai-access-onboarding.js';
|
|
32
|
+
import { buildInventory, formatInventoryTree } from '../indexing/ingest/inventory.js';
|
|
33
|
+
import {
|
|
34
|
+
createCodebaseindexJobGraph,
|
|
35
|
+
advanceJobGraph,
|
|
36
|
+
freezePlanJobGraph,
|
|
37
|
+
skipJobGraphNode,
|
|
38
|
+
formatJobGraphHuman,
|
|
39
|
+
} from '../indexing/ingest/job-graph.js';
|
|
40
|
+
|
|
41
|
+
function pick(value, label = 'Cancelled') {
|
|
42
|
+
if (isCancel(value)) {
|
|
43
|
+
cancel(label);
|
|
44
|
+
const err = new Error('codebaseindex_cancelled');
|
|
45
|
+
err.code = 'AGENTSAM_CODEBASEINDEX_CANCELLED';
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function splitList(value) {
|
|
52
|
+
return String(value || '')
|
|
53
|
+
.split(',')
|
|
54
|
+
.map((s) => s.trim())
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function localSqlitePath(root) {
|
|
59
|
+
return path.join(root, '.agentsam', 'knowledge', 'index.sqlite');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function openStore(root, config, readOnly = false) {
|
|
63
|
+
if (config.storage.driver === 'sqlite') {
|
|
64
|
+
return openSqliteStore(localSqlitePath(root), { readOnly });
|
|
65
|
+
}
|
|
66
|
+
return openPostgresStore(process.env[config.storage.connection_env]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function writeKnowledgeConfig(root, config) {
|
|
70
|
+
const validated = validateConfig(config);
|
|
71
|
+
const target = path.join(root, CONFIG_PATH);
|
|
72
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
73
|
+
fs.writeFileSync(target, `${JSON.stringify(validated, null, 2)}\n`, { mode: 0o600 });
|
|
74
|
+
return validated;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function loadOrBuildConfig(root, preferences) {
|
|
78
|
+
const project = tryReadProjectConfig(root) || ensureProjectManifest(root, {});
|
|
79
|
+
const repositoryId = getRepositoryId(project) || portableRepositoryIdFromGit(root) || preferences.repositoryId;
|
|
80
|
+
const filename = path.join(root, CONFIG_PATH);
|
|
81
|
+
const base = fs.existsSync(filename)
|
|
82
|
+
? readConfig(root)
|
|
83
|
+
: defaultConfig({
|
|
84
|
+
include: preferences.include,
|
|
85
|
+
exclude: preferences.exclude,
|
|
86
|
+
scope: preferences.scopeName || 'default',
|
|
87
|
+
target: preferences.storage === 'postgres' ? 'production' : 'local',
|
|
88
|
+
dimensions: preferences.embedding.dimensions || 768,
|
|
89
|
+
repositoryId,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return writeKnowledgeConfig(root, {
|
|
93
|
+
...base,
|
|
94
|
+
repository_id: base.repository_id || repositoryId,
|
|
95
|
+
scope: {
|
|
96
|
+
name: preferences.scopeName || base.scope?.name || 'default',
|
|
97
|
+
include: preferences.include,
|
|
98
|
+
exclude: preferences.exclude,
|
|
99
|
+
},
|
|
100
|
+
embedding: preferences.embedding.provider === 'none'
|
|
101
|
+
? { provider: 'none', model: 'none', revision: '1', dimensions: 0, parameters: {} }
|
|
102
|
+
: { ...base.embedding, ...preferences.embedding },
|
|
103
|
+
storage: preferences.storage === 'postgres'
|
|
104
|
+
? { driver: 'postgres', connection_env: preferences.connectionEnv || 'AGENTSAM_DATABASE_URL' }
|
|
105
|
+
: { driver: 'sqlite' },
|
|
106
|
+
lane: {
|
|
107
|
+
id: `${preferences.scopeName || 'default'}-ingest`,
|
|
108
|
+
backend: preferences.storage === 'postgres' ? 'postgres_pgvector' : 'local_exact',
|
|
109
|
+
resource: null,
|
|
110
|
+
binding: null,
|
|
111
|
+
index: null,
|
|
112
|
+
metric: 'cosine',
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function providerAdapter(profile) {
|
|
118
|
+
if (profile?.provider === 'none') {
|
|
119
|
+
return {
|
|
120
|
+
validate: () => {},
|
|
121
|
+
embed: async () => {
|
|
122
|
+
throw new Error('embedding_disabled');
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const adapter = createProviderRegistry().get(profile.provider);
|
|
127
|
+
return {
|
|
128
|
+
validate: (input) => adapter.validate(input),
|
|
129
|
+
async embed(text, input, context) {
|
|
130
|
+
return context?.kind === 'query'
|
|
131
|
+
? adapter.embedQuery(text, input, context)
|
|
132
|
+
: (await adapter.embedDocuments([text], input, context))[0];
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Non-interactive / SAM handler entry.
|
|
139
|
+
* @param {object} input
|
|
140
|
+
* @param {object} [ctx]
|
|
141
|
+
*/
|
|
142
|
+
export async function runCodebaseindexIngest(input = {}, ctx = {}) {
|
|
143
|
+
const root = path.resolve(input.root || input.cwd || ctx.cwd || process.cwd());
|
|
144
|
+
const materials = Array.isArray(input.materials)
|
|
145
|
+
? input.materials
|
|
146
|
+
: parsePastedPaths(input.paste || input.paths || '');
|
|
147
|
+
let include = Array.isArray(input.include) && input.include.length ? [...input.include] : ['.'];
|
|
148
|
+
// Exclude is user-authored — never invent a product denylist.
|
|
149
|
+
let exclude = Array.isArray(input.exclude) ? [...input.exclude] : [];
|
|
150
|
+
/** @type {object|null} */
|
|
151
|
+
let staged = null;
|
|
152
|
+
let jobGraph = createCodebaseindexJobGraph({
|
|
153
|
+
status: 'planned',
|
|
154
|
+
current: 'material.stage',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (materials.length) {
|
|
158
|
+
staged = stageMaterials({ root, materials });
|
|
159
|
+
include = [...new Set([...include.filter((x) => x !== '.'), ...staged.include])];
|
|
160
|
+
if (!include.length) include = staged.include.length ? staged.include : ['.'];
|
|
161
|
+
jobGraph = advanceJobGraph(jobGraph, 'material.stage');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const inventory = input.inventory || buildInventory({ root, materials: staged });
|
|
165
|
+
jobGraph = advanceJobGraph({ ...jobGraph, current: 'inventory.classify' }, 'inventory.classify');
|
|
166
|
+
|
|
167
|
+
const embedding = input.embedding && typeof input.embedding === 'object'
|
|
168
|
+
? input.embedding
|
|
169
|
+
: parseEmbeddingChoice(input.embeddingChoice || 'none');
|
|
170
|
+
|
|
171
|
+
const storage = input.storage === 'postgres' ? 'postgres' : 'sqlite';
|
|
172
|
+
const vectors = input.vectors || (embedding.provider === 'none' ? 'none'
|
|
173
|
+
: storage === 'postgres' ? 'pgvector' : 'sqlite_exact');
|
|
174
|
+
|
|
175
|
+
const config = loadOrBuildConfig(root, {
|
|
176
|
+
include,
|
|
177
|
+
exclude,
|
|
178
|
+
embedding,
|
|
179
|
+
storage,
|
|
180
|
+
scopeName: input.scope || 'ingest',
|
|
181
|
+
connectionEnv: input.connectionEnv,
|
|
182
|
+
});
|
|
183
|
+
jobGraph = advanceJobGraph(jobGraph, 'scope.resolve');
|
|
184
|
+
jobGraph = advanceJobGraph(jobGraph, 'profile.resolve');
|
|
185
|
+
jobGraph = advanceJobGraph(jobGraph, 'lane.resolve');
|
|
186
|
+
|
|
187
|
+
const embed = Boolean(input.embed) && embedding.provider !== 'none';
|
|
188
|
+
const store = await openStore(root, config, false);
|
|
189
|
+
try {
|
|
190
|
+
if (input.planOnly) {
|
|
191
|
+
const plan = await planIndex({ root, config, store, embed });
|
|
192
|
+
jobGraph = advanceJobGraph(jobGraph, 'plan.dry_run');
|
|
193
|
+
jobGraph = freezePlanJobGraph(jobGraph, { skipEmbedding: !embed });
|
|
194
|
+
return {
|
|
195
|
+
pipeline: 'sam.codebaseindex.index.run',
|
|
196
|
+
operation: 'codebaseindex.ingest',
|
|
197
|
+
mode: 'plan',
|
|
198
|
+
root: '.',
|
|
199
|
+
config_path: CONFIG_PATH,
|
|
200
|
+
staged,
|
|
201
|
+
inventory: { ...inventory, root: '.' },
|
|
202
|
+
storage_lanes: { metadata: storage, vectors },
|
|
203
|
+
job_graph: jobGraph,
|
|
204
|
+
plan: plan.receipt,
|
|
205
|
+
embedding: config.embedding,
|
|
206
|
+
storage: config.storage,
|
|
207
|
+
include: config.scope.include,
|
|
208
|
+
exclude: config.scope.exclude,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let adapter;
|
|
213
|
+
const embedder = {
|
|
214
|
+
validate: (...args) => (adapter ??= providerAdapter(config.embedding)).validate(...args),
|
|
215
|
+
embed: (...args) => (adapter ??= providerAdapter(config.embedding)).embed(...args),
|
|
216
|
+
};
|
|
217
|
+
const result = await runIndex({
|
|
218
|
+
root,
|
|
219
|
+
config,
|
|
220
|
+
store,
|
|
221
|
+
embed,
|
|
222
|
+
embedder,
|
|
223
|
+
maxInputs: Number(input.maxInputs ?? 200),
|
|
224
|
+
maxCharacters: Number(input.maxCharacters ?? 400000),
|
|
225
|
+
});
|
|
226
|
+
jobGraph = advanceJobGraph(jobGraph, 'plan.dry_run');
|
|
227
|
+
jobGraph = advanceJobGraph(jobGraph, 'ast.parse');
|
|
228
|
+
jobGraph = advanceJobGraph(jobGraph, 'chunks.build');
|
|
229
|
+
|
|
230
|
+
if (embed) {
|
|
231
|
+
jobGraph = advanceJobGraph(jobGraph, 'embedding.generate');
|
|
232
|
+
} else {
|
|
233
|
+
jobGraph = skipJobGraphNode(
|
|
234
|
+
jobGraph,
|
|
235
|
+
'embedding.generate',
|
|
236
|
+
'embedding_disabled',
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
jobGraph = advanceJobGraph(jobGraph, 'storage.write');
|
|
241
|
+
jobGraph = advanceJobGraph(jobGraph, 'generation.verify');
|
|
242
|
+
|
|
243
|
+
const smokeQuery =
|
|
244
|
+
String(input.smokeQuery || config.scope.include?.[0] || 'source').trim()
|
|
245
|
+
|| 'source';
|
|
246
|
+
|
|
247
|
+
const smoke = await retrieve({
|
|
248
|
+
store,
|
|
249
|
+
config,
|
|
250
|
+
text: smokeQuery,
|
|
251
|
+
semantic: false,
|
|
252
|
+
topK: 1,
|
|
253
|
+
tokenBudget: 512,
|
|
254
|
+
generationId: result.generation_id,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
jobGraph = advanceJobGraph(jobGraph, 'search.smoke');
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
pipeline: 'sam.codebaseindex.index.run',
|
|
261
|
+
operation: 'codebaseindex.ingest',
|
|
262
|
+
mode: 'run',
|
|
263
|
+
root: '.',
|
|
264
|
+
config_path: CONFIG_PATH,
|
|
265
|
+
staged,
|
|
266
|
+
inventory: { ...inventory, root: '.' },
|
|
267
|
+
storage_lanes: { metadata: storage, vectors },
|
|
268
|
+
job_graph: jobGraph,
|
|
269
|
+
index: result,
|
|
270
|
+
search_smoke: {
|
|
271
|
+
query: smokeQuery,
|
|
272
|
+
generation_id: smoke.diagnostics?.generation_id || result.generation_id,
|
|
273
|
+
sources_included: smoke.receipt?.sources_included ?? smoke.hits?.length ?? 0,
|
|
274
|
+
},
|
|
275
|
+
embedding: config.embedding,
|
|
276
|
+
storage: config.storage,
|
|
277
|
+
include: config.scope.include,
|
|
278
|
+
exclude: config.scope.exclude,
|
|
279
|
+
assets: staged?.assets || [],
|
|
280
|
+
};
|
|
281
|
+
} finally {
|
|
282
|
+
await store?.close();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function helpText() {
|
|
287
|
+
return [
|
|
288
|
+
'Agent Sam · codebaseindex (ingest)',
|
|
289
|
+
'',
|
|
290
|
+
' Guided SAM primitive for indexing a repo and/or dropped materials.',
|
|
291
|
+
' CLI: agentsam codebaseindex',
|
|
292
|
+
' Operation: codebaseindex.ingest',
|
|
293
|
+
' Pipeline id (receipts/telemetry — NOT a shell command): sam.codebaseindex.index.run',
|
|
294
|
+
'',
|
|
295
|
+
' After a dry-run plan, rerun and choose "Run ingest now" — do not type the pipeline id.',
|
|
296
|
+
'',
|
|
297
|
+
' Embedding models are discovered from your configured provider credentials',
|
|
298
|
+
' (OpenAI, Gemini, Cloudflare Workers AI for Vectorize). Ollama is optional.',
|
|
299
|
+
' Include/exclude paths are prompted — AgentSam does not invent a denylist.',
|
|
300
|
+
'',
|
|
301
|
+
' agentsam codebaseindex interactive wizard (clack)',
|
|
302
|
+
' agentsam ingest alias',
|
|
303
|
+
' agentsam codebaseindex --paths … materials',
|
|
304
|
+
' agentsam codebaseindex --include src --exclude node_modules,.git',
|
|
305
|
+
' agentsam codebaseindex --plan plan only',
|
|
306
|
+
' agentsam codebaseindex --embed enable embedding pass after you pick a model',
|
|
307
|
+
'',
|
|
308
|
+
' tip: use skill agentsam-codebaseindex',
|
|
309
|
+
'',
|
|
310
|
+
].join('\n');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function parseArgv(argv = []) {
|
|
314
|
+
const out = {
|
|
315
|
+
help: false,
|
|
316
|
+
json: false,
|
|
317
|
+
plan: false,
|
|
318
|
+
embed: false,
|
|
319
|
+
yes: false,
|
|
320
|
+
interactive: null,
|
|
321
|
+
paths: [],
|
|
322
|
+
include: '',
|
|
323
|
+
exclude: '',
|
|
324
|
+
storage: '',
|
|
325
|
+
embedding: '',
|
|
326
|
+
cwd: '',
|
|
327
|
+
};
|
|
328
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
329
|
+
const arg = argv[i];
|
|
330
|
+
if (arg === '--help' || arg === '-h') out.help = true;
|
|
331
|
+
else if (arg === '--json') out.json = true;
|
|
332
|
+
else if (arg === '--plan') out.plan = true;
|
|
333
|
+
else if (arg === '--embed') out.embed = true;
|
|
334
|
+
else if (arg === '--yes' || arg === '-y') out.yes = true;
|
|
335
|
+
else if (arg === '--interactive' || arg === '-i') out.interactive = true;
|
|
336
|
+
else if (arg === '--no-interactive') out.interactive = false;
|
|
337
|
+
else if (arg === '--cwd') out.cwd = argv[++i] || '';
|
|
338
|
+
else if (arg === '--paths' || arg === '--materials') out.paths.push(...splitList(argv[++i] || ''));
|
|
339
|
+
else if (arg === '--include') out.include = argv[++i] || '';
|
|
340
|
+
else if (arg === '--exclude') out.exclude = argv[++i] || '';
|
|
341
|
+
else if (arg === '--storage') out.storage = argv[++i] || '';
|
|
342
|
+
else if (arg === '--embedding') out.embedding = argv[++i] || '';
|
|
343
|
+
else if (!arg.startsWith('-')) out.paths.push(arg);
|
|
344
|
+
else throw new Error(`Unknown codebaseindex option: ${arg}`);
|
|
345
|
+
}
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
async function runWizard(root, opts) {
|
|
350
|
+
intro('AgentSam · codebaseindex (inventory-first)');
|
|
351
|
+
|
|
352
|
+
// ① Providers (informational — discovery only) + onboarding if empty
|
|
353
|
+
const discovered = await discoverIngestModelOptions();
|
|
354
|
+
const access = assessAiAccess(discovered);
|
|
355
|
+
const providerLines = [
|
|
356
|
+
discovered.ollama?.online
|
|
357
|
+
? `ollama online · ${(discovered.ollama.models || []).map((m) => m.name).join(', ')}`
|
|
358
|
+
: 'ollama offline (optional local embed/assist)',
|
|
359
|
+
...(discovered.inventory?.providers || [])
|
|
360
|
+
.filter((p) => p.configured)
|
|
361
|
+
.map((p) => `${p.id} credential configured`),
|
|
362
|
+
];
|
|
363
|
+
if (!access.ready) {
|
|
364
|
+
note(
|
|
365
|
+
formatAiAccessOnboarding(access, { wantCloudAi: true }),
|
|
366
|
+
'① Connection · AI access needed for model options',
|
|
367
|
+
);
|
|
368
|
+
const setup = pick(await select({
|
|
369
|
+
message: 'How do you want to unlock AI models?',
|
|
370
|
+
initialValue: 'continue_ast',
|
|
371
|
+
options: [
|
|
372
|
+
{
|
|
373
|
+
value: 'continue_ast',
|
|
374
|
+
label: 'Continue with AST/text only ($0 · no models)',
|
|
375
|
+
hint: 'embeddings stay none',
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
value: 'providers',
|
|
379
|
+
label: 'I will add a provider API key',
|
|
380
|
+
hint: 'run: agentsam providers (then rerun codebaseindex)',
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
value: 'ollama',
|
|
384
|
+
label: 'I will install Ollama locally',
|
|
385
|
+
hint: 'https://ollama.com/download',
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
value: 'studio_cf',
|
|
389
|
+
label: 'Sign in / approve Cloudflare for Local Studio',
|
|
390
|
+
hint: 'identity + Workers AI / MCP',
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
}));
|
|
394
|
+
if (setup === 'providers') {
|
|
395
|
+
note('Run: agentsam providers\nThen: agentsam codebaseindex', 'Next');
|
|
396
|
+
outro('Paused — configure a provider key, then rerun.');
|
|
397
|
+
return { mode: 'needs_ai_access', reason: 'provider_key', pipeline: 'sam.codebaseindex.index.run' };
|
|
398
|
+
}
|
|
399
|
+
if (setup === 'ollama') {
|
|
400
|
+
note(
|
|
401
|
+
[
|
|
402
|
+
'1. Install: https://ollama.com/download',
|
|
403
|
+
'2. ollama pull mxbai-embed-large',
|
|
404
|
+
'3. ollama pull qwen2.5-coder',
|
|
405
|
+
'4. agentsam ollama status',
|
|
406
|
+
'5. agentsam codebaseindex',
|
|
407
|
+
].join('\n'),
|
|
408
|
+
'Ollama setup',
|
|
409
|
+
);
|
|
410
|
+
outro('Paused — install local models, then rerun.');
|
|
411
|
+
return { mode: 'needs_ai_access', reason: 'ollama', pipeline: 'sam.codebaseindex.index.run' };
|
|
412
|
+
}
|
|
413
|
+
if (setup === 'studio_cf') {
|
|
414
|
+
note(
|
|
415
|
+
[
|
|
416
|
+
`Login portal: ${LOCAL_STUDIO_LOGIN}`,
|
|
417
|
+
`CF sign-in: ${CF_OAUTH_LOGIN_START}`,
|
|
418
|
+
'',
|
|
419
|
+
'After Cloudflare approves, return here and rerun:',
|
|
420
|
+
' agentsam codebaseindex',
|
|
421
|
+
'',
|
|
422
|
+
'Dashboard OAuth client must include redirect:',
|
|
423
|
+
' https://agentsam.inneranimalmedia.com/api/oauth/cloudflare/callback',
|
|
424
|
+
'(in addition to /api/connections/cloudflare/callback)',
|
|
425
|
+
].join('\n'),
|
|
426
|
+
'Local Studio · Cloudflare OAuth',
|
|
427
|
+
);
|
|
428
|
+
outro('Paused — complete OAuth approval, then rerun.');
|
|
429
|
+
return { mode: 'needs_ai_access', reason: 'cloudflare_oauth', pipeline: 'sam.codebaseindex.index.run' };
|
|
430
|
+
}
|
|
431
|
+
note(providerLines.join('\n') || 'Continuing without remote/local models.', '① Connection');
|
|
432
|
+
} else {
|
|
433
|
+
note(providerLines.join('\n') || 'No remote credentials — AST/text-only remains valid.', '① Connection');
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// ② Materials
|
|
437
|
+
note(
|
|
438
|
+
[
|
|
439
|
+
'Paste or drag-drop archives, site builds, HTML, images, GLB, or folders.',
|
|
440
|
+
'Leave blank to inventory the repository only.',
|
|
441
|
+
].join('\n'),
|
|
442
|
+
'② Materials',
|
|
443
|
+
);
|
|
444
|
+
const paste = pick(await text({
|
|
445
|
+
message: 'Paths to ingest (paste/drop; blank = repo inventory)',
|
|
446
|
+
placeholder: '/path/to/build.tar.gz ./dist screenshot.png',
|
|
447
|
+
}), 'Ingest cancelled');
|
|
448
|
+
const materials = [...new Set([...(opts.paths || []), ...parsePastedPaths(paste)])];
|
|
449
|
+
|
|
450
|
+
let staged = null;
|
|
451
|
+
if (materials.length) {
|
|
452
|
+
staged = stageMaterials({ root, materials });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ③ Inventory / file map BEFORE scope
|
|
456
|
+
const inventory = buildInventory({ root, materials: staged });
|
|
457
|
+
note(formatInventoryTree(inventory), '③ Inventory / file map');
|
|
458
|
+
const continueAfterInventory = pick(await confirm({
|
|
459
|
+
message: 'Continue to include/exclude using this inventory?',
|
|
460
|
+
initialValue: true,
|
|
461
|
+
}));
|
|
462
|
+
if (!continueAfterInventory) {
|
|
463
|
+
cancel('Stopped after inventory');
|
|
464
|
+
return { mode: 'inventory_only', inventory, staged, pipeline: 'sam.codebaseindex.index.run' };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Default scope from categorized inventory (not "include everything")
|
|
468
|
+
let include = opts.include ? splitList(opts.include) : [...(inventory.suggested.include || [])];
|
|
469
|
+
let exclude = opts.exclude ? splitList(opts.exclude) : [...(inventory.suggested.exclude || [])];
|
|
470
|
+
|
|
471
|
+
if (discovered.assistModels.length) {
|
|
472
|
+
const assistChoice = pick(await select({
|
|
473
|
+
message: '④ Scope — how to set include/exclude?',
|
|
474
|
+
initialValue: 'from_inventory',
|
|
475
|
+
options: [
|
|
476
|
+
{ value: 'from_inventory', label: 'Start from inventory categories', hint: 'source+docs in · usually-exclude out · you still edit' },
|
|
477
|
+
{ value: 'manual', label: 'Enter include/exclude myself', hint: 'blank exclude = exclude nothing' },
|
|
478
|
+
{ value: 'assist', label: 'Suggest with local Ollama (optional)', hint: 'advisory only — inventory still owns categories' },
|
|
479
|
+
],
|
|
480
|
+
}));
|
|
481
|
+
if (assistChoice === 'manual') {
|
|
482
|
+
include = [];
|
|
483
|
+
exclude = [];
|
|
484
|
+
} else if (assistChoice === 'assist') {
|
|
485
|
+
const modelPick = pick(await select({
|
|
486
|
+
message: 'Local chat model for scope suggestions',
|
|
487
|
+
options: discovered.assistModels.map((row) => ({
|
|
488
|
+
value: row.model,
|
|
489
|
+
label: row.label,
|
|
490
|
+
hint: row.hint,
|
|
491
|
+
})),
|
|
492
|
+
}));
|
|
493
|
+
try {
|
|
494
|
+
const suggestion = await suggestScopeWithLocalModel({
|
|
495
|
+
root,
|
|
496
|
+
model: modelPick,
|
|
497
|
+
topLevel: inventory.top_level,
|
|
498
|
+
categories: inventory.categories,
|
|
499
|
+
});
|
|
500
|
+
note(
|
|
501
|
+
[
|
|
502
|
+
suggestion.rationale || 'Local model suggestion (advisory)',
|
|
503
|
+
`include: ${(suggestion.include || []).join(', ') || '(none)'}`,
|
|
504
|
+
`exclude: ${(suggestion.exclude || []).join(', ') || '(none)'}`,
|
|
505
|
+
].join('\n'),
|
|
506
|
+
`Suggested by ${modelPick}`,
|
|
507
|
+
);
|
|
508
|
+
if (pick(await confirm({ message: 'Use as starting include/exclude?', initialValue: true }))) {
|
|
509
|
+
include = suggestion.include;
|
|
510
|
+
exclude = suggestion.exclude;
|
|
511
|
+
}
|
|
512
|
+
} catch (error) {
|
|
513
|
+
note(error?.message || String(error), 'Local assist unavailable');
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
include = splitList(pick(await text({
|
|
519
|
+
message: 'Include paths (comma-separated)',
|
|
520
|
+
initialValue: include.join(',') || (materials.length ? '' : '.'),
|
|
521
|
+
placeholder: 'src,packages,apps,docs',
|
|
522
|
+
})));
|
|
523
|
+
if (!include.length && !materials.length) include = ['.'];
|
|
524
|
+
|
|
525
|
+
exclude = splitList(pick(await text({
|
|
526
|
+
message: 'Exclude paths (blank = exclude nothing)',
|
|
527
|
+
initialValue: exclude.join(','),
|
|
528
|
+
placeholder: 'node_modules,.git,dist — only if you want them out',
|
|
529
|
+
})));
|
|
530
|
+
|
|
531
|
+
// ⑤ Embedding profile (discovered)
|
|
532
|
+
note(
|
|
533
|
+
discovered.options.length > 1
|
|
534
|
+
? `Discovered embed options from credentials (OpenAI/Gemini/Workers AI) + optional Ollama (${discovered.options.length - 1}).`
|
|
535
|
+
: 'No embed providers discovered — AST/text-only is available. Configure CF/OpenAI/Gemini to unlock Vectorize-ready models.',
|
|
536
|
+
'⑤ Embedding profile',
|
|
537
|
+
);
|
|
538
|
+
const embeddingChoice = pick(await select({
|
|
539
|
+
message: 'Embedding model',
|
|
540
|
+
initialValue: 'none',
|
|
541
|
+
options: discovered.options.map((row) => ({
|
|
542
|
+
value: row.value,
|
|
543
|
+
label: row.label,
|
|
544
|
+
hint: row.hint,
|
|
545
|
+
})),
|
|
546
|
+
}));
|
|
547
|
+
const runEmbed = embeddingChoice !== 'none' && pick(await confirm({
|
|
548
|
+
message: embeddingChoice.startsWith('ollama|')
|
|
549
|
+
? 'Run local embedding pass?'
|
|
550
|
+
: 'Run embedding pass (may cost provider tokens)?',
|
|
551
|
+
initialValue: embeddingChoice.startsWith('ollama|'),
|
|
552
|
+
}));
|
|
553
|
+
|
|
554
|
+
// ⑥ Storage lanes
|
|
555
|
+
const lane = pick(await select({
|
|
556
|
+
message: '⑥ Vector / data source lane',
|
|
557
|
+
initialValue: 'local',
|
|
558
|
+
options: [
|
|
559
|
+
{ value: 'local', label: 'Local SQLite', hint: 'metadata + optional exact vectors · $0 cloud' },
|
|
560
|
+
{ value: 'supabase', label: 'Supabase + node-api / Hyperdrive', hint: 'pgvector ANN · BYO edge template' },
|
|
561
|
+
{ value: 'vectorize', label: 'Cloudflare Vectorize', hint: 'customer CF lane · not IAM host SSOT' },
|
|
562
|
+
],
|
|
563
|
+
}));
|
|
564
|
+
const storage = lane === 'supabase' ? 'postgres' : 'sqlite';
|
|
565
|
+
if (lane === 'vectorize') {
|
|
566
|
+
note('Vectorize lane recorded for plan/receipt; full CF adapter wiring is a follow-up slice.', 'Lane note');
|
|
567
|
+
}
|
|
568
|
+
if (lane === 'supabase') {
|
|
569
|
+
note('Uses AGENTSAM_DATABASE_URL / Hyperdrive-style postgres. Owner IAM already has node-api.', 'Lane note');
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// ⑦ Dry-run vs execute
|
|
573
|
+
const planOnly = pick(await select({
|
|
574
|
+
message: '⑦ Execution',
|
|
575
|
+
initialValue: opts.plan ? 'plan' : 'run',
|
|
576
|
+
options: [
|
|
577
|
+
{ value: 'plan', label: 'Dry-run / plan (writes config + plan receipt, no generation activate)', hint: 'recommended first' },
|
|
578
|
+
{ value: 'run', label: 'Execute ingest now', hint: 'writes knowledge store' },
|
|
579
|
+
],
|
|
580
|
+
})) === 'plan';
|
|
581
|
+
|
|
582
|
+
const summary = [
|
|
583
|
+
`root: ${root}`,
|
|
584
|
+
`materials: ${materials.length || 'none'}`,
|
|
585
|
+
`inventory files: ${inventory.counts.files}`,
|
|
586
|
+
`include: ${include.join(', ') || '(from materials)'}`,
|
|
587
|
+
`exclude: ${exclude.join(', ') || '(none)'}`,
|
|
588
|
+
`embedding: ${embeddingChoice}`,
|
|
589
|
+
`lane: ${lane} (metadata=${storage})`,
|
|
590
|
+
`mode: ${planOnly ? 'plan' : 'run'}`,
|
|
591
|
+
].join('\n');
|
|
592
|
+
note(summary, 'Confirm');
|
|
593
|
+
if (!pick(await confirm({ message: 'Proceed with codebaseindex.ingest?', initialValue: true }))) {
|
|
594
|
+
cancel('Ingest aborted');
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const result = await runCodebaseindexIngest({
|
|
599
|
+
root,
|
|
600
|
+
materials,
|
|
601
|
+
include: include.length ? include : undefined,
|
|
602
|
+
exclude,
|
|
603
|
+
storage,
|
|
604
|
+
vectors: lane === 'vectorize' ? 'vectorize' : lane === 'supabase' ? 'pgvector' : (runEmbed ? 'sqlite_exact' : 'none'),
|
|
605
|
+
embeddingChoice,
|
|
606
|
+
embed: runEmbed,
|
|
607
|
+
planOnly,
|
|
608
|
+
inventory,
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
if (result?.job_graph) {
|
|
612
|
+
note(
|
|
613
|
+
formatJobGraphHuman(result.job_graph, { planOnly }),
|
|
614
|
+
'Job graph',
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (planOnly) {
|
|
619
|
+
outro([
|
|
620
|
+
'Plan complete',
|
|
621
|
+
'',
|
|
622
|
+
'No index was written because you selected Dry-run / plan.',
|
|
623
|
+
'',
|
|
624
|
+
'Pipeline ID (not a shell command)',
|
|
625
|
+
` ${result.pipeline}`,
|
|
626
|
+
'',
|
|
627
|
+
'Next',
|
|
628
|
+
' agentsam codebaseindex',
|
|
629
|
+
' → choose "Run ingest now"',
|
|
630
|
+
'',
|
|
631
|
+
'Script/API',
|
|
632
|
+
' sam.invoke("codebaseindex.ingest", { ..., planOnly: false })',
|
|
633
|
+
'',
|
|
634
|
+
'tip: use skill agentsam-codebaseindex',
|
|
635
|
+
].join('\n'));
|
|
636
|
+
} else {
|
|
637
|
+
outro(`Ingest complete · pipeline id ${result.pipeline} (not a shell command)`);
|
|
638
|
+
}
|
|
639
|
+
return result;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* CLI entry: agentsam codebaseindex | ingest
|
|
644
|
+
*/
|
|
645
|
+
export async function runCodebaseindex(argv = []) {
|
|
646
|
+
const opts = parseArgv(argv);
|
|
647
|
+
if (opts.help) {
|
|
648
|
+
process.stdout.write(helpText());
|
|
649
|
+
return { ok: true, help: true };
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const root = repositoryRoot(opts.cwd || process.cwd());
|
|
653
|
+
ensureProjectManifest(root, {});
|
|
654
|
+
const tty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
655
|
+
const wantInteractive = opts.interactive === true || (opts.interactive !== false && tty && !opts.yes && !opts.paths.length && !opts.include);
|
|
656
|
+
|
|
657
|
+
let result;
|
|
658
|
+
if (wantInteractive) {
|
|
659
|
+
result = await runWizard(root, opts);
|
|
660
|
+
} else {
|
|
661
|
+
result = await runCodebaseindexIngest({
|
|
662
|
+
root,
|
|
663
|
+
materials: opts.paths,
|
|
664
|
+
include: opts.include ? splitList(opts.include) : undefined,
|
|
665
|
+
exclude: opts.exclude ? splitList(opts.exclude) : [],
|
|
666
|
+
storage: opts.storage || 'sqlite',
|
|
667
|
+
embeddingChoice: opts.embedding || 'none',
|
|
668
|
+
embed: opts.embed,
|
|
669
|
+
planOnly: opts.plan,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (!result) return null;
|
|
674
|
+
if (opts.json || !tty) {
|
|
675
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
676
|
+
} else if (!wantInteractive) {
|
|
677
|
+
process.stdout.write(`${pc.green('✓')} codebaseindex.ingest ${result.mode}\n`);
|
|
678
|
+
process.stdout.write(` pipeline ${result.pipeline}\n`);
|
|
679
|
+
process.stdout.write(` include ${(result.include || []).join(', ')}\n`);
|
|
680
|
+
process.stdout.write(` storage ${result.storage?.driver}\n`);
|
|
681
|
+
process.stdout.write(` embedding ${result.embedding?.provider}/${result.embedding?.model}\n`);
|
|
682
|
+
if (result.staged?.assets?.length) {
|
|
683
|
+
process.stdout.write(` assets ${result.staged.assets.length} staged\n`);
|
|
684
|
+
}
|
|
685
|
+
process.stdout.write(` tip: use skill agentsam-codebaseindex\n`);
|
|
686
|
+
}
|
|
687
|
+
return result;
|
|
688
|
+
}
|