ai-hero-cli 0.2.15 → 0.3.1
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/bin.cjs +749 -1052
- package/package.json +1 -1
package/bin.cjs
CHANGED
|
@@ -82665,6 +82665,68 @@ var isMailbox = (u) => hasProperty(u, TypeId29);
|
|
|
82665
82665
|
var make66 = make65;
|
|
82666
82666
|
var toChannel4 = toChannel3;
|
|
82667
82667
|
|
|
82668
|
+
// src/git-service/errors.ts
|
|
82669
|
+
var NotAGitRepoError = class extends Data_exports.TaggedError(
|
|
82670
|
+
"NotAGitRepoError"
|
|
82671
|
+
) {
|
|
82672
|
+
};
|
|
82673
|
+
var FailedToFetchUpstreamError = class extends Data_exports.TaggedError(
|
|
82674
|
+
"FailedToFetchUpstreamError"
|
|
82675
|
+
) {
|
|
82676
|
+
};
|
|
82677
|
+
var FailedToCreateBranchError = class extends Data_exports.TaggedError(
|
|
82678
|
+
"FailedToCreateBranchError"
|
|
82679
|
+
) {
|
|
82680
|
+
};
|
|
82681
|
+
var FailedToDeleteBranchError = class extends Data_exports.TaggedError(
|
|
82682
|
+
"FailedToDeleteBranchError"
|
|
82683
|
+
) {
|
|
82684
|
+
};
|
|
82685
|
+
var FailedToFetchOriginError = class extends Data_exports.TaggedError(
|
|
82686
|
+
"FailedToFetchOriginError"
|
|
82687
|
+
) {
|
|
82688
|
+
};
|
|
82689
|
+
var InvalidRefError = class extends Data_exports.TaggedError(
|
|
82690
|
+
"InvalidRefError"
|
|
82691
|
+
) {
|
|
82692
|
+
};
|
|
82693
|
+
var FailedToTrackBranchError = class extends Data_exports.TaggedError(
|
|
82694
|
+
"FailedToTrackBranchError"
|
|
82695
|
+
) {
|
|
82696
|
+
};
|
|
82697
|
+
var FailedToResetError = class extends Data_exports.TaggedError(
|
|
82698
|
+
"FailedToResetError"
|
|
82699
|
+
) {
|
|
82700
|
+
};
|
|
82701
|
+
var FailedToCommitError = class extends Data_exports.TaggedError(
|
|
82702
|
+
"FailedToCommitError"
|
|
82703
|
+
) {
|
|
82704
|
+
};
|
|
82705
|
+
var CherryPickConflictError = class extends Data_exports.TaggedError(
|
|
82706
|
+
"CherryPickConflictError"
|
|
82707
|
+
) {
|
|
82708
|
+
};
|
|
82709
|
+
var FailedToCheckoutError = class extends Data_exports.TaggedError(
|
|
82710
|
+
"FailedToCheckoutError"
|
|
82711
|
+
) {
|
|
82712
|
+
};
|
|
82713
|
+
var FailedToPushError = class extends Data_exports.TaggedError(
|
|
82714
|
+
"FailedToPushError"
|
|
82715
|
+
) {
|
|
82716
|
+
};
|
|
82717
|
+
var FailedToFetchError = class extends Data_exports.TaggedError(
|
|
82718
|
+
"FailedToFetchError"
|
|
82719
|
+
) {
|
|
82720
|
+
};
|
|
82721
|
+
var MergeConflictError = class extends Data_exports.TaggedError(
|
|
82722
|
+
"MergeConflictError"
|
|
82723
|
+
) {
|
|
82724
|
+
};
|
|
82725
|
+
var RebaseConflictError = class extends Data_exports.TaggedError(
|
|
82726
|
+
"RebaseConflictError"
|
|
82727
|
+
) {
|
|
82728
|
+
};
|
|
82729
|
+
|
|
82668
82730
|
// node_modules/.pnpm/@effect+platform@0.90.2_effect@3.17.7/node_modules/@effect/platform/dist/esm/Command.js
|
|
82669
82731
|
var Command_exports2 = {};
|
|
82670
82732
|
__export(Command_exports2, {
|
|
@@ -83975,11 +84037,6 @@ __export(NodeFileSystem_exports2, {
|
|
|
83975
84037
|
layer: () => layer13
|
|
83976
84038
|
});
|
|
83977
84039
|
var layer13 = layer6;
|
|
83978
|
-
var VALID_UPSTREAM_PATTERNS = [
|
|
83979
|
-
"mattpocock",
|
|
83980
|
-
"ai-hero-dev",
|
|
83981
|
-
"total-typescript"
|
|
83982
|
-
];
|
|
83983
84040
|
var GitServiceConfig = class extends Context_exports.Tag(
|
|
83984
84041
|
"GitServiceConfig"
|
|
83985
84042
|
)() {
|
|
@@ -83990,716 +84047,427 @@ var defaultGitServiceConfigLayer = Layer_exports.succeed(
|
|
|
83990
84047
|
cwd: process.cwd()
|
|
83991
84048
|
})
|
|
83992
84049
|
);
|
|
83993
|
-
var
|
|
83994
|
-
|
|
83995
|
-
)
|
|
83996
|
-
}
|
|
83997
|
-
|
|
83998
|
-
|
|
83999
|
-
) {
|
|
84000
|
-
|
|
84001
|
-
|
|
84002
|
-
|
|
84003
|
-
|
|
84004
|
-
|
|
84005
|
-
|
|
84006
|
-
|
|
84007
|
-
)
|
|
84008
|
-
|
|
84009
|
-
|
|
84010
|
-
|
|
84011
|
-
|
|
84012
|
-
|
|
84013
|
-
|
|
84014
|
-
|
|
84015
|
-
)
|
|
84016
|
-
|
|
84017
|
-
|
|
84018
|
-
|
|
84019
|
-
)
|
|
84020
|
-
|
|
84021
|
-
|
|
84022
|
-
"
|
|
84023
|
-
|
|
84024
|
-
|
|
84025
|
-
|
|
84026
|
-
|
|
84027
|
-
|
|
84028
|
-
|
|
84029
|
-
|
|
84030
|
-
|
|
84031
|
-
) {
|
|
84032
|
-
|
|
84033
|
-
|
|
84034
|
-
|
|
84035
|
-
)
|
|
84036
|
-
};
|
|
84037
|
-
|
|
84038
|
-
|
|
84039
|
-
)
|
|
84040
|
-
|
|
84041
|
-
|
|
84042
|
-
|
|
84043
|
-
|
|
84044
|
-
|
|
84045
|
-
|
|
84046
|
-
|
|
84047
|
-
|
|
84048
|
-
|
|
84049
|
-
|
|
84050
|
-
|
|
84051
|
-
) {
|
|
84052
|
-
|
|
84053
|
-
|
|
84054
|
-
|
|
84055
|
-
|
|
84056
|
-
|
|
84057
|
-
|
|
84058
|
-
|
|
84059
|
-
) {
|
|
84060
|
-
}
|
|
84061
|
-
|
|
84062
|
-
|
|
84063
|
-
|
|
84064
|
-
|
|
84065
|
-
const
|
|
84066
|
-
|
|
84067
|
-
|
|
84068
|
-
|
|
84069
|
-
)(
|
|
84070
|
-
|
|
84071
|
-
|
|
84072
|
-
|
|
84050
|
+
var mapExitCode = (exitCode3, makeError) => {
|
|
84051
|
+
if (exitCode3 !== 0) {
|
|
84052
|
+
return Effect_exports.fail(makeError(exitCode3));
|
|
84053
|
+
}
|
|
84054
|
+
return Effect_exports.void;
|
|
84055
|
+
};
|
|
84056
|
+
var makeGitService = Effect_exports.gen(function* () {
|
|
84057
|
+
const config3 = yield* GitServiceConfig;
|
|
84058
|
+
const fs = yield* FileSystem_exports.FileSystem;
|
|
84059
|
+
const runCommandWithString = Effect_exports.fn(
|
|
84060
|
+
"runCommandWithString"
|
|
84061
|
+
)(function* (...commandArgs) {
|
|
84062
|
+
const cwd = config3.cwd;
|
|
84063
|
+
const command2 = Command_exports2.make(...commandArgs).pipe(
|
|
84064
|
+
Command_exports2.workingDirectory(cwd)
|
|
84065
|
+
);
|
|
84066
|
+
return (yield* Command_exports2.string(command2)).trim();
|
|
84067
|
+
});
|
|
84068
|
+
const runCommandWithExitCode = Effect_exports.fn(
|
|
84069
|
+
"runCommandWithExitCode"
|
|
84070
|
+
)(function* (...commandArgs) {
|
|
84071
|
+
const cwd = config3.cwd;
|
|
84072
|
+
const command2 = Command_exports2.make(...commandArgs).pipe(
|
|
84073
|
+
Command_exports2.workingDirectory(cwd),
|
|
84074
|
+
Command_exports2.stdout("inherit"),
|
|
84075
|
+
Command_exports2.stderr("inherit")
|
|
84076
|
+
);
|
|
84077
|
+
return yield* Command_exports2.exitCode(command2);
|
|
84078
|
+
});
|
|
84079
|
+
const resetHard = Effect_exports.fn("resetHard")(function* (sha) {
|
|
84080
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84081
|
+
"git",
|
|
84082
|
+
"reset",
|
|
84083
|
+
"--hard",
|
|
84084
|
+
sha
|
|
84085
|
+
);
|
|
84086
|
+
yield* mapExitCode(
|
|
84087
|
+
exitCode3,
|
|
84088
|
+
(code2) => new FailedToResetError({
|
|
84089
|
+
sha,
|
|
84090
|
+
message: `Failed to reset to ${sha} (exit code: ${code2})`
|
|
84091
|
+
})
|
|
84092
|
+
);
|
|
84093
|
+
});
|
|
84094
|
+
const resetHead = Effect_exports.fn("resetHead")(function* () {
|
|
84095
|
+
yield* runCommandWithExitCode("git", "reset", "HEAD^");
|
|
84096
|
+
});
|
|
84097
|
+
const restoreStaged = Effect_exports.fn(
|
|
84098
|
+
"restoreStaged"
|
|
84099
|
+
)(function* () {
|
|
84100
|
+
yield* runCommandWithExitCode(
|
|
84101
|
+
"git",
|
|
84102
|
+
"restore",
|
|
84103
|
+
"--staged",
|
|
84104
|
+
"."
|
|
84105
|
+
);
|
|
84106
|
+
});
|
|
84107
|
+
return {
|
|
84108
|
+
fetchOrigin: Effect_exports.fn("fetchOrigin")(function* () {
|
|
84109
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84110
|
+
"git",
|
|
84111
|
+
"fetch",
|
|
84112
|
+
"origin"
|
|
84113
|
+
);
|
|
84114
|
+
yield* mapExitCode(
|
|
84115
|
+
exitCode3,
|
|
84116
|
+
(code2) => new FailedToFetchOriginError({
|
|
84117
|
+
message: `Failed to fetch from origin (exit code: ${code2})`
|
|
84118
|
+
})
|
|
84119
|
+
);
|
|
84120
|
+
}),
|
|
84121
|
+
revParse: Effect_exports.fn("revParse")(function* (ref) {
|
|
84122
|
+
const result = yield* runCommandWithString(
|
|
84123
|
+
"git",
|
|
84124
|
+
"rev-parse",
|
|
84125
|
+
ref
|
|
84126
|
+
).pipe(
|
|
84127
|
+
Effect_exports.catchAll(
|
|
84128
|
+
() => Effect_exports.fail(
|
|
84129
|
+
new InvalidRefError({
|
|
84130
|
+
ref,
|
|
84131
|
+
message: `Failed to resolve ref: ${ref}`
|
|
84132
|
+
})
|
|
84133
|
+
)
|
|
84134
|
+
)
|
|
84135
|
+
);
|
|
84136
|
+
return result;
|
|
84137
|
+
}),
|
|
84138
|
+
revListCount: Effect_exports.fn("revListCount")(function* (from, to) {
|
|
84139
|
+
const countOutput = yield* runCommandWithString(
|
|
84140
|
+
"git",
|
|
84141
|
+
"rev-list",
|
|
84142
|
+
"--count",
|
|
84143
|
+
`${from}..${to}`
|
|
84144
|
+
);
|
|
84145
|
+
return parseInt(countOutput, 10);
|
|
84146
|
+
}),
|
|
84147
|
+
getStatusShort: Effect_exports.fn("getStatusShort")(
|
|
84148
|
+
function* () {
|
|
84149
|
+
return yield* runCommandWithString(
|
|
84150
|
+
"git",
|
|
84151
|
+
"status",
|
|
84152
|
+
"--short"
|
|
84073
84153
|
);
|
|
84074
|
-
|
|
84075
|
-
|
|
84076
|
-
|
|
84077
|
-
|
|
84078
|
-
|
|
84079
|
-
|
|
84080
|
-
|
|
84081
|
-
|
|
84082
|
-
|
|
84083
|
-
|
|
84154
|
+
}
|
|
84155
|
+
),
|
|
84156
|
+
resetHard,
|
|
84157
|
+
resetHead,
|
|
84158
|
+
restoreStaged,
|
|
84159
|
+
applyAsUnstagedChanges: Effect_exports.fn(
|
|
84160
|
+
"applyAsUnstagedChanges"
|
|
84161
|
+
)(function* (sha) {
|
|
84162
|
+
yield* resetHard(sha);
|
|
84163
|
+
yield* resetHead();
|
|
84164
|
+
yield* restoreStaged();
|
|
84165
|
+
}),
|
|
84166
|
+
stageAll: Effect_exports.fn("stageAll")(function* () {
|
|
84167
|
+
yield* runCommandWithExitCode("git", "add", ".");
|
|
84168
|
+
}),
|
|
84169
|
+
commit: Effect_exports.fn("commit")(function* (message) {
|
|
84170
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84171
|
+
"git",
|
|
84172
|
+
"commit",
|
|
84173
|
+
"-m",
|
|
84174
|
+
message
|
|
84175
|
+
);
|
|
84176
|
+
yield* mapExitCode(
|
|
84177
|
+
exitCode3,
|
|
84178
|
+
(code2) => new FailedToCommitError({
|
|
84179
|
+
message: `Failed to commit (exit code: ${code2})`
|
|
84180
|
+
})
|
|
84181
|
+
);
|
|
84182
|
+
}),
|
|
84183
|
+
cherryPick: Effect_exports.fn("cherryPick")(function* (range4) {
|
|
84184
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84185
|
+
"git",
|
|
84186
|
+
"cherry-pick",
|
|
84187
|
+
range4
|
|
84188
|
+
);
|
|
84189
|
+
yield* mapExitCode(
|
|
84190
|
+
exitCode3,
|
|
84191
|
+
() => new CherryPickConflictError({
|
|
84192
|
+
range: range4,
|
|
84193
|
+
message: `Cherry-pick conflict on range ${range4}`
|
|
84194
|
+
})
|
|
84195
|
+
);
|
|
84196
|
+
}),
|
|
84197
|
+
cherryPickContinue: Effect_exports.fn("cherryPickContinue")(
|
|
84198
|
+
function* () {
|
|
84199
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84200
|
+
"git",
|
|
84201
|
+
"cherry-pick",
|
|
84202
|
+
"--continue"
|
|
84084
84203
|
);
|
|
84085
|
-
|
|
84086
|
-
|
|
84087
|
-
|
|
84088
|
-
|
|
84089
|
-
|
|
84090
|
-
|
|
84204
|
+
yield* mapExitCode(
|
|
84205
|
+
exitCode3,
|
|
84206
|
+
() => new CherryPickConflictError({
|
|
84207
|
+
range: "continue",
|
|
84208
|
+
message: "Cherry-pick continue encountered conflicts"
|
|
84209
|
+
})
|
|
84210
|
+
);
|
|
84211
|
+
}
|
|
84212
|
+
),
|
|
84213
|
+
cherryPickAbort: Effect_exports.fn("cherryPickAbort")(
|
|
84214
|
+
function* () {
|
|
84215
|
+
yield* runCommandWithExitCode(
|
|
84091
84216
|
"git",
|
|
84092
|
-
"
|
|
84093
|
-
"
|
|
84217
|
+
"cherry-pick",
|
|
84218
|
+
"--abort"
|
|
84094
84219
|
);
|
|
84095
|
-
|
|
84096
|
-
|
|
84097
|
-
|
|
84098
|
-
|
|
84099
|
-
|
|
84100
|
-
|
|
84101
|
-
|
|
84102
|
-
|
|
84103
|
-
|
|
84104
|
-
|
|
84105
|
-
|
|
84106
|
-
|
|
84107
|
-
|
|
84108
|
-
|
|
84109
|
-
|
|
84110
|
-
|
|
84111
|
-
|
|
84112
|
-
|
|
84113
|
-
|
|
84114
|
-
|
|
84115
|
-
|
|
84220
|
+
}
|
|
84221
|
+
),
|
|
84222
|
+
checkout: Effect_exports.fn("checkout")(function* (branch) {
|
|
84223
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84224
|
+
"git",
|
|
84225
|
+
"checkout",
|
|
84226
|
+
branch
|
|
84227
|
+
);
|
|
84228
|
+
yield* mapExitCode(
|
|
84229
|
+
exitCode3,
|
|
84230
|
+
(code2) => new FailedToCheckoutError({
|
|
84231
|
+
branch,
|
|
84232
|
+
message: `Failed to checkout ${branch} (exit code: ${code2})`
|
|
84233
|
+
})
|
|
84234
|
+
);
|
|
84235
|
+
}),
|
|
84236
|
+
pushForceWithLease: Effect_exports.fn("pushForceWithLease")(
|
|
84237
|
+
function* (remote, branch) {
|
|
84238
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84239
|
+
"git",
|
|
84240
|
+
"push",
|
|
84241
|
+
remote,
|
|
84242
|
+
branch,
|
|
84243
|
+
"--force-with-lease"
|
|
84244
|
+
);
|
|
84245
|
+
yield* mapExitCode(
|
|
84246
|
+
exitCode3,
|
|
84247
|
+
(code2) => new FailedToPushError({
|
|
84248
|
+
remote,
|
|
84249
|
+
branch,
|
|
84250
|
+
message: `Failed to push ${branch} to ${remote} (exit code: ${code2})`
|
|
84116
84251
|
})
|
|
84117
84252
|
);
|
|
84118
|
-
}
|
|
84253
|
+
}
|
|
84254
|
+
),
|
|
84255
|
+
checkoutNewBranch: Effect_exports.fn("checkoutNewBranch")(
|
|
84256
|
+
function* (branchName) {
|
|
84257
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84258
|
+
"git",
|
|
84259
|
+
"checkout",
|
|
84260
|
+
"-b",
|
|
84261
|
+
branchName
|
|
84262
|
+
);
|
|
84263
|
+
yield* mapExitCode(
|
|
84264
|
+
exitCode3,
|
|
84265
|
+
(code2) => new FailedToCreateBranchError({
|
|
84266
|
+
branchName,
|
|
84267
|
+
message: `Failed to create branch ${branchName} (exit code: ${code2})`
|
|
84268
|
+
})
|
|
84269
|
+
);
|
|
84270
|
+
}
|
|
84271
|
+
),
|
|
84272
|
+
getLogOnelineReverse: Effect_exports.fn("getLogOnelineReverse")(
|
|
84273
|
+
function* (range4) {
|
|
84274
|
+
return yield* runCommandWithString(
|
|
84275
|
+
"git",
|
|
84276
|
+
"log",
|
|
84277
|
+
"--oneline",
|
|
84278
|
+
"--reverse",
|
|
84279
|
+
range4
|
|
84280
|
+
);
|
|
84281
|
+
}
|
|
84282
|
+
),
|
|
84283
|
+
getLogOneline: Effect_exports.fn("getLogOneline")(function* (branch) {
|
|
84284
|
+
return yield* runCommandWithString(
|
|
84285
|
+
"git",
|
|
84286
|
+
"log",
|
|
84287
|
+
branch,
|
|
84288
|
+
"--oneline"
|
|
84289
|
+
);
|
|
84290
|
+
}),
|
|
84291
|
+
checkoutNewBranchAt: Effect_exports.fn("checkoutNewBranchAt")(
|
|
84292
|
+
function* (branchName, sha) {
|
|
84293
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84294
|
+
"git",
|
|
84295
|
+
"checkout",
|
|
84296
|
+
"-b",
|
|
84297
|
+
branchName,
|
|
84298
|
+
sha
|
|
84299
|
+
);
|
|
84300
|
+
yield* mapExitCode(
|
|
84301
|
+
exitCode3,
|
|
84302
|
+
(code2) => new FailedToCreateBranchError({
|
|
84303
|
+
branchName,
|
|
84304
|
+
message: `Failed to create branch ${branchName} at ${sha} (exit code: ${code2})`
|
|
84305
|
+
})
|
|
84306
|
+
);
|
|
84307
|
+
}
|
|
84308
|
+
),
|
|
84309
|
+
deleteBranch: Effect_exports.fn("deleteBranch")(function* (branchName) {
|
|
84310
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84311
|
+
"git",
|
|
84312
|
+
"branch",
|
|
84313
|
+
"-D",
|
|
84314
|
+
branchName
|
|
84315
|
+
);
|
|
84316
|
+
yield* mapExitCode(
|
|
84317
|
+
exitCode3,
|
|
84318
|
+
(code2) => new FailedToDeleteBranchError({
|
|
84319
|
+
branchName,
|
|
84320
|
+
message: `Failed to delete branch ${branchName} (exit code: ${code2})`
|
|
84321
|
+
})
|
|
84322
|
+
);
|
|
84323
|
+
}),
|
|
84324
|
+
fetch: Effect_exports.fn("fetch")(function* (remote, branch) {
|
|
84325
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84326
|
+
"git",
|
|
84327
|
+
"fetch",
|
|
84328
|
+
remote,
|
|
84329
|
+
branch
|
|
84330
|
+
);
|
|
84331
|
+
yield* mapExitCode(
|
|
84332
|
+
exitCode3,
|
|
84333
|
+
(code2) => new FailedToFetchError({
|
|
84334
|
+
remote,
|
|
84335
|
+
branch,
|
|
84336
|
+
message: `Failed to fetch ${branch} from ${remote} (exit code: ${code2})`
|
|
84337
|
+
})
|
|
84338
|
+
);
|
|
84339
|
+
}),
|
|
84340
|
+
merge: Effect_exports.fn("merge")(function* (ref) {
|
|
84341
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84342
|
+
"git",
|
|
84343
|
+
"merge",
|
|
84344
|
+
ref,
|
|
84345
|
+
"--allow-unrelated-histories"
|
|
84346
|
+
);
|
|
84347
|
+
yield* mapExitCode(
|
|
84348
|
+
exitCode3,
|
|
84349
|
+
() => new MergeConflictError({
|
|
84350
|
+
ref,
|
|
84351
|
+
message: `Merge conflicts detected when merging ${ref}`
|
|
84352
|
+
})
|
|
84353
|
+
);
|
|
84354
|
+
}),
|
|
84355
|
+
rebase: Effect_exports.fn("rebase")(function* (onto) {
|
|
84356
|
+
const exitCode3 = yield* runCommandWithExitCode(
|
|
84357
|
+
"git",
|
|
84358
|
+
"rebase",
|
|
84359
|
+
onto
|
|
84360
|
+
);
|
|
84361
|
+
yield* mapExitCode(
|
|
84362
|
+
exitCode3,
|
|
84363
|
+
() => new RebaseConflictError({
|
|
84364
|
+
onto,
|
|
84365
|
+
message: `Rebase conflicts detected when rebasing onto ${onto}`
|
|
84366
|
+
})
|
|
84367
|
+
);
|
|
84368
|
+
}),
|
|
84369
|
+
ensureIsGitRepo: Effect_exports.fn("ensureIsGitRepo")(
|
|
84370
|
+
function* () {
|
|
84371
|
+
const cwd = config3.cwd;
|
|
84372
|
+
const gitDirPath = path6__namespace.join(cwd, ".git");
|
|
84373
|
+
const exists4 = yield* fs.exists(gitDirPath);
|
|
84374
|
+
if (!exists4) {
|
|
84375
|
+
return yield* new NotAGitRepoError({
|
|
84376
|
+
path: cwd,
|
|
84377
|
+
message: `Current directory is not a git repository: ${cwd}`
|
|
84378
|
+
});
|
|
84379
|
+
}
|
|
84380
|
+
}
|
|
84381
|
+
),
|
|
84382
|
+
getUncommittedChanges: Effect_exports.fn(
|
|
84383
|
+
"getUncommittedChanges"
|
|
84384
|
+
)(function* () {
|
|
84385
|
+
const statusOutput = yield* runCommandWithString(
|
|
84386
|
+
"git",
|
|
84387
|
+
"status",
|
|
84388
|
+
"--porcelain"
|
|
84389
|
+
);
|
|
84119
84390
|
return {
|
|
84120
|
-
|
|
84121
|
-
|
|
84122
|
-
|
|
84123
|
-
|
|
84124
|
-
|
|
84125
|
-
|
|
84126
|
-
|
|
84127
|
-
|
|
84128
|
-
|
|
84129
|
-
|
|
84130
|
-
|
|
84131
|
-
|
|
84132
|
-
|
|
84133
|
-
|
|
84134
|
-
|
|
84135
|
-
|
|
84136
|
-
|
|
84137
|
-
|
|
84138
|
-
|
|
84139
|
-
|
|
84140
|
-
|
|
84141
|
-
|
|
84142
|
-
|
|
84143
|
-
|
|
84144
|
-
|
|
84145
|
-
|
|
84146
|
-
|
|
84147
|
-
|
|
84148
|
-
|
|
84149
|
-
|
|
84150
|
-
|
|
84151
|
-
|
|
84152
|
-
|
|
84153
|
-
|
|
84154
|
-
|
|
84155
|
-
|
|
84156
|
-
|
|
84157
|
-
|
|
84158
|
-
|
|
84159
|
-
|
|
84160
|
-
|
|
84161
|
-
|
|
84162
|
-
|
|
84163
|
-
|
|
84164
|
-
|
|
84165
|
-
|
|
84166
|
-
|
|
84167
|
-
|
|
84168
|
-
|
|
84169
|
-
|
|
84170
|
-
|
|
84171
|
-
|
|
84172
|
-
|
|
84173
|
-
|
|
84174
|
-
|
|
84175
|
-
|
|
84176
|
-
|
|
84177
|
-
|
|
84178
|
-
|
|
84179
|
-
|
|
84180
|
-
|
|
84181
|
-
|
|
84182
|
-
|
|
84183
|
-
|
|
84184
|
-
}),
|
|
84185
|
-
/**
|
|
84186
|
-
* Gets the short status output from git.
|
|
84187
|
-
* Uses `git status --short` which outputs one line per file with
|
|
84188
|
-
* a two-letter status code (e.g., "M " for modified, "??" for untracked).
|
|
84189
|
-
*
|
|
84190
|
-
* @returns The short status output as a string
|
|
84191
|
-
*/
|
|
84192
|
-
getStatusShort: Effect_exports.fn("getStatusShort")(
|
|
84193
|
-
function* () {
|
|
84194
|
-
return yield* runCommandWithString(
|
|
84195
|
-
"git",
|
|
84196
|
-
"status",
|
|
84197
|
-
"--short"
|
|
84198
|
-
);
|
|
84199
|
-
}
|
|
84200
|
-
),
|
|
84201
|
-
/**
|
|
84202
|
-
* Performs a hard reset to the specified SHA.
|
|
84203
|
-
* WARNING: This discards all uncommitted changes and moves HEAD to the target.
|
|
84204
|
-
* Any uncommitted work in the working directory and staging area will be lost.
|
|
84205
|
-
*
|
|
84206
|
-
* @param sha - The commit SHA to reset to
|
|
84207
|
-
* @returns Effect that succeeds when reset completes
|
|
84208
|
-
* @throws FailedToResetError if the reset fails
|
|
84209
|
-
*/
|
|
84210
|
-
resetHard: Effect_exports.fn("resetHard")(function* (sha) {
|
|
84211
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84212
|
-
"git",
|
|
84213
|
-
"reset",
|
|
84214
|
-
"--hard",
|
|
84215
|
-
sha
|
|
84216
|
-
);
|
|
84217
|
-
if (exitCode3 !== 0) {
|
|
84218
|
-
return yield* Effect_exports.fail(
|
|
84219
|
-
new FailedToResetError({
|
|
84220
|
-
sha,
|
|
84221
|
-
message: `Failed to reset to ${sha} (exit code: ${exitCode3})`
|
|
84222
|
-
})
|
|
84223
|
-
);
|
|
84224
|
-
}
|
|
84225
|
-
}),
|
|
84226
|
-
/**
|
|
84227
|
-
* Performs a soft reset of the last commit (git reset HEAD^).
|
|
84228
|
-
* This undoes the last commit but keeps all changes in the working directory.
|
|
84229
|
-
* The changes from the undone commit become unstaged modifications.
|
|
84230
|
-
*
|
|
84231
|
-
* @returns Effect that succeeds when reset completes
|
|
84232
|
-
*/
|
|
84233
|
-
resetHead: Effect_exports.fn("resetHead")(function* () {
|
|
84234
|
-
yield* runCommandWithExitCode("git", "reset", "HEAD^");
|
|
84235
|
-
}),
|
|
84236
|
-
/**
|
|
84237
|
-
* Unstages all staged files (git restore --staged .).
|
|
84238
|
-
* This moves files from the staging area back to unstaged state
|
|
84239
|
-
* without discarding any modifications.
|
|
84240
|
-
*
|
|
84241
|
-
* @returns Effect that succeeds when restore completes
|
|
84242
|
-
*/
|
|
84243
|
-
restoreStaged: Effect_exports.fn("restoreStaged")(function* () {
|
|
84244
|
-
yield* runCommandWithExitCode(
|
|
84245
|
-
"git",
|
|
84246
|
-
"restore",
|
|
84247
|
-
"--staged",
|
|
84248
|
-
"."
|
|
84249
|
-
);
|
|
84250
|
-
}),
|
|
84251
|
-
/**
|
|
84252
|
-
* Stages all changes in the working directory (git add .).
|
|
84253
|
-
* This adds all modified, deleted, and new files to the staging area.
|
|
84254
|
-
*
|
|
84255
|
-
* @returns Effect that succeeds when staging completes
|
|
84256
|
-
*/
|
|
84257
|
-
stageAll: Effect_exports.fn("stageAll")(function* () {
|
|
84258
|
-
yield* runCommandWithExitCode("git", "add", ".");
|
|
84259
|
-
}),
|
|
84260
|
-
/**
|
|
84261
|
-
* Creates a new commit with the specified message.
|
|
84262
|
-
* All currently staged changes will be included in the commit.
|
|
84263
|
-
*
|
|
84264
|
-
* @param message - The commit message
|
|
84265
|
-
* @returns Effect that succeeds when commit completes
|
|
84266
|
-
* @throws FailedToCommitError if the commit fails (e.g., nothing staged, hook failure)
|
|
84267
|
-
*/
|
|
84268
|
-
commit: Effect_exports.fn("commit")(function* (message) {
|
|
84269
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84270
|
-
"git",
|
|
84271
|
-
"commit",
|
|
84272
|
-
"-m",
|
|
84273
|
-
message
|
|
84274
|
-
);
|
|
84275
|
-
if (exitCode3 !== 0) {
|
|
84276
|
-
return yield* Effect_exports.fail(
|
|
84277
|
-
new FailedToCommitError({
|
|
84278
|
-
message: `Failed to commit (exit code: ${exitCode3})`
|
|
84279
|
-
})
|
|
84280
|
-
);
|
|
84281
|
-
}
|
|
84282
|
-
}),
|
|
84283
|
-
/**
|
|
84284
|
-
* Cherry-picks a range of commits onto the current branch.
|
|
84285
|
-
* The range is specified as "from..to" where commits after "from"
|
|
84286
|
-
* up to and including "to" are applied.
|
|
84287
|
-
*
|
|
84288
|
-
* @param range - The commit range to cherry-pick (e.g., "abc123..def456")
|
|
84289
|
-
* @returns Effect that succeeds when cherry-pick completes
|
|
84290
|
-
* @throws CherryPickConflictError if conflicts occur during cherry-pick
|
|
84291
|
-
*/
|
|
84292
|
-
cherryPick: Effect_exports.fn("cherryPick")(function* (range4) {
|
|
84293
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84294
|
-
"git",
|
|
84295
|
-
"cherry-pick",
|
|
84296
|
-
range4
|
|
84297
|
-
);
|
|
84298
|
-
if (exitCode3 !== 0) {
|
|
84299
|
-
return yield* Effect_exports.fail(
|
|
84300
|
-
new CherryPickConflictError({
|
|
84301
|
-
range: range4,
|
|
84302
|
-
message: `Cherry-pick conflict on range ${range4}`
|
|
84303
|
-
})
|
|
84304
|
-
);
|
|
84305
|
-
}
|
|
84306
|
-
}),
|
|
84307
|
-
/**
|
|
84308
|
-
* Continues a cherry-pick after conflicts have been resolved.
|
|
84309
|
-
* Call this after manually resolving conflicts and staging the changes.
|
|
84310
|
-
*
|
|
84311
|
-
* @returns Effect that succeeds when cherry-pick continues, or fails if more conflicts
|
|
84312
|
-
* @throws CherryPickConflictError if additional conflicts occur
|
|
84313
|
-
*/
|
|
84314
|
-
cherryPickContinue: Effect_exports.fn("cherryPickContinue")(
|
|
84315
|
-
function* () {
|
|
84316
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84317
|
-
"git",
|
|
84318
|
-
"cherry-pick",
|
|
84319
|
-
"--continue"
|
|
84320
|
-
);
|
|
84321
|
-
if (exitCode3 !== 0) {
|
|
84322
|
-
return yield* Effect_exports.fail(
|
|
84323
|
-
new CherryPickConflictError({
|
|
84324
|
-
range: "continue",
|
|
84325
|
-
message: "Cherry-pick continue encountered conflicts"
|
|
84326
|
-
})
|
|
84327
|
-
);
|
|
84328
|
-
}
|
|
84329
|
-
}
|
|
84330
|
-
),
|
|
84331
|
-
/**
|
|
84332
|
-
* Aborts an in-progress cherry-pick operation.
|
|
84333
|
-
* This restores the branch to its state before the cherry-pick started.
|
|
84334
|
-
*
|
|
84335
|
-
* @returns Effect that succeeds when abort completes
|
|
84336
|
-
*/
|
|
84337
|
-
cherryPickAbort: Effect_exports.fn("cherryPickAbort")(
|
|
84338
|
-
function* () {
|
|
84339
|
-
yield* runCommandWithExitCode(
|
|
84340
|
-
"git",
|
|
84341
|
-
"cherry-pick",
|
|
84342
|
-
"--abort"
|
|
84343
|
-
);
|
|
84344
|
-
}
|
|
84345
|
-
),
|
|
84346
|
-
/**
|
|
84347
|
-
* Switches to an existing branch.
|
|
84348
|
-
* The working directory must be clean or have changes that don't
|
|
84349
|
-
* conflict with the target branch.
|
|
84350
|
-
*
|
|
84351
|
-
* @param branch - The branch name to switch to
|
|
84352
|
-
* @returns Effect that succeeds when checkout completes
|
|
84353
|
-
* @throws FailedToCheckoutError if checkout fails (branch not found, conflicts)
|
|
84354
|
-
*/
|
|
84355
|
-
checkout: Effect_exports.fn("checkout")(function* (branch) {
|
|
84356
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84357
|
-
"git",
|
|
84358
|
-
"checkout",
|
|
84359
|
-
branch
|
|
84360
|
-
);
|
|
84361
|
-
if (exitCode3 !== 0) {
|
|
84362
|
-
return yield* Effect_exports.fail(
|
|
84363
|
-
new FailedToCheckoutError({
|
|
84364
|
-
branch,
|
|
84365
|
-
message: `Failed to checkout ${branch} (exit code: ${exitCode3})`
|
|
84366
|
-
})
|
|
84367
|
-
);
|
|
84368
|
-
}
|
|
84369
|
-
}),
|
|
84370
|
-
/**
|
|
84371
|
-
* Force pushes a branch to a remote using --force-with-lease.
|
|
84372
|
-
* This is safer than --force because it will fail if the remote has
|
|
84373
|
-
* commits that aren't in your local branch, preventing accidental
|
|
84374
|
-
* overwrites of others' work.
|
|
84375
|
-
*
|
|
84376
|
-
* @param remote - The remote name (e.g., "origin")
|
|
84377
|
-
* @param branch - The branch to push
|
|
84378
|
-
* @returns Effect that succeeds when push completes
|
|
84379
|
-
* @throws FailedToPushError if push fails (rejected, network, auth issues)
|
|
84380
|
-
*/
|
|
84381
|
-
pushForceWithLease: Effect_exports.fn("pushForceWithLease")(
|
|
84382
|
-
function* (remote, branch) {
|
|
84383
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84384
|
-
"git",
|
|
84385
|
-
"push",
|
|
84386
|
-
remote,
|
|
84387
|
-
branch,
|
|
84388
|
-
"--force-with-lease"
|
|
84389
|
-
);
|
|
84390
|
-
if (exitCode3 !== 0) {
|
|
84391
|
-
return yield* Effect_exports.fail(
|
|
84392
|
-
new FailedToPushError({
|
|
84393
|
-
remote,
|
|
84394
|
-
branch,
|
|
84395
|
-
message: `Failed to push ${branch} to ${remote} (exit code: ${exitCode3})`
|
|
84396
|
-
})
|
|
84397
|
-
);
|
|
84398
|
-
}
|
|
84399
|
-
}
|
|
84400
|
-
),
|
|
84401
|
-
/**
|
|
84402
|
-
* Creates and switches to a new branch (git checkout -b).
|
|
84403
|
-
* The branch is created at the current HEAD position.
|
|
84404
|
-
*
|
|
84405
|
-
* @param branchName - The name of the new branch to create
|
|
84406
|
-
* @returns Effect that succeeds when branch is created and checked out
|
|
84407
|
-
* @throws FailedToCreateBranchError if branch creation fails (e.g., branch already exists)
|
|
84408
|
-
*/
|
|
84409
|
-
checkoutNewBranch: Effect_exports.fn("checkoutNewBranch")(
|
|
84410
|
-
function* (branchName) {
|
|
84411
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84412
|
-
"git",
|
|
84413
|
-
"checkout",
|
|
84414
|
-
"-b",
|
|
84415
|
-
branchName
|
|
84416
|
-
);
|
|
84417
|
-
if (exitCode3 !== 0) {
|
|
84418
|
-
return yield* Effect_exports.fail(
|
|
84419
|
-
new FailedToCreateBranchError({
|
|
84420
|
-
branchName,
|
|
84421
|
-
message: `Failed to create branch ${branchName} (exit code: ${exitCode3})`
|
|
84422
|
-
})
|
|
84423
|
-
);
|
|
84424
|
-
}
|
|
84425
|
-
}
|
|
84426
|
-
),
|
|
84427
|
-
/**
|
|
84428
|
-
* Gets commit log in oneline format, reversed (oldest first).
|
|
84429
|
-
* Uses `git log --oneline --reverse` with a range specifier.
|
|
84430
|
-
* Each line contains: <short-sha> <commit-message>
|
|
84431
|
-
*
|
|
84432
|
-
* @param range - The commit range (e.g., "main..feature" or "HEAD~5..HEAD")
|
|
84433
|
-
* @returns The commit log output as a string
|
|
84434
|
-
*/
|
|
84435
|
-
getLogOnelineReverse: Effect_exports.fn("getLogOnelineReverse")(
|
|
84436
|
-
function* (range4) {
|
|
84437
|
-
return yield* runCommandWithString(
|
|
84438
|
-
"git",
|
|
84439
|
-
"log",
|
|
84440
|
-
"--oneline",
|
|
84441
|
-
"--reverse",
|
|
84442
|
-
range4
|
|
84443
|
-
);
|
|
84444
|
-
}
|
|
84445
|
-
),
|
|
84446
|
-
/**
|
|
84447
|
-
* Gets commit log in oneline format for a branch.
|
|
84448
|
-
* Uses `git log <branch> --oneline`.
|
|
84449
|
-
* Each line contains: <short-sha> <commit-message>
|
|
84450
|
-
*
|
|
84451
|
-
* @param branch - The branch to get log for (e.g., "main", "HEAD", "origin/main")
|
|
84452
|
-
* @returns The commit log output as a string
|
|
84453
|
-
*/
|
|
84454
|
-
getLogOneline: Effect_exports.fn("getLogOneline")(function* (branch) {
|
|
84455
|
-
return yield* runCommandWithString(
|
|
84456
|
-
"git",
|
|
84457
|
-
"log",
|
|
84458
|
-
branch,
|
|
84459
|
-
"--oneline"
|
|
84460
|
-
);
|
|
84461
|
-
}),
|
|
84462
|
-
/**
|
|
84463
|
-
* Gets the parent commit SHA of a given commit.
|
|
84464
|
-
* Uses `git rev-parse <sha>^` to resolve the parent ref.
|
|
84465
|
-
*
|
|
84466
|
-
* @param sha - The commit SHA to get the parent of
|
|
84467
|
-
* @returns The full SHA of the parent commit
|
|
84468
|
-
* @throws NoParentCommitError if the commit has no parent (e.g., initial commit)
|
|
84469
|
-
*/
|
|
84470
|
-
getParentCommit: Effect_exports.fn("getParentCommit")(function* (sha) {
|
|
84471
|
-
const parentSha = yield* runCommandWithString(
|
|
84472
|
-
"git",
|
|
84473
|
-
"rev-parse",
|
|
84474
|
-
`${sha}^`
|
|
84475
|
-
).pipe(
|
|
84476
|
-
Effect_exports.catchAll(
|
|
84477
|
-
() => Effect_exports.fail(
|
|
84478
|
-
new NoParentCommitError({ commitSha: sha })
|
|
84479
|
-
)
|
|
84480
|
-
)
|
|
84481
|
-
);
|
|
84482
|
-
return parentSha;
|
|
84483
|
-
}),
|
|
84484
|
-
/**
|
|
84485
|
-
* Creates and switches to a new branch at a specific commit (git checkout -b <name> <sha>).
|
|
84486
|
-
* Unlike checkoutNewBranch which creates at HEAD, this creates the branch
|
|
84487
|
-
* at an arbitrary commit position.
|
|
84488
|
-
*
|
|
84489
|
-
* @param branchName - The name of the new branch to create
|
|
84490
|
-
* @param sha - The commit SHA where the branch should be created
|
|
84491
|
-
* @returns Effect that succeeds when branch is created and checked out
|
|
84492
|
-
* @throws FailedToCreateBranchError if branch creation fails (e.g., branch already exists)
|
|
84493
|
-
*/
|
|
84494
|
-
checkoutNewBranchAt: Effect_exports.fn("checkoutNewBranchAt")(
|
|
84495
|
-
function* (branchName, sha) {
|
|
84496
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84497
|
-
"git",
|
|
84498
|
-
"checkout",
|
|
84499
|
-
"-b",
|
|
84500
|
-
branchName,
|
|
84501
|
-
sha
|
|
84502
|
-
);
|
|
84503
|
-
if (exitCode3 !== 0) {
|
|
84504
|
-
return yield* Effect_exports.fail(
|
|
84505
|
-
new FailedToCreateBranchError({
|
|
84506
|
-
branchName,
|
|
84507
|
-
message: `Failed to create branch ${branchName} at ${sha} (exit code: ${exitCode3})`
|
|
84508
|
-
})
|
|
84509
|
-
);
|
|
84510
|
-
}
|
|
84511
|
-
}
|
|
84512
|
-
),
|
|
84513
|
-
/**
|
|
84514
|
-
* Deletes a local branch.
|
|
84515
|
-
* Uses `git branch -D` which force deletes even if not fully merged.
|
|
84516
|
-
*
|
|
84517
|
-
* @param branchName - The name of the branch to delete
|
|
84518
|
-
* @returns Effect that succeeds when branch is deleted
|
|
84519
|
-
* @throws FailedToDeleteBranchError if deletion fails
|
|
84520
|
-
*/
|
|
84521
|
-
deleteBranch: Effect_exports.fn("deleteBranch")(function* (branchName) {
|
|
84522
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84523
|
-
"git",
|
|
84524
|
-
"branch",
|
|
84525
|
-
"-D",
|
|
84526
|
-
branchName
|
|
84527
|
-
);
|
|
84528
|
-
if (exitCode3 !== 0) {
|
|
84529
|
-
return yield* Effect_exports.fail(
|
|
84530
|
-
new FailedToDeleteBranchError({
|
|
84531
|
-
branchName,
|
|
84532
|
-
message: `Failed to delete branch ${branchName} (exit code: ${exitCode3})`
|
|
84533
|
-
})
|
|
84534
|
-
);
|
|
84535
|
-
}
|
|
84536
|
-
}),
|
|
84537
|
-
/**
|
|
84538
|
-
* Fetches a specific branch from a remote.
|
|
84539
|
-
* Updates the remote-tracking branch (e.g., origin/main) without
|
|
84540
|
-
* modifying local branches or the working directory.
|
|
84541
|
-
*
|
|
84542
|
-
* @param remote - The remote name (e.g., "origin", "upstream")
|
|
84543
|
-
* @param branch - The branch to fetch (e.g., "main")
|
|
84544
|
-
* @returns Effect that succeeds when fetch completes
|
|
84545
|
-
* @throws FailedToFetchError if fetch fails (network, auth, or remote/branch not found)
|
|
84546
|
-
*/
|
|
84547
|
-
fetch: Effect_exports.fn("fetch")(function* (remote, branch) {
|
|
84548
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84549
|
-
"git",
|
|
84550
|
-
"fetch",
|
|
84551
|
-
remote,
|
|
84552
|
-
branch
|
|
84553
|
-
);
|
|
84554
|
-
if (exitCode3 !== 0) {
|
|
84555
|
-
return yield* Effect_exports.fail(
|
|
84556
|
-
new FailedToFetchError({
|
|
84557
|
-
remote,
|
|
84558
|
-
branch,
|
|
84559
|
-
message: `Failed to fetch ${branch} from ${remote} (exit code: ${exitCode3})`
|
|
84560
|
-
})
|
|
84561
|
-
);
|
|
84562
|
-
}
|
|
84563
|
-
}),
|
|
84564
|
-
/**
|
|
84565
|
-
* Merges a ref into the current branch.
|
|
84566
|
-
* This creates a merge commit if necessary, or performs a fast-forward
|
|
84567
|
-
* merge if the current branch is directly behind the target ref.
|
|
84568
|
-
*
|
|
84569
|
-
* @param ref - The ref to merge (e.g., "origin/main", a branch name, or SHA)
|
|
84570
|
-
* @returns Effect that succeeds when merge completes
|
|
84571
|
-
* @throws MergeConflictError if conflicts occur during merge
|
|
84572
|
-
*/
|
|
84573
|
-
merge: Effect_exports.fn("merge")(function* (ref) {
|
|
84574
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84575
|
-
"git",
|
|
84576
|
-
"merge",
|
|
84577
|
-
ref
|
|
84578
|
-
);
|
|
84579
|
-
if (exitCode3 !== 0) {
|
|
84580
|
-
return yield* Effect_exports.fail(
|
|
84581
|
-
new MergeConflictError({
|
|
84582
|
-
ref,
|
|
84583
|
-
message: `Merge conflicts detected when merging ${ref}`
|
|
84584
|
-
})
|
|
84585
|
-
);
|
|
84586
|
-
}
|
|
84587
|
-
}),
|
|
84588
|
-
/**
|
|
84589
|
-
* Rebases the current branch onto another branch.
|
|
84590
|
-
* This replays all commits from the current branch on top of the target branch.
|
|
84591
|
-
* WARNING: Rebase rewrites commit history - all rebased commits get new SHAs.
|
|
84592
|
-
* Never rebase commits that have been pushed to a shared remote unless you
|
|
84593
|
-
* coordinate with all collaborators.
|
|
84594
|
-
*
|
|
84595
|
-
* @param onto - The branch to rebase onto (e.g., "main", "origin/main")
|
|
84596
|
-
* @returns Effect that succeeds when rebase completes
|
|
84597
|
-
* @throws RebaseConflictError if conflicts occur during rebase
|
|
84598
|
-
*/
|
|
84599
|
-
rebase: Effect_exports.fn("rebase")(function* (onto) {
|
|
84600
|
-
const exitCode3 = yield* runCommandWithExitCode(
|
|
84601
|
-
"git",
|
|
84602
|
-
"rebase",
|
|
84603
|
-
onto
|
|
84604
|
-
);
|
|
84605
|
-
if (exitCode3 !== 0) {
|
|
84606
|
-
return yield* Effect_exports.fail(
|
|
84607
|
-
new RebaseConflictError({
|
|
84608
|
-
onto,
|
|
84609
|
-
message: `Rebase conflicts detected when rebasing onto ${onto}`
|
|
84610
|
-
})
|
|
84611
|
-
);
|
|
84612
|
-
}
|
|
84613
|
-
}),
|
|
84614
|
-
ensureIsGitRepo: Effect_exports.fn("ensureIsGitRepo")(
|
|
84615
|
-
function* () {
|
|
84616
|
-
const cwd = config3.cwd;
|
|
84617
|
-
const gitDirPath = path6__namespace.join(cwd, ".git");
|
|
84618
|
-
const exists4 = yield* fs.exists(gitDirPath);
|
|
84619
|
-
if (!exists4) {
|
|
84620
|
-
return yield* new NotAGitRepoError({
|
|
84621
|
-
path: cwd,
|
|
84622
|
-
message: `Current directory is not a git repository: ${cwd}`
|
|
84623
|
-
});
|
|
84624
|
-
}
|
|
84625
|
-
}
|
|
84626
|
-
),
|
|
84627
|
-
getUncommittedChanges: Effect_exports.fn(
|
|
84628
|
-
"getUncommittedChanges"
|
|
84629
|
-
)(function* () {
|
|
84630
|
-
const statusOutput = yield* runCommandWithString(
|
|
84631
|
-
"git",
|
|
84632
|
-
"status",
|
|
84633
|
-
"--porcelain"
|
|
84634
|
-
);
|
|
84635
|
-
return {
|
|
84636
|
-
hasUncommittedChanges: statusOutput !== "",
|
|
84637
|
-
statusOutput
|
|
84638
|
-
};
|
|
84639
|
-
}),
|
|
84640
|
-
/**
|
|
84641
|
-
* This command needs to be run in every user-facing command that
|
|
84642
|
-
* interacts with a branch. It ensures that the branch is connected
|
|
84643
|
-
* to the upstream repository and that the local branch is tracking
|
|
84644
|
-
* the upstream branch.
|
|
84645
|
-
*
|
|
84646
|
-
* This is to handle the case where the user has a fork of the
|
|
84647
|
-
* upstream repository.
|
|
84648
|
-
*/
|
|
84649
|
-
ensureUpstreamBranchConnected: Effect_exports.fn(
|
|
84650
|
-
"ensureUpstreamBranchConnected"
|
|
84651
|
-
)(function* (opts) {
|
|
84652
|
-
const { targetBranch } = opts;
|
|
84653
|
-
const { remoteName } = yield* detectUpstreamRemote();
|
|
84654
|
-
const fetchExitCode = yield* runCommandWithExitCode(
|
|
84655
|
-
"git",
|
|
84656
|
-
"fetch",
|
|
84657
|
-
remoteName,
|
|
84658
|
-
targetBranch
|
|
84659
|
-
);
|
|
84660
|
-
if (fetchExitCode !== 0) {
|
|
84661
|
-
return yield* Effect_exports.fail(
|
|
84662
|
-
new FailedToFetchUpstreamError({
|
|
84663
|
-
targetBranch,
|
|
84664
|
-
message: `Failed to fetch upstream: ${fetchExitCode}`
|
|
84665
|
-
})
|
|
84666
|
-
);
|
|
84667
|
-
}
|
|
84391
|
+
hasUncommittedChanges: statusOutput !== "",
|
|
84392
|
+
statusOutput
|
|
84393
|
+
};
|
|
84394
|
+
}),
|
|
84395
|
+
ensureUpstreamBranchConnected: Effect_exports.fn(
|
|
84396
|
+
"ensureUpstreamBranchConnected"
|
|
84397
|
+
)(function* (opts) {
|
|
84398
|
+
const { targetBranch } = opts;
|
|
84399
|
+
const fetchExitCode = yield* runCommandWithExitCode(
|
|
84400
|
+
"git",
|
|
84401
|
+
"fetch",
|
|
84402
|
+
"upstream",
|
|
84403
|
+
targetBranch
|
|
84404
|
+
);
|
|
84405
|
+
if (fetchExitCode !== 0) {
|
|
84406
|
+
return yield* Effect_exports.fail(
|
|
84407
|
+
new FailedToFetchUpstreamError({
|
|
84408
|
+
targetBranch,
|
|
84409
|
+
message: `Failed to fetch upstream: ${fetchExitCode}`
|
|
84410
|
+
})
|
|
84411
|
+
);
|
|
84412
|
+
}
|
|
84413
|
+
yield* runCommandWithExitCode(
|
|
84414
|
+
"git",
|
|
84415
|
+
"branch",
|
|
84416
|
+
"-D",
|
|
84417
|
+
targetBranch
|
|
84418
|
+
);
|
|
84419
|
+
const trackBranchExitCode = yield* runCommandWithExitCode(
|
|
84420
|
+
"git",
|
|
84421
|
+
"branch",
|
|
84422
|
+
"--track",
|
|
84423
|
+
targetBranch,
|
|
84424
|
+
`upstream/${targetBranch}`
|
|
84425
|
+
);
|
|
84426
|
+
if (trackBranchExitCode !== 0) {
|
|
84427
|
+
return yield* Effect_exports.fail(
|
|
84428
|
+
new FailedToTrackBranchError({
|
|
84429
|
+
branchName: targetBranch,
|
|
84430
|
+
message: `Failed to track branch.`
|
|
84431
|
+
})
|
|
84432
|
+
);
|
|
84433
|
+
}
|
|
84434
|
+
}),
|
|
84435
|
+
getCurrentBranch: Effect_exports.fn("getCurrentBranch")(
|
|
84436
|
+
function* () {
|
|
84437
|
+
const currentBranch = (yield* runCommandWithString(
|
|
84438
|
+
"git",
|
|
84439
|
+
"branch",
|
|
84440
|
+
"--show-current"
|
|
84441
|
+
)).trim();
|
|
84442
|
+
return currentBranch;
|
|
84443
|
+
}
|
|
84444
|
+
),
|
|
84445
|
+
setUpstreamRemote: Effect_exports.fn("setUpstreamRemote")(
|
|
84446
|
+
function* (url2) {
|
|
84447
|
+
const setUrlExitCode = yield* runCommandWithExitCode(
|
|
84448
|
+
"git",
|
|
84449
|
+
"remote",
|
|
84450
|
+
"set-url",
|
|
84451
|
+
"upstream",
|
|
84452
|
+
url2
|
|
84453
|
+
);
|
|
84454
|
+
if (setUrlExitCode !== 0) {
|
|
84668
84455
|
yield* runCommandWithExitCode(
|
|
84669
84456
|
"git",
|
|
84670
|
-
"
|
|
84671
|
-
"
|
|
84672
|
-
|
|
84673
|
-
|
|
84674
|
-
const trackBranchExitCode = yield* runCommandWithExitCode(
|
|
84675
|
-
"git",
|
|
84676
|
-
"branch",
|
|
84677
|
-
"--track",
|
|
84678
|
-
targetBranch,
|
|
84679
|
-
`${remoteName}/${targetBranch}`
|
|
84457
|
+
"remote",
|
|
84458
|
+
"add",
|
|
84459
|
+
"upstream",
|
|
84460
|
+
url2
|
|
84680
84461
|
);
|
|
84681
|
-
|
|
84682
|
-
|
|
84683
|
-
|
|
84684
|
-
|
|
84685
|
-
|
|
84686
|
-
|
|
84687
|
-
|
|
84688
|
-
|
|
84689
|
-
|
|
84690
|
-
getCurrentBranch: Effect_exports.fn("getCurrentBranch")(
|
|
84691
|
-
function* () {
|
|
84692
|
-
const currentBranch = (yield* runCommandWithString(
|
|
84693
|
-
"git",
|
|
84694
|
-
"branch",
|
|
84695
|
-
"--show-current"
|
|
84696
|
-
)).trim();
|
|
84697
|
-
return currentBranch;
|
|
84698
|
-
}
|
|
84699
|
-
),
|
|
84700
|
-
detectUpstreamRemote
|
|
84701
|
-
};
|
|
84702
|
-
}),
|
|
84462
|
+
}
|
|
84463
|
+
}
|
|
84464
|
+
)
|
|
84465
|
+
};
|
|
84466
|
+
});
|
|
84467
|
+
var GitService = class extends Effect_exports.Service()(
|
|
84468
|
+
"GitService",
|
|
84469
|
+
{
|
|
84470
|
+
effect: makeGitService,
|
|
84703
84471
|
dependencies: [
|
|
84704
84472
|
NodeFileSystem_exports2.layer,
|
|
84705
84473
|
defaultGitServiceConfigLayer
|
|
@@ -84750,7 +84518,6 @@ var normalizeExerciseNumber = (str) => {
|
|
|
84750
84518
|
var PromptService = class extends Effect_exports.Service()(
|
|
84751
84519
|
"PromptService",
|
|
84752
84520
|
{
|
|
84753
|
-
// eslint-disable-next-line require-yield
|
|
84754
84521
|
effect: Effect_exports.gen(function* () {
|
|
84755
84522
|
const confirmReadyToCommit = Effect_exports.fn(
|
|
84756
84523
|
"confirmReadyToCommit"
|
|
@@ -84822,27 +84589,6 @@ var PromptService = class extends Effect_exports.Service()(
|
|
|
84822
84589
|
);
|
|
84823
84590
|
return action;
|
|
84824
84591
|
});
|
|
84825
|
-
const selectProblemOrSolution = Effect_exports.fn(
|
|
84826
|
-
"selectProblemOrSolution"
|
|
84827
|
-
)(function* () {
|
|
84828
|
-
const { action } = yield* runPrompt(
|
|
84829
|
-
() => (0, import_prompts.prompt)([
|
|
84830
|
-
{
|
|
84831
|
-
type: "select",
|
|
84832
|
-
name: "action",
|
|
84833
|
-
message: "What would you like to do?",
|
|
84834
|
-
choices: [
|
|
84835
|
-
{
|
|
84836
|
-
title: "Start the exercise",
|
|
84837
|
-
value: "problem"
|
|
84838
|
-
},
|
|
84839
|
-
{ title: "View final code", value: "solution" }
|
|
84840
|
-
]
|
|
84841
|
-
}
|
|
84842
|
-
])
|
|
84843
|
-
);
|
|
84844
|
-
return action;
|
|
84845
|
-
});
|
|
84846
84592
|
const selectResetAction = Effect_exports.fn("selectResetAction")(
|
|
84847
84593
|
function* (_branch) {
|
|
84848
84594
|
const { action } = yield* runPrompt(
|
|
@@ -85013,14 +84759,17 @@ var PromptService = class extends Effect_exports.Service()(
|
|
|
85013
84759
|
type: "autocomplete",
|
|
85014
84760
|
name: "subfolderIndex",
|
|
85015
84761
|
message: "Select a subfolder",
|
|
85016
|
-
choices: subfolders.map((subfolder
|
|
84762
|
+
choices: subfolders.map((subfolder) => ({
|
|
85017
84763
|
title: subfolder,
|
|
85018
|
-
value
|
|
84764
|
+
// Use subfolder name as value instead of numeric index
|
|
84765
|
+
// to avoid prompts library treating 0 as falsy and
|
|
84766
|
+
// returning the title string instead (GitHub issue #42)
|
|
84767
|
+
value: subfolder
|
|
85019
84768
|
}))
|
|
85020
84769
|
}
|
|
85021
84770
|
])
|
|
85022
84771
|
);
|
|
85023
|
-
return subfolderIndex;
|
|
84772
|
+
return subfolders.indexOf(subfolderIndex);
|
|
85024
84773
|
}
|
|
85025
84774
|
);
|
|
85026
84775
|
const selectExerciseAction = Effect_exports.fn(
|
|
@@ -85131,7 +84880,6 @@ var PromptService = class extends Effect_exports.Service()(
|
|
|
85131
84880
|
confirmSaveToTargetBranch,
|
|
85132
84881
|
confirmForcePush,
|
|
85133
84882
|
selectCherryPickConflictAction,
|
|
85134
|
-
selectProblemOrSolution,
|
|
85135
84883
|
selectResetAction,
|
|
85136
84884
|
confirmResetWithUncommittedChanges,
|
|
85137
84885
|
inputBranchName,
|
|
@@ -85257,10 +85005,6 @@ var selectLessonCommit = ({
|
|
|
85257
85005
|
lessonId: selectedLessonId
|
|
85258
85006
|
};
|
|
85259
85007
|
});
|
|
85260
|
-
var getParentCommit = ({ commitSha }) => Effect_exports.gen(function* () {
|
|
85261
|
-
const gitService = yield* GitService;
|
|
85262
|
-
return yield* gitService.getParentCommit(commitSha);
|
|
85263
|
-
});
|
|
85264
85008
|
|
|
85265
85009
|
// src/constants.ts
|
|
85266
85010
|
var DEFAULT_PROJECT_TARGET_BRANCH = "live-run-through";
|
|
@@ -85288,11 +85032,13 @@ var InvalidBranchOperationError = class extends Data_exports.TaggedError(
|
|
|
85288
85032
|
};
|
|
85289
85033
|
var runCherryPick = ({
|
|
85290
85034
|
branch,
|
|
85291
|
-
lessonId
|
|
85035
|
+
lessonId,
|
|
85036
|
+
upstream
|
|
85292
85037
|
}) => Effect_exports.gen(function* () {
|
|
85293
85038
|
const git = yield* GitService;
|
|
85294
85039
|
const promptService = yield* PromptService;
|
|
85295
85040
|
yield* git.ensureIsGitRepo();
|
|
85041
|
+
yield* git.setUpstreamRemote(upstream);
|
|
85296
85042
|
yield* git.ensureUpstreamBranchConnected({
|
|
85297
85043
|
targetBranch: branch
|
|
85298
85044
|
});
|
|
@@ -85342,9 +85088,15 @@ var cherryPick = Command_exports.make(
|
|
|
85342
85088
|
),
|
|
85343
85089
|
Options_exports.withDefault(DEFAULT_PROJECT_TARGET_BRANCH)
|
|
85344
85090
|
),
|
|
85091
|
+
upstream: Options_exports.text("upstream").pipe(
|
|
85092
|
+
Options_exports.withDescription(
|
|
85093
|
+
"Git URL or local path to the upstream exercise repo"
|
|
85094
|
+
)
|
|
85095
|
+
),
|
|
85345
85096
|
cwd: cwdOption
|
|
85346
85097
|
},
|
|
85347
|
-
|
|
85098
|
+
/* v8 ignore start - CLI error handlers are presentation logic */
|
|
85099
|
+
({ branch, cwd, lessonId, upstream }) => runCherryPick({ branch, lessonId, upstream }).pipe(
|
|
85348
85100
|
Effect_exports.provideService(
|
|
85349
85101
|
GitServiceConfig,
|
|
85350
85102
|
GitServiceConfig.of({
|
|
@@ -85358,12 +85110,6 @@ var cherryPick = Command_exports.make(
|
|
|
85358
85110
|
process.exitCode = 1;
|
|
85359
85111
|
});
|
|
85360
85112
|
},
|
|
85361
|
-
NoUpstreamFoundError: (error4) => {
|
|
85362
|
-
return Effect_exports.gen(function* () {
|
|
85363
|
-
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
85364
|
-
process.exitCode = 1;
|
|
85365
|
-
});
|
|
85366
|
-
},
|
|
85367
85113
|
CommitNotFoundError: (error4) => {
|
|
85368
85114
|
return Effect_exports.gen(function* () {
|
|
85369
85115
|
yield* Console_exports.error(
|
|
@@ -85402,6 +85148,7 @@ var cherryPick = Command_exports.make(
|
|
|
85402
85148
|
});
|
|
85403
85149
|
})
|
|
85404
85150
|
)
|
|
85151
|
+
/* v8 ignore stop */
|
|
85405
85152
|
).pipe(
|
|
85406
85153
|
Command_exports.withDescription(
|
|
85407
85154
|
"Cherry-pick a specific lesson commit onto current branch"
|
|
@@ -86084,6 +85831,7 @@ var updateCVM = Command_exports.make(
|
|
|
86084
85831
|
);
|
|
86085
85832
|
var createErrorTracker = () => {
|
|
86086
85833
|
const groupedErrors = {};
|
|
85834
|
+
const errors = [];
|
|
86087
85835
|
return {
|
|
86088
85836
|
addError: (lesson, error4) => {
|
|
86089
85837
|
if (!groupedErrors[lesson.sectionPath]) {
|
|
@@ -86093,20 +85841,21 @@ var createErrorTracker = () => {
|
|
|
86093
85841
|
groupedErrors[lesson.sectionPath][lesson.path] = [];
|
|
86094
85842
|
}
|
|
86095
85843
|
groupedErrors[lesson.sectionPath][lesson.path].push(error4);
|
|
85844
|
+
errors.push({
|
|
85845
|
+
sectionPath: lesson.sectionPath,
|
|
85846
|
+
lessonPath: lesson.path,
|
|
85847
|
+
error: error4
|
|
85848
|
+
});
|
|
86096
85849
|
},
|
|
85850
|
+
getErrors: () => errors,
|
|
85851
|
+
/* v8 ignore start */
|
|
86097
85852
|
log: Effect_exports.gen(function* () {
|
|
86098
|
-
for (const [section, exercises] of Object.entries(
|
|
86099
|
-
groupedErrors
|
|
86100
|
-
)) {
|
|
85853
|
+
for (const [section, exercises] of Object.entries(groupedErrors)) {
|
|
86101
85854
|
yield* Console_exports.log(util.styleText(["bold"], section));
|
|
86102
|
-
for (const [exercise2,
|
|
86103
|
-
exercises
|
|
86104
|
-
)) {
|
|
85855
|
+
for (const [exercise2, errors2] of Object.entries(exercises)) {
|
|
86105
85856
|
yield* Console_exports.log(` ${exercise2}`);
|
|
86106
|
-
for (const error4 of
|
|
86107
|
-
yield* Console_exports.log(
|
|
86108
|
-
util.styleText(["red"], ` ${error4}`)
|
|
86109
|
-
);
|
|
85857
|
+
for (const error4 of errors2) {
|
|
85858
|
+
yield* Console_exports.log(util.styleText(["red"], ` ${error4}`));
|
|
86110
85859
|
}
|
|
86111
85860
|
}
|
|
86112
85861
|
}
|
|
@@ -86114,177 +85863,183 @@ var createErrorTracker = () => {
|
|
|
86114
85863
|
process.exitCode = 1;
|
|
86115
85864
|
}
|
|
86116
85865
|
})
|
|
85866
|
+
/* v8 ignore stop */
|
|
86117
85867
|
};
|
|
86118
85868
|
};
|
|
86119
|
-
var
|
|
86120
|
-
|
|
86121
|
-
|
|
86122
|
-
|
|
86123
|
-
|
|
86124
|
-
|
|
86125
|
-
|
|
86126
|
-
|
|
86127
|
-
|
|
86128
|
-
|
|
86129
|
-
|
|
86130
|
-
|
|
86131
|
-
|
|
86132
|
-
|
|
86133
|
-
|
|
86134
|
-
|
|
86135
|
-
|
|
86136
|
-
|
|
86137
|
-
|
|
86138
|
-
|
|
86139
|
-
|
|
86140
|
-
|
|
85869
|
+
var runLint = (opts) => Effect_exports.gen(function* () {
|
|
85870
|
+
const lessonParser = yield* LessonParserService;
|
|
85871
|
+
const fs = yield* FileSystem_exports.FileSystem;
|
|
85872
|
+
const existsCache = yield* Cache_exports.make({
|
|
85873
|
+
capacity: 1e4,
|
|
85874
|
+
timeToLive: Duration_exports.infinity,
|
|
85875
|
+
lookup: (key) => Effect_exports.gen(function* () {
|
|
85876
|
+
const exists4 = yield* fs.exists(key);
|
|
85877
|
+
return exists4;
|
|
85878
|
+
})
|
|
85879
|
+
});
|
|
85880
|
+
const allReadmeContents = [];
|
|
85881
|
+
const errorTracker = createErrorTracker();
|
|
85882
|
+
const lessons = yield* lessonParser.getLessonsFromRepo(opts.root);
|
|
85883
|
+
for (const lesson of lessons) {
|
|
85884
|
+
const subfolders = yield* lesson.subfolders();
|
|
85885
|
+
if (subfolders.length === 0) {
|
|
85886
|
+
errorTracker.addError(
|
|
85887
|
+
lesson,
|
|
85888
|
+
"No subfolders, like problem or solution, found in the exercise."
|
|
85889
|
+
);
|
|
85890
|
+
continue;
|
|
85891
|
+
}
|
|
85892
|
+
const folderForReadme = subfolders.find(
|
|
85893
|
+
(folder) => folder === "problem" || folder === "explainer" || folder === "explainer.1"
|
|
85894
|
+
);
|
|
85895
|
+
if (!folderForReadme) {
|
|
85896
|
+
errorTracker.addError(
|
|
85897
|
+
lesson,
|
|
85898
|
+
"No problem, explainer, or explainer.1 folder found in the exercise."
|
|
86141
85899
|
);
|
|
86142
|
-
|
|
86143
|
-
|
|
86144
|
-
|
|
85900
|
+
continue;
|
|
85901
|
+
}
|
|
85902
|
+
const readmePath = path6__namespace.join(
|
|
85903
|
+
lesson.absolutePath(),
|
|
85904
|
+
folderForReadme,
|
|
85905
|
+
"readme.md"
|
|
85906
|
+
);
|
|
85907
|
+
const readmeExists = yield* existsCache.get(readmePath);
|
|
85908
|
+
if (!readmeExists) {
|
|
85909
|
+
errorTracker.addError(
|
|
85910
|
+
lesson,
|
|
85911
|
+
"readme.md file not found in the exercise."
|
|
85912
|
+
);
|
|
85913
|
+
} else {
|
|
85914
|
+
const readmeContent = yield* fs.readFileString(readmePath);
|
|
85915
|
+
allReadmeContents.push(readmeContent);
|
|
85916
|
+
if (readmeContent.trim().length === 0) {
|
|
85917
|
+
errorTracker.addError(lesson, "readme.md file is empty");
|
|
85918
|
+
continue;
|
|
85919
|
+
}
|
|
85920
|
+
if (readmeContent.includes("`pnpm run exercise ")) {
|
|
85921
|
+
errorTracker.addError(
|
|
85922
|
+
lesson,
|
|
85923
|
+
"readme.md file contains a pnpm run exercise command. Please remove it."
|
|
85924
|
+
);
|
|
85925
|
+
continue;
|
|
85926
|
+
}
|
|
85927
|
+
const absoluteLinks = readmeContent.match(/\[[^\]]+\]\(\/[^)]+\)/gm) ?? [];
|
|
85928
|
+
for (const link3 of absoluteLinks) {
|
|
85929
|
+
const splitResult = link3.split("](");
|
|
85930
|
+
const url2 = splitResult[1]?.slice(1, -1);
|
|
85931
|
+
if (!url2) continue;
|
|
85932
|
+
const linkExists = yield* existsCache.get(path6__namespace.join(opts.cwd, url2));
|
|
85933
|
+
if (!linkExists) {
|
|
86145
85934
|
errorTracker.addError(
|
|
86146
85935
|
lesson,
|
|
86147
|
-
|
|
85936
|
+
`Broken absolute link in readme.md: ${url2}`
|
|
86148
85937
|
);
|
|
86149
|
-
continue;
|
|
86150
85938
|
}
|
|
86151
|
-
|
|
86152
|
-
|
|
85939
|
+
}
|
|
85940
|
+
const relativeLinks = readmeContent.match(/\[[^\]]+\]\(\.\/[^)]+\)/gm) ?? [];
|
|
85941
|
+
for (const link3 of relativeLinks) {
|
|
85942
|
+
const splitResult = link3.split("](");
|
|
85943
|
+
const url2 = splitResult[1]?.slice(0, -1);
|
|
85944
|
+
if (!url2) continue;
|
|
85945
|
+
const linkExists = yield* existsCache.get(
|
|
85946
|
+
path6__namespace.resolve(lesson.absolutePath(), folderForReadme, url2)
|
|
86153
85947
|
);
|
|
86154
|
-
if (!
|
|
85948
|
+
if (!linkExists) {
|
|
86155
85949
|
errorTracker.addError(
|
|
86156
85950
|
lesson,
|
|
86157
|
-
|
|
85951
|
+
`Broken relative link in readme.md: ${url2}`
|
|
86158
85952
|
);
|
|
86159
|
-
continue;
|
|
86160
85953
|
}
|
|
86161
|
-
|
|
85954
|
+
}
|
|
85955
|
+
}
|
|
85956
|
+
for (const subfolder of subfolders) {
|
|
85957
|
+
const mainFilePath = path6__namespace.join(
|
|
85958
|
+
lesson.absolutePath(),
|
|
85959
|
+
subfolder,
|
|
85960
|
+
"main.ts"
|
|
85961
|
+
);
|
|
85962
|
+
const mainFileExists = yield* existsCache.get(mainFilePath);
|
|
85963
|
+
if (!mainFileExists) {
|
|
85964
|
+
const readmeInSubfolderPath = path6__namespace.join(
|
|
86162
85965
|
lesson.absolutePath(),
|
|
86163
|
-
|
|
85966
|
+
subfolder,
|
|
86164
85967
|
"readme.md"
|
|
86165
85968
|
);
|
|
86166
|
-
const
|
|
86167
|
-
if (!
|
|
86168
|
-
errorTracker.addError(
|
|
86169
|
-
lesson,
|
|
86170
|
-
"readme.md file not found in the exercise."
|
|
86171
|
-
);
|
|
86172
|
-
} else {
|
|
86173
|
-
const readmeContent = yield* fs.readFileString(
|
|
86174
|
-
readmePath
|
|
86175
|
-
);
|
|
86176
|
-
allReadmeContents.push(readmeContent);
|
|
86177
|
-
if (readmeContent.trim().length === 0) {
|
|
86178
|
-
errorTracker.addError(
|
|
86179
|
-
lesson,
|
|
86180
|
-
"readme.md file is empty"
|
|
86181
|
-
);
|
|
86182
|
-
continue;
|
|
86183
|
-
}
|
|
86184
|
-
if (readmeContent.includes("`pnpm run exercise ")) {
|
|
86185
|
-
errorTracker.addError(
|
|
86186
|
-
lesson,
|
|
86187
|
-
"readme.md file contains a pnpm run exercise command. Please remove it."
|
|
86188
|
-
);
|
|
86189
|
-
continue;
|
|
86190
|
-
}
|
|
86191
|
-
const absoluteLinks = readmeContent.match(/\[[^\]]+\]\(\/[^)]+\)/gm) ?? [];
|
|
86192
|
-
for (const link3 of absoluteLinks) {
|
|
86193
|
-
const splitResult = link3.split("](");
|
|
86194
|
-
const url2 = splitResult[1]?.slice(1, -1);
|
|
86195
|
-
if (!url2) continue;
|
|
86196
|
-
const linkExists = yield* existsCache.get(
|
|
86197
|
-
path6__namespace.join(cwd, url2)
|
|
86198
|
-
);
|
|
86199
|
-
if (!linkExists) {
|
|
86200
|
-
errorTracker.addError(
|
|
86201
|
-
lesson,
|
|
86202
|
-
`Broken absolute link in readme.md: ${url2}`
|
|
86203
|
-
);
|
|
86204
|
-
}
|
|
86205
|
-
}
|
|
86206
|
-
const relativeLinks = readmeContent.match(/\[[^\]]+\]\(\.\/[^)]+\)/gm) ?? [];
|
|
86207
|
-
for (const link3 of relativeLinks) {
|
|
86208
|
-
const splitResult = link3.split("](");
|
|
86209
|
-
const url2 = splitResult[1]?.slice(0, -1);
|
|
86210
|
-
if (!url2) continue;
|
|
86211
|
-
const linkExists = yield* existsCache.get(
|
|
86212
|
-
path6__namespace.resolve(
|
|
86213
|
-
lesson.absolutePath(),
|
|
86214
|
-
folderForReadme,
|
|
86215
|
-
url2
|
|
86216
|
-
)
|
|
86217
|
-
);
|
|
86218
|
-
if (!linkExists) {
|
|
86219
|
-
errorTracker.addError(
|
|
86220
|
-
lesson,
|
|
86221
|
-
`Broken relative link in readme.md: ${url2}`
|
|
86222
|
-
);
|
|
86223
|
-
}
|
|
86224
|
-
}
|
|
86225
|
-
}
|
|
86226
|
-
for (const subfolder of subfolders) {
|
|
86227
|
-
const mainFilePath = path6__namespace.join(
|
|
86228
|
-
lesson.absolutePath(),
|
|
86229
|
-
subfolder,
|
|
86230
|
-
"main.ts"
|
|
86231
|
-
);
|
|
86232
|
-
const mainFileExists = yield* existsCache.get(
|
|
86233
|
-
mainFilePath
|
|
86234
|
-
);
|
|
86235
|
-
if (!mainFileExists) {
|
|
86236
|
-
const readmeInSubfolderPath = path6__namespace.join(
|
|
86237
|
-
lesson.absolutePath(),
|
|
86238
|
-
subfolder,
|
|
86239
|
-
"readme.md"
|
|
86240
|
-
);
|
|
86241
|
-
const readmeInSubfolderExists = yield* existsCache.get(readmeInSubfolderPath);
|
|
86242
|
-
if (!readmeInSubfolderExists) {
|
|
86243
|
-
errorTracker.addError(
|
|
86244
|
-
lesson,
|
|
86245
|
-
`main.ts file not found in the ${subfolder} folder.`
|
|
86246
|
-
);
|
|
86247
|
-
}
|
|
86248
|
-
} else {
|
|
86249
|
-
const mainFileContent = yield* fs.readFileString(
|
|
86250
|
-
mainFilePath
|
|
86251
|
-
);
|
|
86252
|
-
const lineCount = mainFileContent.trim().split("\n").length;
|
|
86253
|
-
if (lineCount === 1) {
|
|
86254
|
-
errorTracker.addError(
|
|
86255
|
-
lesson,
|
|
86256
|
-
`main.ts file in the ${subfolder} folder is too short (${lineCount} lines). Please use a readme-only exercise instead if you only need to show instructions.`
|
|
86257
|
-
);
|
|
86258
|
-
}
|
|
86259
|
-
}
|
|
86260
|
-
}
|
|
86261
|
-
const files = yield* lesson.allFiles();
|
|
86262
|
-
if (files.some((file6) => file6.includes(".gitkeep"))) {
|
|
85969
|
+
const readmeInSubfolderExists = yield* existsCache.get(readmeInSubfolderPath);
|
|
85970
|
+
if (!readmeInSubfolderExists) {
|
|
86263
85971
|
errorTracker.addError(
|
|
86264
85972
|
lesson,
|
|
86265
|
-
|
|
85973
|
+
`main.ts file not found in the ${subfolder} folder.`
|
|
86266
85974
|
);
|
|
86267
85975
|
}
|
|
86268
|
-
|
|
85976
|
+
} else {
|
|
85977
|
+
const mainFileContent = yield* fs.readFileString(mainFilePath);
|
|
85978
|
+
const lineCount = mainFileContent.trim().split("\n").length;
|
|
85979
|
+
if (lineCount === 1) {
|
|
86269
85980
|
errorTracker.addError(
|
|
86270
85981
|
lesson,
|
|
86271
|
-
|
|
85982
|
+
`main.ts file in the ${subfolder} folder is too short (${lineCount} lines). Please use a readme-only exercise instead if you only need to show instructions.`
|
|
86272
85983
|
);
|
|
86273
85984
|
}
|
|
86274
85985
|
}
|
|
86275
|
-
|
|
86276
|
-
|
|
86277
|
-
|
|
85986
|
+
}
|
|
85987
|
+
const files = yield* lesson.allFiles();
|
|
85988
|
+
if (files.some((file6) => file6.includes(".gitkeep"))) {
|
|
85989
|
+
errorTracker.addError(lesson, ".gitkeep file found in the exercise.");
|
|
85990
|
+
}
|
|
85991
|
+
if (files.some((file6) => file6.includes("speaker-notes.md"))) {
|
|
85992
|
+
errorTracker.addError(
|
|
85993
|
+
lesson,
|
|
85994
|
+
"speaker-notes.md file found in the exercise. This should not be exposed to users."
|
|
86278
85995
|
);
|
|
86279
|
-
|
|
86280
|
-
|
|
86281
|
-
|
|
86282
|
-
|
|
86283
|
-
|
|
86284
|
-
|
|
85996
|
+
}
|
|
85997
|
+
}
|
|
85998
|
+
const readmeContents = allReadmeContents.join("\n");
|
|
85999
|
+
const referenceLessons = lessons.filter(
|
|
86000
|
+
(lesson) => lesson.sectionName === "reference"
|
|
86001
|
+
);
|
|
86002
|
+
for (const referenceLesson of referenceLessons) {
|
|
86003
|
+
if (!readmeContents.includes(referenceLesson.path)) {
|
|
86004
|
+
errorTracker.addError(
|
|
86005
|
+
referenceLesson,
|
|
86006
|
+
`${referenceLesson.path} is not referenced in any other exercise.`
|
|
86007
|
+
);
|
|
86008
|
+
}
|
|
86009
|
+
}
|
|
86010
|
+
return errorTracker.getErrors();
|
|
86011
|
+
});
|
|
86012
|
+
var lint = Command_exports.make(
|
|
86013
|
+
"lint",
|
|
86014
|
+
{
|
|
86015
|
+
root: rootOption,
|
|
86016
|
+
cwd: cwdOption
|
|
86017
|
+
},
|
|
86018
|
+
Effect_exports.fn("lint")(
|
|
86019
|
+
function* ({ cwd, root }) {
|
|
86020
|
+
const errors = yield* runLint({ cwd, root });
|
|
86021
|
+
const groupedErrors = {};
|
|
86022
|
+
for (const error4 of errors) {
|
|
86023
|
+
if (!groupedErrors[error4.sectionPath]) {
|
|
86024
|
+
groupedErrors[error4.sectionPath] = {};
|
|
86025
|
+
}
|
|
86026
|
+
if (!groupedErrors[error4.sectionPath][error4.lessonPath]) {
|
|
86027
|
+
groupedErrors[error4.sectionPath][error4.lessonPath] = [];
|
|
86285
86028
|
}
|
|
86029
|
+
groupedErrors[error4.sectionPath][error4.lessonPath].push(error4.error);
|
|
86030
|
+
}
|
|
86031
|
+
for (const [section, exercises] of Object.entries(groupedErrors)) {
|
|
86032
|
+
yield* Console_exports.log(util.styleText(["bold"], section));
|
|
86033
|
+
for (const [exercise2, errs] of Object.entries(exercises)) {
|
|
86034
|
+
yield* Console_exports.log(` ${exercise2}`);
|
|
86035
|
+
for (const err of errs) {
|
|
86036
|
+
yield* Console_exports.log(util.styleText(["red"], ` ${err}`));
|
|
86037
|
+
}
|
|
86038
|
+
}
|
|
86039
|
+
}
|
|
86040
|
+
if (errors.length > 0) {
|
|
86041
|
+
process.exitCode = 1;
|
|
86286
86042
|
}
|
|
86287
|
-
yield* errorTracker.log;
|
|
86288
86043
|
},
|
|
86289
86044
|
Effect_exports.catchTags({
|
|
86290
86045
|
InvalidPathError: (error4) => {
|
|
@@ -86307,6 +86062,37 @@ var lint = Command_exports.make(
|
|
|
86307
86062
|
"Lint the repository to ensure it is formatted correctly"
|
|
86308
86063
|
)
|
|
86309
86064
|
);
|
|
86065
|
+
var runRename = (opts) => Effect_exports.gen(function* () {
|
|
86066
|
+
const lessonParser = yield* LessonParserService;
|
|
86067
|
+
const fs = yield* FileSystem_exports.FileSystem;
|
|
86068
|
+
const lessons = yield* lessonParser.getLessonsFromRepo(opts.root);
|
|
86069
|
+
const sections = /* @__PURE__ */ new Set();
|
|
86070
|
+
for (const lesson of lessons) {
|
|
86071
|
+
sections.add(lesson.sectionPath);
|
|
86072
|
+
}
|
|
86073
|
+
const sectionsAsArray = Array.from(sections).sort(
|
|
86074
|
+
(a, b) => a.localeCompare(b)
|
|
86075
|
+
);
|
|
86076
|
+
let totalLessonsRenamed = 0;
|
|
86077
|
+
for (const section of sectionsAsArray) {
|
|
86078
|
+
const lessonsInSection = lessons.filter((lesson) => lesson.sectionPath === section).sort((a, b) => a.num - b.num);
|
|
86079
|
+
const fullSectionPath = path6__namespace.resolve(opts.root, section);
|
|
86080
|
+
yield* Effect_exports.forEach(lessonsInSection, (lesson, index) => {
|
|
86081
|
+
return Effect_exports.gen(function* () {
|
|
86082
|
+
const newLessonNum = (index + 1).toString().padStart(2, "0");
|
|
86083
|
+
const sectionNum = lesson.sectionNum.toString().padStart(2, "0");
|
|
86084
|
+
const newLessonDirname = `${sectionNum}.${newLessonNum}-${lesson.name}`;
|
|
86085
|
+
const newLessonPath = path6__namespace.join(fullSectionPath, newLessonDirname);
|
|
86086
|
+
if (newLessonPath === lesson.absolutePath()) {
|
|
86087
|
+
return;
|
|
86088
|
+
}
|
|
86089
|
+
yield* fs.rename(lesson.absolutePath(), newLessonPath);
|
|
86090
|
+
totalLessonsRenamed++;
|
|
86091
|
+
});
|
|
86092
|
+
});
|
|
86093
|
+
}
|
|
86094
|
+
return totalLessonsRenamed;
|
|
86095
|
+
});
|
|
86310
86096
|
var rename4 = Command_exports.make(
|
|
86311
86097
|
"rename",
|
|
86312
86098
|
{
|
|
@@ -86314,48 +86100,8 @@ var rename4 = Command_exports.make(
|
|
|
86314
86100
|
},
|
|
86315
86101
|
Effect_exports.fn("rename")(
|
|
86316
86102
|
function* ({ root }) {
|
|
86317
|
-
const
|
|
86318
|
-
|
|
86319
|
-
const lessons = yield* lessonParser.getLessonsFromRepo(
|
|
86320
|
-
root
|
|
86321
|
-
);
|
|
86322
|
-
const sections = /* @__PURE__ */ new Set();
|
|
86323
|
-
for (const lesson of lessons) {
|
|
86324
|
-
sections.add(lesson.sectionPath);
|
|
86325
|
-
}
|
|
86326
|
-
const sectionsAsArray = Array.from(sections).sort(
|
|
86327
|
-
(a, b) => a.localeCompare(b)
|
|
86328
|
-
);
|
|
86329
|
-
let totalLessonsRenamed = 0;
|
|
86330
|
-
for (const section of sectionsAsArray) {
|
|
86331
|
-
const lessonsInSection = lessons.filter((lesson) => lesson.sectionPath === section).sort((a, b) => a.num - b.num);
|
|
86332
|
-
const fullSectionPath = path6__namespace.resolve(root, section);
|
|
86333
|
-
yield* Effect_exports.forEach(
|
|
86334
|
-
lessonsInSection,
|
|
86335
|
-
(lesson, index) => {
|
|
86336
|
-
return Effect_exports.gen(function* () {
|
|
86337
|
-
const newLessonNum = (index + 1).toString().padStart(2, "0");
|
|
86338
|
-
const sectionNum = lesson.sectionNum.toString().padStart(2, "0");
|
|
86339
|
-
const newLessonDirname = `${sectionNum}.${newLessonNum}-${lesson.name}`;
|
|
86340
|
-
const newLessonPath = path6__namespace.join(
|
|
86341
|
-
fullSectionPath,
|
|
86342
|
-
newLessonDirname
|
|
86343
|
-
);
|
|
86344
|
-
if (newLessonPath === lesson.absolutePath()) {
|
|
86345
|
-
return;
|
|
86346
|
-
}
|
|
86347
|
-
yield* fs.rename(
|
|
86348
|
-
lesson.absolutePath(),
|
|
86349
|
-
newLessonPath
|
|
86350
|
-
);
|
|
86351
|
-
totalLessonsRenamed++;
|
|
86352
|
-
});
|
|
86353
|
-
}
|
|
86354
|
-
);
|
|
86355
|
-
}
|
|
86356
|
-
yield* Console_exports.log(
|
|
86357
|
-
`Renamed ${totalLessonsRenamed} lessons`
|
|
86358
|
-
);
|
|
86103
|
+
const totalLessonsRenamed = yield* runRename({ root });
|
|
86104
|
+
yield* Console_exports.log(`Renamed ${totalLessonsRenamed} lessons`);
|
|
86359
86105
|
},
|
|
86360
86106
|
Effect_exports.catchTags({
|
|
86361
86107
|
InvalidPathError: (error4) => {
|
|
@@ -87195,7 +86941,7 @@ var editCommit = Command_exports.make(
|
|
|
87195
86941
|
yield* Console_exports.log(
|
|
87196
86942
|
`Resetting to ${targetSha} (${commitLabel})...`
|
|
87197
86943
|
);
|
|
87198
|
-
const resetResult = yield* gitService.
|
|
86944
|
+
const resetResult = yield* gitService.applyAsUnstagedChanges(targetSha).pipe(
|
|
87199
86945
|
Effect_exports.map(() => ({ failed: false })),
|
|
87200
86946
|
Effect_exports.catchTag(
|
|
87201
86947
|
"FailedToResetError",
|
|
@@ -87207,11 +86953,6 @@ var editCommit = Command_exports.make(
|
|
|
87207
86953
|
process.exitCode = 1;
|
|
87208
86954
|
return;
|
|
87209
86955
|
}
|
|
87210
|
-
yield* Console_exports.log(
|
|
87211
|
-
"Undoing commit and unstaging changes..."
|
|
87212
|
-
);
|
|
87213
|
-
yield* gitService.resetHead();
|
|
87214
|
-
yield* gitService.restoreStaged();
|
|
87215
86956
|
yield* Console_exports.log(
|
|
87216
86957
|
"\u2713 Reset complete with unstaged changes"
|
|
87217
86958
|
);
|
|
@@ -87529,7 +87270,7 @@ var applyDemoReset = (commitSha) => Effect_exports.gen(function* () {
|
|
|
87529
87270
|
const git = yield* GitService;
|
|
87530
87271
|
yield* Console_exports.log(`
|
|
87531
87272
|
Resetting to ${commitSha}...`);
|
|
87532
|
-
yield* git.
|
|
87273
|
+
yield* git.applyAsUnstagedChanges(commitSha).pipe(
|
|
87533
87274
|
Effect_exports.catchTag("FailedToResetError", () => {
|
|
87534
87275
|
process.exitCode = 1;
|
|
87535
87276
|
return Effect_exports.fail(
|
|
@@ -87540,10 +87281,6 @@ Resetting to ${commitSha}...`);
|
|
|
87540
87281
|
);
|
|
87541
87282
|
})
|
|
87542
87283
|
);
|
|
87543
|
-
yield* Console_exports.log("Undoing commit...");
|
|
87544
|
-
yield* git.resetHead();
|
|
87545
|
-
yield* Console_exports.log("Unstaging changes...");
|
|
87546
|
-
yield* git.restoreStaged();
|
|
87547
87284
|
yield* Console_exports.log(
|
|
87548
87285
|
"\u2713 Commit applied with unstaged changes\n"
|
|
87549
87286
|
);
|
|
@@ -87955,42 +87692,49 @@ var InvalidBranchOperationError2 = class extends Data_exports.TaggedError(
|
|
|
87955
87692
|
"InvalidBranchOperationError"
|
|
87956
87693
|
) {
|
|
87957
87694
|
};
|
|
87695
|
+
var UncommittedChangesError = class extends Data_exports.TaggedError(
|
|
87696
|
+
"UncommittedChangesError"
|
|
87697
|
+
) {
|
|
87698
|
+
};
|
|
87699
|
+
var runPull = (opts) => Effect_exports.gen(function* () {
|
|
87700
|
+
const git = yield* GitService;
|
|
87701
|
+
yield* git.ensureIsGitRepo();
|
|
87702
|
+
const currentBranch = yield* git.getCurrentBranch();
|
|
87703
|
+
if (currentBranch === "main") {
|
|
87704
|
+
return yield* new InvalidBranchOperationError2({
|
|
87705
|
+
message: "Cannot pull when on main branch. Switch to a working branch first."
|
|
87706
|
+
});
|
|
87707
|
+
}
|
|
87708
|
+
const { hasUncommittedChanges, statusOutput } = yield* git.getUncommittedChanges();
|
|
87709
|
+
if (hasUncommittedChanges) {
|
|
87710
|
+
return yield* new UncommittedChangesError({
|
|
87711
|
+
statusOutput
|
|
87712
|
+
});
|
|
87713
|
+
}
|
|
87714
|
+
yield* git.setUpstreamRemote(opts.upstream);
|
|
87715
|
+
yield* Console_exports.log("Fetching main from upstream...");
|
|
87716
|
+
yield* git.fetch("upstream", "main");
|
|
87717
|
+
yield* Console_exports.log(
|
|
87718
|
+
`Merging upstream/main into ${currentBranch}...`
|
|
87719
|
+
);
|
|
87720
|
+
yield* git.merge("upstream/main");
|
|
87721
|
+
yield* Console_exports.log(
|
|
87722
|
+
`
|
|
87723
|
+
\u2713 Successfully merged upstream/main into ${currentBranch}`
|
|
87724
|
+
);
|
|
87725
|
+
});
|
|
87958
87726
|
var pull = Command_exports.make(
|
|
87959
87727
|
"pull",
|
|
87960
87728
|
{
|
|
87961
|
-
cwd: cwdOption
|
|
87729
|
+
cwd: cwdOption,
|
|
87730
|
+
upstream: Options_exports.text("upstream").pipe(
|
|
87731
|
+
Options_exports.withDescription(
|
|
87732
|
+
"Git URL or local path to the upstream exercise repo"
|
|
87733
|
+
)
|
|
87734
|
+
)
|
|
87962
87735
|
},
|
|
87963
|
-
|
|
87964
|
-
|
|
87965
|
-
yield* git.ensureIsGitRepo();
|
|
87966
|
-
const currentBranch = yield* git.getCurrentBranch();
|
|
87967
|
-
if (currentBranch === "main") {
|
|
87968
|
-
return yield* new InvalidBranchOperationError2({
|
|
87969
|
-
message: "Cannot pull when on main branch. Switch to a working branch first."
|
|
87970
|
-
});
|
|
87971
|
-
}
|
|
87972
|
-
const { hasUncommittedChanges, statusOutput } = yield* git.getUncommittedChanges();
|
|
87973
|
-
if (hasUncommittedChanges) {
|
|
87974
|
-
yield* Console_exports.error("You have uncommitted changes:\n");
|
|
87975
|
-
yield* Console_exports.error(statusOutput);
|
|
87976
|
-
yield* Console_exports.error(
|
|
87977
|
-
"\nCommit or stash your changes before pulling:\n git stash\n ai-hero pull\n git stash pop"
|
|
87978
|
-
);
|
|
87979
|
-
process.exitCode = 1;
|
|
87980
|
-
return;
|
|
87981
|
-
}
|
|
87982
|
-
const { remoteName } = yield* git.detectUpstreamRemote();
|
|
87983
|
-
yield* Console_exports.log(`Fetching main from ${remoteName}...`);
|
|
87984
|
-
yield* git.fetch(remoteName, "main");
|
|
87985
|
-
yield* Console_exports.log(
|
|
87986
|
-
`Merging ${remoteName}/main into ${currentBranch}...`
|
|
87987
|
-
);
|
|
87988
|
-
yield* git.merge(`${remoteName}/main`);
|
|
87989
|
-
yield* Console_exports.log(
|
|
87990
|
-
`
|
|
87991
|
-
\u2713 Successfully merged ${remoteName}/main into ${currentBranch}`
|
|
87992
|
-
);
|
|
87993
|
-
}).pipe(
|
|
87736
|
+
/* v8 ignore start - CLI error handlers are presentation logic */
|
|
87737
|
+
({ cwd, upstream }) => runPull({ upstream }).pipe(
|
|
87994
87738
|
Effect_exports.provideService(
|
|
87995
87739
|
GitServiceConfig,
|
|
87996
87740
|
GitServiceConfig.of({
|
|
@@ -87998,13 +87742,17 @@ var pull = Command_exports.make(
|
|
|
87998
87742
|
})
|
|
87999
87743
|
),
|
|
88000
87744
|
Effect_exports.catchTags({
|
|
88001
|
-
|
|
87745
|
+
UncommittedChangesError: (error4) => {
|
|
88002
87746
|
return Effect_exports.gen(function* () {
|
|
88003
|
-
yield* Console_exports.error(
|
|
87747
|
+
yield* Console_exports.error("You have uncommitted changes:\n");
|
|
87748
|
+
yield* Console_exports.error(error4.statusOutput);
|
|
87749
|
+
yield* Console_exports.error(
|
|
87750
|
+
"\nCommit or stash your changes before pulling:\n git stash\n ai-hero pull\n git stash pop"
|
|
87751
|
+
);
|
|
88004
87752
|
process.exitCode = 1;
|
|
88005
87753
|
});
|
|
88006
87754
|
},
|
|
88007
|
-
|
|
87755
|
+
NotAGitRepoError: (error4) => {
|
|
88008
87756
|
return Effect_exports.gen(function* () {
|
|
88009
87757
|
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
88010
87758
|
process.exitCode = 1;
|
|
@@ -88038,6 +87786,7 @@ var pull = Command_exports.make(
|
|
|
88038
87786
|
});
|
|
88039
87787
|
})
|
|
88040
87788
|
)
|
|
87789
|
+
/* v8 ignore stop */
|
|
88041
87790
|
).pipe(
|
|
88042
87791
|
Command_exports.withDescription(
|
|
88043
87792
|
"Pull latest changes from upstream main"
|
|
@@ -88049,20 +87798,16 @@ var InvalidBranchOperationError3 = class extends Data_exports.TaggedError(
|
|
|
88049
87798
|
"InvalidBranchOperationError"
|
|
88050
87799
|
) {
|
|
88051
87800
|
};
|
|
88052
|
-
var InvalidOptionsError = class extends Data_exports.TaggedError(
|
|
88053
|
-
"InvalidOptionsError"
|
|
88054
|
-
) {
|
|
88055
|
-
};
|
|
88056
87801
|
var runReset = ({
|
|
88057
87802
|
branch,
|
|
88058
87803
|
demo,
|
|
88059
87804
|
lessonId,
|
|
88060
|
-
|
|
88061
|
-
solution
|
|
87805
|
+
upstream
|
|
88062
87806
|
}) => Effect_exports.gen(function* () {
|
|
88063
87807
|
const git = yield* GitService;
|
|
88064
87808
|
const promptService = yield* PromptService;
|
|
88065
87809
|
yield* git.ensureIsGitRepo();
|
|
87810
|
+
yield* git.setUpstreamRemote(upstream);
|
|
88066
87811
|
yield* git.ensureUpstreamBranchConnected({
|
|
88067
87812
|
targetBranch: branch
|
|
88068
87813
|
});
|
|
@@ -88072,32 +87817,7 @@ var runReset = ({
|
|
|
88072
87817
|
promptMessage: "Which lesson do you want to reset to? (type to search)",
|
|
88073
87818
|
excludeCurrentBranch: false
|
|
88074
87819
|
});
|
|
88075
|
-
|
|
88076
|
-
let stateDescription = "final code";
|
|
88077
|
-
if (problem && solution) {
|
|
88078
|
-
return yield* new InvalidOptionsError({
|
|
88079
|
-
message: "Cannot use both --problem and --solution flags"
|
|
88080
|
-
});
|
|
88081
|
-
}
|
|
88082
|
-
if (demo && (problem || solution)) {
|
|
88083
|
-
return yield* new InvalidOptionsError({
|
|
88084
|
-
message: "Cannot use --demo with --problem or --solution flags"
|
|
88085
|
-
});
|
|
88086
|
-
}
|
|
88087
|
-
if (!problem && !solution && !demo) {
|
|
88088
|
-
const state = yield* promptService.selectProblemOrSolution();
|
|
88089
|
-
if (state === "problem") {
|
|
88090
|
-
commitToUse = yield* getParentCommit({
|
|
88091
|
-
commitSha: targetCommit.sha
|
|
88092
|
-
});
|
|
88093
|
-
stateDescription = "problem state";
|
|
88094
|
-
}
|
|
88095
|
-
} else if (problem) {
|
|
88096
|
-
commitToUse = yield* getParentCommit({
|
|
88097
|
-
commitSha: targetCommit.sha
|
|
88098
|
-
});
|
|
88099
|
-
stateDescription = "problem state";
|
|
88100
|
-
}
|
|
87820
|
+
const commitToUse = targetCommit.sha;
|
|
88101
87821
|
const currentBranch = yield* git.getCurrentBranch();
|
|
88102
87822
|
let action;
|
|
88103
87823
|
if (currentBranch === "main") {
|
|
@@ -88124,7 +87844,7 @@ var runReset = ({
|
|
|
88124
87844
|
"new"
|
|
88125
87845
|
);
|
|
88126
87846
|
yield* Console_exports.log(
|
|
88127
|
-
`Creating branch ${branchName} from ${
|
|
87847
|
+
`Creating branch ${branchName} from ${selectedLessonId}...`
|
|
88128
87848
|
);
|
|
88129
87849
|
yield* git.checkoutNewBranchAt(branchName, commitToUse);
|
|
88130
87850
|
yield* Console_exports.log(
|
|
@@ -88143,21 +87863,17 @@ var runReset = ({
|
|
|
88143
87863
|
}
|
|
88144
87864
|
}
|
|
88145
87865
|
yield* Console_exports.log(
|
|
88146
|
-
`Resetting to ${
|
|
87866
|
+
`Resetting to ${selectedLessonId}...`
|
|
88147
87867
|
);
|
|
88148
|
-
yield* git.resetHard(commitToUse);
|
|
88149
87868
|
if (demo) {
|
|
87869
|
+
yield* git.applyAsUnstagedChanges(commitToUse);
|
|
88150
87870
|
yield* Console_exports.log(
|
|
88151
|
-
|
|
88152
|
-
);
|
|
88153
|
-
yield* git.resetHead();
|
|
88154
|
-
yield* git.restoreStaged();
|
|
88155
|
-
yield* Console_exports.log(
|
|
88156
|
-
`\u2713 Demo mode: Reset to lesson ${selectedLessonId} with unstaged changes`
|
|
87871
|
+
`\u2713 Demo mode: Reset to ${selectedLessonId} with unstaged changes`
|
|
88157
87872
|
);
|
|
88158
87873
|
} else {
|
|
87874
|
+
yield* git.resetHard(commitToUse);
|
|
88159
87875
|
yield* Console_exports.log(
|
|
88160
|
-
`\u2713 Reset to
|
|
87876
|
+
`\u2713 Reset to ${selectedLessonId}`
|
|
88161
87877
|
);
|
|
88162
87878
|
}
|
|
88163
87879
|
});
|
|
@@ -88173,22 +87889,16 @@ var reset2 = Command_exports.make(
|
|
|
88173
87889
|
),
|
|
88174
87890
|
Options_exports.withDefault(DEFAULT_PROJECT_TARGET_BRANCH)
|
|
88175
87891
|
),
|
|
88176
|
-
|
|
88177
|
-
|
|
88178
|
-
Options_exports.withDescription(
|
|
88179
|
-
"Reset to problem state (start the exercise)"
|
|
88180
|
-
)
|
|
88181
|
-
),
|
|
88182
|
-
solution: Options_exports.boolean("solution").pipe(
|
|
88183
|
-
Options_exports.withAlias("s"),
|
|
87892
|
+
demo: Options_exports.boolean("demo").pipe(Options_exports.withAlias("d")),
|
|
87893
|
+
upstream: Options_exports.text("upstream").pipe(
|
|
88184
87894
|
Options_exports.withDescription(
|
|
88185
|
-
"
|
|
87895
|
+
"Git URL or local path to the upstream exercise repo"
|
|
88186
87896
|
)
|
|
88187
87897
|
),
|
|
88188
|
-
demo: Options_exports.boolean("demo").pipe(Options_exports.withAlias("d")),
|
|
88189
87898
|
cwd: cwdOption
|
|
88190
87899
|
},
|
|
88191
|
-
|
|
87900
|
+
/* v8 ignore start - CLI error handlers are presentation logic */
|
|
87901
|
+
({ branch, cwd, demo, lessonId, upstream }) => runReset({ branch, lessonId, demo, upstream }).pipe(
|
|
88192
87902
|
Effect_exports.provideService(
|
|
88193
87903
|
GitServiceConfig,
|
|
88194
87904
|
GitServiceConfig.of({
|
|
@@ -88196,26 +87906,12 @@ var reset2 = Command_exports.make(
|
|
|
88196
87906
|
})
|
|
88197
87907
|
),
|
|
88198
87908
|
Effect_exports.catchTags({
|
|
88199
|
-
NoParentCommitError: (error4) => {
|
|
88200
|
-
return Effect_exports.gen(function* () {
|
|
88201
|
-
yield* Console_exports.error(
|
|
88202
|
-
`Error: Commit ${error4.commitSha} has no parent commit. Repository may be in an invalid state.`
|
|
88203
|
-
);
|
|
88204
|
-
process.exitCode = 1;
|
|
88205
|
-
});
|
|
88206
|
-
},
|
|
88207
87909
|
NotAGitRepoError: (error4) => {
|
|
88208
87910
|
return Effect_exports.gen(function* () {
|
|
88209
87911
|
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
88210
87912
|
process.exitCode = 1;
|
|
88211
87913
|
});
|
|
88212
87914
|
},
|
|
88213
|
-
NoUpstreamFoundError: (error4) => {
|
|
88214
|
-
return Effect_exports.gen(function* () {
|
|
88215
|
-
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
88216
|
-
process.exitCode = 1;
|
|
88217
|
-
});
|
|
88218
|
-
},
|
|
88219
87915
|
CommitNotFoundError: (error4) => {
|
|
88220
87916
|
return Effect_exports.gen(function* () {
|
|
88221
87917
|
yield* Console_exports.error(
|
|
@@ -88254,6 +87950,7 @@ var reset2 = Command_exports.make(
|
|
|
88254
87950
|
});
|
|
88255
87951
|
})
|
|
88256
87952
|
)
|
|
87953
|
+
/* v8 ignore stop */
|
|
88257
87954
|
).pipe(
|
|
88258
87955
|
Command_exports.withDescription("Reset to a specific lesson commit")
|
|
88259
87956
|
);
|