@jentrix/cli 0.5.12 → 0.5.13
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/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/commands/jentrix-align.md +2 -1
- package/claude-plugin/hooks/hooks.json +5 -5
- package/codex-plugin/plugins/jentrix/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/plugins/jentrix/hooks/hooks.json +7 -7
- package/dist/main.js +123 -35
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jentrix",
|
|
3
3
|
"description": "Connect this Claude Code session to a Jentrix project: /jentrix-connect binds the current session (trusted lifecycle hooks supply the session id), /jentrix-align runs the MVP alignment wizard, /jentrix-status and /jentrix-end wrap the same session operations. Business logic lives in the Jentrix CLI — removing this plugin leaves `jentrix session attach` as the universal fallback.",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1"
|
|
5
5
|
}
|
|
@@ -59,7 +59,8 @@ and do NOT answer any question yourself.
|
|
|
59
59
|
and move with
|
|
60
60
|
`jentrix task move --task <taskId> --to-column-id <columnId>`. Use only
|
|
61
61
|
the columns the board actually has — never invent a status. `/jentrix-end`
|
|
62
|
-
moves it to
|
|
62
|
+
moves it to the In review column when the work is genuinely finished —
|
|
63
|
+
the terminal move is the operator's Accept, never yours. A
|
|
63
64
|
board that never moves is a board that lies about what is in flight.
|
|
64
65
|
11. If align wrote `./.mcp.json`, relay that line too: MCP servers load at
|
|
65
66
|
session start, so the tools in THIS session still point wherever they
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "M20.1 \u00a715.1 \u2014 lifecycle bridge: hooks append their structured stdin payload (session_id, transcript_path, cwd) to the local session context file via `stacks-runner session-hook`. argv carries only the
|
|
2
|
+
"description": "M20.1 \u00a715.1 \u2014 lifecycle bridge: hooks append their structured stdin payload (session_id, transcript_path, cwd) to the local session context file via `stacks-runner session-hook`. argv carries only the provider and event name (the runner resolves the directory cross-platform \u2014 STA-131: a literal $HOME never expands in Windows hook commands) \u2014 never credentials or transcript content. PreCompact/PostCompact additionally run `jentrix session snapshot`, which FOLLOWS THE CAPTURE CONSENT: capture ON preserves the transcript range about to leave the model's context; capture OFF (the MVP default) records the compaction boundary and NO content, because `capture: \"off\"` was disclosed as typed artifacts only, no transcript. Preservation is never distillation \u2014 a hook has no model turn; /jentrix-checkpoint does that. Compaction-path hooks carry an explicit 10s timeout (STA-51): they run inside the operator's /compact, and a slow artifact push must delay it by seconds, not the 60s default.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "stacks-runner session-hook --
|
|
9
|
+
"command": "stacks-runner session-hook --provider claude --event SessionStart"
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
12
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "stacks-runner session-hook --
|
|
19
|
+
"command": "stacks-runner session-hook --provider claude --event SessionEnd"
|
|
20
20
|
}
|
|
21
21
|
]
|
|
22
22
|
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"hooks": [
|
|
27
27
|
{
|
|
28
28
|
"type": "command",
|
|
29
|
-
"command": "stacks-runner session-hook --
|
|
29
|
+
"command": "stacks-runner session-hook --provider claude --event PreCompact",
|
|
30
30
|
"timeout": 10
|
|
31
31
|
},
|
|
32
32
|
{
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"hooks": [
|
|
43
43
|
{
|
|
44
44
|
"type": "command",
|
|
45
|
-
"command": "stacks-runner session-hook --
|
|
45
|
+
"command": "stacks-runner session-hook --provider claude --event PostCompact",
|
|
46
46
|
"timeout": 10
|
|
47
47
|
},
|
|
48
48
|
{
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "stacks-runner session-hook --
|
|
9
|
+
"command": "stacks-runner session-hook --provider codex --event SessionStart"
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
12
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "stacks-runner session-hook --
|
|
19
|
+
"command": "stacks-runner session-hook --provider codex --event UserPromptSubmit"
|
|
20
20
|
}
|
|
21
21
|
]
|
|
22
22
|
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"hooks": [
|
|
27
27
|
{
|
|
28
28
|
"type": "command",
|
|
29
|
-
"command": "stacks-runner session-hook --
|
|
29
|
+
"command": "stacks-runner session-hook --provider codex --event PostToolUse"
|
|
30
30
|
}
|
|
31
31
|
]
|
|
32
32
|
}
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"hooks": [
|
|
37
37
|
{
|
|
38
38
|
"type": "command",
|
|
39
|
-
"command": "stacks-runner session-hook --
|
|
39
|
+
"command": "stacks-runner session-hook --provider codex --event Stop"
|
|
40
40
|
}
|
|
41
41
|
]
|
|
42
42
|
}
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"hooks": [
|
|
47
47
|
{
|
|
48
48
|
"type": "command",
|
|
49
|
-
"command": "stacks-runner session-hook --
|
|
49
|
+
"command": "stacks-runner session-hook --provider codex --event PreCompact",
|
|
50
50
|
"timeout": 10
|
|
51
51
|
},
|
|
52
52
|
{
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"hooks": [
|
|
63
63
|
{
|
|
64
64
|
"type": "command",
|
|
65
|
-
"command": "stacks-runner session-hook --
|
|
65
|
+
"command": "stacks-runner session-hook --provider codex --event PostCompact",
|
|
66
66
|
"timeout": 10
|
|
67
67
|
},
|
|
68
68
|
{
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"hooks": [
|
|
79
79
|
{
|
|
80
80
|
"type": "command",
|
|
81
|
-
"command": "stacks-runner session-hook --
|
|
81
|
+
"command": "stacks-runner session-hook --provider codex --event SessionEnd"
|
|
82
82
|
}
|
|
83
83
|
]
|
|
84
84
|
}
|
package/dist/main.js
CHANGED
|
@@ -20962,7 +20962,7 @@ function refreshAccessToken(input) {
|
|
|
20962
20962
|
|
|
20963
20963
|
// src/client.ts
|
|
20964
20964
|
var CLI_NAME = "stacks-cli";
|
|
20965
|
-
var CLI_VERSION = "0.5.
|
|
20965
|
+
var CLI_VERSION = "0.5.13";
|
|
20966
20966
|
var DEAD_TOKEN_MESSAGE = "authentication failed (HTTP 401): the token is dead or expired \u2014 mint a new PAT at /account/tokens on your Jentrix server and update STACKS_TOKEN (or --token / the config file).";
|
|
20967
20967
|
var RELOGIN_MESSAGE = "OAuth session expired and could not be refreshed \u2014 run `jentrix login` to sign in again.";
|
|
20968
20968
|
function originOf2(url2) {
|
|
@@ -21909,6 +21909,30 @@ import {
|
|
|
21909
21909
|
writeFileSync as writeFileSync2
|
|
21910
21910
|
} from "node:fs";
|
|
21911
21911
|
import { dirname as dirname2, join as join2 } from "node:path";
|
|
21912
|
+
|
|
21913
|
+
// src/retry.ts
|
|
21914
|
+
async function withRateLimitRetry(fn, options) {
|
|
21915
|
+
const { maxRetries, maxWaitSeconds, sleep, now } = options;
|
|
21916
|
+
const start = now();
|
|
21917
|
+
let attempt = 0;
|
|
21918
|
+
for (; ; ) {
|
|
21919
|
+
const result = await fn();
|
|
21920
|
+
const envelope = envelopeOfResult(result);
|
|
21921
|
+
if (envelope?.error.code !== "RATE_LIMITED") return result;
|
|
21922
|
+
const retryAfter = envelope.error.retryAfterSeconds;
|
|
21923
|
+
if (typeof retryAfter !== "number" || !Number.isFinite(retryAfter)) {
|
|
21924
|
+
return result;
|
|
21925
|
+
}
|
|
21926
|
+
if (retryAfter < 0) return result;
|
|
21927
|
+
if (attempt >= maxRetries) return result;
|
|
21928
|
+
const elapsedMs = now() - start;
|
|
21929
|
+
if (elapsedMs + retryAfter * 1e3 > maxWaitSeconds * 1e3) return result;
|
|
21930
|
+
await sleep(retryAfter * 1e3);
|
|
21931
|
+
attempt += 1;
|
|
21932
|
+
}
|
|
21933
|
+
}
|
|
21934
|
+
|
|
21935
|
+
// src/commands/session.ts
|
|
21912
21936
|
var LEGACY_MARKER_KEY = "__v1__";
|
|
21913
21937
|
function isMarker(value) {
|
|
21914
21938
|
return typeof value === "object" && value !== null && typeof value.sessionId === "string";
|
|
@@ -22029,9 +22053,28 @@ function isRecord5(value) {
|
|
|
22029
22053
|
async function callStructured(caller, name, args) {
|
|
22030
22054
|
return call(caller, name, args);
|
|
22031
22055
|
}
|
|
22056
|
+
var ToolCallError = class extends Error {
|
|
22057
|
+
constructor(message, code = null) {
|
|
22058
|
+
super(message);
|
|
22059
|
+
this.code = code;
|
|
22060
|
+
}
|
|
22061
|
+
code;
|
|
22062
|
+
};
|
|
22032
22063
|
async function call(caller, name, args) {
|
|
22033
|
-
const result = await
|
|
22064
|
+
const result = await withRateLimitRetry(
|
|
22065
|
+
() => caller.callTool({ name, arguments: args }),
|
|
22066
|
+
{
|
|
22067
|
+
maxRetries: 2,
|
|
22068
|
+
maxWaitSeconds: 60,
|
|
22069
|
+
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
|
|
22070
|
+
now: Date.now
|
|
22071
|
+
}
|
|
22072
|
+
);
|
|
22034
22073
|
if (isRecord5(result) && result.isError === true) {
|
|
22074
|
+
const envelope = envelopeOfResult(result);
|
|
22075
|
+
if (envelope) {
|
|
22076
|
+
throw new ToolCallError(envelope.error.message, envelope.error.code);
|
|
22077
|
+
}
|
|
22035
22078
|
let message = "tool call failed";
|
|
22036
22079
|
if (Array.isArray(result.content)) {
|
|
22037
22080
|
const text = result.content.find(
|
|
@@ -22046,7 +22089,7 @@ async function call(caller, name, args) {
|
|
|
22046
22089
|
}
|
|
22047
22090
|
}
|
|
22048
22091
|
}
|
|
22049
|
-
throw new
|
|
22092
|
+
throw new ToolCallError(message);
|
|
22050
22093
|
}
|
|
22051
22094
|
return isRecord5(result) && isRecord5(result.structuredContent) ? result.structuredContent : {};
|
|
22052
22095
|
}
|
|
@@ -23573,6 +23616,26 @@ function registerSessionCommand(program3, deps2, onExit2) {
|
|
|
23573
23616
|
}
|
|
23574
23617
|
|
|
23575
23618
|
// src/commands/align.ts
|
|
23619
|
+
async function resolveWorkspaceFlag(caller, wanted, pinned) {
|
|
23620
|
+
const listed = await callStructured(caller, "list_workspaces", {});
|
|
23621
|
+
const rows = listed.workspaces ?? [];
|
|
23622
|
+
const match = rows.find(
|
|
23623
|
+
(ws) => ws.id === wanted || ws.slug === wanted.toLowerCase()
|
|
23624
|
+
);
|
|
23625
|
+
if (!match) {
|
|
23626
|
+
throw new UsageError(
|
|
23627
|
+
`--workspace ${wanted} matches none of your workspaces (slugs: ${rows.map((ws) => ws.slug).filter(Boolean).join(", ") || "none visible"})`,
|
|
23628
|
+
EXIT_CODES.NOT_FOUND
|
|
23629
|
+
);
|
|
23630
|
+
}
|
|
23631
|
+
if (pinned && pinned.id !== match.id) {
|
|
23632
|
+
throw new UsageError(
|
|
23633
|
+
`--workspace ${wanted} conflicts with this token's pinned workspace (${pinned.id})`,
|
|
23634
|
+
EXIT_CODES.FORBIDDEN
|
|
23635
|
+
);
|
|
23636
|
+
}
|
|
23637
|
+
return match.id;
|
|
23638
|
+
}
|
|
23576
23639
|
var MAX_WORK_ITEMS = 15;
|
|
23577
23640
|
async function projectBoards(caller, projectId) {
|
|
23578
23641
|
const project = await callStructured(caller, "get_project", { projectId });
|
|
@@ -24364,10 +24427,17 @@ async function runAlign(flags, deps2) {
|
|
|
24364
24427
|
let pendingCreateProject = null;
|
|
24365
24428
|
if (flags.newTask) workItem = `__new__:${flags.newTask}`;
|
|
24366
24429
|
if (flags.newProject && flags.newProject.trim()) {
|
|
24367
|
-
|
|
24430
|
+
let workspaceId = catalog.chosenWorkspaceId ?? catalog.pinnedWorkspace?.id ?? null;
|
|
24431
|
+
if (flags.workspace?.trim()) {
|
|
24432
|
+
workspaceId = await resolveWorkspaceFlag(
|
|
24433
|
+
caller,
|
|
24434
|
+
flags.workspace.trim(),
|
|
24435
|
+
catalog.pinnedWorkspace ?? null
|
|
24436
|
+
);
|
|
24437
|
+
}
|
|
24368
24438
|
if (!workspaceId) {
|
|
24369
24439
|
throw new UsageError(
|
|
24370
|
-
"--new-project needs a resolved workspace (a workspace-pinned token
|
|
24440
|
+
"--new-project needs a resolved workspace (a workspace-pinned token, a repo-matched candidate, or --workspace <id-or-slug>) \u2014 none resolved here"
|
|
24371
24441
|
);
|
|
24372
24442
|
}
|
|
24373
24443
|
pendingCreateProject = {
|
|
@@ -24694,6 +24764,9 @@ function registerAlignCommand(program3, deps2, onExit2) {
|
|
|
24694
24764
|
).option("--project <id-or-slug>", "project to align to").option(
|
|
24695
24765
|
"--new-project <name>",
|
|
24696
24766
|
"create a project in the resolved workspace (seeds a board + repo/board links), then align to it"
|
|
24767
|
+
).option(
|
|
24768
|
+
"--workspace <id-or-slug>",
|
|
24769
|
+
"workspace for --new-project when neither a pinned token nor a repo match resolves one (fresh checkout, non-interactive)"
|
|
24697
24770
|
).option("--task <taskId>", "existing work item to align to").option(
|
|
24698
24771
|
"--new-task <title>",
|
|
24699
24772
|
"create a task (existing ops core) and align to it"
|
|
@@ -24944,7 +25017,20 @@ async function basisBlock(refs, deps2) {
|
|
|
24944
25017
|
});
|
|
24945
25018
|
const record3 = result.artifact ?? result;
|
|
24946
25019
|
titles.set(id, String(record3.title ?? ""));
|
|
24947
|
-
} catch {
|
|
25020
|
+
} catch (error2) {
|
|
25021
|
+
const code = error2 instanceof ToolCallError ? error2.code : null;
|
|
25022
|
+
if (code === "RATE_LIMITED") {
|
|
25023
|
+
throw new UsageError(
|
|
25024
|
+
`--basis ${id} could not be verified \u2014 the server is rate limiting reads; the ref may be fine. Retry the push shortly.`,
|
|
25025
|
+
EXIT_CODES.RATE_LIMITED
|
|
25026
|
+
);
|
|
25027
|
+
}
|
|
25028
|
+
if (code && code !== "NOT_FOUND" && code !== "FORBIDDEN") {
|
|
25029
|
+
throw new UsageError(
|
|
25030
|
+
`--basis ${id} could not be verified (${code}) \u2014 the ref may be fine. Retry the push.`,
|
|
25031
|
+
EXIT_CODES.INTERNAL
|
|
25032
|
+
);
|
|
25033
|
+
}
|
|
24948
25034
|
throw new UsageError(
|
|
24949
25035
|
`--basis ${id} does not resolve to an artifact you can read \u2014 push the context first (\`jentrix push context\`), or pass a URL`,
|
|
24950
25036
|
EXIT_CODES.NOT_FOUND
|
|
@@ -25023,7 +25109,7 @@ async function offerCardMint(kind, payload, flags, deps2, sessionId = null) {
|
|
|
25023
25109
|
sessionId
|
|
25024
25110
|
});
|
|
25025
25111
|
deps2.writeOut(
|
|
25026
|
-
`Minted ${minted.key ?? minted.id} on ${board.name} \xB7 artifact linked \xB7 ${flags.blocks ? "BLOCKS" : "RELATES_TO"} ${payload.taskId}`
|
|
25112
|
+
`Minted ${minted.key ?? minted.id} on ${board.name} \xB7 ${minted.artifactLinked ? "artifact linked" : "artifact NOT linked (see note)"} \xB7 ${flags.blocks ? "BLOCKS" : "RELATES_TO"} ${payload.taskId}`
|
|
25027
25113
|
);
|
|
25028
25114
|
} catch (error2) {
|
|
25029
25115
|
deps2.writeErr(
|
|
@@ -25068,7 +25154,7 @@ async function mintCard(deps2, input) {
|
|
|
25068
25154
|
idempotencyKey: `mint-${input.artifactId}`
|
|
25069
25155
|
});
|
|
25070
25156
|
const issueId = String(created.id);
|
|
25071
|
-
await (deps2.fetchImpl ?? fetch)(
|
|
25157
|
+
const linkResponse = await (deps2.fetchImpl ?? fetch)(
|
|
25072
25158
|
new URL(taskTarget(issueId).path, stacksBaseUrlOf(target.url)),
|
|
25073
25159
|
{
|
|
25074
25160
|
method: "POST",
|
|
@@ -25080,16 +25166,29 @@ async function mintCard(deps2, input) {
|
|
|
25080
25166
|
body: JSON.stringify({ refArtifactId: input.artifactId })
|
|
25081
25167
|
}
|
|
25082
25168
|
);
|
|
25169
|
+
const artifactLinked = linkResponse.ok;
|
|
25170
|
+
if (!artifactLinked) {
|
|
25171
|
+
deps2.writeErr(
|
|
25172
|
+
`note: minted the card but linking artifact ${input.artifactId} to it failed (HTTP ${linkResponse.status}) \u2014 link it by hand: jentrix push ${pushKindForNoun(input.noun)} --task ${issueId} --ref ${input.artifactId}`
|
|
25173
|
+
);
|
|
25174
|
+
}
|
|
25083
25175
|
await callStructured(caller, "add_task_link", {
|
|
25084
25176
|
fromTaskId: issueId,
|
|
25085
25177
|
toTaskId: input.anchorTaskId,
|
|
25086
25178
|
kind: input.blocks ? "BLOCKS" : "RELATES_TO"
|
|
25087
25179
|
});
|
|
25088
|
-
return {
|
|
25180
|
+
return {
|
|
25181
|
+
id: issueId,
|
|
25182
|
+
key: created.key,
|
|
25183
|
+
artifactLinked
|
|
25184
|
+
};
|
|
25089
25185
|
},
|
|
25090
25186
|
input.sessionId ? { sessionId: input.sessionId } : void 0
|
|
25091
25187
|
);
|
|
25092
25188
|
}
|
|
25189
|
+
function pushKindForNoun(noun) {
|
|
25190
|
+
return noun === "Gap" ? "gap" : noun === "Issue" ? "issue" : "findings";
|
|
25191
|
+
}
|
|
25093
25192
|
async function runMintIssue(flags, deps2) {
|
|
25094
25193
|
try {
|
|
25095
25194
|
let sessionId = null;
|
|
@@ -25135,9 +25234,10 @@ async function runMintIssue(flags, deps2) {
|
|
|
25135
25234
|
issueKey: minted.key ?? null,
|
|
25136
25235
|
boardId: board.id,
|
|
25137
25236
|
artifactId: flags.artifact,
|
|
25237
|
+
artifactLinked: minted.artifactLinked,
|
|
25138
25238
|
relatedTaskId: flags.fromTask,
|
|
25139
25239
|
linkKind: flags.blocks ? "BLOCKS" : "RELATES_TO"
|
|
25140
|
-
}) : `Minted ${minted.key ?? minted.id} on ${board.name} \xB7 artifact linked \xB7 ${flags.blocks ? "BLOCKS" : "RELATES_TO"} ${flags.fromTask}`
|
|
25240
|
+
}) : `Minted ${minted.key ?? minted.id} on ${board.name} \xB7 ${minted.artifactLinked ? "artifact linked" : "artifact NOT linked (see note)"} \xB7 ${flags.blocks ? "BLOCKS" : "RELATES_TO"} ${flags.fromTask}`
|
|
25141
25241
|
);
|
|
25142
25242
|
return 0;
|
|
25143
25243
|
} catch (error2) {
|
|
@@ -26020,28 +26120,6 @@ function cellText(value) {
|
|
|
26020
26120
|
return text;
|
|
26021
26121
|
}
|
|
26022
26122
|
|
|
26023
|
-
// src/retry.ts
|
|
26024
|
-
async function withRateLimitRetry(fn, options) {
|
|
26025
|
-
const { maxRetries, maxWaitSeconds, sleep, now } = options;
|
|
26026
|
-
const start = now();
|
|
26027
|
-
let attempt = 0;
|
|
26028
|
-
for (; ; ) {
|
|
26029
|
-
const result = await fn();
|
|
26030
|
-
const envelope = envelopeOfResult(result);
|
|
26031
|
-
if (envelope?.error.code !== "RATE_LIMITED") return result;
|
|
26032
|
-
const retryAfter = envelope.error.retryAfterSeconds;
|
|
26033
|
-
if (typeof retryAfter !== "number" || !Number.isFinite(retryAfter)) {
|
|
26034
|
-
return result;
|
|
26035
|
-
}
|
|
26036
|
-
if (retryAfter < 0) return result;
|
|
26037
|
-
if (attempt >= maxRetries) return result;
|
|
26038
|
-
const elapsedMs = now() - start;
|
|
26039
|
-
if (elapsedMs + retryAfter * 1e3 > maxWaitSeconds * 1e3) return result;
|
|
26040
|
-
await sleep(retryAfter * 1e3);
|
|
26041
|
-
attempt += 1;
|
|
26042
|
-
}
|
|
26043
|
-
}
|
|
26044
|
-
|
|
26045
26123
|
// src/call.ts
|
|
26046
26124
|
async function callTool(client, name, args, options) {
|
|
26047
26125
|
let result;
|
|
@@ -27577,7 +27655,10 @@ function renderOperatorIdentity(operator, workspaceName) {
|
|
|
27577
27655
|
}
|
|
27578
27656
|
async function executable(path) {
|
|
27579
27657
|
try {
|
|
27580
|
-
await fs.access(
|
|
27658
|
+
await fs.access(
|
|
27659
|
+
path,
|
|
27660
|
+
process.platform === "win32" ? constants.F_OK : constants.X_OK
|
|
27661
|
+
);
|
|
27581
27662
|
return await fs.realpath(path);
|
|
27582
27663
|
} catch {
|
|
27583
27664
|
return null;
|
|
@@ -28302,8 +28383,15 @@ async function runSetupCommand(flags, deps2) {
|
|
|
28302
28383
|
}
|
|
28303
28384
|
const codex = await deps2.resolveCodex();
|
|
28304
28385
|
if (codex) await registerCodexMcp(deps2, codex, pending);
|
|
28305
|
-
if (flags.git !== false && deps2.
|
|
28306
|
-
|
|
28386
|
+
if (flags.git !== false && deps2.cwd() !== deps2.homeDir()) {
|
|
28387
|
+
if (deps2.isInteractive) {
|
|
28388
|
+
await bootstrapRepository(deps2);
|
|
28389
|
+
} else if (!await deps2.resolveGit() || (await deps2.git(["rev-parse", "--is-inside-work-tree"], deps2.cwd())).code !== 0) {
|
|
28390
|
+
say(
|
|
28391
|
+
deps2,
|
|
28392
|
+
"note: skipped the repository offer (not an interactive terminal) \u2014 this folder is not a git work tree, and align requires one. Run `git init` here first."
|
|
28393
|
+
);
|
|
28394
|
+
}
|
|
28307
28395
|
}
|
|
28308
28396
|
say(deps2, "");
|
|
28309
28397
|
if (pending.failedPlugins.length) {
|