@amistio/cli 0.1.15 → 0.1.17
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 +2 -0
- package/dist/index.js +147 -36
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ Provider-backed model preferences use sanitized catalog fields: `--provider`, `-
|
|
|
39
39
|
|
|
40
40
|
When `--tool copilot` uses the GitHub Copilot SDK, Amistio approves read-only permission requests by default and denies mutating, network, MCP, hook, memory, and shell requests. Set `AMISTIO_COPILOT_APPROVE_ALL=1` only on a local machine where broad Copilot SDK approval is intentional.
|
|
41
41
|
|
|
42
|
+
When `--tool codex` uses the Codex SDK, intermediate progress can be quiet until the final response. For live Codex CLI logs, run `amistio run --watch --tool codex --invocation-channel command`.
|
|
43
|
+
|
|
42
44
|
`amistio runner status` reports local background runner state, latest heartbeat, and bounded resource usage when available. Resource usage is latest-sample runner process memory/CPU plus safe aggregate system memory/load signals; it does not include source files, environment variables, command lines, process lists, credentials, or arbitrary local paths.
|
|
43
45
|
|
|
44
46
|
The runner advertises its supported work kinds in heartbeats. Current runners can claim read-only `projectContextRefresh` jobs from the workspace Context panel and create due runner-driven refreshes when no fresh approved map exists. Context refreshes inspect the paired checkout locally without modifying files and submit only bounded summaries, slices, entities, relations, safe citations, confidence, freshness, and repo-relative paths. If a submitted context refresh contains unsafe evidence, unsafe paths, or a map too large to store safely, Amistio marks the refresh failed with a safe reason instead of storing the rejected raw result. Approved maps are reused as context packs for source-aware assistant and impact-preview work. Current runners can also claim read-only issue diagnosis jobs from the web Issues panel, generate root-cause analysis and a proposed fix, and submit that result without modifying source. They can claim manual read-only `appEvaluationScan` jobs from the workspace Evaluate panel and create at most one due hourly evaluation during normal watch/background polling when app evaluation is enabled for the repository link. Evaluation results contain bounded summaries, safe evidence, suggested actions, lifecycle proposals, and repo-relative paths only. Current runners can also claim manual read-only `securityPostureScan` jobs from the workspace Security panel and create due daily posture checks during normal watch/background polling. Security scan results contain bounded summaries, standard references, safe evidence, and repo-relative paths only; source, secrets, environment variables, command lines, process lists, credentials, provider sessions, and arbitrary local paths stay local. Implementation or cleanup is queued separately only after the user approves an issue analysis, app evaluation finding, or security remediation plan in the app.
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { createHash as createHash7, randomUUID } from "node:crypto";
|
|
5
5
|
import { writeFile as writeFile9 } from "node:fs/promises";
|
|
6
6
|
import os7 from "node:os";
|
|
7
|
-
import
|
|
7
|
+
import path15 from "node:path";
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
|
|
10
10
|
// ../shared/src/schemas.ts
|
|
@@ -773,6 +773,9 @@ var projectContextRepoPathSchema = z.string().trim().min(1).max(300).refine((val
|
|
|
773
773
|
}
|
|
774
774
|
return !value.split(/[\\/]+/).includes("..");
|
|
775
775
|
}, "Path must be repository-relative without traversal");
|
|
776
|
+
var projectContextCitationSchema = assistantCitationSchema.extend({
|
|
777
|
+
repoPath: projectContextRepoPathSchema.optional()
|
|
778
|
+
});
|
|
776
779
|
var projectContextCoverageSchema = z.object({
|
|
777
780
|
status: projectContextFreshnessSchema.default("missing"),
|
|
778
781
|
sliceCount: z.number().int().nonnegative().default(0),
|
|
@@ -789,7 +792,7 @@ var projectContextSliceSchema = z.object({
|
|
|
789
792
|
repoPaths: z.array(projectContextRepoPathSchema).max(80).default([]),
|
|
790
793
|
ownerHints: z.array(z.string().trim().min(1).max(160)).max(20).default([]),
|
|
791
794
|
tags: z.array(z.string().trim().min(1).max(80)).max(30).default([]),
|
|
792
|
-
citations: z.array(
|
|
795
|
+
citations: z.array(projectContextCitationSchema).default([]),
|
|
793
796
|
dependsOn: z.array(z.string().trim().min(1).max(160)).max(50).default([]),
|
|
794
797
|
freshness: projectContextFreshnessSchema.default("fresh"),
|
|
795
798
|
confidence: z.number().min(0).max(1).default(0.6),
|
|
@@ -803,7 +806,7 @@ var projectContextEntitySchema = z.object({
|
|
|
803
806
|
summary: z.string().trim().min(1).max(1200).optional(),
|
|
804
807
|
aliases: z.array(z.string().trim().min(1).max(200)).default([]),
|
|
805
808
|
sliceIds: z.array(z.string().trim().min(1).max(160)).default([]),
|
|
806
|
-
citations: z.array(
|
|
809
|
+
citations: z.array(projectContextCitationSchema).default([]),
|
|
807
810
|
confidence: z.number().min(0).max(1).default(0.6)
|
|
808
811
|
});
|
|
809
812
|
var projectContextRelationSchema = z.object({
|
|
@@ -812,7 +815,7 @@ var projectContextRelationSchema = z.object({
|
|
|
812
815
|
fromId: z.string().trim().min(1).max(200),
|
|
813
816
|
toId: z.string().trim().min(1).max(200),
|
|
814
817
|
summary: z.string().trim().min(1).max(1200),
|
|
815
|
-
citations: z.array(
|
|
818
|
+
citations: z.array(projectContextCitationSchema).default([]),
|
|
816
819
|
confidence: z.number().min(0).max(1).default(0.6)
|
|
817
820
|
});
|
|
818
821
|
var projectSystemDiagramStatusSchema = z.enum(["draft", "proposed", "approved", "stale", "archived"]);
|
|
@@ -829,7 +832,7 @@ var projectSystemDiagramNodeSchema = z.object({
|
|
|
829
832
|
lane: z.string().trim().min(1).max(120).optional(),
|
|
830
833
|
sliceIds: z.array(z.string().trim().min(1).max(160)).default([]),
|
|
831
834
|
entityIds: z.array(z.string().trim().min(1).max(200)).default([]),
|
|
832
|
-
citations: z.array(
|
|
835
|
+
citations: z.array(projectContextCitationSchema).min(1),
|
|
833
836
|
confidence: z.number().min(0).max(1).default(0.6),
|
|
834
837
|
freshness: projectContextFreshnessSchema.default("fresh")
|
|
835
838
|
});
|
|
@@ -840,7 +843,7 @@ var projectSystemDiagramEdgeSchema = z.object({
|
|
|
840
843
|
relationType: knowledgeRelationTypeSchema.default("mentions"),
|
|
841
844
|
label: z.string().trim().min(1).max(120).optional(),
|
|
842
845
|
summary: z.string().trim().min(1).max(1200),
|
|
843
|
-
citations: z.array(
|
|
846
|
+
citations: z.array(projectContextCitationSchema).min(1),
|
|
844
847
|
confidence: z.number().min(0).max(1).default(0.6),
|
|
845
848
|
freshness: projectContextFreshnessSchema.default("fresh")
|
|
846
849
|
});
|
|
@@ -849,7 +852,7 @@ var projectSystemDiagramGroupSchema = z.object({
|
|
|
849
852
|
label: z.string().trim().min(1).max(120),
|
|
850
853
|
kind: projectSystemDiagramGroupKindSchema.default("group"),
|
|
851
854
|
summary: z.string().trim().min(1).max(1200).optional(),
|
|
852
|
-
citations: z.array(
|
|
855
|
+
citations: z.array(projectContextCitationSchema).default([])
|
|
853
856
|
});
|
|
854
857
|
var projectSystemDiagramViewSchema = z.object({
|
|
855
858
|
viewId: z.string().trim().min(1).max(160),
|
|
@@ -871,7 +874,7 @@ var projectSystemDiagramGraphManifestSchema = z.object({
|
|
|
871
874
|
edges: z.array(projectSystemDiagramEdgeSchema).default([]),
|
|
872
875
|
groups: z.array(projectSystemDiagramGroupSchema).default([]),
|
|
873
876
|
views: z.array(projectSystemDiagramViewSchema).min(1),
|
|
874
|
-
citations: z.array(
|
|
877
|
+
citations: z.array(projectContextCitationSchema).default([]),
|
|
875
878
|
unknowns: z.array(z.string().trim().min(1).max(300)).default([]),
|
|
876
879
|
warnings: z.array(z.string().trim().min(1).max(600)).default([])
|
|
877
880
|
});
|
|
@@ -957,7 +960,7 @@ var projectContextPackSchema = z.object({
|
|
|
957
960
|
slices: z.array(projectContextSliceSchema).default([]),
|
|
958
961
|
entities: z.array(projectContextEntitySchema).default([]),
|
|
959
962
|
relations: z.array(projectContextRelationSchema).default([]),
|
|
960
|
-
citations: z.array(
|
|
963
|
+
citations: z.array(projectContextCitationSchema).default([]),
|
|
961
964
|
freshnessWarnings: z.array(z.string().trim().min(1).max(600)).default([]),
|
|
962
965
|
tokenEstimate: z.number().int().nonnegative().default(0),
|
|
963
966
|
generatedAt: isoDateTimeSchema
|
|
@@ -2382,8 +2385,8 @@ var toolSessionMutationSchema = z3.object({
|
|
|
2382
2385
|
});
|
|
2383
2386
|
function resolveApiUrl(apiUrl, urlPath) {
|
|
2384
2387
|
const base = apiUrl.endsWith("/") ? apiUrl.slice(0, -1) : apiUrl;
|
|
2385
|
-
const
|
|
2386
|
-
return new URL(`${base}${
|
|
2388
|
+
const path16 = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
|
|
2389
|
+
return new URL(`${base}${path16}`);
|
|
2387
2390
|
}
|
|
2388
2391
|
|
|
2389
2392
|
// src/orchestrator.ts
|
|
@@ -3195,6 +3198,9 @@ async function runCodexSdk(input) {
|
|
|
3195
3198
|
approvalPolicy: "on-request",
|
|
3196
3199
|
skipGitRepoCheck: true
|
|
3197
3200
|
});
|
|
3201
|
+
if (input.streamOutput) {
|
|
3202
|
+
process.stderr.write("Codex SDK is running; intermediate progress may be quiet until the final response. Use --invocation-channel command for Codex CLI logs.\n");
|
|
3203
|
+
}
|
|
3198
3204
|
const result = await thread.run(input.prompt);
|
|
3199
3205
|
if (input.streamOutput && result.finalResponse) {
|
|
3200
3206
|
process.stdout.write(result.finalResponse);
|
|
@@ -4371,6 +4377,7 @@ function defaultSessionStorePath() {
|
|
|
4371
4377
|
}
|
|
4372
4378
|
|
|
4373
4379
|
// src/work-runner.ts
|
|
4380
|
+
import path10 from "node:path";
|
|
4374
4381
|
var generationResultStart = "AMISTIO_BRAIN_GENERATION_RESULT_START";
|
|
4375
4382
|
var generationResultEnd = "AMISTIO_BRAIN_GENERATION_RESULT_END";
|
|
4376
4383
|
var assistantAnswerStart = "AMISTIO_ASSISTANT_ANSWER_START";
|
|
@@ -4385,6 +4392,7 @@ var appEvaluationStart = "AMISTIO_APP_EVALUATION_START";
|
|
|
4385
4392
|
var appEvaluationEnd = "AMISTIO_APP_EVALUATION_END";
|
|
4386
4393
|
var projectContextRefreshStart = "AMISTIO_PROJECT_CONTEXT_REFRESH_START";
|
|
4387
4394
|
var projectContextRefreshEnd = "AMISTIO_PROJECT_CONTEXT_REFRESH_END";
|
|
4395
|
+
var validProjectContextSliceKinds = /* @__PURE__ */ new Set(["overview", "architecture", "domain", "data", "api", "frontend", "backend", "cli", "workflow", "operations", "security", "testing", "unknown"]);
|
|
4388
4396
|
var validProjectContextEntityTypes = /* @__PURE__ */ new Set(["project", "system", "component", "domain", "tool", "decision", "feature", "risk", "team", "workflow", "unknown"]);
|
|
4389
4397
|
var validProjectContextRelationTypes = /* @__PURE__ */ new Set(["uses", "depends_on", "decides", "supersedes", "touches", "blocks", "implements", "mentions"]);
|
|
4390
4398
|
function createWorkExecutionPrompt(workItem, context) {
|
|
@@ -4489,10 +4497,12 @@ function createProjectContextRefreshPrompt(workItem, context) {
|
|
|
4489
4497
|
"## Mapping Requirements",
|
|
4490
4498
|
"",
|
|
4491
4499
|
"- Create slices for architecture, domain, data, API, frontend, backend, CLI, workflows, operations, security, and testing when those surfaces exist.",
|
|
4500
|
+
"- Use only these exact singular slice kind values: overview, architecture, domain, data, api, frontend, backend, cli, workflow, operations, security, testing, unknown.",
|
|
4492
4501
|
"- Capture entities and relations that explain how the app is put together and where future work should look first.",
|
|
4493
4502
|
"- Prefer summaries, repository-relative paths, short citations, tags, and freshness status over raw source excerpts.",
|
|
4494
4503
|
"- Mark stale or missing areas explicitly instead of guessing.",
|
|
4495
4504
|
"- Keep repoPaths repository-relative; never include /absolute paths or ../ traversal.",
|
|
4505
|
+
"- If local inspection prints a path inside this checkout, convert it to the repository-relative path before returning JSON.",
|
|
4496
4506
|
"",
|
|
4497
4507
|
"## Data Safety",
|
|
4498
4508
|
"",
|
|
@@ -4949,7 +4959,7 @@ function parseAppEvaluationScanResult(output) {
|
|
|
4949
4959
|
const parsed = JSON.parse(stripJsonFence(payload));
|
|
4950
4960
|
return appEvaluationScanResultSchema.parse(parsed);
|
|
4951
4961
|
}
|
|
4952
|
-
function parseProjectContextRefreshResult(output) {
|
|
4962
|
+
function parseProjectContextRefreshResult(output, options = {}) {
|
|
4953
4963
|
const start = output.indexOf(projectContextRefreshStart);
|
|
4954
4964
|
const end = output.indexOf(projectContextRefreshEnd, start + projectContextRefreshStart.length);
|
|
4955
4965
|
if (start === -1 || end === -1 || end <= start) {
|
|
@@ -4957,7 +4967,8 @@ function parseProjectContextRefreshResult(output) {
|
|
|
4957
4967
|
}
|
|
4958
4968
|
const payload = output.slice(start + projectContextRefreshStart.length, end).trim();
|
|
4959
4969
|
const parsed = JSON.parse(stripJsonFence(payload));
|
|
4960
|
-
|
|
4970
|
+
const normalized = normalizeProjectContextRefreshPaths(normalizeProjectContextRefreshEnums(parsed), options);
|
|
4971
|
+
return projectContextRefreshResultSchema.parse(normalized);
|
|
4961
4972
|
}
|
|
4962
4973
|
function projectContextRefreshSubmissionFailureSummary(result) {
|
|
4963
4974
|
if (result.refresh.status !== "failed" && result.workItem.status !== "failed") {
|
|
@@ -5026,6 +5037,16 @@ function normalizeProjectContextRefreshEnums(value) {
|
|
|
5026
5037
|
return value;
|
|
5027
5038
|
}
|
|
5028
5039
|
const normalized = { ...value };
|
|
5040
|
+
if (Array.isArray(normalized.slices)) {
|
|
5041
|
+
normalized.slices = normalized.slices.map((slice) => {
|
|
5042
|
+
if (!isObjectRecord(slice)) {
|
|
5043
|
+
return slice;
|
|
5044
|
+
}
|
|
5045
|
+
const normalizedSlice = { ...slice };
|
|
5046
|
+
normalizedSlice.kind = normalizeProjectContextSliceKind(slice.kind);
|
|
5047
|
+
return normalizedSlice;
|
|
5048
|
+
});
|
|
5049
|
+
}
|
|
5029
5050
|
if (Array.isArray(normalized.entities)) {
|
|
5030
5051
|
normalized.entities = normalized.entities.map((entity) => {
|
|
5031
5052
|
if (!isObjectRecord(entity)) {
|
|
@@ -5048,6 +5069,94 @@ function normalizeProjectContextRefreshEnums(value) {
|
|
|
5048
5069
|
}
|
|
5049
5070
|
return normalized;
|
|
5050
5071
|
}
|
|
5072
|
+
function normalizeProjectContextSliceKind(value) {
|
|
5073
|
+
if (typeof value !== "string") {
|
|
5074
|
+
return "unknown";
|
|
5075
|
+
}
|
|
5076
|
+
const normalized = value.trim().toLowerCase();
|
|
5077
|
+
if (validProjectContextSliceKinds.has(normalized)) {
|
|
5078
|
+
return normalized;
|
|
5079
|
+
}
|
|
5080
|
+
if (normalized.endsWith("s")) {
|
|
5081
|
+
const singular = normalized.slice(0, -1);
|
|
5082
|
+
if (validProjectContextSliceKinds.has(singular)) {
|
|
5083
|
+
return singular;
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
return "unknown";
|
|
5087
|
+
}
|
|
5088
|
+
function normalizeProjectContextRefreshPaths(value, options) {
|
|
5089
|
+
if (!isObjectRecord(value)) {
|
|
5090
|
+
return value;
|
|
5091
|
+
}
|
|
5092
|
+
const normalized = { ...value };
|
|
5093
|
+
if (Array.isArray(normalized.slices)) {
|
|
5094
|
+
normalized.slices = normalized.slices.map((slice) => normalizeProjectContextSlicePaths(slice, options));
|
|
5095
|
+
}
|
|
5096
|
+
if (Array.isArray(normalized.entities)) {
|
|
5097
|
+
normalized.entities = normalized.entities.map((entity) => normalizeProjectContextCitationPaths(entity, options));
|
|
5098
|
+
}
|
|
5099
|
+
if (Array.isArray(normalized.relations)) {
|
|
5100
|
+
normalized.relations = normalized.relations.map((relation) => normalizeProjectContextCitationPaths(relation, options));
|
|
5101
|
+
}
|
|
5102
|
+
return normalized;
|
|
5103
|
+
}
|
|
5104
|
+
function normalizeProjectContextSlicePaths(value, options) {
|
|
5105
|
+
if (!isObjectRecord(value)) {
|
|
5106
|
+
return value;
|
|
5107
|
+
}
|
|
5108
|
+
const normalized = normalizeProjectContextCitationPaths(value, options);
|
|
5109
|
+
if (Array.isArray(normalized.repoPaths)) {
|
|
5110
|
+
normalized.repoPaths = normalized.repoPaths.map((repoPath) => typeof repoPath === "string" ? normalizeProjectContextRepoPath(repoPath, options) : repoPath);
|
|
5111
|
+
}
|
|
5112
|
+
return normalized;
|
|
5113
|
+
}
|
|
5114
|
+
function normalizeProjectContextCitationPaths(value, options) {
|
|
5115
|
+
if (!isObjectRecord(value)) {
|
|
5116
|
+
return value;
|
|
5117
|
+
}
|
|
5118
|
+
const normalized = { ...value };
|
|
5119
|
+
if (Array.isArray(normalized.citations)) {
|
|
5120
|
+
normalized.citations = normalized.citations.map((citation) => {
|
|
5121
|
+
if (!isObjectRecord(citation)) {
|
|
5122
|
+
return citation;
|
|
5123
|
+
}
|
|
5124
|
+
const normalizedCitation = { ...citation };
|
|
5125
|
+
if (typeof normalizedCitation.repoPath === "string") {
|
|
5126
|
+
normalizedCitation.repoPath = normalizeProjectContextRepoPath(normalizedCitation.repoPath, options);
|
|
5127
|
+
}
|
|
5128
|
+
return normalizedCitation;
|
|
5129
|
+
});
|
|
5130
|
+
}
|
|
5131
|
+
return normalized;
|
|
5132
|
+
}
|
|
5133
|
+
function normalizeProjectContextRepoPath(value, options) {
|
|
5134
|
+
const trimmed = value.trim();
|
|
5135
|
+
if (!trimmed || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(trimmed) || /^file:/i.test(trimmed) || /^[A-Za-z]:($|[^\\/])/.test(trimmed)) {
|
|
5136
|
+
throwUnsafeProjectContextPath();
|
|
5137
|
+
}
|
|
5138
|
+
const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") || path10.isAbsolute(trimmed) || path10.win32.isAbsolute(trimmed);
|
|
5139
|
+
if (!absolute) {
|
|
5140
|
+
return normalizeRelativeProjectContextPath(trimmed);
|
|
5141
|
+
}
|
|
5142
|
+
if (!options.repositoryRoot) {
|
|
5143
|
+
throwUnsafeProjectContextPath();
|
|
5144
|
+
}
|
|
5145
|
+
const useWindowsPathRules = path10.win32.isAbsolute(trimmed) && !trimmed.startsWith("/");
|
|
5146
|
+
const relativePath = useWindowsPathRules ? path10.win32.relative(path10.win32.resolve(options.repositoryRoot), path10.win32.resolve(trimmed)) : path10.relative(path10.resolve(options.repositoryRoot), path10.resolve(trimmed));
|
|
5147
|
+
return normalizeRelativeProjectContextPath(relativePath);
|
|
5148
|
+
}
|
|
5149
|
+
function normalizeRelativeProjectContextPath(value) {
|
|
5150
|
+
const normalized = value.trim().replace(/\\/g, "/");
|
|
5151
|
+
const segments = normalized.split("/").filter((segment) => segment.length > 0 && segment !== ".");
|
|
5152
|
+
if (!segments.length || normalized.startsWith("/") || normalized === "~" || normalized.startsWith("~/") || /^[A-Za-z]:/.test(normalized) || segments.includes("..")) {
|
|
5153
|
+
throwUnsafeProjectContextPath();
|
|
5154
|
+
}
|
|
5155
|
+
return segments.join("/");
|
|
5156
|
+
}
|
|
5157
|
+
function throwUnsafeProjectContextPath() {
|
|
5158
|
+
throw new Error("Project context refresh contains an unsafe repository path.");
|
|
5159
|
+
}
|
|
5051
5160
|
function normalizeProjectContextEntityType(value) {
|
|
5052
5161
|
if (typeof value !== "string") {
|
|
5053
5162
|
return "unknown";
|
|
@@ -5240,7 +5349,7 @@ function roundNumber(value, digits) {
|
|
|
5240
5349
|
import { execFile as execFile4 } from "node:child_process";
|
|
5241
5350
|
import { createHash as createHash6 } from "node:crypto";
|
|
5242
5351
|
import { readdir as readdir4, readFile as readFile8, stat as stat4 } from "node:fs/promises";
|
|
5243
|
-
import
|
|
5352
|
+
import path11 from "node:path";
|
|
5244
5353
|
import { promisify as promisify4 } from "node:util";
|
|
5245
5354
|
var execFileAsync4 = promisify4(execFile4);
|
|
5246
5355
|
var defaultMaxFileKb = 256;
|
|
@@ -5259,12 +5368,12 @@ var documentFolderByType = {
|
|
|
5259
5368
|
workflow: "docs/workflows"
|
|
5260
5369
|
};
|
|
5261
5370
|
async function inspectLocalRepository(rootDir, defaultBranch) {
|
|
5262
|
-
const requestedRoot =
|
|
5371
|
+
const requestedRoot = path11.resolve(rootDir);
|
|
5263
5372
|
const root = await runGit2(["-C", requestedRoot, "rev-parse", "--show-toplevel"]).catch(() => requestedRoot);
|
|
5264
5373
|
const detectedBranch = await runGit2(["-C", root, "symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => defaultBranch);
|
|
5265
5374
|
const originUrl = await runGit2(["-C", root, "remote", "get-url", "origin"]).catch(() => void 0);
|
|
5266
5375
|
const parsedCloneUrl = originUrl ? parseOptionalOriginCloneUrl(originUrl) : void 0;
|
|
5267
|
-
const repoName = (parsedCloneUrl?.repoName ??
|
|
5376
|
+
const repoName = (parsedCloneUrl?.repoName ?? path11.basename(root)) || "repository";
|
|
5268
5377
|
const fingerprintSeed = parsedCloneUrl ? `origin:${parsedCloneUrl.normalizedKey}` : `repo:${repoName}:${detectedBranch || defaultBranch}`;
|
|
5269
5378
|
return {
|
|
5270
5379
|
rootDir: root,
|
|
@@ -5276,7 +5385,7 @@ async function inspectLocalRepository(rootDir, defaultBranch) {
|
|
|
5276
5385
|
};
|
|
5277
5386
|
}
|
|
5278
5387
|
async function scanLegacyDocuments(options) {
|
|
5279
|
-
const rootDir =
|
|
5388
|
+
const rootDir = path11.resolve(options.rootDir);
|
|
5280
5389
|
const maxBytes = (options.maxFileKb ?? defaultMaxFileKb) * 1024;
|
|
5281
5390
|
const skipped = [];
|
|
5282
5391
|
const candidates = [];
|
|
@@ -5296,7 +5405,7 @@ async function scanLegacyDocuments(options) {
|
|
|
5296
5405
|
skipped.push({ repoPath, reason: "excluded" });
|
|
5297
5406
|
continue;
|
|
5298
5407
|
}
|
|
5299
|
-
const fullPath =
|
|
5408
|
+
const fullPath = path11.join(rootDir, ...repoPath.split("/"));
|
|
5300
5409
|
const fileStat = await stat4(fullPath).catch(() => void 0);
|
|
5301
5410
|
if (!fileStat?.isFile()) {
|
|
5302
5411
|
skipped.push({ repoPath, reason: "unreadable" });
|
|
@@ -5398,8 +5507,8 @@ async function listRepositoryPaths(rootDir) {
|
|
|
5398
5507
|
async function walkRepository(rootDir, directory, files) {
|
|
5399
5508
|
const entries = await readdir4(directory, { withFileTypes: true }).catch(() => []);
|
|
5400
5509
|
for (const entry of entries) {
|
|
5401
|
-
const fullPath =
|
|
5402
|
-
const repoPath = normalizeRepoPath4(
|
|
5510
|
+
const fullPath = path11.join(directory, entry.name);
|
|
5511
|
+
const repoPath = normalizeRepoPath4(path11.relative(rootDir, fullPath));
|
|
5403
5512
|
if (entry.isDirectory()) {
|
|
5404
5513
|
if (!excludedDirectoryNames.has(entry.name)) {
|
|
5405
5514
|
await walkRepository(rootDir, fullPath, files);
|
|
@@ -5465,9 +5574,9 @@ function uniqueDestinationPath(basePath, sourcePath, usedPaths) {
|
|
|
5465
5574
|
usedPaths.add(basePath);
|
|
5466
5575
|
return basePath;
|
|
5467
5576
|
}
|
|
5468
|
-
const extension =
|
|
5469
|
-
const directory =
|
|
5470
|
-
const basename =
|
|
5577
|
+
const extension = path11.posix.extname(basePath) || ".md";
|
|
5578
|
+
const directory = path11.posix.dirname(basePath);
|
|
5579
|
+
const basename = path11.posix.basename(basePath, extension);
|
|
5471
5580
|
const uniquePath = `${directory}/${basename}-${hashText(sourcePath, 8)}${extension}`;
|
|
5472
5581
|
usedPaths.add(uniquePath);
|
|
5473
5582
|
return uniquePath;
|
|
@@ -5486,7 +5595,7 @@ function inferTitle2(content, repoPath) {
|
|
|
5486
5595
|
if (heading) return heading;
|
|
5487
5596
|
const htmlHeading = body.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
|
|
5488
5597
|
if (htmlHeading) return htmlHeading;
|
|
5489
|
-
const basename =
|
|
5598
|
+
const basename = path11.posix.basename(repoPath, path11.posix.extname(repoPath)).replace(/[-_]+/g, " ").trim();
|
|
5490
5599
|
return titleCase(basename || "Imported Document");
|
|
5491
5600
|
}
|
|
5492
5601
|
function stripFrontmatter(content) {
|
|
@@ -5520,7 +5629,7 @@ async function runGit2(args) {
|
|
|
5520
5629
|
|
|
5521
5630
|
// src/runner-actions.ts
|
|
5522
5631
|
import { spawn as spawn4 } from "node:child_process";
|
|
5523
|
-
import
|
|
5632
|
+
import path12 from "node:path";
|
|
5524
5633
|
function buildBackgroundRunnerArgs(options) {
|
|
5525
5634
|
const args = [
|
|
5526
5635
|
"run",
|
|
@@ -5530,7 +5639,7 @@ function buildBackgroundRunnerArgs(options) {
|
|
|
5530
5639
|
"--runner-id",
|
|
5531
5640
|
options.runnerId,
|
|
5532
5641
|
"--root",
|
|
5533
|
-
|
|
5642
|
+
path12.resolve(options.root),
|
|
5534
5643
|
"--session",
|
|
5535
5644
|
options.session,
|
|
5536
5645
|
"--interval-seconds",
|
|
@@ -5648,7 +5757,7 @@ function truncateProcessOutput(value) {
|
|
|
5648
5757
|
// src/git-worktree.ts
|
|
5649
5758
|
import { execFile as execFile5 } from "node:child_process";
|
|
5650
5759
|
import { mkdir as mkdir9, stat as stat5 } from "node:fs/promises";
|
|
5651
|
-
import
|
|
5760
|
+
import path13 from "node:path";
|
|
5652
5761
|
import { promisify as promisify5 } from "node:util";
|
|
5653
5762
|
var execFileAsync5 = promisify5(execFile5);
|
|
5654
5763
|
function needsGitWorktreeIsolation(workItem) {
|
|
@@ -5677,7 +5786,7 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
|
|
|
5677
5786
|
await assertExistingWorktree(worktreePath, identity.branch);
|
|
5678
5787
|
return { ...identity, baseRevision, worktreePath };
|
|
5679
5788
|
}
|
|
5680
|
-
await mkdir9(
|
|
5789
|
+
await mkdir9(path13.dirname(worktreePath), { recursive: true });
|
|
5681
5790
|
const branchExists = await gitCommandSucceeds(repoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${identity.branch}`]);
|
|
5682
5791
|
const worktreeArgs = branchExists ? ["worktree", "add", worktreePath, identity.branch] : ["worktree", "add", "-b", identity.branch, worktreePath, baseRevision];
|
|
5683
5792
|
await gitOutput(repoRoot, worktreeArgs).catch((error) => {
|
|
@@ -5686,9 +5795,9 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
|
|
|
5686
5795
|
return { ...identity, baseRevision, worktreePath };
|
|
5687
5796
|
}
|
|
5688
5797
|
function localWorktreePath(repoRoot, worktreeKey) {
|
|
5689
|
-
const repoName =
|
|
5798
|
+
const repoName = path13.basename(repoRoot);
|
|
5690
5799
|
const worktreeSlug = worktreeKey.split("/").filter(Boolean).pop() ?? "work";
|
|
5691
|
-
return
|
|
5800
|
+
return path13.join(path13.dirname(repoRoot), `${repoName}.worktrees`, worktreeSlug);
|
|
5692
5801
|
}
|
|
5693
5802
|
async function assertExistingWorktree(worktreePath, branch) {
|
|
5694
5803
|
await gitOutput(worktreePath, ["rev-parse", "--is-inside-work-tree"]);
|
|
@@ -5735,7 +5844,7 @@ function errorMessage2(error) {
|
|
|
5735
5844
|
|
|
5736
5845
|
// src/implementation-handoff.ts
|
|
5737
5846
|
import { execFile as execFile6 } from "node:child_process";
|
|
5738
|
-
import
|
|
5847
|
+
import path14 from "node:path";
|
|
5739
5848
|
import { promisify as promisify6 } from "node:util";
|
|
5740
5849
|
var execFileAsync6 = promisify6(execFile6);
|
|
5741
5850
|
async function completeImplementationHandoff(input) {
|
|
@@ -5821,7 +5930,7 @@ async function cleanupWorktree(run, input) {
|
|
|
5821
5930
|
return { status: "failed", message: "Cleanup skipped because the worktree is not clean after PR handoff." };
|
|
5822
5931
|
}
|
|
5823
5932
|
try {
|
|
5824
|
-
await gitOutput2(run, input.primaryRepoRoot ||
|
|
5933
|
+
await gitOutput2(run, input.primaryRepoRoot || path14.dirname(input.worktreePath), ["worktree", "remove", input.worktreePath]);
|
|
5825
5934
|
return { status: "completed" };
|
|
5826
5935
|
} catch (error) {
|
|
5827
5936
|
return { status: "failed", message: `Cleanup failed: ${safeErrorMessage(error)}` };
|
|
@@ -6310,7 +6419,7 @@ program.command("run").description("Claim and run approved Amistio work locally"
|
|
|
6310
6419
|
projectId: context.metadata.amistioProjectId,
|
|
6311
6420
|
repositoryLinkId: context.metadata.repositoryLinkId,
|
|
6312
6421
|
runnerId,
|
|
6313
|
-
rootDir:
|
|
6422
|
+
rootDir: path15.resolve(options.root),
|
|
6314
6423
|
apiUrl: options.apiUrl,
|
|
6315
6424
|
args: buildBackgroundRunnerArgs(resolvedOptions)
|
|
6316
6425
|
});
|
|
@@ -6482,7 +6591,7 @@ runnerService.command("install").description("Install a user-level startup servi
|
|
|
6482
6591
|
projectId: context.metadata.amistioProjectId,
|
|
6483
6592
|
repositoryLinkId: context.metadata.repositoryLinkId,
|
|
6484
6593
|
runnerId,
|
|
6485
|
-
rootDir:
|
|
6594
|
+
rootDir: path15.resolve(options.root),
|
|
6486
6595
|
apiUrl: options.apiUrl,
|
|
6487
6596
|
args,
|
|
6488
6597
|
platform
|
|
@@ -6954,6 +7063,7 @@ async function runNextWorkItem({
|
|
|
6954
7063
|
return await finalizeProjectContextRefreshWork({
|
|
6955
7064
|
apiClient,
|
|
6956
7065
|
durationMs: Date.now() - startedAt,
|
|
7066
|
+
executionRoot,
|
|
6957
7067
|
projectId,
|
|
6958
7068
|
repositoryLinkId,
|
|
6959
7069
|
runnerId,
|
|
@@ -7808,6 +7918,7 @@ ${toolResult.stderr}`);
|
|
|
7808
7918
|
async function finalizeProjectContextRefreshWork({
|
|
7809
7919
|
apiClient,
|
|
7810
7920
|
durationMs,
|
|
7921
|
+
executionRoot,
|
|
7811
7922
|
projectId,
|
|
7812
7923
|
repositoryLinkId,
|
|
7813
7924
|
runnerId,
|
|
@@ -7822,7 +7933,7 @@ async function finalizeProjectContextRefreshWork({
|
|
|
7822
7933
|
if (toolResult.exitCode === 0) {
|
|
7823
7934
|
try {
|
|
7824
7935
|
refreshResult = parseProjectContextRefreshResult(`${toolResult.stdout}
|
|
7825
|
-
${toolResult.stderr}
|
|
7936
|
+
${toolResult.stderr}`, { repositoryRoot: executionRoot });
|
|
7826
7937
|
} catch (error) {
|
|
7827
7938
|
refreshError = errorMessage3(error);
|
|
7828
7939
|
}
|
|
@@ -8199,7 +8310,7 @@ function parseReasoningEffort(value) {
|
|
|
8199
8310
|
throw new Error(`Expected reasoning effort auto, low, medium, high, or xhigh; received ${value}.`);
|
|
8200
8311
|
}
|
|
8201
8312
|
function inferRepoName(root) {
|
|
8202
|
-
return
|
|
8313
|
+
return path15.basename(path15.resolve(root)) || "repository";
|
|
8203
8314
|
}
|
|
8204
8315
|
function createRepoFingerprint(accountId, projectId, repositoryLinkId) {
|
|
8205
8316
|
return createHash7("sha256").update(`${accountId}:${projectId}:${repositoryLinkId}`).digest("hex");
|