careermate 0.0.8 → 0.0.9
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/AGENTS.md +2 -2
- package/LICENSE +1 -1
- package/README.md +78 -81
- package/bin/careermate.mjs +11 -2
- package/dist/career-os/eop/cover-letter.md +10 -4
- package/dist/career-os/eop/interview-prep.md +1 -0
- package/dist/career-os/knowledge/cover-letter.md +4 -0
- package/dist/career-os/knowledge/verifiers/human-voice.md +7 -2
- package/dist/doctor.mjs +888 -340
- package/dist/mcp.mjs +904 -350
- package/dist/migrate.mjs +208 -16
- package/dist/public/i18n/en/applications.js +19 -0
- package/dist/public/i18n/en/common.js +6 -0
- package/dist/public/i18n/en/jobs.js +17 -0
- package/dist/public/i18n/en/settings.js +5 -2
- package/dist/public/i18n/ko/applications.js +19 -0
- package/dist/public/i18n/ko/common.js +5 -0
- package/dist/public/i18n/ko/jobs.js +17 -0
- package/dist/public/i18n/ko/settings.js +5 -2
- package/dist/public/lib.js +29 -0
- package/dist/public/pages/applications.js +86 -10
- package/dist/public/pages/documents.js +16 -7
- package/dist/public/pages/home.js +12 -0
- package/dist/public/pages/interview.js +11 -4
- package/dist/public/pages/jobs.js +71 -1
- package/dist/public/pages/settings.js +2 -2
- package/dist/public/styles.css +13 -0
- package/dist/web.mjs +544 -199
- package/docs/FAQ.md +13 -3
- package/docs/MCP_TOOLS.md +22 -9
- package/docs/career-os/eop/cover-letter.md +10 -4
- package/docs/career-os/eop/interview-prep.md +1 -0
- package/docs/career-os/knowledge/cover-letter.md +4 -0
- package/docs/career-os/knowledge/verifiers/human-voice.md +7 -2
- package/package.json +3 -1
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/jobsearch.ts +6 -2
- package/packages/core/src/offers.ts +41 -0
- package/packages/core/src/services.ts +5 -1
- package/packages/core/src/summary.ts +245 -19
- package/packages/db/src/connection.ts +70 -2
- package/packages/db/src/index.ts +1 -0
- package/packages/db/src/repositories.ts +140 -8
- package/packages/db/src/schema.ts +140 -8
- package/packages/mcp-tools/src/result.ts +9 -0
- package/packages/mcp-tools/src/tools.ts +143 -20
- package/packages/parsers/src/documents.ts +7 -1
- package/packages/prompts/src/humanize.ts +4 -0
- package/packages/shared/src/schemas.ts +134 -0
- package/scripts/init.ts +2 -0
package/dist/web.mjs
CHANGED
|
@@ -976,8 +976,8 @@ var init_tap = __esm({
|
|
|
976
976
|
});
|
|
977
977
|
|
|
978
978
|
// node_modules/underscore/modules/toPath.js
|
|
979
|
-
function toPath(
|
|
980
|
-
return isArray_default(
|
|
979
|
+
function toPath(path7) {
|
|
980
|
+
return isArray_default(path7) ? path7 : [path7];
|
|
981
981
|
}
|
|
982
982
|
var init_toPath = __esm({
|
|
983
983
|
"node_modules/underscore/modules/toPath.js"() {
|
|
@@ -989,8 +989,8 @@ var init_toPath = __esm({
|
|
|
989
989
|
});
|
|
990
990
|
|
|
991
991
|
// node_modules/underscore/modules/_toPath.js
|
|
992
|
-
function toPath2(
|
|
993
|
-
return _.toPath(
|
|
992
|
+
function toPath2(path7) {
|
|
993
|
+
return _.toPath(path7);
|
|
994
994
|
}
|
|
995
995
|
var init_toPath2 = __esm({
|
|
996
996
|
"node_modules/underscore/modules/_toPath.js"() {
|
|
@@ -1001,11 +1001,11 @@ var init_toPath2 = __esm({
|
|
|
1001
1001
|
});
|
|
1002
1002
|
|
|
1003
1003
|
// node_modules/underscore/modules/_deepGet.js
|
|
1004
|
-
function deepGet(obj2,
|
|
1005
|
-
var length =
|
|
1004
|
+
function deepGet(obj2, path7) {
|
|
1005
|
+
var length = path7.length;
|
|
1006
1006
|
for (var i = 0; i < length; i++) {
|
|
1007
1007
|
if (obj2 == null) return void 0;
|
|
1008
|
-
obj2 = obj2[
|
|
1008
|
+
obj2 = obj2[path7[i]];
|
|
1009
1009
|
}
|
|
1010
1010
|
return length ? obj2 : void 0;
|
|
1011
1011
|
}
|
|
@@ -1016,8 +1016,8 @@ var init_deepGet = __esm({
|
|
|
1016
1016
|
});
|
|
1017
1017
|
|
|
1018
1018
|
// node_modules/underscore/modules/get.js
|
|
1019
|
-
function get(object2,
|
|
1020
|
-
var value = deepGet(object2, toPath2(
|
|
1019
|
+
function get(object2, path7, defaultValue) {
|
|
1020
|
+
var value = deepGet(object2, toPath2(path7));
|
|
1021
1021
|
return isUndefined(value) ? defaultValue : value;
|
|
1022
1022
|
}
|
|
1023
1023
|
var init_get = __esm({
|
|
@@ -1030,11 +1030,11 @@ var init_get = __esm({
|
|
|
1030
1030
|
});
|
|
1031
1031
|
|
|
1032
1032
|
// node_modules/underscore/modules/has.js
|
|
1033
|
-
function has2(obj2,
|
|
1034
|
-
|
|
1035
|
-
var length =
|
|
1033
|
+
function has2(obj2, path7) {
|
|
1034
|
+
path7 = toPath2(path7);
|
|
1035
|
+
var length = path7.length;
|
|
1036
1036
|
for (var i = 0; i < length; i++) {
|
|
1037
|
-
var key =
|
|
1037
|
+
var key = path7[i];
|
|
1038
1038
|
if (!has(obj2, key)) return false;
|
|
1039
1039
|
obj2 = obj2[key];
|
|
1040
1040
|
}
|
|
@@ -1074,10 +1074,10 @@ var init_matcher = __esm({
|
|
|
1074
1074
|
});
|
|
1075
1075
|
|
|
1076
1076
|
// node_modules/underscore/modules/property.js
|
|
1077
|
-
function property(
|
|
1078
|
-
|
|
1077
|
+
function property(path7) {
|
|
1078
|
+
path7 = toPath2(path7);
|
|
1079
1079
|
return function(obj2) {
|
|
1080
|
-
return deepGet(obj2,
|
|
1080
|
+
return deepGet(obj2, path7);
|
|
1081
1081
|
};
|
|
1082
1082
|
}
|
|
1083
1083
|
var init_property = __esm({
|
|
@@ -1193,8 +1193,8 @@ var init_noop = __esm({
|
|
|
1193
1193
|
// node_modules/underscore/modules/propertyOf.js
|
|
1194
1194
|
function propertyOf(obj2) {
|
|
1195
1195
|
if (obj2 == null) return noop;
|
|
1196
|
-
return function(
|
|
1197
|
-
return get(obj2,
|
|
1196
|
+
return function(path7) {
|
|
1197
|
+
return get(obj2, path7);
|
|
1198
1198
|
};
|
|
1199
1199
|
}
|
|
1200
1200
|
var init_propertyOf = __esm({
|
|
@@ -1399,14 +1399,14 @@ var init_template = __esm({
|
|
|
1399
1399
|
});
|
|
1400
1400
|
|
|
1401
1401
|
// node_modules/underscore/modules/result.js
|
|
1402
|
-
function result(obj2,
|
|
1403
|
-
|
|
1404
|
-
var length =
|
|
1402
|
+
function result(obj2, path7, fallback) {
|
|
1403
|
+
path7 = toPath2(path7);
|
|
1404
|
+
var length = path7.length;
|
|
1405
1405
|
if (!length) {
|
|
1406
1406
|
return isFunction_default(fallback) ? fallback.call(obj2) : fallback;
|
|
1407
1407
|
}
|
|
1408
1408
|
for (var i = 0; i < length; i++) {
|
|
1409
|
-
var prop = obj2 == null ? void 0 : obj2[
|
|
1409
|
+
var prop = obj2 == null ? void 0 : obj2[path7[i]];
|
|
1410
1410
|
if (prop === void 0) {
|
|
1411
1411
|
prop = fallback;
|
|
1412
1412
|
i = length;
|
|
@@ -2130,14 +2130,14 @@ var init_invoke = __esm({
|
|
|
2130
2130
|
init_map();
|
|
2131
2131
|
init_deepGet();
|
|
2132
2132
|
init_toPath2();
|
|
2133
|
-
invoke_default = restArguments(function(obj2,
|
|
2133
|
+
invoke_default = restArguments(function(obj2, path7, args) {
|
|
2134
2134
|
var contextPath, func;
|
|
2135
|
-
if (isFunction_default(
|
|
2136
|
-
func =
|
|
2135
|
+
if (isFunction_default(path7)) {
|
|
2136
|
+
func = path7;
|
|
2137
2137
|
} else {
|
|
2138
|
-
|
|
2139
|
-
contextPath =
|
|
2140
|
-
|
|
2138
|
+
path7 = toPath2(path7);
|
|
2139
|
+
contextPath = path7.slice(0, -1);
|
|
2140
|
+
path7 = path7[path7.length - 1];
|
|
2141
2141
|
}
|
|
2142
2142
|
return map(obj2, function(context) {
|
|
2143
2143
|
var method = func;
|
|
@@ -2146,7 +2146,7 @@ var init_invoke = __esm({
|
|
|
2146
2146
|
context = deepGet(context, contextPath);
|
|
2147
2147
|
}
|
|
2148
2148
|
if (context == null) return void 0;
|
|
2149
|
-
method = context[
|
|
2149
|
+
method = context[path7];
|
|
2150
2150
|
}
|
|
2151
2151
|
return method == null ? method : method.apply(context, args);
|
|
2152
2152
|
});
|
|
@@ -11664,8 +11664,8 @@ var require_utils = __commonJS({
|
|
|
11664
11664
|
var result2 = transform[inputType][outputType](input);
|
|
11665
11665
|
return result2;
|
|
11666
11666
|
};
|
|
11667
|
-
exports2.resolve = function(
|
|
11668
|
-
var parts =
|
|
11667
|
+
exports2.resolve = function(path7) {
|
|
11668
|
+
var parts = path7.split("/");
|
|
11669
11669
|
var result2 = [];
|
|
11670
11670
|
for (var index = 0; index < parts.length; index++) {
|
|
11671
11671
|
var part = parts[index];
|
|
@@ -17518,18 +17518,18 @@ var require_object = __commonJS({
|
|
|
17518
17518
|
var object2 = new ZipObject(name, zipObjectContent, o);
|
|
17519
17519
|
this.files[name] = object2;
|
|
17520
17520
|
};
|
|
17521
|
-
var parentFolder = function(
|
|
17522
|
-
if (
|
|
17523
|
-
|
|
17521
|
+
var parentFolder = function(path7) {
|
|
17522
|
+
if (path7.slice(-1) === "/") {
|
|
17523
|
+
path7 = path7.substring(0, path7.length - 1);
|
|
17524
17524
|
}
|
|
17525
|
-
var lastSlash =
|
|
17526
|
-
return lastSlash > 0 ?
|
|
17525
|
+
var lastSlash = path7.lastIndexOf("/");
|
|
17526
|
+
return lastSlash > 0 ? path7.substring(0, lastSlash) : "";
|
|
17527
17527
|
};
|
|
17528
|
-
var forceTrailingSlash = function(
|
|
17529
|
-
if (
|
|
17530
|
-
|
|
17528
|
+
var forceTrailingSlash = function(path7) {
|
|
17529
|
+
if (path7.slice(-1) !== "/") {
|
|
17530
|
+
path7 += "/";
|
|
17531
17531
|
}
|
|
17532
|
-
return
|
|
17532
|
+
return path7;
|
|
17533
17533
|
};
|
|
17534
17534
|
var folderAdd = function(name, createFolders) {
|
|
17535
17535
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -18568,27 +18568,27 @@ var require_zipfile = __commonJS({
|
|
|
18568
18568
|
};
|
|
18569
18569
|
});
|
|
18570
18570
|
}
|
|
18571
|
-
function splitPath(
|
|
18572
|
-
var lastIndex =
|
|
18571
|
+
function splitPath(path7) {
|
|
18572
|
+
var lastIndex = path7.lastIndexOf("/");
|
|
18573
18573
|
if (lastIndex === -1) {
|
|
18574
|
-
return { dirname: "", basename:
|
|
18574
|
+
return { dirname: "", basename: path7 };
|
|
18575
18575
|
} else {
|
|
18576
18576
|
return {
|
|
18577
|
-
dirname:
|
|
18578
|
-
basename:
|
|
18577
|
+
dirname: path7.substring(0, lastIndex),
|
|
18578
|
+
basename: path7.substring(lastIndex + 1)
|
|
18579
18579
|
};
|
|
18580
18580
|
}
|
|
18581
18581
|
}
|
|
18582
18582
|
function joinPath() {
|
|
18583
|
-
var nonEmptyPaths = Array.prototype.filter.call(arguments, function(
|
|
18584
|
-
return
|
|
18583
|
+
var nonEmptyPaths = Array.prototype.filter.call(arguments, function(path7) {
|
|
18584
|
+
return path7;
|
|
18585
18585
|
});
|
|
18586
18586
|
var relevantPaths = [];
|
|
18587
|
-
nonEmptyPaths.forEach(function(
|
|
18588
|
-
if (/^\//.test(
|
|
18589
|
-
relevantPaths = [
|
|
18587
|
+
nonEmptyPaths.forEach(function(path7) {
|
|
18588
|
+
if (/^\//.test(path7)) {
|
|
18589
|
+
relevantPaths = [path7];
|
|
18590
18590
|
} else {
|
|
18591
|
-
relevantPaths.push(
|
|
18591
|
+
relevantPaths.push(path7);
|
|
18592
18592
|
}
|
|
18593
18593
|
});
|
|
18594
18594
|
return relevantPaths.join("/");
|
|
@@ -26013,9 +26013,9 @@ var require_office_xml_reader = __commonJS({
|
|
|
26013
26013
|
return collapseAlternateContent(document2)[0];
|
|
26014
26014
|
});
|
|
26015
26015
|
}
|
|
26016
|
-
function readXmlFromZipFile(docxFile,
|
|
26017
|
-
if (docxFile.exists(
|
|
26018
|
-
return docxFile.read(
|
|
26016
|
+
function readXmlFromZipFile(docxFile, path7) {
|
|
26017
|
+
if (docxFile.exists(path7)) {
|
|
26018
|
+
return docxFile.read(path7, "utf-8").then(stripUtf8Bom).then(read);
|
|
26019
26019
|
} else {
|
|
26020
26020
|
return promises.resolve(null);
|
|
26021
26021
|
}
|
|
@@ -27782,10 +27782,10 @@ var require_body_reader = __commonJS({
|
|
|
27782
27782
|
}
|
|
27783
27783
|
}
|
|
27784
27784
|
function findEmbeddedImageFile(relationshipId) {
|
|
27785
|
-
var
|
|
27785
|
+
var path7 = uris.uriToZipEntryName("word", relationships.findTargetByRelationshipId(relationshipId));
|
|
27786
27786
|
return {
|
|
27787
|
-
path:
|
|
27788
|
-
read: docxFile.read.bind(docxFile,
|
|
27787
|
+
path: path7,
|
|
27788
|
+
read: docxFile.read.bind(docxFile, path7)
|
|
27789
27789
|
};
|
|
27790
27790
|
}
|
|
27791
27791
|
function readImage(imageFile, altText) {
|
|
@@ -28025,12 +28025,12 @@ var require_content_types_reader = __commonJS({
|
|
|
28025
28025
|
}
|
|
28026
28026
|
function contentTypes(overrides, extensionDefaults) {
|
|
28027
28027
|
return {
|
|
28028
|
-
findContentType: function(
|
|
28029
|
-
var overrideContentType = overrides[
|
|
28028
|
+
findContentType: function(path7) {
|
|
28029
|
+
var overrideContentType = overrides[path7];
|
|
28030
28030
|
if (overrideContentType) {
|
|
28031
28031
|
return overrideContentType;
|
|
28032
28032
|
} else {
|
|
28033
|
-
var pathParts =
|
|
28033
|
+
var pathParts = path7.split(".");
|
|
28034
28034
|
var extension = pathParts[pathParts.length - 1];
|
|
28035
28035
|
if (extensionDefaults.hasOwnProperty(extension)) {
|
|
28036
28036
|
return extensionDefaults[extension];
|
|
@@ -28277,12 +28277,12 @@ var require_comments_reader = __commonJS({
|
|
|
28277
28277
|
var require_path_is_absolute = __commonJS({
|
|
28278
28278
|
"node_modules/path-is-absolute/index.js"(exports2, module2) {
|
|
28279
28279
|
"use strict";
|
|
28280
|
-
function posix(
|
|
28281
|
-
return
|
|
28280
|
+
function posix(path7) {
|
|
28281
|
+
return path7.charAt(0) === "/";
|
|
28282
28282
|
}
|
|
28283
|
-
function win32(
|
|
28283
|
+
function win32(path7) {
|
|
28284
28284
|
var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
|
|
28285
|
-
var result2 = splitDeviceRe.exec(
|
|
28285
|
+
var result2 = splitDeviceRe.exec(path7);
|
|
28286
28286
|
var device = result2[1] || "";
|
|
28287
28287
|
var isUnc = Boolean(device && device.charAt(1) !== ":");
|
|
28288
28288
|
return Boolean(result2[2] || isUnc);
|
|
@@ -28297,7 +28297,7 @@ var require_path_is_absolute = __commonJS({
|
|
|
28297
28297
|
var require_files = __commonJS({
|
|
28298
28298
|
"node_modules/mammoth/lib/docx/files.js"(exports2) {
|
|
28299
28299
|
"use strict";
|
|
28300
|
-
var
|
|
28300
|
+
var fs6 = __require("fs");
|
|
28301
28301
|
var url = __require("url");
|
|
28302
28302
|
var os3 = __require("os");
|
|
28303
28303
|
var dirname = __require("path").dirname;
|
|
@@ -28317,19 +28317,19 @@ var require_files = __commonJS({
|
|
|
28317
28317
|
}
|
|
28318
28318
|
var base = options.relativeToFile ? dirname(options.relativeToFile) : null;
|
|
28319
28319
|
function read(uri, encoding) {
|
|
28320
|
-
return resolveUri(uri).then(function(
|
|
28321
|
-
return readFile(
|
|
28320
|
+
return resolveUri(uri).then(function(path7) {
|
|
28321
|
+
return readFile(path7, encoding).caught(function(error) {
|
|
28322
28322
|
var message = "could not open external image: '" + uri + "' (document directory: '" + base + "')\n" + error.message;
|
|
28323
28323
|
return promises.reject(new Error(message));
|
|
28324
28324
|
});
|
|
28325
28325
|
});
|
|
28326
28326
|
}
|
|
28327
28327
|
function resolveUri(uri) {
|
|
28328
|
-
var
|
|
28329
|
-
if (isAbsolutePath(
|
|
28330
|
-
return promises.resolve(
|
|
28328
|
+
var path7 = uriToPath(uri);
|
|
28329
|
+
if (isAbsolutePath(path7)) {
|
|
28330
|
+
return promises.resolve(path7);
|
|
28331
28331
|
} else if (base) {
|
|
28332
|
-
return promises.resolve(resolvePath(base,
|
|
28332
|
+
return promises.resolve(resolvePath(base, path7));
|
|
28333
28333
|
} else {
|
|
28334
28334
|
return promises.reject(new Error("could not find external image '" + uri + "', path of input document is unknown"));
|
|
28335
28335
|
}
|
|
@@ -28338,18 +28338,18 @@ var require_files = __commonJS({
|
|
|
28338
28338
|
read
|
|
28339
28339
|
};
|
|
28340
28340
|
}
|
|
28341
|
-
var readFile = promises.promisify(
|
|
28341
|
+
var readFile = promises.promisify(fs6.readFile.bind(fs6));
|
|
28342
28342
|
function uriToPath(uriString, platform) {
|
|
28343
28343
|
if (!platform) {
|
|
28344
28344
|
platform = os3.platform();
|
|
28345
28345
|
}
|
|
28346
28346
|
var uri = url.parse(uriString);
|
|
28347
28347
|
if (isLocalFileUri(uri) || isRelativeUri(uri)) {
|
|
28348
|
-
var
|
|
28349
|
-
if (platform === "win32" && /^\/[a-z]:/i.test(
|
|
28350
|
-
return
|
|
28348
|
+
var path7 = decodeURIComponent(uri.path);
|
|
28349
|
+
if (platform === "win32" && /^\/[a-z]:/i.test(path7)) {
|
|
28350
|
+
return path7.slice(1);
|
|
28351
28351
|
} else {
|
|
28352
|
-
return
|
|
28352
|
+
return path7;
|
|
28353
28353
|
}
|
|
28354
28354
|
} else {
|
|
28355
28355
|
throw new Error("Could not convert URI to path: " + uriString);
|
|
@@ -28550,18 +28550,18 @@ var require_docx_reader = __commonJS({
|
|
|
28550
28550
|
readElement: contentTypesReader.readContentTypesFromXml,
|
|
28551
28551
|
defaultValue: contentTypesReader.defaultContentTypes
|
|
28552
28552
|
});
|
|
28553
|
-
function readNumberingFromZipFile(zipFile,
|
|
28553
|
+
function readNumberingFromZipFile(zipFile, path7, styles) {
|
|
28554
28554
|
return xmlFileReader({
|
|
28555
|
-
filename:
|
|
28555
|
+
filename: path7,
|
|
28556
28556
|
readElement: function(element) {
|
|
28557
28557
|
return numberingXml.readNumberingXml(element, { styles });
|
|
28558
28558
|
},
|
|
28559
28559
|
defaultValue: numberingXml.defaultNumbering
|
|
28560
28560
|
})(zipFile);
|
|
28561
28561
|
}
|
|
28562
|
-
function readStylesFromZipFile(zipFile,
|
|
28562
|
+
function readStylesFromZipFile(zipFile, path7) {
|
|
28563
28563
|
return xmlFileReader({
|
|
28564
|
-
filename:
|
|
28564
|
+
filename: path7,
|
|
28565
28565
|
readElement: stylesReader.readStylesXml,
|
|
28566
28566
|
defaultValue: stylesReader.defaultStyles
|
|
28567
28567
|
})(zipFile);
|
|
@@ -28593,10 +28593,10 @@ var require_style_map = __commonJS({
|
|
|
28593
28593
|
});
|
|
28594
28594
|
}
|
|
28595
28595
|
function updateRelationships(docxFile) {
|
|
28596
|
-
var
|
|
28596
|
+
var path7 = "word/_rels/document.xml.rels";
|
|
28597
28597
|
var relationshipsUri = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
28598
28598
|
var relationshipElementName = "{" + relationshipsUri + "}Relationship";
|
|
28599
|
-
return docxFile.read(
|
|
28599
|
+
return docxFile.read(path7, "utf8").then(xml.readString).then(function(relationshipsContainer) {
|
|
28600
28600
|
var relationships = relationshipsContainer.children;
|
|
28601
28601
|
addOrUpdateElement(relationships, relationshipElementName, "Id", {
|
|
28602
28602
|
"Id": "rMammothStyleMap",
|
|
@@ -28604,21 +28604,21 @@ var require_style_map = __commonJS({
|
|
|
28604
28604
|
"Target": styleMapAbsolutePath
|
|
28605
28605
|
});
|
|
28606
28606
|
var namespaces = { "": relationshipsUri };
|
|
28607
|
-
return docxFile.write(
|
|
28607
|
+
return docxFile.write(path7, xml.writeString(relationshipsContainer, namespaces));
|
|
28608
28608
|
});
|
|
28609
28609
|
}
|
|
28610
28610
|
function updateContentTypes(docxFile) {
|
|
28611
|
-
var
|
|
28611
|
+
var path7 = "[Content_Types].xml";
|
|
28612
28612
|
var contentTypesUri = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
28613
28613
|
var overrideName = "{" + contentTypesUri + "}Override";
|
|
28614
|
-
return docxFile.read(
|
|
28614
|
+
return docxFile.read(path7, "utf8").then(xml.readString).then(function(typesElement) {
|
|
28615
28615
|
var children = typesElement.children;
|
|
28616
28616
|
addOrUpdateElement(children, overrideName, "PartName", {
|
|
28617
28617
|
"PartName": styleMapAbsolutePath,
|
|
28618
28618
|
"ContentType": "text/prs.mammoth.style-map"
|
|
28619
28619
|
});
|
|
28620
28620
|
var namespaces = { "": contentTypesUri };
|
|
28621
|
-
return docxFile.write(
|
|
28621
|
+
return docxFile.write(path7, xml.writeString(typesElement, namespaces));
|
|
28622
28622
|
});
|
|
28623
28623
|
}
|
|
28624
28624
|
function addOrUpdateElement(elements, name, identifyingAttribute, attributes) {
|
|
@@ -29315,9 +29315,9 @@ var require_document_to_html = __commonJS({
|
|
|
29315
29315
|
};
|
|
29316
29316
|
var paths = [];
|
|
29317
29317
|
if (run.highlight !== null) {
|
|
29318
|
-
var
|
|
29319
|
-
if (
|
|
29320
|
-
paths.push(
|
|
29318
|
+
var path7 = findHtmlPath({ type: "highlight", color: run.highlight });
|
|
29319
|
+
if (path7) {
|
|
29320
|
+
paths.push(path7);
|
|
29321
29321
|
}
|
|
29322
29322
|
}
|
|
29323
29323
|
if (run.isSmallCaps) {
|
|
@@ -29352,15 +29352,15 @@ var require_document_to_html = __commonJS({
|
|
|
29352
29352
|
messages.push(unrecognisedStyleWarning("run", run));
|
|
29353
29353
|
}
|
|
29354
29354
|
paths.push(stylePath);
|
|
29355
|
-
paths.forEach(function(
|
|
29356
|
-
nodes =
|
|
29355
|
+
paths.forEach(function(path8) {
|
|
29356
|
+
nodes = path8.wrap.bind(path8, nodes);
|
|
29357
29357
|
});
|
|
29358
29358
|
return nodes();
|
|
29359
29359
|
}
|
|
29360
29360
|
function findHtmlPathForRunProperty(elementType, defaultTagName) {
|
|
29361
|
-
var
|
|
29362
|
-
if (
|
|
29363
|
-
return
|
|
29361
|
+
var path7 = findHtmlPath({ type: elementType });
|
|
29362
|
+
if (path7) {
|
|
29363
|
+
return path7;
|
|
29364
29364
|
} else if (defaultTagName) {
|
|
29365
29365
|
return htmlPaths.element(defaultTagName, {}, { fresh: false });
|
|
29366
29366
|
} else {
|
|
@@ -31080,11 +31080,11 @@ var require_options_reader = __commonJS({
|
|
|
31080
31080
|
var require_unzip = __commonJS({
|
|
31081
31081
|
"node_modules/mammoth/lib/unzip.js"(exports2) {
|
|
31082
31082
|
"use strict";
|
|
31083
|
-
var
|
|
31083
|
+
var fs6 = __require("fs");
|
|
31084
31084
|
var promises = require_promises();
|
|
31085
31085
|
var zipfile = require_zipfile();
|
|
31086
31086
|
exports2.openZip = openZip;
|
|
31087
|
-
var readFile = promises.promisify(
|
|
31087
|
+
var readFile = promises.promisify(fs6.readFile);
|
|
31088
31088
|
function openZip(options) {
|
|
31089
31089
|
if (options.path) {
|
|
31090
31090
|
return readFile(options.path).then(zipfile.openArrayBuffer);
|
|
@@ -31401,8 +31401,8 @@ var require_cjs = __commonJS({
|
|
|
31401
31401
|
return module3 = {
|
|
31402
31402
|
path: basedir,
|
|
31403
31403
|
exports: {},
|
|
31404
|
-
require: function(
|
|
31405
|
-
return commonjsRequire(
|
|
31404
|
+
require: function(path7, base) {
|
|
31405
|
+
return commonjsRequire(path7, base === void 0 || base === null ? module3.path : base);
|
|
31406
31406
|
}
|
|
31407
31407
|
}, fn(module3, module3.exports), module3.exports;
|
|
31408
31408
|
}
|
|
@@ -31809,9 +31809,9 @@ var require_cjs = __commonJS({
|
|
|
31809
31809
|
}
|
|
31810
31810
|
return o;
|
|
31811
31811
|
}
|
|
31812
|
-
var
|
|
31812
|
+
var fs6;
|
|
31813
31813
|
function get_fs() {
|
|
31814
|
-
return
|
|
31814
|
+
return fs6 || (fs6 = require$$0__default["default"]);
|
|
31815
31815
|
}
|
|
31816
31816
|
function parse2(file, options) {
|
|
31817
31817
|
if (file[0] == 80 && file[1] == 75) return parse_zip(file, options);
|
|
@@ -32096,7 +32096,7 @@ var require_cjs = __commonJS({
|
|
|
32096
32096
|
}
|
|
32097
32097
|
function read_file(filename2, options) {
|
|
32098
32098
|
get_fs();
|
|
32099
|
-
return parse2(
|
|
32099
|
+
return parse2(fs6.readFileSync(filename2), options);
|
|
32100
32100
|
}
|
|
32101
32101
|
function read(blob, options) {
|
|
32102
32102
|
switch (options && options.type || "base64") {
|
|
@@ -32362,7 +32362,7 @@ var require_cjs = __commonJS({
|
|
|
32362
32362
|
while (o.l < o.length) o.write_shift(1, 0);
|
|
32363
32363
|
return o;
|
|
32364
32364
|
}
|
|
32365
|
-
function find2(cfb2,
|
|
32365
|
+
function find2(cfb2, path7) {
|
|
32366
32366
|
var UCFullPaths = cfb2.FullPaths.map(function(x) {
|
|
32367
32367
|
return x.toUpperCase();
|
|
32368
32368
|
});
|
|
@@ -32371,11 +32371,11 @@ var require_cjs = __commonJS({
|
|
|
32371
32371
|
return y[y.length - (x.slice(-1) == "/" ? 2 : 1)];
|
|
32372
32372
|
});
|
|
32373
32373
|
var k = false;
|
|
32374
|
-
if (
|
|
32374
|
+
if (path7.charCodeAt(0) === 47) {
|
|
32375
32375
|
k = true;
|
|
32376
|
-
|
|
32377
|
-
} else k =
|
|
32378
|
-
var UCPath =
|
|
32376
|
+
path7 = UCFullPaths[0].slice(0, -1) + path7;
|
|
32377
|
+
} else k = path7.indexOf("/") !== -1;
|
|
32378
|
+
var UCPath = path7.toUpperCase();
|
|
32379
32379
|
var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
|
|
32380
32380
|
if (w !== -1) return cfb2.FileIndex[w];
|
|
32381
32381
|
var m = !UCPath.match(chr1);
|
|
@@ -32411,7 +32411,7 @@ var require_cjs = __commonJS({
|
|
|
32411
32411
|
function write_file(cfb2, filename2, options) {
|
|
32412
32412
|
get_fs();
|
|
32413
32413
|
var o = _write(cfb2, options);
|
|
32414
|
-
|
|
32414
|
+
fs6.writeFileSync(filename2, o);
|
|
32415
32415
|
}
|
|
32416
32416
|
function a2s(o) {
|
|
32417
32417
|
var out = new Array(o.length);
|
|
@@ -32423,7 +32423,7 @@ var require_cjs = __commonJS({
|
|
|
32423
32423
|
switch (options && options.type || "buffer") {
|
|
32424
32424
|
case "file":
|
|
32425
32425
|
get_fs();
|
|
32426
|
-
|
|
32426
|
+
fs6.writeFileSync(options.filename, o);
|
|
32427
32427
|
return o;
|
|
32428
32428
|
case "binary":
|
|
32429
32429
|
return typeof o == "string" ? o : a2s(o);
|
|
@@ -37848,8 +37848,8 @@ var require_cjs = __commonJS({
|
|
|
37848
37848
|
reader.readUInt16();
|
|
37849
37849
|
var id3 = reader.readUInt16();
|
|
37850
37850
|
var extension = reader.readString();
|
|
37851
|
-
var
|
|
37852
|
-
var payload = cfb.find(this.container,
|
|
37851
|
+
var path7 = "Root Entry/BinData/BIN".concat("".concat(id3.toString(16).toUpperCase()).padStart(4, "0"), ".").concat(extension);
|
|
37852
|
+
var payload = cfb.find(this.container, path7).content;
|
|
37853
37853
|
this.result.binData.push(new BinData(extension, pako_1.inflate(payload, {
|
|
37854
37854
|
windowBits: -15
|
|
37855
37855
|
})));
|
|
@@ -39358,7 +39358,7 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
39358
39358
|
|
|
39359
39359
|
// apps/web/src/server.ts
|
|
39360
39360
|
import http from "node:http";
|
|
39361
|
-
import
|
|
39361
|
+
import path6 from "node:path";
|
|
39362
39362
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
39363
39363
|
|
|
39364
39364
|
// packages/db/src/paths.ts
|
|
@@ -39405,6 +39405,8 @@ function clearRuntimeInfo() {
|
|
|
39405
39405
|
}
|
|
39406
39406
|
|
|
39407
39407
|
// packages/db/src/connection.ts
|
|
39408
|
+
import fs3 from "node:fs";
|
|
39409
|
+
import path3 from "node:path";
|
|
39408
39410
|
import { DatabaseSync } from "node:sqlite";
|
|
39409
39411
|
|
|
39410
39412
|
// packages/db/src/schema.ts
|
|
@@ -39723,33 +39725,155 @@ var MIGRATIONS = [
|
|
|
39723
39725
|
// idempotent. Feeds next-round prep and consistency (lessons carry into later interviews).
|
|
39724
39726
|
`
|
|
39725
39727
|
ALTER TABLE interview_preps ADD COLUMN debrief TEXT NOT NULL DEFAULT '{}';
|
|
39728
|
+
`,
|
|
39729
|
+
// v7 — offer comparison (한국 총보상 필드) + company reputation research field on jobs.
|
|
39730
|
+
// offers: one per job (UNIQUE job_id, mirrors interview_preps). Cash pieces are numeric (만원) so
|
|
39731
|
+
// the server can deterministically sum an annual estimate; equity/other stay free-text (comp is
|
|
39732
|
+
// messy). ai_score/verdict are written by the connected AI at save time (no LLM here) and rendered
|
|
39733
|
+
// by the dashboard, so it never needs to call an LLM. jobs.reputation: AI-researched company
|
|
39734
|
+
// reputation summary (same pattern as company_overview) — feeds offer verdicts + offer-evaluation.
|
|
39735
|
+
`
|
|
39736
|
+
CREATE TABLE IF NOT EXISTS offers (
|
|
39737
|
+
id TEXT PRIMARY KEY,
|
|
39738
|
+
job_id TEXT NOT NULL UNIQUE REFERENCES jobs(id) ON DELETE CASCADE,
|
|
39739
|
+
base_salary INTEGER,
|
|
39740
|
+
bonus_amount INTEGER,
|
|
39741
|
+
welfare_amount INTEGER,
|
|
39742
|
+
signing_amount INTEGER,
|
|
39743
|
+
equity_note TEXT,
|
|
39744
|
+
comp_note TEXT,
|
|
39745
|
+
work_arrangement TEXT,
|
|
39746
|
+
contract_type TEXT,
|
|
39747
|
+
accept_deadline TEXT,
|
|
39748
|
+
ai_score INTEGER,
|
|
39749
|
+
verdict TEXT,
|
|
39750
|
+
notes TEXT,
|
|
39751
|
+
created_at TEXT NOT NULL,
|
|
39752
|
+
updated_at TEXT NOT NULL
|
|
39753
|
+
);
|
|
39754
|
+
CREATE INDEX IF NOT EXISTS idx_offers_job ON offers(job_id);
|
|
39755
|
+
ALTER TABLE jobs ADD COLUMN reputation TEXT;
|
|
39756
|
+
`,
|
|
39757
|
+
// v8 — offer lifecycle status. 지원 상태(전형 깔때기 = 회사의 프로세스)와 직교하는
|
|
39758
|
+
// "내 응답" 축: open(진행)/accepted(수락)/declined(거절). declined여도 행을 지우지
|
|
39759
|
+
// 않는다 — 조건(연봉·처우) 히스토리는 다음 협상의 자산이라, 대시보드가 접힌
|
|
39760
|
+
// '지난 오퍼'로 강등해 보여줄 뿐이다. Additive ALTER (runner가 멱등 처리).
|
|
39761
|
+
`
|
|
39762
|
+
ALTER TABLE offers ADD COLUMN offer_status TEXT NOT NULL DEFAULT 'open';
|
|
39763
|
+
`,
|
|
39764
|
+
// v9 — 한국 문항형 자소서: 회사가 지정한 문항·글자수를 공고에 구조화 보관. 한국 자소서는
|
|
39765
|
+
// 회사별 문항형(항목·글자수 제한)이 지배적이라, AI가 문항별로 답변을 쓰고 글자수를 점검할 때
|
|
39766
|
+
// 참조할 원본을 공고 옆에 둔다(별도 엔티티가 아니라 job 컨텍스트에 함께 실린다). JSON 배열을
|
|
39767
|
+
// TEXT에 저장(다른 JSON 필드와 동일). Additive ALTER (runner가 멱등 처리).
|
|
39768
|
+
`
|
|
39769
|
+
ALTER TABLE jobs ADD COLUMN questions TEXT NOT NULL DEFAULT '[]';
|
|
39770
|
+
`,
|
|
39771
|
+
// v10 — 탈락 회고: 어느 전형 단계에서 떨어졌는지 자가 기록. 탈락 사유를 고지하는 기업은 6%뿐이고
|
|
39772
|
+
// 지원자 83%가 알고 싶어하므로, 이 자가 기록이 "서류는 붙는데 면접에서 떨어진다" 같은 패턴을 로컬
|
|
39773
|
+
// 데이터로 드러내는 유일한 신호다. 탈락이 아니거나 미기록이면 NULL. Additive ALTER (runner가 멱등 처리).
|
|
39774
|
+
`
|
|
39775
|
+
ALTER TABLE applications ADD COLUMN rejected_stage TEXT;
|
|
39776
|
+
`,
|
|
39777
|
+
// v11 — 전형 일정: 서류마감→인적성·AI역검→1·2차 면접→발표로 이어지는 단계별 날짜를 공고에
|
|
39778
|
+
// 구조화 보관. 일정을 jobs에 두는 이유: 서류마감(deadline)이 이미 jobs에 있고, save_job_posting
|
|
39779
|
+
// 업서트를 그대로 재사용해 도구 신설 없이 갱신할 수 있다. 면접초대 메일·발표 공지를 사용자가
|
|
39780
|
+
// 붙여넣으면 AI가 날짜를 추출해 저장하고, 서버가 D-day·같은 날짜 충돌을 결정론으로 계산한다.
|
|
39781
|
+
// JSON 배열을 TEXT에 저장(다른 JSON 필드와 동일). Additive ALTER (runner가 멱등 처리).
|
|
39782
|
+
`
|
|
39783
|
+
ALTER TABLE jobs ADD COLUMN schedule TEXT NOT NULL DEFAULT '[]';
|
|
39726
39784
|
`
|
|
39727
39785
|
];
|
|
39728
39786
|
function migrate(db) {
|
|
39729
39787
|
db.exec(`CREATE TABLE IF NOT EXISTS _meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);`);
|
|
39730
39788
|
const row = db.prepare(`SELECT value FROM _meta WHERE key = 'schema_version'`).get();
|
|
39731
39789
|
const from = row ? Number(row.value) : 0;
|
|
39790
|
+
if (from >= MIGRATIONS.length) return { from, to: from };
|
|
39732
39791
|
for (let v = from; v < MIGRATIONS.length; v++) {
|
|
39733
|
-
db
|
|
39792
|
+
applyMigration(db, v);
|
|
39734
39793
|
}
|
|
39735
|
-
|
|
39736
|
-
|
|
39737
|
-
|
|
39738
|
-
|
|
39739
|
-
|
|
39740
|
-
|
|
39794
|
+
return { from, to: MIGRATIONS.length };
|
|
39795
|
+
}
|
|
39796
|
+
function stampVersion(db, version) {
|
|
39797
|
+
db.prepare(
|
|
39798
|
+
`INSERT INTO _meta (key, value) VALUES ('schema_version', ?)
|
|
39799
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`
|
|
39800
|
+
).run(String(version));
|
|
39801
|
+
}
|
|
39802
|
+
function columnExists(db, table, column) {
|
|
39803
|
+
const rows = db.prepare(`PRAGMA table_info("${table.replaceAll('"', '""')}")`).all();
|
|
39804
|
+
return rows.some((r) => r.name === column);
|
|
39805
|
+
}
|
|
39806
|
+
var SELF_TRANSACTIONAL_MIGRATIONS = /* @__PURE__ */ new Set([1]);
|
|
39807
|
+
var ALTER_ADD_COLUMN_RE = /^[ \t]*ALTER TABLE\s+(\w+)\s+ADD COLUMN\s+(\w+)[^;]*;[ \t]*$/gm;
|
|
39808
|
+
function skipExistingColumns(db, sql) {
|
|
39809
|
+
return sql.replace(
|
|
39810
|
+
ALTER_ADD_COLUMN_RE,
|
|
39811
|
+
(stmt, table, column) => columnExists(db, table, column) ? "" : stmt
|
|
39812
|
+
);
|
|
39813
|
+
}
|
|
39814
|
+
function applyMigration(db, v) {
|
|
39815
|
+
const sql = MIGRATIONS[v];
|
|
39816
|
+
if (SELF_TRANSACTIONAL_MIGRATIONS.has(v)) {
|
|
39817
|
+
db.exec(sql);
|
|
39818
|
+
stampVersion(db, v + 1);
|
|
39819
|
+
return;
|
|
39820
|
+
}
|
|
39821
|
+
db.exec("BEGIN");
|
|
39822
|
+
try {
|
|
39823
|
+
db.exec(skipExistingColumns(db, sql));
|
|
39824
|
+
stampVersion(db, v + 1);
|
|
39825
|
+
db.exec("COMMIT");
|
|
39826
|
+
} catch (err) {
|
|
39827
|
+
try {
|
|
39828
|
+
db.exec("ROLLBACK");
|
|
39829
|
+
} catch {
|
|
39830
|
+
}
|
|
39831
|
+
throw err;
|
|
39741
39832
|
}
|
|
39742
|
-
return { from, to };
|
|
39743
39833
|
}
|
|
39744
39834
|
|
|
39745
39835
|
// packages/db/src/connection.ts
|
|
39746
39836
|
var _db = null;
|
|
39837
|
+
var PRE_MIGRATE_KEEP = 5;
|
|
39838
|
+
function vacuumInto(db, destPath) {
|
|
39839
|
+
if (/[\0\n\r]/.test(destPath)) throw new Error("backup path not safe for SQL literal");
|
|
39840
|
+
db.exec(`VACUUM INTO '${destPath.replace(/'/g, "''")}'`);
|
|
39841
|
+
}
|
|
39842
|
+
function preMigrationBackup(db) {
|
|
39843
|
+
try {
|
|
39844
|
+
const hasMeta = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='_meta'`).get();
|
|
39845
|
+
if (!hasMeta) return;
|
|
39846
|
+
const row = db.prepare(`SELECT value FROM _meta WHERE key = 'schema_version'`).get();
|
|
39847
|
+
const from = row ? Number(row.value) : 0;
|
|
39848
|
+
if (from === 0 || from >= MIGRATIONS.length) return;
|
|
39849
|
+
const dir = getBackupsDir();
|
|
39850
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
39851
|
+
const dest = path3.join(dir, `pre-migrate-v${from}-${stamp}.sqlite`);
|
|
39852
|
+
try {
|
|
39853
|
+
vacuumInto(db, dest);
|
|
39854
|
+
} catch {
|
|
39855
|
+
fs3.copyFileSync(getDbPath(), dest);
|
|
39856
|
+
}
|
|
39857
|
+
const stale = fs3.readdirSync(dir).filter((f) => f.startsWith("pre-migrate-") && f.endsWith(".sqlite")).sort().reverse().slice(PRE_MIGRATE_KEEP);
|
|
39858
|
+
for (const f of stale) {
|
|
39859
|
+
try {
|
|
39860
|
+
fs3.unlinkSync(path3.join(dir, f));
|
|
39861
|
+
} catch {
|
|
39862
|
+
}
|
|
39863
|
+
}
|
|
39864
|
+
} catch (err) {
|
|
39865
|
+
console.error(
|
|
39866
|
+
`[careermate] \uC5C5\uADF8\uB808\uC774\uB4DC \uC804 \uC790\uB3D9 \uBC31\uC5C5 \uC2E4\uD328(\uB9C8\uC774\uADF8\uB808\uC774\uC158\uC740 \uACC4\uC18D \uC9C4\uD589): ${err instanceof Error ? err.message : String(err)}`
|
|
39867
|
+
);
|
|
39868
|
+
}
|
|
39869
|
+
}
|
|
39747
39870
|
function getDb() {
|
|
39748
39871
|
if (_db) return _db;
|
|
39749
39872
|
const db = new DatabaseSync(getDbPath());
|
|
39750
39873
|
db.exec("PRAGMA journal_mode = WAL;");
|
|
39751
39874
|
db.exec("PRAGMA foreign_keys = ON;");
|
|
39752
39875
|
db.exec("PRAGMA busy_timeout = 5000;");
|
|
39876
|
+
preMigrationBackup(db);
|
|
39753
39877
|
migrate(db);
|
|
39754
39878
|
_db = db;
|
|
39755
39879
|
return db;
|
|
@@ -40409,8 +40533,8 @@ function getErrorMap() {
|
|
|
40409
40533
|
|
|
40410
40534
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
40411
40535
|
var makeIssue = (params) => {
|
|
40412
|
-
const { data, path:
|
|
40413
|
-
const fullPath = [...
|
|
40536
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
40537
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
40414
40538
|
const fullIssue = {
|
|
40415
40539
|
...issueData,
|
|
40416
40540
|
path: fullPath
|
|
@@ -40526,11 +40650,11 @@ var errorUtil;
|
|
|
40526
40650
|
|
|
40527
40651
|
// node_modules/zod/v3/types.js
|
|
40528
40652
|
var ParseInputLazyPath = class {
|
|
40529
|
-
constructor(parent, value,
|
|
40653
|
+
constructor(parent, value, path7, key) {
|
|
40530
40654
|
this._cachedPath = [];
|
|
40531
40655
|
this.parent = parent;
|
|
40532
40656
|
this.data = value;
|
|
40533
|
-
this._path =
|
|
40657
|
+
this._path = path7;
|
|
40534
40658
|
this._key = key;
|
|
40535
40659
|
}
|
|
40536
40660
|
get path() {
|
|
@@ -44206,6 +44330,22 @@ var CoverLetterRecordSchema = external_exports.object({
|
|
|
44206
44330
|
current_content: external_exports.string().nullable(),
|
|
44207
44331
|
versions: external_exports.array(CoverLetterVersionRecordSchema).optional()
|
|
44208
44332
|
});
|
|
44333
|
+
var JobQuestionSchema = external_exports.object({
|
|
44334
|
+
no: external_exports.number().int().positive().optional().describe("\uBB38\uD56D \uBC88\uD638(\uC788\uC73C\uBA74)"),
|
|
44335
|
+
question: external_exports.string().max(MAX_BODY).describe("\uBB38\uD56D \uD14D\uC2A4\uD2B8(\uD68C\uC0AC\uAC00 \uC81C\uC2DC\uD55C \uC790\uC18C\uC11C \uD56D\uBAA9)"),
|
|
44336
|
+
min_chars: external_exports.number().int().positive().optional().describe("\uAE00\uC790\uC218 \uD558\uD55C(\uC788\uC73C\uBA74)"),
|
|
44337
|
+
max_chars: external_exports.number().int().positive().optional().describe("\uAE00\uC790\uC218 \uC0C1\uD55C(\uC788\uC73C\uBA74)"),
|
|
44338
|
+
count_mode: external_exports.enum(["with_space", "no_space", "byte"]).optional().describe("\uAE00\uC790\uC218 \uAE30\uC900: with_space=\uACF5\uBC31\uD3EC\uD568(\uAE30\uBCF8)\xB7no_space=\uACF5\uBC31\uC81C\uC678\xB7byte=UTF-8 \uBC14\uC774\uD2B8"),
|
|
44339
|
+
note: optLine.describe('\uBD80\uAC00 \uBA54\uBAA8(\uC608: "\uD544\uC218", "\uACBD\uD5D8 \uC911\uC2EC")')
|
|
44340
|
+
});
|
|
44341
|
+
var SCHEDULE_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
44342
|
+
var SCHEDULE_TIME_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
44343
|
+
var JobScheduleItemSchema = external_exports.object({
|
|
44344
|
+
label: reqLine.describe("\uC77C\uC815 \uC774\uB984 (\uC608: 1\uCC28 \uBA74\uC811\xB7AI\uC5ED\uAC80\xB7\uC11C\uB958 \uBC1C\uD45C)"),
|
|
44345
|
+
date: external_exports.string().regex(SCHEDULE_DATE_RE, "YYYY-MM-DD \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4").describe("\uC77C\uC815 \uB0A0\uC9DC YYYY-MM-DD"),
|
|
44346
|
+
time: external_exports.string().regex(SCHEDULE_TIME_RE, "HH:MM(24\uC2DC\uAC04) \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4").optional().describe("\uC2DC\uAC01 HH:MM(24\uC2DC\uAC04, \uC120\uD0DD)"),
|
|
44347
|
+
note: optLine.describe("\uBD80\uAC00 \uBA54\uBAA8(\uC608: \uC7A5\uC18C\xB7\uC900\uBE44\uBB3C, \uC120\uD0DD)")
|
|
44348
|
+
});
|
|
44209
44349
|
var JobInputSchema = external_exports.object({
|
|
44210
44350
|
company: reqLine,
|
|
44211
44351
|
position: reqLine.describe("\uC9C1\uBB34/\uD3EC\uC9C0\uC158\uBA85"),
|
|
@@ -44219,7 +44359,10 @@ var JobInputSchema = external_exports.object({
|
|
|
44219
44359
|
source: external_exports.string().max(MAX_LINE).optional().describe("\uCD9C\uCC98 (\uC0AC\uB78C\uC778/\uC6D0\uD2F0\uB4DC/\uC9C1\uC811 \uC785\uB825 \uB4F1)"),
|
|
44220
44360
|
company_overview: optBody.describe("\uD68C\uC0AC \uC0AC\uC5C5\uAC1C\uC694\xB7\uBBF8\uC158\xB7\uC8FC\uC694 \uC81C\uD488\xB7\uCD5C\uADFC \uD65C\uB3D9 (AI\uAC00 \uB9AC\uC11C\uCE58\uD574 \uCC44\uC6C0)"),
|
|
44221
44361
|
talent_profile: optBody.describe("\uD68C\uC0AC\uAC00 \uAC15\uC870\uD558\uB294 \uC778\uC7AC\uC0C1 (\uD55C\uAD6D \uC790\uC18C\uC11C\xB7\uBA74\uC811\uC5D0\uC11C \uC815\uB82C \uAE30\uC900)"),
|
|
44222
|
-
core_values: strList.optional().describe("\uD68C\uC0AC \uD575\uC2EC\uAC00\uCE58 (\uD0A4\uC6CC\uB4DC \uBC30\uC5F4)")
|
|
44362
|
+
core_values: strList.optional().describe("\uD68C\uC0AC \uD575\uC2EC\uAC00\uCE58 (\uD0A4\uC6CC\uB4DC \uBC30\uC5F4)"),
|
|
44363
|
+
reputation: optBody.describe("\uD68C\uC0AC \uD3C9\uD310 \uC694\uC57D \u2014 \uD3C9\uC810\xB7\uC6CC\uB77C\uBC38\xB7\uBB38\uD654 \uB9AC\uC2A4\uD06C \uB4F1 (AI\uAC00 company-research \uD50C\uB808\uC774\uBD81\uC73C\uB85C \uB9AC\uC11C\uCE58\uD574 \uCC44\uC6C0; \uCD9C\uCC98\xB7\uCD5C\uADFC\uC131 \uD45C\uAE30)"),
|
|
44364
|
+
questions: external_exports.array(JobQuestionSchema).max(MAX_ITEMS).optional().describe("\uD68C\uC0AC \uC9C0\uC815 \uC790\uC18C\uC11C \uBB38\uD56D\xB7\uAE00\uC790\uC218 \u2014 \uC0AC\uC6A9\uC790\uAC00 \uBB38\uD56D\uC744 \uC8FC\uBA74 \uAD6C\uC870\uD654 \uC800\uC7A5"),
|
|
44365
|
+
schedule: external_exports.array(JobScheduleItemSchema).max(MAX_ITEMS).optional().describe("\uC804\uD615 \uC77C\uC815 \u2014 \uBA74\uC811\uCD08\uB300 \uBA54\uC77C\xB7\uBC1C\uD45C \uACF5\uC9C0\uB97C \uBC1B\uC73C\uBA74 \uAD6C\uC870\uD654 \uC800\uC7A5(label\xB7date \uD544\uC218, time \uC120\uD0DD). \uC11C\uB958 \uB9C8\uAC10\uC740 deadline \uD544\uB4DC\uB97C \uC4F0\uC138\uC694.")
|
|
44223
44366
|
});
|
|
44224
44367
|
var JobRecordSchema = external_exports.object({
|
|
44225
44368
|
...baseRecord,
|
|
@@ -44235,7 +44378,46 @@ var JobRecordSchema = external_exports.object({
|
|
|
44235
44378
|
source: external_exports.string().nullable(),
|
|
44236
44379
|
company_overview: external_exports.string().nullable(),
|
|
44237
44380
|
talent_profile: external_exports.string().nullable(),
|
|
44238
|
-
core_values: external_exports.array(external_exports.string())
|
|
44381
|
+
core_values: external_exports.array(external_exports.string()),
|
|
44382
|
+
reputation: external_exports.string().nullable(),
|
|
44383
|
+
questions: external_exports.array(JobQuestionSchema),
|
|
44384
|
+
schedule: external_exports.array(JobScheduleItemSchema)
|
|
44385
|
+
});
|
|
44386
|
+
var OFFER_STATUSES = ["open", "accepted", "declined"];
|
|
44387
|
+
var OfferInputSchema = external_exports.object({
|
|
44388
|
+
job_id: reqLine,
|
|
44389
|
+
offer_status: external_exports.enum(OFFER_STATUSES).optional().describe("\uC624\uD37C \uC0C1\uD0DC \u2014 open(\uC9C4\uD589 \uC911)/accepted(\uC218\uB77D)/declined(\uAC70\uC808). \uC0DD\uB7B5 \uC2DC \uAE30\uC874 \uAC12 \uC720\uC9C0(\uC2E0\uADDC \uC800\uC7A5\uC740 open)"),
|
|
44390
|
+
base_salary: external_exports.number().nonnegative().optional().describe("\uAE30\uBCF8\uAE09/\uC5F0\uBD09 (\uB9CC\uC6D0)"),
|
|
44391
|
+
bonus_amount: external_exports.number().nonnegative().optional().describe("\uC5F0 \uC131\uACFC\uAE09\xB7\uC0C1\uC5EC \uAE30\uB300\uC561 (\uB9CC\uC6D0)"),
|
|
44392
|
+
welfare_amount: external_exports.number().nonnegative().optional().describe("\uBCF5\uC9C0\uD3EC\uC778\uD2B8 \uB4F1 \uC5F0\uD658\uC0B0 (\uB9CC\uC6D0)"),
|
|
44393
|
+
signing_amount: external_exports.number().nonnegative().optional().describe("\uC0AC\uC774\uB2DD\uBCF4\uB108\uC2A4 \uC77C\uC2DC\uAE08 (\uB9CC\uC6D0)"),
|
|
44394
|
+
equity_note: optNote.describe("\uC8FC\uC2DD/\uC2A4\uD1A1\uC635\uC158 (\uC815\uC131 \uC11C\uC220 \u2014 \uAC00\uCE58\uD3C9\uAC00\uAC00 \uBAA8\uD638\uD558\uBBC0\uB85C \uD14D\uC2A4\uD2B8)"),
|
|
44395
|
+
comp_note: optBody.describe("\uAE30\uD0C0 \uBCF4\uC0C1 \uC790\uC720 \uC11C\uC220"),
|
|
44396
|
+
work_arrangement: optLine.describe("\uADFC\uBB34\uD615\uD0DC (\uC7AC\uD0DD/\uD558\uC774\uBE0C\uB9AC\uB4DC/\uCD9C\uADFC)"),
|
|
44397
|
+
contract_type: optLine.describe("\uACC4\uC57D\uD615\uD0DC (\uC815\uADDC/\uACC4\uC57D \uB4F1)"),
|
|
44398
|
+
accept_deadline: optLine.describe("\uC218\uB77D \uB9C8\uAC10\uC77C YYYY-MM-DD"),
|
|
44399
|
+
ai_score: external_exports.number().min(0).max(100).optional().describe("AI\uAC00 \uB9E4\uAE34 \uC885\uD569 \uC810\uC218 0~100 (\uC800\uC7A5 \uC2DC AI\uAC00 \uCC44\uC6C0)"),
|
|
44400
|
+
verdict: optBody.describe("\uCD5C\uC885\uD3C9 \u2014 \uC5B4\uB5A4 \uC0C1\uD669\uC774\uBA74 \uC5B4\uB514\uAC00 \uC88B\uC740\uC9C0 \uB4F1 (AI\uAC00 \uC800\uC7A5 \uC2DC \uC791\uC131)"),
|
|
44401
|
+
notes: optNote
|
|
44402
|
+
});
|
|
44403
|
+
var OfferRecordSchema = external_exports.object({
|
|
44404
|
+
...baseRecord,
|
|
44405
|
+
job_id: external_exports.string(),
|
|
44406
|
+
offer_status: external_exports.enum(OFFER_STATUSES),
|
|
44407
|
+
base_salary: external_exports.number().nullable(),
|
|
44408
|
+
bonus_amount: external_exports.number().nullable(),
|
|
44409
|
+
welfare_amount: external_exports.number().nullable(),
|
|
44410
|
+
signing_amount: external_exports.number().nullable(),
|
|
44411
|
+
equity_note: external_exports.string().nullable(),
|
|
44412
|
+
comp_note: external_exports.string().nullable(),
|
|
44413
|
+
work_arrangement: external_exports.string().nullable(),
|
|
44414
|
+
contract_type: external_exports.string().nullable(),
|
|
44415
|
+
accept_deadline: external_exports.string().nullable(),
|
|
44416
|
+
ai_score: external_exports.number().nullable(),
|
|
44417
|
+
verdict: external_exports.string().nullable(),
|
|
44418
|
+
notes: external_exports.string().nullable(),
|
|
44419
|
+
/** Server-computed annual cash estimate = base + bonus + welfare (signing is one-time, excluded). Null if no numeric pieces. */
|
|
44420
|
+
total_comp_annual_est: external_exports.number().nullable()
|
|
44239
44421
|
});
|
|
44240
44422
|
var FitAnalysisInputSchema = external_exports.object({
|
|
44241
44423
|
job_id: reqLine.describe("\uBD84\uC11D \uB300\uC0C1 \uACF5\uACE0 ID"),
|
|
@@ -44258,6 +44440,7 @@ var FitAnalysisRecordSchema = external_exports.object({
|
|
|
44258
44440
|
missing_keywords: external_exports.array(external_exports.string()),
|
|
44259
44441
|
recommendations: external_exports.array(external_exports.string())
|
|
44260
44442
|
});
|
|
44443
|
+
var REJECTED_STAGES = ["document", "assessment", "interview", "final", "other"];
|
|
44261
44444
|
var ApplicationInputSchema = external_exports.object({
|
|
44262
44445
|
job_id: reqLine,
|
|
44263
44446
|
status: external_exports.enum(APPLICATION_STATUSES).optional(),
|
|
@@ -44278,7 +44461,10 @@ var ApplicationStatusUpdateSchema = external_exports.object({
|
|
|
44278
44461
|
application_id: optLine,
|
|
44279
44462
|
status: external_exports.enum(APPLICATION_STATUSES),
|
|
44280
44463
|
note: optNote.describe("\uC0C1\uD0DC \uBCC0\uACBD \uC0AC\uC720/\uBA54\uBAA8"),
|
|
44281
|
-
submission: ApplicationSubmissionSchema.optional().describe("\uC9C0\uC6D0 \uC644\uB8CC \uAE30\uB85D\uC5D0 \uB0A8\uAE38 \uC81C\uCD9C \uC790\uB8CC \uC2A4\uB0C5\uC0F7")
|
|
44464
|
+
submission: ApplicationSubmissionSchema.optional().describe("\uC9C0\uC6D0 \uC644\uB8CC \uAE30\uB85D\uC5D0 \uB0A8\uAE38 \uC81C\uCD9C \uC790\uB8CC \uC2A4\uB0C5\uC0F7"),
|
|
44465
|
+
rejected_stage: external_exports.enum(REJECTED_STAGES).optional().describe(
|
|
44466
|
+
"\uD0C8\uB77D \uD68C\uACE0 \u2014 'rejected'\uB85C \uBC14\uAFC0 \uB54C \uC5B4\uB290 \uB2E8\uACC4\uC5D0\uC11C \uB5A8\uC5B4\uC84C\uB294\uC9C0: \uC11C\uB958=document, \uC778\uC801\uC131\xB7AI\uC5ED\uAC80=assessment, \uBA74\uC811=interview, \uCD5C\uC885\xB7\uCC98\uC6B0=final, \uAE30\uD0C0=other. rejected\uAC00 \uC544\uB2CC \uC0C1\uD0DC\uC5D0\uB294 \uC800\uC7A5\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
|
44467
|
+
)
|
|
44282
44468
|
});
|
|
44283
44469
|
var ApplicationRecordSchema = external_exports.object({
|
|
44284
44470
|
...baseRecord,
|
|
@@ -44287,7 +44473,8 @@ var ApplicationRecordSchema = external_exports.object({
|
|
|
44287
44473
|
resume_id: external_exports.string().nullable(),
|
|
44288
44474
|
cover_letter_id: external_exports.string().nullable(),
|
|
44289
44475
|
applied_at: external_exports.string().nullable(),
|
|
44290
|
-
notes: external_exports.string().nullable()
|
|
44476
|
+
notes: external_exports.string().nullable(),
|
|
44477
|
+
rejected_stage: external_exports.enum(REJECTED_STAGES).nullable()
|
|
44291
44478
|
});
|
|
44292
44479
|
var StarGuideSchema = external_exports.object({
|
|
44293
44480
|
question: external_exports.string().max(MAX_NOTE),
|
|
@@ -44391,7 +44578,7 @@ var ApplicationContextSchema = external_exports.object({
|
|
|
44391
44578
|
});
|
|
44392
44579
|
|
|
44393
44580
|
// packages/shared/src/build-info.ts
|
|
44394
|
-
var APP_VERSION = true ? "0.0.
|
|
44581
|
+
var APP_VERSION = true ? "0.0.9" : "0.0.0-dev";
|
|
44395
44582
|
var BUNDLED = true;
|
|
44396
44583
|
|
|
44397
44584
|
// packages/shared/src/index.ts
|
|
@@ -44939,6 +45126,9 @@ function mapJob(r) {
|
|
|
44939
45126
|
company_overview: r.company_overview ?? null,
|
|
44940
45127
|
talent_profile: r.talent_profile ?? null,
|
|
44941
45128
|
core_values: fromJson(r.core_values, []),
|
|
45129
|
+
reputation: r.reputation ?? null,
|
|
45130
|
+
questions: fromJson(r.questions, []),
|
|
45131
|
+
schedule: fromJson(r.schedule, []),
|
|
44942
45132
|
created_at: r.created_at,
|
|
44943
45133
|
updated_at: r.updated_at
|
|
44944
45134
|
};
|
|
@@ -44968,7 +45158,7 @@ var jobRepo = {
|
|
|
44968
45158
|
if (existing) {
|
|
44969
45159
|
const m = { ...existing, ...input };
|
|
44970
45160
|
db.prepare(
|
|
44971
|
-
`UPDATE jobs SET company=?,position=?,url=?,location=?,employment_type=?,description=?,requirements=?,keywords=?,deadline=?,source=?,company_overview=?,talent_profile=?,core_values=?,updated_at=? WHERE id=?`
|
|
45161
|
+
`UPDATE jobs SET company=?,position=?,url=?,location=?,employment_type=?,description=?,requirements=?,keywords=?,deadline=?,source=?,company_overview=?,talent_profile=?,core_values=?,reputation=?,questions=?,schedule=?,updated_at=? WHERE id=?`
|
|
44972
45162
|
).run(
|
|
44973
45163
|
m.company,
|
|
44974
45164
|
m.position,
|
|
@@ -44983,6 +45173,12 @@ var jobRepo = {
|
|
|
44983
45173
|
m.company_overview ?? null,
|
|
44984
45174
|
m.talent_profile ?? null,
|
|
44985
45175
|
toJson(m.core_values ?? []),
|
|
45176
|
+
m.reputation ?? null,
|
|
45177
|
+
// questions omitted from input → m keeps existing.questions (preserved);
|
|
45178
|
+
// provided → replaced. Same merge semantics as the other JSON fields.
|
|
45179
|
+
toJson(m.questions ?? []),
|
|
45180
|
+
// schedule follows the same preserve-on-omit merge (v11 전형 일정).
|
|
45181
|
+
toJson(m.schedule ?? []),
|
|
44986
45182
|
ts,
|
|
44987
45183
|
existing.id
|
|
44988
45184
|
);
|
|
@@ -44990,8 +45186,8 @@ var jobRepo = {
|
|
|
44990
45186
|
}
|
|
44991
45187
|
const newJobId = id3 ?? newId("job_");
|
|
44992
45188
|
db.prepare(
|
|
44993
|
-
`INSERT INTO jobs (id,company,position,url,location,employment_type,description,requirements,keywords,deadline,source,company_overview,talent_profile,core_values,created_at,updated_at)
|
|
44994
|
-
VALUES (
|
|
45189
|
+
`INSERT INTO jobs (id,company,position,url,location,employment_type,description,requirements,keywords,deadline,source,company_overview,talent_profile,core_values,reputation,questions,schedule,created_at,updated_at)
|
|
45190
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`
|
|
44995
45191
|
).run(
|
|
44996
45192
|
newJobId,
|
|
44997
45193
|
input.company,
|
|
@@ -45007,6 +45203,9 @@ var jobRepo = {
|
|
|
45007
45203
|
input.company_overview ?? null,
|
|
45008
45204
|
input.talent_profile ?? null,
|
|
45009
45205
|
toJson(input.core_values ?? []),
|
|
45206
|
+
input.reputation ?? null,
|
|
45207
|
+
toJson(input.questions ?? []),
|
|
45208
|
+
toJson(input.schedule ?? []),
|
|
45010
45209
|
ts,
|
|
45011
45210
|
ts
|
|
45012
45211
|
);
|
|
@@ -45020,6 +45219,7 @@ var jobRepo = {
|
|
|
45020
45219
|
db.prepare(`DELETE FROM applications WHERE job_id=?`).run(id3);
|
|
45021
45220
|
db.prepare(`DELETE FROM interview_preps WHERE job_id=?`).run(id3);
|
|
45022
45221
|
db.prepare(`DELETE FROM application_timeline_events WHERE job_id=?`).run(id3);
|
|
45222
|
+
db.prepare(`DELETE FROM offers WHERE job_id=?`).run(id3);
|
|
45023
45223
|
return db.prepare(`DELETE FROM jobs WHERE id=?`).run(id3).changes > 0;
|
|
45024
45224
|
});
|
|
45025
45225
|
}
|
|
@@ -45094,6 +45294,8 @@ function mapApplication(r) {
|
|
|
45094
45294
|
cover_letter_id: r.cover_letter_id,
|
|
45095
45295
|
applied_at: r.applied_at,
|
|
45096
45296
|
notes: r.notes,
|
|
45297
|
+
// 탈락 회고: 탈락이 아니거나 미기록이면 NULL(v10 이전 DB는 컬럼이 없어 undefined → null 정규화).
|
|
45298
|
+
rejected_stage: r.rejected_stage ?? null,
|
|
45097
45299
|
created_at: r.created_at,
|
|
45098
45300
|
updated_at: r.updated_at
|
|
45099
45301
|
};
|
|
@@ -45130,17 +45332,19 @@ var applicationRepo = {
|
|
|
45130
45332
|
const app = this.ensure(input.job_id, input.status ?? "draft");
|
|
45131
45333
|
if (input.status && input.status !== app.status) assertStatusTransition(app.status, input.status);
|
|
45132
45334
|
const m = { ...app, ...input };
|
|
45335
|
+
const rejectedStageValue = m.status === "rejected" ? m.rejected_stage ?? null : null;
|
|
45133
45336
|
getDb().prepare(
|
|
45134
|
-
`UPDATE applications SET status=?,resume_id=?,cover_letter_id=?,applied_at=?,notes=?,updated_at=? WHERE id=?`
|
|
45135
|
-
).run(m.status, m.resume_id ?? null, m.cover_letter_id ?? null, m.applied_at ?? null, m.notes ?? null, now(), app.id);
|
|
45337
|
+
`UPDATE applications SET status=?,resume_id=?,cover_letter_id=?,applied_at=?,notes=?,rejected_stage=?,updated_at=? WHERE id=?`
|
|
45338
|
+
).run(m.status, m.resume_id ?? null, m.cover_letter_id ?? null, m.applied_at ?? null, m.notes ?? null, rejectedStageValue, now(), app.id);
|
|
45136
45339
|
return this.get(app.id);
|
|
45137
45340
|
},
|
|
45138
|
-
setStatus(jobId, status, note) {
|
|
45341
|
+
setStatus(jobId, status, note, rejectedStage) {
|
|
45139
45342
|
const app = this.ensure(jobId);
|
|
45140
45343
|
assertStatusTransition(app.status, status);
|
|
45141
45344
|
const appliedAt = status === "applied" && !app.applied_at ? now() : app.applied_at;
|
|
45142
45345
|
const notes = note ? [app.notes, note].filter(Boolean).join("\n") : app.notes;
|
|
45143
|
-
|
|
45346
|
+
const rejectedStageValue = status === "rejected" ? rejectedStage ?? app.rejected_stage ?? null : null;
|
|
45347
|
+
getDb().prepare(`UPDATE applications SET status=?, applied_at=?, notes=?, rejected_stage=?, updated_at=? WHERE id=?`).run(status, appliedAt, notes, rejectedStageValue, now(), app.id);
|
|
45144
45348
|
return this.get(app.id);
|
|
45145
45349
|
}
|
|
45146
45350
|
};
|
|
@@ -45260,6 +45464,96 @@ var timelineRepo = {
|
|
|
45260
45464
|
return getDb().prepare(`DELETE FROM application_timeline_events WHERE id=?`).run(id3).changes > 0;
|
|
45261
45465
|
}
|
|
45262
45466
|
};
|
|
45467
|
+
function mapOffer(r) {
|
|
45468
|
+
const base = r.base_salary ?? null;
|
|
45469
|
+
const bonus = r.bonus_amount ?? null;
|
|
45470
|
+
const welfare = r.welfare_amount ?? null;
|
|
45471
|
+
const hasAny = base != null || bonus != null || welfare != null;
|
|
45472
|
+
const total = hasAny ? (base ?? 0) + (bonus ?? 0) + (welfare ?? 0) : null;
|
|
45473
|
+
return {
|
|
45474
|
+
id: r.id,
|
|
45475
|
+
job_id: r.job_id,
|
|
45476
|
+
offer_status: r.offer_status ?? "open",
|
|
45477
|
+
base_salary: base,
|
|
45478
|
+
bonus_amount: bonus,
|
|
45479
|
+
welfare_amount: welfare,
|
|
45480
|
+
signing_amount: r.signing_amount ?? null,
|
|
45481
|
+
equity_note: r.equity_note ?? null,
|
|
45482
|
+
comp_note: r.comp_note ?? null,
|
|
45483
|
+
work_arrangement: r.work_arrangement ?? null,
|
|
45484
|
+
contract_type: r.contract_type ?? null,
|
|
45485
|
+
accept_deadline: r.accept_deadline ?? null,
|
|
45486
|
+
ai_score: r.ai_score ?? null,
|
|
45487
|
+
verdict: r.verdict ?? null,
|
|
45488
|
+
notes: r.notes ?? null,
|
|
45489
|
+
total_comp_annual_est: total,
|
|
45490
|
+
created_at: r.created_at,
|
|
45491
|
+
updated_at: r.updated_at
|
|
45492
|
+
};
|
|
45493
|
+
}
|
|
45494
|
+
var offerRepo = {
|
|
45495
|
+
getByJob(jobId) {
|
|
45496
|
+
const r = getDb().prepare(`SELECT * FROM offers WHERE job_id=?`).get(jobId);
|
|
45497
|
+
return r ? mapOffer(r) : null;
|
|
45498
|
+
},
|
|
45499
|
+
list() {
|
|
45500
|
+
return getDb().prepare(`SELECT * FROM offers ORDER BY ai_score IS NULL, ai_score DESC, updated_at DESC`).all().map(mapOffer);
|
|
45501
|
+
},
|
|
45502
|
+
/** Upsert by job_id (one offer per job). Missing fields are preserved on update (partial-safe). */
|
|
45503
|
+
save(input) {
|
|
45504
|
+
const db = getDb();
|
|
45505
|
+
const existing = this.getByJob(input.job_id);
|
|
45506
|
+
const ts = now();
|
|
45507
|
+
const n = (v, prev) => v ?? prev ?? null;
|
|
45508
|
+
const s = (v, prev) => v ?? prev ?? null;
|
|
45509
|
+
if (existing) {
|
|
45510
|
+
db.prepare(
|
|
45511
|
+
`UPDATE offers SET offer_status=?,base_salary=?,bonus_amount=?,welfare_amount=?,signing_amount=?,equity_note=?,comp_note=?,work_arrangement=?,contract_type=?,accept_deadline=?,ai_score=?,verdict=?,notes=?,updated_at=? WHERE id=?`
|
|
45512
|
+
).run(
|
|
45513
|
+
input.offer_status ?? existing.offer_status,
|
|
45514
|
+
n(input.base_salary, existing.base_salary),
|
|
45515
|
+
n(input.bonus_amount, existing.bonus_amount),
|
|
45516
|
+
n(input.welfare_amount, existing.welfare_amount),
|
|
45517
|
+
n(input.signing_amount, existing.signing_amount),
|
|
45518
|
+
s(input.equity_note, existing.equity_note),
|
|
45519
|
+
s(input.comp_note, existing.comp_note),
|
|
45520
|
+
s(input.work_arrangement, existing.work_arrangement),
|
|
45521
|
+
s(input.contract_type, existing.contract_type),
|
|
45522
|
+
s(input.accept_deadline, existing.accept_deadline),
|
|
45523
|
+
n(input.ai_score, existing.ai_score),
|
|
45524
|
+
s(input.verdict, existing.verdict),
|
|
45525
|
+
s(input.notes, existing.notes),
|
|
45526
|
+
ts,
|
|
45527
|
+
existing.id
|
|
45528
|
+
);
|
|
45529
|
+
return this.getByJob(input.job_id);
|
|
45530
|
+
}
|
|
45531
|
+
const id3 = newId("ofr_");
|
|
45532
|
+
db.prepare(
|
|
45533
|
+
`INSERT INTO offers (id,job_id,offer_status,base_salary,bonus_amount,welfare_amount,signing_amount,equity_note,comp_note,work_arrangement,contract_type,accept_deadline,ai_score,verdict,notes,created_at,updated_at)
|
|
45534
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`
|
|
45535
|
+
).run(
|
|
45536
|
+
id3,
|
|
45537
|
+
input.job_id,
|
|
45538
|
+
input.offer_status ?? "open",
|
|
45539
|
+
input.base_salary ?? null,
|
|
45540
|
+
input.bonus_amount ?? null,
|
|
45541
|
+
input.welfare_amount ?? null,
|
|
45542
|
+
input.signing_amount ?? null,
|
|
45543
|
+
input.equity_note ?? null,
|
|
45544
|
+
input.comp_note ?? null,
|
|
45545
|
+
input.work_arrangement ?? null,
|
|
45546
|
+
input.contract_type ?? null,
|
|
45547
|
+
input.accept_deadline ?? null,
|
|
45548
|
+
input.ai_score ?? null,
|
|
45549
|
+
input.verdict ?? null,
|
|
45550
|
+
input.notes ?? null,
|
|
45551
|
+
ts,
|
|
45552
|
+
ts
|
|
45553
|
+
);
|
|
45554
|
+
return this.getByJob(input.job_id);
|
|
45555
|
+
}
|
|
45556
|
+
};
|
|
45263
45557
|
function getEntityCounts() {
|
|
45264
45558
|
const db = getDb();
|
|
45265
45559
|
const ALLOWED_TABLES = /* @__PURE__ */ new Set([
|
|
@@ -45272,7 +45566,8 @@ function getEntityCounts() {
|
|
|
45272
45566
|
"jobs",
|
|
45273
45567
|
"applications",
|
|
45274
45568
|
"interview_preps",
|
|
45275
|
-
"application_timeline_events"
|
|
45569
|
+
"application_timeline_events",
|
|
45570
|
+
"offers"
|
|
45276
45571
|
]);
|
|
45277
45572
|
const c = (t) => {
|
|
45278
45573
|
if (!ALLOWED_TABLES.has(t)) throw new Error(`getEntityCounts: \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uC740 \uD14C\uC774\uBE14 \uC774\uB984: ${t}`);
|
|
@@ -45288,7 +45583,8 @@ function getEntityCounts() {
|
|
|
45288
45583
|
jobs: c("jobs"),
|
|
45289
45584
|
applications: c("applications"),
|
|
45290
45585
|
interview_preps: c("interview_preps"),
|
|
45291
|
-
application_timeline_events: c("application_timeline_events")
|
|
45586
|
+
application_timeline_events: c("application_timeline_events"),
|
|
45587
|
+
offers: c("offers")
|
|
45292
45588
|
};
|
|
45293
45589
|
}
|
|
45294
45590
|
|
|
@@ -45352,15 +45648,15 @@ function injectToken(html) {
|
|
|
45352
45648
|
}
|
|
45353
45649
|
|
|
45354
45650
|
// apps/web/src/http.ts
|
|
45355
|
-
import
|
|
45356
|
-
import
|
|
45651
|
+
import fs4 from "node:fs";
|
|
45652
|
+
import path4 from "node:path";
|
|
45357
45653
|
var MAX_BODY2 = 32 * 1024 * 1024;
|
|
45358
45654
|
var Router = class {
|
|
45359
45655
|
routes = [];
|
|
45360
|
-
add(method,
|
|
45656
|
+
add(method, path7, handler) {
|
|
45361
45657
|
const keys2 = [];
|
|
45362
45658
|
const pattern = new RegExp(
|
|
45363
|
-
"^" +
|
|
45659
|
+
"^" + path7.replace(/:[^/]+/g, (m) => {
|
|
45364
45660
|
keys2.push(m.slice(1));
|
|
45365
45661
|
return "([^/]+)";
|
|
45366
45662
|
}) + "/?$"
|
|
@@ -45475,15 +45771,15 @@ var MIME = {
|
|
|
45475
45771
|
};
|
|
45476
45772
|
function serveStatic(res, root2, relPath, transform) {
|
|
45477
45773
|
const cleaned = decodeURIComponent(relPath).replace(/\0/g, "");
|
|
45478
|
-
const resolved =
|
|
45479
|
-
if (resolved !== root2 && !resolved.startsWith(root2 +
|
|
45774
|
+
const resolved = path4.resolve(root2, "." + path4.posix.normalize("/" + cleaned));
|
|
45775
|
+
if (resolved !== root2 && !resolved.startsWith(root2 + path4.sep)) {
|
|
45480
45776
|
res.writeHead(403).end("Forbidden");
|
|
45481
45777
|
return true;
|
|
45482
45778
|
}
|
|
45483
|
-
if (!
|
|
45484
|
-
const ext =
|
|
45779
|
+
if (!fs4.existsSync(resolved) || !fs4.statSync(resolved).isFile()) return false;
|
|
45780
|
+
const ext = path4.extname(resolved).toLowerCase();
|
|
45485
45781
|
const mime = MIME[ext] ?? "application/octet-stream";
|
|
45486
|
-
let payload =
|
|
45782
|
+
let payload = fs4.readFileSync(resolved);
|
|
45487
45783
|
if (transform && ext === ".html") payload = transform(payload.toString("utf8"));
|
|
45488
45784
|
const headers = {
|
|
45489
45785
|
"Content-Type": mime,
|
|
@@ -46075,12 +46371,12 @@ function saveCoverLetterVersion(input) {
|
|
|
46075
46371
|
}
|
|
46076
46372
|
return { coverLetter, version, verification, forced };
|
|
46077
46373
|
}
|
|
46078
|
-
function updateApplicationStatus(jobId, status, note, submission) {
|
|
46374
|
+
function updateApplicationStatus(jobId, status, note, submission, rejectedStage) {
|
|
46079
46375
|
const job = jobRepo.get(jobId);
|
|
46080
46376
|
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
46081
46377
|
const before2 = applicationRepo.getByJob(jobId);
|
|
46082
46378
|
const application = tx(() => {
|
|
46083
|
-
let application2 = applicationRepo.setStatus(jobId, status, note);
|
|
46379
|
+
let application2 = applicationRepo.setStatus(jobId, status, note, rejectedStage);
|
|
46084
46380
|
const submittedDocs = (submission?.document_ids ?? []).map((docId) => documentRepo.get(docId)).filter((doc) => !!doc);
|
|
46085
46381
|
const submittedCoverLetter = submission?.cover_letter_id ? coverLetterRepo.get(submission.cover_letter_id, true) : null;
|
|
46086
46382
|
if (status === "applied" && submission) {
|
|
@@ -46116,7 +46412,9 @@ function updateApplicationStatus(jobId, status, note, submission) {
|
|
|
46116
46412
|
status,
|
|
46117
46413
|
status_label: APPLICATION_STATUS_LABELS[status],
|
|
46118
46414
|
note: note ?? null,
|
|
46119
|
-
submission: submissionPayload
|
|
46415
|
+
submission: submissionPayload,
|
|
46416
|
+
// 탈락 회고: rejected로 넘어갈 때 실제 저장된 단계(setStatus가 정합성 처리한 값)를 타임라인에도 남긴다.
|
|
46417
|
+
rejected_stage: application2.rejected_stage
|
|
46120
46418
|
},
|
|
46121
46419
|
occurred_at: submittedAtToOccurrence(submittedAt)
|
|
46122
46420
|
});
|
|
@@ -46150,8 +46448,21 @@ function saveInterviewPrep(input) {
|
|
|
46150
46448
|
var ACTIVE = ["draft", "planned", "applied", "document_passed", "interview"];
|
|
46151
46449
|
var DEADLINE_ACTIONABLE = ["draft", "planned"];
|
|
46152
46450
|
var DEADLINE_SOON_DAYS = 14;
|
|
46153
|
-
var
|
|
46451
|
+
var SCHEDULE_SOON_DAYS = 7;
|
|
46154
46452
|
var DAY_MS = 864e5;
|
|
46453
|
+
function collectFutureSchedule(jobs, now2) {
|
|
46454
|
+
const items = [];
|
|
46455
|
+
for (const job of jobs) {
|
|
46456
|
+
for (const s of job.schedule ?? []) {
|
|
46457
|
+
const d_day = daysUntilDate(s.date, now2);
|
|
46458
|
+
if (d_day == null || d_day < 0) continue;
|
|
46459
|
+
items.push({ job, label: s.label, date: s.date, time: s.time, d_day });
|
|
46460
|
+
}
|
|
46461
|
+
}
|
|
46462
|
+
return items.sort(
|
|
46463
|
+
(a, b) => a.date < b.date ? -1 : a.date > b.date ? 1 : (a.time || "99:99").localeCompare(b.time || "99:99")
|
|
46464
|
+
);
|
|
46465
|
+
}
|
|
46155
46466
|
function daysUntilDate(dateStr, now2) {
|
|
46156
46467
|
if (!dateStr) return null;
|
|
46157
46468
|
const d = /* @__PURE__ */ new Date(`${dateStr}T00:00:00`);
|
|
@@ -46166,6 +46477,24 @@ function daysSinceTimestamp(iso, now2) {
|
|
|
46166
46477
|
if (isNaN(d.getTime())) return null;
|
|
46167
46478
|
return Math.floor((now2.getTime() - d.getTime()) / DAY_MS);
|
|
46168
46479
|
}
|
|
46480
|
+
function businessDaysSince(iso, now2) {
|
|
46481
|
+
if (!iso) return null;
|
|
46482
|
+
const start = new Date(iso);
|
|
46483
|
+
if (isNaN(start.getTime())) return null;
|
|
46484
|
+
const s = new Date(start);
|
|
46485
|
+
s.setHours(0, 0, 0, 0);
|
|
46486
|
+
const e = new Date(now2);
|
|
46487
|
+
e.setHours(0, 0, 0, 0);
|
|
46488
|
+
if (e.getTime() <= s.getTime()) return 0;
|
|
46489
|
+
let count = 0;
|
|
46490
|
+
const cursor = new Date(s);
|
|
46491
|
+
while (cursor.getTime() < e.getTime()) {
|
|
46492
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
46493
|
+
const dow = cursor.getDay();
|
|
46494
|
+
if (dow !== 0 && dow !== 6) count++;
|
|
46495
|
+
}
|
|
46496
|
+
return count;
|
|
46497
|
+
}
|
|
46169
46498
|
function jobWithMeta(job) {
|
|
46170
46499
|
const app = applicationRepo.getByJob(job.id);
|
|
46171
46500
|
const fit = fitRepo.getByJob(job.id);
|
|
@@ -46178,14 +46507,16 @@ function getHomeSummary(now2 = /* @__PURE__ */ new Date()) {
|
|
|
46178
46507
|
const applications = applicationRepo.list();
|
|
46179
46508
|
const coverLetters = coverLetterRepo.list();
|
|
46180
46509
|
const statusByJob = new Map(applications.map((a) => [a.job_id, a]));
|
|
46510
|
+
const jobById = new Map(jobs.map((j) => [j.id, j]));
|
|
46511
|
+
const preppedJobIds = new Set(interviewRepo.list().map((p) => p.job_id));
|
|
46181
46512
|
const status_breakdown = Object.keys(APPLICATION_STATUS_LABELS).map((status) => ({
|
|
46182
46513
|
status,
|
|
46183
46514
|
label: APPLICATION_STATUS_LABELS[status],
|
|
46184
46515
|
count: applications.filter((a) => a.status === status).length
|
|
46185
46516
|
}));
|
|
46186
46517
|
const active = applications.filter((a) => ACTIVE.includes(a.status));
|
|
46187
|
-
const interview_todo = applications.filter((a) => INTERVIEW_UNLOCK_STATUSES.includes(a.status) && !
|
|
46188
|
-
const job =
|
|
46518
|
+
const interview_todo = applications.filter((a) => INTERVIEW_UNLOCK_STATUSES.includes(a.status) && !preppedJobIds.has(a.job_id)).map((a) => {
|
|
46519
|
+
const job = jobById.get(a.job_id);
|
|
46189
46520
|
return job ? { job, status_label: APPLICATION_STATUS_LABELS[a.status] } : null;
|
|
46190
46521
|
}).filter((x) => x !== null);
|
|
46191
46522
|
const deadlines = jobs.map((job) => {
|
|
@@ -46196,11 +46527,13 @@ function getHomeSummary(now2 = /* @__PURE__ */ new Date()) {
|
|
|
46196
46527
|
return { job, status, status_label: APPLICATION_STATUS_LABELS[status], days_left };
|
|
46197
46528
|
}).filter((x) => x !== null).sort((a, b) => a.days_left - b.days_left).slice(0, 5);
|
|
46198
46529
|
const followups = applications.filter((a) => a.status === "applied").map((a) => {
|
|
46199
|
-
const
|
|
46200
|
-
if (
|
|
46201
|
-
const
|
|
46530
|
+
const biz = businessDaysSince(a.applied_at, now2);
|
|
46531
|
+
if (biz == null || biz < FOLLOWUP_DUE_BIZ_DAYS) return null;
|
|
46532
|
+
const days_since = daysSinceTimestamp(a.applied_at, now2) ?? 0;
|
|
46533
|
+
const job = jobById.get(a.job_id);
|
|
46202
46534
|
return job ? { job, days_since } : null;
|
|
46203
46535
|
}).filter((x) => x !== null).sort((a, b) => b.days_since - a.days_since).slice(0, 5);
|
|
46536
|
+
const upcoming_schedule = collectFutureSchedule(jobs, now2).filter((x) => x.d_day <= SCHEDULE_SOON_DAYS).map((x) => ({ job: x.job, label: x.label, date: x.date, ...x.time ? { time: x.time } : {}, d_day: x.d_day })).slice(0, 6);
|
|
46204
46537
|
return {
|
|
46205
46538
|
onboarding,
|
|
46206
46539
|
counts: {
|
|
@@ -46212,7 +46545,7 @@ function getHomeSummary(now2 = /* @__PURE__ */ new Date()) {
|
|
|
46212
46545
|
status_breakdown,
|
|
46213
46546
|
recent_jobs: jobs.slice(0, 6).map(jobWithMeta),
|
|
46214
46547
|
in_progress: active.slice(0, 6).map((application) => {
|
|
46215
|
-
const job =
|
|
46548
|
+
const job = jobById.get(application.job_id) ?? null;
|
|
46216
46549
|
return {
|
|
46217
46550
|
application,
|
|
46218
46551
|
job,
|
|
@@ -46223,15 +46556,17 @@ function getHomeSummary(now2 = /* @__PURE__ */ new Date()) {
|
|
|
46223
46556
|
interview_todo,
|
|
46224
46557
|
deadlines,
|
|
46225
46558
|
followups,
|
|
46559
|
+
upcoming_schedule,
|
|
46226
46560
|
recent_activity: activityRepo.recent(10)
|
|
46227
46561
|
};
|
|
46228
46562
|
}
|
|
46229
46563
|
function listRecentActivity(limit = 20) {
|
|
46230
46564
|
return activityRepo.recent(limit);
|
|
46231
46565
|
}
|
|
46566
|
+
var FOLLOWUP_DUE_BIZ_DAYS = 5;
|
|
46232
46567
|
|
|
46233
46568
|
// packages/core/src/jobsearch.ts
|
|
46234
|
-
var UA =
|
|
46569
|
+
var UA = `careermate/${APP_VERSION} (+https://careermate.life)`;
|
|
46235
46570
|
function toYmd(v) {
|
|
46236
46571
|
if (typeof v !== "string" || v.length < 10) return void 0;
|
|
46237
46572
|
const m = v.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
@@ -46296,6 +46631,14 @@ var jumpit = {
|
|
|
46296
46631
|
var PROVIDERS = [wanted, jumpit];
|
|
46297
46632
|
var JOB_SEARCH_SOURCES = PROVIDERS.map((p) => p.id);
|
|
46298
46633
|
|
|
46634
|
+
// packages/core/src/offers.ts
|
|
46635
|
+
function withJob(offer, job) {
|
|
46636
|
+
return { ...offer, company: job?.company ?? "\u2014", position: job?.position ?? "\u2014" };
|
|
46637
|
+
}
|
|
46638
|
+
function compareOffers() {
|
|
46639
|
+
return offerRepo.list().map((o) => withJob(o, jobRepo.get(o.job_id)));
|
|
46640
|
+
}
|
|
46641
|
+
|
|
46299
46642
|
// packages/prompts/src/system.ts
|
|
46300
46643
|
var CAREERMATE_SYSTEM_PROMPT = `\uB2F9\uC2E0\uC740 \uC0AC\uC6A9\uC790\uC758 'CareerMate' \uCEE4\uB9AC\uC5B4 \uBE44\uC11C\uC785\uB2C8\uB2E4.
|
|
46301
46644
|
|
|
@@ -46446,12 +46789,15 @@ var HUMANIZE_WRITING_GUIDE = `# \uC0AC\uB78C\uC774 \uC4F4 \uAC83\uCC98\uB7FC: \u
|
|
|
46446
46789
|
3. \uAE30\uACC4\uC801 \uBCD1\uB82C\uAD6C\uC870 \u2014 \uC138 \uAC1C\uC529 \uB098\uC5F4(rule of three), \uBAA8\uB4E0 \uBB38\uB2E8\uC774 \uB611\uAC19\uC740 \uACE8\uACA9.
|
|
46447
46790
|
- "\uCCAB\uC9F8\u2026\uB458\uC9F8\u2026\uC14B\uC9F8", "A\uD558\uACE0 B\uD558\uBA70 C\uD558\uB294" \uAC19\uC740 \uADE0\uC77C\uD55C \uB098\uC5F4\uC744 \uBC18\uBCF5\uD558\uC9C0 \uC54A\uB294\uB2E4.
|
|
46448
46791
|
- \uBB38\uB2E8\uB9C8\uB2E4 \uAE38\uC774\uC640 \uC2DC\uC791 \uBC29\uC2DD\uC744 \uC77C\uBD80\uB7EC \uB2E4\uB974\uAC8C \uD55C\uB2E4.
|
|
46792
|
+
- \uAC19\uC740 \uCE90\uCE58\uD504\uB808\uC774\uC988\xB7\uBAA8\uD2F0\uD504(\uC608: "1\uC6D0\uB3C4 \uD2C0\uB9AC\uC9C0 \uC54A\uB294")\uB97C \uBB38\uC11C \uC804\uCCB4\uC5D0\uC11C **\uCD5C\uB300 2\uD68C**\uAE4C\uC9C0\uB9CC \uC4F4\uB2E4. 3\uD68C\uBD80\uD130\uB294 \uC778\uC704\uC801 \uC7A5\uCE58\uB85C \uC77D\uD600 \uC624\uD788\uB824 \uC0AC\uB78C \uB0C4\uC0C8\uB97C \uC9C0\uC6B4\uB2E4 \u2014 \uBC18\uBCF5\uD558\uACE0 \uC2F6\uC73C\uBA74 \uB9E4\uBC88 \uB2E4\uB978 \uB9D0\uB85C \uBC14\uAFD4 \uD45C\uD604\uD55C\uB2E4.
|
|
46449
46793
|
|
|
46450
46794
|
4. \uC0C1\uD22C\uC801 \uC5F0\uACB0\uC5B4 \uB0A8\uBC1C \u2014 "\uB610\uD55C", "\uBFD0\uB9CC \uC544\uB2C8\uB77C", "\uB354 \uB098\uC544\uAC00", "\uC774\uB97C \uD1B5\uD574", "\uACB0\uB860\uC801\uC73C\uB85C".
|
|
46451
46795
|
- \uC811\uC18D\uC5B4 \uC5C6\uC774 \uBB38\uC7A5\uC744 \uC787\uAC70\uB098, \uC0AC\uAC74\uC758 \uD750\uB984 \uC790\uCCB4\uB85C \uC5F0\uACB0\uD55C\uB2E4.
|
|
46452
46796
|
|
|
46453
46797
|
5. \uADE0\uC77C\uD55C \uBB38\uC7A5 \uB9AC\uB4EC \u2014 \uBAA8\uB4E0 \uBB38\uC7A5\uC774 \uBE44\uC2B7\uD55C \uAE38\uC774.
|
|
46454
46798
|
- \uC9E7\uC740 \uBB38\uC7A5\uACFC \uAE34 \uBB38\uC7A5\uC744 \uC11E\uB294\uB2E4. \uAC00\uB054 \uC544\uC8FC \uC9E7\uAC8C \uB04A\uB294\uB2E4. \uC774\uB807\uAC8C.
|
|
46799
|
+
- \uBE44\uC2B7\uD55C \uAE38\uC774\uC758 \uBB38\uC7A5\uC744 \uC138 \uAC1C \uC5F0\uC18D\uC73C\uB85C \uC4F0\uC9C0 \uC54A\uB294\uB2E4. \uD558\uB098\uB294 \uAE38\uAC8C \uD480\uACE0 \uB2E4\uC74C\uC740 \uD22D \uB04A\uB294 \uC2DD\uC73C\uB85C \uD638\uD761\uC744 \uBC14\uAFBC\uB2E4.
|
|
46800
|
+
- \uBB38\uB2E8\uB9C8\uB2E4 \uD55C \uD638\uD761\uC5D0 \uC77D\uD788\uB294 \uC9E7\uC740 \uB2E8\uD0C0 \uBB38\uC7A5(8\uB2E8\uC5B4 \uC548\uD30E \uC774\uD558)\uC744 \uCD5C\uC18C \uD558\uB098 \uB123\uB294\uB2E4.
|
|
46455
46801
|
|
|
46456
46802
|
6. \uACFC\uC7A5\uB41C \uC218\uC2DD\xB7\uC218\uB3D9\uD0DC \u2014 "\uB9E4\uC6B0", "\uC815\uB9D0\uB85C", "\uD0C1\uC6D4\uD55C", "\uC131\uACF5\uC801\uC73C\uB85C", "~\uB418\uC5B4\uC84C\uC2B5\uB2C8\uB2E4".
|
|
46457
46803
|
- \uBD80\uC0AC\uB97C \uBE7C\uACE0 \uB3D9\uC0AC\xB7\uBA85\uC0AC\uB97C \uAD6C\uCCB4\uD654\uD55C\uB2E4. \uB2A5\uB3D9\uD0DC\uB97C \uAE30\uBCF8\uC73C\uB85C \uD55C\uB2E4.
|
|
@@ -64434,16 +64780,16 @@ var replacer = ({ json, patch, patchText, context, keepOriginalStyles = true })
|
|
|
64434
64780
|
didFindOccurrence: true
|
|
64435
64781
|
};
|
|
64436
64782
|
};
|
|
64437
|
-
var goToElementFromPath = (json,
|
|
64783
|
+
var goToElementFromPath = (json, path7) => {
|
|
64438
64784
|
let element = json;
|
|
64439
|
-
for (let i = 1; i <
|
|
64440
|
-
const index =
|
|
64785
|
+
for (let i = 1; i < path7.length; i++) {
|
|
64786
|
+
const index = path7[i];
|
|
64441
64787
|
element = element.elements[index];
|
|
64442
64788
|
}
|
|
64443
64789
|
return element;
|
|
64444
64790
|
};
|
|
64445
|
-
var goToParentElementFromPath = (json,
|
|
64446
|
-
var getLastElementIndexFromPath = (
|
|
64791
|
+
var goToParentElementFromPath = (json, path7) => goToElementFromPath(json, path7.slice(0, path7.length - 1));
|
|
64792
|
+
var getLastElementIndexFromPath = (path7) => path7[path7.length - 1];
|
|
64447
64793
|
var PatchType = {
|
|
64448
64794
|
/** Replace entire file-level elements (e.g., whole paragraphs) */
|
|
64449
64795
|
DOCUMENT: "file",
|
|
@@ -65046,12 +65392,12 @@ function getServerInfo() {
|
|
|
65046
65392
|
}
|
|
65047
65393
|
|
|
65048
65394
|
// apps/web/src/settings.ts
|
|
65049
|
-
import
|
|
65395
|
+
import fs5 from "node:fs";
|
|
65050
65396
|
import os2 from "node:os";
|
|
65051
|
-
import
|
|
65397
|
+
import path5 from "node:path";
|
|
65052
65398
|
import { spawn } from "node:child_process";
|
|
65053
65399
|
import { fileURLToPath } from "node:url";
|
|
65054
|
-
var __dirname =
|
|
65400
|
+
var __dirname = path5.dirname(fileURLToPath(import.meta.url));
|
|
65055
65401
|
function listTables(db) {
|
|
65056
65402
|
return db.prepare(
|
|
65057
65403
|
`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != '_meta' ORDER BY name`
|
|
@@ -65092,14 +65438,14 @@ function isRecord(v) {
|
|
|
65092
65438
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
65093
65439
|
}
|
|
65094
65440
|
function appRoot() {
|
|
65095
|
-
return BUNDLED ? __dirname :
|
|
65441
|
+
return BUNDLED ? __dirname : path5.resolve(__dirname, "..", "..", "..");
|
|
65096
65442
|
}
|
|
65097
65443
|
function shortcutFolder() {
|
|
65098
65444
|
const override = process.env.CAREERMATE_SHORTCUT_DIR?.trim();
|
|
65099
65445
|
if (override) return override;
|
|
65100
|
-
const desktop =
|
|
65101
|
-
const parent =
|
|
65102
|
-
return
|
|
65446
|
+
const desktop = path5.join(os2.homedir(), "Desktop");
|
|
65447
|
+
const parent = fs5.existsSync(desktop) ? desktop : getExportsDir();
|
|
65448
|
+
return path5.join(parent, "CareerMate \uB300\uC2DC\uBCF4\uB4DC");
|
|
65103
65449
|
}
|
|
65104
65450
|
function openFolder(dir) {
|
|
65105
65451
|
try {
|
|
@@ -65168,8 +65514,8 @@ function macLauncherScript() {
|
|
|
65168
65514
|
const root2 = appRoot();
|
|
65169
65515
|
const dataDir = getDataDir();
|
|
65170
65516
|
const nodePath = process.execPath;
|
|
65171
|
-
const binPath =
|
|
65172
|
-
const bundledWeb = BUNDLED ?
|
|
65517
|
+
const binPath = path5.join(root2, "bin", "careermate.mjs");
|
|
65518
|
+
const bundledWeb = BUNDLED ? path5.join(root2, "web.mjs") : path5.join(root2, "dist", "web.mjs");
|
|
65173
65519
|
return `#!/bin/zsh
|
|
65174
65520
|
set -e
|
|
65175
65521
|
|
|
@@ -65216,8 +65562,8 @@ function windowsLauncherScript() {
|
|
|
65216
65562
|
const root2 = appRoot();
|
|
65217
65563
|
const dataDir = getDataDir();
|
|
65218
65564
|
const nodePath = process.execPath;
|
|
65219
|
-
const binPath =
|
|
65220
|
-
const bundledWeb = BUNDLED ?
|
|
65565
|
+
const binPath = path5.join(root2, "bin", "careermate.mjs");
|
|
65566
|
+
const bundledWeb = BUNDLED ? path5.join(root2, "web.mjs") : path5.join(root2, "dist", "web.mjs");
|
|
65221
65567
|
return `@echo off
|
|
65222
65568
|
setlocal
|
|
65223
65569
|
set "CAREERMATE_DATA_DIR=${cmdQuote(dataDir)}"
|
|
@@ -65332,45 +65678,43 @@ function restoreBackup(raw) {
|
|
|
65332
65678
|
function createBackup() {
|
|
65333
65679
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
65334
65680
|
const dir = getBackupsDir();
|
|
65335
|
-
const dbBackup =
|
|
65336
|
-
const jsonBackup =
|
|
65337
|
-
const resolvedDir =
|
|
65338
|
-
if (!
|
|
65681
|
+
const dbBackup = path5.join(dir, `careermate-${stamp}.sqlite`);
|
|
65682
|
+
const jsonBackup = path5.join(dir, `careermate-${stamp}.json`);
|
|
65683
|
+
const resolvedDir = path5.resolve(dir);
|
|
65684
|
+
if (!path5.resolve(dbBackup).startsWith(resolvedDir + path5.sep)) {
|
|
65339
65685
|
throw new Error("\uBC31\uC5C5 \uACBD\uB85C\uAC00 \uBC31\uC5C5 \uD3F4\uB354\uB97C \uBC97\uC5B4\uB0AC\uC2B5\uB2C8\uB2E4.");
|
|
65340
65686
|
}
|
|
65341
|
-
const safeForLiteral = !/[\0\n\r]/.test(dbBackup);
|
|
65342
65687
|
try {
|
|
65343
|
-
|
|
65344
|
-
getDb().exec(`VACUUM INTO '${dbBackup.replace(/'/g, "''")}'`);
|
|
65688
|
+
vacuumInto(getDb(), dbBackup);
|
|
65345
65689
|
} catch {
|
|
65346
|
-
|
|
65690
|
+
fs5.copyFileSync(getDbPath(), dbBackup);
|
|
65347
65691
|
}
|
|
65348
|
-
|
|
65692
|
+
fs5.writeFileSync(jsonBackup, JSON.stringify(exportAll(), null, 2), "utf8");
|
|
65349
65693
|
return { backup_path: dbBackup, json_path: jsonBackup };
|
|
65350
65694
|
}
|
|
65351
65695
|
function createDashboardShortcut(open = false) {
|
|
65352
65696
|
const dir = shortcutFolder();
|
|
65353
|
-
|
|
65697
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
65354
65698
|
const readme = `CareerMate \uB300\uC2DC\uBCF4\uB4DC \uBC14\uB85C\uAC00\uAE30
|
|
65355
65699
|
|
|
65356
65700
|
- \uB300\uC2DC\uBCF4\uB4DC\uAC00 \uC774\uBBF8 \uC2E4\uD589 \uC911\uC774\uBA74 \uBE0C\uB77C\uC6B0\uC800\uB9CC \uC5FD\uB2C8\uB2E4.
|
|
65357
65701
|
- \uB300\uC2DC\uBCF4\uB4DC\uAC00 \uAEBC\uC838 \uC788\uC73C\uBA74 \uC11C\uBC84\uB97C \uC2DC\uC791\uD558\uACE0 \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5FD\uB2C8\uB2E4.
|
|
65358
65702
|
- \uC774 \uD3F4\uB354\uB294 \uC774 \uCEF4\uD4E8\uD130\uC758 CareerMate \uC124\uCE58 \uACBD\uB85C\uC640 \uB370\uC774\uD130 \uD3F4\uB354\uB97C \uAE30\uC900\uC73C\uB85C \uB9CC\uB4E4\uC5B4\uC84C\uC2B5\uB2C8\uB2E4.
|
|
65359
65703
|
`;
|
|
65360
|
-
const readmePath =
|
|
65361
|
-
|
|
65704
|
+
const readmePath = path5.join(dir, "README.txt");
|
|
65705
|
+
fs5.writeFileSync(readmePath, readme, "utf8");
|
|
65362
65706
|
let launcherPath;
|
|
65363
65707
|
if (process.platform === "win32") {
|
|
65364
|
-
launcherPath =
|
|
65365
|
-
|
|
65708
|
+
launcherPath = path5.join(dir, "CareerMate \uB300\uC2DC\uBCF4\uB4DC.cmd");
|
|
65709
|
+
fs5.writeFileSync(launcherPath, windowsLauncherScript(), "utf8");
|
|
65366
65710
|
} else if (process.platform === "darwin") {
|
|
65367
|
-
launcherPath =
|
|
65368
|
-
|
|
65369
|
-
|
|
65711
|
+
launcherPath = path5.join(dir, "CareerMate \uB300\uC2DC\uBCF4\uB4DC.command");
|
|
65712
|
+
fs5.writeFileSync(launcherPath, macLauncherScript(), { encoding: "utf8", mode: 493 });
|
|
65713
|
+
fs5.chmodSync(launcherPath, 493);
|
|
65370
65714
|
} else {
|
|
65371
|
-
launcherPath =
|
|
65372
|
-
|
|
65373
|
-
|
|
65715
|
+
launcherPath = path5.join(dir, "careermate-dashboard.sh");
|
|
65716
|
+
fs5.writeFileSync(launcherPath, linuxLauncherScript(), { encoding: "utf8", mode: 493 });
|
|
65717
|
+
fs5.chmodSync(launcherPath, 493);
|
|
65374
65718
|
}
|
|
65375
65719
|
if (open) openFolder(dir);
|
|
65376
65720
|
return {
|
|
@@ -65398,10 +65742,10 @@ function resetAll(confirm) {
|
|
|
65398
65742
|
}
|
|
65399
65743
|
function listBackups() {
|
|
65400
65744
|
const dir = getBackupsDir();
|
|
65401
|
-
if (!
|
|
65402
|
-
return
|
|
65403
|
-
const p =
|
|
65404
|
-
const st =
|
|
65745
|
+
if (!fs5.existsSync(dir)) return [];
|
|
65746
|
+
return fs5.readdirSync(dir).filter((f) => f.endsWith(".sqlite") || f.endsWith(".json")).map((f) => {
|
|
65747
|
+
const p = path5.join(dir, f);
|
|
65748
|
+
const st = fs5.statSync(p);
|
|
65405
65749
|
return { filename: f, path: p, size: st.size, created_at: st.mtime.toISOString() };
|
|
65406
65750
|
}).sort((a, b) => b.created_at.localeCompare(a.created_at));
|
|
65407
65751
|
}
|
|
@@ -65583,6 +65927,7 @@ function registerApiRoutes(router2) {
|
|
|
65583
65927
|
"/api/context",
|
|
65584
65928
|
(ctx) => getApplicationContext({ job_id: ctx.query.get("job_id") ?? void 0 })
|
|
65585
65929
|
);
|
|
65930
|
+
router2.get("/api/offers", () => ({ offers: compareOffers() }));
|
|
65586
65931
|
router2.get("/api/prompts", () => ({ prompts: PROMPTS }));
|
|
65587
65932
|
router2.get("/api/workflows", () => ({ workflows: WORKFLOWS }));
|
|
65588
65933
|
router2.get("/api/meta", () => ({
|
|
@@ -65822,8 +66167,8 @@ function isDownload(v) {
|
|
|
65822
66167
|
}
|
|
65823
66168
|
|
|
65824
66169
|
// apps/web/src/server.ts
|
|
65825
|
-
var __dirname2 =
|
|
65826
|
-
var WEB_ROOT = BUNDLED ?
|
|
66170
|
+
var __dirname2 = path6.dirname(fileURLToPath2(import.meta.url));
|
|
66171
|
+
var WEB_ROOT = BUNDLED ? path6.resolve(__dirname2, "public") : path6.resolve(__dirname2, "..", "public");
|
|
65827
66172
|
var LANDING_URL = "https://careermate.life/";
|
|
65828
66173
|
var router = new Router();
|
|
65829
66174
|
registerApiRoutes(router);
|