ai-hero-cli 0.2.15 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.cjs +743 -1049
- 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(
|
|
@@ -85131,7 +84877,6 @@ var PromptService = class extends Effect_exports.Service()(
|
|
|
85131
84877
|
confirmSaveToTargetBranch,
|
|
85132
84878
|
confirmForcePush,
|
|
85133
84879
|
selectCherryPickConflictAction,
|
|
85134
|
-
selectProblemOrSolution,
|
|
85135
84880
|
selectResetAction,
|
|
85136
84881
|
confirmResetWithUncommittedChanges,
|
|
85137
84882
|
inputBranchName,
|
|
@@ -85257,10 +85002,6 @@ var selectLessonCommit = ({
|
|
|
85257
85002
|
lessonId: selectedLessonId
|
|
85258
85003
|
};
|
|
85259
85004
|
});
|
|
85260
|
-
var getParentCommit = ({ commitSha }) => Effect_exports.gen(function* () {
|
|
85261
|
-
const gitService = yield* GitService;
|
|
85262
|
-
return yield* gitService.getParentCommit(commitSha);
|
|
85263
|
-
});
|
|
85264
85005
|
|
|
85265
85006
|
// src/constants.ts
|
|
85266
85007
|
var DEFAULT_PROJECT_TARGET_BRANCH = "live-run-through";
|
|
@@ -85288,11 +85029,13 @@ var InvalidBranchOperationError = class extends Data_exports.TaggedError(
|
|
|
85288
85029
|
};
|
|
85289
85030
|
var runCherryPick = ({
|
|
85290
85031
|
branch,
|
|
85291
|
-
lessonId
|
|
85032
|
+
lessonId,
|
|
85033
|
+
upstream
|
|
85292
85034
|
}) => Effect_exports.gen(function* () {
|
|
85293
85035
|
const git = yield* GitService;
|
|
85294
85036
|
const promptService = yield* PromptService;
|
|
85295
85037
|
yield* git.ensureIsGitRepo();
|
|
85038
|
+
yield* git.setUpstreamRemote(upstream);
|
|
85296
85039
|
yield* git.ensureUpstreamBranchConnected({
|
|
85297
85040
|
targetBranch: branch
|
|
85298
85041
|
});
|
|
@@ -85342,9 +85085,15 @@ var cherryPick = Command_exports.make(
|
|
|
85342
85085
|
),
|
|
85343
85086
|
Options_exports.withDefault(DEFAULT_PROJECT_TARGET_BRANCH)
|
|
85344
85087
|
),
|
|
85088
|
+
upstream: Options_exports.text("upstream").pipe(
|
|
85089
|
+
Options_exports.withDescription(
|
|
85090
|
+
"Git URL or local path to the upstream exercise repo"
|
|
85091
|
+
)
|
|
85092
|
+
),
|
|
85345
85093
|
cwd: cwdOption
|
|
85346
85094
|
},
|
|
85347
|
-
|
|
85095
|
+
/* v8 ignore start - CLI error handlers are presentation logic */
|
|
85096
|
+
({ branch, cwd, lessonId, upstream }) => runCherryPick({ branch, lessonId, upstream }).pipe(
|
|
85348
85097
|
Effect_exports.provideService(
|
|
85349
85098
|
GitServiceConfig,
|
|
85350
85099
|
GitServiceConfig.of({
|
|
@@ -85358,12 +85107,6 @@ var cherryPick = Command_exports.make(
|
|
|
85358
85107
|
process.exitCode = 1;
|
|
85359
85108
|
});
|
|
85360
85109
|
},
|
|
85361
|
-
NoUpstreamFoundError: (error4) => {
|
|
85362
|
-
return Effect_exports.gen(function* () {
|
|
85363
|
-
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
85364
|
-
process.exitCode = 1;
|
|
85365
|
-
});
|
|
85366
|
-
},
|
|
85367
85110
|
CommitNotFoundError: (error4) => {
|
|
85368
85111
|
return Effect_exports.gen(function* () {
|
|
85369
85112
|
yield* Console_exports.error(
|
|
@@ -85402,6 +85145,7 @@ var cherryPick = Command_exports.make(
|
|
|
85402
85145
|
});
|
|
85403
85146
|
})
|
|
85404
85147
|
)
|
|
85148
|
+
/* v8 ignore stop */
|
|
85405
85149
|
).pipe(
|
|
85406
85150
|
Command_exports.withDescription(
|
|
85407
85151
|
"Cherry-pick a specific lesson commit onto current branch"
|
|
@@ -86084,6 +85828,7 @@ var updateCVM = Command_exports.make(
|
|
|
86084
85828
|
);
|
|
86085
85829
|
var createErrorTracker = () => {
|
|
86086
85830
|
const groupedErrors = {};
|
|
85831
|
+
const errors = [];
|
|
86087
85832
|
return {
|
|
86088
85833
|
addError: (lesson, error4) => {
|
|
86089
85834
|
if (!groupedErrors[lesson.sectionPath]) {
|
|
@@ -86093,20 +85838,21 @@ var createErrorTracker = () => {
|
|
|
86093
85838
|
groupedErrors[lesson.sectionPath][lesson.path] = [];
|
|
86094
85839
|
}
|
|
86095
85840
|
groupedErrors[lesson.sectionPath][lesson.path].push(error4);
|
|
85841
|
+
errors.push({
|
|
85842
|
+
sectionPath: lesson.sectionPath,
|
|
85843
|
+
lessonPath: lesson.path,
|
|
85844
|
+
error: error4
|
|
85845
|
+
});
|
|
86096
85846
|
},
|
|
85847
|
+
getErrors: () => errors,
|
|
85848
|
+
/* v8 ignore start */
|
|
86097
85849
|
log: Effect_exports.gen(function* () {
|
|
86098
|
-
for (const [section, exercises] of Object.entries(
|
|
86099
|
-
groupedErrors
|
|
86100
|
-
)) {
|
|
85850
|
+
for (const [section, exercises] of Object.entries(groupedErrors)) {
|
|
86101
85851
|
yield* Console_exports.log(util.styleText(["bold"], section));
|
|
86102
|
-
for (const [exercise2,
|
|
86103
|
-
exercises
|
|
86104
|
-
)) {
|
|
85852
|
+
for (const [exercise2, errors2] of Object.entries(exercises)) {
|
|
86105
85853
|
yield* Console_exports.log(` ${exercise2}`);
|
|
86106
|
-
for (const error4 of
|
|
86107
|
-
yield* Console_exports.log(
|
|
86108
|
-
util.styleText(["red"], ` ${error4}`)
|
|
86109
|
-
);
|
|
85854
|
+
for (const error4 of errors2) {
|
|
85855
|
+
yield* Console_exports.log(util.styleText(["red"], ` ${error4}`));
|
|
86110
85856
|
}
|
|
86111
85857
|
}
|
|
86112
85858
|
}
|
|
@@ -86114,177 +85860,183 @@ var createErrorTracker = () => {
|
|
|
86114
85860
|
process.exitCode = 1;
|
|
86115
85861
|
}
|
|
86116
85862
|
})
|
|
85863
|
+
/* v8 ignore stop */
|
|
86117
85864
|
};
|
|
86118
85865
|
};
|
|
86119
|
-
var
|
|
86120
|
-
|
|
86121
|
-
|
|
86122
|
-
|
|
86123
|
-
|
|
86124
|
-
|
|
86125
|
-
|
|
86126
|
-
|
|
86127
|
-
|
|
86128
|
-
|
|
86129
|
-
|
|
86130
|
-
|
|
86131
|
-
|
|
86132
|
-
|
|
86133
|
-
|
|
86134
|
-
|
|
86135
|
-
|
|
86136
|
-
|
|
86137
|
-
|
|
86138
|
-
|
|
86139
|
-
|
|
86140
|
-
|
|
85866
|
+
var runLint = (opts) => Effect_exports.gen(function* () {
|
|
85867
|
+
const lessonParser = yield* LessonParserService;
|
|
85868
|
+
const fs = yield* FileSystem_exports.FileSystem;
|
|
85869
|
+
const existsCache = yield* Cache_exports.make({
|
|
85870
|
+
capacity: 1e4,
|
|
85871
|
+
timeToLive: Duration_exports.infinity,
|
|
85872
|
+
lookup: (key) => Effect_exports.gen(function* () {
|
|
85873
|
+
const exists4 = yield* fs.exists(key);
|
|
85874
|
+
return exists4;
|
|
85875
|
+
})
|
|
85876
|
+
});
|
|
85877
|
+
const allReadmeContents = [];
|
|
85878
|
+
const errorTracker = createErrorTracker();
|
|
85879
|
+
const lessons = yield* lessonParser.getLessonsFromRepo(opts.root);
|
|
85880
|
+
for (const lesson of lessons) {
|
|
85881
|
+
const subfolders = yield* lesson.subfolders();
|
|
85882
|
+
if (subfolders.length === 0) {
|
|
85883
|
+
errorTracker.addError(
|
|
85884
|
+
lesson,
|
|
85885
|
+
"No subfolders, like problem or solution, found in the exercise."
|
|
85886
|
+
);
|
|
85887
|
+
continue;
|
|
85888
|
+
}
|
|
85889
|
+
const folderForReadme = subfolders.find(
|
|
85890
|
+
(folder) => folder === "problem" || folder === "explainer" || folder === "explainer.1"
|
|
85891
|
+
);
|
|
85892
|
+
if (!folderForReadme) {
|
|
85893
|
+
errorTracker.addError(
|
|
85894
|
+
lesson,
|
|
85895
|
+
"No problem, explainer, or explainer.1 folder found in the exercise."
|
|
86141
85896
|
);
|
|
86142
|
-
|
|
86143
|
-
|
|
86144
|
-
|
|
85897
|
+
continue;
|
|
85898
|
+
}
|
|
85899
|
+
const readmePath = path6__namespace.join(
|
|
85900
|
+
lesson.absolutePath(),
|
|
85901
|
+
folderForReadme,
|
|
85902
|
+
"readme.md"
|
|
85903
|
+
);
|
|
85904
|
+
const readmeExists = yield* existsCache.get(readmePath);
|
|
85905
|
+
if (!readmeExists) {
|
|
85906
|
+
errorTracker.addError(
|
|
85907
|
+
lesson,
|
|
85908
|
+
"readme.md file not found in the exercise."
|
|
85909
|
+
);
|
|
85910
|
+
} else {
|
|
85911
|
+
const readmeContent = yield* fs.readFileString(readmePath);
|
|
85912
|
+
allReadmeContents.push(readmeContent);
|
|
85913
|
+
if (readmeContent.trim().length === 0) {
|
|
85914
|
+
errorTracker.addError(lesson, "readme.md file is empty");
|
|
85915
|
+
continue;
|
|
85916
|
+
}
|
|
85917
|
+
if (readmeContent.includes("`pnpm run exercise ")) {
|
|
85918
|
+
errorTracker.addError(
|
|
85919
|
+
lesson,
|
|
85920
|
+
"readme.md file contains a pnpm run exercise command. Please remove it."
|
|
85921
|
+
);
|
|
85922
|
+
continue;
|
|
85923
|
+
}
|
|
85924
|
+
const absoluteLinks = readmeContent.match(/\[[^\]]+\]\(\/[^)]+\)/gm) ?? [];
|
|
85925
|
+
for (const link3 of absoluteLinks) {
|
|
85926
|
+
const splitResult = link3.split("](");
|
|
85927
|
+
const url2 = splitResult[1]?.slice(1, -1);
|
|
85928
|
+
if (!url2) continue;
|
|
85929
|
+
const linkExists = yield* existsCache.get(path6__namespace.join(opts.cwd, url2));
|
|
85930
|
+
if (!linkExists) {
|
|
86145
85931
|
errorTracker.addError(
|
|
86146
85932
|
lesson,
|
|
86147
|
-
|
|
85933
|
+
`Broken absolute link in readme.md: ${url2}`
|
|
86148
85934
|
);
|
|
86149
|
-
continue;
|
|
86150
85935
|
}
|
|
86151
|
-
|
|
86152
|
-
|
|
85936
|
+
}
|
|
85937
|
+
const relativeLinks = readmeContent.match(/\[[^\]]+\]\(\.\/[^)]+\)/gm) ?? [];
|
|
85938
|
+
for (const link3 of relativeLinks) {
|
|
85939
|
+
const splitResult = link3.split("](");
|
|
85940
|
+
const url2 = splitResult[1]?.slice(0, -1);
|
|
85941
|
+
if (!url2) continue;
|
|
85942
|
+
const linkExists = yield* existsCache.get(
|
|
85943
|
+
path6__namespace.resolve(lesson.absolutePath(), folderForReadme, url2)
|
|
86153
85944
|
);
|
|
86154
|
-
if (!
|
|
85945
|
+
if (!linkExists) {
|
|
86155
85946
|
errorTracker.addError(
|
|
86156
85947
|
lesson,
|
|
86157
|
-
|
|
85948
|
+
`Broken relative link in readme.md: ${url2}`
|
|
86158
85949
|
);
|
|
86159
|
-
continue;
|
|
86160
85950
|
}
|
|
86161
|
-
|
|
85951
|
+
}
|
|
85952
|
+
}
|
|
85953
|
+
for (const subfolder of subfolders) {
|
|
85954
|
+
const mainFilePath = path6__namespace.join(
|
|
85955
|
+
lesson.absolutePath(),
|
|
85956
|
+
subfolder,
|
|
85957
|
+
"main.ts"
|
|
85958
|
+
);
|
|
85959
|
+
const mainFileExists = yield* existsCache.get(mainFilePath);
|
|
85960
|
+
if (!mainFileExists) {
|
|
85961
|
+
const readmeInSubfolderPath = path6__namespace.join(
|
|
86162
85962
|
lesson.absolutePath(),
|
|
86163
|
-
|
|
85963
|
+
subfolder,
|
|
86164
85964
|
"readme.md"
|
|
86165
85965
|
);
|
|
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"))) {
|
|
85966
|
+
const readmeInSubfolderExists = yield* existsCache.get(readmeInSubfolderPath);
|
|
85967
|
+
if (!readmeInSubfolderExists) {
|
|
86263
85968
|
errorTracker.addError(
|
|
86264
85969
|
lesson,
|
|
86265
|
-
|
|
85970
|
+
`main.ts file not found in the ${subfolder} folder.`
|
|
86266
85971
|
);
|
|
86267
85972
|
}
|
|
86268
|
-
|
|
85973
|
+
} else {
|
|
85974
|
+
const mainFileContent = yield* fs.readFileString(mainFilePath);
|
|
85975
|
+
const lineCount = mainFileContent.trim().split("\n").length;
|
|
85976
|
+
if (lineCount === 1) {
|
|
86269
85977
|
errorTracker.addError(
|
|
86270
85978
|
lesson,
|
|
86271
|
-
|
|
85979
|
+
`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
85980
|
);
|
|
86273
85981
|
}
|
|
86274
85982
|
}
|
|
86275
|
-
|
|
86276
|
-
|
|
86277
|
-
|
|
85983
|
+
}
|
|
85984
|
+
const files = yield* lesson.allFiles();
|
|
85985
|
+
if (files.some((file6) => file6.includes(".gitkeep"))) {
|
|
85986
|
+
errorTracker.addError(lesson, ".gitkeep file found in the exercise.");
|
|
85987
|
+
}
|
|
85988
|
+
if (files.some((file6) => file6.includes("speaker-notes.md"))) {
|
|
85989
|
+
errorTracker.addError(
|
|
85990
|
+
lesson,
|
|
85991
|
+
"speaker-notes.md file found in the exercise. This should not be exposed to users."
|
|
86278
85992
|
);
|
|
86279
|
-
|
|
86280
|
-
|
|
86281
|
-
|
|
86282
|
-
|
|
86283
|
-
|
|
86284
|
-
|
|
85993
|
+
}
|
|
85994
|
+
}
|
|
85995
|
+
const readmeContents = allReadmeContents.join("\n");
|
|
85996
|
+
const referenceLessons = lessons.filter(
|
|
85997
|
+
(lesson) => lesson.sectionName === "reference"
|
|
85998
|
+
);
|
|
85999
|
+
for (const referenceLesson of referenceLessons) {
|
|
86000
|
+
if (!readmeContents.includes(referenceLesson.path)) {
|
|
86001
|
+
errorTracker.addError(
|
|
86002
|
+
referenceLesson,
|
|
86003
|
+
`${referenceLesson.path} is not referenced in any other exercise.`
|
|
86004
|
+
);
|
|
86005
|
+
}
|
|
86006
|
+
}
|
|
86007
|
+
return errorTracker.getErrors();
|
|
86008
|
+
});
|
|
86009
|
+
var lint = Command_exports.make(
|
|
86010
|
+
"lint",
|
|
86011
|
+
{
|
|
86012
|
+
root: rootOption,
|
|
86013
|
+
cwd: cwdOption
|
|
86014
|
+
},
|
|
86015
|
+
Effect_exports.fn("lint")(
|
|
86016
|
+
function* ({ cwd, root }) {
|
|
86017
|
+
const errors = yield* runLint({ cwd, root });
|
|
86018
|
+
const groupedErrors = {};
|
|
86019
|
+
for (const error4 of errors) {
|
|
86020
|
+
if (!groupedErrors[error4.sectionPath]) {
|
|
86021
|
+
groupedErrors[error4.sectionPath] = {};
|
|
86022
|
+
}
|
|
86023
|
+
if (!groupedErrors[error4.sectionPath][error4.lessonPath]) {
|
|
86024
|
+
groupedErrors[error4.sectionPath][error4.lessonPath] = [];
|
|
86285
86025
|
}
|
|
86026
|
+
groupedErrors[error4.sectionPath][error4.lessonPath].push(error4.error);
|
|
86027
|
+
}
|
|
86028
|
+
for (const [section, exercises] of Object.entries(groupedErrors)) {
|
|
86029
|
+
yield* Console_exports.log(util.styleText(["bold"], section));
|
|
86030
|
+
for (const [exercise2, errs] of Object.entries(exercises)) {
|
|
86031
|
+
yield* Console_exports.log(` ${exercise2}`);
|
|
86032
|
+
for (const err of errs) {
|
|
86033
|
+
yield* Console_exports.log(util.styleText(["red"], ` ${err}`));
|
|
86034
|
+
}
|
|
86035
|
+
}
|
|
86036
|
+
}
|
|
86037
|
+
if (errors.length > 0) {
|
|
86038
|
+
process.exitCode = 1;
|
|
86286
86039
|
}
|
|
86287
|
-
yield* errorTracker.log;
|
|
86288
86040
|
},
|
|
86289
86041
|
Effect_exports.catchTags({
|
|
86290
86042
|
InvalidPathError: (error4) => {
|
|
@@ -86307,6 +86059,37 @@ var lint = Command_exports.make(
|
|
|
86307
86059
|
"Lint the repository to ensure it is formatted correctly"
|
|
86308
86060
|
)
|
|
86309
86061
|
);
|
|
86062
|
+
var runRename = (opts) => Effect_exports.gen(function* () {
|
|
86063
|
+
const lessonParser = yield* LessonParserService;
|
|
86064
|
+
const fs = yield* FileSystem_exports.FileSystem;
|
|
86065
|
+
const lessons = yield* lessonParser.getLessonsFromRepo(opts.root);
|
|
86066
|
+
const sections = /* @__PURE__ */ new Set();
|
|
86067
|
+
for (const lesson of lessons) {
|
|
86068
|
+
sections.add(lesson.sectionPath);
|
|
86069
|
+
}
|
|
86070
|
+
const sectionsAsArray = Array.from(sections).sort(
|
|
86071
|
+
(a, b) => a.localeCompare(b)
|
|
86072
|
+
);
|
|
86073
|
+
let totalLessonsRenamed = 0;
|
|
86074
|
+
for (const section of sectionsAsArray) {
|
|
86075
|
+
const lessonsInSection = lessons.filter((lesson) => lesson.sectionPath === section).sort((a, b) => a.num - b.num);
|
|
86076
|
+
const fullSectionPath = path6__namespace.resolve(opts.root, section);
|
|
86077
|
+
yield* Effect_exports.forEach(lessonsInSection, (lesson, index) => {
|
|
86078
|
+
return Effect_exports.gen(function* () {
|
|
86079
|
+
const newLessonNum = (index + 1).toString().padStart(2, "0");
|
|
86080
|
+
const sectionNum = lesson.sectionNum.toString().padStart(2, "0");
|
|
86081
|
+
const newLessonDirname = `${sectionNum}.${newLessonNum}-${lesson.name}`;
|
|
86082
|
+
const newLessonPath = path6__namespace.join(fullSectionPath, newLessonDirname);
|
|
86083
|
+
if (newLessonPath === lesson.absolutePath()) {
|
|
86084
|
+
return;
|
|
86085
|
+
}
|
|
86086
|
+
yield* fs.rename(lesson.absolutePath(), newLessonPath);
|
|
86087
|
+
totalLessonsRenamed++;
|
|
86088
|
+
});
|
|
86089
|
+
});
|
|
86090
|
+
}
|
|
86091
|
+
return totalLessonsRenamed;
|
|
86092
|
+
});
|
|
86310
86093
|
var rename4 = Command_exports.make(
|
|
86311
86094
|
"rename",
|
|
86312
86095
|
{
|
|
@@ -86314,48 +86097,8 @@ var rename4 = Command_exports.make(
|
|
|
86314
86097
|
},
|
|
86315
86098
|
Effect_exports.fn("rename")(
|
|
86316
86099
|
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
|
-
);
|
|
86100
|
+
const totalLessonsRenamed = yield* runRename({ root });
|
|
86101
|
+
yield* Console_exports.log(`Renamed ${totalLessonsRenamed} lessons`);
|
|
86359
86102
|
},
|
|
86360
86103
|
Effect_exports.catchTags({
|
|
86361
86104
|
InvalidPathError: (error4) => {
|
|
@@ -87195,7 +86938,7 @@ var editCommit = Command_exports.make(
|
|
|
87195
86938
|
yield* Console_exports.log(
|
|
87196
86939
|
`Resetting to ${targetSha} (${commitLabel})...`
|
|
87197
86940
|
);
|
|
87198
|
-
const resetResult = yield* gitService.
|
|
86941
|
+
const resetResult = yield* gitService.applyAsUnstagedChanges(targetSha).pipe(
|
|
87199
86942
|
Effect_exports.map(() => ({ failed: false })),
|
|
87200
86943
|
Effect_exports.catchTag(
|
|
87201
86944
|
"FailedToResetError",
|
|
@@ -87207,11 +86950,6 @@ var editCommit = Command_exports.make(
|
|
|
87207
86950
|
process.exitCode = 1;
|
|
87208
86951
|
return;
|
|
87209
86952
|
}
|
|
87210
|
-
yield* Console_exports.log(
|
|
87211
|
-
"Undoing commit and unstaging changes..."
|
|
87212
|
-
);
|
|
87213
|
-
yield* gitService.resetHead();
|
|
87214
|
-
yield* gitService.restoreStaged();
|
|
87215
86953
|
yield* Console_exports.log(
|
|
87216
86954
|
"\u2713 Reset complete with unstaged changes"
|
|
87217
86955
|
);
|
|
@@ -87529,7 +87267,7 @@ var applyDemoReset = (commitSha) => Effect_exports.gen(function* () {
|
|
|
87529
87267
|
const git = yield* GitService;
|
|
87530
87268
|
yield* Console_exports.log(`
|
|
87531
87269
|
Resetting to ${commitSha}...`);
|
|
87532
|
-
yield* git.
|
|
87270
|
+
yield* git.applyAsUnstagedChanges(commitSha).pipe(
|
|
87533
87271
|
Effect_exports.catchTag("FailedToResetError", () => {
|
|
87534
87272
|
process.exitCode = 1;
|
|
87535
87273
|
return Effect_exports.fail(
|
|
@@ -87540,10 +87278,6 @@ Resetting to ${commitSha}...`);
|
|
|
87540
87278
|
);
|
|
87541
87279
|
})
|
|
87542
87280
|
);
|
|
87543
|
-
yield* Console_exports.log("Undoing commit...");
|
|
87544
|
-
yield* git.resetHead();
|
|
87545
|
-
yield* Console_exports.log("Unstaging changes...");
|
|
87546
|
-
yield* git.restoreStaged();
|
|
87547
87281
|
yield* Console_exports.log(
|
|
87548
87282
|
"\u2713 Commit applied with unstaged changes\n"
|
|
87549
87283
|
);
|
|
@@ -87955,42 +87689,49 @@ var InvalidBranchOperationError2 = class extends Data_exports.TaggedError(
|
|
|
87955
87689
|
"InvalidBranchOperationError"
|
|
87956
87690
|
) {
|
|
87957
87691
|
};
|
|
87692
|
+
var UncommittedChangesError = class extends Data_exports.TaggedError(
|
|
87693
|
+
"UncommittedChangesError"
|
|
87694
|
+
) {
|
|
87695
|
+
};
|
|
87696
|
+
var runPull = (opts) => Effect_exports.gen(function* () {
|
|
87697
|
+
const git = yield* GitService;
|
|
87698
|
+
yield* git.ensureIsGitRepo();
|
|
87699
|
+
const currentBranch = yield* git.getCurrentBranch();
|
|
87700
|
+
if (currentBranch === "main") {
|
|
87701
|
+
return yield* new InvalidBranchOperationError2({
|
|
87702
|
+
message: "Cannot pull when on main branch. Switch to a working branch first."
|
|
87703
|
+
});
|
|
87704
|
+
}
|
|
87705
|
+
const { hasUncommittedChanges, statusOutput } = yield* git.getUncommittedChanges();
|
|
87706
|
+
if (hasUncommittedChanges) {
|
|
87707
|
+
return yield* new UncommittedChangesError({
|
|
87708
|
+
statusOutput
|
|
87709
|
+
});
|
|
87710
|
+
}
|
|
87711
|
+
yield* git.setUpstreamRemote(opts.upstream);
|
|
87712
|
+
yield* Console_exports.log("Fetching main from upstream...");
|
|
87713
|
+
yield* git.fetch("upstream", "main");
|
|
87714
|
+
yield* Console_exports.log(
|
|
87715
|
+
`Merging upstream/main into ${currentBranch}...`
|
|
87716
|
+
);
|
|
87717
|
+
yield* git.merge("upstream/main");
|
|
87718
|
+
yield* Console_exports.log(
|
|
87719
|
+
`
|
|
87720
|
+
\u2713 Successfully merged upstream/main into ${currentBranch}`
|
|
87721
|
+
);
|
|
87722
|
+
});
|
|
87958
87723
|
var pull = Command_exports.make(
|
|
87959
87724
|
"pull",
|
|
87960
87725
|
{
|
|
87961
|
-
cwd: cwdOption
|
|
87726
|
+
cwd: cwdOption,
|
|
87727
|
+
upstream: Options_exports.text("upstream").pipe(
|
|
87728
|
+
Options_exports.withDescription(
|
|
87729
|
+
"Git URL or local path to the upstream exercise repo"
|
|
87730
|
+
)
|
|
87731
|
+
)
|
|
87962
87732
|
},
|
|
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(
|
|
87733
|
+
/* v8 ignore start - CLI error handlers are presentation logic */
|
|
87734
|
+
({ cwd, upstream }) => runPull({ upstream }).pipe(
|
|
87994
87735
|
Effect_exports.provideService(
|
|
87995
87736
|
GitServiceConfig,
|
|
87996
87737
|
GitServiceConfig.of({
|
|
@@ -87998,13 +87739,17 @@ var pull = Command_exports.make(
|
|
|
87998
87739
|
})
|
|
87999
87740
|
),
|
|
88000
87741
|
Effect_exports.catchTags({
|
|
88001
|
-
|
|
87742
|
+
UncommittedChangesError: (error4) => {
|
|
88002
87743
|
return Effect_exports.gen(function* () {
|
|
88003
|
-
yield* Console_exports.error(
|
|
87744
|
+
yield* Console_exports.error("You have uncommitted changes:\n");
|
|
87745
|
+
yield* Console_exports.error(error4.statusOutput);
|
|
87746
|
+
yield* Console_exports.error(
|
|
87747
|
+
"\nCommit or stash your changes before pulling:\n git stash\n ai-hero pull\n git stash pop"
|
|
87748
|
+
);
|
|
88004
87749
|
process.exitCode = 1;
|
|
88005
87750
|
});
|
|
88006
87751
|
},
|
|
88007
|
-
|
|
87752
|
+
NotAGitRepoError: (error4) => {
|
|
88008
87753
|
return Effect_exports.gen(function* () {
|
|
88009
87754
|
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
88010
87755
|
process.exitCode = 1;
|
|
@@ -88038,6 +87783,7 @@ var pull = Command_exports.make(
|
|
|
88038
87783
|
});
|
|
88039
87784
|
})
|
|
88040
87785
|
)
|
|
87786
|
+
/* v8 ignore stop */
|
|
88041
87787
|
).pipe(
|
|
88042
87788
|
Command_exports.withDescription(
|
|
88043
87789
|
"Pull latest changes from upstream main"
|
|
@@ -88049,20 +87795,16 @@ var InvalidBranchOperationError3 = class extends Data_exports.TaggedError(
|
|
|
88049
87795
|
"InvalidBranchOperationError"
|
|
88050
87796
|
) {
|
|
88051
87797
|
};
|
|
88052
|
-
var InvalidOptionsError = class extends Data_exports.TaggedError(
|
|
88053
|
-
"InvalidOptionsError"
|
|
88054
|
-
) {
|
|
88055
|
-
};
|
|
88056
87798
|
var runReset = ({
|
|
88057
87799
|
branch,
|
|
88058
87800
|
demo,
|
|
88059
87801
|
lessonId,
|
|
88060
|
-
|
|
88061
|
-
solution
|
|
87802
|
+
upstream
|
|
88062
87803
|
}) => Effect_exports.gen(function* () {
|
|
88063
87804
|
const git = yield* GitService;
|
|
88064
87805
|
const promptService = yield* PromptService;
|
|
88065
87806
|
yield* git.ensureIsGitRepo();
|
|
87807
|
+
yield* git.setUpstreamRemote(upstream);
|
|
88066
87808
|
yield* git.ensureUpstreamBranchConnected({
|
|
88067
87809
|
targetBranch: branch
|
|
88068
87810
|
});
|
|
@@ -88072,32 +87814,7 @@ var runReset = ({
|
|
|
88072
87814
|
promptMessage: "Which lesson do you want to reset to? (type to search)",
|
|
88073
87815
|
excludeCurrentBranch: false
|
|
88074
87816
|
});
|
|
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
|
-
}
|
|
87817
|
+
const commitToUse = targetCommit.sha;
|
|
88101
87818
|
const currentBranch = yield* git.getCurrentBranch();
|
|
88102
87819
|
let action;
|
|
88103
87820
|
if (currentBranch === "main") {
|
|
@@ -88124,7 +87841,7 @@ var runReset = ({
|
|
|
88124
87841
|
"new"
|
|
88125
87842
|
);
|
|
88126
87843
|
yield* Console_exports.log(
|
|
88127
|
-
`Creating branch ${branchName} from ${
|
|
87844
|
+
`Creating branch ${branchName} from ${selectedLessonId}...`
|
|
88128
87845
|
);
|
|
88129
87846
|
yield* git.checkoutNewBranchAt(branchName, commitToUse);
|
|
88130
87847
|
yield* Console_exports.log(
|
|
@@ -88143,21 +87860,17 @@ var runReset = ({
|
|
|
88143
87860
|
}
|
|
88144
87861
|
}
|
|
88145
87862
|
yield* Console_exports.log(
|
|
88146
|
-
`Resetting to ${
|
|
87863
|
+
`Resetting to ${selectedLessonId}...`
|
|
88147
87864
|
);
|
|
88148
|
-
yield* git.resetHard(commitToUse);
|
|
88149
87865
|
if (demo) {
|
|
87866
|
+
yield* git.applyAsUnstagedChanges(commitToUse);
|
|
88150
87867
|
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`
|
|
87868
|
+
`\u2713 Demo mode: Reset to ${selectedLessonId} with unstaged changes`
|
|
88157
87869
|
);
|
|
88158
87870
|
} else {
|
|
87871
|
+
yield* git.resetHard(commitToUse);
|
|
88159
87872
|
yield* Console_exports.log(
|
|
88160
|
-
`\u2713 Reset to
|
|
87873
|
+
`\u2713 Reset to ${selectedLessonId}`
|
|
88161
87874
|
);
|
|
88162
87875
|
}
|
|
88163
87876
|
});
|
|
@@ -88173,22 +87886,16 @@ var reset2 = Command_exports.make(
|
|
|
88173
87886
|
),
|
|
88174
87887
|
Options_exports.withDefault(DEFAULT_PROJECT_TARGET_BRANCH)
|
|
88175
87888
|
),
|
|
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"),
|
|
87889
|
+
demo: Options_exports.boolean("demo").pipe(Options_exports.withAlias("d")),
|
|
87890
|
+
upstream: Options_exports.text("upstream").pipe(
|
|
88184
87891
|
Options_exports.withDescription(
|
|
88185
|
-
"
|
|
87892
|
+
"Git URL or local path to the upstream exercise repo"
|
|
88186
87893
|
)
|
|
88187
87894
|
),
|
|
88188
|
-
demo: Options_exports.boolean("demo").pipe(Options_exports.withAlias("d")),
|
|
88189
87895
|
cwd: cwdOption
|
|
88190
87896
|
},
|
|
88191
|
-
|
|
87897
|
+
/* v8 ignore start - CLI error handlers are presentation logic */
|
|
87898
|
+
({ branch, cwd, demo, lessonId, upstream }) => runReset({ branch, lessonId, demo, upstream }).pipe(
|
|
88192
87899
|
Effect_exports.provideService(
|
|
88193
87900
|
GitServiceConfig,
|
|
88194
87901
|
GitServiceConfig.of({
|
|
@@ -88196,26 +87903,12 @@ var reset2 = Command_exports.make(
|
|
|
88196
87903
|
})
|
|
88197
87904
|
),
|
|
88198
87905
|
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
87906
|
NotAGitRepoError: (error4) => {
|
|
88208
87907
|
return Effect_exports.gen(function* () {
|
|
88209
87908
|
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
88210
87909
|
process.exitCode = 1;
|
|
88211
87910
|
});
|
|
88212
87911
|
},
|
|
88213
|
-
NoUpstreamFoundError: (error4) => {
|
|
88214
|
-
return Effect_exports.gen(function* () {
|
|
88215
|
-
yield* Console_exports.error(`Error: ${error4.message}`);
|
|
88216
|
-
process.exitCode = 1;
|
|
88217
|
-
});
|
|
88218
|
-
},
|
|
88219
87912
|
CommitNotFoundError: (error4) => {
|
|
88220
87913
|
return Effect_exports.gen(function* () {
|
|
88221
87914
|
yield* Console_exports.error(
|
|
@@ -88254,6 +87947,7 @@ var reset2 = Command_exports.make(
|
|
|
88254
87947
|
});
|
|
88255
87948
|
})
|
|
88256
87949
|
)
|
|
87950
|
+
/* v8 ignore stop */
|
|
88257
87951
|
).pipe(
|
|
88258
87952
|
Command_exports.withDescription("Reset to a specific lesson commit")
|
|
88259
87953
|
);
|